Giter Club home page Giter Club logo

alloy's Introduction

Alloy version godbolt.badge

Embrace (post) modern C++

Overview

Alloy solves the problem of run-time manipulation of heterogeneous values with more flexibility and expressive power than the tools provided by the standard library.

#include "alloy.hpp"

#include <iostream>
#include <string>
#include <utility>

int main() {
    // suppose you have some data
    auto data = alloy::capture("Hello", ' ', "World" , '!');

    // and means to consume it
    auto print = [](auto&&... data) {
        // we'll simply print to the standard output in this example
        (std::cout << ... << std::forward<decltype(data)>(data)) << std::endl;
    };

    // all you need is to connect the ends
    data >> print; // Hello World!

    // just as easily you can build data pipelines
    auto predicate = [](auto x) {
        return std::string{x} != "!";
    };

    data >> alloy::filter(predicate) >> print; // Hello World

    // with Alloy you can kiss `std::apply` goodbye
    alloy::unpack(std::make_tuple(3, '.', "14")) >> print; // 3.14

    // you can even iterate through tuples in a regular for-loop
    auto tup = std::make_tuple(3, '.', "14");

    for(std::size_t i = 0; i < std::tuple_size<decltype(tup)>{}; ++i)
        alloy::unpack(tup) >> alloy::at(i) >> alloy::prepend(i, ": ") >> print;

    // 0: 3
    // 1: .
    // 2: 14

    // `std::visit` is also a thing of the past
    using var = std::variant<int, char, std::string>;

    var i = 3;
    var c = '.';
    var s = "14";

    alloy::unpack(i, c, s) >> print; // 3.14

    // while you are at it, why not mixing tuples and variants together?
    alloy::unpack(std::make_tuple("pi", '='), i, c, s) >> print; // pi=3.14

    // tuples and variants are too mainstream?
    // not a problem, you can also provide your very own custom data sources
    auto produce = [](auto consume) {
        return consume("Hello", ' ', "World");
    };

    // the following are all equivalent and print Hello World
    alloy::source{produce} >> print;
    produce >> alloy::sink{print};
    alloy::source{produce} >> alloy::sink{print};

    // and your very own streams too
    auto process = [](auto const& sink) {
        return [&sink](auto hello, auto _, auto world) {
            return sink(hello, _, "brave", _, "new", _, world, '!');
        };
    };

    produce >> alloy::stream{process} >> print; // Hello brave new World!

    // embrace (post) modern C++

    auto wrap = [](auto const& sink) {
        return [&sink](auto word) {
            return sink('(', word, ')');
        };
    };

    alloy::forward("post") >> alloy::stream{wrap}
                           >> alloy::prepend("embrace", ' ')
                           >> alloy::append(' ', "modern C++") >> print;
}

Motivation

Have you ever wished std::tuple provided an overload for operator [] just likestd::vector and std::map do?

As you might have guessed, it's actually impossible to overload the subscript operator for tuples, but the reason why might not be obvious at first.

An example is worth a thousand words, so can you guess the type of x below?

auto x = std::make_tuple(1, 1.0, '1', "one")[std::rand() % 4];

The type of x depends on a run-time value and therefore may not be deduced by the compiler, which is thus unable to compile such a program to begin with.

Fine, as long as we are able to, say, filter the elements in a std::tuple based on a predicate, we should be able to tackle most real world problems. That should be easy right?

Nope.

Can you deduce the type of x this time?

template<typename Tuple, typename Predicate>
decltype(auto) filter(Tuple&&, Predicate&&);

auto x = filter(std::make_tuple(1, 1.0, '1', "one"), [](auto&&) {
    return std::rand() % 2;
});

Heck, the predicate doesn't even depend on the elements themselves, but still we are unable to deduce the return type!

Alright, forget about returning values, let's forward results to a callback function instead.

template<typename Tuple, typename Predicate, typename Callback>
void filter(Tuple&&, Predicate&&, Callback&&);

auto predicate = [](auto&&) {
    return std::rand() % 2;
};

auto callback = [](auto&&... /*args*/) { /* ... */ };

filter(std::make_tuple(1, 1.0, '1', "one"), predicate, callback);

That was easy after all... or was it? Let us not forget that we still need to implement filter.

How can the standard library help us get there, you might have asked yourself, and the answer is quite simple in fact: It can't really.

Sure std::apply can help us extract the elements out of the tuple, but that's about all the standard library can do for us, from then on we are on our own.

template<typename Tuple, typename Predicate, typename Callback>
void filter(Tuple&& tuple, Predicate&& predicate, Callback&& callback) {
    constexpr auto impl = [&predicate, &callback](auto&&... elements) {
        // TODO: do the heavy lifting :(
    };

    std::apply(std::forward<Tuple>(tuple), impl);
}

We don't want to keep reinventing the wheel, we want to solve real problems, but for that we need the building blocks.

auto tuple = std::make_tuple(1, 1.0, '1', "one");

auto predicate = [](auto&&) {
    return std::rand() % 2;
};

auto callback = [](auto&&... /*args*/) { /* ... */ };

alloy::unpack(tuple) >> alloy::filter(predicate) >> callback;

We need Alloy.

Quick Start

  1. Download alloy.hpp
  2. # include </path/to/alloy.hpp>
  3. Embrace (post) modern C++

Portability

Alloy requires C++17 and is known to work on GCC and Clang.

License

This project is licensed under the MIT.

alloy's People

Contributors

brunocodutra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

cmakeezer

alloy's Issues

Improve the README

Make a note that we are overloading operator << to do the magic and not to be confused with its usual overloading for io streaming

Should alloy::unpack be implicit?

currently in order to use std::tuples and std::variants as Sources, one has to be explicit:

auto tup = std::make_tuple(1, '1', "one");

alloy::unpack(tup) >> sink; // equivalent to sink(1, '1', "one");

std::variant<int, char, std::string> var = "two"; 

alloy::unpack(var) >> sink; // equivalent to sink("two");

// or even
alloy::unpack(tup, var) >> sink; // equivalent to sink(1, '1', "one", "two");

should alloy::unpack be implicit instead?

auto tup = std::make_tuple(1, '1', "one");

tup >> sink; // equivalent to sink(1, '1', "one");

std::variant<int, char, std::string> var = "two"; 

var >> sink; // equivalent to sink("two");

alloy::join(tup, var) >> sink; // equivalent to sink(1, '1', "one", "two");

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.