tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
tuple.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2019 Tobias Hienzsch
3
4#ifndef TETL_TUPLE_TUPLE_HPP
5#define TETL_TUPLE_TUPLE_HPP
6
7#include <etl/_config/all.hpp>
8
9#include <etl/_mpl/at.hpp>
10#include <etl/_tuple/ignore.hpp>
11#include <etl/_tuple/is_tuple_like.hpp>
12#include <etl/_tuple/tuple_element.hpp>
13#include <etl/_tuple/tuple_size.hpp>
14#include <etl/_type_traits/declval.hpp>
15#include <etl/_type_traits/index_constant.hpp>
16#include <etl/_type_traits/is_convertible.hpp>
17#include <etl/_type_traits/is_copy_constructible.hpp>
18#include <etl/_type_traits/is_default_constructible.hpp>
19#include <etl/_type_traits/is_implicit_default_constructible.hpp>
20#include <etl/_type_traits/is_move_assignable.hpp>
21#include <etl/_type_traits/is_move_constructible.hpp>
22#include <etl/_type_traits/is_nothrow_move_assignable.hpp>
23#include <etl/_type_traits/is_nothrow_move_constructible.hpp>
24#include <etl/_type_traits/is_nothrow_swappable.hpp>
25#include <etl/_type_traits/is_same.hpp>
26#include <etl/_utility/forward.hpp>
27#include <etl/_utility/index_sequence.hpp>
28#include <etl/_utility/move.hpp>
29#include <etl/_utility/swap.hpp>
30
31namespace etl {
32
33namespace detail {
34
35template <etl::size_t I, typename T>
36struct tuple_leaf {
37 template <typename... Args>
38 constexpr tuple_leaf(Args&&... args)
39 : _value(etl::forward<Args>(args)...)
40 {
41 }
42
43 [[nodiscard]] constexpr auto operator[](index_constant<I> /*idx*/) & noexcept -> T&
44 {
45 return _value;
46 }
47
48 [[nodiscard]] constexpr auto operator[](index_constant<I> /*idx*/) const& noexcept -> T const&
49 {
50 return _value;
51 }
52
53 [[nodiscard]] constexpr auto operator[](index_constant<I> /*idx*/) && noexcept -> T&&
54 {
55 return etl::move(_value);
56 }
57
58 [[nodiscard]] constexpr auto operator[](index_constant<I> /*idx*/) const&& noexcept -> T const&&
59 {
60 return etl::move(_value);
61 }
62
63 constexpr auto swap(index_constant<I> /*idx*/, T& other) noexcept(is_nothrow_swappable_v<T>) -> void
64 {
65 using etl::swap;
66 swap(_value, other);
67 }
68
69private:
70 // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
71 TETL_NO_UNIQUE_ADDRESS T _value;
72};
73
74template <typename... Ts>
75struct tuple_storage;
76
77template <size_t... Idx, typename... Ts>
78struct tuple_storage<etl::index_sequence<Idx...>, Ts...> : tuple_leaf<Idx, Ts>... {
79 explicit(not(is_implicit_default_constructible_v<Ts> and ...)) constexpr tuple_storage()
80 requires((is_default_constructible_v<Ts> and ...))
81 : tuple_leaf<Idx, Ts>{}...
82 {
83 }
84
85 // No. 2
86 explicit(not(is_convertible_v<Ts const&, Ts> and ...)) constexpr tuple_storage(Ts const&... args)
87 requires((is_copy_constructible_v<Ts> and ...) && (sizeof...(Ts) > 0))
88 : tuple_leaf<Idx, Ts>(args)...
89 {
90 }
91
92 // No. 3
93 template <typename... Us>
94 requires((is_constructible_v<Ts, Us &&> and ...) && (sizeof...(Ts) > 0) && (sizeof...(Ts) == sizeof...(Us)))
95 explicit(!(is_convertible_v<Us&&, Ts> and ...)) constexpr tuple_storage(Us&&... args)
96 : tuple_leaf<Idx, Ts>(etl::forward<Us>(args))...
97 {
98 }
99
100 constexpr tuple_storage(tuple_storage const&) = default;
101 constexpr tuple_storage(tuple_storage&&) noexcept = default;
102
103 using tuple_leaf<Idx, Ts>::operator[]...;
104
105 constexpr auto swap(tuple_storage& other) noexcept((is_nothrow_swappable_v<Ts> && ...)) -> void
106 {
107 (tuple_leaf<Idx, Ts>::swap(etl::index_v<Idx>, other[etl::index_v<Idx>]), ...);
108 }
109};
110
111} // namespace detail
112
113template <typename... Ts>
114struct tuple {
115 // No. 1
116 explicit(not(is_implicit_default_constructible_v<Ts> && ...)) constexpr tuple()
117 requires((is_default_constructible_v<Ts> and ...))
118 : _storage()
119 {
120 }
121
122 // No. 2
123 explicit(not(is_convertible_v<Ts const&, Ts> && ...)) constexpr tuple(Ts const&... args)
124 requires((is_copy_constructible_v<Ts> && ...) and (sizeof...(Ts) > 0))
125 : _storage(args...)
126 {
127 }
128
129 // No. 3
130 template <typename... Us>
131 requires((is_constructible_v<Ts, Us &&> && ...) and (sizeof...(Ts) > 0) and (sizeof...(Ts) == sizeof...(Us)))
132 explicit(!(is_convertible_v<Us&&, Ts> && ...)) constexpr tuple(Us&&... args)
133 : _storage(etl::forward<Us>(args)...)
134 {
135 }
136
137 constexpr tuple(tuple const&) = default;
138 constexpr tuple(tuple&&) noexcept = default;
139
140 template <etl::size_t I>
141 [[nodiscard]] constexpr auto operator[](etl::index_constant<I> idx) & noexcept -> auto&
142 {
143 return _storage[idx];
144 }
145
146 template <etl::size_t I>
147 [[nodiscard]] constexpr auto operator[](etl::index_constant<I> idx) const& noexcept -> auto const&
148 {
149 return _storage[idx];
150 }
151
152 template <etl::size_t I>
153 [[nodiscard]] constexpr auto operator[](etl::index_constant<I> idx) && noexcept -> auto&&
154 {
155 return etl::move(_storage)[idx];
156 }
157
158 template <etl::size_t I>
159 [[nodiscard]] constexpr auto operator[](etl::index_constant<I> idx) const&& noexcept -> auto const&&
160 {
161 return etl::move(_storage)[idx];
162 }
163
164 constexpr auto swap(tuple& other) noexcept((is_nothrow_swappable_v<Ts> and ...)) -> void
165 {
166 _storage.swap(other._storage);
167 }
168
169private:
170 using storage_type = detail::tuple_storage<etl::index_sequence_for<Ts...>, Ts...>;
171 TETL_NO_UNIQUE_ADDRESS storage_type _storage; // NOLINT(modernize-use-default-member-init)
172};
173
174template <etl::size_t I, typename... Ts>
175struct tuple_element<I, tuple<Ts...>> {
176 static_assert(I < sizeof...(Ts));
177 using type = mpl::at_t<I, mpl::list<Ts...>>;
178};
179
180template <typename... Ts>
181struct tuple_size<tuple<Ts...>> : integral_constant<size_t, sizeof...(Ts)> { };
182
183template <typename... Ts>
184inline constexpr auto is_tuple_like<etl::tuple<Ts...>> = true;
185
186template <etl::size_t I, typename... Ts>
187[[nodiscard]] constexpr auto get(tuple<Ts...>& t) -> auto&
188{
189 static_assert(I < sizeof...(Ts));
190 return t[etl::index_v<I>];
191}
192
193template <etl::size_t I, typename... Ts>
194[[nodiscard]] constexpr auto get(tuple<Ts...> const& t) -> auto const&
195{
196 static_assert(I < sizeof...(Ts));
197 return t[etl::index_v<I>];
198}
199
200template <etl::size_t I, typename... Ts>
201[[nodiscard]] constexpr auto get(tuple<Ts...>&& t) -> auto&&
202{
203 static_assert(I < sizeof...(Ts));
204 return etl::move(t)[etl::index_v<I>];
205}
206
207template <etl::size_t I, typename... Ts>
208[[nodiscard]] constexpr auto get(tuple<Ts...> const&& t) -> auto const&&
209{
210 static_assert(I < sizeof...(Ts));
211 return etl::move(t)[etl::index_v<I>];
212}
213
214template <typename... Ts, typename... Us>
215 requires(sizeof...(Ts) == sizeof...(Us))
216[[nodiscard]] constexpr auto operator==(tuple<Ts...> const& lhs, tuple<Us...> const& rhs) -> bool
217{
218 if constexpr (sizeof...(Ts) == 0) {
219 return false;
220 } else {
221 return [&]<etl::size_t... Is>(etl::index_sequence<Is...> /*i*/) {
222 using etl::get;
223 return ((get<Is>(lhs) == get<Is>(rhs)) and ...);
224 }(etl::index_sequence_for<Ts...>{});
225 }
226}
227
228} // namespace etl
229
230#endif // TETL_TUPLE_TUPLE_HPP
Definition at.hpp:10
Definition adjacent_find.hpp:9
constexpr auto get(tuple< Ts... > const &&t) -> auto const &&
Definition tuple.hpp:208
constexpr auto get(tuple< Ts... > &t) -> auto &
Definition tuple.hpp:187
constexpr auto get(tuple< Ts... > const &t) -> auto const &
Definition tuple.hpp:194
constexpr auto operator==(tuple< Ts... > const &lhs, tuple< Us... > const &rhs) -> bool
Definition tuple.hpp:216
constexpr auto get(tuple< Ts... > &&t) -> auto &&
Definition tuple.hpp:201
Definition integral_constant.hpp:10
Definition list.hpp:11
Definition tuple.hpp:114
constexpr tuple(tuple const &)=default
constexpr auto swap(tuple &other) noexcept((is_nothrow_swappable_v< Ts > and ...)) -> void
Definition tuple.hpp:164
constexpr auto operator[](etl::index_constant< I > idx) const &&noexcept -> auto const &&
Definition tuple.hpp:159
constexpr auto operator[](etl::index_constant< I > idx) &&noexcept -> auto &&
Definition tuple.hpp:153
explicit(!(is_convertible_v< Us &&, Ts > &&...)) const expr tuple(Us &&... args)
Definition tuple.hpp:132
constexpr tuple(tuple &&) noexcept=default
explicit(not(is_convertible_v< Ts const &, Ts > &&...)) const expr tuple(Ts const &... args)
Definition tuple.hpp:123
constexpr auto operator[](etl::index_constant< I > idx) &noexcept -> auto &
Definition tuple.hpp:141
constexpr auto operator[](etl::index_constant< I > idx) const &noexcept -> auto const &
Definition tuple.hpp:147