Full Code of larspensjo/SimpleSignal for AI

master 0c337f1a8fbd cached
4 files
15.6 KB
4.1k tokens
38 symbols
1 requests
Download .txt
Repository: larspensjo/SimpleSignal
Branch: master
Commit: 0c337f1a8fbd
Files: 4
Total size: 15.6 KB

Directory structure:
gitextract_60vfiz5h/

├── .gitignore
├── README.md
├── SimpleSignal.h
└── test.cpp

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/*.exe


================================================
FILE: README.md
================================================
# High performance C++11 signals
See [Performance of a C++11 Signal System](http://www.testbit.eu/2013/cpp11-signal-system-performance/) for
the original source code, as well as performance measurements compared to other signalling systems.

The 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/).
## Declare a signal
This example declares a signal 'sig' that takes three arguments and returns a char.
```c++
Simple::Signal<char (float, int, std::string)> sig;
```
## Connect to a signal
This example connects 'sig' to a static function.
It is also possible to connect to member functions or lambda functions.
```c++
static char float_callback (float f, int, std::string) {
  // ...
  return 0;
}

void Init() {
  sig.connect(float_callback);
}
```
## Fire a signal
```c++
void func() {
  // ...
  sig.emit(1.0f, 7, "xxxx");
}
```


================================================
FILE: SimpleSignal.h
================================================
// CC0 Public Domain: http://creativecommons.org/publicdomain/zero/1.0/
#pragma once

#include <memory>
#include <functional>
#include <list>
#include <vector>
#include <algorithm>

namespace Simple {

namespace Lib {

/// ProtoSignal is the template implementation for callback list.
template<typename,typename> class ProtoSignal;   // undefined

/// CollectorInvocation invokes signal handlers differently depending on return type.
template<typename,typename> struct CollectorInvocation;

/// CollectorLast returns the result of the last signal handler from a signal emission.
template<typename Result>
struct CollectorLast {
  using CollectorResult = Result;
  explicit        CollectorLast ()              : last_() {}
  inline bool     operator()    (Result r)      { last_ = r; return true; }
  CollectorResult result        ()              { return last_; }
private:
  Result last_;
};

/// CollectorDefault implements the default signal handler collection behaviour.
template<typename Result>
struct CollectorDefault : CollectorLast<Result>
{};

/// CollectorDefault specialisation for signals with void return type.
template<>
struct CollectorDefault<void> {
  using CollectorResult = void;
  void                  result     ()           {}
  inline bool           operator() (void)       { return true; }
};

/// CollectorInvocation specialisation for regular signals.
template<class Collector, class R, class... Args>
struct CollectorInvocation<Collector, R (Args...)> {
  inline bool
  invoke (Collector &collector, const std::function<R (Args...)> &cbf, Args... args) const
  {
    return collector (cbf (args...));
  }
};

/// CollectorInvocation specialisation for signals with void return type.
template<class Collector, class... Args>
struct CollectorInvocation<Collector, void (Args...)> {
  inline bool
  invoke (Collector &collector, const std::function<void (Args...)> &cbf, Args... args) const
  {
    cbf (args...); return collector();
  }
};

/// ProtoSignal template specialised for the callback signature and collector.
template<class Collector, class R, class... Args>
class ProtoSignal<R (Args...), Collector> : private CollectorInvocation<Collector, R (Args...)> {
protected:
  using CbFunction = std::function<R (Args...)>;
  using Result = typename CbFunction::result_type;
  using CollectorResult = typename Collector::CollectorResult;

private:
  /*copy-ctor*/ ProtoSignal (const ProtoSignal&) = delete;
  ProtoSignal&  operator=   (const ProtoSignal&) = delete;

  using CallbackSlot = std::shared_ptr<CbFunction>;
  using CallbackList = std::list<CallbackSlot>;
  CallbackList callback_list_;

  size_t add_cb(const CbFunction& cb)
  {
    callback_list_.emplace_back(std::make_shared<CbFunction>(cb));
    return size_t (callback_list_.back().get());
  }

  bool remove_cb(size_t id)
  {
    auto it =std::remove_if(begin(callback_list_), end(callback_list_),
                            [id](const CallbackSlot& slot) { return size_t(slot.get()) == id; });
    bool const removed = it != end(callback_list_);
    callback_list_.erase(it, end(callback_list_));
    return removed;
  }

public:
  /// ProtoSignal constructor, connects default callback if non-nullptr.
  ProtoSignal (const CbFunction &method)
  {
    if (method)
      add_cb(method);
  }
  /// ProtoSignal destructor releases all resources associated with this signal.
  ~ProtoSignal ()
  {
  }

  /// Operator to add a new function or lambda as signal handler, returns a handler connection ID.
  size_t connect (const CbFunction &cb)      { return add_cb(cb); }
  /// Operator to remove a signal handler through it connection ID, returns if a handler was removed.
  bool   disconnect (size_t connection)         { return remove_cb(connection); }

  /// Emit a signal, i.e. invoke all its callbacks and collect return types with the Collector.
  CollectorResult
  emit (Args... args) const
  {
    Collector collector;
    for (auto &slot : callback_list_) {
        if (slot) {
            const bool continue_emission = this->invoke (collector, *slot, args...);
            if (!continue_emission)
              break;
        }
    }
    return collector.result();
  }
  // Number of connected slots.
  std::size_t
  size () const
  {
    return callback_list_.size();
  }
};

} // Lib
// namespace Simple

/**
 * Signal is a template type providing an interface for arbitrary callback lists.
 * A signal type needs to be declared with the function signature of its callbacks,
 * and optionally a return result collector class type.
 * Signal callbacks can be added with operator+= to a signal and removed with operator-=, using
 * a callback connection ID return by operator+= as argument.
 * The callbacks of a signal are invoked with the emit() method and arguments according to the signature.
 * The result returned by emit() depends on the signal collector class. By default, the result of
 * the last callback is returned from emit(). Collectors can be implemented to accumulate callback
 * results or to halt a running emissions in correspondance to callback results.
 * The signal implementation is safe against recursion, so callbacks may be removed and
 * added during a signal emission and recursive emit() calls are also safe.
 * The overhead of an unused signal is intentionally kept very low, around the size of a single pointer.
 * Note that the Signal template types is non-copyable.
 */
template <typename SignalSignature, class Collector = Lib::CollectorDefault<typename std::function<SignalSignature>::result_type> >
struct Signal /*final*/ :
    Lib::ProtoSignal<SignalSignature, Collector>
{
  using ProtoSignal = Lib::ProtoSignal<SignalSignature, Collector>;
  using CbFunction = typename ProtoSignal::CbFunction;
  /// Signal constructor, supports a default callback as argument.
  Signal (const CbFunction &method = CbFunction()) : ProtoSignal (method) {}
};

/// This function creates a std::function by binding @a object to the member function pointer @a method.
template<class Instance, class Class, class R, class... Args> std::function<R (Args...)>
slot (Instance &object, R (Class::*method) (Args...))
{
  return [&object, method] (Args... args) { return (object .* method) (args...); };
}

/// This function creates a std::function by binding @a object to the member function pointer @a method.
template<class Class, class R, class... Args> std::function<R (Args...)>
slot (Class *object, R (Class::*method) (Args...))
{
  return [object, method] (Args... args) { return (object ->* method) (args...); };
}

/// Keep signal emissions going while all handlers return !0 (true).
template<typename Result>
struct CollectorUntil0 {
  using CollectorResult = Result;
  explicit                      CollectorUntil0 ()      : result_() {}
  const CollectorResult&        result          ()      { return result_; }
  inline bool
  operator() (Result r)
  {
    result_ = r;
    return result_ ? true : false;
  }
private:
  CollectorResult result_;
};

/// Keep signal emissions going while all handlers return 0 (false).
template<typename Result>
struct CollectorWhile0 {
  using CollectorResult = Result;
  explicit                      CollectorWhile0 ()      : result_() {}
  const CollectorResult&        result          ()      { return result_; }
  inline bool
  operator() (Result r)
  {
    result_ = r;
    return result_ ? false : true;
  }
private:
  CollectorResult result_;
};

/// CollectorVector returns the result of the all signal handlers from a signal emission in a std::vector.
template<typename Result>
struct CollectorVector {
  using CollectorResult = std::vector<Result>;
  const CollectorResult&        result ()       { return result_; }
  inline bool
  operator() (Result r)
  {
    result_.push_back (r);
    return true;
  }
private:
  CollectorResult result_;
};

} // Simple


================================================
FILE: test.cpp
================================================
#include "SimpleSignal.h"

// g++ -Wall -O2 -std=gnu++11 -pthread test.cpp && ./a.out
// append -fsanitize=address for memory debugging

#include <string>
#include <stdarg.h>
#include <time.h>
#include <ctime>
#include <cstdlib>
#include <cassert>

#ifndef _MSC_VER
#include <sys/time.h>
#include <stdio.h>
static std::string string_printf (const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
#endif

static std::string
string_printf (const char *format, ...)
{
  std::string result;
  char str[1000];
  va_list args;
  va_start (args, format);
  if (vsnprintf (str, sizeof str, format, args) >= 0)
    result = str;
  va_end (args);
  return result;
}

static uint64_t
timestamp_benchmark ()
{
  auto now = std::clock();
  return 1.0e9 / CLOCKS_PER_SEC * now;
}

struct TestCounter {
  static uint64_t get     ();
  static void     set     (uint64_t);
  static void     add2    (void*, uint64_t);
};

namespace { // Anon
void        (*test_counter_add2) (void*, uint64_t) = TestCounter::add2; // external symbol to prevent easy inlining
static uint64_t test_counter_var = 0;
} // Anon

class BasicSignalTests {
  static std::string accu;
  struct Foo {
    char
    foo_bool (float f, int i, std::string s)
    {
      accu += string_printf ("Foo: %.2f\n", f + i + s.size());
      return true;
    }
  };
  static char
  float_callback (float f, int, std::string)
  {
    accu += string_printf ("float: %.2f\n", f);
    return 0;
  }
public:
  static void
  run()
  {
    accu = "";
    Simple::Signal<char (float, int, std::string)> sig1;
    size_t id1 = sig1.connect(float_callback);
    size_t id2 = sig1.connect([] (float, int i, std::string) { accu += string_printf ("int: %d\n", i); return 0; });
    size_t id3 = sig1.connect([] (float, int, const std::string &s) { accu += string_printf ("string: %s\n", s.c_str()); return 0; });
    sig1.emit (.3, 4, "huhu");
    bool success;
    success = sig1.disconnect(id1); assert (success == true);  success = sig1.disconnect(id1); assert (success == false);
    success = sig1.disconnect(id2); assert (success == true);  success = sig1.disconnect(id3); assert (success == true);
    success = sig1.disconnect(id3); assert (success == false); success = sig1.disconnect(id2); assert (success == false);
    Foo foo;
    sig1.connect(Simple::slot (foo, &Foo::foo_bool));
    sig1.connect(Simple::slot (&foo, &Foo::foo_bool));
    sig1.emit (.5, 1, "12");

    Simple::Signal<void (std::string, int)> sig2;
    sig2.connect([] (std::string msg, int) { accu += string_printf ("msg: %s", msg.c_str()); });
    sig2.connect([] (std::string, int d)   { accu += string_printf (" *%d*\n", d); });
    sig2.emit ("in sig2", 17);

    accu += "DONE";

    const char *expected =
      "float: 0.30\n"
      "int: 4\n"
      "string: huhu\n"
      "Foo: 3.50\n"
      "Foo: 3.50\n"
      "msg: in sig2 *17*\n"
      "DONE";
    assert (accu == expected);
  }
};
std::string BasicSignalTests::accu;


class TestCollectorVector {
  static int handler1   ()  { return 1; }
  static int handler42  ()  { return 42; }
  static int handler777 ()  { return 777; }
  public:
  static void
  run ()
  {
    Simple::Signal<int (), Simple::CollectorVector<int>> sig_vector;
    sig_vector.connect(handler777);
    sig_vector.connect(handler42);
    sig_vector.connect(handler1);
    sig_vector.connect(handler42);
    sig_vector.connect(handler777);
    std::vector<int> results = sig_vector.emit();
    const std::vector<int> reference = { 777, 42, 1, 42, 777, };
    assert(5 == sig_vector.size());
    assert (results == reference);
  }
};

class TestCollectorUntil0 {
  bool check1, check2;
  TestCollectorUntil0() : check1 (0), check2 (0) {}
  bool handler_true  ()  { check1 = true; return true; }
  bool handler_false ()  { check2 = true; return false; }
  bool handler_abort ()  { std::abort(); }
  public:
  static void
  run ()
  {
    TestCollectorUntil0 self;
    Simple::Signal<bool (), Simple::CollectorUntil0<bool>> sig_until0;
    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_true));
    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_false));
    sig_until0.connect(Simple::slot (self, &TestCollectorUntil0::handler_abort));
    assert (!self.check1 && !self.check2);
    const bool result = sig_until0.emit();
    assert (!result && self.check1 && self.check2);
  }
};

class TestCollectorWhile0 {
  bool check1, check2;
  TestCollectorWhile0() : check1 (0), check2 (0) {}
  bool handler_0     ()  { check1 = true; return false; }
  bool handler_1     ()  { check2 = true; return true; }
  bool handler_abort ()  { std::abort(); }
  public:
  static void
  run ()
  {
    TestCollectorWhile0 self;
    Simple::Signal<bool (), Simple::CollectorWhile0<bool>> sig_while0;
    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_0));
    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_1));
    sig_while0.connect(Simple::slot (self, &TestCollectorWhile0::handler_abort));
    assert (!self.check1 && !self.check2);
    const bool result = sig_while0.emit();
    assert (result == true && self.check1 && self.check2);
  }
};

static void
bench_simple_signal()
{
  Simple::Signal<void (void*, uint64_t)> sig_increment;
  sig_increment.connect(test_counter_add2);
  const uint64_t start_counter = TestCounter::get();
  const uint64_t benchstart = timestamp_benchmark();
  uint64_t i;
  for (i = 0; i < 999999; i++)
    {
      sig_increment.emit (nullptr, 1);
    }
  const uint64_t benchdone = timestamp_benchmark();
  const uint64_t end_counter = TestCounter::get();
  assert (end_counter - start_counter == i);
  printf ("OK\n  Benchmark: Simple::Signal: %fns per emission (size=%u): ", size_t (benchdone - benchstart) * 1.0 / size_t (i),
          (unsigned int) sizeof (sig_increment));
}

static void
bench_callback_loop()
{
  void (*counter_increment) (void*, uint64_t) = test_counter_add2;
  const uint64_t start_counter = TestCounter::get();
  const uint64_t benchstart = timestamp_benchmark();
  uint64_t i;
  for (i = 0; i < 999999; i++)
    {
      counter_increment (nullptr, 1);
    }
  const uint64_t benchdone = timestamp_benchmark();
  const uint64_t end_counter = TestCounter::get();
  assert (end_counter - start_counter == i);
  printf ("OK\n  Benchmark: callback loop: %fns per round: ", size_t (benchdone - benchstart) * 1.0 / size_t (i));
}

uint64_t
TestCounter::get ()
{
  return test_counter_var;
}

void
TestCounter::set (uint64_t v)
{
  test_counter_var = v;
}

void
TestCounter::add2 (void*, uint64_t v)
{
  test_counter_var += v;
}

int
main (int   argc,
      char *argv[])
{
  printf ("Signal/Basic Tests: ");
  BasicSignalTests::run();
  printf ("OK\n");

  printf ("Signal/CollectorVector: ");
  TestCollectorVector::run();
  printf ("OK\n");

  printf ("Signal/CollectorUntil0: ");
  TestCollectorUntil0::run();
  printf ("OK\n");

  printf ("Signal/CollectorWhile0: ");
  TestCollectorWhile0::run();
  printf ("OK\n");

  printf ("Signal/Benchmark: Simple::Signal: ");
  bench_simple_signal();
  printf ("OK\n");

  printf ("Signal/Benchmark: callback loop: ");
  bench_callback_loop();
  printf ("OK\n");

  return 0;
}
Download .txt
gitextract_60vfiz5h/

├── .gitignore
├── README.md
├── SimpleSignal.h
└── test.cpp
Download .txt
SYMBOL INDEX (38 symbols across 2 files)

FILE: SimpleSignal.h
  function namespace (line 10) | namespace Simple {
  function invoke (line 57) | inline bool
  function add_cb (line 80) | size_t add_cb(const CbFunction& cb)
  function remove_cb (line 86) | bool remove_cb(size_t id)
  function connect (line 108) | size_t connect (const CbFunction &cb)      { return add_cb(cb); }
  function disconnect (line 110) | bool   disconnect (size_t connection)         { return remove_cb(connect...
  function CollectorResult (line 113) | CollectorResult
  type Signal (line 153) | struct Signal
  function ProtoSignal (line 159) | ProtoSignal (method) {}
  function CollectorResult (line 212) | const CollectorResult&        result ()       { return result_; }

FILE: test.cpp
  function string_printf (line 19) | static std::string
  function timestamp_benchmark (line 32) | static uint64_t
  type TestCounter (line 39) | struct TestCounter {
  class BasicSignalTests (line 50) | class BasicSignalTests {
    type Foo (line 52) | struct Foo {
      method foo_bool (line 53) | char
    method float_callback (line 60) | static char
    method run (line 67) | static void
  class TestCollectorVector (line 106) | class TestCollectorVector {
    method handler1 (line 107) | static int handler1   ()  { return 1; }
    method handler42 (line 108) | static int handler42  ()  { return 42; }
    method handler777 (line 109) | static int handler777 ()  { return 777; }
    method run (line 111) | static void
  class TestCollectorUntil0 (line 127) | class TestCollectorUntil0 {
    method TestCollectorUntil0 (line 129) | TestCollectorUntil0() : check1 (0), check2 (0) {}
    method handler_true (line 130) | bool handler_true  ()  { check1 = true; return true; }
    method handler_false (line 131) | bool handler_false ()  { check2 = true; return false; }
    method handler_abort (line 132) | bool handler_abort ()  { std::abort(); }
    method run (line 134) | static void
  class TestCollectorWhile0 (line 148) | class TestCollectorWhile0 {
    method TestCollectorWhile0 (line 150) | TestCollectorWhile0() : check1 (0), check2 (0) {}
    method handler_0 (line 151) | bool handler_0     ()  { check1 = true; return false; }
    method handler_1 (line 152) | bool handler_1     ()  { check2 = true; return true; }
    method handler_abort (line 153) | bool handler_abort ()  { std::abort(); }
    method run (line 155) | static void
  function bench_simple_signal (line 169) | static void
  function bench_callback_loop (line 188) | static void
  function main (line 223) | int
Condensed preview — 4 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (17K chars).
[
  {
    "path": ".gitignore",
    "chars": 7,
    "preview": "/*.exe\n"
  },
  {
    "path": "README.md",
    "chars": 935,
    "preview": "# High performance C++11 signals\nSee [Performance of a C++11 Signal System](http://www.testbit.eu/2013/cpp11-signal-syst"
  },
  {
    "path": "SimpleSignal.h",
    "chars": 7838,
    "preview": "// CC0 Public Domain: http://creativecommons.org/publicdomain/zero/1.0/\n#pragma once\n\n#include <memory>\n#include <functi"
  },
  {
    "path": "test.cpp",
    "chars": 7205,
    "preview": "#include \"SimpleSignal.h\"\n\n// g++ -Wall -O2 -std=gnu++11 -pthread test.cpp && ./a.out\n// append -fsanitize=address for m"
  }
]

About this extraction

This page contains the full source code of the larspensjo/SimpleSignal GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4 files (15.6 KB), approximately 4.1k tokens, and a symbol index with 38 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!