Skip to content

Commit ba5380a

Browse files
authored
Introduce static_container adaptation
`std::array` and similar types are now considered product types. static `std::span ' is convertible to kumi::tuple.
1 parent 0e1a182 commit ba5380a

File tree

9 files changed

+160
-41
lines changed

9 files changed

+160
-41
lines changed

include/kumi/algorithm/convert.hpp

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,8 @@
77
//==================================================================================================
88
#pragma once
99

10-
#include <span>
11-
1210
namespace kumi
1311
{
14-
namespace _
15-
{
16-
// Workaround as span has no tuple_element/tuple_size defined even if it's static
17-
// as opposed to ranges::subrange for some reason
18-
template<typename T> struct is_static_span : std::false_type
19-
{
20-
};
21-
22-
template<typename T, std::size_t N>
23-
struct is_static_span<std::span<T, N>> : std::bool_constant<(N != std::dynamic_extent)>
24-
{
25-
};
26-
27-
template<typename T>
28-
concept static_span = is_static_span<std::remove_cvref_t<T>>::value;
29-
}
30-
3112
namespace _
3213
{
3314
template<product_type Tuple, typename IndexSequence, template<typename...> class Meta = std::type_identity>
@@ -105,7 +86,7 @@ namespace kumi
10586
//! @param t kumi::product_type to convert
10687
//! @return An instance of kumi::tuple constructed from each elements of `t` in order.
10788
//!
108-
//! @note An overload is provided for static std::span.
89+
//! @note An overload is provided for kumi::static_container.
10990
//!
11091
//! ## Example
11192
//! @include doc/to_tuple.cpp
@@ -115,9 +96,11 @@ namespace kumi
11596
return apply([](auto&&... elems) { return tuple{elems...}; }, KUMI_FWD(t));
11697
}
11798

118-
template<_::static_span S> [[nodiscard]] KUMI_ABI constexpr auto to_tuple(S&& s)
99+
template<static_container S>
100+
[[nodiscard]] KUMI_ABI constexpr auto to_tuple(S&& s)
101+
requires(!product_type<S>)
119102
{
120-
constexpr auto N = std::remove_cvref_t<S>::extent;
103+
constexpr auto N = container_size_v<S>;
121104
if constexpr (N == 0) return tuple{};
122105
else
123106
return [&]<std::size_t... I>(std::index_sequence<I...>) {

include/kumi/detail/concepts.hpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,6 @@
1515

1616
namespace kumi::_
1717
{
18-
//==============================================================================================
19-
// Helper concepts for tuple detection
20-
//==============================================================================================
21-
// Concept specifying a type is non-empty standard tuple-like type.
22-
template<typename T>
23-
concept non_empty_tuple = requires(T const& t) {
24-
typename std::tuple_element<0, std::remove_cvref_t<T>>::type;
25-
typename std::tuple_size<std::remove_cvref_t<T>>::type;
26-
};
27-
28-
// Concept specifying a type is an empty standard tuple-like type.
29-
template<typename T>
30-
concept empty_tuple = (std::tuple_size<std::remove_cvref_t<T>>::value == 0);
31-
3218
//==============================================================================================
3319
// Helper concepts for construction checks
3420
//==============================================================================================

include/kumi/utils/concepts.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ namespace kumi
4242
template<typename T>
4343
concept record_type = product_type<T> && is_record_type<std::remove_cvref_t<T>>::value;
4444

45+
//================================================================================================
46+
//! @ingroup concepts
47+
//! @brief Concept specifying a type follows the Container Type semantic
48+
//!
49+
//! A type `T` models `kumi::static_container` if it is an homogeneous container of fixed size.
50+
//================================================================================================
51+
template<typename T>
52+
concept static_container = is_static_container_v<std::remove_cvref_t<T>>;
53+
4554
//================================================================================================
4655
//! @ingroup concepts
4756
//! @brief Concept specifying a type follows the Product Type semantic and has a known size

include/kumi/utils/monoid.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
SPDX-License-Identifier: BSL-1.0
66
*/
77
//==================================================================================================
8+
#pragma once
9+
810
#include <cstddef>
911

1012
namespace kumi

include/kumi/utils/std.hpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
#include <kumi/utils/concepts.hpp>
1111
#include <kumi/utils/traits.hpp>
12-
#include <array>
1312
#include <type_traits>
1413
#include <utility>
1514

@@ -87,10 +86,6 @@ struct std::basic_common_reference<kumi::tuple<Ts...>, kumi::tuple<Us...>, TQual
8786
//==================================================================================================
8887
// Standard types support (for those that model `tuple-like` & are declared in `utility`)
8988
//==================================================================================================
90-
template<typename T, std::size_t N> struct kumi::is_product_type<std::array<T, N>> : std::true_type
91-
{
92-
};
93-
9489
template<typename... Ts> struct kumi::is_product_type<std::tuple<Ts...>> : std::true_type
9590
{
9691
};

include/kumi/utils/traits.hpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,39 @@
1616

1717
namespace kumi
1818
{
19+
20+
namespace _
21+
{
22+
//==============================================================================================
23+
// Helper concepts for tuple detection
24+
//==============================================================================================
25+
// Concept specifying a type is non-empty standard tuple-like type.
26+
template<typename T>
27+
concept non_empty_tuple = requires(T const& t) {
28+
typename std::tuple_element<0, std::remove_cvref_t<T>>::type;
29+
typename std::tuple_size<std::remove_cvref_t<T>>::type;
30+
};
31+
32+
// Concept specifying a type is an empty standard tuple-like type.
33+
template<typename T>
34+
concept empty_tuple = (std::tuple_size<std::remove_cvref_t<T>>::value == 0);
35+
36+
//==============================================================================================
37+
// Helper concepts for container detection
38+
//==============================================================================================
39+
// Concept specifying a type is standard container-like type.
40+
template<typename T>
41+
concept container_like = requires(T const& t) {
42+
typename T::value_type;
43+
typename T::size_type;
44+
45+
{ t.size() } -> kumi::convertible_to<std::size_t>;
46+
{ t.begin() };
47+
{ t.end() };
48+
{ t.data() };
49+
};
50+
}
51+
1952
//================================================================================================
2053
//! @ingroup traits
2154
//! @brief Opt-in traits for types behaving like a kumi::product_type
@@ -177,6 +210,107 @@ namespace kumi
177210
template<std::size_t I, typename T> using member_t = typename member<I, T>::type;
178211
}
179212

213+
namespace kumi
214+
{
215+
//================================================================================================
216+
//! @ingroup traits
217+
//! @brief Traits detecting types behaving like a kumi::static_container.
218+
//!
219+
//! To be treated like a static_container, a user defined type must expose a type and a
220+
//! statically know size encoded in the type. It shall also provide general container utilities.
221+
//!
222+
//! @note The type shall be templated on the type and the size to be picked up.
223+
//!
224+
//! ## Helper value
225+
//! @code
226+
//! template<typename T> inline constexpr auto is_static_container = is_static_container<T>::value;
227+
//! @endcode
228+
//! ## Example:
229+
//==============================================================================================
230+
template<typename T> struct is_static_container : std::false_type
231+
{
232+
};
233+
234+
template<template<class, std::size_t> typename Container, typename T, std::size_t N>
235+
requires _::container_like<Container<T, N>> && (N != static_cast<std::size_t>(-1))
236+
struct is_static_container<Container<T, N>> : std::true_type
237+
{
238+
using value_type = T;
239+
using size = std::integral_constant<std::size_t, N>;
240+
};
241+
242+
template<typename T> inline constexpr auto is_static_container_v = is_static_container<T>::value;
243+
244+
//================================================================================================
245+
//! @ingroup traits
246+
//! @brief Returns the number of elements of a kumi::static_container
247+
//!
248+
//! @tparam T kumi::static_container to inspect
249+
//!
250+
//! ## Helper value
251+
//! @code
252+
//! template<typename T> inline constexpr auto container_size_v = container_size<T>::value;
253+
//! @endcode
254+
//================================================================================================
255+
template<typename T> struct container_size : is_static_container<T>::size
256+
{
257+
};
258+
259+
template<typename T> struct container_size<T&> : container_size<T>
260+
{
261+
};
262+
263+
template<typename T> struct container_size<T&&> : container_size<T>
264+
{
265+
};
266+
267+
template<typename T> struct container_size<T const&> : container_size<T>
268+
{
269+
};
270+
271+
template<typename T> struct container_size<T const&&> : container_size<T>
272+
{
273+
};
274+
275+
template<typename T> inline constexpr auto container_size_v = container_size<T>::value;
276+
277+
//================================================================================================
278+
//! @ingroup traits
279+
//! @brief Provides access to the type of the elements of a kumi::static_container.
280+
//!
281+
//! @tparam T kumi::static_container to access
282+
//!
283+
//! ## Helper type
284+
//! @code
285+
//! namespace kumi
286+
//! {
287+
//! template<typename T> using container_type_t = typename container_type<T>::type;
288+
//! }
289+
//! @endcode
290+
//================================================================================================
291+
template<typename T> struct container_type : is_static_container<T>::value_type
292+
{
293+
};
294+
295+
template<typename T> struct container_type<T&> : container_type<T>
296+
{
297+
};
298+
299+
template<typename T> struct container_type<T&&> : container_type<T>
300+
{
301+
};
302+
303+
template<typename T> struct container_type<T const&> : container_type<T>
304+
{
305+
};
306+
307+
template<typename T> struct container_type<T const&&> : container_type<T>
308+
{
309+
};
310+
311+
template<typename T> using container_type_t = typename container_type<T>::type;
312+
}
313+
180314
namespace kumi
181315
{
182316
//================================================================================================
@@ -404,4 +538,10 @@ namespace kumi
404538
// Forward declaration
405539
template<typename... Ts> struct tuple;
406540
template<typename... Ts> struct record;
541+
542+
template<typename T>
543+
requires(is_static_container_v<T> && (_::non_empty_tuple<T> || _::empty_tuple<T>))
544+
struct is_product_type<T> : std::true_type
545+
{
546+
};
407547
}

test/unit/adapt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <kumi/kumi.hpp>
1010
#include <tts/tts.hpp>
1111
#include <tuple>
12+
#include <array>
1213
#include "test.hpp"
1314

1415
TTS_CASE("Check adapted types model kumi::product_type concept")

test/unit/builder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <kumi/kumi.hpp>
1010
#include <tts/tts.hpp>
1111
#include "test.hpp"
12+
#include <array>
1213

1314
TTS_CASE("Check tuple_element of the output of result::builder_make_t")
1415
{

test/unit/convert.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <kumi/kumi.hpp>
1010
#include <tts/tts.hpp>
1111
#include "test.hpp"
12+
#include <array>
13+
#include <span>
1214

1315
struct my_product_type
1416
{

0 commit comments

Comments
 (0)