diff --git a/source/simple/support/carcdr.hpp b/source/simple/support/carcdr.hpp index eff41f8b5e6f9c6359594710a20acdc323d253c8..875dc25fe88d3b9a308a7ee764714cdc55c2be84 100644 --- a/source/simple/support/carcdr.hpp +++ b/source/simple/support/carcdr.hpp @@ -1,11 +1,12 @@ #ifndef SIMPLE_SUPPORT_CARCDR_HPP #define SIMPLE_SUPPORT_CARCDR_HPP -#include <tuple> +#include <cstdint> #include <utility> namespace simple::support { + using std::size_t; template <typename Int, Int... Values> using lisp_list = std::integer_sequence<Int, Values...>; @@ -23,67 +24,38 @@ namespace simple::support template <typename IntSeq> using cdr = typename carcdr<IntSeq>::cdr; - template <typename IntSeq> - constexpr typename IntSeq::value_type car() noexcept - { - static_assert( IntSeq::size() > 0 ); - return carcdr<IntSeq>::car; - } + template <typename List, size_t = 0, auto ... Rest> + std::nullptr_t car; - template <typename IntSeq> - constexpr typename IntSeq::value_type car(typename IntSeq::value_type value) noexcept + template <typename List, size_t N, + typename List::value_type nil> + constexpr typename List::value_type + car<List, N, nil> = []() { - if constexpr ( IntSeq::size() > 0 ) - return (void)value, carcdr<IntSeq>::car; + if constexpr ( N >= List::size() ) + return nil; else - return value; - } + return car<List, N>; + }(); - template <typename IntSeq, size_t N> - constexpr typename IntSeq::value_type car() noexcept + template <typename List, size_t N> + constexpr typename List::value_type + car<List, N> = []() { - static_assert( N < IntSeq::size() ); + static_assert( N < List::size() ); if constexpr (N == 0) - return car<IntSeq>(); - else - return car<cdr<IntSeq>, N - 1>(); - } - - template <typename IntSeq, size_t N> - constexpr typename IntSeq::value_type car(typename IntSeq::value_type value) noexcept - { - if constexpr ( N >= IntSeq::size() ) - return value; - else if constexpr (N == 0) - return car<IntSeq>(value); + return car<List>; else - return car<cdr<IntSeq>, N - 1>(value); - } - - template <typename... Rest, size_t... indices> - constexpr auto subtuple(const std::tuple<Rest...>& tuple, std::integer_sequence<size_t, indices...>) - { - return std::make_tuple(std::get<indices>(tuple)...); - } - - template <typename First, typename... Rest> - constexpr auto tuple_car(const std::tuple<First, Rest...>& tuple) - { - return std::get<0>(tuple); - } - - constexpr std::nullptr_t tuple_car(const std::tuple<>&) - { - return nullptr; - } + return car<cdr<List>, N - 1>; + }(); - template <typename First, typename... Rest> - constexpr auto tuple_cdr(const std::tuple<First, Rest...>& tuple) + template <typename List> + constexpr typename List::value_type + car<List, 0> = []() { - using indices = std::make_index_sequence< - std::tuple_size_v<std::decay_t<decltype(tuple)>>>; - return subtuple(tuple, cdr<indices>{}); - } + static_assert( List::size() > 0 ); + return carcdr<List>::car; + }(); } // namespace simple::support diff --git a/source/simple/support/tuple_utils.hpp b/source/simple/support/tuple_utils.hpp index 4561716acd5d8f79454ccbc83209426add4ffb27..36ee8fbe27ab3fb11222474c0cf1f326fd3fae07 100644 --- a/source/simple/support/tuple_utils.hpp +++ b/source/simple/support/tuple_utils.hpp @@ -1,50 +1,3 @@ -#ifndef SIMPLE_SUPPORT_TUPLE_UTILS_HPP -#define SIMPLE_SUPPORT_TUPLE_UTILS_HPP -#include <tuple> -#include <functional> -#include "range.hpp" - -namespace simple::support -{ - - // wow this is a mess... you think it'll be optimized? O_o - //TODO: return a variant?? - template<typename F, typename First, size_t I = std::tuple_size_v<std::remove_reference_t<First>> - 1, typename... Rest> - [[nodiscard]] constexpr - decltype(auto) apply_for(size_t index, F&& f, First&& first, Rest&&... rest) - { - using std::remove_reference_t; - using First_t = remove_reference_t<First>; - using std::apply; - using std::get; - using std::tuple_element_t; - using std::forward; - static_assert(I >= 0 && I < std::tuple_size_v<First_t>); - if(I == index) - // std::invoke is not constexpr -_- - return apply(forward<F>(f), std::forward_as_tuple( - forward<tuple_element_t<I, First_t>>(get<I>(first)), - forward<tuple_element_t<I, remove_reference_t<Rest>>>(get<I>(rest))... - )); - if constexpr (I > 0) - return apply_for<F, decltype(forward<First_t>(first)), I - 1>(index, forward<F>(f), - forward<First_t>(first), forward<remove_reference_t<Rest>>(rest)...); - - throw std::logic_error("simple::support::apply_for - this should never happen"); - } - - template<typename F, typename First, size_t I = std::tuple_size_v<std::remove_reference_t<First>> - 1, typename... Rest> - constexpr - void apply_for(range<size_t> index_range, F&& f, First&& first, Rest&&... rest) - { - for(size_t i = index_range.lower(); i < index_range.upper(); ++i) - { - apply_for(i, std::forward<F>(f), - std::forward<std::remove_reference_t<First>>(first), - std::forward<std::remove_reference_t<Rest>>(rest)...); - } - } - -} // namespace simple::support - -#endif /* end of include guard */ +#include "tuple_utils/apply_for.hpp" +#include "tuple_utils/carcdr.hpp" +#include "tuple_utils/subtuple.hpp" diff --git a/source/simple/support/tuple_utils/apply_for.hpp b/source/simple/support/tuple_utils/apply_for.hpp new file mode 100644 index 0000000000000000000000000000000000000000..504ac61e7db01ab8ff277a0b815b2c09f8255d69 --- /dev/null +++ b/source/simple/support/tuple_utils/apply_for.hpp @@ -0,0 +1,51 @@ +#ifndef SIMPLE_SUPPORT_TUPLE_UTILS_APPLY_FOR_HPP +#define SIMPLE_SUPPORT_TUPLE_UTILS_APPLY_FOR_HPP + +#include <tuple> +#include <functional> +#include "../range.hpp" + +namespace simple::support +{ + + // wow this is a mess... you think it'll be optimized? O_o + //TODO: return a variant?? + template<typename F, typename First, size_t I = std::tuple_size_v<std::remove_reference_t<First>> - 1, typename... Rest> + [[nodiscard]] constexpr + decltype(auto) apply_for(size_t index, F&& f, First&& first, Rest&&... rest) + { + using std::remove_reference_t; + using First_t = remove_reference_t<First>; + using std::apply; + using std::get; + using std::tuple_element_t; + using std::forward; + static_assert(I >= 0 && I < std::tuple_size_v<First_t>); + if(I == index) + // std::invoke is not constexpr -_- + return apply(forward<F>(f), std::forward_as_tuple( + forward<tuple_element_t<I, First_t>>(get<I>(first)), + forward<tuple_element_t<I, remove_reference_t<Rest>>>(get<I>(rest))... + )); + if constexpr (I > 0) + return apply_for<F, decltype(forward<First_t>(first)), I - 1>(index, forward<F>(f), + forward<First_t>(first), forward<remove_reference_t<Rest>>(rest)...); + + throw std::logic_error("simple::support::apply_for - this should never happen"); + } + + template<typename F, typename First, size_t I = std::tuple_size_v<std::remove_reference_t<First>> - 1, typename... Rest> + constexpr + void apply_for(range<size_t> index_range, F&& f, First&& first, Rest&&... rest) + { + for(size_t i = index_range.lower(); i < index_range.upper(); ++i) + { + apply_for(i, std::forward<F>(f), + std::forward<std::remove_reference_t<First>>(first), + std::forward<std::remove_reference_t<Rest>>(rest)...); + } + } + +} // namespace simple::support + +#endif /* end of include guard */ diff --git a/source/simple/support/tuple_utils/carcdr.hpp b/source/simple/support/tuple_utils/carcdr.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6b3ae64605a538fa01e4ade3a9eabad80406de39 --- /dev/null +++ b/source/simple/support/tuple_utils/carcdr.hpp @@ -0,0 +1,46 @@ +#ifndef SIMPLE_SUPPORT_TUPLE_UTILS_CARCDR_HPP +#define SIMPLE_SUPPORT_TUPLE_UTILS_CARCDR_HPP + +#include "subtuple.hpp" +#include "../carcdr.hpp" + +namespace simple::support +{ + + template <typename Tuple> + constexpr decltype(auto) tuple_car(Tuple&& tuple) + noexcept(noexcept(std::get<0>(std::forward<Tuple>(tuple)))) + { + return std::get<0>(std::forward<Tuple>(tuple)); + } + + constexpr std::nullptr_t tuple_car(const std::tuple<>&) + { + return nullptr; + } + + template <typename First, typename... Rest> + constexpr auto tuple_cdr(const std::tuple<First, Rest...>& tuple) + { + using indices = std::make_index_sequence< + std::tuple_size_v<std::decay_t<decltype(tuple)>>>; + return subtuple(tuple, cdr<indices>{}); + } + + template <typename First, typename... Rest> + constexpr auto tuple_tie_cdr(const std::tuple<First, Rest...>& tuple) + { + using indices = tuple_indecies<decltype(tuple)>; + return tie_subtuple(tuple, cdr<indices>{}); + } + + template <typename First, typename... Rest> + constexpr auto tuple_tie_cdr(std::tuple<First, Rest...>& tuple) + { + using indices = tuple_indecies<decltype(tuple)>; + return tie_subtuple(tuple, cdr<indices>{}); + } + +} // namespace simple::support + +#endif /* end of include guard */ diff --git a/source/simple/support/tuple_utils/subtuple.hpp b/source/simple/support/tuple_utils/subtuple.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9086d8ced3c5a9fb78f32e20c2b4a81f2659115 --- /dev/null +++ b/source/simple/support/tuple_utils/subtuple.hpp @@ -0,0 +1,34 @@ +#ifndef SIMPLE_SUPPORT_TUPLE_UTILS_SUBTUPLE_HPP +#define SIMPLE_SUPPORT_TUPLE_UTILS_SUBTUPLE_HPP +#include <utility> +#include <tuple> + +namespace simple::support +{ + + template <typename... Rest, size_t... indices> + constexpr auto subtuple(const std::tuple<Rest...>& tuple, std::integer_sequence<size_t, indices...>) + { + return std::make_tuple(std::get<indices>(tuple)...); + } + + template <typename... Rest, size_t... indices> + constexpr auto tie_subtuple(const std::tuple<Rest...>& tuple, std::integer_sequence<size_t, indices...>) + { + return std::tie(std::get<indices>(tuple)...); + } + + template <typename... Rest, size_t... indices> + constexpr auto tie_subtuple(std::tuple<Rest...>& tuple, std::integer_sequence<size_t, indices...>) + { + return std::tie(std::get<indices>(tuple)...); + } + + template <typename T> + using tuple_indecies = std::make_index_sequence< + std::tuple_size_v<std::decay_t<T>> + >; + +} // namespace simple::support + +#endif /* end of include guard */ diff --git a/unit_tests/carcdr.cpp b/unit_tests/carcdr.cpp index 28b3f26898cc9103a7c80ccd9f3949b7e82e78e6..e31fe9d19f293db938e82ad44055caa4c0bb0992 100644 --- a/unit_tests/carcdr.cpp +++ b/unit_tests/carcdr.cpp @@ -5,15 +5,12 @@ using namespace simple::support; int main() { using ints = lisp_list<int, -1, 10, 13, 999>; - static_assert(car<ints>() == -1); + static_assert(car<ints> == -1); static_assert(std::is_same_v< cdr<ints>, lisp_list<int, 10, 13, 999> >); - static_assert(car< cdr<cdr<ints>> >() == 13); - static_assert(car<ints, 3>() == 999); - static_assert(car<lisp_list<int>>(321) == 321); - static_assert(car<ints, 10>(9517) == 9517); // *shrug* + static_assert(car< cdr<cdr<ints>> > == 13); + static_assert(car<ints, 3> == 999); + static_assert(car<lisp_list<int>, 0, 321> == 321); + static_assert(car<ints, 10, -9517> == -9517); // *shrug* - constexpr auto t = std::make_tuple(true, 1.5, 5); - static_assert(tuple_car(t)); - static_assert(1.5 == tuple_car(tuple_cdr(t))); return 0; } diff --git a/unit_tests/tuple_utils.cpp b/unit_tests/tuple_utils.cpp index 7d3fa704bec72e314390aaf934556b7a10f33717..ac7e8a23764f0540e9571b2955fe30ae1f9763e9 100644 --- a/unit_tests/tuple_utils.cpp +++ b/unit_tests/tuple_utils.cpp @@ -3,9 +3,10 @@ #include <iostream> #include "simple/support/tuple_utils.hpp" -int main() +using namespace simple::support; + +void ApplyFor() { - using simple::support::apply_for; auto t = std::tuple(0," one ",2," three"); std::stringstream ss; @@ -47,5 +48,52 @@ int main() assert( 4 == apply_for(2, [](auto&& x) { return x + 2; }, t3) ); +} + +template <typename... T> +constexpr auto tuple_tie(std::tuple<T...>& t) +{ + return std::apply(std::tie<T...>, t); +} + +void CarCdr() +{ + + { auto t = std::tuple(true, 1.5, 5); + assert(tuple_car(t)); + assert(1.5 == tuple_car(tuple_cdr(t))); + } + + { auto t = std::tuple(1, 2, 3); + auto tref = tuple_tie(t); + + assert(t == tref); + + tuple_car(tref) = -4; + + assert(tuple_car(t) == -4); + assert(t == tref); + + auto tref_cdr = tuple_tie_cdr(tref); + + tuple_car(tref_cdr) = 13; + + assert(std::get<1>(t) == 13); + assert(tref_cdr == std::tuple(13,3)); + + auto tref_cdr2 = tuple_tie_cdr(t); + tuple_car(tref_cdr2) = 12; + + assert(std::get<1>(t) == 12); + assert(tref_cdr2 == tref_cdr); + assert(tref_cdr2 == std::tuple(12,3)); + assert(tref_cdr == std::tuple(12,3)); + } +} + +int main() +{ + ApplyFor(); + CarCdr(); return 0; }