{"id":17188746,"url":"https://github.com/brunocodutra/alloy","last_synced_at":"2025-04-13T19:22:21.810Z","repository":{"id":48294477,"uuid":"75228347","full_name":"brunocodutra/alloy","owner":"brunocodutra","description":"Embrace (post) modern C++","archived":false,"fork":false,"pushed_at":"2021-10-24T17:43:06.000Z","size":305,"stargazers_count":9,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-27T10:02:03.365Z","etag":null,"topics":["cpp","cpp17","heterogeneous-algorithms","tuples","variants","visitor"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brunocodutra.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-30T21:23:18.000Z","updated_at":"2023-12-19T03:02:04.000Z","dependencies_parsed_at":"2022-09-19T00:02:04.136Z","dependency_job_id":null,"html_url":"https://github.com/brunocodutra/alloy","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brunocodutra%2Falloy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brunocodutra%2Falloy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brunocodutra%2Falloy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brunocodutra%2Falloy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brunocodutra","download_url":"https://codeload.github.com/brunocodutra/alloy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248766687,"owners_count":21158302,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp17","heterogeneous-algorithms","tuples","variants","visitor"],"created_at":"2024-10-15T01:09:46.047Z","updated_at":"2025-04-13T19:22:21.779Z","avatar_url":"https://github.com/brunocodutra.png","language":"C++","readme":"# Alloy [![version]][semver] [![godbolt.badge]][godbolt.alloy]\nEmbrace (post) modern C++\n\n## Overview\n\n**Alloy** solves the problem of run-time manipulation of heterogeneous values\nwith more flexibility and expressive power than the tools provided by the\nstandard library.\n\n```.cpp\n#include \"alloy.hpp\"\n\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cutility\u003e\n\nint main() {\n    // suppose you have some data\n    auto data = alloy::capture(\"Hello\", ' ', \"World\" , '!');\n\n    // and means to consume it\n    auto print = [](auto\u0026\u0026... data) {\n        // we'll simply print to the standard output in this example\n        (std::cout \u003c\u003c ... \u003c\u003c std::forward\u003cdecltype(data)\u003e(data)) \u003c\u003c std::endl;\n    };\n\n    // all you need is to connect the ends\n    data \u003e\u003e print; // Hello World!\n\n    // just as easily you can build data pipelines\n    auto predicate = [](auto x) {\n        return std::string{x} != \"!\";\n    };\n\n    data \u003e\u003e alloy::filter(predicate) \u003e\u003e print; // Hello World\n\n    // with Alloy you can kiss `std::apply` goodbye\n    alloy::unpack(std::make_tuple(3, '.', \"14\")) \u003e\u003e print; // 3.14\n\n    // you can even iterate through tuples in a regular for-loop\n    auto tup = std::make_tuple(3, '.', \"14\");\n\n    for(std::size_t i = 0; i \u003c std::tuple_size\u003cdecltype(tup)\u003e{}; ++i)\n        alloy::unpack(tup) \u003e\u003e alloy::at(i) \u003e\u003e alloy::prepend(i, \": \") \u003e\u003e print;\n\n    // 0: 3\n    // 1: .\n    // 2: 14\n\n    // `std::visit` is also a thing of the past\n    using var = std::variant\u003cint, char, std::string\u003e;\n\n    var i = 3;\n    var c = '.';\n    var s = \"14\";\n\n    alloy::unpack(i, c, s) \u003e\u003e print; // 3.14\n\n    // while you are at it, why not mixing tuples and variants together?\n    alloy::unpack(std::make_tuple(\"pi\", '='), i, c, s) \u003e\u003e print; // pi=3.14\n\n    // tuples and variants are too mainstream?\n    // not a problem, you can also provide your very own custom data sources\n    auto produce = [](auto consume) {\n        return consume(\"Hello\", ' ', \"World\");\n    };\n\n    // the following are all equivalent and print Hello World\n    alloy::source{produce} \u003e\u003e print;\n    produce \u003e\u003e alloy::sink{print};\n    alloy::source{produce} \u003e\u003e alloy::sink{print};\n\n    // and your very own streams too\n    auto process = [](auto const\u0026 sink) {\n        return [\u0026sink](auto hello, auto _, auto world) {\n            return sink(hello, _, \"brave\", _, \"new\", _, world, '!');\n        };\n    };\n\n    produce \u003e\u003e alloy::stream{process} \u003e\u003e print; // Hello brave new World!\n\n    // embrace (post) modern C++\n\n    auto wrap = [](auto const\u0026 sink) {\n        return [\u0026sink](auto word) {\n            return sink('(', word, ')');\n        };\n    };\n\n    alloy::forward(\"post\") \u003e\u003e alloy::stream{wrap}\n                           \u003e\u003e alloy::prepend(\"embrace\", ' ')\n                           \u003e\u003e alloy::append(' ', \"modern C++\") \u003e\u003e print;\n}\n```\n\n## Motivation\n\nHave you ever wished `std::tuple` provided an overload for `operator []` just\nlike`std::vector` and `std::map` do?\n\nAs you might have guessed, it's actually impossible to overload the subscript\noperator for tuples, but the reason why might not be obvious at first.\n\nAn example is worth a thousand words, so can you guess the type of `x` below?\n\n```.cpp\nauto x = std::make_tuple(1, 1.0, '1', \"one\")[std::rand() % 4];\n```\n\nThe type of `x` depends on a run-time value and therefore may not be deduced by\nthe compiler, which is thus unable to compile such a program to begin with.\n\nFine, as long as we are able to, say, filter the elements in a `std::tuple`\nbased on a predicate, we should be able to tackle most real world problems.\nThat should be easy right?\n\nNope.\n\nCan you deduce the type of `x` this time?\n\n```.cpp\ntemplate\u003ctypename Tuple, typename Predicate\u003e\ndecltype(auto) filter(Tuple\u0026\u0026, Predicate\u0026\u0026);\n\nauto x = filter(std::make_tuple(1, 1.0, '1', \"one\"), [](auto\u0026\u0026) {\n    return std::rand() % 2;\n});\n```\n\nHeck, the predicate doesn't even depend on the elements themselves, but still we\nare unable to deduce the return type!\n\nAlright, forget about returning values, let's forward results to a callback\nfunction instead.\n\n```.cpp\ntemplate\u003ctypename Tuple, typename Predicate, typename Callback\u003e\nvoid filter(Tuple\u0026\u0026, Predicate\u0026\u0026, Callback\u0026\u0026);\n\nauto predicate = [](auto\u0026\u0026) {\n    return std::rand() % 2;\n};\n\nauto callback = [](auto\u0026\u0026... /*args*/) { /* ... */ };\n\nfilter(std::make_tuple(1, 1.0, '1', \"one\"), predicate, callback);\n```\n\nThat was easy after all... or was it? Let us not forget that we still need to\nimplement `filter`.\n\nHow can the standard library help us get there, you might have asked yourself,\nand the answer is quite simple in fact: _It can't really._\n\nSure `std::apply` can help us extract the elements out of the tuple, but that's\nabout all the standard library can do for us, from then on we are on our own.\n\n```.cpp\ntemplate\u003ctypename Tuple, typename Predicate, typename Callback\u003e\nvoid filter(Tuple\u0026\u0026 tuple, Predicate\u0026\u0026 predicate, Callback\u0026\u0026 callback) {\n    constexpr auto impl = [\u0026predicate, \u0026callback](auto\u0026\u0026... elements) {\n        // TODO: do the heavy lifting :(\n    };\n\n    std::apply(std::forward\u003cTuple\u003e(tuple), impl);\n}\n```\n\nWe don't want to keep reinventing the wheel, we want to solve real problems, but\nfor that we need the building blocks.\n\n```.cpp\nauto tuple = std::make_tuple(1, 1.0, '1', \"one\");\n\nauto predicate = [](auto\u0026\u0026) {\n    return std::rand() % 2;\n};\n\nauto callback = [](auto\u0026\u0026... /*args*/) { /* ... */ };\n\nalloy::unpack(tuple) \u003e\u003e alloy::filter(predicate) \u003e\u003e callback;\n```\n\nWe need Alloy.\n\n## Quick Start\n\n1. Download [alloy.hpp][releases]\n2. `# include \u003c/path/to/alloy.hpp\u003e`\n3. Embrace (post) modern C++\n\n## Portability\n\nAlloy requires C++17 and is known to work on GCC and Clang.\n\n## License\n\nThis project is licensed under the [MIT][license].\n\n[version]:          https://badge.fury.io/gh/brunocodutra%2Falloy.svg\n[semver]:           https://semver.org\n\n[godbolt.alloy]:    https://godbolt.org/z/4P38zfnMh\n[godbolt.badge]:    https://img.shields.io/badge/try%20it-on%20godbolt-222266.svg\n\n[license]:          https://github.com/brunocodutra/alloy/blob/master/LICENSE\n[releases]:         https://github.com/brunocodutra/alloy/releases\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrunocodutra%2Falloy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrunocodutra%2Falloy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrunocodutra%2Falloy/lists"}