⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal_test.cpp

📁 An article on the implementation of a fast C++ delegate with many advanced features.
💻 CPP
字号:
// FD.Delegate library

// Copyright Douglas Gregor 2001-2003. Use, modification and
// distribution is subject to the Boost Software License, Version
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// For more information, see http://www.boost.org

// Copyright JaeWook Choi 2007
// , modified from Boost.Signals signal_test.cpp

#include <boost/test/minimal.hpp>
#include <boost/signal.hpp>
#include <fd/delegate.hpp>
#include <functional>
#include <iostream>

template<typename T>
struct max_or_default {
  typedef T result_type;
  template<typename InputIterator>
  typename InputIterator::value_type
  operator()(InputIterator first, InputIterator last) const
  {
    if (first == last)
      return T();

    T max = *first++;
    for (; first != last; ++first)
      max = (*first > max)? *first : max;

    return max;
  }
};

struct make_int {
  make_int(int n, int cn) : N(n), CN(cn) {}

  int operator()() { return N; }
  int operator()() const { return CN; }

  int N;
  int CN;
};

bool operator ==(make_int const & lhs, make_int const & rhs)
{
  return lhs.N == rhs.N;
}

FD_DELEGATE_EQUALITY_COMPARABLE_TYPE(make_int);

template<int N>
struct make_increasing_int {
  make_increasing_int() : n(N) {}

  int operator()() const { return n++; }

  mutable int n;
};

static void
test_zero_args()
{
  make_int i42(42, 41);
  make_int i2(2, 1);
  make_int i72(72, 71);
  make_int i63(63, 63);
  make_int i62(62, 61);

  {
    boost::signal<int (), max_or_default<int> > s0;
    fd::delegate<int ()> d0;

    std::cout << "sizeof(signal) = " << sizeof(s0) << std::endl;
    std::cout << "sizeof(delegate) = " << sizeof(d0) << std::endl;
    boost::BOOST_SIGNALS_NAMESPACE::connection c2 = s0.connect(i2);
    d0 += i2;
    boost::BOOST_SIGNALS_NAMESPACE::connection c72 = s0.connect(72, i72);
    d0 += i72;
    boost::BOOST_SIGNALS_NAMESPACE::connection c62 = s0.connect(60, i62);
    d0 += i62;
    boost::BOOST_SIGNALS_NAMESPACE::connection c42 = s0.connect(i42);
    d0 += i42;

    BOOST_CHECK(s0() == 72);
    BOOST_CHECK(d0(max_or_default<int>()) == 72);

    s0.disconnect(72);
    d0 -= i72;
    BOOST_CHECK(s0() == 62);
    BOOST_CHECK(d0(max_or_default<int>()) == 62);

    c72.disconnect(); // Double-disconnect should be safe
    d0 -= i72;
    BOOST_CHECK(s0() == 62);
    BOOST_CHECK(d0(max_or_default<int>()) == 62);

    s0.disconnect(72); // Triple-disconect should be safe
    d0 -= i72;
    BOOST_CHECK(s0() == 62);
    BOOST_CHECK(d0(max_or_default<int>()) == 62);

    // Also connect 63 in the same group as 62
    s0.connect(60, i63);
    d0 += i63;
    BOOST_CHECK(s0() == 63);
    BOOST_CHECK(d0(max_or_default<int>()) == 63);

    // Disconnect all of the 60's
    s0.disconnect(60);
    d0 -= i62;
    d0 -= i63;
    BOOST_CHECK(s0() == 42);
    BOOST_CHECK(d0(max_or_default<int>()) == 42);

    c42.disconnect();
    d0 -= i42;
    BOOST_CHECK(s0() == 2);
    BOOST_CHECK(d0(max_or_default<int>()) == 2);

    c2.disconnect();
    d0 -= i2;
    BOOST_CHECK(s0() == 0);
    BOOST_CHECK(d0(max_or_default<int>()) == 0);
    BOOST_CHECK(d0.empty());
    try
    {
      d0();
    } catch(fd::bad_function_call) { }
  }

  {
    boost::signal<int (), max_or_default<int> > s0;
    boost::BOOST_SIGNALS_NAMESPACE::connection c2 = s0.connect(i2);
    boost::BOOST_SIGNALS_NAMESPACE::connection c72 = s0.connect(i72);
    boost::BOOST_SIGNALS_NAMESPACE::connection c62 = s0.connect(i62);
    boost::BOOST_SIGNALS_NAMESPACE::connection c42 = s0.connect(i42);

    const boost::signal<int (), max_or_default<int> >& cs0 = s0;
    BOOST_CHECK(cs0() == 72);

    fd::delegate<int ()> d0;
    d0 += i2;
    d0 += i72;
    d0 += i62;
    d0 += i42;

    fd::delegate<int ()> const & cd0 = d0;
    BOOST_CHECK(cd0(max_or_default<int>()) == 72);
  }

  {
    make_increasing_int<7> i7;
    make_increasing_int<10> i10;

    boost::signal<int (), max_or_default<int> > s0;
    boost::BOOST_SIGNALS_NAMESPACE::connection c7 = s0.connect(i7);
    boost::BOOST_SIGNALS_NAMESPACE::connection c10 = s0.connect(i10);

    // boost::signal<int (), max_or_default<int> > s1( s0 );  // Not copy-constructible,
    // s1 = s0;                                               // nor assignable.

    BOOST_CHECK(s0() == 10);
    BOOST_CHECK(s0() == 11);

    fd::delegate<int ()> d0, d1, d2;
    d0 += i7;
    d0 += i10;

    d1 = d0;

    BOOST_CHECK(d0(max_or_default<int>()) == 10);
    BOOST_CHECK(d0(max_or_default<int>()) == 11);

    d2 = d0;

    BOOST_CHECK(d1(max_or_default<int>()) == 10);
    BOOST_CHECK(d1(max_or_default<int>()) == 11);

    BOOST_CHECK(d2(max_or_default<int>()) == 12);
    BOOST_CHECK(d2(max_or_default<int>()) == 13);
  }
}

