Skip to content

Commit

Permalink
Merge pull request #109 from elbeno/better-join
Browse files Browse the repository at this point in the history
✨ Add `join` overload that deals with empty tuples
  • Loading branch information
elbeno authored Jun 4, 2024
2 parents 8cac8e4 + 8c52e8d commit 00e5c1f
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 3 deletions.
28 changes: 25 additions & 3 deletions docs/tuple.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,20 @@ NOTE: `tuple_cat` is an algorithm in
xref:tuple_algorithms.adoc#_tuple_algorithms_hpp[`tuple_algorithms.hpp`].

`join` is a member function that works the same way as `fold_left`, but without
needing an initial value. It is only defined for non-empty tuples.
needing an initial value. It has overloads either for non-empty tuples, or for
empty tuples with a given default.
[source,cpp]
----
auto t = stdx::tuple{1, 2, 3};
auto sum = t.join(std::plus{}); // 6
auto sum1 = stdx::tuple{1, 2, 3}.join(std::plus{}); // 6
auto sum2 = stdx::tuple{1}.join(std::plus{}); // 1
auto sum3 = stdx::tuple{}.join(42, std::plus{}); // 42
----

`join` is useful for things like string concatenation with comma separation.
[source,cpp]
----
auto sum1 = stdx::tuple{"hello"s, "world"s}.join(
[] (auto const &acc, auto const &s) { return acc + ", " + s; }); // "hello, world"
----

=== Indexed tuples
Expand Down Expand Up @@ -186,3 +195,16 @@ auto t = stdx::tuple{map_entry<X, int>{42}}; // regular tuple
auto i = stdx::apply_indices<key_for>(t); // tuple indexed with key_for
auto x = get<X>(i).value; // 42
----

=== `one_of`

`one_of` is a convenient way to declaratively determine if a value is in a set.

[source,cpp]
----
auto is_taxicab(int x) -> bool {
return x == one_of{2, 1'729, 875'339'319};
}
----

NOTE: `one_of` is a type, not a function.
17 changes: 17 additions & 0 deletions include/stdx/tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,23 @@ struct tuple_impl<std::index_sequence<Is...>, index_function_list<Fs...>, Ts...>
.value;
}

template <typename Init, typename Op>
constexpr auto join(Init &&init, Op &&op) const & {
if constexpr (sizeof...(Ts) == 0) {
return init;
} else {
return this->join(std::forward<Op>(op));
}
}
template <typename Init, typename Op>
constexpr auto join(Init &&init, Op &&op) && {
if constexpr (sizeof...(Ts) == 0) {
return init;
} else {
return std::move(*this).join(std::forward<Op>(op));
}
}

constexpr static auto size =
std::integral_constant<std::size_t, sizeof...(Ts)>{};
constexpr static auto ugly_Value(...) -> void;
Expand Down
11 changes: 11 additions & 0 deletions test/tuple_algorithms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ TEST_CASE("join", "[tuple_algorithms]") {
.value == 42);
}

TEST_CASE("join (single element)", "[tuple_algorithms]") {
constexpr auto t = stdx::tuple{1};
static_assert(t.join(std::plus{}) == 1);
}

TEST_CASE("join with default for empty tuple", "[tuple_algorithms]") {
static_assert(stdx::tuple{}.join(42, std::plus{}) == 42);
static_assert(stdx::tuple{1}.join(42, std::plus{}) == 1);
static_assert(stdx::tuple{1, 2, 3}.join(42, std::plus{}) == 6);
}

TEST_CASE("for_each", "[tuple_algorithms]") {
{
auto const t = stdx::tuple{};
Expand Down

0 comments on commit 00e5c1f

Please sign in to comment.