Metall v0.30
A persistent memory allocator for data-centric analytics
 
Loading...
Searching...
No Matches
key_value_pair.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_KEY_VALUE_PAIR_HPP
7#define METALL_JSON_KEY_VALUE_PAIR_HPP
8
9#include <string_view>
10#include <memory>
11#include <string>
12#include <algorithm>
13#include <cstring>
14
15#include <metall/offset_ptr.hpp>
16#include <metall/detail/utilities.hpp>
18
19namespace metall::json {
20
21namespace jsndtl {
24template <typename char_type, typename char_traits, typename allocator_type,
25 typename other_key_value_pair_type>
28 const other_key_value_pair_type &other_key_value) noexcept {
29 if (key_value.key().length() != other_key_value.key().length())
30 return false;
31 if (std::strcmp(key_value.key_c_str(), other_key_value.key_c_str()) != 0)
32 return false;
33 return key_value.value() == other_key_value.value();
34}
35} // namespace jsndtl
36
40#ifdef DOXYGEN_SKIP
41template <typename char_type = char,
42 typename char_traits = std::char_traits<char_type>,
43 typename Alloc = std::allocator<char_type>>
44#else
45template <typename _char_type, typename _char_traits, typename Alloc>
46#endif
48 private:
49 using char_allocator_type =
50 typename std::allocator_traits<Alloc>::template rebind_alloc<_char_type>;
51 using char_pointer =
52 typename std::allocator_traits<char_allocator_type>::pointer;
53
54 public:
55 using char_type = _char_type;
56 using char_traits = _char_traits;
57 using allocator_type = Alloc;
58 using key_type = std::basic_string_view<char_type, char_traits>;
60 using size_type = std::size_t;
61
62 public:
69 const allocator_type &alloc = allocator_type())
70 : m_value(value, alloc) {
71 priv_allocate_key(key.data(), key.length(), m_value.get_allocator());
72 }
73
80 const allocator_type &alloc = allocator_type())
81 : m_value(std::move(value), alloc) {
82 priv_allocate_key(key.data(), key.length(), m_value.get_allocator());
83 }
84
86 key_value_pair(const key_value_pair &other) : m_value(other.m_value) {
87 priv_allocate_key(other.key_c_str(), other.m_key_length,
88 m_value.get_allocator());
89 }
90
92 key_value_pair(const key_value_pair &other, const allocator_type &alloc)
93 : m_value(other.m_value, alloc) {
94 priv_allocate_key(other.key_c_str(), other.m_key_length,
95 m_value.get_allocator());
96 }
97
100 : m_value(std::move(other.m_value)) {
101 if (other.priv_short_key()) {
102 m_short_key_buf = other.m_short_key_buf;
103 } else {
104 m_long_key = std::move(other.m_long_key);
105 other.m_long_key = nullptr;
106 }
107 m_key_length = other.m_key_length;
108 other.m_key_length = 0;
109 }
110
112 key_value_pair(key_value_pair &&other, const allocator_type &alloc) noexcept
113 : m_value(alloc) {
114 if (alloc == other.get_allocator()) {
115 if (other.priv_short_key()) {
116 m_short_key_buf = other.m_short_key_buf;
117 } else {
118 m_long_key = std::move(other.m_long_key);
119 other.m_long_key = nullptr;
120 }
121 m_key_length = other.m_key_length;
122 other.m_key_length = 0;
123 } else {
124 priv_allocate_key(other.key_c_str(), other.m_key_length, get_allocator());
125 other.priv_deallocate_key(other.get_allocator());
126 }
127 m_value = std::move(other.m_value);
128 }
129
132 if (this == &other) return *this;
133
134 priv_deallocate_key(get_allocator()); // deallocate the key using the
135 // current allocator first
136 m_value = other.m_value;
137 // This line has to come after copying m_value because m_value decides if
138 // allocator is needed to be propagated.
139 priv_allocate_key(other.key_c_str(), other.m_key_length, get_allocator());
140
141 return *this;
142 }
143
146 if (this == &other) return *this;
147
148 priv_deallocate_key(get_allocator()); // deallocate the key using the
149 // current allocator first
150
151 auto other_allocator = other.m_value.get_allocator();
152 m_value = std::move(other.m_value);
153
154 if (get_allocator() == other.get_allocator()) {
155 if (other.priv_short_key()) {
156 m_short_key_buf = other.m_short_key_buf;
157 } else {
158 m_long_key = std::move(other.m_long_key);
159 other.m_long_key = nullptr;
160 }
161 m_key_length = other.m_key_length;
162 other.m_key_length = 0;
163 } else {
164 priv_allocate_key(other.key_c_str(), other.m_key_length, get_allocator());
165 other.priv_deallocate_key(other_allocator);
166 }
167
168 return *this;
169 }
170
172 void swap(key_value_pair &other) noexcept {
173 if constexpr (!std::is_same_v<
174 typename std::allocator_traits<
175 allocator_type>::propagate_on_container_swap,
176 std::true_type>) {
177 // This is an undefined behavior in the C++ standard.
178 assert(get_allocator() == other.get_allocator());
179 }
180
181 using std::swap;
182
183 if (priv_short_key()) {
184 swap(m_short_key, other.m_short_key);
185 } else {
186 swap(m_long_key, other.m_long_key);
187 }
188 swap(m_key_length, other.m_key_length);
189
190 swap(m_value, other.m_value);
191 }
192
194 ~key_value_pair() noexcept { priv_deallocate_key(get_allocator()); }
195
198 const key_type key() const noexcept {
199 return key_type(key_c_str(), m_key_length);
200 }
201
204 const char_type *key_c_str() const noexcept { return priv_key_c_str(); }
205
208 value_type &value() noexcept { return m_value; }
209
212 const value_type &value() const noexcept { return m_value; }
213
218 friend bool operator==(const key_value_pair &lhs,
219 const key_value_pair &rhs) noexcept {
221 }
222
227 friend bool operator!=(const key_value_pair &lhs,
228 const key_value_pair &rhs) noexcept {
229 return !(lhs == rhs);
230 }
231
233 allocator_type get_allocator() const noexcept {
234 return m_value.get_allocator();
235 }
236
237 private:
238 static constexpr uint32_t k_short_key_max_length =
239 sizeof(char_pointer) - 1; // -1 for '0'
240
241 const char_type *priv_key_c_str() const noexcept {
242 if (priv_short_key()) {
243 return m_short_key;
244 }
245 return metall::to_raw_pointer(m_long_key);
246 }
247
248 bool priv_short_key() const noexcept {
249 return (m_key_length <= k_short_key_max_length);
250 }
251
252 bool priv_long_key() const noexcept { return !priv_short_key(); }
253
254 bool priv_allocate_key(const char_type *const key, const size_type length,
255 char_allocator_type alloc) {
256 assert(m_key_length == 0);
257 m_key_length = length;
258
259 if (priv_short_key()) {
260 std::char_traits<char_type>::copy(m_short_key, key, m_key_length);
261 std::char_traits<char_type>::assign(m_short_key[m_key_length], '\0');
262 } else {
263 m_long_key = std::allocator_traits<char_allocator_type>::allocate(
264 alloc, m_key_length + 1);
265 if (!m_long_key) {
266 m_key_length = 0;
267 std::abort(); // TODO: change
268 return false;
269 }
270
271 std::char_traits<char_type>::copy(metall::to_raw_pointer(m_long_key), key,
272 m_key_length);
273 std::char_traits<char_type>::assign(m_long_key[m_key_length], '\0');
274 }
275
276 return true;
277 }
278
279 bool priv_deallocate_key(char_allocator_type alloc) {
280 if (m_key_length > k_short_key_max_length) {
281 std::allocator_traits<char_allocator_type>::deallocate(alloc, m_long_key,
282 m_key_length + 1);
283 m_long_key = nullptr;
284 }
285 m_key_length = 0;
286 return true;
287 }
288
289 union {
290 char_type m_short_key[k_short_key_max_length + 1]; // + 1 for '\0'
291 static_assert(sizeof(char_type) * (k_short_key_max_length + 1) <=
292 sizeof(uint64_t),
293 "sizeof(m_short_key) is bigger than sizeof(uint64_t)");
295
296 char_pointer m_long_key{nullptr};
297 };
298 size_type m_key_length{0};
299
300 value_type m_value;
301};
302
304template <typename char_type, typename char_traits, typename allocator_type>
310
311} // namespace metall::json
312
313#endif // METALL_JSON_KEY_VALUE_PAIR_HPP
A class for holding a pair of JSON string (as its key) and JSON value (as its value).
Definition key_value_pair.hpp:47
char_type m_short_key[k_short_key_max_length+1]
Definition key_value_pair.hpp:290
Alloc allocator_type
Definition key_value_pair.hpp:57
key_value_pair(key_type key, value_type &&value, const allocator_type &alloc=allocator_type())
Constructor.
Definition key_value_pair.hpp:79
key_value_pair & operator=(const key_value_pair &other)
Copy assignment operator.
Definition key_value_pair.hpp:131
friend bool operator==(const key_value_pair &lhs, const key_value_pair &rhs) noexcept
Return true if two key-value pairs are equal.
Definition key_value_pair.hpp:218
key_value_pair & operator=(key_value_pair &&other) noexcept
Move assignment operator.
Definition key_value_pair.hpp:145
void swap(key_value_pair &other) noexcept
Swap contents.
Definition key_value_pair.hpp:172
std::basic_string_view< char_type, char_traits > key_type
Definition key_value_pair.hpp:58
allocator_type get_allocator() const noexcept
Return an allocator object.
Definition key_value_pair.hpp:233
_char_type char_type
Definition key_value_pair.hpp:55
value_type & value() noexcept
References the stored JSON value.
Definition key_value_pair.hpp:208
~key_value_pair() noexcept
Destructor.
Definition key_value_pair.hpp:194
const value_type & value() const noexcept
References the stored JSON value.
Definition key_value_pair.hpp:212
key_value_pair(key_value_pair &&other, const allocator_type &alloc) noexcept
Allocator-extended move constructor.
Definition key_value_pair.hpp:112
key_value_pair(key_type key, const value_type &value, const allocator_type &alloc=allocator_type())
Constructor.
Definition key_value_pair.hpp:68
key_value_pair(const key_value_pair &other)
Copy constructor.
Definition key_value_pair.hpp:86
key_value_pair(const key_value_pair &other, const allocator_type &alloc)
Allocator-extended copy constructor.
Definition key_value_pair.hpp:92
key_value_pair(key_value_pair &&other) noexcept
Move constructor.
Definition key_value_pair.hpp:99
_char_traits char_traits
Definition key_value_pair.hpp:56
friend bool operator!=(const key_value_pair &lhs, const key_value_pair &rhs) noexcept
Return true if two key-value pairs are not equal.
Definition key_value_pair.hpp:227
metall::json::value< allocator_type > value_type
Definition key_value_pair.hpp:59
const key_type key() const noexcept
Returns the stored key.
Definition key_value_pair.hpp:198
uint64_t m_short_key_buf
Definition key_value_pair.hpp:294
std::size_t size_type
Definition key_value_pair.hpp:60
const char_type * key_c_str() const noexcept
Returns the stored key as const char*.
Definition key_value_pair.hpp:204
char_pointer m_long_key
Definition key_value_pair.hpp:296
JSON value. A container that holds a single bool, int64, uint64, double, JSON string,...
Definition value.hpp:82
void swap(value &other) noexcept
Swap contents.
Definition value.hpp:209
allocator_type get_allocator() const noexcept
Return an allocator object.
Definition value.hpp:510
value()
Constructor.
Definition value.hpp:99
bool general_key_value_pair_equal(const key_value_pair< char_type, char_traits, allocator_type > &key_value, const other_key_value_pair_type &other_key_value) noexcept
Provides 'equal' calculation for other key-value types that have the same interface as the object cla...
Definition key_value_pair.hpp:26
Namespace for Metall JSON container, which is in an experimental phase.
Definition array.hpp:17
void swap(array< allocator_type > &lhd, array< allocator_type > &rhd) noexcept
Swap value instances.
Definition array.hpp:193