| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | //====================================================================================================================== | ||
| 2 | //! @file | ||
| 3 | /* | ||
| 4 | KUMI - Compact Tuple Tools | ||
| 5 | Copyright : KUMI Project Contributors | ||
| 6 | SPDX-License-Identifier: BSL-1.0 | ||
| 7 | */ | ||
| 8 | //====================================================================================================================== | ||
| 9 | #pragma once | ||
| 10 | |||
| 11 | #include <kumi/product_types/tuple.hpp> | ||
| 12 | |||
| 13 | namespace kumi | ||
| 14 | { | ||
| 15 | //==================================================================================================================== | ||
| 16 | /** | ||
| 17 | @class record | ||
| 18 | @ingroup kumi_record_related | ||
| 19 | @brief Fixed-size collection of heterogeneous tagged fields, tags are unique. | ||
| 20 | |||
| 21 | kumi::record provides an aggregate based implementation of a record. It provides algorithms and | ||
| 22 | functions designed to facilitate record's handling and transformations. | ||
| 23 | |||
| 24 | kumi::record is also compatible with standard tuple operations and structured bindings to some | ||
| 25 | extent. | ||
| 26 | |||
| 27 | @tparam Ts Sequence of fields stored inside kumi::record. | ||
| 28 | |||
| 29 | @see @ref kumi_record_type | ||
| 30 | |||
| 31 | ## Example: | ||
| 32 | @include doc/record/api/introduction.cpp | ||
| 33 | **/ | ||
| 34 | //==================================================================================================================== | ||
| 35 | template<typename... Ts> struct record | ||
| 36 | { | ||
| 37 | using is_record_type = void; | ||
| 38 | using set_t = kumi::_::make_set_t<Ts...>; | ||
| 39 | |||
| 40 | static constexpr bool is_homogeneous = false; | ||
| 41 | |||
| 42 | set_t impl; | ||
| 43 | |||
| 44 | //================================================================================================================== | ||
| 45 | /** | ||
| 46 | @name Accessors | ||
| 47 | @{ | ||
| 48 | **/ | ||
| 49 | //================================================================================================================== | ||
| 50 | |||
| 51 | //================================================================================================================== | ||
| 52 | /** | ||
| 53 | @brief Extracts the Ith field from a kumi::record | ||
| 54 | |||
| 55 | @note Does not participate in overload resolution if `I` is not in [0, sizeof...(Ts)). | ||
| 56 | @param i Compile-time index of the field to access | ||
| 57 | @return A reference to the selected field of current record. | ||
| 58 | |||
| 59 | ## Example: | ||
| 60 | @include doc/record/api/subscript.cpp | ||
| 61 | **/ | ||
| 62 | //================================================================================================================== | ||
| 63 | template<std::size_t I> | ||
| 64 | KUMI_ABI constexpr decltype(auto) operator[]([[maybe_unused]] kumi::index_t<I> i) & noexcept | ||
| 65 | requires(I < sizeof...(Ts)) | ||
| 66 | { | ||
| 67 | using T = kumi::element_t<I, tuple<Ts...>>; | ||
| 68 | 1448 | return static_cast<T&>(impl); | |
| 69 | } | ||
| 70 | |||
| 71 | /// @overload | ||
| 72 | template<std::size_t I> | ||
| 73 | KUMI_ABI constexpr decltype(auto) operator[](kumi::index_t<I>) && noexcept | ||
| 74 | requires(I < sizeof...(Ts)) | ||
| 75 | { | ||
| 76 | using T = kumi::element_t<I, tuple<Ts...>>; | ||
| 77 | 615 | return static_cast<T&&>(static_cast<set_t&&>(impl)); | |
| 78 | } | ||
| 79 | |||
| 80 | /// @overload | ||
| 81 | template<std::size_t I> | ||
| 82 | KUMI_ABI constexpr decltype(auto) operator[](kumi::index_t<I>) const&& noexcept | ||
| 83 | requires(I < sizeof...(Ts)) | ||
| 84 | { | ||
| 85 | using T = kumi::element_t<I, tuple<Ts...>>; | ||
| 86 | 13 | return static_cast<T const&&>(static_cast<set_t const&&>(impl)); | |
| 87 | } | ||
| 88 | |||
| 89 | /// @overload | ||
| 90 | template<std::size_t I> | ||
| 91 | KUMI_ABI constexpr decltype(auto) operator[](kumi::index_t<I>) const& noexcept | ||
| 92 | requires(I < sizeof...(Ts)) | ||
| 93 | { | ||
| 94 | using T = kumi::element_t<I, tuple<Ts...>>; | ||
| 95 | 904 | return static_cast<T const&>(impl); | |
| 96 | } | ||
| 97 | |||
| 98 | //================================================================================================================== | ||
| 99 | /** | ||
| 100 | @brief Extracts the element with type T from a kumi::record | ||
| 101 | |||
| 102 | @note Does not participate in overload resolution if `T` is not present in the record or if | ||
| 103 | the record contains duplicate types | ||
| 104 | |||
| 105 | @param type The type to access in the record | ||
| 106 | @return A reference to the selected element of current record. | ||
| 107 | |||
| 108 | ## Example: | ||
| 109 | @include doc/record/api/typed_subscript.cpp | ||
| 110 | **/ | ||
| 111 | //================================================================================================================== | ||
| 112 | template<typename T> | ||
| 113 | KUMI_ABI constexpr decltype(auto) operator[]([[maybe_unused]] kumi::as<T> type) & noexcept | ||
| 114 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 115 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 116 | { | ||
| 117 | 10 | return impl(std::type_identity<T>{}); | |
| 118 | } | ||
| 119 | |||
| 120 | /// @overload | ||
| 121 | template<typename T> | ||
| 122 | KUMI_ABI constexpr decltype(auto) operator[](kumi::as<T>) && noexcept | ||
| 123 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 124 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 125 | { | ||
| 126 | return static_cast<set_t&&>(impl)(std::type_identity<T>{}); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// @overload | ||
| 130 | template<typename T> | ||
| 131 | KUMI_ABI constexpr decltype(auto) operator[](kumi::as<T>) const&& noexcept | ||
| 132 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 133 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 134 | { | ||
| 135 | return static_cast<set_t const&&>(impl)(std::type_identity<T>{}); | ||
| 136 | } | ||
| 137 | |||
| 138 | /// @overload | ||
| 139 | template<typename T> | ||
| 140 | KUMI_ABI constexpr decltype(auto) operator[](kumi::as<T>) const& noexcept | ||
| 141 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 142 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 143 | { | ||
| 144 | 3 | return impl(std::type_identity<T>{}); | |
| 145 | } | ||
| 146 | |||
| 147 | //================================================================================================================== | ||
| 148 | /** | ||
| 149 | @brief Extracts the element of the field labeled L from a kumi::record | ||
| 150 | |||
| 151 | @note Does not participate in overload resolution if the label is not present in the record | ||
| 152 | |||
| 153 | @param l label of the field to access | ||
| 154 | @return A reference to the element of the selected field of current record. | ||
| 155 | |||
| 156 | ## Example: | ||
| 157 | @include doc/record/api/labeled_subscript.cpp | ||
| 158 | **/ | ||
| 159 | //================================================================================================================== | ||
| 160 | |||
| 161 | template<kumi::str Name> | ||
| 162 | KUMI_ABI constexpr decltype(auto) operator[]([[maybe_unused]] kumi::label_t<Name> l) & noexcept | ||
| 163 | requires(kumi::concepts::contains_label<kumi::label_t<Name>, Ts...>) | ||
| 164 | { | ||
| 165 | 35 | return impl(std::integral_constant<kumi::str<Name.size()>, Name>{}); | |
| 166 | } | ||
| 167 | |||
| 168 | /// @overload | ||
| 169 | template<kumi::str Name> | ||
| 170 | KUMI_ABI constexpr decltype(auto) operator[](kumi::label_t<Name>) && noexcept | ||
| 171 | requires(kumi::concepts::contains_label<kumi::label_t<Name>, Ts...>) | ||
| 172 | { | ||
| 173 | return static_cast<set_t&&>(impl)(std::integral_constant<kumi::str<Name.size()>, Name>{}); | ||
| 174 | } | ||
| 175 | |||
| 176 | /// @overload | ||
| 177 | template<kumi::str Name> | ||
| 178 | KUMI_ABI constexpr decltype(auto) operator[](kumi::label_t<Name>) const&& noexcept | ||
| 179 | requires(kumi::concepts::contains_label<kumi::label_t<Name>, Ts...>) | ||
| 180 | { | ||
| 181 | return static_cast<set_t const&&>(impl)(std::integral_constant<kumi::str<Name.size()>, Name>{}); | ||
| 182 | } | ||
| 183 | |||
| 184 | /// @overload | ||
| 185 | template<kumi::str Name> | ||
| 186 | KUMI_ABI constexpr decltype(auto) operator[](kumi::label_t<Name>) const& noexcept | ||
| 187 | requires(kumi::concepts::contains_label<kumi::label_t<Name>, Ts...>) | ||
| 188 | { | ||
| 189 | 3 | return impl(std::integral_constant<kumi::str<Name.size()>, Name>{}); | |
| 190 | } | ||
| 191 | |||
| 192 | //================================================================================================================== | ||
| 193 | /** | ||
| 194 | @brief Extracts the element whose identifier matches Id from a kumi::record | ||
| 195 | |||
| 196 | @note Does not participate in overload resolution if no field whose identifier matches Id is present in | ||
| 197 | the record. | ||
| 198 | @tparam Id Identifier of the element to access | ||
| 199 | @return A reference to the selected element of current record. | ||
| 200 | |||
| 201 | ## Example: | ||
| 202 | @include doc/record/api/named_subscript.cpp | ||
| 203 | **/ | ||
| 204 | //================================================================================================================== | ||
| 205 | template<kumi::concepts::identifier Id> | ||
| 206 | KUMI_ABI constexpr decltype(auto) operator[](Id const&) & noexcept | ||
| 207 | requires(kumi::concepts::contains_identifier<Id, Ts...>) | ||
| 208 | { | ||
| 209 | 196 | return impl(kumi::_::tag_of_t<Id>{}); | |
| 210 | } | ||
| 211 | |||
| 212 | /// @overload | ||
| 213 | template<kumi::concepts::identifier Id> | ||
| 214 | KUMI_ABI constexpr decltype(auto) operator[](Id const&) && noexcept | ||
| 215 | requires(kumi::concepts::contains_identifier<Id, Ts...>) | ||
| 216 | { | ||
| 217 | 22 | return static_cast<set_t&&>(impl)(kumi::_::tag_of_t<Id>{}); | |
| 218 | } | ||
| 219 | |||
| 220 | /// @overload | ||
| 221 | template<kumi::concepts::identifier Id> | ||
| 222 | KUMI_ABI constexpr decltype(auto) operator[](Id const&) const&& noexcept | ||
| 223 | requires(kumi::concepts::contains_identifier<Id, Ts...>) | ||
| 224 | { | ||
| 225 | return static_cast<set_t const&&>(impl)(kumi::_::tag_of_t<Id>{}); | ||
| 226 | } | ||
| 227 | |||
| 228 | /// @overload | ||
| 229 | template<kumi::concepts::identifier Id> | ||
| 230 | KUMI_ABI constexpr decltype(auto) operator[](Id const&) const& noexcept | ||
| 231 | requires(kumi::concepts::contains_identifier<Id, Ts...>) | ||
| 232 | { | ||
| 233 | 1230 | return impl(kumi::_::tag_of_t<Id>{}); | |
| 234 | } | ||
| 235 | |||
| 236 | //================================================================================================================== | ||
| 237 | //! @} | ||
| 238 | //================================================================================================================== | ||
| 239 | |||
| 240 | //================================================================================================================== | ||
| 241 | /** | ||
| 242 | @name Properties | ||
| 243 | @{ | ||
| 244 | **/ | ||
| 245 | //================================================================================================================== | ||
| 246 | |||
| 247 | /// @return Returns the number of elements in a kumi::record | ||
| 248 | 21 | [[nodiscard]] KUMI_ABI static constexpr auto size() noexcept { return sizeof...(Ts); } | |
| 249 | |||
| 250 | /// @return Returns `true` if a kumi::record contains 0 elements | ||
| 251 | [[nodiscard]] KUMI_ABI static constexpr bool empty() noexcept { return sizeof...(Ts) == 0; } | ||
| 252 | |||
| 253 | /// Returns the identifiers associated to the elements of a kumi::record | ||
| 254 | [[nodiscard]] KUMI_ABI static constexpr auto identifiers() noexcept { return tuple{kumi::identifier_of<Ts>()...}; } | ||
| 255 | |||
| 256 | /// Returns the labels associated to the elements of a kumi::record | ||
| 257 | [[nodiscard]] KUMI_ABI static constexpr auto labels() noexcept { return tuple{kumi::label_of<Ts>()...}; } | ||
| 258 | |||
| 259 | // The type is named rather than taken from decltype(*this): nvcc rejects that spelling inside a | ||
| 260 | // lambda in a member function, and it is the only thing that kept a record out of a kernel. | ||
| 261 | /// Returns references to the values of the elements in a kumi::record | ||
| 262 | [[nodiscard]] KUMI_ABI constexpr auto values() noexcept | ||
| 263 | { | ||
| 264 | return [&]<std::size_t... I>(std::index_sequence<I...>) { | ||
| 265 | return tuple<stored_member_t<I, record&>...>{kumi::field_value_of(get<I>(*this))...}; | ||
| 266 | }(std::make_index_sequence<sizeof...(Ts)>{}); | ||
| 267 | } | ||
| 268 | |||
| 269 | /// @overload | ||
| 270 | [[nodiscard]] KUMI_ABI constexpr auto values() const noexcept | ||
| 271 | { | ||
| 272 | return [&]<std::size_t... I>(std::index_sequence<I...>) { | ||
| 273 | return tuple<stored_member_t<I, record const&>...>{kumi::field_value_of(get<I>(*this))...}; | ||
| 274 | }(std::make_index_sequence<sizeof...(Ts)>{}); | ||
| 275 | } | ||
| 276 | |||
| 277 | //================================================================================================================== | ||
| 278 | //! @} | ||
| 279 | //================================================================================================================== | ||
| 280 | |||
| 281 | //================================================================================================================== | ||
| 282 | /** | ||
| 283 | @brief Replaces the content of the record with the content of another record. | ||
| 284 | @param other kumi::record to copy or move from | ||
| 285 | @return `*this` | ||
| 286 | |||
| 287 | @note This function does not participate in overload resolution if the fields in each record | ||
| 288 | do not match or if the types between two matching fields do not match. | ||
| 289 | **/ | ||
| 290 | //================================================================================================================== | ||
| 291 | template<typename... Us> | ||
| 292 | KUMI_ABI constexpr record& operator=(record<Us...> const& other) | ||
| 293 | requires(kumi::concepts::equivalent<record, record<Us...>>) | ||
| 294 | #ifndef KUMI_DOXYGEN_INVOKED | ||
| 295 | && (kumi::_::fieldwise_convertible<record, record<Us...>>) | ||
| 296 | #endif | ||
| 297 | { | ||
| 298 | ((get<kumi::identifier_of<Ts>()>(*this) = get<kumi::identifier_of<Ts>()>(KUMI_FWD(other))), ...); | ||
| 299 | return *this; | ||
| 300 | } | ||
| 301 | |||
| 302 | /// @overload | ||
| 303 | template<typename... Us> | ||
| 304 | KUMI_ABI constexpr record& operator=(record<Us...>&& other) | ||
| 305 | requires(kumi::concepts::equivalent<record, record<Us...>>) | ||
| 306 | #ifndef KUMI_DOXYGEN_INVOKED | ||
| 307 | && (kumi::_::fieldwise_convertible<record, record<Us...>>) | ||
| 308 | #endif | ||
| 309 | { | ||
| 310 | 11 | ((get<kumi::identifier_of<Ts>()>(*this) = get<kumi::identifier_of<Ts>()>(KUMI_FWD(other))), ...); | |
| 311 | 2 | return *this; | |
| 312 | } | ||
| 313 | }; | ||
| 314 | |||
| 315 | //================================================================================================================== | ||
| 316 | /** | ||
| 317 | @name Comparison operators | ||
| 318 | @related kumi::record | ||
| 319 | @{ | ||
| 320 | **/ | ||
| 321 | //================================================================================================================== | ||
| 322 | |||
| 323 | /// @brief Compares a record with another for equality | ||
| 324 | template<typename... Ts, typename... Us> | ||
| 325 | KUMI_ABI constexpr auto operator==(record<Ts...> const& self, record<Us...> const& other) noexcept | ||
| 326 | #ifndef KUMI_DOXYGEN_INVOKED | ||
| 327 | requires(kumi::_::fieldwise_comparable<record<Ts...>, record<Us...>>) | ||
| 328 | #endif | ||
| 329 | { | ||
| 330 |
113/156✓ Branch 1 taken 27 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 19 times.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 16 times.
✓ Branch 11 taken 5 times.
✓ Branch 12 taken 8 times.
✓ Branch 13 taken 12 times.
✓ Branch 14 taken 6 times.
✓ Branch 15 taken 6 times.
✓ Branch 16 taken 12 times.
✓ Branch 17 taken 8 times.
✓ Branch 18 taken 3 times.
✓ Branch 19 taken 12 times.
✓ Branch 20 taken 11 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 12 times.
✓ Branch 23 taken 6 times.
✓ Branch 24 taken 1 times.
✓ Branch 25 taken 12 times.
✓ Branch 26 taken 6 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 12 times.
✓ Branch 29 taken 6 times.
✓ Branch 30 taken 1 times.
✓ Branch 31 taken 9 times.
✓ Branch 32 taken 8 times.
✓ Branch 33 taken 1 times.
✓ Branch 34 taken 10 times.
✓ Branch 35 taken 8 times.
✓ Branch 36 taken 1 times.
✓ Branch 37 taken 12 times.
✓ Branch 38 taken 5 times.
✓ Branch 39 taken 1 times.
✓ Branch 40 taken 12 times.
✓ Branch 41 taken 5 times.
✓ Branch 42 taken 2 times.
✓ Branch 43 taken 10 times.
✓ Branch 44 taken 6 times.
✓ Branch 45 taken 1 times.
✓ Branch 46 taken 9 times.
✓ Branch 47 taken 14 times.
✓ Branch 48 taken 1 times.
✓ Branch 49 taken 5 times.
✓ Branch 50 taken 14 times.
✗ Branch 51 not taken.
✓ Branch 52 taken 3 times.
✓ Branch 53 taken 15 times.
✗ Branch 54 not taken.
✓ Branch 55 taken 3 times.
✓ Branch 56 taken 11 times.
✓ Branch 57 taken 1 times.
✓ Branch 58 taken 3 times.
✓ Branch 59 taken 5 times.
✓ Branch 60 taken 1 times.
✓ Branch 61 taken 3 times.
✓ Branch 62 taken 4 times.
✓ Branch 63 taken 1 times.
✓ Branch 64 taken 3 times.
✓ Branch 65 taken 4 times.
✓ Branch 66 taken 1 times.
✓ Branch 67 taken 2 times.
✓ Branch 68 taken 2 times.
✓ Branch 69 taken 1 times.
✓ Branch 70 taken 2 times.
✓ Branch 71 taken 2 times.
✓ Branch 72 taken 1 times.
✓ Branch 73 taken 2 times.
✓ Branch 74 taken 1 times.
✓ Branch 75 taken 1 times.
✓ Branch 76 taken 1 times.
✓ Branch 77 taken 1 times.
✗ Branch 78 not taken.
✓ Branch 79 taken 1 times.
✓ Branch 80 taken 1 times.
✗ Branch 81 not taken.
✓ Branch 82 taken 1 times.
✓ Branch 83 taken 1 times.
✗ Branch 84 not taken.
✓ Branch 85 taken 1 times.
✓ Branch 86 taken 1 times.
✗ Branch 87 not taken.
✓ Branch 89 taken 1 times.
✓ Branch 90 taken 1 times.
✗ Branch 91 not taken.
✓ Branch 92 taken 1 times.
✓ Branch 93 taken 1 times.
✗ Branch 94 not taken.
✓ Branch 95 taken 1 times.
✓ Branch 96 taken 1 times.
✗ Branch 97 not taken.
✓ Branch 98 taken 2 times.
✗ Branch 99 not taken.
✓ Branch 101 taken 2 times.
✗ Branch 102 not taken.
✓ Branch 104 taken 2 times.
✗ Branch 105 not taken.
✓ Branch 107 taken 3 times.
✗ Branch 108 not taken.
✓ Branch 110 taken 3 times.
✗ Branch 111 not taken.
✓ Branch 113 taken 3 times.
✗ Branch 114 not taken.
✓ Branch 116 taken 3 times.
✗ Branch 117 not taken.
✓ Branch 119 taken 3 times.
✗ Branch 120 not taken.
✓ Branch 122 taken 2 times.
✗ Branch 123 not taken.
✓ Branch 125 taken 2 times.
✗ Branch 126 not taken.
✓ Branch 128 taken 2 times.
✗ Branch 129 not taken.
✓ Branch 131 taken 3 times.
✗ Branch 132 not taken.
✓ Branch 134 taken 3 times.
✗ Branch 135 not taken.
✓ Branch 137 taken 3 times.
✗ Branch 138 not taken.
✓ Branch 140 taken 1 times.
✗ Branch 141 not taken.
✓ Branch 143 taken 1 times.
✗ Branch 144 not taken.
✓ Branch 146 taken 1 times.
✗ Branch 147 not taken.
✓ Branch 149 taken 1 times.
✗ Branch 150 not taken.
✓ Branch 152 taken 1 times.
✗ Branch 153 not taken.
✓ Branch 155 taken 1 times.
✗ Branch 156 not taken.
✓ Branch 158 taken 1 times.
✗ Branch 159 not taken.
✓ Branch 161 taken 1 times.
✗ Branch 162 not taken.
✓ Branch 165 taken 2 times.
✗ Branch 166 not taken.
✓ Branch 168 taken 2 times.
✗ Branch 169 not taken.
✓ Branch 171 taken 2 times.
✗ Branch 172 not taken.
✓ Branch 174 taken 2 times.
✗ Branch 175 not taken.
✓ Branch 177 taken 2 times.
✗ Branch 178 not taken.
✓ Branch 180 taken 2 times.
✗ Branch 181 not taken.
✓ Branch 183 taken 2 times.
✗ Branch 184 not taken.
✓ Branch 186 taken 2 times.
✗ Branch 187 not taken.
|
1170 | return ((get<kumi::identifier_of<Ts>()>(self) == get<kumi::identifier_of<Ts>()>(other)) && ...); |
| 331 | } | ||
| 332 | |||
| 333 | /// @brief Compares a record with another for inequality | ||
| 334 | template<typename... Ts, typename... Us> | ||
| 335 | KUMI_ABI constexpr auto operator!=(record<Ts...> const& self, record<Us...> const& other) noexcept | ||
| 336 | #ifndef KUMI_DOXYGEN_INVOKED | ||
| 337 | requires(kumi::_::fieldwise_comparable<record<Ts...>, record<Us...>>) | ||
| 338 | #endif | ||
| 339 | { | ||
| 340 | return !(self == other); | ||
| 341 | } | ||
| 342 | |||
| 343 | //================================================================================================================== | ||
| 344 | //! @} | ||
| 345 | //================================================================================================================== | ||
| 346 | |||
| 347 | //================================================================================================================== | ||
| 348 | /** | ||
| 349 | @related kumi::record | ||
| 350 | @brief Inserts a kumi::record in an output stream | ||
| 351 | **/ | ||
| 352 | //================================================================================================================== | ||
| 353 | template<typename CharT, typename Traits, typename... Ts> | ||
| 354 | 291 | std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, record<Ts...> const& t) noexcept | |
| 355 | { | ||
| 356 | 291 | return kumi::_::print(os, t, '{', ',', '}', std::make_index_sequence<sizeof...(Ts) - 1>{}); | |
| 357 | } | ||
| 358 | |||
| 359 | template<> struct record<> | ||
| 360 | { | ||
| 361 | using is_record_type = void; | ||
| 362 | static constexpr bool is_homogeneous = false; | ||
| 363 | |||
| 364 | 6 | [[nodiscard]] KUMI_ABI static constexpr auto size() noexcept { return std::size_t{0}; } | |
| 365 | |||
| 366 | [[nodiscard]] KUMI_ABI static constexpr auto empty() noexcept { return true; } | ||
| 367 | |||
| 368 | [[nodiscard]] KUMI_ABI static constexpr auto names() noexcept { return kumi::tuple{}; } | ||
| 369 | |||
| 370 | [[nodiscard]] KUMI_ABI static constexpr auto values() noexcept { return kumi::tuple{}; } | ||
| 371 | |||
| 372 | 32 | KUMI_ABI friend constexpr auto operator<=>(record<>, record<>) noexcept = default; | |
| 373 | |||
| 374 | template<typename T> | ||
| 375 | [[nodiscard]] KUMI_ABI constexpr operator T() const noexcept | ||
| 376 | requires(kumi::concepts::unit_type<T>) | ||
| 377 | { | ||
| 378 | return {}; | ||
| 379 | } | ||
| 380 | |||
| 381 | template<typename T> | ||
| 382 | [[nodiscard]] KUMI_ABI constexpr operator T() noexcept | ||
| 383 | requires(kumi::concepts::unit_type<T>) | ||
| 384 | { | ||
| 385 | return {}; | ||
| 386 | } | ||
| 387 | |||
| 388 | template<typename CharT, typename Traits> | ||
| 389 | 2 | friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, record<>) noexcept | |
| 390 | { | ||
| 391 | 2 | return os << "{}"; | |
| 392 | } | ||
| 393 | }; | ||
| 394 | |||
| 395 | //==================================================================================================================== | ||
| 396 | // Specialisation to clearly signal errors due to duplicate fields | ||
| 397 | //==================================================================================================================== | ||
| 398 | template<typename... Ts> | ||
| 399 | requires(!kumi::concepts::uniquely_named<Ts...> || !kumi::concepts::fully_named<Ts...> || | ||
| 400 | !kumi::concepts::uniquely_labeled<Ts...>) | ||
| 401 | struct record<Ts...> | ||
| 402 | { | ||
| 403 | static_assert(kumi::concepts::uniquely_named<Ts...>, "Duplicate fields in record definition"); | ||
| 404 | static_assert(kumi::concepts::uniquely_labeled<Ts...>, "Duplicate identifier representation in record definition"); | ||
| 405 | static_assert(kumi::concepts::fully_named<Ts...>, "Anonymous field usage in record definition"); | ||
| 406 | record(Ts&&...) = delete; | ||
| 407 | }; | ||
| 408 | |||
| 409 | //==================================================================================================================== | ||
| 410 | /** | ||
| 411 | @name Record Deduction Guides | ||
| 412 | @{ | ||
| 413 | **/ | ||
| 414 | //==================================================================================================================== | ||
| 415 | |||
| 416 | //==================================================================================================================== | ||
| 417 | /** | ||
| 418 | @related kumi::record | ||
| 419 | @brief kumi::record deduction guide | ||
| 420 | @tparam Ts Type lists to build the record with. | ||
| 421 | **/ | ||
| 422 | //==================================================================================================================== | ||
| 423 | template<typename... Ts> record(Ts&&...) -> record<std::unwrap_ref_decay_t<Ts>...>; | ||
| 424 | |||
| 425 | //==================================================================================================================== | ||
| 426 | //! @} | ||
| 427 | //==================================================================================================================== | ||
| 428 | |||
| 429 | //==================================================================================================================== | ||
| 430 | /** | ||
| 431 | @name Record construction | ||
| 432 | @{ | ||
| 433 | **/ | ||
| 434 | //==================================================================================================================== | ||
| 435 | |||
| 436 | template<kumi::concepts::identifier auto... Fields> struct tie_as_record_t | ||
| 437 | { | ||
| 438 | template<typename... Ts> [[nodiscard]] KUMI_ABI constexpr auto operator()(Ts&... ts) const | ||
| 439 | { | ||
| 440 | 10 | return kumi::record<kumi::field<decltype(Fields), Ts&>...>{ts...}; | |
| 441 | } | ||
| 442 | }; | ||
| 443 | |||
| 444 | //==================================================================================================================== | ||
| 445 | /** | ||
| 446 | @ingroup kumi_record_related | ||
| 447 | |||
| 448 | @var tie_as_record | ||
| 449 | @brief Creates a kumi::record of lvalue references to its arguments. | ||
| 450 | |||
| 451 | @qualifier inline | ||
| 452 | @qualifier constexpr | ||
| 453 | @qualifier nodiscard | ||
| 454 | |||
| 455 | @groupheader{Header file} | ||
| 456 | @code | ||
| 457 | #include <kumi/product_types/record.hpp> | ||
| 458 | @endcode | ||
| 459 | |||
| 460 | @groupheader{Call Signature} | ||
| 461 | |||
| 462 | @code | ||
| 463 | template<kumi::concepts::identifier auto... Fields, typename... Ts> | ||
| 464 | constexpr auto tie_as_record(Ts&... ts); | ||
| 465 | @endcode | ||
| 466 | |||
| 467 | @subgroupheader{Parameters} | ||
| 468 | |||
| 469 | - `Fields` : Non type template parameters names to associate with each element. | ||
| 470 | - `ts`: Zero or more lvalue arguments to construct the record from. | ||
| 471 | |||
| 472 | @subgroupheader{Return value} | ||
| 473 | |||
| 474 | - A kumi::record object containing lvalue references. | ||
| 475 | |||
| 476 | @groupheader{Example} | ||
| 477 | |||
| 478 | @godbolt{doc/record/api/tie_as_record.cpp} | ||
| 479 | |||
| 480 | **/ | ||
| 481 | //==================================================================================================================== | ||
| 482 | template<kumi::concepts::identifier auto... Fields> | ||
| 483 | KUMI_VARIABLE_ABI constexpr tie_as_record_t<Fields...> tie_as_record{}; | ||
| 484 | |||
| 485 | template<kumi::concepts::identifier auto... Fields> struct forward_as_record_t | ||
| 486 | { | ||
| 487 | template<typename... Ts> | ||
| 488 | [[nodiscard]] KUMI_ABI constexpr auto operator()(Ts&&... ts) const | ||
| 489 | requires(sizeof...(Fields) == sizeof...(Ts)) | ||
| 490 | { | ||
| 491 | 6 | return kumi::record<kumi::field<decltype(Fields), Ts&&>...>{KUMI_FWD(ts)...}; | |
| 492 | } | ||
| 493 | }; | ||
| 494 | |||
| 495 | //==================================================================================================================== | ||
| 496 | /** | ||
| 497 | @ingroup kumi_record_related | ||
| 498 | |||
| 499 | @var forward_as_record | ||
| 500 | @brief Creates a kumi::record of forwarding references to its arguments. | ||
| 501 | |||
| 502 | Constructs a record of references to the arguments in ts suitable for forwarding as an | ||
| 503 | argument to a function. The record has rvalue reference data members when rvalues are used as | ||
| 504 | arguments, and otherwise has lvalue reference data members. | ||
| 505 | |||
| 506 | @note If the arguments are temporaries, `forward_as_record` does not extend their lifetime; | ||
| 507 | they have to be used before the end of the full expression. | ||
| 508 | |||
| 509 | @qualifier inline | ||
| 510 | @qualifier constexpr | ||
| 511 | @qualifier nodiscard | ||
| 512 | |||
| 513 | @groupheader{Header file} | ||
| 514 | @code | ||
| 515 | #include <kumi/product_types/record.hpp> | ||
| 516 | @endcode | ||
| 517 | |||
| 518 | @groupheader{Call Signature} | ||
| 519 | |||
| 520 | @code | ||
| 521 | template<typename... Ts> | ||
| 522 | constexpr auto forward_as_record(Ts&&... ts); | ||
| 523 | @endcode | ||
| 524 | |||
| 525 | @subgroupheader{Parameters} | ||
| 526 | - `Fields`: Non type template parameters names to associate with each element. | ||
| 527 | - `ts`: Zero or more lvalue arguments to construct the record from. | ||
| 528 | |||
| 529 | @subgroupheader{Return value} | ||
| 530 | |||
| 531 | - A kumi::record constructed as `kumi::record<kumi::field<decltype(Fields),Ts&&>...>(std::forward<Ts>(ts)...)` | ||
| 532 | |||
| 533 | @groupheader{Example} | ||
| 534 | |||
| 535 | @godbolt{doc/record/api/forward_as_record.cpp} | ||
| 536 | |||
| 537 | **/ | ||
| 538 | //==================================================================================================================== | ||
| 539 | template<kumi::concepts::identifier auto... Fields> | ||
| 540 | KUMI_VARIABLE_ABI constexpr forward_as_record_t<Fields...> forward_as_record{}; | ||
| 541 | |||
| 542 | struct make_record_t | ||
| 543 | { | ||
| 544 | template<typename... Ts> | ||
| 545 | [[nodiscard]] KUMI_ABI constexpr auto operator()(Ts&&... ts) const -> kumi::record<std::unwrap_ref_decay_t<Ts>...> | ||
| 546 | requires(kumi::concepts::uniquely_named<Ts...> && kumi::concepts::fully_named<Ts...>) | ||
| 547 | { | ||
| 548 | 185 | return {KUMI_FWD(ts)...}; | |
| 549 | 1 | } | |
| 550 | }; | ||
| 551 | |||
| 552 | //==================================================================================================================== | ||
| 553 | /** | ||
| 554 | @ingroup kumi_record_related | ||
| 555 | |||
| 556 | @var make_record | ||
| 557 | @brief Creates a record object, deducing the target type from the types of arguments. | ||
| 558 | |||
| 559 | @qualifier inline | ||
| 560 | @qualifier constexpr | ||
| 561 | @qualifier nodiscard | ||
| 562 | |||
| 563 | @groupheader{Header file} | ||
| 564 | @code | ||
| 565 | #include <kumi/product_types/record.hpp> | ||
| 566 | @endcode | ||
| 567 | |||
| 568 | @groupheader{Call Signature} | ||
| 569 | |||
| 570 | @code | ||
| 571 | template<typename... Ts> | ||
| 572 | constexpr auto make_record(Ts&&... ts); | ||
| 573 | @endcode | ||
| 574 | |||
| 575 | @subgroupheader{Parameters} | ||
| 576 | |||
| 577 | - `ts`: Zero or more arguments to construct the record from. | ||
| 578 | |||
| 579 | @subgroupheader{Return value} | ||
| 580 | |||
| 581 | - A kumi::record constructed from the arguments or their inner references when an argument | ||
| 582 | is an instance of `std::reference_wrapper`. | ||
| 583 | |||
| 584 | @groupheader{Example} | ||
| 585 | |||
| 586 | @godbolt{doc/record/api/make_record.cpp} | ||
| 587 | |||
| 588 | **/ | ||
| 589 | //==================================================================================================================== | ||
| 590 | KUMI_VARIABLE_ABI constexpr make_record_t make_record{}; | ||
| 591 | |||
| 592 | namespace _ | ||
| 593 | { | ||
| 594 | template<kumi::concepts::record_type T, std::size_t... I> | ||
| 595 | 18 | KUMI_HIDDEN_ABI constexpr auto to_ref_(kumi::_::adl_tag_t, T&& t, std::index_sequence<I...>) -> kumi::record< | |
| 596 | kumi::field<decltype(kumi::identifier_of<kumi::element_t<I, T>>()), kumi::stored_member_t<I, T>&&>...> | ||
| 597 | { | ||
| 598 | 132 | return {kumi::field_value_of(get<I>(KUMI_FWD(t)))...}; | |
| 599 | } | ||
| 600 | } | ||
| 601 | |||
| 602 | //==================================================================================================================== | ||
| 603 | //! @} | ||
| 604 | //==================================================================================================================== | ||
| 605 | |||
| 606 | //==================================================================================================================== | ||
| 607 | /** | ||
| 608 | @name Record conversion | ||
| 609 | @{ | ||
| 610 | **/ | ||
| 611 | //==================================================================================================================== | ||
| 612 | |||
| 613 | template<kumi::concepts::record_type Type> struct from_record_t | ||
| 614 | { | ||
| 615 | private: | ||
| 616 | template<typename... Ts, std::size_t... I> | ||
| 617 | 3 | KUMI_HIDDEN_ABI constexpr Type impl(record<Ts...> const& r, std::index_sequence<I...>) const | |
| 618 | { | ||
| 619 | 5 | return Type{get<kumi::identifier_of<kumi::element_t<I, Type>>()>(r)...}; | |
| 620 | 3 | } | |
| 621 | |||
| 622 | public: | ||
| 623 | template<typename... Ts> | ||
| 624 | [[nodiscard]] KUMI_ABI constexpr Type operator()(record<Ts...> const& r) const | ||
| 625 | requires( | ||
| 626 | kumi::concepts::equivalent<typename kumi::_::as_tuple<Type, std::make_index_sequence<kumi::size_v<Type>>>::type, | ||
| 627 | kumi::tuple<Ts...>>) | ||
| 628 | { | ||
| 629 |
1/1✓ Branch 1 taken 1 times.
|
3 | return impl(r, std::make_index_sequence<sizeof...(Ts)>{}); |
| 630 | } | ||
| 631 | }; | ||
| 632 | |||
| 633 | //==================================================================================================================== | ||
| 634 | /** | ||
| 635 | @ingroup kumi_record_related | ||
| 636 | |||
| 637 | @var from_record | ||
| 638 | @brief Converts a kumi::record to an instance of an arbitrary type that models kumi::record_type | ||
| 639 | |||
| 640 | |||
| 641 | Constructs an instance of `Type` by passing elements of `r` to the appropriate constructor. | ||
| 642 | |||
| 643 | @qualifier inline | ||
| 644 | @qualifier constexpr | ||
| 645 | @qualifier nodiscard | ||
| 646 | |||
| 647 | @groupheader{Header file} | ||
| 648 | @code | ||
| 649 | #include <kumi/product_types/record.hpp> | ||
| 650 | @endcode | ||
| 651 | |||
| 652 | @groupheader{Call Signature} | ||
| 653 | |||
| 654 | @code | ||
| 655 | template<typename Type, record_type R> | ||
| 656 | constexpr auto from_record(R&& r); | ||
| 657 | @endcode | ||
| 658 | |||
| 659 | @subgroupheader{Parameters} | ||
| 660 | |||
| 661 | - `Type` : Type to generate | ||
| 662 | - `r`: kumi::record to convert. | ||
| 663 | |||
| 664 | @subgroupheader{Return value} | ||
| 665 | |||
| 666 | - An instance of `Type` constructed from each element of `r` in order. | ||
| 667 | |||
| 668 | @groupheader{Example} | ||
| 669 | |||
| 670 | @godbolt{doc/record/api/from_record.cpp} | ||
| 671 | |||
| 672 | **/ | ||
| 673 | //==================================================================================================================== | ||
| 674 | template<kumi::concepts::record_type Type> KUMI_VARIABLE_ABI constexpr from_record_t<Type> from_record{}; | ||
| 675 | |||
| 676 | struct to_record_t | ||
| 677 | { | ||
| 678 | private: | ||
| 679 | 5 | template<typename R, std::size_t... I> KUMI_HIDDEN_ABI constexpr auto impl(R&& r, std::index_sequence<I...>) const | |
| 680 | { | ||
| 681 | if constexpr (sizeof...(I) == 0) return kumi::record{}; | ||
| 682 | else | ||
| 683 | return kumi::record{kumi::capture_field<kumi::identifier_of<kumi::element_t<I, R>>()>( | ||
| 684 | 16 | get<kumi::identifier_of<kumi::element_t<I, R>>()>(KUMI_FWD(r)))...}; | |
| 685 | } | ||
| 686 | |||
| 687 | public: | ||
| 688 | template<kumi::concepts::record_type Type> [[nodiscard]] KUMI_ABI constexpr auto operator()(Type&& r) const | ||
| 689 | { | ||
| 690 | 3 | return impl(KUMI_FWD(r), std::make_index_sequence<kumi::size_v<Type>>{}); | |
| 691 | } | ||
| 692 | }; | ||
| 693 | |||
| 694 | //==================================================================================================================== | ||
| 695 | /** | ||
| 696 | @ingroup kumi_record_related | ||
| 697 | |||
| 698 | @var to_record | ||
| 699 | @brief Converts a kumi::concepts::record_type to an instance of kumi::record | ||
| 700 | |||
| 701 | Constructs an instance of kumi::record from the elements of the kumi::concepts::record_type parameters | ||
| 702 | |||
| 703 | @qualifier inline | ||
| 704 | @qualifier constexpr | ||
| 705 | @qualifier nodiscard | ||
| 706 | |||
| 707 | @groupheader{Header file} | ||
| 708 | @code | ||
| 709 | #include <kumi/product_types/record.hpp> | ||
| 710 | @endcode | ||
| 711 | |||
| 712 | @groupheader{Call Signature} | ||
| 713 | |||
| 714 | @code | ||
| 715 | template<record_type R> | ||
| 716 | constexpr auto to_record(R&& r); | ||
| 717 | @endcode | ||
| 718 | |||
| 719 | @subgroupheader{Parameters} | ||
| 720 | |||
| 721 | - `r`: kumi::concepts::record_type to convert | ||
| 722 | |||
| 723 | @subgroupheader{Return value} | ||
| 724 | |||
| 725 | - An instance of kumi::record constructed from each element of `r` in order. | ||
| 726 | |||
| 727 | @groupheader{Example} | ||
| 728 | |||
| 729 | @godbolt{doc/record/api/to_record.cpp} | ||
| 730 | |||
| 731 | **/ | ||
| 732 | //==================================================================================================================== | ||
| 733 | KUMI_VARIABLE_ABI constexpr to_record_t to_record{}; | ||
| 734 | |||
| 735 | //==================================================================================================================== | ||
| 736 | //! @} | ||
| 737 | //==================================================================================================================== | ||
| 738 | |||
| 739 | //==================================================================================================================== | ||
| 740 | /** | ||
| 741 | @name Record accessors | ||
| 742 | @{ | ||
| 743 | **/ | ||
| 744 | //==================================================================================================================== | ||
| 745 | |||
| 746 | //==================================================================================================================== | ||
| 747 | /** | ||
| 748 | @related record | ||
| 749 | @brief Extracts the Ith field from a kumi::record | ||
| 750 | |||
| 751 | @note Does not participate in overload resolution if `I` is not in [0, sizeof...(Ts)). | ||
| 752 | @tparam I Compile-time index of the field to access | ||
| 753 | @param r Record to index | ||
| 754 | @return A reference to the selected field of r. | ||
| 755 | |||
| 756 | @qualifier nodiscard | ||
| 757 | @qualifier inline | ||
| 758 | @qualifier constexpr | ||
| 759 | @qualifier noexcept | ||
| 760 | |||
| 761 | ## Example: | ||
| 762 | @include doc/record/api/get.cpp | ||
| 763 | **/ | ||
| 764 | //==================================================================================================================== | ||
| 765 | template<std::size_t I, typename... Ts> | ||
| 766 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>& r) noexcept | ||
| 767 | requires(I < sizeof...(Ts)) | ||
| 768 | { | ||
| 769 | 1450 | return r[kumi::index<I>]; | |
| 770 | } | ||
| 771 | |||
| 772 | /// @related record | ||
| 773 | /// @overload | ||
| 774 | template<std::size_t I, typename... Ts> | ||
| 775 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>&& r) noexcept | ||
| 776 | requires(I < sizeof...(Ts)) | ||
| 777 | { | ||
| 778 | 681 | return static_cast<record<Ts...>&&>(r)[kumi::index<I>]; | |
| 779 | } | ||
| 780 | |||
| 781 | /// @related record | ||
| 782 | /// @overload | ||
| 783 | template<std::size_t I, typename... Ts> | ||
| 784 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const& r) noexcept | ||
| 785 | requires(I < sizeof...(Ts)) | ||
| 786 | { | ||
| 787 | 889 | return r[kumi::index<I>]; | |
| 788 | } | ||
| 789 | |||
| 790 | /// @related record | ||
| 791 | /// @overload | ||
| 792 | template<std::size_t I, typename... Ts> | ||
| 793 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const&& r) noexcept | ||
| 794 | requires(I < sizeof...(Ts)) | ||
| 795 | { | ||
| 796 | 13 | return static_cast<record<Ts...> const&&>(r)[kumi::index<I>]; | |
| 797 | } | ||
| 798 | |||
| 799 | //==================================================================================================================== | ||
| 800 | /** | ||
| 801 | @related record | ||
| 802 | @brief Extracts the element of the field labeled L from a kumi::record if it exists | ||
| 803 | |||
| 804 | @note Does not participate in overload resolution if the names are not unique | ||
| 805 | @tparam L Non type template parameter label of the field to access | ||
| 806 | @param r Record to index | ||
| 807 | @return A reference to the element of the selected field of r. | ||
| 808 | |||
| 809 | @qualifier nodiscard | ||
| 810 | @qualifier inline | ||
| 811 | @qualifier constexpr | ||
| 812 | @qualifier noexcept | ||
| 813 | |||
| 814 | ## Example: | ||
| 815 | @include doc/record/api/labeled_get.cpp | ||
| 816 | **/ | ||
| 817 | //==================================================================================================================== | ||
| 818 | template<kumi::str L, typename... Ts> | ||
| 819 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>& r) noexcept | ||
| 820 | requires(kumi::_::contains_label<L, Ts...>()) | ||
| 821 | { | ||
| 822 | 30 | return r[kumi::label<L>]; | |
| 823 | } | ||
| 824 | |||
| 825 | /// @related record | ||
| 826 | /// @overload | ||
| 827 | template<kumi::str L, typename... Ts> | ||
| 828 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>&& r) noexcept | ||
| 829 | requires(kumi::_::contains_label<L, Ts...>()) | ||
| 830 | { | ||
| 831 | return static_cast<record<Ts...>&&>(r)[kumi::label<L>]; | ||
| 832 | } | ||
| 833 | |||
| 834 | /// @related record | ||
| 835 | /// @overload | ||
| 836 | template<kumi::str L, typename... Ts> | ||
| 837 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const& r) noexcept | ||
| 838 | requires(kumi::_::contains_label<L, Ts...>()) | ||
| 839 | { | ||
| 840 | 3 | return r[kumi::label<L>]; | |
| 841 | } | ||
| 842 | |||
| 843 | /// @related record | ||
| 844 | /// @overload | ||
| 845 | template<kumi::str L, typename... Ts> | ||
| 846 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const&& r) noexcept | ||
| 847 | requires(kumi::_::contains_label<L, Ts...>()) | ||
| 848 | { | ||
| 849 | return static_cast<record<Ts...> const&&>(r)[kumi::label<L>]; | ||
| 850 | } | ||
| 851 | |||
| 852 | //==================================================================================================================== | ||
| 853 | /** | ||
| 854 | @related record | ||
| 855 | @brief Extracts the field identified by Id from a kumi::record if it exists | ||
| 856 | |||
| 857 | @note Does not participate in overload resolution if the names are not unique | ||
| 858 | @tparam Id Non type template parameter identifier of the element to access | ||
| 859 | @param r Record to index | ||
| 860 | @return A reference to the selected element of r. | ||
| 861 | |||
| 862 | @qualifier nodiscard | ||
| 863 | @qualifier inline | ||
| 864 | @qualifier constexpr | ||
| 865 | @qualifier noexcept | ||
| 866 | |||
| 867 | ## Example: | ||
| 868 | @include doc/record/api/named_get.cpp | ||
| 869 | **/ | ||
| 870 | //==================================================================================================================== | ||
| 871 | template<kumi::concepts::identifier auto Id, typename... Ts> | ||
| 872 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>& r) noexcept | ||
| 873 | requires(kumi::concepts::contains_identifier<decltype(Id), Ts...>) | ||
| 874 | { | ||
| 875 | 163 | return r[Id]; | |
| 876 | } | ||
| 877 | |||
| 878 | /// @related record | ||
| 879 | /// @overload | ||
| 880 | template<kumi::concepts::identifier auto Id, typename... Ts> | ||
| 881 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>&& r) noexcept | ||
| 882 | requires(kumi::concepts::contains_identifier<decltype(Id), Ts...>) | ||
| 883 | { | ||
| 884 | 19 | return static_cast<record<Ts...>&&>(r)[Id]; | |
| 885 | } | ||
| 886 | |||
| 887 | /// @related record | ||
| 888 | /// @overload | ||
| 889 | template<kumi::concepts::identifier auto Id, typename... Ts> | ||
| 890 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const& r) noexcept | ||
| 891 | requires(kumi::concepts::contains_identifier<decltype(Id), Ts...>) | ||
| 892 | { | ||
| 893 | 1230 | return r[Id]; | |
| 894 | } | ||
| 895 | |||
| 896 | /// @related record | ||
| 897 | /// @overload | ||
| 898 | template<kumi::concepts::identifier auto Id, typename... Ts> | ||
| 899 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const&& r) noexcept | ||
| 900 | requires(kumi::concepts::contains_identifier<decltype(Id), Ts...>) | ||
| 901 | { | ||
| 902 | return static_cast<record<Ts...> const&&>(r)[Id]; | ||
| 903 | } | ||
| 904 | |||
| 905 | //==================================================================================================================== | ||
| 906 | /** | ||
| 907 | @related record | ||
| 908 | @brief Extracts the field whose underlying type is T from a kumi::record if it exists | ||
| 909 | |||
| 910 | @note Does not participate in overload resolution if the types are not unique | ||
| 911 | @tparam T Type of the element to access | ||
| 912 | @param r Record to index | ||
| 913 | @return A reference to the selected element of r. | ||
| 914 | |||
| 915 | @qualifier nodiscard | ||
| 916 | @qualifier inline | ||
| 917 | @qualifier constexpr | ||
| 918 | @qualifier noexcept | ||
| 919 | |||
| 920 | ## Example: | ||
| 921 | @include doc/record/api/typed_get.cpp | ||
| 922 | **/ | ||
| 923 | //==================================================================================================================== | ||
| 924 | template<typename T, typename... Ts> | ||
| 925 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>& r) noexcept | ||
| 926 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 927 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 928 | { | ||
| 929 | 9 | return r[kumi::as<T>{}]; | |
| 930 | } | ||
| 931 | |||
| 932 | /// @related record | ||
| 933 | /// @overload | ||
| 934 | template<typename T, typename... Ts> | ||
| 935 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...>&& r) noexcept | ||
| 936 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 937 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 938 | { | ||
| 939 | return static_cast<record<Ts...>&&>(r)[kumi::as<T>{}]; | ||
| 940 | } | ||
| 941 | |||
| 942 | /// @related record | ||
| 943 | /// @overload | ||
| 944 | template<typename T, typename... Ts> | ||
| 945 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const& r) noexcept | ||
| 946 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 947 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 948 | { | ||
| 949 | 6 | return r[kumi::as<T>{}]; | |
| 950 | } | ||
| 951 | |||
| 952 | /// @related record | ||
| 953 | /// @overload | ||
| 954 | template<typename T, typename... Ts> | ||
| 955 | [[nodiscard]] KUMI_ABI constexpr decltype(auto) get(record<Ts...> const&& r) noexcept | ||
| 956 | requires(kumi::concepts::uniquely_typed<kumi::_::type_of_t<Ts>...> && | ||
| 957 | kumi::concepts::contains_type<T, kumi::_::type_of_t<Ts>...>) | ||
| 958 | { | ||
| 959 | return static_cast<record<Ts...> const&&>(r)[kumi::as<T>{}]; | ||
| 960 | } | ||
| 961 | |||
| 962 | //==================================================================================================================== | ||
| 963 | //! @} | ||
| 964 | //==================================================================================================================== | ||
| 965 | #ifndef KUMI_DOXYGEN_INVOKED | ||
| 966 | /// Improves diagnostic for out of bounds index | ||
| 967 | template<std::size_t I, typename R> | ||
| 968 | requires(kumi::is_kumi_record_v<std::remove_cvref_t<R>> && ((I >= kumi::size_v<R>) || (I < 0))) | ||
| 969 | constexpr auto get(R&& r) = delete; | ||
| 970 | |||
| 971 | /// Improves diagnostic for non present label | ||
| 972 | template<kumi::str S, typename R> | ||
| 973 | requires(kumi::is_kumi_record_v<std::remove_cvref_t<R>> && !kumi::_::contains_identifier<S, R>()) | ||
| 974 | constexpr auto get(R&& r) = delete; | ||
| 975 | |||
| 976 | /// Improves diagnostic for non present identifier | ||
| 977 | template<kumi::concepts::identifier auto S, typename R> | ||
| 978 | requires(kumi::is_kumi_record_v<std::remove_cvref_t<R>> && !kumi::concepts::contains_identifier<decltype(S), R>) | ||
| 979 | constexpr auto get(R&& r) = delete; | ||
| 980 | |||
| 981 | /// Improves diagnostic for non present type | ||
| 982 | template<typename U, typename R> | ||
| 983 | requires(kumi::is_kumi_record_v<std::remove_cvref_t<R>> && !kumi::concepts::contains_type<U, R>) | ||
| 984 | constexpr auto get(R&& r) = delete; | ||
| 985 | #endif | ||
| 986 | |||
| 987 | // Builder protocol | ||
| 988 | template<kumi::concepts::record_type R> struct builder<R> | ||
| 989 | { | ||
| 990 | using type = R; | ||
| 991 | |||
| 992 | template<typename... Us> using to = kumi::record<Us...>; | ||
| 993 | |||
| 994 | template<typename... Args> [[nodiscard]] KUMI_ABI static constexpr auto make(Args&&... args) | ||
| 995 | { | ||
| 996 | 178 | return kumi::make_record(KUMI_FWD(args)...); | |
| 997 | } | ||
| 998 | |||
| 999 | template<typename... Args> [[nodiscard]] KUMI_ABI static constexpr auto build(Args&&... args) | ||
| 1000 | { | ||
| 1001 | return kumi::record{KUMI_FWD(args)...}; | ||
| 1002 | } | ||
| 1003 | }; | ||
| 1004 | |||
| 1005 | // As we are lacking a proper mechanism to find the least restrictive subtype, we fallback to a specializable trait | ||
| 1006 | template<kumi::concepts::record_type... Ts> struct common_product_type<Ts...> | ||
| 1007 | { | ||
| 1008 | using type = kumi::record<>; | ||
| 1009 | }; | ||
| 1010 | } | ||
| 1011 |