1#ifndef SIMDJSON_CONCEPTS_H
2#define SIMDJSON_CONCEPTS_H
3#if SIMDJSON_SUPPORTS_CONCEPTS
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, \
18 obj.method(std::move(val)); \
19 requires !requires { obj = std::move(val); }; \
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+=)
32#undef SIMDJSON_IMPL_CONCEPT
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>>;
39concept string_view_like = std::is_convertible_v<T, std::string_view> &&
40 !std::is_convertible_v<T, const char*>;
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>;
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>>;
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>;
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)...);
82 static_assert(!
sizeof(T *),
83 "We don't know how to add things to this container");
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) {
95 emplace_one(obj, std::move(val))
96 } -> std::same_as<typename std::remove_cvref_t<T>::reference>;
101concept smart_pointer =
requires(std::remove_cvref_t<T> ptr) {
103 typename std::remove_cvref_t<T>::element_type;
108 } -> std::same_as<typename std::remove_cvref_t<T>::element_type *>;
111 { *ptr } -> std::same_as<typename std::remove_cvref_t<T>::element_type &>;
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));
122 } -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
124 {
static_cast<bool>(obj) } -> std::same_as<bool>;
125 { obj.reset() }
noexcept -> std::same_as<void>;
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*>;
142concept container_but_not_string =
143 std::ranges::input_range<T> && !string_like<T> && !concepts::string_view_keyed_map<T>;
152template <
typename Tag,
typename... Args>
153concept tag_invocable =
requires(Tag tag, Args... args) {
154 tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
157template <
typename Tag,
typename... Args>
158concept nothrow_tag_invocable =
159 tag_invocable<Tag, Args...> &&
requires(Tag tag, Args... args) {
161 tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
The top level simdjson namespace, containing everything the library provides.