Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions docs/utility.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,49 @@ std::uint32_t i;
assert(stdx::is_aligned_with<std::uint32_t>(&i));
----

=== `make_integer_sequence`

`make_integer_sequence` is a class template that derives from
https://en.cppreference.com/w/cpp/utility/integer_sequence.html[`std::make_integer_sequence`].
Likewise, `make_index_sequence` and `index_sequence_for` are analogous with
their standard counterparts. In fact each `stdx` version derives from the `std`
version, so can be used in exactly the same way, for instance:

[source,cpp]
----
auto sum = []<std::size_t... Is>(std::index_sequence<Is...>) {
return (std::size_t{} + ... + Is);
}(stdx::make_index_sequence<3>{});

// sum is 6
----
The difference is that `stdx::make_integer_sequence` implements the tuple
protocol. This means that it is usable with
xref:tuple_algorithms.adoc#_tuple_algorithms_hpp[tuple algorithms]. And when
using the tuple protocol, `stdx::make_index_sequence` produces
`std::integral_constant<std::size_t, I>` rather than `std::size_t{I}`.

[source,cpp]
----
template <std::size_t N>
auto f() {
// use make_index_sequence with tuple algorithms
stdx::unrolled_for_each(
[](auto x) {
// x is std::integral_constant<std::size_t, I> for each I
},
stdx::make_index_sequence<N>{});

// or with C++26, destructure into a pack (optionally constexpr here)
auto [...Is] = stdx::make_index_sequence<N>{};

// std::integral_constant implicitly converts to its contained type...
auto rt_sum = (std::size_t{} + ... + Is);
// ...or can be used at compile time
constexpr auto ct_sum = (std::size_t{} + ... + decltype(Is)::value);
}
----

=== `overload`

`overload` is a struct designed to encapsulate an overload set. It inherits from
Expand Down
6 changes: 6 additions & 0 deletions include/stdx/span.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ class span : public detail::span_base<T, Extent> {
}
};

template <std::size_t I, typename T, std::size_t E>
[[nodiscard]] constexpr auto get(span<T, E> s) -> decltype(s[I]) {
static_assert(E == dynamic_extent or I < E, "get() out of range on span");
return s[I];
}

// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
template <class T, std::size_t N> auto as_bytes(span<T, N> s) noexcept {
if constexpr (N == dynamic_extent) {
Expand Down
3 changes: 3 additions & 0 deletions include/stdx/tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#if __cplusplus >= 202002L

#include <stdx/udls.hpp>
#include <stdx/utility.hpp>

#include <array>
#include <concepts>
Expand Down Expand Up @@ -408,6 +409,8 @@ tuple_impl(Ts...)
template <typename T> constexpr auto tuple_size_v = T::size();
template <typename T, std::size_t N>
constexpr auto tuple_size_v<std::array<T, N>> = N;
template <typename T, T N>
constexpr auto tuple_size_v<make_integer_sequence<T, N>> = std::size_t{N};

template <std::size_t I, typename T>
using tuple_element_t = typename T::template element_t<I>;
Expand Down
4 changes: 2 additions & 2 deletions include/stdx/tuple_algorithms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ template <template <typename T> typename Pred, tuplelike T>
namespace detail {
template <std::size_t I, typename... Ts>
constexpr auto invoke_at(auto &&op, Ts &&...ts) -> decltype(auto) {
return op(std::forward<Ts>(ts)[index<I>]...);
return op(get<I>(std::forward<Ts>(ts))...);
}

template <typename... Ts>
Expand Down Expand Up @@ -181,7 +181,7 @@ constexpr auto for_each(Op &&op, Ts &&...ts) -> Op {
namespace detail {
template <std::size_t I, typename... Ts>
constexpr auto invoke_with_idx_at(auto &&op, Ts &&...ts) -> decltype(auto) {
return op.template operator()<I>(std::forward<Ts>(ts)[index<I>]...);
return op.template operator()<I>(get<I>(std::forward<Ts>(ts))...);
}
} // namespace detail

Expand Down
20 changes: 20 additions & 0 deletions include/stdx/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,29 @@ template <typename T> constexpr auto is_ct_v<type_identity<T>> = true;
template <typename T> constexpr auto is_ct_v<T const> = is_ct_v<T>;

#endif

template <typename T, T N>
struct make_integer_sequence : std::make_integer_sequence<T, N> {};
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;

template <std::size_t I, typename T, T N>
constexpr auto get(make_integer_sequence<T, N>) {
return std::integral_constant<T, I>{};
}

} // namespace v1
} // namespace stdx

template <typename T, T N>
struct std::tuple_size<stdx::make_integer_sequence<T, N>>
: std::integral_constant<std::size_t, N> {};
template <std::size_t I, typename T, T N>
struct std::tuple_element<I, stdx::make_integer_sequence<T, N>>
: stdx::type_identity<std::integral_constant<T, I>> {};

// NOLINTBEGIN(cppcoreguidelines-macro-usage)

#ifndef FWD
Expand Down
14 changes: 14 additions & 0 deletions test/tuple_algorithms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <stdx/span.hpp>
#include <stdx/tuple_algorithms.hpp>
#include <stdx/utility.hpp>

#include <catch2/catch_template_test_macros.hpp>
#include <catch2/catch_test_macros.hpp>
Expand Down Expand Up @@ -246,6 +247,19 @@ TEST_CASE("unrolled_for_each on spans", "[tuple_algorithms]") {
CHECK(a == std::array{0, 1, 2});
}

TEST_CASE("unrolled_for_each on index_sequence", "[tuple_algorithms]") {
auto a = std::array{1u, 2u, 3u};
auto sum = std::size_t{};
stdx::unrolled_for_each(
[&](auto &x, auto y) {
sum += x + y;
x--;
},
a, stdx::make_index_sequence<stdx::ct_capacity(a)>{});
CHECK(sum == 9u);
CHECK(a == std::array{0u, 1u, 2u});
}

TEST_CASE("tuple_cat", "[tuple_algorithms]") {
STATIC_REQUIRE(stdx::tuple_cat() == stdx::tuple{});
STATIC_REQUIRE(stdx::tuple_cat(stdx::tuple{}, stdx::tuple{}) ==
Expand Down
20 changes: 20 additions & 0 deletions test/utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,3 +432,23 @@ TEST_CASE("CX_WRAP non-constexpr expression", "[utility]") {
#endif

#endif

STDX_PRAGMA(diagnostic push)
#ifdef __clang__
STDX_PRAGMA(diagnostic ignored "-Wunknown-warning-option")
STDX_PRAGMA(diagnostic ignored "-Wc++26-extensions")
#endif
#if __cpp_structured_bindings >= 202411L
namespace {
template <std::size_t N> constexpr auto sum() {
auto [... Is] = stdx::make_index_sequence<N>{};
constexpr auto sum = (0 + ... + decltype(Is)::value);
return sum;
}
} // namespace

TEST_CASE("destructurable integer_sequence", "[utility]") {
STATIC_CHECK(sum<4>() == 6);
}
#endif
STDX_PRAGMA(diagnostic pop)