From c87b785391ff779783e6fa80f47d0f3a0896b082 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Wed, 11 Sep 2024 08:19:40 -0600 Subject: [PATCH] :sparkles: Add `tuple_cons` and `tuple_snoc` Making a tuple of one element just to call `tuple_cat` is cumbersome. Why not use `tuple_cons`/`tuple_snoc`? Or for non-lispers, `tuple_push_front` and `tuple_push_back`? --- docs/tuple_algorithms.adoc | 30 ++++++++++++++++++++ include/stdx/tuple_algorithms.hpp | 32 +++++++++++++++++++++ test/tuple_algorithms.cpp | 46 +++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/docs/tuple_algorithms.adoc b/docs/tuple_algorithms.adoc index de99677..4be6fa4 100644 --- a/docs/tuple_algorithms.adoc +++ b/docs/tuple_algorithms.adoc @@ -22,6 +22,10 @@ contains various (free function) algorithms that work on `stdx::tuple`. * `to_unordered_set` - produce a tuple of unique types that are in the order given * `transform` - a variadic transform on tuple(s) * `tuple_cat` - like `std::tuple_cat` +* `tuple_cons` - add an element to the front of a tuple +* `tuple_push_back` - alias for `tuple_snoc` +* `tuple_push_front` - alias for `tuple_cons` +* `tuple_snoc` - add an element to the back of a tuple * `unique` - produce a tuple where adjacent types that are the same are merged into one element (the first such) === `all_of`, `any_of`, `none_of` @@ -278,6 +282,32 @@ auto x = get(t).value; // 42 `tuple_cat` works just like https://en.cppreference.com/w/cpp/utility/tuple/tuple_cat[`std::tuple_cat`]. +=== `tuple_cons`/`tuple_push_front` + +`tuple_cons` adds an item to the front of a tuple. `tuple_push_front` is an +alias for `tuple_cons`. + +[source,cpp] +---- +auto t = stdx::tuple_cons(1, stdx:tuple{2, 3}); // {1, 2, 3} +---- + +NOTE: `tuple_cons` preserves the reference qualifiers in the given tuple, but +decays the "single" argument, as `make_tuple` does. + +=== `tuple_snoc`/`tuple_push_back` + +`tuple_snoc` adds an item to the back of a tuple. `tuple_push_back` is an alias +for `tuple_snoc`. + +[source,cpp] +---- +auto t = stdx::tuple_snoc(stdx:tuple{2, 3}, 1); // {2, 3, 1} +---- + +NOTE: `tuple_snoc` preserves the reference qualifiers in the given tuple, but +decays the "single" argument, as `make_tuple` does. + === `unique` `unique` works like diff --git a/include/stdx/tuple_algorithms.hpp b/include/stdx/tuple_algorithms.hpp index e95bfd1..ab89303 100644 --- a/include/stdx/tuple_algorithms.hpp +++ b/include/stdx/tuple_algorithms.hpp @@ -49,6 +49,38 @@ template [[nodiscard]] constexpr auto tuple_cat(Ts &&...ts) { } } +template +[[nodiscard]] constexpr auto tuple_cons(T &&t, Tup &&tup) { + using tuple_t = std::remove_cvref_t; + return [&](std::index_sequence) { + return stdx::tuple, + stdx::tuple_element_t...>{ + std::forward(t), std::forward(tup)[index]...}; + }(std::make_index_sequence>{}); +} + +template +[[nodiscard]] constexpr auto tuple_snoc(Tup &&tup, T &&t) { + using tuple_t = std::remove_cvref_t; + return [&](std::index_sequence) { + return stdx::tuple..., + std::remove_cvref_t>{ + std::forward(tup)[index]..., std::forward(t)}; + }(std::make_index_sequence>{}); +} + +template +[[nodiscard]] constexpr auto tuple_push_front(T &&t, + Tup &&tup) -> decltype(auto) { + return tuple_cons(std::forward(t), std::forward(tup)); +} + +template +[[nodiscard]] constexpr auto tuple_push_back(Tup &&tup, + T &&t) -> decltype(auto) { + return tuple_snoc(std::forward(tup), std::forward(t)); +} + template