Metall v0.30
A persistent memory allocator for data-centric analytics
 
Loading...
Searching...
No Matches
value.hpp
Go to the documentation of this file.
1// Copyright 2021 Lawrence Livermore National Security, LLC and other Metall
2// Project Developers. See the top-level COPYRIGHT file for details.
3//
4// SPDX-License-Identifier: (Apache-2.0 OR MIT)
5
6#ifndef METALL_JSON_VALUE_HPP
7#define METALL_JSON_VALUE_HPP
8
9#include <memory>
10#include <utility>
11#include <string_view>
12#include <variant>
13#include <type_traits>
14
16
17namespace metall::json {
18
19namespace {
20namespace mc = metall::container;
21}
22
23namespace jsndtl {
24
27template <typename allocator_type, typename other_value_type>
29 const other_value_type &other_value) noexcept {
30 if (other_value.is_null()) {
31 return value.is_null();
32 } else if (other_value.is_bool()) {
33 return value.is_bool() && value.as_bool() == other_value.as_bool();
34 } else if (other_value.is_int64()) {
35 if (value.is_int64()) {
36 return value.as_int64() == other_value.as_int64();
37 }
38 if (value.is_uint64()) {
39 return (other_value.as_int64() < 0)
40 ? false
41 : value.as_uint64() ==
42 static_cast<std::uint64_t>(other_value.as_int64());
43 }
44 return false;
45 } else if (other_value.is_uint64()) {
46 if (value.is_uint64()) {
47 return value.as_uint64() == other_value.as_uint64();
48 }
49 if (value.is_int64()) {
50 return (value.as_int64() < 0)
51 ? false
52 : static_cast<std::uint64_t>(value.as_int64()) ==
53 other_value.as_uint64();
54 }
55 return false;
56 } else if (other_value.is_double()) {
57 return value.is_double() && value.as_double() == other_value.as_double();
58 } else if (other_value.is_object()) {
59 return value.is_object() && (value.as_object() == other_value.as_object());
60 } else if (other_value.is_array()) {
61 return value.is_array() && (value.as_array() == other_value.as_array());
62 } else if (other_value.is_string()) {
63 if (!value.is_string()) return false;
64 const auto &str = value.as_string();
65 const auto &other_srt = other_value.as_string();
66 return str.compare(other_srt.c_str()) == 0;
67 }
68
69 assert(false);
70 return false;
71}
72} // namespace jsndtl
73
77#ifdef DOXYGEN_SKIP
78template <typename Alloc = std::allocator<std::byte>>
79#else
80template <typename Alloc>
81#endif
82class value {
83 public:
84 using allocator_type = Alloc;
87 typename std::allocator_traits<
88 allocator_type>::template rebind_alloc<char>>;
91
92 private:
93 using internal_data_type =
94 std::variant<null_type, bool, std::int64_t, std::uint64_t, double,
96
97 public:
99 value() { priv_reset(); }
100
103 explicit value(const allocator_type &alloc) : m_allocator(alloc) {
104 priv_reset();
105 }
106
108 value(const value &other)
109 : m_allocator(
110 std::allocator_traits<allocator_type>::
111 select_on_container_copy_construction(other.get_allocator())),
112 m_data(other.m_data) {}
113
115 value(const value &other, const allocator_type &alloc) : m_allocator(alloc) {
116 if (other.is_object()) {
117 m_data.template emplace<object_type>(other.as_object(), m_allocator);
118 } else if (other.is_array()) {
119 m_data.template emplace<array_type>(other.as_array(), m_allocator);
120 } else if (other.is_string()) {
121 m_data.template emplace<string_type>(other.as_string(), m_allocator);
122 } else {
123 m_data = other.m_data;
124 }
125 }
126
128 value(value &&other) noexcept
129 : m_allocator(std::move(other.m_allocator)),
130 m_data(std::move(other.m_data)) {
131 other.priv_reset();
132 }
133
135 value(value &&other, const allocator_type &alloc) noexcept
136 : m_allocator(alloc) {
137 if (other.is_object()) {
138 m_data.template emplace<object_type>(std::move(other.as_object()),
139 m_allocator);
140 } else if (other.is_array()) {
141 m_data.template emplace<array_type>(std::move(other.as_array()),
142 m_allocator);
143 } else if (other.is_string()) {
144 m_data.template emplace<string_type>(std::move(other.as_string()),
145 m_allocator);
146 } else {
147 m_data = std::move(other.m_data);
148 }
149 other.priv_reset();
150 }
151
153 ~value() noexcept { priv_reset(); }
154
156 value &operator=(const value &other) {
157 if (this == &other) return *this;
158
159 if constexpr (std::is_same_v<
160 typename std::allocator_traits<allocator_type>::
161 propagate_on_container_copy_assignment,
162 std::true_type>) {
163 m_allocator = other.m_allocator;
164 }
165
166 // Cannot do `m_data = other.m_data`
167 // because std::variant calls the allocator-extended copy constructor of the
168 // holding data, which ignores propagate_on_container_copy_assignment value.
169 if (other.is_object()) {
170 emplace_object() = other.as_object();
171 } else if (other.is_array()) {
172 emplace_array() = other.as_array();
173 } else if (other.is_string()) {
174 emplace_string() = other.as_string();
175 } else {
176 m_data = other.m_data;
177 }
178
179 return *this;
180 }
181
183 value &operator=(value &&other) noexcept {
184 if (this == &other) return *this;
185
186 if constexpr (std::is_same_v<
187 typename std::allocator_traits<allocator_type>::
188 propagate_on_container_move_assignment,
189 std::true_type>) {
190 m_allocator = std::move(other.m_allocator);
191 }
192
193 if (other.is_object()) {
194 emplace_object() = std::move(other.as_object());
195 } else if (other.is_array()) {
196 emplace_array() = std::move(other.as_array());
197 } else if (other.is_string()) {
198 emplace_string() = std::move(other.as_string());
199 } else {
200 m_data = std::move(other.m_data);
201 }
202
203 other.priv_reset();
204
205 return *this;
206 }
207
209 void swap(value &other) noexcept {
210 using std::swap;
211 if constexpr (std::is_same_v<
212 typename std::allocator_traits<
213 allocator_type>::propagate_on_container_swap,
214 std::true_type>) {
215 swap(m_allocator, other.m_allocator);
216 } else {
217 // This is an undefined behavior in the C++ standard.
218 assert(get_allocator() == other.m_allocator);
219 }
220
221 swap(m_data, other.m_data);
222 }
223
226 value &operator=(const bool b) {
227 emplace_bool() = b;
228 return *this;
229 }
230
233 value &operator=(const signed char i) {
234 return operator=(static_cast<long long>(i));
235 }
236
239 value &operator=(const short i) {
240 return operator=(static_cast<long long>(i));
241 }
242
245 value &operator=(const int i) { return operator=(static_cast<long long>(i)); }
246
249 value &operator=(const long i) {
250 return operator=(static_cast<long long>(i));
251 }
252
255 value &operator=(const long long i) {
256 emplace_int64() = i;
257 return *this;
258 }
259
262 value &operator=(const unsigned char u) {
263 return operator=(static_cast<unsigned long long>(u));
264 }
265
268 value &operator=(const unsigned short u) {
269 return operator=(static_cast<unsigned long long>(u));
270 }
271
274 value &operator=(const unsigned int u) {
275 return operator=(static_cast<unsigned long long>(u));
276 }
277
280 value &operator=(const unsigned long u) {
281 return operator=(static_cast<unsigned long long>(u));
282 }
283
286 value &operator=(const unsigned long long u) {
287 emplace_uint64() = u;
288 return *this;
289 }
290
293 value &operator=(std::nullptr_t) {
294 emplace_null();
295 return *this;
296 }
297
300 value &operator=(const double d) {
301 emplace_double() = d;
302 return *this;
303 }
304
307 value &operator=(std::string_view s) {
308 emplace_string() = s.data();
309 return *this;
310 }
311
314 value &operator=(const char *const s) {
315 emplace_string() = s;
316 return *this;
317 }
318
322 emplace_string() = s;
323 return *this;
324 }
325
326 // value &operator=(std::initializer_list<value_ref> init);
327
331 emplace_string() = std::move(s);
332 return *this;
333 }
334
338 emplace_array() = arr;
339 return *this;
340 }
341
345 emplace_array() = std::move(arr);
346 return *this;
347 }
348
352 emplace_object() = obj;
353 return *this;
354 }
355
359 emplace_object() = std::move(obj);
360 return *this;
361 }
362
365 void emplace_null() { priv_reset(); }
366
369 bool &emplace_bool() {
370 priv_reset();
371 return m_data.template emplace<bool>();
372 }
373
376 std::int64_t &emplace_int64() {
377 priv_reset();
378 return m_data.template emplace<std::int64_t>();
379 }
380
383 std::uint64_t &emplace_uint64() {
384 priv_reset();
385 return m_data.template emplace<std::uint64_t>();
386 }
387
390 double &emplace_double() {
391 priv_reset();
392 return m_data.template emplace<double>();
393 }
394
398 priv_reset();
399 return m_data.template emplace<string_type>(m_allocator);
400 }
401
405 priv_reset();
406 return m_data.template emplace<array_type>(m_allocator);
407 }
408
412 priv_reset();
413 return m_data.template emplace<object_type>(m_allocator);
414 }
415
417 bool &as_bool() { return std::get<bool>(m_data); }
418
421 const bool &as_bool() const { return std::get<bool>(m_data); }
422
425 std::int64_t &as_int64() { return std::get<std::int64_t>(m_data); }
426
429 const std::int64_t &as_int64() const {
430 return std::get<std::int64_t>(m_data);
431 }
432
435 std::uint64_t &as_uint64() { return std::get<std::uint64_t>(m_data); }
436
439 const std::uint64_t &as_uint64() const {
440 return std::get<std::uint64_t>(m_data);
441 }
442
444 double &as_double() { return std::get<double>(m_data); }
445
448 const double &as_double() const { return std::get<double>(m_data); }
449
451 string_type &as_string() { return std::get<string_type>(m_data); }
452
455 const string_type &as_string() const { return std::get<string_type>(m_data); }
456
458 array_type &as_array() { return std::get<array_type>(m_data); }
459
462 const array_type &as_array() const { return std::get<array_type>(m_data); }
463
465 object_type &as_object() { return std::get<object_type>(m_data); }
466
469 const object_type &as_object() const { return std::get<object_type>(m_data); }
470
472 bool is_null() const noexcept {
473 return std::holds_alternative<null_type>(m_data);
474 }
475
477 bool is_bool() const noexcept { return std::holds_alternative<bool>(m_data); }
478
480 bool is_int64() const noexcept {
481 return std::holds_alternative<int64_t>(m_data);
482 }
483
485 bool is_uint64() const noexcept {
486 return std::holds_alternative<uint64_t>(m_data);
487 }
488
490 bool is_double() const noexcept {
491 return std::holds_alternative<double>(m_data);
492 }
493
495 bool is_string() const noexcept {
496 return std::holds_alternative<string_type>(m_data);
497 }
498
500 bool is_array() const noexcept {
501 return std::holds_alternative<array_type>(m_data);
502 }
503
505 bool is_object() const noexcept {
506 return std::holds_alternative<object_type>(m_data);
507 }
508
510 allocator_type get_allocator() const noexcept { return m_allocator; }
511
513 friend bool operator==(const value &lhs, const value &rhs) noexcept {
514 return jsndtl::general_value_equal(lhs, rhs);
515 ;
516 }
517
523 friend bool operator!=(const value &lhs, const value &rhs) noexcept {
524 return !(lhs == rhs);
525 }
526
527 private:
528 bool priv_reset() {
529 m_data.template emplace<null_type>();
530 return true;
531 }
532
533 allocator_type m_allocator{allocator_type{}};
534 internal_data_type m_data{null_type{}};
535};
536
538template <typename allocator_type>
540 value<allocator_type> &rhd) noexcept {
541 lhd.swap(rhd);
542}
543
544} // namespace metall::json
545
546#endif // METALL_JSON_VALUE_HPP
JSON array. An array is an ordered collection of values.
Definition array.hpp:43
JSON object. An object is a table key and value pairs. The order of key-value pairs depends on the im...
Definition object.hpp:22
JSON value. A container that holds a single bool, int64, uint64, double, JSON string,...
Definition value.hpp:82
value & operator=(const double d)
Assign a double value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:300
value & operator=(const unsigned short u)
Assign an unsigned short value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:268
bool & emplace_bool()
Set a bool and return a reference. The old content is destroyed.
Definition value.hpp:369
value & operator=(string_type &&s)
Assign a string_type value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:330
const std::uint64_t & as_uint64() const
Return a const reference to the underlying std::uint64_t, or throw an exception.
Definition value.hpp:439
value & operator=(const long i)
Assign a long value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:249
value & operator=(const char *const s)
Assign a const char* value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:314
const string_type & as_string() const
Return a const reference to the underlying string, or throw an exception.
Definition value.hpp:455
value & operator=(value &&other) noexcept
Move assignment operator.
Definition value.hpp:183
value & operator=(const int i)
Assign an int value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:245
array_type & as_array()
Return a reference to the underlying array, or throw an exception.
Definition value.hpp:458
value & operator=(const string_type &s)
Assign a string_type value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:321
value & operator=(const signed char i)
Assign a char value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:233
value & operator=(std::nullptr_t)
Assign a null value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:293
bool is_null() const noexcept
Return true if this is a null.
Definition value.hpp:472
object_type & as_object()
Return a reference to the underlying object, or throw an exception.
Definition value.hpp:465
value & operator=(const unsigned char u)
Assign an unsigned char value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:262
bool is_string() const noexcept
Return true if this is a string.
Definition value.hpp:495
bool is_int64() const noexcept
Return true if this is a int64.
Definition value.hpp:480
const double & as_double() const
Return a const reference to the underlying double, or throw an exception.
Definition value.hpp:448
const array_type & as_array() const
Return a const reference to the underlying array, or throw an exception.
Definition value.hpp:462
bool & as_bool()
Return a reference to the underlying bool, or throw an exception.
Definition value.hpp:417
value & operator=(object_type &&obj)
Assign an object_type value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:358
friend bool operator==(const value &lhs, const value &rhs) noexcept
Equal operator.
Definition value.hpp:513
value(value &&other) noexcept
Move constructor.
Definition value.hpp:128
bool is_uint64() const noexcept
Return true if this is a uint64.
Definition value.hpp:485
friend bool operator!=(const value &lhs, const value &rhs) noexcept
Return true if two values are not equal. Two values are equal when they are the same kind and their r...
Definition value.hpp:523
void swap(value &other) noexcept
Swap contents.
Definition value.hpp:209
double & emplace_double()
Set a double and return a reference. The old content is destroyed.
Definition value.hpp:390
bool is_bool() const noexcept
Return true if this is a bool.
Definition value.hpp:477
string_type & emplace_string()
Set an empty string and return a reference. The old content is destroyed.
Definition value.hpp:397
value & operator=(array_type &&arr)
Assign an array_type value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:344
std::uint64_t & emplace_uint64()
Set a uint64 and return a reference. The old content is destroyed.
Definition value.hpp:383
value & operator=(const unsigned long long u)
Assign an unsigned long long value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:286
const object_type & as_object() const
Return a const reference to the underlying object, or throw an exception.
Definition value.hpp:469
value & operator=(const array_type &arr)
Assign an array_type value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:337
~value() noexcept
Destructor.
Definition value.hpp:153
value(const value &other, const allocator_type &alloc)
Allocator-extended copy constructor.
Definition value.hpp:115
object< Alloc > object_type
Definition value.hpp:89
value & operator=(const unsigned long u)
Assign an unsigned long value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:280
bool is_object() const noexcept
Return true if this is a object.
Definition value.hpp:505
value & operator=(const unsigned int u)
Assign an unsigned int value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:274
object_type & emplace_object()
Set an empty object and return a reference. The old content is destroyed.
Definition value.hpp:411
array_type & emplace_array()
Set an empty array and return a reference. The old content is destroyed.
Definition value.hpp:404
value(const allocator_type &alloc)
Constructor.
Definition value.hpp:103
allocator_type get_allocator() const noexcept
Return an allocator object.
Definition value.hpp:510
value & operator=(const short i)
Assign a short value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:239
array< Alloc > array_type
Definition value.hpp:90
value & operator=(const object_type &obj)
Assign an object_type value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:351
bool is_array() const noexcept
Return true if this is an array.
Definition value.hpp:500
std::int64_t & emplace_int64()
Set a int64 and return a reference. The old content is destroyed.
Definition value.hpp:376
std::uint64_t & as_uint64()
Return a reference to the underlying std::uint64_t, or throw an exception.
Definition value.hpp:435
const std::int64_t & as_int64() const
Return a const reference to the underlying std::int64_t, or throw an exception.
Definition value.hpp:429
value & operator=(const value &other)
Copy assignment operator.
Definition value.hpp:156
value & operator=(const long long i)
Assign a long long value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:255
basic_string< char, std::char_traits< char >, typename std::allocator_traits< allocator_type >::template rebind_alloc< char > > string_type
Definition value.hpp:88
value(value &&other, const allocator_type &alloc) noexcept
Allocator-extended move constructor.
Definition value.hpp:135
value & operator=(const bool b)
Assign a bool value. Allocates a memory storage or destroy the old content, if necessary.
Definition value.hpp:226
string_type & as_string()
Return a reference to the underlying string, or throw an exception.
Definition value.hpp:451
const bool & as_bool() const
Return a const reference to the underlying bool, or throw an exception.
Definition value.hpp:421
bool is_double() const noexcept
Return true if this is a double.
Definition value.hpp:490
std::int64_t & as_int64()
Return a reference to the underlying std::int64_t, or throw an exception.
Definition value.hpp:425
Alloc allocator_type
Definition value.hpp:84
void emplace_null()
Set a null. The old content is destroyed.
Definition value.hpp:365
value(const value &other)
Copy constructor.
Definition value.hpp:108
double & as_double()
Return a reference to the underlying double, or throw an exception.
Definition value.hpp:444
value()
Constructor.
Definition value.hpp:99
value & operator=(std::string_view s)
Assign a std::string_view value. Allocates a memory storage or destroy the old content,...
Definition value.hpp:307
Namespace for Metall container.
bool general_value_equal(const value< allocator_type > &value, const other_value_type &other_value) noexcept
Provides 'equal' calculation for other value types that have the same interface as the value class.
Definition value.hpp:28
Namespace for Metall JSON container, which is in an experimental phase.
Definition array.hpp:17
metall::container::basic_string< char_t, traits, allocator_type > basic_string
JSON basic string type.
Definition json_fwd.hpp:44
std::monostate null_type
JSON null type.
Definition json_fwd.hpp:39
void swap(array< allocator_type > &lhd, array< allocator_type > &rhd) noexcept
Swap value instances.
Definition array.hpp:193