[
  {
    "path": ".gitignore",
    "content": "/*.exe\n"
  },
  {
    "path": "README.md",
    "content": "# High performance C++11 signals\nSee [Performance of a C++11 Signal System](http://www.testbit.eu/2013/cpp11-signal-system-performance/) for\nthe original source code, as well as performance measurements compared to other signalling systems.\n\nThe original author, Tim Janik, licensed the source code to the public domain [CC0 1.0 Universal (CC0 1.0)](http://creativecommons.org/publicdomain/zero/1.0/).\n## Declare a signal\nThis example declares a signal 'sig' that takes three arguments and returns a char.\n```c++\nSimple::Signal<char (float, int, std::string)> sig;\n```\n## Connect to a signal\nThis example connects 'sig' to a static function.\nIt is also possible to connect to member functions or lambda functions.\n```c++\nstatic char float_callback (float f, int, std::string) {\n  // ...\n  return 0;\n}\n\nvoid Init() {\n  sig.connect(float_callback);\n}\n```\n## Fire a signal\n```c++\nvoid func() {\n  // ...\n  sig.emit(1.0f, 7, \"xxxx\");\n}\n```\n"
  },
  {
    "path": "SimpleSignal.h",
    "content": "// CC0 Public Domain: http://creativecommons.org/publicdomain/zero/1.0/\n#pragma once\n\n#include <memory>\n#include <functional>\n#include <list>\n#include <vector>\n#include <algorithm>\n\nnamespace Simple {\n\nnamespace Lib {\n\n/// ProtoSignal is the template implementation for callback list.\ntemplate<typename,typename> class ProtoSignal;   // undefined\n\n/// CollectorInvocation invokes signal handlers differently depending on return type.\ntemplate<typename,typename> struct CollectorInvocation;\n\n/// CollectorLast returns the result of the last signal handler from a signal emission.\ntemplate<typename Result>\nstruct CollectorLast {\n  using CollectorResult = Result;\n  explicit        CollectorLast ()              : last_() {}\n  inline bool     operator()    (Result r)      { last_ = r; return true; }\n  CollectorResult result        ()              { return last_; }\nprivate:\n  Result last_;\n};\n\n/// CollectorDefault implements the default signal handler collection behaviour.\ntemplate<typename Result>\nstruct CollectorDefault : CollectorLast<Result>\n{};\n\n/// CollectorDefault specialisation for signals with void return type.\ntemplate<>\nstruct CollectorDefault<void> {\n  using CollectorResult = void;\n  void                  result     ()           {}\n  inline bool           operator() (void)       { return true; }\n};\n\n/// CollectorInvocation specialisation for regular signals.\ntemplate<class Collector, class R, class... Args>\nstruct CollectorInvocation<Collector, R (Args...)> {\n  inline bool\n  invoke (Collector &collector, const std::function<R (Args...)> &cbf, Args... args) const\n  {\n    return collector (cbf (args...));\n  }\n};\n\n/// CollectorInvocation specialisation for signals with void return type.\ntemplate<class Collector, class... Args>\nstruct CollectorInvocation<Collector, void (Args...)> {\n  inline bool\n  invoke (Collector &collector, const std::function<void (Args...)> &cbf, Args... args) const\n  {\n    cbf (args...); return collector();\n  }\n};\n\n/// ProtoSignal template specialised for the callback signature and collector.\ntemplate<class Collector, class R, class... Args>\nclass ProtoSignal<R (Args...), Collector> : private CollectorInvocation<Collector, R (Args...)> {\nprotected:\n  using CbFunction = std::function<R (Args...)>;\n  using Result = typename CbFunction::result_type;\n  using CollectorResult = typename Collector::CollectorResult;\n\nprivate:\n  /*copy-ctor*/ ProtoSignal (const ProtoSignal&) = delete;\n  ProtoSignal&  operator=   (const ProtoSignal&) = delete;\n\n  using CallbackSlot = std::shared_ptr<CbFunction>;\n  using CallbackList = std::list<CallbackSlot>;\n  CallbackList callback_list_;\n\n  size_t add_cb(const CbFunction& cb)\n  {\n    callback_list_.emplace_back(std::make_shared<CbFunction>(cb));\n    return size_t (callback_list_.back().get());\n  }\n\n  bool remove_cb(size_t id)\n  {\n    auto it =std::remove_if(begin(callback_list_), end(callback_list_),\n                            [id](const CallbackSlot& slot) { return size_t(slot.get()) == id; });\n    bool const removed = it != end(callback_list_);\n    callback_list_.erase(it, end(callback_list_));\n    return removed;\n  }\n\npublic:\n  /// ProtoSignal constructor, connects default callback if non-nullptr.\n  ProtoSignal (const CbFunction &method)\n  {\n    if (method)\n      add_cb(method);\n  }\n  /// ProtoSignal destructor releases all resources associated with this signal.\n  ~ProtoSignal ()\n  {\n  }\n\n  /// Operator to add a new function or lambda as signal handler, returns a handler connection ID.\n  size_t connect (const CbFunction &cb)      { return add_cb(cb); }\n  /// Operator to remove a signal handler through it connection ID, returns if a handler was removed.\n  bool   disconnect (size_t connection)         { return remove_cb(connection); }\n\n  /// Emit a signal, i.e. invoke all its callbacks and collect return types with the Collector.\n  CollectorResult\n  emit (Args... args) const\n  {\n    Collector collector;\n    for (auto &slot : callback_list_) {\n        if (slot) {\n            const bool continue_emission = this->invoke (collector, *slot, args...);\n            if (!continue_emission)\n              break;\n        }\n    }\n    return collector.result();\n  }\n  // Number of connected slots.\n  std::size_t\n  size () const\n  {\n    return callback_list_.size();\n  }\n};\n\n} // Lib\n// namespace Simple\n\n/**\n * Signal is a template type providing an interface for arbitrary callback lists.\n * A signal type needs to be declared with the function signature of its callbacks,\n * and optionally a return result collector class type.\n * Signal callbacks can be added with operator+= to a signal and removed with operator-=, using\n * a callback connection ID return by operator+= as argument.\n * The callbacks of a signal are invoked with the emit() method and arguments according to the signature.\n * The result returned by emit() depends on the signal collector class. By default, the result of\n * the last callback is returned from emit(). Collectors can be implemented to accumulate callback\n * results or to halt a running emissions in correspondance to callback results.\n * The signal implementation is safe against recursion, so callbacks may be removed and\n * added during a signal emission and recursive emit() calls are also safe.\n * The overhead of an unused signal is intentionally kept very low, around the size of a single pointer.\n * Note that the Signal template types is non-copyable.\n */\ntemplate <typename SignalSignature, class Collector = Lib::CollectorDefault<typename std::function<SignalSignature>::result_type> >\nstruct Signal /*final*/ :\n    Lib::ProtoSignal<SignalSignature, Collector>\n{\n  using ProtoSignal = Lib::ProtoSignal<SignalSignature, Collector>;\n  using CbFunction = typename ProtoSignal::CbFunction;\n  /// Signal constructor, supports a default callback as argument.\n  Signal (const CbFunction &method = CbFunction()) : ProtoSignal (method) {}\n};\n\n/// This function creates a std::function by binding @a object to the member function pointer @a method.\ntemplate<class Instance, class Class, class R, class... Args> std::function<R (Args...)>\nslot (Instance &object, R (Class::*method) (Args...))\n{\n  return [&object, method] (Args... args) { return (object .* method) (args...); };\n}\n\n/// This function creates a std::function by binding @a object to the member function pointer @a method.\ntemplate<class Class, class R, class... Args> std::function<R (Args...)>\nslot (Class *object, R (Class::*method) (Args...))\n{\n  return [object, method] (Args... args) { return (object ->* method) (args...); };\n}\n\n/// Keep signal emissions going while all handlers return !0 (true).\ntemplate<typename Result>\nstruct CollectorUntil0 {\n  using CollectorResult = Result;\n  explicit                      CollectorUntil0 ()      : result_() {}\n  const CollectorResult&        result          ()      { return result_; }\n  inline bool\n  operator() (Result r)\n  {\n    result_ = r;\n    return result_ ? true : false;\n  }\nprivate:\n  CollectorResult result_;\n};\n\n/// Keep signal emissions going while all handlers return 0 (false).\ntemplate<typename Result>\nstruct CollectorWhile0 {\n  using CollectorResult = Result;\n  explicit                      CollectorWhile0 ()      : result_() {}\n  const CollectorResult&        result          ()      { return result_; }\n  inline bool\n  operator() (Result r)\n  {\n    result_ = r;\n    return result_ ? false : true;\n  }\nprivate:\n  CollectorResult result_;\n};\n\n/// CollectorVector returns the result of the all signal handlers from a signal emission in a std::vector.\ntemplate<typename Result>\nstruct CollectorVector {\n  using CollectorResult = std::vector<Result>;\n  const CollectorResult&        result ()       { return result_; }\n  inline bool\n  operator() (Result r)\n  {\n    result_.push_back (r);\n    return true;\n  }\nprivate:\n  CollectorResult result_;\n};\n\n} // Simple\n"
  },
  {
    "path": "test.cpp",
    "content": "#include \"SimpleSignal.h\"\n\n// g++ -Wall -O2 -std=gnu++11 -pthread test.cpp && ./a.out\n// append -fsanitize=address for memory debugging\n\n#include <string>\n#include <stdarg.h>\n#include <time.h>\n#include <ctime>\n#include <cstdlib>\n#include <cassert>\n\n#ifndef _MSC_VER\n#include <sys/time.h>\n#include <stdio.h>\nstatic std::string string_printf (const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));\n#endif\n\nstatic std::string\nstring_printf (const char *format, ...)\n{\n  std::string result;\n  char str[1000];\n  va_list args;\n  va_start (args, format);\n  if (vsnprintf (str, sizeof str, format, args) >= 0)\n    result = str;\n  va_end (args);\n  return result;\n}\n\nstatic uint64_t\ntimestamp_benchmark ()\n{\n  auto now = std::clock();\n  return 1.0e9 / CLOCKS_PER_SEC * now;\n}\n\nstruct TestCounter {\n  static uint64_t get     ();\n  static void     set     (uint64_t);\n  static void     add2    (void*, uint64_t);\n};\n\nnamespace { // Anon\nvoid        (*test_counter_add2) (void*, uint64_t) = TestCounter::add2; // external symbol to prevent easy inlining\nstatic uint64_t test_counter_var = 0;\n} // Anon\n\nclass BasicSignalTests {\n  static std::string accu;\n  struct Foo {\n    char\n    foo_bool (float f, int i, std::string s)\n    {\n      accu += string_printf (\"Foo: %.2f\\n\", f + i + s.size());\n      return true;\n    }\n  };\n  static char\n  float_callback (float f, int, std::string)\n  {\n    accu += string_printf (\"float: %.2f\\n\", f);\n    return 0;\n  }\npublic:\n  static void\n  run()\n  {\n    accu = \"\";\n    Simple::Signal<char (float, int, std::string)> sig1;\n    size_t id1 = sig1.connect(float_callback);\n    size_t id2 = sig1.connect([] (float, int i, std::string) { accu += string_printf (\"int: %d\\n\", i); return 0; });\n    size_t id3 = sig1.connect([] (float, int, const std::string &s) { accu += string_printf (\"string: %s\\n\", s.c_str()); return 0; });\n    sig1.emit (.3, 4, \"huhu\");\n    bool success;\n    success = sig1.disconnect(id1); assert (success == true);  success = sig1.disconnect(id1); assert (success == false);\n    success = sig1.disconnect(id2); assert (success == true);  success = sig1.disconnect(id3); assert (success == true);\n    success = sig1.disconnect(id3); assert (success == false); success = sig1.disconnect(id2); assert (success == false);\n    Foo foo;\n    sig1.connect(Simple::slot (foo, &Foo::foo_bool));\n    sig1.connect(Simple::slot (&foo, &Foo::foo_bool));\n    sig1.emit (.5, 1, \"12\");\n\n    Simple::Signal<void (std::string, int)> sig2;\n    sig2.connect([] (std::string msg, int) { accu += string_printf (\"msg: %s\", msg.c_str()); });\n    sig2.connect([] (std::string, int d)   { accu += string_printf (\" *%d*\\n\", d); });\n    sig2.emit (\"in sig2\", 17);\n\n    accu += \"DONE\";\n\n    const char *expected =\n      \"float: 0.30\\n\"\n      \"int: 4\\n\"\n      \"string: huhu\\n\"\n      \"Foo: 3.50\\n\"\n      \"Foo: 3.50\\n\"\n      \"msg: in sig2 *17*\\n\"\n      \"DONE\";\n    assert (accu == expected);\n  }\n};\nstd::string BasicSignalTests::accu;\n\n\nclass TestCollectorVector {\n  static int handler1   ()  { return 1; }\n  static int handler42  ()  { return 42; }\n  static int handler777 ()  { return 777; }\n  public:\n  static void\n  run ()\n  {\n    Simple::Signal<int (), Simple::CollectorVector<int>> sig_vector;\n    sig_vector.connect(handler777);\n    sig_vector.connect(handler42);\n    sig_vector.connect(handler1);\n    sig_vector.connect(handler42);\n    sig_vector.connect(handler777);\n    std::vector<int> results = sig_vector.emit();\n    const std::vector<int> reference = { 777, 42, 1, 42, 777, };\n    assert(5 == sig_vector.size());\n    assert (results == reference);\n  }\n};\n\nclass TestCollectorUntil0 {\n  bool check1, check2;\n  TestCollectorUntil0() : check1 (0), check2 (0) {}\n  bool handler_true  ()  { check1 = true; return true; }\n  bool handler_false ()  { check2 = true; return false; }\n  bool handler_abort ()  { std::abort(); }\n  public:\n  static void\n  run ()\n  {\n    TestCollectorUntil0 self;\n    Simple::Signal<bool (), Simple::CollectorUntil0<bool>> sig_until0;\n    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_true));\n    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_false));\n    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_abort));\n    assert (!self.check1 && !self.check2);\n    const bool result = sig_until0.emit();\n    assert (!result && self.check1 && self.check2);\n  }\n};\n\nclass TestCollectorWhile0 {\n  bool check1, check2;\n  TestCollectorWhile0() : check1 (0), check2 (0) {}\n  bool handler_0     ()  { check1 = true; return false; }\n  bool handler_1     ()  { check2 = true; return true; }\n  bool handler_abort ()  { std::abort(); }\n  public:\n  static void\n  run ()\n  {\n    TestCollectorWhile0 self;\n    Simple::Signal<bool (), Simple::CollectorWhile0<bool>> sig_while0;\n    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_0));\n    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_1));\n    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_abort));\n    assert (!self.check1 && !self.check2);\n    const bool result = sig_while0.emit();\n    assert (result == true && self.check1 && self.check2);\n  }\n};\n\nstatic void\nbench_simple_signal()\n{\n  Simple::Signal<void (void*, uint64_t)> sig_increment;\n  sig_increment.connect(test_counter_add2);\n  const uint64_t start_counter = TestCounter::get();\n  const uint64_t benchstart = timestamp_benchmark();\n  uint64_t i;\n  for (i = 0; i < 999999; i++)\n    {\n      sig_increment.emit (nullptr, 1);\n    }\n  const uint64_t benchdone = timestamp_benchmark();\n  const uint64_t end_counter = TestCounter::get();\n  assert (end_counter - start_counter == i);\n  printf (\"OK\\n  Benchmark: Simple::Signal: %fns per emission (size=%u): \", size_t (benchdone - benchstart) * 1.0 / size_t (i),\n          (unsigned int) sizeof (sig_increment));\n}\n\nstatic void\nbench_callback_loop()\n{\n  void (*counter_increment) (void*, uint64_t) = test_counter_add2;\n  const uint64_t start_counter = TestCounter::get();\n  const uint64_t benchstart = timestamp_benchmark();\n  uint64_t i;\n  for (i = 0; i < 999999; i++)\n    {\n      counter_increment (nullptr, 1);\n    }\n  const uint64_t benchdone = timestamp_benchmark();\n  const uint64_t end_counter = TestCounter::get();\n  assert (end_counter - start_counter == i);\n  printf (\"OK\\n  Benchmark: callback loop: %fns per round: \", size_t (benchdone - benchstart) * 1.0 / size_t (i));\n}\n\nuint64_t\nTestCounter::get ()\n{\n  return test_counter_var;\n}\n\nvoid\nTestCounter::set (uint64_t v)\n{\n  test_counter_var = v;\n}\n\nvoid\nTestCounter::add2 (void*, uint64_t v)\n{\n  test_counter_var += v;\n}\n\nint\nmain (int   argc,\n      char *argv[])\n{\n  printf (\"Signal/Basic Tests: \");\n  BasicSignalTests::run();\n  printf (\"OK\\n\");\n\n  printf (\"Signal/CollectorVector: \");\n  TestCollectorVector::run();\n  printf (\"OK\\n\");\n\n  printf (\"Signal/CollectorUntil0: \");\n  TestCollectorUntil0::run();\n  printf (\"OK\\n\");\n\n  printf (\"Signal/CollectorWhile0: \");\n  TestCollectorWhile0::run();\n  printf (\"OK\\n\");\n\n  printf (\"Signal/Benchmark: Simple::Signal: \");\n  bench_simple_signal();\n  printf (\"OK\\n\");\n\n  printf (\"Signal/Benchmark: callback loop: \");\n  bench_callback_loop();\n  printf (\"OK\\n\");\n\n  return 0;\n}\n"
  }
]