simdjson 4.0.7
Ridiculously Fast JSON
Loading...
Searching...
No Matches
concepts.h
1#ifndef SIMDJSON_CONCEPTS_H
2#define SIMDJSON_CONCEPTS_H
3#if SIMDJSON_SUPPORTS_CONCEPTS
4
5#include <concepts>
6#include <type_traits>
7
8namespace simdjson {
9namespace concepts {
10
11namespace details {
12#define SIMDJSON_IMPL_CONCEPT(name, method) \
13 template <typename T> \
14 concept supports_##name = !std::is_const_v<T> && requires { \
15 typename std::remove_cvref_t<T>::value_type; \
16 requires requires(typename std::remove_cvref_t<T>::value_type &&val, \
17 T obj) { \
18 obj.method(std::move(val)); \
19 requires !requires { obj = std::move(val); }; \
20 }; \
21 };
22
23SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
24SIMDJSON_IMPL_CONCEPT(emplace, emplace)
25SIMDJSON_IMPL_CONCEPT(push_back, push_back)
26SIMDJSON_IMPL_CONCEPT(add, add)
27SIMDJSON_IMPL_CONCEPT(push, push)
28SIMDJSON_IMPL_CONCEPT(append, append)
29SIMDJSON_IMPL_CONCEPT(insert, insert)
30SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
31
32#undef SIMDJSON_IMPL_CONCEPT
33} // namespace details
34
35template <typename T>
36concept is_pair = requires { typename T::first_type; typename T::second_type; } &&
37 std::same_as<T, std::pair<typename T::first_type, typename T::second_type>>;
38template <typename T>
39concept string_view_like = std::is_convertible_v<T, std::string_view> &&
40 !std::is_convertible_v<T, const char*>;
41
42template<typename T>
43concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
44 && !std::is_same_v<T, std::string_view>
45 && std::is_default_constructible_v<T>;
46
47template<typename M>
48concept string_view_keyed_map = string_view_like<typename M::key_type>
49 && requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
50 { m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
51};
52
55template <typename T>
56concept appendable_containers =
57 (details::supports_emplace_back<T> || details::supports_emplace<T> ||
58 details::supports_push_back<T> || details::supports_push<T> ||
59 details::supports_add<T> || details::supports_append<T> ||
60 details::supports_insert<T>) && !string_view_keyed_map<T>;
61
63template <appendable_containers T, typename... Args>
64constexpr decltype(auto) emplace_one(T &vec, Args &&...args) {
65 if constexpr (details::supports_emplace_back<T>) {
66 return vec.emplace_back(std::forward<Args>(args)...);
67 } else if constexpr (details::supports_emplace<T>) {
68 return vec.emplace(std::forward<Args>(args)...);
69 } else if constexpr (details::supports_push_back<T>) {
70 return vec.push_back(std::forward<Args>(args)...);
71 } else if constexpr (details::supports_push<T>) {
72 return vec.push(std::forward<Args>(args)...);
73 } else if constexpr (details::supports_add<T>) {
74 return vec.add(std::forward<Args>(args)...);
75 } else if constexpr (details::supports_append<T>) {
76 return vec.append(std::forward<Args>(args)...);
77 } else if constexpr (details::supports_insert<T>) {
78 return vec.insert(std::forward<Args>(args)...);
79 } else if constexpr (details::supports_op_append<T> && sizeof...(Args) == 1) {
80 return vec.operator+=(std::forward<Args>(args)...);
81 } else {
82 static_assert(!sizeof(T *),
83 "We don't know how to add things to this container");
84 }
85}
86
90template <typename T>
91concept returns_reference = appendable_containers<T> && requires {
92 typename std::remove_cvref_t<T>::reference;
93 requires requires(typename std::remove_cvref_t<T>::value_type &&val, T obj) {
94 {
95 emplace_one(obj, std::move(val))
96 } -> std::same_as<typename std::remove_cvref_t<T>::reference>;
97 };
98};
99
100template <typename T>
101concept smart_pointer = requires(std::remove_cvref_t<T> ptr) {
102 // Check if T has a member type named element_type
103 typename std::remove_cvref_t<T>::element_type;
104
105 // Check if T has a get() member function
106 {
107 ptr.get()
108 } -> std::same_as<typename std::remove_cvref_t<T>::element_type *>;
109
110 // Check if T can be dereferenced
111 { *ptr } -> std::same_as<typename std::remove_cvref_t<T>::element_type &>;
112};
113
114template <typename T>
115concept optional_type = requires(std::remove_cvref_t<T> obj) {
116 typename std::remove_cvref_t<T>::value_type;
117 { obj.value() } -> std::same_as<typename std::remove_cvref_t<T>::value_type&>;
118 requires requires(typename std::remove_cvref_t<T>::value_type &&val) {
119 obj.emplace(std::move(val));
120 {
121 obj.value_or(val)
122 } -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
123 };
124 { static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
125 { obj.reset() } noexcept -> std::same_as<void>;
126};
127
128
129
130// Types we serialize as JSON strings (not as containers)
131template <typename T>
132concept string_like =
133 std::is_same_v<std::remove_cvref_t<T>, std::string> ||
134 std::is_same_v<std::remove_cvref_t<T>, std::string_view> ||
135 std::is_same_v<std::remove_cvref_t<T>, const char*> ||
136 std::is_same_v<std::remove_cvref_t<T>, char*>;
137
138// Concept that checks if a type is a container but not a string (because
139// strings handling must be handled differently)
140// Now uses iterator-based approach for broader container support
141template <typename T>
142concept container_but_not_string =
143 std::ranges::input_range<T> && !string_like<T> && !concepts::string_view_keyed_map<T>;
144
145
146} // namespace concepts
147
148
152template <typename Tag, typename... Args>
153concept tag_invocable = requires(Tag tag, Args... args) {
154 tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
155};
156
157template <typename Tag, typename... Args>
158concept nothrow_tag_invocable =
159 tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
160 {
161 tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
162 } noexcept;
163 };
164
165} // namespace simdjson
166#endif // SIMDJSON_SUPPORTS_CONCEPTS
167#endif // SIMDJSON_CONCEPTS_H
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8