static void
test_one_arg()
{
  boost::signal<int (int value), max_or_default<int> > s1;

  s1.connect(std::negate<int>());
  s1.connect(std::bind1st(std::multiplies<int>(), 2));

  BOOST_CHECK(s1(1) == 2);
  BOOST_CHECK(s1(-1) == 1);

  fd::delegate<int (int value)> d1;

  d1 += std::negate<int>();
  d1 += std::bind1st(std::multiplies<int>(), 2);

  BOOST_CHECK(d1(1, max_or_default<int>()) == 2);
  BOOST_CHECK(d1(-1, max_or_default<int>()) == 1);
}

static void
test_signal_signal_connect()
{
  boost::signal<int (int value), max_or_default<int> > s1;

  s1.connect(std::negate<int>());

  BOOST_CHECK(s1(3) == -3);

  fd::delegate<int (int value)> d1;

  d1 += std::negate<int>();

  BOOST_CHECK(d1(3, max_or_default<int>()) == -3);

  {
    boost::signal<int (int value), max_or_default<int> > s2;
    s1.connect(s2);
    s2.connect(std::bind1st(std::multiplies<int>(), 2));
    s2.connect(std::bind1st(std::multiplies<int>(), -3));

    BOOST_CHECK(s2(-3) == 9);
    BOOST_CHECK(s1(3) == 6);

    {
      fd::delegate<int (int value)> d2;

      // Reference to other FD.Delegate is added so any changes made on d2 afterward
      // will affect d1 as well.
      fd::multicast::scoped_token stok1 = d1.add(boost::ref( d2 ));

      d2 += std::bind1st(std::multiplies<int>(), 2);
      d2 += std::bind1st(std::multiplies<int>(), -3);

      BOOST_CHECK(d2(-3, max_or_default<int>()) == 9);

      BOOST_CHECK(d1(3, max_or_default<int>()) != 6);
      BOOST_CHECK(d1(3, max_or_default<int>()) == -3);
      // Multicast can not pass down the combiner interface into the referenced
      // multicast of compatible FD.Delegate type since a callable entity is internally
      // stored without type information nor the combiner interface is not a part of
      // FD.Delegate type.
      //
      // Therefore when d1(3, max_or_default<int>()) is called,
      //   a) std::negate<int>(3) and
      //   b) d2(3),
      // are called in an order with max_or_default<int>() combiner.
      //
      // Since d2 itself is a multicast, it will call
      //   b-1) std::multiplies<int>()(2, 3) and
      //   b-2) std::multiplies<int>()(-3, 3)
      // without combiner interface thus will return -9 which is the last return
      // value of delegates in the multicast.
      //
      // Combiner interface is only applied for between -3 from std::negate<int>(3) and
      // -9 from d2(3) and -3 will be returned as result.

    } // stok1 goes out of scope and disconnects

    {
      fd::delegate<int (int value)> d3;

      // Non-reference to other FD.Delegate is added so all delegates stored
      // in d3 at the moment will be copied to d1 but any changes made on d3 afterward
      // will not affect d1 at all.
      fd::multicast::scoped_token stok2 = d1.add( d3 );

      // d3 is an empty delegate so no delegate has been copied into d1.

      d3 += std::bind1st(std::multiplies<int>(), 2);
      d3 += std::bind1st(std::multiplies<int>(), -3);

      BOOST_CHECK(d3(-3, max_or_default<int>()) == 9);

      BOOST_CHECK(d1(3, max_or_default<int>()) != 6);
      BOOST_CHECK(d1(3, max_or_default<int>()) == -3);
      // When d1(3, max_or_default<int>()) is called, only
      // std::negate<int>(3) will be called as it is a only
      // delegate in d1.

    } // stok2 goes out of scope and disconnects

  } // s2 goes out of scope and disconnects

  BOOST_CHECK(s1(3) == -3);
  BOOST_CHECK(d1(3, max_or_default<int>()) == -3);
}

int
test_main(int, char* [])
{
  test_zero_args();
  test_one_arg();
  test_signal_signal_connect();
  return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -