All Projects → netromdk → sigs

netromdk / sigs

Licence: MIT license
Simple thread-safe signal/slot C++17 include-only library.

Programming Languages

C++
36643 projects - #6 most used programming language
python
139335 projects - #7 most used programming language
CMake
9771 projects
c
50402 projects - #5 most used programming language

Projects that are alternatives of or similar to sigs

lambda-example
Example REST service for a Lambda article I wrote
Stars: ✭ 23 (-28.12%)
Mutual labels:  lambda
tech1-temple-aws
AWS Proofs of Concepts repository. No Longer Supported
Stars: ✭ 32 (+0%)
Mutual labels:  lambda
serverless-podcast
[UNMAINTAINED] 📢 Easy, cheap podcast hosting using Serverless and S3
Stars: ✭ 15 (-53.12%)
Mutual labels:  lambda
aws-cloudformation-cognito-identity-pool
A Lambda-backed Custom Resource for a Cognito Identity Pool in CloudFormation
Stars: ✭ 35 (+9.38%)
Mutual labels:  lambda
serverless-graalvm-demo
Sample serverless application written in Java compiled with GraalVM native-image
Stars: ✭ 132 (+312.5%)
Mutual labels:  lambda
aws-backup-lambda
A utility AWS lambda function to manage EBS and RDS snapshot backups.
Stars: ✭ 60 (+87.5%)
Mutual labels:  lambda
lambda-runtime-pypy3.5
AWS Lambda Runtime for PyPy 3.5
Stars: ✭ 17 (-46.87%)
Mutual labels:  lambda
slic-watch
Easy alarms and dashboards for Lambda, DynamoDB, API Gateway, Kinesis, Step Functions and more
Stars: ✭ 88 (+175%)
Mutual labels:  lambda
serverless-plugin-parcel
A Serverless framework plugin to bundle assets with Parcel (ES6/7 or Typescript)
Stars: ✭ 23 (-28.12%)
Mutual labels:  lambda
ooso
Java library for running Serverless MapReduce jobs
Stars: ✭ 25 (-21.87%)
Mutual labels:  lambda
terraform-aws-efs-backup
Terraform module designed to easily backup EFS filesystems to S3 using DataPipeline
Stars: ✭ 40 (+25%)
Mutual labels:  lambda
lambda2js
Converts a C# expression tree (from Linq namespace) to a syntatically correct javascript code.
Stars: ✭ 51 (+59.38%)
Mutual labels:  lambda
lambda-ci
CI/CD for Lambda Functions with Jenkins
Stars: ✭ 20 (-37.5%)
Mutual labels:  lambda
jenkinsfile-runner-lambda
Run Jenkinsfiles in AWS Lambda
Stars: ✭ 52 (+62.5%)
Mutual labels:  lambda
cora
Genius programmer should write his own lisp!
Stars: ✭ 40 (+25%)
Mutual labels:  lambda
lambda-lite-js
a tiny FUNCITONAL LANGUAGE implemented by javascript. 一个函数式语言,使用 js 实现。
Stars: ✭ 77 (+140.63%)
Mutual labels:  lambda
terraform-lambda-fixed-ip
Provide a fixed IP (ElasticIP) to your AWS Lambdas
Stars: ✭ 20 (-37.5%)
Mutual labels:  lambda
aws-maven-plugin
Deploys resources to AWS using maven
Stars: ✭ 25 (-21.87%)
Mutual labels:  lambda
signal-msg
Send Signal messages from GNU Emacs using signal-cli
Stars: ✭ 20 (-37.5%)
Mutual labels:  signal
lambda-memory-performance-benchmark
Performance and cost benchmark tool for AWS Lambda on memory sizes 📈⏱
Stars: ✭ 60 (+87.5%)
Mutual labels:  lambda

Test Clang Sanitizers CodeQL

sigs

Simple thread-safe signal/slot C++17 library, which is templated and include-only. No linking required. Just include the header file "sigs.h".

In all its simplicity, the class sigs::Signal implements a signal that can be triggered when some event occurs. To receive the signal slots can be connected to it. A slot can be any callable type: lambda, functor, function, or member function. Slots can be disconnected when not needed anymore.

A signal is triggered by invoking its operator()() with an optional amount of arguments to be forwarded to each of the connected slots' invocations. But they must conform with the parameter types of sigs::Signal::SlotType, which reflects the first template argument given when instantiating a sigs::Signal.

Table of contents

Examples

The most simple use case is having a void() invoked:

sigs::Signal<void()> s;
s.connect([]{ std::cout << "Hello, signals. I'm an invoked slot.\n"; });
s(); // Trigger it, which will call the function.

As mentioned above you can pass arbitrary arguments to the slots but the types will be enforced at compile-time.

sigs::Signal<void(int, const std::string&)> s;
s.connect([](int n, const std::string &str) {
  std::cout << "I received " << n << " and " << str << std::endl;
});

// Prints "I received 42 and I like lambdas!".
s(42, "I like lambdas!");

// Error! "no known conversion from 'char const[5]' to 'int' for 1st argument".
s("hmm?", "I like lambdas!");

When connecting a slot the result is a sigs::Connection, and the connection can be disconnected by calling sigs::Connection::disconnect() or sigs::Signal::disconnect(sigs::Connection).

sigs::Signal<void()> s;
s.connect([]{ std::cout << "Hi"; });
auto conn = s.connect([]{ std::cout << " there!\n"; });

// Prints "Hi there!".
s();

// Disconnect second slot.
conn->disconnect();

