Skip to content

A small utility library for chaining arbitrary callables

License

Notifications You must be signed in to change notification settings

helmesjo/pipeable

Folders and files

NameName
Last commit message
Last commit date

Latest commit

727bcd7 · May 28, 2021

History

77 Commits
Jan 11, 2020
Sep 17, 2020
Feb 15, 2020
Sep 17, 2020
Sep 17, 2020
Oct 26, 2019
Sep 17, 2020
May 14, 2021
Sep 17, 2020
Oct 26, 2019
May 28, 2021
May 14, 2021
Oct 29, 2019
Sep 17, 2020

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