• Stars
    star
    207
  • Rank 189,087 (Top 4 %)
  • Language
    C++
  • License
    Boost Software Li...
  • Created about 5 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Transducers for C++ — Clojure style higher order push/pull sequence transformations
Github Actions Badge CodeCov Badge Sinusoidal Engineering badge

Logotype

zug is a C++ library providing transducers. Transducers are composable sequential transformations independent of the source. They are extremely lightweight, and can be used to express algorithms over pull-based sequences (iterators, files) but also push based sequences (signals, events, asynchronous streams) in a generic way.

This project is part of a long-term vision helping interactive and concurrent C++ programs become easier to write. Help this project's long term sustainability by becoming a patron or buying a sponsorship package: [email protected]

Example

auto xf = zug::filter([](int x) { return x > 0; })
        | zug::map([](int x) { return std::to_string(x); });

Here xf is a transducer, a transformation over a sequence of integers, resulting in a sequence of strings. Note, however, that this transformation makes no reference to whatever it is transforming. In fact, we can apply it in many ways.

Transforming a range

auto data1 = std::vector<int>{3, -2, 42, -10};
auto data2 = zug::into(std::vector<std::string>{}, xf, data1);
assert(data2 == {"3", "42"});

As a lazy iterator

auto data1 = std::vector<int>{ ... };
auto data2 = zug::sequence(xf, data1);
std::copy(data2.begin(), data2.end(), ...);

Generators and sinks

zug::run(zug::read<int>(std::cin) | xf |
         zug::write(std::cout));

Reads integers from the terminal and outputs back the positive ones.

Transforming cursors

The library is used in Lager, a library implementing the unidirectional data-flow architecture for C++ interactive applications. It is used to treat reactive values as a temporal sequence that can be transformed in arbitrary ways. For example:

auto x = lager::state<int>{42};
auto y = lager::reader<std::string>{x.xform(xf)}
y.watch([] (auto&& v) { std::cout << v << std::endl; });
x.set(10); // outputs: 10
x.set(-2); // no output

Why?

You have learn Sean Parent's lesson: No Raw Loops. Instead of iterating over sequences directly, you use STL algoriths like transform, filter, etc, or even better, the new ranges library.

However, what if you have a sequence that can not be easily or efficiently expressed as an iterator? Then, you may have to reimplement all these algorithms again, on top of whatever sequence abstraction you have invented, for example, see RxCpp... Or you use transducers.

Transducers are generic algorithmic transformations, in a way that is completely agnostic of the actual sequence that is being transformed. As a library author, you can add transducer support for your library, and automatically get access to our wide collection of transducers and allow your users to simply write their own.

Dependencies

This library is written in C++14 and a compliant compiler is necessary. It is continuously tested with Clang 3.8 and GCC 6, but it might work with other compilers and versions.

If compiling with C++14 and using skip, boost variant is required.

For C++17 and above, no external library is necessary and there are no other requirements.

Usage

This is a header only library but to be configured correctly you need to run CMake first:

mkdir -p build && cd build
cmake ..

Or you can just copy the zug subfolder somewhere in your include path.

Development

In order to develop the library, you will need to compile and run the examples, tests and benchmarks. These require some additional tools. The easiest way to install them is by using the Nix package manager. At the root of the repository just type:

nix-shell

This will download all required dependencies and create an isolated environment in which you can use these dependencies, without polluting your system.

Then you can proceed to generate a development project using CMake:

mkdir build && cd build
cmake ..

From then on, one may build and run all tests by doing:

make check

License

Boost logo

This software is licensed under the Boost Software License 1.0.

The full text of the license is can be accessed via this link and is also included in the LICENSE file of this software package.

More Repositories

1

immer

Postmodern immutable and persistent data structures for C++ — value semantics at scale
C++
2,491
star
2

lager

C++ library for value-oriented design using the unidirectional data-flow architecture — Redux for C++
C++
641
star
3

ewig

The eternal text editor — Didactic Ersatz Emacs to show immutable data-structures and the single-atom architecture
C++
531
star
4

psychosynth

GNU Psychosynth is a a synthesizer and modular audio framework inspired by the ideas of the Reactable.
C++
58
star
5

schmutz

SCHeMe UnterstüTZung — easy Guile Scheme C++ bindings
C++
41
star
6

mixco

Mixco is a framework for creating hardware controller scripts for the amazing Mixxx DJ software
CoffeeScript
28
star
7

heterarchy

Cooperative multiple inheritance for CoffeeScript, à-la Python. http://sinusoid.es/heterarchy/
CoffeeScript
12
star
8

gnujump

Official mirror of GNU Jump, a simple yet addictive jumping game. https://jump.gnu.sinusoid.es
Shell
6
star
9

cooper

Easy and safe cooperative methods for Python
Python
5
star
10

sinusoides

∿∿∿ code for my personal website at https://sinusoid.es ∿∿∿
JavaScript
4
star
11

noxim-3d

Fork of the Noxim NoC simulator for the exploration of 3D networks.
C++
4
star
12

dotfiles

Look ma, I also git my dotfiles!
Emacs Lisp
3
star
13

mixxx-db-tools

Personal tools for manipulating the Mixxx library data-base
Python
2
star
14

jpblib

Jolly Python Basic Library http://www.sinusoid.es/jpblib/
Python
1
star
15

mittagessen

Randomly choose where to go for lunch
Clojure
1
star
16

overdose

A stupid game I made in uni very long ago...
C++
1
star