-
Notifications
You must be signed in to change notification settings - Fork 3
Tuple
#include <veg/tuple.hpp>
namespace veg {
template <typename T, usize I>
using inner_ith = decltype(VEG_DECLVAL(T)[Fix<isize{I}>{}]);
template <typename... Ts>
struct Tuple { /*...*/ };
} // namespace veg
A lightweight tuple type with operator[]
access notation and support for structured bindings (since C++17).
Example:
#include <veg/tuple.hpp>
using namespace veg;
auto main() -> int {
Tuple<int, float> t{tuplify, 3, 2.5};
dbg(t); // prints { 3, +2.5000e+00, }
t[0_c] = 13;
t[1_c] = 3.5F;
dbg(t); // prints { 13, +3.5000e+00, }
}
Tuple<Ts...>::~Tuple() = default;
Destroys the inner members
Tuple<Ts...>::Tuple(Tuplify /*tuplify*/, Ts... args) noexcept(nothrow_movable<Ts> && ...);
template <typename... Fns>
Tuple<Ts...>::Tuple(InPlace<Tuplify> /*inplace[tuplify]*/, Fns... fns) noexcept(nothrow_fn_once<Fns, Ts> && ...)
requires(fn_once<Fns, Ts> && ...);
Builds a tuple from the provided arguments, or in place by calling the provided functions.
explicit Tuple<Ts...>::Tuple(Tuple const&) = default;
Copies the contained values.
Tuple<Ts...>::Tuple(Tuple const&) = default;
Moves the contained values.
auto Tuple<Ts...>::operator=(Tuple const&) -> Tuple& = default;
Copy assigns the contained values. Deleted for reference types.
auto Tuple<Ts...>::operator=(Tuple&&) -> Tuple& = default;
Move assigns the contained values. Deleted for reference types.
auto Tuple<Ts...>::as_ref() const& noexcept -> Tuple<Ref<Ts>...>
auto Tuple<Ts...>::as_mut() & noexcept -> Tuple<Ref<Ts>...>
Returns a tuple of [mutable] references to the contained values.
template <isize I>
auto Tuple<Ts...>::operator[](Fix<I>) const& noexcept -> Ts[I] const&
requires (I < sizeof...(Ts));
template <isize I>
auto Tuple<Ts...>::operator[](Fix<I>) & noexcept -> Ts[I]&
requires (I < sizeof...(Ts));
template <isize I>
auto Tuple<Ts...>::operator[](Fix<I>) && noexcept(nothrow_movable<Ts[I]>) -> Ts[I]
requires (I < sizeof...(Ts));
Returns the I-th value or a [mutable] reference to it.
Implements the fmt::Debug<Tuple<Ts...>>
trait: prints the contained values.
Implements the cmp::Ord<Tuple<Ts...>, Tuple<Us...>>
trait and operator==
: compares the contained values lexicographically.
template <typename... Ts>
auto tuplify(Ts... args) noexcept(nothrow_movable<Ts> && ...) -> Tuple<Ts...>;
Returns a tuple of the given arguments.
Example:
#include <veg/tuple.hpp>
#include <veg/util/assert.hpp>
auto main() -> int {
using namespace veg;
Tuple<int, float> t0{tuplify, 1, 2.5F};
auto t1 = tuplify(1, 2.5F);
VEG_ASSERT(t0 == t1);
}
namespace tuple {
template <typename... Fns, typename... Ts = meta::invoke_result_t<Fns>...>
auto with(Fns... fns) noexcept(nothrow_fn_once<Fns, Ts> && ...) -> Tuple<Ts...>
requires (fn_once<Fns, Ts> && ...);
} // namespace tuple
Returns a tuple created by calling the given functions.
Example:
#include <veg/tuple.hpp>
#include <veg/util/assert.hpp>
auto main() -> int {
using namespace veg;
Tuple<int, float> t0{tuplify, 1, 2.5F};
auto t1 = tuple::with(
[](){ return 1; },
[](){ return 2.5F; }
);
VEG_ASSERT(t0 == t1);
}
namespace tuple {
template <typename... Tuples>
auto zip(Tuples... tuples) noexcept(nothrow_movable<Tuples> && ...) -> Zip<Tuples>
requires (tuple<Tuples> && ...);
} // namespace tuple
tuple<Tuples>
checks if the type is a tuple (inherits publicly and unambiguously from one Tuple<Ts...>
).
Returns a tuple of tuples, whose Ith element is a tuple containing the Ith element from each parameter tuple.
Example:
#include <veg/tuple.hpp>
#include <veg/util/assert.hpp>
auto main() -> int {
using namespace veg;
auto t0 = tuplify(1, 2, 3);
auto t1 = tuplify(4, 5, 6);
auto t_zipped = tuple::zip(VEG_FWD(t0), VEG_FWD(t1));
VEG_ASSERT(t_zipped == tuplify(
tuplify(1, 4),
tuplify(2, 5),
tuplify(3, 6)
));
}
namespace tuple {
template <typename... Tuples>
auto cat(Tuples... tuples) noexcept(nothrow_movable<Tuples> && ...) -> Cat<Tuples>
requires (tuple<Tuples> && ...);
} // namespace tuple
tuple<Tuples>
checks if the type is a tuple (inherits publicly and unambiguously from one Tuple<Ts...>
).
Returns a tuple that contains the elements of the first tuple, followed by the elements of the second tuple, and so on.
Example:
#include <veg/tuple.hpp>
#include <veg/util/assert.hpp>
auto main() -> int {
using namespace veg;
auto t0 = tuplify(1, 2, 3);
auto t1 = tuplify(4, 5, 6);
auto t_catted = tuple::cat(VEG_FWD(t0), VEG_FWD(t1));
VEG_ASSERT(t_catted == tuplify(1, 2, 3, 4, 5, 6));
}
namespace tuple {
template <typename Fn, typename... Ts, typename Ret = meta::invoke_result_t<Fn, Ts...>>
auto unpack(Tuple<Ts...> tuple, Fn fn) noexcept(nothrow_fn_once<Fn, Ret, Ts...>)
requires fn_once<Fn, Ret, Ts...>;
} // namespace tuple
Returns VEG_FWD(fn)(VEG_FWD(tuple.0), VEG_FWD(tuple.1), ...)
.
Example:
#include <veg/tuple.hpp>
#include <veg/util/assert.hpp>
auto main() -> int {
using namespace veg;
auto t = tuplify(2, 5);
VEG_ASSERT(tuple::unpack(
VEG_FWD(t),
[](auto a, auto b) { return a + b; }
) == 7);
}
namespace tuple {
template <typename Fn, typename... Ts>
void for_each(Tuple<Ts...> tuple, Fn fn) noexcept(nothrow_fn_mut<Fn, void, Ts> && ...)
requires (fn_mut<Fn, void, Ts> && ...);
template <typename Fn, typename... Ts, usize... Is = [0, ..., sizeof...(Ts) - 1]>
void for_each_i(Tuple<Ts...> tuple, Fn fn) noexcept(nothrow_fn_once<inner_ith<Fn&, Is>, void, Ts> && ...)
requires (fn_once<inner_ith<Fn&, Is>, void, Ts> && ...);
} // namespace tuple
Call the provided function (or tuple-ish of functions) for each element in the tuple.
Example:
#include <veg/tuple.hpp>
#include <veg/util/assert.hpp>
auto main() -> int {
using namespace veg;
auto t = tuplify(1, 3.5);
auto print = [](auto a) { dbg(a); };
tuple::for_each(t.as_ref(), print);
auto times_x_in_place = tuplify(
[](RefMut<int> a) { (*a) *= 4; },
[](RefMut<double> a) { (*a) *= 6; }
);
tuple::for_each_i(t.as_mut(), VEG_FWD(times_x_in_place));
VEG_ASSERT(t == tuplify(4, 21));
}
namespace tuple {
template <typename Fn, typename... Ts, typename... Rets = meta::invoke_result_t<Fn&, Ts>...>
auto map(Tuple<Ts...> tuple, Fn fn) noexcept(nothrow_fn_mut<Fn, void, Ts> && ...) -> Tuple<Rets...>
requires (fn_mut<Fn, Rets, Ts> && ...);
template <typename Fn, typename... Ts, usize... Is = [0, ..., sizeof...(Ts) - 1], typename... Rets = meta::invoke_result_t<inner_ith<Fn&, Is>, Ts>...>
void for_each_i(Tuple<Ts...> tuple, Fn fn) noexcept(nothrow_fn_once<inner_ith<Fn&, Is>, Rets, Ts> && ...)
requires (fn_once<inner_ith<Fn&, Is>, Rets, Ts> && ...);
} // namespace tuple
Call the provided function (or tuple-ish of functions) for each element in the tuple and get the result.
Example:
#include <veg/tuple.hpp>
#include <veg/util/assert.hpp>
auto main() -> int {
using namespace veg;
auto t = tuplify(1, 3.5);
auto times_2 = [](auto a) { return 2 * (*a); };
VEG_ASSERT(tuple::map(t.as_ref(), times_2) == tuplify(2, 7.0));
auto times_x = tuplify(
[](Ref<int> a) { return 4 * (*a); },
[](Ref<double> a) { return 6 * (*a); }
);
VEG_ASSERT((tuple::map_i(t.as_ref(), VEG_FWD(times_x))) == tuplify(4, 21));
}