360 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			360 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //     __ _____ _____ _____
 | ||
|  | //  __|  |   __|     |   | |  JSON for Modern C++
 | ||
|  | // |  |  |__   |  |  | | | |  version 3.11.3
 | ||
|  | // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
 | ||
|  | //
 | ||
|  | // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
 | ||
|  | // SPDX-License-Identifier: MIT
 | ||
|  | 
 | ||
|  | #pragma once
 | ||
|  | 
 | ||
|  | #include <functional> // equal_to, less
 | ||
|  | #include <initializer_list> // initializer_list
 | ||
|  | #include <iterator> // input_iterator_tag, iterator_traits
 | ||
|  | #include <memory> // allocator
 | ||
|  | #include <stdexcept> // for out_of_range
 | ||
|  | #include <type_traits> // enable_if, is_convertible
 | ||
|  | #include <utility> // pair
 | ||
|  | #include <vector> // vector
 | ||
|  | 
 | ||
|  | #include <nlohmann/detail/macro_scope.hpp>
 | ||
|  | #include <nlohmann/detail/meta/type_traits.hpp>
 | ||
|  | 
 | ||
|  | NLOHMANN_JSON_NAMESPACE_BEGIN | ||
|  | 
 | ||
|  | /// ordered_map: a minimal map-like container that preserves insertion order
 | ||
|  | /// for use within nlohmann::basic_json<ordered_map>
 | ||
|  | template <class Key, class T, class IgnoredLess = std::less<Key>, | ||
|  |           class Allocator = std::allocator<std::pair<const Key, T>>> | ||
|  |                   struct ordered_map : std::vector<std::pair<const Key, T>, Allocator> | ||
|  | { | ||
|  |     using key_type = Key; | ||
|  |     using mapped_type = T; | ||
|  |     using Container = std::vector<std::pair<const Key, T>, Allocator>; | ||
|  |     using iterator = typename Container::iterator; | ||
|  |     using const_iterator = typename Container::const_iterator; | ||
|  |     using size_type = typename Container::size_type; | ||
|  |     using value_type = typename Container::value_type; | ||
|  | #ifdef JSON_HAS_CPP_14
 | ||
|  |     using key_compare = std::equal_to<>; | ||
|  | #else
 | ||
|  |     using key_compare = std::equal_to<Key>; | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     // Explicit constructors instead of `using Container::Container`
 | ||
|  |     // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
 | ||
|  |     ordered_map() noexcept(noexcept(Container())) : Container{} {} | ||
|  |     explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} | ||
|  |     template <class It> | ||
|  |     ordered_map(It first, It last, const Allocator& alloc = Allocator()) | ||
|  |         : Container{first, last, alloc} {} | ||
|  |     ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() ) | ||
|  |         : Container{init, alloc} {} | ||
|  | 
 | ||
|  |     std::pair<iterator, bool> emplace(const key_type& key, T&& t) | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return {it, false}; | ||
|  |             } | ||
|  |         } | ||
|  |         Container::emplace_back(key, std::forward<T>(t)); | ||
|  |         return {std::prev(this->end()), true}; | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     std::pair<iterator, bool> emplace(KeyType && key, T && t) | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return {it, false}; | ||
|  |             } | ||
|  |         } | ||
|  |         Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t)); | ||
|  |         return {std::prev(this->end()), true}; | ||
|  |     } | ||
|  | 
 | ||
|  |     T& operator[](const key_type& key) | ||
|  |     { | ||
|  |         return emplace(key, T{}).first->second; | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     T & operator[](KeyType && key) | ||
|  |     { | ||
|  |         return emplace(std::forward<KeyType>(key), T{}).first->second; | ||
|  |     } | ||
|  | 
 | ||
|  |     const T& operator[](const key_type& key) const | ||
|  |     { | ||
|  |         return at(key); | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     const T & operator[](KeyType && key) const | ||
|  |     { | ||
|  |         return at(std::forward<KeyType>(key)); | ||
|  |     } | ||
|  | 
 | ||
|  |     T& at(const key_type& key) | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return it->second; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         JSON_THROW(std::out_of_range("key not found")); | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
 | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return it->second; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         JSON_THROW(std::out_of_range("key not found")); | ||
|  |     } | ||
|  | 
 | ||
|  |     const T& at(const key_type& key) const | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return it->second; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         JSON_THROW(std::out_of_range("key not found")); | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
 | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return it->second; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         JSON_THROW(std::out_of_range("key not found")); | ||
|  |     } | ||
|  | 
 | ||
|  |     size_type erase(const key_type& key) | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 // Since we cannot move const Keys, re-construct them in place
 | ||
|  |                 for (auto next = it; ++next != this->end(); ++it) | ||
|  |                 { | ||
|  |                     it->~value_type(); // Destroy but keep allocation
 | ||
|  |                     new (&*it) value_type{std::move(*next)}; | ||
|  |                 } | ||
|  |                 Container::pop_back(); | ||
|  |                 return 1; | ||
|  |             } | ||
|  |         } | ||
|  |         return 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
 | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 // Since we cannot move const Keys, re-construct them in place
 | ||
