Skip to content

A small utility library for chaining arbitrary callables

License

Notifications You must be signed in to change notification settings

helmesjo/pipeable

Repository files navigation

Cpp Standard Linux & macOS Windows

pipeable

Just want to invoke some callable object, take the result and forward to another callable, and another, and another..? A small library I needed that others might find useful.

I don't know functional programming, so I probably bring a pretty poor name-game. Got better names at hand? I gladly accept feedback!

TL;DR:

#include <pipeable/pipeable.hpp>
// ...

// Bring "pipe" operator into scope
using pipeable::operator>>=;

struct extract_number
{
  int operator()(string input);
};

struct number_plus
{
  number_plus(int val);
  int operator()(int input);
};

int main(int argc, char *argv[])
{
  int specialNumber = "my nr 1 hat" >>= extract_number() >>= number_plus(5);
  cout << specialNumber; // output: 6
  
  return 0;
}

Interceptors:

A special callable capable of "intercepting" the invocation chain and inject custom logic. As first argument it will receive a callable representing the downstream pipeline (to be invoked by the interceptor).

for_each example:

// Pass lambda to "make_interceptor" with first argument as generic. Rest is desired input
auto for_each = pipeable::assembly::make_interceptor(
  [](auto&& downstream, const vector& values){
    for(const int& value : values)
    {
      downstream(value); // will call print_to_stdout()
    }
  });

struct print_to_stdout
{
  void operator()(int val) { cout << val; }
};

vector{1, 2, 3} >>= for_each >>= print_to_stdout();
// output: 1 2 3

Built-in interceptors:

  • for_each: Iterate left-hand iterable and forward each individual value to downstream.
  • visit: Apply the visitor pattorn (std::visit) to left-hand std::variant<...> and invoke on downstream.
  • unpack: Unpack left-hand tuple and pass elements as individual arguments to downstream.
  • maybe: Forward left-hand optional value to downstream if it exists, else do nothing.

Data Generator:

A callable storing other callables to-be-invoked whenever new data is generated (observer pattern).

#include <pipeable/data_generator.hpp>

struct print_to_stdout
{
  void operator()(int val) { cout << val; }
};

data_generator<int> myGenerator;
print_to_stdout receiver;
myGenerator += &receiver;   // Register receiver

myGenerator(1);             // output: 1
1 >>= myGenerator;          // output: 1

myGenerator -= &receiver;   // Deregister receiver
myGenerator(1);             // No output

Data Source:

An iterable type to be "pulled" for data until no more exists.

#include <pipeable/data_source.hpp>

struct int_source final : public data_source<int>
{
    std::optional<int> next() override
    {
        return current_ < 100 ? std::optional<int>{current_++} : std::nullopt;
    }
    int current_ = 0;
};

struct print_to_stdout
{
  void operator()(int val) { cout << val; }
};

int_source mySource;

mySource >>= for_each >>= print_to_stdout();
// output: 0 ... 99

Build & Install

From source:

  1. mkdir build && cd build
  2. cmake .. && cmake --build .
    • Run tests: ctest
  3. cmake --build . --target install

From conan:

  • Name: pipeable/0.2@helmesjo/stable
  • Repo: https://helmesjo.jfrog.io/artifactory/api/conan/public-conan

Releases

No releases published

Packages

No packages published

Languages