12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181 |
- // Copyright (c) 2018-2020 configor - Nomango
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // is the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included is
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- #pragma once
- #include "configor_iterator.hpp"
- #include <algorithm> // std::for_each, std::all_of
- #include <cmath> // std::fabs
- #include <limits> // std::numeric_limits
- #include <memory> // std::allocator_traits
- #include <sstream> // std::stringstream
- #include <type_traits> // std::enable_if, std::is_same, std::is_integral, std::is_floating_point
- #include <utility> // std::swap, std::forward, std::declval
- namespace configor
- {
- namespace detail
- {
- template <typename _ValTy>
- class value_constructor;
- } // namespace detail
- template <typename _Args>
- class basic_value final : public value_constant
- {
- friend detail::value_constructor<basic_value>;
- public:
- template <typename _Ty>
- using allocator_type = typename _Args::template allocator_type<_Ty>;
- using boolean_type = typename _Args::boolean_type;
- using integer_type = typename _Args::integer_type;
- using float_type = typename _Args::float_type;
- using char_type = typename _Args::char_type;
- using string_type =
- typename _Args::template string_type<char_type, std::char_traits<char_type>, allocator_type<char_type>>;
- using array_type = typename _Args::template array_type<basic_value, allocator_type<basic_value>>;
- using object_type = typename _Args::template object_type<string_type, basic_value, std::less<string_type>,
- allocator_type<std::pair<const string_type, basic_value>>>;
- template <typename _Ty>
- using binder_type = typename _Args::template binder_type<_Ty>;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using iterator = detail::iterator<basic_value>;
- using const_iterator = detail::iterator<const basic_value>;
- using reverse_iterator = detail::reverse_iterator<iterator>;
- using const_reverse_iterator = detail::reverse_iterator<const_iterator>;
- union data_type
- {
- boolean_type boolean;
- integer_type integer;
- float_type floating;
- string_type* string;
- object_type* object;
- array_type* vector;
- };
- basic_value(std::nullptr_t = nullptr)
- : type_{ value_constant::null }
- , data_{}
- {
- }
- basic_value(const value_constant::type t)
- : type_{ t }
- , data_{}
- {
- using accessor = detail::value_constructor<basic_value>;
- switch (t)
- {
- case value_constant::object:
- accessor::template construct<value_constant::object>(*this);
- break;
- case value_constant::array:
- accessor::template construct<value_constant::array>(*this);
- break;
- case value_constant::string:
- accessor::template construct<value_constant::string>(*this);
- break;
- case value_constant::integer:
- accessor::template construct<value_constant::integer>(*this, integer_type(0));
- break;
- case value_constant::floating:
- accessor::template construct<value_constant::floating>(*this, float_type(0.0));
- break;
- case value_constant::boolean:
- accessor::template construct<value_constant::boolean>(*this, boolean_type(false));
- break;
- default:
- break;
- }
- }
- basic_value(const basic_value& other)
- : type_{ other.type() }
- , data_{}
- {
- using accessor = detail::value_constructor<basic_value>;
- switch (other.type())
- {
- case value_constant::object:
- accessor::template construct<value_constant::object>(*this, *other.data().object);
- break;
- case value_constant::array:
- accessor::template construct<value_constant::array>(*this, *other.data().vector);
- break;
- case value_constant::string:
- accessor::template construct<value_constant::string>(*this, *other.data().string);
- break;
- case value_constant::integer:
- accessor::template construct<value_constant::integer>(*this, other.data().integer);
- break;
- case value_constant::floating:
- accessor::template construct<value_constant::floating>(*this, other.data().floating);
- break;
- case value_constant::boolean:
- accessor::template construct<value_constant::boolean>(*this, other.data().boolean);
- break;
- default:
- break;
- }
- }
- basic_value(basic_value&& other) noexcept
- : type_{ other.type() }
- , data_{ other.data() }
- {
- other.type(value_constant::null);
- other.data().object = nullptr;
- }
- template <typename _CompatibleTy, typename _UTy = typename detail::remove_cvref<_CompatibleTy>::type,
- typename std::enable_if<!is_value<_UTy>::value && detail::has_to_value<basic_value, _UTy>::value,
- int>::type = 0>
- basic_value(_CompatibleTy&& value)
- : type_{ value_constant::null }
- , data_{}
- {
- binder_type<_UTy>::to_value(*this, std::forward<_CompatibleTy>(value));
- }
- ~basic_value()
- {
- using accessor = detail::value_constructor<basic_value>;
- accessor::destroy(*this);
- }
- const data_type& data() const
- {
- return data_;
- }
- data_type& data()
- {
- return data_;
- }
- inline value_constant::type type() const
- {
- return type_;
- }
- private:
- inline void type(value_constant::type t)
- {
- type_ = t;
- }
- public:
- inline bool is_object() const
- {
- return type() == value_constant::object;
- }
- inline bool is_array() const
- {
- return type() == value_constant::array;
- }
- inline bool is_string() const
- {
- return type() == value_constant::string;
- }
- inline bool is_bool() const
- {
- return type() == value_constant::boolean;
- }
- inline bool is_integer() const
- {
- return type() == value_constant::integer;
- }
- inline bool is_floating() const
- {
- return type() == value_constant::floating;
- }
- inline bool is_number() const
- {
- return is_integer() || is_floating();
- }
- inline bool is_null() const
- {
- return type() == value_constant::null;
- }
- public:
- inline iterator begin()
- {
- iterator iter(this);
- iter.set_begin();
- return iter;
- }
- inline const_iterator begin() const
- {
- return cbegin();
- }
- inline const_iterator cbegin() const
- {
- const_iterator iter(this);
- iter.set_begin();
- return iter;
- }
- inline iterator end()
- {
- iterator iter(this);
- iter.set_end();
- return iter;
- }
- inline const_iterator end() const
- {
- return cend();
- }
- inline const_iterator cend() const
- {
- const_iterator iter(this);
- iter.set_end();
- return iter;
- }
- inline reverse_iterator rbegin()
- {
- return reverse_iterator(end());
- }
- inline const_reverse_iterator rbegin() const
- {
- return const_reverse_iterator(end());
- }
- inline const_reverse_iterator crbegin() const
- {
- return rbegin();
- }
- inline reverse_iterator rend()
- {
- return reverse_iterator(begin());
- }
- inline const_reverse_iterator rend() const
- {
- return const_reverse_iterator(begin());
- }
- inline const_reverse_iterator crend() const
- {
- return rend();
- }
- public:
- inline size_type size() const
- {
- switch (type())
- {
- case value_constant::null:
- return 0;
- case value_constant::array:
- return data().vector->size();
- case value_constant::object:
- return data().object->size();
- default:
- return 1;
- }
- }
- bool empty() const
- {
- if (is_null())
- return true;
- if (is_object())
- return data().object->empty();
- if (is_array())
- return data().vector->empty();
- return false;
- }
- iterator find(const typename object_type::key_type& key)
- {
- if (is_object())
- {
- iterator iter(this);
- iter.object_it_ = data().object->find(key);
- return iter;
- }
- return end();
- }
- const_iterator find(const typename object_type::key_type& key) const
- {
- if (is_object())
- {
- const_iterator iter(this);
- iter.object_it_ = data().object->find(key);
- return iter;
- }
- return cend();
- }
- inline size_type count(const typename object_type::key_type& key) const
- {
- return is_object() ? data().object->count(key) : 0;
- }
- size_type erase(const typename object_type::key_type& key)
- {
- if (!is_object())
- {
- throw configor_invalid_key("cannot use erase() with non-object value");
- }
- return data().object->erase(key);
- }
- void erase(const size_type index)
- {
- if (!is_array())
- {
- throw configor_invalid_key("cannot use erase() with non-array value");
- }
- data().vector->erase(data().vector->begin() + static_cast<difference_type>(index));
- }
- template <class _IterTy, typename = typename std::enable_if<std::is_same<_IterTy, iterator>::value
- || std::is_same<_IterTy, const_iterator>::value>::type>
- _IterTy erase(_IterTy pos)
- {
- _IterTy result = end();
- switch (type())
- {
- case value_constant::object:
- {
- result.object_it_ = data().object->erase(pos.object_it_);
- break;
- }
- case value_constant::array:
- {
- result.array_it_ = data().vector->erase(pos.array_it_);
- break;
- }
- default:
- throw configor_invalid_iterator("cannot use erase() with non-object & non-array value");
- }
- return result;
- }
- template <class _IterTy, typename = typename std::enable_if<std::is_same<_IterTy, iterator>::value
- || std::is_same<_IterTy, const_iterator>::value>::type>
- _IterTy erase(_IterTy first, _IterTy last)
- {
- _IterTy result = end();
- switch (type())
- {
- case value_constant::object:
- {
- result.object_it_ = data().object->erase(first.object_it_, last.object_it_);
- break;
- }
- case value_constant::array:
- {
- result.array_it_ = data().vector->erase(first.array_it_, last.array_it_);
- break;
- }
- default:
- throw configor_invalid_iterator("cannot use erase() with non-object & non-array value");
- }
- return result;
- }
- void push_back(const basic_value& v)
- {
- emplace_back(v);
- }
- void push_back(basic_value&& v)
- {
- emplace_back(std::move(v));
- }
- template <typename... _Ty>
- void emplace_back(_Ty&&... v)
- {
- if (!is_null() && !is_array())
- {
- throw configor_type_error("use push_back() or emplace_back() with non-array value");
- }
- if (is_null())
- {
- *this = value_constant::array;
- }
- data().vector->emplace_back(std::forward<_Ty>(v)...);
- }
- void clear()
- {
- switch (type())
- {
- case value_constant::integer:
- data().integer = 0;
- break;
- case value_constant::floating:
- data().floating = static_cast<float_type>(0.0);
- break;
- case value_constant::boolean:
- data().boolean = false;
- break;
- case value_constant::string:
- data().string->clear();
- break;
- case value_constant::array:
- data().vector->clear();
- break;
- case value_constant::object:
- data().object->clear();
- break;
- default:
- break;
- }
- }
- private:
- // get pointer value
- inline boolean_type* do_get_ptr(boolean_type*) noexcept
- {
- return is_bool() ? &data().boolean : nullptr;
- }
- inline const boolean_type* do_get_ptr(const boolean_type*) const noexcept
- {
- return is_bool() ? &data().boolean : nullptr;
- }
- inline integer_type* do_get_ptr(integer_type*) noexcept
- {
- return is_integer() ? &data().integer : nullptr;
- }
- inline const integer_type* do_get_ptr(const integer_type*) const noexcept
- {
- return is_integer() ? &data().integer : nullptr;
- }
- inline float_type* do_get_ptr(float_type*) noexcept
- {
- return is_floating() ? &data().floating : nullptr;
- }
- inline const float_type* do_get_ptr(const float_type*) const noexcept
- {
- return is_floating() ? &data().floating : nullptr;
- }
- inline string_type* do_get_ptr(string_type*) noexcept
- {
- return is_string() ? data().string : nullptr;
- }
- inline const string_type* do_get_ptr(const string_type*) const noexcept
- {
- return is_string() ? data().string : nullptr;
- }
- inline array_type* do_get_ptr(array_type*) noexcept
- {
- return is_array() ? data().vector : nullptr;
- }
- inline const array_type* do_get_ptr(const array_type*) const noexcept
- {
- return is_array() ? data().vector : nullptr;
- }
- inline object_type* do_get_ptr(object_type*) noexcept
- {
- return is_object() ? data().object : nullptr;
- }
- inline const object_type* do_get_ptr(const object_type*) const noexcept
- {
- return is_object() ? data().object : nullptr;
- }
- public:
- // get_ptr
- template <typename _Ty, typename = typename std::enable_if<std::is_pointer<_Ty>::value>::type>
- auto get_ptr() const -> decltype(std::declval<const basic_value&>().do_get_ptr(std::declval<_Ty>()))
- {
- return do_get_ptr(static_cast<_Ty>(nullptr));
- }
- template <typename _Ty, typename = typename std::enable_if<std::is_pointer<_Ty>::value>::type>
- auto get_ptr() -> decltype(std::declval<basic_value&>().do_get_ptr(std::declval<_Ty>()))
- {
- return do_get_ptr(static_cast<_Ty>(nullptr));
- }
- private:
- // get reference value
- template <typename _RefTy, typename _ValTy, typename _PtrTy = typename std::add_pointer<_RefTy>::type>
- static auto do_get_ref(_ValTy& c) -> decltype(c.template get_ptr<_PtrTy>(), std::declval<_RefTy>())
- {
- auto* ptr = c.template get_ptr<_PtrTy>();
- if (ptr != nullptr)
- {
- return *ptr;
- }
- throw configor_type_error(std::string("incompatible reference type for get, actual type is ")
- + to_string(c.type()));
- }
- // get value
- template <typename _Ty, typename = typename std::enable_if<std::is_same<basic_value, _Ty>::value>::type>
- _Ty do_get(detail::priority<3>) const
- {
- return *this;
- }
- template <typename _Ty, typename = typename std::enable_if<std::is_pointer<_Ty>::value>::type>
- auto do_get(detail::priority<2>) const noexcept
- -> decltype(std::declval<const basic_value&>().do_get_ptr(std::declval<_Ty>()))
- {
- return do_get_ptr(static_cast<_Ty>(nullptr));
- }
- template <typename _Ty,
- typename = typename std::enable_if<detail::has_non_default_from_value<basic_value, _Ty>::value>::type>
- _Ty do_get(detail::priority<1>) const
- {
- return binder_type<_Ty>::from_value(*this);
- }
- template <typename _Ty,
- typename = typename std::enable_if<std::is_default_constructible<_Ty>::value
- && detail::has_from_value<basic_value, _Ty>::value>::type>
- _Ty do_get(detail::priority<0>) const
- {
- _Ty value{};
- binder_type<_Ty>::from_value(*this, value);
- return value;
- }
- // get value by reference
- template <typename _Ty, typename = typename std::enable_if<std::is_same<basic_value, _Ty>::value>::type>
- _Ty& do_get(_Ty& value, detail::priority<3>) const
- {
- return (value = *this);
- }
- template <typename _Ty, typename = typename std::enable_if<std::is_pointer<_Ty>::value>::type>
- auto do_get(_Ty& value, detail::priority<2>) const noexcept
- -> decltype(std::declval<const basic_value&>().do_get_ptr(std::declval<_Ty>()))
- {
- return (value = do_get_ptr(static_cast<_Ty>(nullptr)));
- }
- template <typename _Ty, typename = typename std::enable_if<detail::has_from_value<basic_value, _Ty>::value>::type>
- _Ty& do_get(_Ty& value, detail::priority<1>) const
- {
- binder_type<_Ty>::from_value(*this, value);
- return value;
- }
- template <typename _Ty,
- typename = typename std::enable_if<detail::has_non_default_from_value<basic_value, _Ty>::value>::type>
- _Ty& do_get(_Ty& value, detail::priority<0>) const
- {
- value = binder_type<_Ty>::from_value(*this);
- return value;
- }
- public:
- // get
- template <typename _Ty, typename _UTy = typename detail::remove_cvref<_Ty>::type,
- typename = typename std::enable_if<!std::is_reference<_Ty>::value>::type>
- auto get() const -> decltype(std::declval<const basic_value&>().template do_get<_UTy>(detail::priority<3>{}))
- {
- return do_get<_UTy>(detail::priority<3>{});
- }
- template <typename _Ty, typename = typename std::enable_if<std::is_pointer<_Ty>::value>::type>
- auto get() -> decltype(std::declval<basic_value&>().template get_ptr<_Ty>())
- {
- return get_ptr<_Ty>();
- }
- template <typename _Ty, typename std::enable_if<std::is_reference<_Ty>::value, int>::type = 0>
- auto get() -> decltype(basic_value::template do_get_ref<_Ty>(std::declval<basic_value&>()))
- {
- return do_get_ref<_Ty>(*this);
- }
- template <typename _Ty,
- typename std::enable_if<std::is_reference<_Ty>::value
- && std::is_const<typename std::remove_reference<_Ty>::type>::value,
- int>::type = 0>
- auto get() const -> decltype(basic_value::template do_get_ref<_Ty>(std::declval<const basic_value&>()))
- {
- return do_get_ref<_Ty>(*this);
- }
- template <typename _Ty>
- auto get(_Ty& value) const
- -> decltype(std::declval<const basic_value&>().template do_get<_Ty>(std::declval<_Ty&>(),
- detail::priority<3>{}),
- bool{})
- {
- try
- {
- do_get<_Ty>(value, detail::priority<3>{});
- return true;
- }
- catch (...)
- {
- }
- return false;
- }
- template <typename _Ty, typename = typename std::enable_if<detail::is_value_getable<basic_value, _Ty>::value
- && !std::is_pointer<_Ty>::value
- && !std::is_reference<_Ty>::value>::type>
- inline operator _Ty() const
- {
- return get<_Ty>();
- }
- public:
- // swap function
- inline void swap(basic_value& rhs)
- {
- std::swap(type_, rhs.type_);
- std::swap(data_, rhs.data_);
- }
- // operator= functions
- basic_value& operator=(const basic_value& rhs)
- {
- if (this != &rhs)
- {
- basic_value tmp{ rhs };
- this->swap(tmp);
- }
- return *this;
- }
- basic_value& operator=(basic_value&& rhs)
- {
- if (this != &rhs)
- {
- basic_value old{ std::move(*this) };
- this->swap(rhs);
- }
- return *this;
- }
- // operator[] functions
- basic_value& operator[](const size_type index)
- {
- if (is_null())
- {
- *this = value_constant::array;
- }
- if (!is_array())
- {
- throw configor_invalid_key("operator[] called on a non-array object");
- }
- if (index >= data().vector->size())
- {
- data().vector->insert(data().vector->end(), index - data().vector->size() + 1, basic_value());
- }
- return (*data().vector)[index];
- }
- inline basic_value& operator[](const size_type index) const
- {
- return at(index);
- }
- basic_value& operator[](const typename object_type::key_type& key)
- {
- if (is_null())
- {
- *this = value_constant::object;
- }
- if (!is_object())
- {
- throw configor_invalid_key("operator[] called on a non-object type");
- }
- return (*data().object)[key];
- }
- inline basic_value& operator[](const typename object_type::key_type& key) const
- {
- return at(key);
- }
- basic_value& at(const size_type index) const
- {
- if (!is_array())
- {
- throw configor_invalid_key("operator[] called on a non-array type");
- }
- if (index >= data().vector->size())
- {
- throw std::out_of_range("operator[] index out of range");
- }
- return (*data().vector)[index];
- }
- template <typename _CharTy>
- basic_value& operator[](_CharTy* key)
- {
- if (is_null())
- {
- *this = value_constant::object;
- }
- if (!is_object())
- {
- throw configor_invalid_key("operator[] called on a non-object object");
- }
- return (*data().object)[key];
- }
- template <typename _CharTy>
- inline basic_value& operator[](_CharTy* key) const
- {
- return at(key);
- }
- basic_value& at(const typename object_type::key_type& key) const
- {
- if (!is_object())
- {
- throw configor_invalid_key("operator[] called on a non-object object");
- }
- auto iter = data().object->find(key);
- if (iter == data().object->end())
- {
- throw std::out_of_range("operator[] key out of range");
- }
- return iter->second;
- }
- template <typename _CharTy>
- basic_value& at(_CharTy* key) const
- {
- if (!is_object())
- {
- throw configor_invalid_key("operator[] called on a non-object object");
- }
- auto iter = data().object->find(key);
- if (iter == data().object->end())
- {
- throw std::out_of_range("operator[] key out of range");
- }
- return iter->second;
- }
- public:
- // eq functions
- friend bool operator==(const basic_value& lhs, const basic_value& rhs)
- {
- if (lhs.type() == rhs.type())
- {
- switch (lhs.type())
- {
- case value_constant::array:
- return (*lhs.data().vector == *rhs.data().vector);
- case value_constant::object:
- return (*lhs.data().object == *rhs.data().object);
- case value_constant::null:
- return true;
- case value_constant::string:
- return *lhs.data().string == *rhs.data().string;
- case value_constant::boolean:
- return lhs.data().boolean == rhs.data().boolean;
- case value_constant::integer:
- return lhs.data().integer == rhs.data().integer;
- case value_constant::floating:
- return lhs.data().floating == rhs.data().floating;
- default:
- return false;
- }
- }
- else if (lhs.type() == value_constant::integer && rhs.type() == value_constant::floating)
- {
- return static_cast<float_type>(lhs.data().integer) == rhs.data().floating;
- }
- else if (lhs.type() == value_constant::floating && rhs.type() == value_constant::integer)
- {
- return lhs.data().floating == static_cast<float_type>(rhs.data().integer);
- }
- return false;
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator==(const basic_value& lhs, _ScalarTy rhs)
- {
- return lhs == basic_value(rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator==(_ScalarTy lhs, const basic_value& rhs)
- {
- return basic_value(lhs) == rhs;
- }
- // ne functions
- friend inline bool operator!=(const basic_value& lhs, const basic_value& rhs)
- {
- return !(lhs == rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator!=(const basic_value& lhs, _ScalarTy rhs)
- {
- return lhs != basic_value(rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator!=(_ScalarTy lhs, const basic_value& rhs)
- {
- return basic_value(lhs) != rhs;
- }
- // lt functions
- friend bool operator<(const basic_value& lhs, const basic_value& rhs)
- {
- const auto lhs_type = lhs.type();
- const auto rhs_type = rhs.type();
- if (lhs_type == rhs_type)
- {
- switch (lhs_type)
- {
- case value_constant::array:
- return (*lhs.data().vector) < (*rhs.data().vector);
- case value_constant::object:
- return (*lhs.data().object) < (*rhs.data().object);
- case value_constant::null:
- return false;
- case value_constant::string:
- return (*lhs.data().string) < (*rhs.data().string);
- case value_constant::boolean:
- return (lhs.data().boolean < rhs.data().boolean);
- case value_constant::integer:
- return (lhs.data().integer < rhs.data().integer);
- case value_constant::floating:
- return (lhs.data().floating < rhs.data().floating);
- default:
- return false;
- }
- }
- else if (lhs_type == value_constant::integer && rhs_type == value_constant::floating)
- {
- return (static_cast<float_type>(lhs.data().integer) < rhs.data().floating);
- }
- else if (lhs_type == value_constant::floating && rhs_type == value_constant::integer)
- {
- return (lhs.data().floating < static_cast<float_type>(rhs.data().integer));
- }
- return false;
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator<(const basic_value& lhs, _ScalarTy rhs)
- {
- return lhs < basic_value(rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator<(_ScalarTy lhs, const basic_value& rhs)
- {
- return basic_value(lhs) < rhs;
- }
- // lte functions
- friend inline bool operator<=(const basic_value& lhs, const basic_value& rhs)
- {
- return !(rhs < lhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator<=(const basic_value& lhs, _ScalarTy rhs)
- {
- return lhs <= basic_value(rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator<=(_ScalarTy lhs, const basic_value& rhs)
- {
- return basic_value(lhs) <= rhs;
- }
- // gt functions
- friend inline bool operator>(const basic_value& lhs, const basic_value& rhs)
- {
- return rhs < lhs;
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator>(const basic_value& lhs, _ScalarTy rhs)
- {
- return lhs > basic_value(rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator>(_ScalarTy lhs, const basic_value& rhs)
- {
- return basic_value(lhs) > rhs;
- }
- // gte functions
- friend inline bool operator>=(const basic_value& lhs, const basic_value& rhs)
- {
- return !(lhs < rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator>=(const basic_value& lhs, _ScalarTy rhs)
- {
- return lhs >= basic_value(rhs);
- }
- template <typename _ScalarTy, typename = typename std::enable_if<std::is_scalar<_ScalarTy>::value>::type>
- friend inline bool operator>=(_ScalarTy lhs, const basic_value& rhs)
- {
- return basic_value(lhs) >= rhs;
- }
- private:
- value_constant::type type_;
- data_type data_;
- };
- namespace detail
- {
- template <typename _ValTy>
- class value_constructor
- {
- public:
- using value_type = _ValTy;
- template <typename _Ty>
- using allocator_type = typename value_type::template allocator_type<_Ty>;
- template <value_constant::type _Ty>
- using type_constant = std::integral_constant<value_constant::type, _Ty>;
- template <value_constant::type _Ty, typename... _Args>
- static void reset(value_type& v, _Args&&... args)
- {
- destroy(v);
- v.type(_Ty);
- construct<_Ty>(v, std::forward<_Args>(args)...);
- }
- template <value_constant::type _Ty, typename... _Args>
- static inline void construct(value_type& v, _Args&&... args)
- {
- construct(type_constant<_Ty>{}, v, std::forward<_Args>(args)...);
- }
- static void destroy(value_type& v)
- {
- switch (v.type())
- {
- case value_constant::object:
- destroy<typename value_type::object_type>(v.data().object);
- break;
- case value_constant::array:
- destroy<typename value_type::array_type>(v.data().vector);
- break;
- case value_constant::string:
- destroy<typename value_type::string_type>(v.data().string);
- break;
- default:
- break;
- }
- }
- private:
- template <typename... _Args>
- static inline void construct(type_constant<value_constant::object>, value_type& v, _Args&&... args)
- {
- v.data().object = create_data<typename value_type::object_type>(std::forward<_Args>(args)...);
- }
- template <typename... _Args>
- static inline void construct(type_constant<value_constant::array>, value_type& v, _Args&&... args)
- {
- v.data().vector = create_data<typename value_type::array_type>(std::forward<_Args>(args)...);
- }
- template <typename... _Args>
- static inline void construct(type_constant<value_constant::string>, value_type& v, _Args&&... args)
- {
- v.data().string = create_data<typename value_type::string_type>(std::forward<_Args>(args)...);
- }
- template <typename... _Args>
- static inline void construct(type_constant<value_constant::integer>, value_type& v, _Args&&... args)
- {
- v.data().integer = typename value_type::integer_type{ std::forward<_Args>(args)... };
- }
- template <typename... _Args>
- static inline void construct(type_constant<value_constant::floating>, value_type& v, _Args&&... args)
- {
- v.data().floating = typename value_type::float_type{ std::forward<_Args>(args)... };
- }
- template <typename... _Args>
- static inline void construct(type_constant<value_constant::boolean>, value_type& v, _Args&&... args)
- {
- v.data().boolean = typename value_type::boolean_type{ std::forward<_Args>(args)... };
- }
- template <typename... _Args>
- static inline void construct(type_constant<value_constant::null>, value_type& v, _Args&&... args)
- {
- ((void)v);
- }
- template <typename _Ty, typename... _Args>
- static _Ty* create_data(_Args&&... args)
- {
- using allocator_traits = std::allocator_traits<allocator_type<_Ty>>;
- static allocator_type<_Ty> allocator;
- auto ptr = allocator_traits::allocate(allocator, 1);
- allocator_traits::construct(allocator, ptr, std::forward<_Args>(args)...);
- return ptr;
- }
- template <typename _Ty>
- static void destroy(_Ty* ptr)
- {
- using allocator_traits = std::allocator_traits<allocator_type<_Ty>>;
- static allocator_type<_Ty> allocator;
- allocator_traits::destroy(allocator, ptr);
- allocator_traits::deallocate(allocator, ptr, 1);
- }
- };
- template <typename _ValTy>
- class value_maker
- {
- public:
- using value_type = _ValTy;
- struct object
- {
- using pair_type = std::pair<typename value_type::string_type, value_type>;
- object(std::initializer_list<pair_type> list)
- : list_(list)
- {
- }
- operator value_type() const
- {
- value_type v{ value_constant::object };
- std::for_each(list_.begin(), list_.end(),
- [&](const pair_type& pair) { v.data().object->emplace(pair.first, pair.second); });
- return v;
- }
- private:
- std::initializer_list<pair_type> list_;
- };
- struct array
- {
- array(std::initializer_list<value_type> list)
- : list_(list)
- {
- }
- operator value_type() const
- {
- value_type v{ value_constant::array };
- v.data().vector->reserve(list_.size());
- v.data().vector->assign(list_.begin(), list_.end());
- return v;
- }
- private:
- std::initializer_list<value_type> list_;
- };
- };
- } // namespace detail
- template <typename _ValTy>
- inline _ValTy make_object(std::initializer_list<std::pair<typename _ValTy::string_type, _ValTy>> list)
- {
- return typename detail::value_maker<_ValTy>::object{ list };
- }
- template <typename _ValTy>
- inline _ValTy make_array(std::initializer_list<_ValTy> list)
- {
- return typename detail::value_maker<_ValTy>::array{ list };
- }
- } // namespace configor
|