|  |                 for (auto next = it; ++next != this->end(); ++it) | ||
|  |                 { | ||
|  |                     it->~value_type(); // Destroy but keep allocation
 | ||
|  |                     new (&*it) value_type{std::move(*next)}; | ||
|  |                 } | ||
|  |                 Container::pop_back(); | ||
|  |                 return 1; | ||
|  |             } | ||
|  |         } | ||
|  |         return 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     iterator erase(iterator pos) | ||
|  |     { | ||
|  |         return erase(pos, std::next(pos)); | ||
|  |     } | ||
|  | 
 | ||
|  |     iterator erase(iterator first, iterator last) | ||
|  |     { | ||
|  |         if (first == last) | ||
|  |         { | ||
|  |             return first; | ||
|  |         } | ||
|  | 
 | ||
|  |         const auto elements_affected = std::distance(first, last); | ||
|  |         const auto offset = std::distance(Container::begin(), first); | ||
|  | 
 | ||
|  |         // This is the start situation. We need to delete elements_affected
 | ||
|  |         // elements (3 in this example: e, f, g), and need to return an
 | ||
|  |         // iterator past the last deleted element (h in this example).
 | ||
|  |         // Note that offset is the distance from the start of the vector
 | ||
|  |         // to first. We will need this later.
 | ||
|  | 
 | ||
|  |         // [ a, b, c, d, e, f, g, h, i, j ]
 | ||
|  |         //               ^        ^
 | ||
|  |         //             first    last
 | ||
|  | 
 | ||
|  |         // Since we cannot move const Keys, we re-construct them in place.
 | ||
|  |         // We start at first and re-construct (viz. copy) the elements from
 | ||
|  |         // the back of the vector. Example for first iteration:
 | ||
|  | 
 | ||
|  |         //               ,--------.
 | ||
|  |         //               v        |   destroy e and re-construct with h
 | ||
|  |         // [ a, b, c, d, e, f, g, h, i, j ]
 | ||
|  |         //               ^        ^
 | ||
|  |         //               it       it + elements_affected
 | ||
|  | 
 | ||
|  |         for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) | ||
|  |         { | ||
|  |             it->~value_type(); // destroy but keep allocation
 | ||
|  |             new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
 | ||
|  |         } | ||
|  | 
 | ||
|  |         // [ a, b, c, d, h, i, j, h, i, j ]
 | ||
|  |         //               ^        ^
 | ||
|  |         //             first    last
 | ||
|  | 
 | ||
|  |         // remove the unneeded elements at the end of the vector
 | ||
|  |         Container::resize(this->size() - static_cast<size_type>(elements_affected)); | ||
|  | 
 | ||
|  |         // [ a, b, c, d, h, i, j ]
 | ||
|  |         //               ^        ^
 | ||
|  |         //             first    last
 | ||
|  | 
 | ||
|  |         // first is now pointing past the last deleted element, but we cannot
 | ||
|  |         // use this iterator, because it may have been invalidated by the
 | ||
|  |         // resize call. Instead, we can return begin() + offset.
 | ||
|  |         return Container::begin() + offset; | ||
|  |     } | ||
|  | 
 | ||
|  |     size_type count(const key_type& key) const | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return 1; | ||
|  |             } | ||
|  |         } | ||
|  |         return 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
 | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return 1; | ||
|  |             } | ||
|  |         } | ||
|  |         return 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     iterator find(const key_type& key) | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return it; | ||
|  |             } | ||
|  |         } | ||
|  |         return Container::end(); | ||
|  |     } | ||
|  | 
 | ||
|  |     template<class KeyType, detail::enable_if_t< | ||
|  |                  detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> | ||
|  |     iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
 | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return it; | ||
|  |             } | ||
|  |         } | ||
|  |         return Container::end(); | ||
|  |     } | ||
|  | 
 | ||
|  |     const_iterator find(const key_type& key) const | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, key)) | ||
|  |             { | ||
|  |                 return it; | ||
|  |             } | ||
|  |         } | ||
|  |         return Container::end(); | ||
|  |     } | ||
|  | 
 | ||
|  |     std::pair<iterator, bool> insert( value_type&& value ) | ||
|  |     { | ||
|  |         return emplace(value.first, std::move(value.second)); | ||
|  |     } | ||
|  | 
 | ||
|  |     std::pair<iterator, bool> insert( const value_type& value ) | ||
|  |     { | ||
|  |         for (auto it = this->begin(); it != this->end(); ++it) | ||
|  |         { | ||
|  |             if (m_compare(it->first, value.first)) | ||
|  |             { | ||
|  |                 return {it, false}; | ||
|  |             } | ||
|  |         } | ||
|  |         Container::push_back(value); | ||
|  |         return {--this->end(), true}; | ||
|  |     } | ||
|  | 
 | ||
|  |     template<typename InputIt> | ||
|  |     using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category, | ||
|  |             std::input_iterator_tag>::value>::type; | ||
|  | 
 | ||
|  |     template<typename InputIt, typename = require_input_iter<InputIt>> | ||
|  |     void insert(InputIt first, InputIt last) | ||
|  |     { | ||
|  |         for (auto it = first; it != last; ++it) | ||
|  |         { | ||
|  |             insert(*it); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | private: | ||
|  |     JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare(); | ||
|  | }; | ||
|  | 
 | ||
|  | NLOHMANN_JSON_NAMESPACE_END |