18 template <
typename RESOLVER,
typename PATH_TYPE,
typename POINTER_TYPE,
typename... TAGS>
19 concept resolver_can_resolve_path_from_pointer =
requires (PATH_TYPE path, POINTER_TYPE pointer) {
20 { RESOLVER::template resolve_path_from_reference<POINTER_TYPE, TAGS...>(pointer, path) } -> std::same_as<bool>;
22 template <
typename RESOLVER,
typename PATH_TYPE,
typename POINTER_TYPE,
typename... TAGS>
23 concept resolver_can_validate_path =
requires (PATH_TYPE path) {
24 { RESOLVER::template validate_path<POINTER_TYPE, TAGS...>(path) };
26 template <
typename RESOLVER>
27 concept resolver_has_empty_path =
false;
29 template <
typename RESOLVER,
typename PATH_TYPE,
typename POINTER_TYPE,
typename... TAGS>
30 concept valid_resolver =
requires (PATH_TYPE & path, POINTER_TYPE & pointer) {
31 { RESOLVER::template resolve_reference_from_path<POINTER_TYPE, TAGS...>(path, pointer) } -> std::same_as<bool>;
34 template <
typename BASE_POINTER_TYPE,
typename PATH_TYPE>
35 struct flyweight_resolver
37 using value_type = std::pointer_traits<BASE_POINTER_TYPE>::element_type;
41 template <
typename POINTER_TYPE,
typename... TAGS>
42 static bool empty_path(PATH_TYPE
const& path)
48 template <
typename POINTER_TYPE,
typename... TAGS>
49 static bool resolve_reference_from_path(PATH_TYPE
const& path, POINTER_TYPE& out_ref)
51 out_ref = empty_path<POINTER_TYPE, TAGS...>(path)
52 ? mapping.mutate_in_place([&path](
auto& mapping) { return &mapping[path]; })
57 template <
typename POINTER_TYPE,
typename... TAGS>
58 static bool resolve_path_from_reference(POINTER_TYPE
const& ref, PATH_TYPE& out_path)
60 return mapping.read_only_access([&out_path, ptr = std::to_address(ref)](
auto const& mapping) {
61 for (
auto const& [path, val] : mapping)
73 template <
typename POINTER_TYPE,
typename... TAGS>
74 static void validate_path(PATH_TYPE& path)
90 typename POINTER_TYPE,
91 typename PATH_TYPE = std::string,
92 typename RESOLVER_TYPE = detail::flyweight_resolver<POINTER_TYPE, PATH_TYPE>,
94 struct caching_path_reference
100 using resolver_type = RESOLVER_TYPE;
101 using path_type = PATH_TYPE;
102 using pointer_type = POINTER_TYPE;
110 caching_path_reference() noexcept = default;
111 caching_path_reference(caching_path_reference const&) noexcept = default;
112 caching_path_reference(caching_path_reference&&) noexcept = default;
113 caching_path_reference& operator=(caching_path_reference const& obj) noexcept = default;
114 caching_path_reference& operator=(caching_path_reference&& obj) noexcept = default;
117 template <typename T>
118 requires (std::constructible_from<path_type, T> && !std::same_as<caching_path_reference, std::remove_cvref_t<T>>)
119 caching_path_reference(T&& p) : m_path(std::forward<T>(p)) { validate_path(); }
122 template <
typename T>
123 requires (std::assignable_from<path_type, T> && !std::same_as<caching_path_reference, std::remove_cvref_t<T>>)
124 auto&
operator=(T&& p) {
126 m_path = std::forward<T>(p);
132 template <
typename T>
137 template <
typename T>
138 requires (
can_resolve_path_from_pointer&& std::assignable_from<pointer_type, T> && !std::same_as<caching_path_reference, std::remove_cvref_t<T>>)
139 auto&
operator=(T&& p) {
140 m_pointer = std::forward<T>(p);
145 pointer_type operator->()
const {
return pointer(); }
146 auto& operator*()
const {
return *pointer(); }
148 template <
typename T>
149 bool operator==(T
const& other)
const
151 (std::same_as<std::remove_cvref_t<T>, caching_path_reference>) ||
152 (std::same_as<std::remove_cvref_t<T>, pointer_type>) ||
153 (std::same_as<std::remove_cvref_t<T>, path_type>) ||
154 (std::constructible_from<std::string_view, T const&> && std::equality_comparable_with<path_type const&, std::string_view>)
157 if constexpr (std::is_same_v<std::remove_cvref_t<T>, caching_path_reference>)
158 return path() == other.path();
159 else if constexpr (std::is_same_v<std::remove_cvref_t<T>, pointer_type>)
160 return pointer() == other;
161 else if constexpr (std::is_same_v<std::remove_cvref_t<T>, path_type>)
162 return path() == other;
163 else if constexpr (std::constructible_from<std::string_view, T const&> && std::equality_comparable_with<path_type const&, std::string_view>)
164 return path() == std::string_view{ other };
167 template <
typename T>
168 auto operator<=>(T
const& other)
const
170 (std::same_as<std::remove_cvref_t<T>, caching_path_reference>) ||
171 (std::same_as<std::remove_cvref_t<T>, pointer_type>) ||
172 (std::same_as<std::remove_cvref_t<T>, path_type>) ||
173 (std::constructible_from<std::string_view, T const&> && std::equality_comparable_with<path_type const&, std::string_view>)
176 if constexpr (std::is_same_v<std::remove_cvref_t<T>, caching_path_reference>)
177 return path() <=> other.path();
178 else if constexpr (std::is_same_v<std::remove_cvref_t<T>, pointer_type>)
179 return pointer() <=> other;
180 else if constexpr (std::is_same_v<std::remove_cvref_t<T>, path_type>)
181 return path() <=> other;
182 else if constexpr (std::constructible_from<std::string_view, T const&> && std::equality_comparable_with<path_type const&, std::string_view>)
183 return path() <=> std::string_view{ other };
187 void reset() { m_path = {}; m_pointer = {}; }
189 path_type
const& path() const& {
194 bool path_empty()
const {
196 return path_empty(m_path);
199 path_type path() && {
201 return std::move(m_path);
204 pointer_type
const& pointer() const& {
209 pointer_type pointer() && {
211 return std::move(m_pointer);
214 explicit operator bool() const noexcept {
return pointer() != pointer_type{}; }
215 explicit operator path_type() const noexcept {
return path(); }
219 static bool path_empty(path_type
const& empty)
221 if constexpr (std::is_same_v<path_type, std::string>)
222 return empty.empty();
223 else if constexpr (detail::resolver_has_empty_path<resolver_type>)
224 return resolver_type::template path_empty<TAGS...>(empty);
226 return empty == path_type{};
231 if constexpr (detail::resolver_can_validate_path<resolver_type, PATH_TYPE, POINTER_TYPE, TAGS...>)
232 resolver_type::template validate_path<pointer_type, TAGS...>(m_path);
235 void resolve_pointer()
const
237 if (m_pointer || path_empty(m_path))
return;
238 resolver_type::template resolve_reference_from_path<pointer_type, TAGS...>(m_path, m_pointer);
241 void resolve_path()
const
245 if (!path_empty(m_path) || !m_pointer)
return;
246 resolver_type::template resolve_path_from_reference<pointer_type, TAGS...>(m_pointer, m_path);
250 mutable path_type m_path{};
251 mutable pointer_type m_pointer{};
257 template <
typename RESOLVER_TYPE,
typename PATH_TYPE,
typename POINTER_TYPE>
258 struct path_reference<RESOLVER_TYPE, PATH_TYPE, POINTER_TYPE, NoCache>
260 using resolver_type = RESOLVER_TYPE;
261 using path_type = PATH_TYPE;
262 using pointer_type = POINTER_TYPE;
267 static constexpr bool can_resolve_path_from_pointer = detail::resolver_can_resolve_path_from_pointer<resolver_type, path_type, pointer_type, NoCache>;
269 path_reference() noexcept = default;
270 path_reference(path_reference const&) noexcept = default;
271 path_reference(path_reference&&) noexcept = default;
272 path_reference& operator=(path_reference const& obj) noexcept = default;
273 path_reference& operator=(path_reference&& obj) noexcept = default;
275 template <typename T>
276 requires (std::constructible_from<path_type, T> && !std::same_as<path_reference, std::remove_cvref_t<T>>)
277 path_reference(T&& p) : m_path(std::forward<T>(p)) { validate_path(); }
279 template <
typename T>
280 requires (std::assignable_from<path_type, T> && !std::same_as<path_reference, std::remove_cvref_t<T>>)
281 auto&
operator=(T&& p) {
282 m_path = std::forward<T>(p);
287 template <
typename T>
288 requires can_resolve_path_from_pointer&& std::constructible_from<pointer_type, T>
289 path_reference(T&& p) { resolve_path(p); }
291 template <
typename T>
292 requires can_resolve_path_from_pointer&& std::assignable_from<pointer_type, T>
293 auto& operator=(T&& p) {
298 pointer_type operator->()
const {
return pointer(); }
299 auto& operator*()
const {
return *pointer(); }
301 auto operator<=>(path_reference
const& other)
const {
return path() <=> other.path(); }
302 auto operator==(path_reference
const& other)
const {
return path() == other.path(); }
304 auto operator<=>(pointer_type
const& ptr)
const {
return pointer() <=> ptr; }
305 auto operator==(pointer_type
const& ptr)
const {
return pointer() == ptr; }
307 auto operator<=>(std::string_view path)
const {
return this->path() <=> path; }
308 auto operator==(std::string_view path)
const {
return this->path() == path; }
310 void reset() { m_path = {}; }
312 path_type
const& path() const& {
316 bool path_empty()
const {
317 return path_empty(m_path);
321 return std::move(m_path);
324 pointer_type pointer()
const {
325 return resolve_pointer();
328 explicit operator bool() const noexcept {
return pointer() != pointer_type{}; }
329 explicit operator path_type() const noexcept {
return path(); }
333 static bool path_empty(path_type
const& empty)
335 if constexpr (std::is_same_v<path_type, std::string>)
336 return empty.empty();
337 else if constexpr (detail::resolver_has_empty_path<resolver_type>)
338 resolver_type::template path_empty<NoCache>(empty);
340 return empty == path_type{};
345 if constexpr (detail::resolver_can_validate_path<resolver_type>)
347 pointer_type pointer{};
348 resolver_type::template validate_path<pointer_type, NoCache>(m_path, pointer);
352 pointer_type resolve_pointer()
const
354 if (path_empty(m_path))
return {};
355 pointer_type pointer{};
356 resolver_type::template ResolveReferenceFromPath<pointer_type, NoCache>(m_path, pointer);
360 void resolve_path(
const pointer_type& pointer)
const
362 if (!path_empty(m_path))
return;
363 if constexpr (can_resolve_path_from_pointer)
364 resolver_type::template resolve_path_from_reference<pointer_type, NoCache>(pointer, m_path);
367 mutable path_type m_path{};
protected_object< T, MUTEX_TYPE > shared_protected_object
Same as protected_object but uses std::shared_mutex by default.
Primary namespace for everything in this library.
caching_path_reference(T &&p)
Construction from pointer.
static constexpr bool can_resolve_path_from_pointer
Doesn't work for some reason... static_assert(detail::valid_resolver<resolver_type,...
void reset()
Sets both the path and pointer to their defaults.