{"id":26213444,"url":"https://github.com/jkalias/functional_cpp","last_synced_at":"2025-04-15T16:59:40.924Z","repository":{"id":41963619,"uuid":"387602376","full_name":"jkalias/functional_cpp","owner":"jkalias","description":"A wrapper of common C++ std types for functional programming","archived":false,"fork":false,"pushed_at":"2023-09-24T18:50:48.000Z","size":154,"stargazers_count":22,"open_issues_count":2,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-15T16:59:29.914Z","etag":null,"topics":["cpp","functional-programming"],"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/jkalias.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,"governance":null}},"created_at":"2021-07-19T21:50:24.000Z","updated_at":"2024-02-23T23:54:13.000Z","dependencies_parsed_at":"2022-08-05T14:00:41.216Z","dependency_job_id":null,"html_url":"https://github.com/jkalias/functional_cpp","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkalias%2Ffunctional_cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkalias%2Ffunctional_cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkalias%2Ffunctional_cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkalias%2Ffunctional_cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jkalias","download_url":"https://codeload.github.com/jkalias/functional_cpp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249116231,"owners_count":21215142,"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","functional-programming"],"created_at":"2025-03-12T09:19:41.480Z","updated_at":"2025-04-15T16:59:40.906Z","avatar_url":"https://github.com/jkalias.png","language":"C++","readme":"[![CMake Build Matrix](https://github.com/jkalias/functional_cpp/actions/workflows/cmake.yml/badge.svg)](https://github.com/jkalias/functional_cpp/actions/workflows/cmake.yml)\n[![GitHub license](https://img.shields.io/github/license/jkalias/functional_cpp)](https://github.com/jkalias/functional_cpp/blob/main/LICENSE)\n# Say hello to functional C++\nA wrapper for C++ std::vector and std::set geared towards functional programming and fluent APIs. This project is heavily influenced and inspired by C# and Swift.\n\nThe primary focus of this library is\n* readability at the call site (\"make it work, make it right, make it fast\")\n* surfacing existing algorithms from the standard library, and lowering the barrier for their extended usage\n* elimination of vector index operations\n* encapsulation of the iterator madness\n* removal of manual for-loops\n\n## Compilation (Cmake)\n### Dependencies\n* CMake \u003e= 3.14\n\n### Minimum C++ version\n* C++11\n\nAn out-of-source build strategy is used. All following examples assume an output build folder named ```build```. If no additional argument is passed to CMake, C++11 is used. Otherwise, you can pass ```-DCMAKE_CXX_STANDARD=17``` and it will use C++17 for example.\n### macOS (Xcode)\n```console\ncd functional_cpp\ncmake -S . -B build -G Xcode\n```\nThen open the generated ```functional_cpp.xcodeproj``` in the ```build``` folder.\n\n### macOS (Makefiles/clang)\n```console\ncd functional_cpp\ncmake -S . -B build\ncmake --build build\nbuild/tests/unit_tests\n```\n\n### macOS (Makefiles/g++)\nAssuming you have installed Homebrew, you can then use the gcc and g++ compilers by doing the following (this example uses version gcc 11)\n```console\ncd functional_cpp\ncmake \\\n    -S . \\\n    -B build \\\n    -DCMAKE_C_COMPILER=/opt/homebrew/Cellar/gcc/11.2.0/bin/gcc-11 \\\n    -DCMAKE_CXX_COMPILER=/opt/homebrew/Cellar/gcc/11.2.0/bin/g++-11\ncmake --build build\nbuild/tests/unit_tests\n```\n\n### Linux (Makefiles)\n```console\ncd functional_cpp\ncmake -S . -B build\ncmake --build build\nbuild/tests/unit_tests\n```\n\n### Windows (Visual Studio)\n```console\ncd functional_cpp\ncmake -S . -B build\n```\nThen open the generated ```functional_cpp.sln``` in the ```build``` folder.\n\n## Functional vector usage (fcpp::vector)\n### extract unique (distinct) elements in a set\n```c++\n#include \"vector.h\" // instead of \u003cvector\u003e\n\nconst fcpp::vector\u003cint\u003e numbers({1, 4, 2, 5, 8, 3, 1, 7, 1});\n\n// contains only 1, 2, 3, 4, 5, 7, 8\nconst fcpp::set\u003cint\u003e unique_numbers = numbers.distinct();\n```\n\n### zip, map, filter, sort, reduce\n```c++\n#include \"vector.h\" // instead of \u003cvector\u003e\n\nstruct person {\n    person(int age, std::string name)\n    : age(age), name(std::move(name))\n    {}\n    int age;\n    std::string name;\n    \n    std::size_t hash() const {\n        // a clever implementation of hash    \n        // ...\n    }\n    \n    bool operator\u003c (const person\u0026 other) const {\n        return hash() \u003c other.hash();\n    }\n};\n\n// ...\n\n// the employees' ages\nconst fcpp::vector\u003cint\u003e ages({32, 45, 37, 23});\n\n// the employees' names\nconst fcpp::vector\u003cstd::string\u003e names({\"Jake\", \"Anna\", \"Kate\", \"Bob\"});\n\nconst auto employees_below_40 = ages\n    // zip two vectors for simultaneous processing\n    .zip(names)\n\n    // apply the functional map algorithm (transform from one type to another)\n    .map\u003cperson\u003e([](const std::pair\u003cint, std::string\u003e\u0026 pair) {                     \n        return person(pair.first, pair.second);\n    })\n    \n    // filter the elements using a local function (lambda)\n    .filter([](const person\u0026 p) {\n        return p.age \u003c 40;\n    })\n    \n    // sort according to custom predicate\n    .sort([](const person\u0026 person1, const person\u0026 person2) {\n        return person1.age \u003c person2.age;\n    });\n\n/*\n prints the following:\n Bob is 23 years old.\n Jake is 32 years old.\n Kate is 37 years old.\n */\nemployees_below_40.for_each([](const person\u0026 p) {\n    std::cout \u003c\u003c p.name \u003c\u003c \" is \" \u003c\u003c p.age \u003c\u003c \" years old.\" \u003c\u003c std::endl;\n});\n\n// total_age = 92\nconst auto total_age = employees_below_40.reduce(0, [](const int\u0026 partial_sum, const person\u0026 p){\n    return partial_sum + p.age;\n});\n```\n### index search\n```c++\n#include \"vector.h\" // instead of \u003cvector\u003e\n\nconst fcpp::vector numbers({1, 4, 2, 5, 8, 3, 1, 7, 1});\n\nconst auto first_index_of_one = numbers.find_first_index(1);\n// returns 0\nfirst_index_of_one.value();\n\nconst auto last_index_of_one = numbers.find_last_index(1);\n// returns 8\nlast_index_of_one.value();\n\n// all_indices_of_one -\u003e { 0, 6, 8 }\nconst auto all_indices_of_one = numbers.find_all_indices(1);\n\nconst auto index_of_nine = numbers.find_first_index(9);\n// returns false\nindex_of_nine.has_value();\n```\n\n### remove, insert\n```c++\n#include \"vector.h\" // instead of \u003cvector\u003e\n#include \"index_range.h\"\n\nfcpp::vector\u003cint\u003e numbers({1, 4, 2, 5, 8, 3, 1, 7, 1});\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({1, 4, 2, 5, 3, 1, 7, 1});\nnumbers.remove_at(4);\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({4, 2, 5, 3, 1, 7, 1});\nnumbers.remove_front();\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({4, 2, 5, 3, 1, 7});\nnumbers.remove_back();\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({4, 2, 7});\nnumbers.remove_range(index_range::start_count(2, 3));\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({4, 8, 2, 7});\nnumbers.insert_at(1, 8);\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({-10, 4, 8, 2, 7});\nnumbers.insert_front(-10);\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({-10, 4, 8, 2, 7, 9});\nnumbers.insert_back(9);\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({-10, 4, 8, 3, -2, 5, 2, 7, 9});\nnumbers.insert_at(3, std::vector({3, -2, 5}));\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({4, -6, 7, -10, 4, 8, 3, -2, 5, 2, 7, 9});\nnumbers.insert_front(fcpp::vector({4, -6, 7}));\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({4, -6, 7, -10, 4, 8, 3, -2, 5, 2, 7, 9, 7, 3});\nnumbers.insert_back(std::initializer_list({7, 3}));\n```\n\n### size, capacity, reserve, resize\n```c++\n#include \"vector.h\" // instead of \u003cvector\u003e\n\n// numbers.capacity() = 9\n// numbers.size() = 9\nfcpp::vector\u003cint\u003e numbers({1, 4, 2, 5, 8, 3, 1, 7, 1});\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({1, 4, 2, 5, 8});\n// numbers.capacity() = 9\n// numbers.size() = 5\nnumbers.resize(5);\n\n// numbers -\u003e fcpp::vector\u003cint\u003e({1, 4, 2, 5, 8, 0, 0});\n// numbers.capacity() = 9\n// numbers.size() = 7\nnumbers.resize(7);\n\n// empty_numbers.capacity() = 0\n// empty_numbers.size() = 0\nfcpp::vector\u003cint\u003e empty_numbers;\n\n// empty_numbers.capacity() = 5\n// empty_numbers.size() = 0\nempty_numbers.reserve(5);\n```\n\n### all_of, any_of, none_of\n```c++\n#include \"vector.h\" // instead of \u003cvector\u003e\n\nfcpp::vector\u003cint\u003e numbers({1, 4, 2, 5, 8, 3, 1, 7, 1});\n\n// returns true\nnumbers.all_of([](const int\u0026 number) {\n    return number \u003c 10;\n});\n\n// returns false\nnumbers.all_of([](const int\u0026 number) {\n    return number \u003e 2;\n});\n\n// returns true\nnumbers.any_of([](const int\u0026 number) {\n    return number \u003c 5;\n});\n\n// returns false\nnumbers.any_of([](const int\u0026 number) {\n    return number \u003e 9;\n});\n\n// returns true\nnumbers.none_of([](const int\u0026 number) {\n    return number \u003c -2;\n});\n\n// returns false\nnumbers.none_of([](const int\u0026 number) {\n    return number \u003e 7;\n});\n```\n\n### Parallel algorithms\nSince C++17 several STL algorithms can be executed in parallel.\n\nclang on macOS does not yet fully support the parallel execution model, however on Windows and Linux, an `fcpp::vector` supports the following parallel algorithms\n```c++\nfor_each_parallel\nmap_parallel\nfilter_parallel\nsort_parallel\nall_of_parallel\nany_of_parallel\nnone_of_parallel\n```\n\n## Functional set usage (fcpp::set)\n### difference, union, intersection (works with fcpp::set and std::set)\n```c++\n#include \"set.h\" // instead of \u003cset\u003e\n\n// struct person as defined previously\nstruct person_comparator {\n    bool operator() (const person\u0026 a, const person\u0026 b) const {\n        return a \u003c b;\n    }\n};\n\n// ...\n\n// a set containing all colleagues\nconst fcpp::set\u003cperson, person_comparator\u003e colleagues({\n    person(51, \"George\"),\n    person(15, \"Jake\"),\n    person(18, \"Jannet\"),\n    person(41, \"Jackie\"),\n    person(25, \"Kate\")\n});\n\n// a set containing all friends\nconst fcpp::set\u003cperson, person_comparator\u003e friends({\n    person(51, \"George\"),\n    person(41, \"Jackie\"),\n    person(42, \"Crystal\"),\n});\n\n// find which colleagues are not friends\n// contains person(15, \"Jake\"), person(18, \"Jannet\") and person(25, \"Kate\")\nconst auto colleagues_but_not_friends = colleagues.difference_with(friends);\n\n// find which friends are colleagues\n// same as colleagues.intersect_with(friends)\n// contains person(51, \"George\"), person(41, \"Jackie\")\nconst auto good_colleagues = friends.intersection_with(colleagues);\n\n// a set of close family members\nconst fcpp::set\u003cperson, person_comparator\u003e family({\n    person(51, \"Paul\"),\n    person(81, \"Barbara\"),\n});\n\n// all of our friends and family for the next party invitation\n// contains person(51, \"George\"), person(41, \"Jackie\"), person(42, \"Crystal\"), person(51, \"Paul\"), person(81, \"Barbara\") \nconst auto friends_and_family = friends.union_with(family);\n\n// all set keys in a vetor\nconst fcpp::vector\u003cperson\u003e = friends_and_family.keys();\n```\n\n### zip, map, filter, reduce\n```c++\n#include \"set.h\" // instead of \u003cset\u003e\n\n// the employees' ages\nconst fcpp::set\u003cint\u003e ages({ 25, 45, 30, 63 });\n\n// the employees' names\nconst fcpp::set\u003cstd::string\u003e names({ \"Jake\", \"Bob\", \"Michael\", \"Philipp\" });\n\nconst auto employees_below_40 = ages\n    // zip two sets for simultaneous processing\n    .zip(names)\n\n    // apply the functional map algorithm (transform from one type to another)\n    .map\u003cperson\u003e([](const std::pair\u003cint, std::string\u003e\u0026 pair) {                     \n        return person(pair.first, pair.second);\n    })\n    \n    // filter the elements using a local function (lambda)\n    .filter([](const person\u0026 p) {\n        return p.age \u003c 40;\n    });\n    \n/*\n prints the following:\n Jake is 30 years old.\n Bob is 25 years old.\n */\nemployees_below_40.for_each([](const person\u0026 p) {\n    std::cout \u003c\u003c p.name \u003c\u003c \" is \" \u003c\u003c p.age \u003c\u003c \" years old.\" \u003c\u003c std::endl;\n});\n\n// total_age = 55\nconst auto total_age = employees_below_40.reduce(0, [](const int\u0026 partial_sum, const person\u0026 p){\n    return partial_sum + p.age;\n});\n```\n\n### all_of, any_of, none_of\n```c++\n#include \"set.h\" // instead of \u003cset\u003e\n\nfcpp::set\u003cint\u003e numbers({1, 4, 2, 5, 8, 3, 7});\n\n// returns true\nnumbers.all_of([](const int\u0026 number) {\n    return number \u003c 10;\n});\n\n// returns false\nnumbers.all_of([](const int\u0026 number) {\n    return number \u003e 2;\n});\n\n// returns true\nnumbers.any_of([](const int\u0026 number) {\n    return number \u003c 5;\n});\n\n// returns false\nnumbers.any_of([](const int\u0026 number) {\n    return number \u003e 9;\n});\n\n// returns true\nnumbers.none_of([](const int\u0026 number) {\n    return number \u003c -2;\n});\n\n// returns false\nnumbers.none_of([](const int\u0026 number) {\n    return number \u003e 7;\n});\n```\n\n### remove, insert, contains, size, clear\n```c++\n#include \"set.h\" // instead of \u003cset\u003e\n\nfcpp::set\u003cint\u003e numbers({1, 2, 3, 4, 5, 7, 8});\n\n// numbers -\u003e fcpp::set\u003cint\u003e numbers({1, 2, 3, 5, 7, 8});\nnumbers.remove(4);\n\n// numbers -\u003e fcpp::set\u003cint\u003e numbers({1, 2, 3, 5, 7, 8, 10});\nnumbers.insert(10);\n\n// returns true\nnumbers.contains(10);\n\n// returns false\nnumbers.contains(25);\n\n// returns 7\nnumbers.size();\n\n// removes all keys\nnumbers.clear();\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkalias%2Ffunctional_cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjkalias%2Ffunctional_cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkalias%2Ffunctional_cpp/lists"}