|
26 | 26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | 27 | */ |
28 | 28 | #pragma once |
| 29 | + |
29 | 30 | #ifndef PICOJSON_USE_INT64 |
30 | 31 | #define PICOJSON_USE_INT64 |
31 | 32 | #define __STDC_FORMAT_MACROS 1 |
32 | 33 | #endif |
33 | 34 |
|
| 35 | +// If PICOJSON_USE_ORDERED_OBJECT is set, picojson uses ordered dict for objects. |
| 36 | +// When iterating the object, the order of keys is the order they appear in the json string. |
| 37 | +// This macro is set by default. |
| 38 | +#ifndef PICOJSON_USE_ORDERED_OBJECT |
| 39 | +#define PICOJSON_USE_ORDERED_OBJECT 1 |
| 40 | +#endif |
| 41 | + |
34 | 42 | #include <algorithm> |
| 43 | +#include <cassert> |
35 | 44 | #include <cstddef> |
36 | 45 | #include <cstdio> |
37 | 46 | #include <cstdlib> |
@@ -137,10 +146,177 @@ enum { INDENT_WIDTH = 2 }; |
137 | 146 |
|
138 | 147 | struct null {}; |
139 | 148 |
|
| 149 | +// The ordered version of hashmap. When iterating through the hashmap, |
| 150 | +// the elements maintain the order in which they were inserted. |
| 151 | +// Its API is the same as std::unordered_map. |
| 152 | +template <typename Key, typename T> |
| 153 | +class ordered_hashmap : private std::unordered_map<Key, T> { |
| 154 | + public: |
| 155 | + using value_type = std::pair<const Key, T>; |
| 156 | + |
| 157 | + private: |
| 158 | + template <bool IsConst> |
| 159 | + struct iterator_base { |
| 160 | + public: |
| 161 | + using pointer = std::conditional_t<IsConst, const value_type*, value_type*>; |
| 162 | + using reference = std::conditional_t<IsConst, const value_type&, value_type&>; |
| 163 | + |
| 164 | + iterator_base(const iterator_base<IsConst>& other) |
| 165 | + : order_index(other.order_index), obj_ptr(other.obj_ptr) {} |
| 166 | + |
| 167 | + template <bool _IsConst = IsConst, typename = std::enable_if_t<_IsConst>> |
| 168 | + iterator_base(const iterator_base<false>& other) |
| 169 | + : order_index(other.order_index), obj_ptr(other.obj_ptr) { |
| 170 | + static_assert(_IsConst, "This constructor should only be used for const iterators."); |
| 171 | + } |
| 172 | + |
| 173 | + iterator_base<IsConst>& operator++() { |
| 174 | + ++order_index; |
| 175 | + return *this; |
| 176 | + } |
| 177 | + iterator_base<IsConst> operator++(int) { |
| 178 | + auto tmp = *this; |
| 179 | + ++order_index; |
| 180 | + return tmp; |
| 181 | + } |
| 182 | + pointer operator->() const { |
| 183 | + assert(order_index >= 0 && order_index < obj_ptr->order.size()); |
| 184 | + return obj_ptr->std::unordered_map<Key, T>::find(obj_ptr->order[order_index]).operator->(); |
| 185 | + } |
| 186 | + reference operator*() const { return *operator->(); } |
| 187 | + bool operator==(const iterator_base<IsConst>& other) const { |
| 188 | + return order_index == other.order_index && obj_ptr == other.obj_ptr; |
| 189 | + } |
| 190 | + bool operator!=(const iterator_base<IsConst>& other) const { return !(*this == other); } |
| 191 | + |
| 192 | + friend class ordered_hashmap; |
| 193 | + |
| 194 | + private: |
| 195 | + using obj_pointer_type = std::conditional_t<IsConst, const ordered_hashmap*, ordered_hashmap*>; |
| 196 | + iterator_base(int order_index, obj_pointer_type obj_ptr) |
| 197 | + : order_index(order_index), obj_ptr(obj_ptr) {} |
| 198 | + |
| 199 | + int order_index; |
| 200 | + obj_pointer_type obj_ptr; |
| 201 | + }; |
| 202 | + |
| 203 | + public: |
| 204 | + using iterator = iterator_base<false>; |
| 205 | + using const_iterator = iterator_base<true>; |
| 206 | + |
| 207 | + ordered_hashmap() = default; |
| 208 | + ordered_hashmap(const ordered_hashmap&) = default; |
| 209 | + ordered_hashmap(ordered_hashmap&&) = default; |
| 210 | + ordered_hashmap(std::initializer_list<value_type> init) : std::unordered_map<Key, T>(init) { |
| 211 | + for (const auto& pair : init) { |
| 212 | + order.push_back(pair.first); |
| 213 | + } |
| 214 | + } |
| 215 | + ordered_hashmap& operator=(const ordered_hashmap&) = default; |
| 216 | + ordered_hashmap& operator=(ordered_hashmap&&) = default; |
| 217 | + |
| 218 | + iterator begin() { return {0, this}; } |
| 219 | + iterator end() { return {static_cast<int>(order.size()), this}; } |
| 220 | + const_iterator begin() const { return {0, this}; } |
| 221 | + const_iterator end() const { return {static_cast<int>(order.size()), this}; } |
| 222 | + const_iterator cbegin() const { return {0, this}; } |
| 223 | + const_iterator cend() const { return {static_cast<int>(order.size()), this}; } |
| 224 | + |
| 225 | + using std::unordered_map<Key, T>::empty; |
| 226 | + using std::unordered_map<Key, T>::size; |
| 227 | + using std::unordered_map<Key, T>::at; |
| 228 | + |
| 229 | + T& operator[](const Key& key) { |
| 230 | + if (count(key) == 0) { |
| 231 | + order.push_back(key); |
| 232 | + } |
| 233 | + return std::unordered_map<Key, T>::operator[](key); |
| 234 | + } |
| 235 | + |
| 236 | + using std::unordered_map<Key, T>::count; |
| 237 | + |
| 238 | + iterator find(const Key& key) { |
| 239 | + auto it = std::find(order.begin(), order.end(), key); |
| 240 | + if (it == order.end()) { |
| 241 | + return end(); |
| 242 | + } |
| 243 | + return {static_cast<int>(std::distance(order.begin(), it)), this}; |
| 244 | + } |
| 245 | + |
| 246 | + const_iterator find(const Key& key) const { |
| 247 | + auto it = std::find(order.begin(), order.end(), key); |
| 248 | + if (it == order.end()) { |
| 249 | + return end(); |
| 250 | + } |
| 251 | + return {static_cast<int>(std::distance(order.begin(), it)), this}; |
| 252 | + } |
| 253 | + |
| 254 | + void clear() { |
| 255 | + std::unordered_map<Key, T>::clear(); |
| 256 | + order.clear(); |
| 257 | + } |
| 258 | + |
| 259 | + std::pair<iterator, bool> insert(const value_type& value) { |
| 260 | + if (count(value.first)) { |
| 261 | + return {find(value.first), false}; |
| 262 | + } |
| 263 | + order.push_back(value.first); |
| 264 | + std::unordered_map<Key, T>::insert(value); |
| 265 | + return {{static_cast<int>(order.size()) - 1, this}, true}; |
| 266 | + } |
| 267 | + |
| 268 | + template <class... Args> |
| 269 | + std::pair<iterator, bool> emplace(Args&&... args) { |
| 270 | + return insert(value_type(std::forward<Args>(args)...)); |
| 271 | + } |
| 272 | + |
| 273 | + iterator erase(const_iterator pos) { |
| 274 | + assert(pos.order_index >= 0 && pos.order_index < order.size()); |
| 275 | + std::unordered_map<Key, T>::erase(order[pos.order_index]); |
| 276 | + order.erase(order.begin() + pos.order_index); |
| 277 | + return {pos.order_index, this}; |
| 278 | + } |
| 279 | + |
| 280 | + iterator erase(iterator pos) { |
| 281 | + assert(pos.order_index >= 0 && pos.order_index < order.size()); |
| 282 | + std::unordered_map<Key, T>::erase(order[pos.order_index]); |
| 283 | + order.erase(order.begin() + pos.order_index); |
| 284 | + return pos; |
| 285 | + } |
| 286 | + |
| 287 | + size_t erase(const Key& key) { |
| 288 | + if (std::unordered_map<Key, T>::erase(key)) { |
| 289 | + order.erase(std::find(order.begin(), order.end(), key)); |
| 290 | + return 1; |
| 291 | + } else { |
| 292 | + return 0; |
| 293 | + } |
| 294 | + } |
| 295 | + |
| 296 | + template <typename _Key, typename _T> |
| 297 | + friend bool operator==(const ordered_hashmap<_Key, _T>& lhs, |
| 298 | + const ordered_hashmap<_Key, _T>& rhs); |
| 299 | + |
| 300 | + private: |
| 301 | + std::vector<Key> order; |
| 302 | +}; |
| 303 | + |
| 304 | +template <typename Key, typename T> |
| 305 | +bool operator==(const ordered_hashmap<Key, T>& lhs, const ordered_hashmap<Key, T>& rhs) { |
| 306 | + return static_cast<const std::unordered_map<Key, T>&>(lhs) == |
| 307 | + static_cast<const std::unordered_map<Key, T>&>(rhs) && |
| 308 | + lhs.order == rhs.order; |
| 309 | +} |
| 310 | + |
140 | 311 | class value { |
141 | 312 | public: |
142 | 313 | typedef std::vector<value> array; |
| 314 | +#ifdef PICOJSON_USE_ORDERED_OBJECT |
| 315 | + typedef ordered_hashmap<std::string, value> object; |
| 316 | +#else |
143 | 317 | typedef std::unordered_map<std::string, value> object; |
| 318 | +#endif |
| 319 | + |
144 | 320 | union _storage { |
145 | 321 | bool boolean_; |
146 | 322 | double number_; |
|
0 commit comments