14
14
#include < utility>
15
15
#include < vector>
16
16
17
- #include " glaze/core/common.hpp"
18
- #include " glaze/util/type_traits.hpp"
19
-
20
17
// This async_map is intended to hold thread safe value types (V)
21
18
22
19
namespace glz
@@ -138,22 +135,22 @@ namespace glz
138
135
pointer operator ->() const { return (*item_it).get (); }
139
136
140
137
// Equality Comparison
141
- bool operator ==(const iterator& other) const { return item_it == other.item_it ; }
138
+ bool operator ==(const iterator& other) const noexcept { return item_it == other.item_it ; }
142
139
143
140
// Inequality Comparison
144
- bool operator !=(const iterator& other) const { return !(*this == other); }
141
+ bool operator !=(const iterator& other) const noexcept { return !(*this == other); }
145
142
146
143
// Comparison operators with iterator
147
- bool operator <(const iterator& other) const { return item_it < other.item_it ; }
148
- bool operator >(const iterator& other) const { return item_it > other.item_it ; }
149
- bool operator <=(const iterator& other) const { return item_it <= other.item_it ; }
144
+ bool operator <(const iterator& other) const noexcept { return item_it < other.item_it ; }
145
+ bool operator >(const iterator& other) const noexcept { return item_it > other.item_it ; }
146
+ bool operator <=(const iterator& other) const noexcept { return item_it <= other.item_it ; }
150
147
bool operator >=(const iterator& other) const { return item_it >= other.item_it ; }
151
148
152
149
// Comparison operators with const_iterator
153
- bool operator <(const const_iterator& other) const { return item_it < other.item_it ; }
154
- bool operator >(const const_iterator& other) const { return item_it > other.item_it ; }
155
- bool operator <=(const const_iterator& other) const { return item_it <= other.item_it ; }
156
- bool operator >=(const const_iterator& other) const { return item_it >= other.item_it ; }
150
+ bool operator <(const const_iterator& other) const noexcept { return item_it < other.item_it ; }
151
+ bool operator >(const const_iterator& other) const noexcept { return item_it > other.item_it ; }
152
+ bool operator <=(const const_iterator& other) const noexcept { return item_it <= other.item_it ; }
153
+ bool operator >=(const const_iterator& other) const noexcept { return item_it >= other.item_it ; }
157
154
};
158
155
159
156
class const_iterator
@@ -223,41 +220,43 @@ namespace glz
223
220
pointer operator ->() const { return (*item_it).get (); }
224
221
225
222
// Equality Comparison
226
- bool operator ==(const const_iterator& other) const { return item_it == other.item_it ; }
223
+ bool operator ==(const const_iterator& other) const noexcept { return item_it == other.item_it ; }
227
224
228
225
// Inequality Comparison
229
- bool operator !=(const const_iterator& other) const { return !(*this == other); }
226
+ bool operator !=(const const_iterator& other) const noexcept { return !(*this == other); }
230
227
231
228
// Comparison operators with const_iterator
232
- bool operator <(const const_iterator& other) const { return item_it < other.item_it ; }
233
- bool operator >(const const_iterator& other) const { return item_it > other.item_it ; }
234
- bool operator <=(const const_iterator& other) const { return item_it <= other.item_it ; }
235
- bool operator >=(const const_iterator& other) const { return item_it >= other.item_it ; }
229
+ bool operator <(const const_iterator& other) const noexcept { return item_it < other.item_it ; }
230
+ bool operator >(const const_iterator& other) const noexcept { return item_it > other.item_it ; }
231
+ bool operator <=(const const_iterator& other) const noexcept { return item_it <= other.item_it ; }
232
+ bool operator >=(const const_iterator& other) const noexcept { return item_it >= other.item_it ; }
236
233
237
234
// Comparison operators with iterator
238
- bool operator <(const iterator& other) const { return item_it < other.item_it ; }
239
- bool operator >(const iterator& other) const { return item_it > other.item_it ; }
240
- bool operator <=(const iterator& other) const { return item_it <= other.item_it ; }
241
- bool operator >=(const iterator& other) const { return item_it >= other.item_it ; }
235
+ bool operator <(const iterator& other) const noexcept { return item_it < other.item_it ; }
236
+ bool operator >(const iterator& other) const noexcept { return item_it > other.item_it ; }
237
+ bool operator <=(const iterator& other) const noexcept { return item_it <= other.item_it ; }
238
+ bool operator >=(const iterator& other) const noexcept { return item_it >= other.item_it ; }
242
239
};
243
240
244
241
// Value Proxy Class Definition
245
242
class value_proxy
246
243
{
247
244
private:
248
- value_type & value_ref;
245
+ V & value_ref;
249
246
std::shared_ptr<std::shared_lock<std::shared_mutex>> shared_lock_ptr;
250
247
std::shared_ptr<std::unique_lock<std::shared_mutex>> unique_lock_ptr;
251
248
252
249
public:
253
- value_proxy (value_type & value_ref,
250
+ value_proxy (V & value_ref,
254
251
std::shared_ptr<std::shared_lock<std::shared_mutex>> existing_shared_lock = nullptr ,
255
252
std::shared_ptr<std::unique_lock<std::shared_mutex>> existing_unique_lock = nullptr )
256
253
: value_ref(value_ref), shared_lock_ptr(existing_shared_lock), unique_lock_ptr(existing_unique_lock)
257
254
{
258
255
// Ensure that a lock is provided
259
256
assert (shared_lock_ptr || unique_lock_ptr);
260
257
}
258
+
259
+ static constexpr bool glaze_value_proxy = true ;
261
260
262
261
// Disable Copy and Move
263
262
value_proxy (const value_proxy&) = delete ;
@@ -266,15 +265,29 @@ namespace glz
266
265
value_proxy& operator =(value_proxy&&) = delete ;
267
266
268
267
// Access the value
269
- V& value () { return value_ref. second ; }
268
+ V& value () { return value_ref; }
270
269
271
- const V& value () const { return value_ref. second ; }
270
+ const V& value () const { return value_ref; }
272
271
273
272
// Arrow Operator
274
- value_type* operator ->() { return &value_ref; }
273
+ V* operator ->() { return &value_ref; }
274
+
275
+ const V* operator ->() const { return &value_ref; }
276
+
277
+ V& operator *() { return value_ref; }
278
+
279
+ const V& operator *() const { return value_ref; }
275
280
276
281
// Implicit Conversion to V&
277
- operator V&() { return value_ref.second ; }
282
+ operator V&() { return value_ref; }
283
+
284
+ operator const V&() const { return value_ref; }
285
+
286
+ template <class T >
287
+ value_proxy& operator =(const T& other) {
288
+ value_ref = other;
289
+ return *this ;
290
+ }
278
291
279
292
bool operator ==(const V& other) const { return value () == other; }
280
293
};
@@ -283,11 +296,11 @@ namespace glz
283
296
class const_value_proxy
284
297
{
285
298
private:
286
- const_value_type & value_ref;
299
+ const V & value_ref;
287
300
std::shared_ptr<std::shared_lock<std::shared_mutex>> shared_lock_ptr;
288
301
289
302
public:
290
- const_value_proxy (const_value_type & value_ref,
303
+ const_value_proxy (const V & value_ref,
291
304
std::shared_ptr<std::shared_lock<std::shared_mutex>> existing_shared_lock)
292
305
: value_ref(value_ref), shared_lock_ptr(existing_shared_lock)
293
306
{
@@ -302,24 +315,60 @@ namespace glz
302
315
const_value_proxy& operator =(const_value_proxy&&) = delete ;
303
316
304
317
// Access the value
305
- const V& value () const { return value_ref. second ; }
318
+ const V& value () const { return value_ref; }
306
319
307
320
// Arrow Operator
308
- const_value_type* operator ->() const { return &value_ref; }
321
+ const V* operator ->() const { return &value_ref; }
322
+
323
+ const V& operator *() const { return value_ref; }
309
324
310
325
// Implicit Conversion to const V&
311
- operator const V&() const { return value_ref. second ; }
326
+ operator const V&() const { return value_ref; }
312
327
313
328
bool operator ==(const V& other) const { return value () == other; }
314
329
};
315
-
316
- template <class KeyType >
317
- [[deprecated(
318
- " operator[] is not allowed with async_map because it would require expensive unique locks" )]] value_proxy
319
- operator [](const KeyType&)
330
+
331
+ value_proxy operator [](const K& key)
320
332
{
321
- static_assert (false_v<KeyType>);
322
- };
333
+ // Acquire a shared lock to search for the key
334
+ std::shared_lock<std::shared_mutex> shared_lock (mutex);
335
+ auto [it, found] = binary_search_key (key);
336
+
337
+ if (found) {
338
+ auto shared_lock_ptr = std::make_shared<std::shared_lock<std::shared_mutex>>(std::move (shared_lock));
339
+ return value_proxy ((*it)->second , shared_lock_ptr);
340
+ }
341
+ else {
342
+ // Key doesn't exist; release the shared_lock
343
+ shared_lock.unlock ();
344
+ // Acquire a unique lock to modify the map
345
+ std::unique_lock<std::shared_mutex> unique_lock (mutex);
346
+
347
+ // Double-check if the key was inserted by another thread
348
+ std::tie (it, found) = binary_search_key (key);
349
+
350
+ if (!found) {
351
+ // Insert a new element with default-constructed value
352
+ it = items.insert (it, std::make_unique<std::pair<K, V>>(
353
+ std::piecewise_construct,
354
+ std::forward_as_tuple (key),
355
+ std::forward_as_tuple ()));
356
+ }
357
+
358
+ unique_lock.unlock ();
359
+ shared_lock.lock ();
360
+
361
+ // Find the value once again in case a modification occurred
362
+ std::tie (it, found) = binary_search_key (key);
363
+
364
+ if (!found) {
365
+ throw std::out_of_range (" Key was removed by another thread" );
366
+ }
367
+
368
+ auto shared_lock_ptr = std::make_shared<std::shared_lock<std::shared_mutex>>(std::move (shared_lock));
369
+ return value_proxy ((*it)->second , shared_lock_ptr);
370
+ }
371
+ }
323
372
324
373
// Insert method behaves like std::map::insert
325
374
std::pair<iterator, bool > insert (const std::pair<K, V>& pair)
@@ -447,7 +496,7 @@ namespace glz
447
496
auto [it, found] = binary_search_key (key);
448
497
449
498
if (found) {
450
- return value_proxy (* (*it), shared_lock_ptr);
499
+ return value_proxy ((*it)-> second , shared_lock_ptr);
451
500
}
452
501
else {
453
502
throw std::out_of_range (" Key not found" );
@@ -463,7 +512,7 @@ namespace glz
463
512
auto [it, found] = binary_search_key (key);
464
513
465
514
if (found) {
466
- return const_value_proxy (* (*it), shared_lock_ptr);
515
+ return const_value_proxy ((*it)-> second , shared_lock_ptr);
467
516
}
468
517
else {
469
518
throw std::out_of_range (" Key not found" );
@@ -521,3 +570,19 @@ namespace glz
521
570
}
522
571
};
523
572
}
573
+
574
+ namespace glz ::detail
575
+ {
576
+ template <class T >
577
+ concept is_value_proxy = requires { T::glaze_value_proxy; };
578
+
579
+ template <is_value_proxy T>
580
+ struct from <JSON, T>
581
+ {
582
+ template <auto Opts>
583
+ static void op (auto && value, is_context auto && ctx, auto && it, auto && end)
584
+ {
585
+ read <JSON>::op<Opts>(value.value (), ctx, it, end);
586
+ }
587
+ };
588
+ }
0 commit comments