// Or by using the signal: s.disconnect(conn);

// Prints "Hi".
s();

Note that all slots can be disconnected by giving no arguments to sigs::Signal::disconnect(), or by calling sigs::Signal::clear().

Slots can be any callable type: lambda, functor, or function. Even member functions.

void func() {
  std::cout << "Called function\n";
}

class Functor {
public:
  void operator()() {
    std::cout << "Called functor\n";
  }
};

class Foo {
public:
  void test() {
    std::cout << "Called member fuction\n";
  }
};

sigs::Signal<void()> s;
s.connect(func);
s.connect([]{ std::cout << "Called lambda\n"; });
s.connect(Functor());

Foo foo;
s.connect(&foo, &Foo::test);

s();

/* Prints:
Called function
Called lambda
Called functor
Called member funtion
*/

Another useful feature is the ability to connect signals to signals. If a first signal is connected to a second signal, and the second signal is triggered, then all of the slots of the first signal are triggered as well - and with the same arguments.

sigs::Signal<void()> s1;
s1.connect([]{ std::cout << "Hello 1 from s1\n"; });
s1.connect([]{ std::cout << "Hello 2 from s1\n"; });

decltype(s1) s2;
s2.connect(s1);

s2();

/* Prints:
Hello 1 from s1
Hello 2 from s1
*/

A signal can be disconnected by using sigs::Signal::disconnect(sigs::Signal&), or the regular sigs::Connection::disconnect().

Ambiguous types

Sometimes there are several overloads for a given function and then it's not enough to just specify &Class::functionName because the compiler does not know which overload to choose.

Consider the following code:

class Ambiguous {
public:
  void foo(int i, int j) { std::cout << "Ambiguous::foo(int, int)\n"; }

  void foo(int i, float j) { std::cout << "Ambiguous::foo(int, float)\n"; }
};

sigs::Signal<void(int, int)> s;

Ambiguous amb;
s.connect(&amb, &Ambiguous::foo); // <-- Will fail!

Instead we must use the sigs::Use<>::overloadOf() construct:

s.connect(&amb, sigs::Use<int, int>::overloadOf(&Ambiguous::foo));
s(42, 48);

/* Prints:
Ambiguous::foo(int, int)
*/

Without changing the signal we can also connect the second overload foo(int, float):

// This one only works because int can be coerced into float.
s.connect(&amb, sigs::Use<int, float>::overloadOf(&Ambiguous::foo));
s(12, 34);

/* Prints:
Ambiguous::foo(int, int)
Ambiguous::foo(int, float)
*/

Return values

If slots have return values they can be gathered by triggering the signal with a function. But the argument type must be the same as the return type!

The following example adds together the integers from each connected slot:

sigs::Signal<int()> s;
s.connect([] { return 1; });
s.connect([] { return 2; });
s.connect([] { return 3; });

int sum = 0;
s([&sum](int retVal) { sum += retVal; });
// sum is now = 1 + 2 + 3 = 6

Signal interface

When a signal is used in an abstraction one most often doesn't want it exposed directly as a public member since it destroys encapsulation. sigs::Signal::interface() can be used instead to only expose connect and disconnect methods of the signal - it is a std::unique_ptr<sigs::Signal::Interface> wrapper instance.

The example shows a button abstraction where actions can easily be added or removed while preserving the encapsulation of the signal:

class Button {
public:
  void click()
  {
    clickSignal_();
  }

  [[nodiscard]] auto clickSignal()
  {
    return clickSignal_.interface();
  }

private:
  sigs::Signal<void()> clickSignal_;
};

int main()
{
  Button btn;
  btn.clickSignal()->connect([] { std::cout << "direct fn" << std::endl; });
  btn.clickSignal()->connect([] { std::cout << "direct fn 2" << std::endl; });

  auto conn = btn.clickSignal()->connect([] { std::cout << "you won't see me" << std::endl; });
  conn->disconnect();

  btn.click();
  return 0;
}

Blocking signals and slots

Sometimes it is necessary to block a signal, and any recursive signals, from triggering. That is achieved through sigs::Signal::setBlocked(bool) and sigs::Signal::blocked():

sigs::Signal<void()> s;
s.connect([] { /* .. */ });
s.connect([] { /* .. */ });
s.setBlocked(true);

// No slots will be triggered since the signal is blocked.
s();

To make things simpler, the sigs::SignalBlocker class utilizes the RAII idiom to block/unblock via its own scoped lifetime:

sigs::Signal<void()> s;
s.connect([] { /* .. */ });
s.connect([] { /* .. */ });

{
  sigs::SignalBlocker<void()> blocker(s);

  // No slots will be triggered since the signal is blocked.
  s();
}

// All connected slots are triggered since the signal is no longer blocked.
s();

Customizing lock and mutex types

The default signal type sigs::Signal<T> is actually short for sigs::BasicSignal<T, sigs::BasicLock> (with sigs::BasicLock = std::lock_guard<std::mutex>). Thus the lock type is std::lock_guard and the mutex type is std::mutex.

Custom lock and mutex types can be supplied by defining a new type, for instance:

template <typename T>
using MySignal = sigs::BasicSignal<T, MyLock>;

The required lock and mutex interfaces are as follows:

class Mutex {
public:
  void lock();
  void unlock();
};

template <typename Mutex>
class Lock {
public:
  using mutex_type = Mutex;

  explicit Lock(Mutex &);
};

The lock type is supposed to lock/unlock following the RAII idiom.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].