Skip to content

Commit ef16643

Browse files
authored
Handling of identifiers has been fixed (#179)
1 parent 37b58c5 commit ef16643

File tree

17 files changed

+197
-105
lines changed

17 files changed

+197
-105
lines changed

include/kumi/algorithm/contains.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace kumi
1212
namespace _
1313
{
1414
template<typename T, typename... Ts>
15-
constexpr bool contains = ((concepts::field<T> && std::invocable<T, Ts>) || ...);
15+
constexpr bool contains = ((concepts::field<T> && std::invocable<T, tag_of_t<Ts>>) || ...);
1616
}
1717

1818
//==================================================================================================================
@@ -37,8 +37,7 @@ namespace kumi
3737
}(std::make_index_sequence<size_v<T>>{});
3838
else
3939
return []<std::size_t... I>(std::index_sequence<I...>) {
40-
if constexpr (((concepts::field<element_t<I, T>> && std::invocable<element_t<I, T>, std::remove_cvref_t<K>>) ||
41-
...))
40+
if constexpr (((concepts::field<element_t<I, T>> && std::invocable<element_t<I, T>, _::tag_of_t<K>>) || ...))
4241
return true;
4342
else return false;
4443
}(std::make_index_sequence<size_v<T>>{});

include/kumi/algorithm/flatten.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ namespace kumi
2121
return [&]<std::size_t... I>(std::index_sequence<I...>) {
2222
auto v_or_r = [&]<typename V>(V&& v) {
2323
using FV = kumi::result::field_value_of_t<V>;
24-
constexpr auto curr_name = name_of(as<V>{}).to_str();
24+
constexpr auto curr_name = _::make_str(name_of<V>());
2525

2626
if constexpr (concepts::record_type<FV>)
2727
{
2828
return [&]<std::size_t... J>(std::index_sequence<J...>) {
2929
return record{
30-
(capture_field<name<concatenate_str<curr_name, name_of(as<element_t<J, FV>>{}).to_str()>()>{}>(
30+
(capture_field<name<concatenate_str<curr_name, _::make_str(name_of<element_t<J, FV>>())>()>{}>(
3131
field_value_of(get<J>(field_value_of(KUMI_FWD(v))))))...};
3232
}(std::make_index_sequence<size_v<FV>>{});
3333
}
@@ -46,8 +46,8 @@ namespace kumi
4646
return [&]<std::size_t... I>(std::index_sequence<I...>) {
4747
auto v_or_r = [&]<typename V>(V&& v) {
4848
constexpr auto curr_name = [&] {
49-
if constexpr (std::is_same_v<Prefix_type, unit>) return name<name_of(as<V>{}).to_str()>{};
50-
else return name<concatenate_str<Prefix.to_str(), name_of(as<V>{}).to_str()>()>{};
49+
if constexpr (std::is_same_v<Prefix_type, unit>) return name<_::make_str(name_of<V>())>{};
50+
else return name<concatenate_str<_::make_str(Prefix), _::make_str(name_of<V>())>()>{};
5151
}();
5252

5353
if constexpr (concepts::record_type<kumi::result::field_value_of_t<V>>)
@@ -67,8 +67,8 @@ namespace kumi
6767
using Prefix_type = std::remove_cvref_t<decltype(Prefix)>;
6868
auto v_or_r = [&]<typename V>(V&& v) {
6969
constexpr auto curr_name = [&] {
70-
if constexpr (std::is_same_v<Prefix_type, unit>) return name<name_of(as<V>{}).to_str()>{};
71-
else return name<concatenate_str<Prefix.to_str(), name_of(as<V>{}).to_str()>()>{};
70+
if constexpr (std::is_same_v<Prefix_type, unit>) return name<_::make_str(name_of<V>())>{};
71+
else return name<concatenate_str<_::make_str(Prefix), _::make_str(name_of<V>())>()>{};
7272
}();
7373

7474
if constexpr (concepts::record_type<kumi::result::field_value_of_t<V>>)

include/kumi/algorithm/for_each.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ namespace kumi
115115
constexpr auto fields = members_of(as<Tuple>{});
116116
auto const invoker = [&]<std::size_t I>(std::integral_constant<std::size_t, I>) {
117117
constexpr auto field = get<I>(fields);
118-
f(field.to_str(), get<field>(KUMI_FWD(t)), get<field>(KUMI_FWD(ts))...);
118+
f(_::make_str(field), get<field>(KUMI_FWD(t)), get<field>(KUMI_FWD(ts))...);
119119
};
120120

121121
[=]<std::size_t... I>(std::index_sequence<I...>) {

include/kumi/algorithm/inner_product.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ namespace kumi
9090
else if constexpr (concepts::record_type<S1>)
9191
{
9292
return [&]<std::size_t... I>(std::index_sequence<I...>) {
93-
return (_::foldable{sum, invoke(prod, get<name_of(as<element_t<I, S1>>{})>(KUMI_FWD(s1)),
94-
get<name_of(as<element_t<I, S1>>{})>(KUMI_FWD(s2)))} >>
93+
return (_::foldable{sum, invoke(prod, get<name_of<element_t<I, S1>>()>(KUMI_FWD(s1)),
94+
get<name_of<element_t<I, S1>>()>(KUMI_FWD(s2)))} >>
9595
... >> _::foldable{sum, init})
9696
.value;
9797
}(std::make_index_sequence<size<S1>::value>());
@@ -115,9 +115,8 @@ namespace kumi
115115
else if constexpr (concepts::record_type<S1>)
116116
{
117117
return [&]<std::size_t... I>(std::index_sequence<I...>) {
118-
return (
119-
init + ... +
120-
(get<name_of(as<element_t<I, S1>>{})>(KUMI_FWD(s1)) * get<name_of(as<element_t<I, S1>>{})>(KUMI_FWD(s2))));
118+
return (init + ... +
119+
(get<name_of<element_t<I, S1>>()>(KUMI_FWD(s1)) * get<name_of<element_t<I, S1>>()>(KUMI_FWD(s2))));
121120
}(std::make_index_sequence<size<S1>::value>());
122121
}
123122
else

include/kumi/algorithm/map.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace kumi
5151
auto const call = [&]<std::size_t N, typename... Ts>(index_t<N>, Ts&&... args) {
5252
if constexpr (concepts::record_type<Tuple>)
5353
{
54-
constexpr auto field = name_of(as<element_t<N, Tuple>>{});
54+
constexpr auto field = name_of<element_t<N, Tuple>>();
5555
return capture_field<field>(invoke(f, get<field>(args)...));
5656
}
5757
else return invoke(f, get<N>(KUMI_FWD(args))...);
@@ -173,8 +173,8 @@ namespace kumi
173173
else
174174
{
175175
auto const call = [&]<std::size_t N, typename... Ts>(index_t<N>, Ts&&... args) {
176-
constexpr auto field = name_of(as<element_t<N, Tuple>>{});
177-
return capture_field<field>(invoke(f, field.to_str(), (get<field>(args))...));
176+
constexpr auto field = name_of<element_t<N, Tuple>>();
177+
return capture_field<field>(invoke(f, _::make_str(field), (get<field>(args))...));
178178
};
179179

180180
return [&]<std::size_t... I>(std::index_sequence<I...>) {

include/kumi/algorithm/meta.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace kumi
2626
if constexpr (concepts::sized_product_type<T, 0>) return tuple{};
2727
else
2828
return [&]<std::size_t... I>(std::index_sequence<I...>) {
29-
return tuple{name_of(as<element_t<I, T>>{})...};
29+
return tuple{name_of<element_t<I, T>>()...};
3030
}(std::make_index_sequence<size_v<T>>{});
3131
}
3232

include/kumi/detail.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ namespace kumi
2828
#include <kumi/detail/abi.hpp>
2929
#include <kumi/detail/dependencies.hpp>
3030
#include <kumi/detail/preprocessor.hpp>
31+
#include <kumi/detail/stdfix.hpp>
3132
#include <kumi/detail/str.hpp>
33+
#include <kumi/detail/concepts.hpp>
3234
#include <kumi/detail/typename.hpp>
3335
#include <kumi/detail/streamable.hpp>
34-
#include <kumi/detail/stdfix.hpp>
35-
#include <kumi/detail/concepts.hpp>
3636
#include <kumi/detail/meta_helpers.hpp>
37+
#include <kumi/detail/field.hpp>
3738
#include <kumi/detail/binder.hpp>
3839
#include <kumi/detail/optimized.hpp>

include/kumi/detail/concepts.hpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace kumi::_
1515

1616
template<auto ID> struct value
1717
{
18+
using type = decltype(ID);
1819
};
1920

2021
using invalid = std::integral_constant<std::size_t, static_cast<std::size_t>(-1)>;
@@ -33,11 +34,18 @@ namespace kumi::_
3334
template<typename T, typename... Args>
3435
concept implicit_constructible = requires(Args... args) { T{args...}; };
3536

37+
// To be displayed an identifier need to be constructible via T{}, and either expose a constexpr to_str() or
38+
// nothing, in which case the typer will be used (see typename.hpp)
3639
template<typename T>
37-
concept identifier = requires(T const& t) {
38-
typename std::remove_cvref_t<T>::tag_type;
39-
{ std::remove_cvref_t<T>::to_str() };
40-
};
40+
concept valid_display_name =
41+
implicit_constructible<T> &&
42+
(!requires { to_str(T{}); } || std::same_as<typename value<to_str(T{})>::type, kumi::str>);
43+
44+
//==============================================================================================
45+
// Helper concepts for custom identifier/field use (these are fundamental types in kumi)
46+
//==============================================================================================
47+
template<typename T>
48+
concept identifier = requires(T const& t) { typename std::remove_cvref_t<T>::tag_type; };
4149

4250
template<typename O>
4351
concept field = requires(O const& o) {
@@ -47,6 +55,11 @@ namespace kumi::_
4755
{ std::remove_cvref_t<O>::name() };
4856
};
4957

58+
template<identifier T> struct tag_of
59+
{
60+
using type = typename std::remove_cvref_t<T>::tag_type;
61+
};
62+
5063
template<field T> struct key_of
5164
{
5265
using type = typename std::remove_cvref_t<T>::identifier_type;
@@ -57,6 +70,7 @@ namespace kumi::_
5770
using type = typename std::remove_cvref_t<T>::type;
5871
};
5972

73+
template<identifier T> using tag_of_t = typename tag_of<std::remove_cvref_t<T>>::type;
6074
template<field T> using key_of_t = typename key_of<std::remove_cvref_t<T>>::type;
6175
template<field T> using type_of_t = typename type_of<std::remove_cvref_t<T>>::type;
6276

@@ -226,8 +240,8 @@ namespace kumi::_
226240
static consteval invalid get_index();
227241
};
228242

229-
template<std::size_t I, typename Ref, field Field>
230-
requires(std::is_same_v<Ref, key_of_t<Field>>)
243+
template<std::size_t I, identifier Ref, field Field>
244+
requires(std::is_same_v<tag_of_t<Ref>, key_of_t<Field>>)
231245
struct check_field<I, Ref, Field>
232246
{
233247
using constant = std::integral_constant<std::size_t, I>;
Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace kumi
1919
//! @tparam Id a compile time string that is used to retrieve the field.
2020
//! @tparam T the type of the value that is wrapped.
2121
//================================================================================================
22-
template<concepts::identifier Id, typename T> struct field
22+
template<typename Id, typename T> struct field
2323
{
2424
using type = T;
2525
using identifier_type = Id;
@@ -28,7 +28,7 @@ namespace kumi
2828
T value;
2929

3030
/// Name associated to the field
31-
static constexpr auto name() { return Id::to_str(); }
31+
static constexpr auto name() { return _::make_str(Id{}); }
3232

3333
KUMI_ABI constexpr T& operator()(identifier_type) & noexcept { return value; }
3434

@@ -54,12 +54,12 @@ namespace kumi
5454
template<typename CharT, typename Traits>
5555
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, field const& w) noexcept
5656
{
57-
return os << Id{} << " : " << _::make_streamable(w.value);
57+
return os << _::make_str(std::remove_cvref_t<Id>{}) << " : " << _::make_streamable(w.value);
5858
}
5959
};
6060

6161
// EBO
62-
template<concepts::identifier Id, typename T>
62+
template<typename Id, typename T>
6363
requires(std::is_empty_v<T>)
6464
struct field<Id, T> : T
6565
{
@@ -68,7 +68,7 @@ namespace kumi
6868
using inner_type = std::type_identity<T>;
6969

7070
/// Name associated to the field
71-
static constexpr auto name() { return Id::to_str(); }
71+
static constexpr auto name() { return _::make_str(Id{}); }
7272

7373
KUMI_ABI constexpr T& operator()(identifier_type) & noexcept { return *this; }
7474

@@ -94,10 +94,19 @@ namespace kumi
9494
template<typename CharT, typename Traits>
9595
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, field const& w) noexcept
9696
{
97-
return os << Id{} << " : " << _::make_streamable(w(_::key_of_t<decltype(w)>{}));
97+
return os << _::make_str(std::remove_cvref_t<Id>{}) << " : " << _::make_streamable(w(_::key_of_t<decltype(w)>{}));
9898
}
9999
};
100100

101+
/// Specialisation to clearly indicate an error
102+
template<typename Id, typename T>
103+
requires(!_::valid_display_name<Id>)
104+
struct field<Id, T>
105+
{
106+
field(T&&) = delete;
107+
static_assert(_::valid_display_name<Id>, "User defined to_str(...) function is not constexpr");
108+
};
109+
101110
//================================================================================================
102111
//! @ingroup utility
103112
//! @brief Extracts the name from a kumi::field or returns the parameter.
@@ -106,9 +115,9 @@ namespace kumi
106115
//! @tparam T The name to extract name from.
107116
//! @return The name of the field or kumi::unknown.
108117
//================================================================================================
109-
template<typename T> [[nodiscard]] KUMI_ABI constexpr auto name_of(as<T>) noexcept
118+
template<typename T> [[nodiscard]] KUMI_ABI consteval auto name_of() noexcept
110119
{
111-
if constexpr (concepts::field<T>) return _::key_of_t<T>{};
120+
if constexpr (_::field<T>) return _::key_of_t<T>{};
112121
else return kumi::unknown{};
113122
};
114123

@@ -123,7 +132,7 @@ namespace kumi
123132
//================================================================================================
124133
template<typename T> [[nodiscard]] KUMI_ABI constexpr decltype(auto) field_value_of(T&& t) noexcept
125134
{
126-
if constexpr (concepts::field<T>) return (KUMI_FWD(t)(_::key_of_t<T>{}));
135+
if constexpr (_::field<T>) return (KUMI_FWD(t)(_::key_of_t<T>{}));
127136
else return KUMI_FWD(t);
128137
};
129138

@@ -137,7 +146,7 @@ namespace kumi
137146
//! @return A `field` that correctly keeps the qualified input type.
138147
//! @related kumi::field
139148
//================================================================================================
140-
template<concepts::identifier auto Name, typename T>
149+
template<_::identifier auto Name, typename T>
141150
[[nodiscard]] KUMI_ABI constexpr decltype(auto) capture_field(T&& t) noexcept
142151
{
143152
return field<decltype(Name), T>{KUMI_FWD(t)};
@@ -157,25 +166,25 @@ namespace kumi
157166
//================================================================================================
158167
template<typename U, typename T> [[nodiscard]] KUMI_ABI constexpr decltype(auto) field_cast(T&& t) noexcept
159168
{
160-
if constexpr (concepts::field<U>)
169+
if constexpr (_::field<U>)
161170
return field<_::key_of_t<T>, _::type_of_t<U>>{static_cast<_::type_of_t<U>>(KUMI_FWD(t)(_::key_of_t<T>{}))};
162-
else if constexpr (!concepts::field<T>) return static_cast<_::type_of_t<U>>(KUMI_FWD(t));
171+
else if constexpr (!_::field<T>) return static_cast<_::type_of_t<U>>(KUMI_FWD(t));
163172
else return field<_::key_of_t<T>, U>{static_cast<U>(KUMI_FWD(t)(_::key_of_t<T>{}))};
164173
}
165174

166175
namespace result
167176
{
168177
template<typename T> struct name_of
169178
{
170-
using type = decltype(kumi::name_of(as<T>{}));
179+
using type = decltype(kumi::name_of<T>());
171180
};
172181

173182
template<typename T> struct field_value_of
174183
{
175184
using type = decltype(kumi::field_value_of(std::declval<T>()));
176185
};
177186

178-
template<concepts::identifier auto Name, typename T> struct capture_field
187+
template<_::identifier auto Name, typename T> struct capture_field
179188
{
180189
using type = decltype(kumi::capture_field<Name>(std::declval<T>()));
181190
};
@@ -189,7 +198,7 @@ namespace kumi
189198

190199
template<typename T> using field_value_of_t = typename field_value_of<T>::type;
191200

192-
template<concepts::identifier auto Name, typename T> using capture_field_t = typename capture_field<Name, T>::type;
201+
template<_::identifier auto Name, typename T> using capture_field_t = typename capture_field<Name, T>::type;
193202

194203
template<typename U, typename T> using field_cast_t = typename field_cast<U, T>::type;
195204
}

include/kumi/detail/streamable.hpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ namespace kumi::_
1111
{
1212
//================================================================================================
1313
//! @ingroup utility
14-
//! @brief Provides an extension point `as_streamable` in order to output types with no stream
15-
//! operator defined.
14+
//! @brief Provides an extension point `as_streamable` in order to output values of types with
15+
//! no stream operator defined.
1616
//!
1717
//! @note This function is an implementation detail and only documented to show how to use
1818
//! the `as_streamable` extension point.
@@ -30,4 +30,27 @@ namespace kumi::_
3030
else if constexpr (requires { as_streamable(e); }) return as_streamable(e);
3131
else return kumi::unknown{};
3232
}
33+
34+
//================================================================================================
35+
//! @ingroup utility
36+
//! @brief Provides an extension point `to_str` in order to output types with no textual
37+
//! representation defined.
38+
//!
39+
//! @note This function is an implementation detail and only documented to show how to use
40+
//! the `to_str` extension point. It is used in order to handle identifiers/fields
41+
//! display and manipulations. to_str needs to be constexpr callable, if not some concepts
42+
//! might fail unexpectedly
43+
//!
44+
//! @tparam T Type of the element to output.
45+
//! @param t The value of the element to output.
46+
//! @return A kumi::str representing the input type
47+
//!
48+
//! ## Example:
49+
//! @include doc/infra/to_str.cpp
50+
//================================================================================================
51+
template<valid_display_name T> consteval str make_str(T const& t)
52+
{
53+
if constexpr (requires { to_str(t); }) return to_str(t);
54+
else return typer<std::remove_cvref_t<T>>();
55+
}
3356
}

0 commit comments

Comments
 (0)