header_utils
Loading...
Searching...
No Matches
path_reference.h
1#pragma once
2
3#include <concepts>
4#include <compare>
5#include <string_view>
6#include <string>
7#include <map>
8#include "threading.h"
9
10namespace ghassanpl
11{
15
16 namespace detail
17 {
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>;
21 };
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) };
25 };
26 template <typename RESOLVER>
27 concept resolver_has_empty_path = false;
28
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>;
32 };
33
34 template <typename BASE_POINTER_TYPE, typename PATH_TYPE>
35 struct flyweight_resolver
36 {
37 using value_type = std::pointer_traits<BASE_POINTER_TYPE>::element_type;
38
40
41 template <typename POINTER_TYPE, typename... TAGS>
42 static bool empty_path(PATH_TYPE const& path)
43 {
44 using std::empty;
45 return empty(path);
46 }
47
48 template <typename POINTER_TYPE, typename... TAGS>
49 static bool resolve_reference_from_path(PATH_TYPE const& path, POINTER_TYPE& out_ref)
50 {
51 out_ref = empty_path<POINTER_TYPE, TAGS...>(path)
52 ? mapping.mutate_in_place([&path](auto& mapping) { return &mapping[path]; })
53 : POINTER_TYPE{};
54 return true;
55 }
56
57 template <typename POINTER_TYPE, typename... TAGS>
58 static bool resolve_path_from_reference(POINTER_TYPE const& ref, PATH_TYPE& out_path)
59 {
60 return mapping.read_only_access([&out_path, ptr = std::to_address(ref)](auto const& mapping) {
61 for (auto const& [path, val] : mapping)
62 {
63 if (&val == ptr)
64 {
65 out_path = path;
66 return true;
67 }
68 }
69 return false;
70 });
71 }
72
73 template <typename POINTER_TYPE, typename... TAGS>
74 static void validate_path(PATH_TYPE& path)
75 {
77 }
78
80 };
81 }
82
89 template <
90 typename POINTER_TYPE,
91 typename PATH_TYPE = std::string,
92 typename RESOLVER_TYPE = detail::flyweight_resolver<POINTER_TYPE, PATH_TYPE>,
93 typename... TAGS>
94 struct caching_path_reference
95 {
96 // TODO: Possible tags:
97 // - thread_safe (adds a shared_mutex and protection for accessors)
98 // - resolver_context (adds a pointer to RESOLVER_TYPE that is used to call the resolution functions)
99
100 using resolver_type = RESOLVER_TYPE;
101 using path_type = PATH_TYPE;
102 using pointer_type = POINTER_TYPE;
103
107
108 static constexpr bool can_resolve_path_from_pointer = detail::resolver_can_resolve_path_from_pointer<resolver_type, path_type, pointer_type, TAGS...>;
109
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;
115
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(); }
120
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) {
125 m_pointer = {};
126 m_path = std::forward<T>(p);
127 validate_path();
128 return *this;
129 }
130
132 template <typename T>
133 requires (can_resolve_path_from_pointer&& std::constructible_from<pointer_type, T>)
134 caching_path_reference(T&& p) : m_pointer(std::forward<T>(p)) { m_path = {}; }
135
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);
141 m_path = {};
142 return *this;
143 }
144
145 pointer_type operator->() const { return pointer(); }
146 auto& operator*() const { return *pointer(); }
147
148 template <typename T>
149 bool operator==(T const& other) const
150 requires (
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>)
155 )
156 {
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 };
165 }
166
167 template <typename T>
168 auto operator<=>(T const& other) const
169 requires (
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>)
174 )
175 {
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 };
184 }
185
187 void reset() { m_path = {}; m_pointer = {}; }
188
189 path_type const& path() const& {
190 resolve_path();
191 return m_path;
192 }
193
194 bool path_empty() const {
195 resolve_path();
196 return path_empty(m_path);
197 }
198
199 path_type path() && {
200 resolve_path();
201 return std::move(m_path);
202 }
203
204 pointer_type const& pointer() const& {
205 resolve_pointer();
206 return m_pointer;
207 }
208
209 pointer_type pointer() && {
210 resolve_pointer();
211 return std::move(m_pointer);
212 }
213
214 explicit operator bool() const noexcept { return pointer() != pointer_type{}; }
215 explicit operator path_type() const noexcept { return path(); }
216
217 private:
218
219 static bool path_empty(path_type const& empty)
220 {
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);
225 else
226 return empty == path_type{};
227 }
228
229 void validate_path()
230 {
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);
233 }
234
235 void resolve_pointer() const
236 {
237 if (m_pointer || path_empty(m_path)) return;
238 resolver_type::template resolve_reference_from_path<pointer_type, TAGS...>(m_path, m_pointer);
239 }
240
241 void resolve_path() const
242 {
243 if constexpr (can_resolve_path_from_pointer)
244 {
245 if (!path_empty(m_path) || !m_pointer) return;
246 resolver_type::template resolve_path_from_reference<pointer_type, TAGS...>(m_pointer, m_path);
247 }
248 }
249
250 mutable path_type m_path{};
251 mutable pointer_type m_pointer{};
252 };
253
255
256#if 0
257 template <typename RESOLVER_TYPE, typename PATH_TYPE, typename POINTER_TYPE>
258 struct path_reference<RESOLVER_TYPE, PATH_TYPE, POINTER_TYPE, NoCache>
259 {
260 using resolver_type = RESOLVER_TYPE;
261 using path_type = PATH_TYPE;
262 using pointer_type = POINTER_TYPE;
263
266
267 static constexpr bool can_resolve_path_from_pointer = detail::resolver_can_resolve_path_from_pointer<resolver_type, path_type, pointer_type, NoCache>;
268
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;
274
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(); }
278
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);
283 validate_path();
284 return *this;
285 }
286
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); }
290
291 template <typename T>
292 requires can_resolve_path_from_pointer&& std::assignable_from<pointer_type, T>
293 auto& operator=(T&& p) {
294 resolve_path(p);
295 return *this;
296 }
297
298 pointer_type operator->() const { return pointer(); }
299 auto& operator*() const { return *pointer(); }
300
301 auto operator<=>(path_reference const& other) const { return path() <=> other.path(); }
302 auto operator==(path_reference const& other) const { return path() == other.path(); }
303
304 auto operator<=>(pointer_type const& ptr) const { return pointer() <=> ptr; }
305 auto operator==(pointer_type const& ptr) const { return pointer() == ptr; }
306
307 auto operator<=>(std::string_view path) const { return this->path() <=> path; }
308 auto operator==(std::string_view path) const { return this->path() == path; }
309
310 void reset() { m_path = {}; }
311
312 path_type const& path() const& {
313 return m_path;
314 }
315
316 bool path_empty() const {
317 return path_empty(m_path);
318 }
319
320 path_type path()&& {
321 return std::move(m_path);
322 }
323
324 pointer_type pointer() const {
325 return resolve_pointer();
326 }
327
328 explicit operator bool() const noexcept { return pointer() != pointer_type{}; }
329 explicit operator path_type() const noexcept { return path(); }
330
331 private:
332
333 static bool path_empty(path_type const& empty)
334 {
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);
339 else
340 return empty == path_type{};
341 }
342
343 void validate_path()
344 {
345 if constexpr (detail::resolver_can_validate_path<resolver_type>)
346 {
347 pointer_type pointer{};
348 resolver_type::template validate_path<pointer_type, NoCache>(m_path, pointer);
349 }
350 }
351
352 pointer_type resolve_pointer() const
353 {
354 if (path_empty(m_path)) return {};
355 pointer_type pointer{};
356 resolver_type::template ResolveReferenceFromPath<pointer_type, NoCache>(m_path, pointer);
357 return pointer;
358 }
359
360 void resolve_path(const pointer_type& pointer) const
361 {
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);
365 }
366
367 mutable path_type m_path{};
368 };
369#endif
370}
protected_object< T, MUTEX_TYPE > shared_protected_object
Same as protected_object but uses std::shared_mutex by default.
Definition threading.h:169
Primary namespace for everything in this library.
Definition align+rec2.h:10
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.