libcruft-util/json/tree.cpp

1074 lines
27 KiB
C++
Raw Normal View History

/*
2015-04-13 18:05:28 +10:00
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
2015-04-13 18:05:28 +10:00
* http://www.apache.org/licenses/LICENSE-2.0
2014-05-20 14:11:28 +10:00
*
2015-04-13 18:05:28 +10:00
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010-2018 Danny Robson <danny@nerdcruft.net>
*/
#include "tree.hpp"
#include "except.hpp"
#include "flat.hpp"
2016-04-05 11:06:01 +10:00
#include "../debug.hpp"
#include "../io.hpp"
#include "../iterator.hpp"
2016-04-05 11:06:01 +10:00
#include "../maths.hpp"
2017-01-05 20:21:20 +11:00
#include "../stream.hpp"
2011-05-23 17:18:52 +10:00
#include "preprocessor.hpp"
2011-05-23 17:18:52 +10:00
#include <algorithm>
#include <cstdlib>
#include <iomanip>
2011-05-23 17:18:52 +10:00
2017-01-05 20:21:20 +11:00
///////////////////////////////////////////////////////////////////////////////
using json::tree::node;
using json::tree::object;
using json::tree::array;
using json::tree::string;
using json::tree::number;
using json::tree::boolean;
using json::tree::null;
2011-05-23 17:18:52 +10:00
2015-08-28 20:36:21 +10:00
///////////////////////////////////////////////////////////////////////////////
namespace util {
bool
is_integer (const json::tree::number &node)
{
using R = json::tree::number::repr_t;
switch (node.repr ()) {
case R::REAL:
return is_integer (node.real ());
case R::SINT:
case R::UINT:
return true;
}
unreachable ();
}
//-----------------------------------------------------------------------------
bool
is_integer (const json::tree::node &node)
{
return node.is_number () && is_integer (node.as_number ());
}
}
2015-08-28 20:36:21 +10:00
///////////////////////////////////////////////////////////////////////////////
template <typename T>
static
typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
std::unique_ptr<json::tree::node> &output);
2011-05-23 17:18:52 +10:00
//-----------------------------------------------------------------------------
template <typename T>
static
typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
json::tree::array &parent)
{
for (auto cursor = first; cursor != last; ) {
if (cursor->tag == json::flat::type::ARRAY_END)
return cursor + 1;
std::unique_ptr<json::tree::node> value;
cursor = ::parse<T> (cursor, last, value);
parent.insert (std::move (value));
}
unreachable ();
2012-04-26 18:18:09 +10:00
}
//-----------------------------------------------------------------------------
template <typename T>
static
typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
json::tree::object &parent)
{
for (auto cursor = first; cursor != last; ) {
if (cursor->tag == json::flat::type::OBJECT_END)
return cursor + 1;
CHECK_EQ (cursor->tag, json::flat::type::STRING);
std::string key (cursor->first + 1, cursor->last - 1);
++cursor;
std::unique_ptr<json::tree::node> val;
cursor = ::parse<T> (cursor, last, val);
parent.insert (key, std::move (val));
}
unreachable ();
}
//-----------------------------------------------------------------------------
template <typename T>
static
typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
std::unique_ptr<json::tree::node> &output)
{
CHECK (first != last);
CHECK (output.get () == nullptr);
using F = json::flat::type;
switch (first->tag) {
case F::NUL:
output.reset (new json::tree::null ());
return first + 1;
case F::BOOLEAN:
CHECK (*first->first == 't' || *first->first == 'f');
output.reset (new json::tree::boolean (*first->first == 't'));
return first + 1;
case F::STRING:
CHECK_NEQ (&*first->first, &*first->last);
output.reset (new json::tree::string (first->first + 1, first->last - 1));
return first + 1;
case F::INTEGER: {
T start = first->first;
bool negative = *start == '-';
if (negative)
++start;
T finish = start;
uintmax_t v = 0;
while (isdigit (*finish))
v *= 10, v += *finish - '0', ++finish;
if (finish == start || finish > first->last)
throw json::parse_error ("invalid integer");
if (negative)
output.reset (new json::tree::number (-intmax_t(v)));
else
output.reset (new json::tree::number (v));
return first + 1;
}
case F::REAL: {
std::string str (first->first, first->last);
output.reset (new json::tree::number (std::atof (str.c_str())));
return first + 1;
}
case F::ARRAY_BEGIN: {
auto value = std::make_unique<json::tree::array> ();
auto cursor = ::parse<T> (first + 1, last, *value);
output = std::move (value);
return cursor;
}
case F::OBJECT_BEGIN: {
auto value = std::make_unique<json::tree::object> ();
auto cursor = ::parse<T> (first + 1, last, *value);
output = std::move (value);
return cursor;
}
case F::UNKNOWN:
case F::OBJECT_END:
case F::ARRAY_END:
unreachable ();
}
unreachable ();
}
2015-08-28 20:36:21 +10:00
///////////////////////////////////////////////////////////////////////////////
template <typename T>
std::unique_ptr<json::tree::node>
json::tree::parse (const util::view<T> &src)
{
std::unique_ptr<json::tree::node> output;
auto data = json::flat::parse (src);
auto end = ::parse<T> (data.cbegin (), data.cend (), output);
CHECK (end == data.cend ());
(void)end;
return output;
}
#define INSTANTIATE(KLASS) \
template \
std::unique_ptr<json::tree::node> \
json::tree::parse (const util::view<KLASS>&);
MAP0(INSTANTIATE,
std::string::iterator,
std::string::const_iterator,
const char*,
char *
);
#undef INSTANTIATE
//-----------------------------------------------------------------------------
std::unique_ptr<json::tree::node>
json::tree::parse (const std::experimental::filesystem::path &src)
{
const util::mapped_file data (src);
return parse (util::view{data}.cast<const char*> ());
}
///////////////////////////////////////////////////////////////////////////////
void
json::tree::write (const json::tree::node &node, std::ostream &os)
{
node.write (os);
}
2015-03-18 15:54:13 +11:00
///////////////////////////////////////////////////////////////////////////////
2012-04-19 16:41:10 +10:00
// Type conversion
const json::tree::object&
json::tree::node::as_object (void) const&
2015-03-18 15:54:13 +11:00
{ throw json::type_error ("node is not an object"); }
2011-05-23 17:18:52 +10:00
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
const json::tree::array&
json::tree::node::as_array (void) const&
2015-03-18 15:54:13 +11:00
{ throw json::type_error ("node is not an array"); }
2011-05-23 17:18:52 +10:00
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
const json::tree::string&
json::tree::node::as_string (void) const&
2015-03-18 15:54:13 +11:00
{ throw json::type_error ("node is not a string"); }
2011-05-23 17:18:52 +10:00
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
const json::tree::number&
json::tree::node::as_number (void) const&
2015-03-18 15:54:13 +11:00
{ throw json::type_error ("node is not a number"); }
2011-05-23 17:18:52 +10:00
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
const json::tree::boolean&
json::tree::node::as_boolean (void) const&
2015-03-18 15:54:13 +11:00
{ throw json::type_error ("node is not a boolean"); }
2011-05-23 17:18:52 +10:00
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
const json::tree::null&
json::tree::node::as_null (void) const&
{ throw json::type_error ("node is not a null"); }
2015-08-28 20:36:21 +10:00
///////////////////////////////////////////////////////////////////////////////
json::tree::object&
json::tree::node::as_object (void)&
{ throw json::type_error ("node is not an object"); }
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
json::tree::array&
json::tree::node::as_array (void)&
{ throw json::type_error ("node is not an array"); }
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
json::tree::string&
json::tree::node::as_string (void)&
{ throw json::type_error ("node is not a string"); }
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
json::tree::number&
json::tree::node::as_number (void)&
{ throw json::type_error ("node is not a number"); }
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
json::tree::boolean&
json::tree::node::as_boolean (void)&
{ throw json::type_error ("node is not a boolean"); }
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
json::tree::null&
json::tree::node::as_null (void)&
{ throw json::type_error ("node is not a null"); }
2012-04-13 11:15:08 +10:00
2015-02-16 23:34:50 +11:00
///////////////////////////////////////////////////////////////////////////////
2015-03-23 18:41:07 +11:00
bool
json::tree::node::as_bool (void) const
{
return !!as_boolean ();
}
//-----------------------------------------------------------------------------
2015-02-16 23:34:50 +11:00
float
json::tree::node::as_float (void) const
{
return static_cast<float> (as_number ().real ());
2015-02-16 23:34:50 +11:00
}
//-----------------------------------------------------------------------------
double
json::tree::node::as_double (void) const
{
return as_number ().real ();
2015-02-16 23:34:50 +11:00
}
//-----------------------------------------------------------------------------
uintmax_t
2015-02-16 23:34:50 +11:00
json::tree::node::as_uint (void) const
{
return as_number ().uint ();
}
2015-02-16 23:34:50 +11:00
//-----------------------------------------------------------------------------
intmax_t
json::tree::node::as_sint (void) const
{
return as_number ().sint ();
2015-02-16 23:34:50 +11:00
}
2015-03-18 15:48:01 +11:00
//-----------------------------------------------------------------------------
const char*
json::tree::node::as_chars (void) const&
2015-03-18 15:48:01 +11:00
{
return as_string ().native ().c_str ();
}
2012-04-19 16:41:10 +10:00
2015-09-08 14:33:39 +10:00
///////////////////////////////////////////////////////////////////////////////
2017-01-05 15:06:49 +11:00
namespace json::tree {
#if defined(__clang__)
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuseless-cast"
#endif
2015-09-08 14:33:39 +10:00
template <>
bool node::as (void) const
{
return as_bool ();
}
//-----------------------------------------------------------------------------
template <>
float json::tree::node::as (void) const
{
return as_float ();
}
//-----------------------------------------------------------------------------
template <>
double
json::tree::node::as (void) const
{
return as_double ();
}
//-----------------------------------------------------------------------------
template <>
uint32_t
json::tree::node::as (void) const
{
return static_cast<uint32_t> (as_uint ());
}
//-----------------------------------------------------------------------------
template <>
uint64_t
json::tree::node::as (void) const
{
return static_cast<uint64_t> (as_uint ());
}
//-----------------------------------------------------------------------------
template <>
int32_t
json::tree::node::as (void) const
{
return static_cast<int32_t> (as_sint ());
}
2015-09-08 14:33:39 +10:00
//-----------------------------------------------------------------------------
template <>
int64_t
json::tree::node::as (void) const
{
return static_cast<int64_t> (as_sint ());
}
//-------------------------------------------------------------------------
template <>
const std::string&
json::tree::node::as (void) const
{
return as_string ().native ();
}
#if defined(__clang__)
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
2017-01-05 15:06:49 +11:00
}
2015-09-08 14:33:39 +10:00
///////////////////////////////////////////////////////////////////////////////
// Global operatoers
2011-05-23 17:18:52 +10:00
bool
json::tree::node::operator!= (const node &rhs) const
2011-05-23 17:18:52 +10:00
{ return !(*this == rhs); }
2015-08-28 20:36:21 +10:00
//-----------------------------------------------------------------------------
bool json::tree::node::operator==(const char *rhs) const
{
try {
2012-04-20 18:07:42 +10:00
return as_string ().native () == rhs;
} catch (const json::type_error&) {
return false;
}
}
2012-01-04 17:05:40 +11:00
//-----------------------------------------------------------------------------
json::tree::node&
json::tree::node::operator[] (const std::string &key)&
{ return as_object ()[key]; }
//-----------------------------------------------------------------------------
json::tree::node&
json::tree::node::operator[] (size_t idx)&
{ return as_array()[idx]; }
//-----------------------------------------------------------------------------
const json::tree::node&
json::tree::node::operator[] (const std::string &key) const&
{ return as_object ()[key]; }
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
const json::tree::node&
json::tree::node::operator[] (size_t idx) const&
{ return as_array()[idx]; }
2012-04-19 16:41:10 +10:00
2015-03-18 15:54:13 +11:00
///////////////////////////////////////////////////////////////////////////////
2012-04-19 16:41:10 +10:00
// Object
json::tree::object::~object ()
{ ; }
2011-05-23 17:18:52 +10:00
2015-03-18 15:44:46 +11:00
//-----------------------------------------------------------------------------
std::unique_ptr<json::tree::node>
json::tree::object::clone (void) const
{
auto obj = std::make_unique<json::tree::object> ();
for (auto &i: *this)
obj->insert (i.first, i.second->clone ());
return std::move (obj);
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
bool
json::tree::object::operator== (const json::tree::object &rhs) const
2015-03-18 15:54:13 +11:00
{
if (rhs.size () != size ())
return false;
for (auto const &[i,j]: util::zip (m_values, rhs.m_values)) {
if (i.first != j.first)
2011-05-23 17:18:52 +10:00
return false;
if (*i.second != *j.second)
2011-05-23 17:18:52 +10:00
return false;
}
return true;
}
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
void
json::tree::object::insert (const std::string &_key, std::unique_ptr<json::tree::node> &&value)
2015-03-18 15:54:13 +11:00
{
m_values[_key] = move(value);
}
2011-05-23 17:18:52 +10:00
2015-03-18 15:40:16 +11:00
//-----------------------------------------------------------------------------
json::tree::node&
json::tree::object::operator[](const std::string &key)&
2015-03-18 15:40:16 +11:00
{
auto value = m_values.find (key);
if (value == m_values.end ())
throw json::key_error (key);
return *value->second;
}
2011-05-23 17:18:52 +10:00
2015-03-18 15:40:16 +11:00
//-----------------------------------------------------------------------------
const json::tree::node&
json::tree::object::operator[](const std::string &key) const&
2015-03-18 15:40:16 +11:00
{
2011-05-23 17:18:52 +10:00
auto value = m_values.find (key);
2015-03-18 15:40:16 +11:00
if (value == m_values.end ())
throw json::key_error (key);
2011-05-23 17:18:52 +10:00
return *value->second;
}
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
2012-04-20 18:09:23 +10:00
bool
2015-03-18 15:54:13 +11:00
json::tree::object::has (const std::string &key) const
{
2012-04-20 18:09:23 +10:00
return m_values.find (key) != m_values.end ();
}
2015-03-18 16:00:21 +11:00
//-----------------------------------------------------------------------------
json::tree::object::const_iterator
json::tree::object::find (const std::string &key) const
{
return m_values.find (key);
2012-04-19 16:44:35 +10:00
}
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
json::tree::object::const_iterator
json::tree::object::begin (void) const
2012-04-19 16:44:35 +10:00
{ return m_values.begin (); }
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
json::tree::object::const_iterator
json::tree::object::end (void) const
2012-04-19 16:44:35 +10:00
{ return m_values.end (); }
2015-03-18 16:00:21 +11:00
//-----------------------------------------------------------------------------
size_t
json::tree::object::size (void) const
{
return m_values.size ();
}
//-----------------------------------------------------------------------------
void
json::tree::object::clear (void)
{
m_values.clear ();
}
//-----------------------------------------------------------------------------
void
json::tree::object::erase (const std::string &key)
{
auto pos = m_values.find (key);
if (pos == m_values.end ())
throw json::error ("erasing invalid key");
m_values.erase (key);
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
std::ostream&
2015-03-18 15:54:13 +11:00
json::tree::object::write (std::ostream &os) const
{
2012-04-12 14:09:33 +10:00
os << "{\n";
{
util::indenter raii(os);
2011-05-23 17:18:52 +10:00
2012-04-12 14:09:33 +10:00
for (auto i = m_values.begin (); i != m_values.end ();) {
os << '"' << i->first << "\" : " << *i->second;
2011-05-23 17:18:52 +10:00
2012-04-12 14:09:33 +10:00
if (++i != m_values.end ())
os << ",\n";
}
2011-05-23 17:18:52 +10:00
}
2012-04-12 14:09:33 +10:00
os << "\n}";
2011-05-23 17:18:52 +10:00
return os;
}
2015-03-18 15:54:13 +11:00
///////////////////////////////////////////////////////////////////////////////
2012-04-19 16:41:10 +10:00
// Array
2011-05-23 17:18:52 +10:00
json::tree::array::~array()
{
m_values.clear ();
}
2011-05-23 17:18:52 +10:00
2015-03-18 15:44:46 +11:00
//-----------------------------------------------------------------------------
std::unique_ptr<json::tree::node>
json::tree::array::clone (void) const
{
auto ret = std::make_unique<array> ();
for (const auto &i: *this)
ret->insert (i.clone ());
return std::move (ret);
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
void
json::tree::array::insert (std::unique_ptr<json::tree::node> &&_value)
{
m_values.push_back (move (_value));
}
2011-05-23 17:18:52 +10:00
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
bool
2015-03-18 15:54:13 +11:00
json::tree::array::operator==(const json::tree::array &rhs) const
{
if (rhs.size () != size ())
return false;
for (auto const &[i,j]: util::zip (m_values, rhs.m_values))
if (*i != *j)
return false;
2011-05-23 17:18:52 +10:00
return true;
}
//-----------------------------------------------------------------------------
bool
json::tree::array::operator== (const node &rhs) const
{
return rhs == *this;
}
//-----------------------------------------------------------------------------
size_t
json::tree::array::size (void) const
{
return m_values.size ();
}
//-----------------------------------------------------------------------------
json::tree::node&
json::tree::array::operator[] (size_t idx)&
{
return *m_values[idx];
}
//-----------------------------------------------------------------------------
const json::tree::node&
json::tree::array::operator[] (size_t idx) const&
{
return *m_values[idx];
}
2015-03-18 15:59:29 +11:00
//-----------------------------------------------------------------------------
json::tree::array::iterator
json::tree::array::begin (void)
{
return iterator (m_values.begin ());
}
//-----------------------------------------------------------------------------
json::tree::array::iterator
json::tree::array::end (void)
{
return iterator (m_values.end ());
}
//-----------------------------------------------------------------------------
json::tree::array::const_iterator
json::tree::array::begin (void) const
{
return const_iterator (m_values.begin ());
}
//-----------------------------------------------------------------------------
json::tree::array::const_iterator
json::tree::array::end (void) const
{
return const_iterator (m_values.end ());
}
//-----------------------------------------------------------------------------
json::tree::array::const_iterator
json::tree::array::cbegin (void) const
{
return const_iterator (m_values.cbegin ());
}
//-----------------------------------------------------------------------------
json::tree::array::const_iterator
json::tree::array::cend (void) const
{
return const_iterator (m_values.cend ());
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
std::ostream&
json::tree::array::write (std::ostream &os) const {
2014-05-20 14:11:28 +10:00
os << "[\n";
2012-04-12 14:09:33 +10:00
{
util::indenter raii(os);
2011-05-23 17:18:52 +10:00
2012-04-12 14:09:33 +10:00
for (auto i = m_values.begin (); i != m_values.end (); ++i) {
(*i)->write (os);
2011-05-23 17:18:52 +10:00
2012-04-12 14:09:33 +10:00
if (i != m_values.end () - 1)
os << ",\n";
}
2011-05-23 17:18:52 +10:00
}
2012-04-12 14:09:33 +10:00
os << "\n]";
2011-05-23 17:18:52 +10:00
return os;
}
2015-03-18 15:54:13 +11:00
///////////////////////////////////////////////////////////////////////////////
2012-04-19 16:41:10 +10:00
// String
2011-05-23 17:18:52 +10:00
2015-03-18 15:44:46 +11:00
std::unique_ptr<json::tree::node>
json::tree::string::clone (void) const
{
return std::make_unique<json::tree::string> (m_value);
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
std::ostream&
2015-03-18 15:54:13 +11:00
json::tree::string::write (std::ostream &os) const
{
2011-05-23 17:18:52 +10:00
os << '"' << m_value << '"';
return os;
}
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
bool
2015-03-18 15:54:13 +11:00
json::tree::string::operator== (const json::tree::string &rhs) const
2011-05-23 17:18:52 +10:00
{ return rhs.m_value == m_value; }
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
2012-04-20 18:18:47 +10:00
bool
2015-03-18 15:54:13 +11:00
json::tree::string::operator== (const char *rhs) const
2012-04-20 18:18:47 +10:00
{ return rhs == m_value; }
//-----------------------------------------------------------------------------
bool
json::tree::string::operator== (const std::string &rhs) const
{ return rhs == m_value; }
2015-03-18 15:54:13 +11:00
///////////////////////////////////////////////////////////////////////////////
2012-04-19 16:41:10 +10:00
// Number
2011-05-23 17:18:52 +10:00
2015-03-18 15:44:46 +11:00
std::unique_ptr<json::tree::node>
json::tree::number::clone (void) const
{
switch (m_repr) {
case REAL: return std::make_unique<json::tree::number> (m_value.r);
case SINT: return std::make_unique<json::tree::number> (m_value.s);
case UINT: return std::make_unique<json::tree::number> (m_value.u);
}
unreachable ();
2015-03-18 15:44:46 +11:00
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
std::ostream&
2015-03-18 15:54:13 +11:00
json::tree::number::write (std::ostream &os) const
{
2017-01-05 20:21:20 +11:00
util::stream::scoped::precision p (os);
switch (m_repr) {
2017-01-05 20:21:20 +11:00
case REAL: return os << std::setprecision (std::numeric_limits<real_t>::digits10) << m_value.r;
case SINT: return os << std::setprecision (std::numeric_limits<sint_t>::digits10) << m_value.s;
case UINT: return os << std::setprecision (std::numeric_limits<uint_t>::digits10) << m_value.u;
}
unreachable ();
2011-05-23 17:18:52 +10:00
}
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
bool
json::tree::number::operator ==(const json::tree::number &rhs) const {
if (repr () != rhs.repr ())
return false;
switch (repr ()) {
case REAL: return util::almost_equal (real (), rhs.real ());
case SINT: return util::almost_equal (sint (), rhs.sint ());
case UINT: return util::almost_equal (uint (), rhs.uint ());
}
unreachable ();
}
///////////////////////////////////////////////////////////////////////////////
json::tree::number::real_t
json::tree::number::real (void) const
{
switch (repr ()) {
case REAL:
return m_value.r;
case UINT:
if (uint_t (real_t (m_value.u)) != m_value.u)
throw type_error ("number is not a real");
return m_value.u;
case SINT:
if (sint_t (real_t (m_value.s)) != m_value.s)
throw type_error ("number is not a real");
return m_value.s;
}
unreachable ();
}
//-----------------------------------------------------------------------------
json::tree::number::sint_t
json::tree::number::sint (void) const
{
switch (repr ()) {
case SINT:
return m_value.s;
case REAL:
if (!::util::equal (real_t (sint_t (m_value.r)), m_value.r))
throw type_error ("number is not a sint");
return sint_t (m_value.r);
case UINT:
if (uint_t (sint_t (m_value.u)) != m_value.u)
throw type_error ("number is not a sint");
return m_value.s;
}
unreachable ();
}
//-----------------------------------------------------------------------------
json::tree::number::uint_t
json::tree::number::uint (void) const
{
switch (repr ()) {
case UINT:
return m_value.u;
case REAL:
if (!::util::equal (real_t (uint_t (m_value.r)), m_value.r))
throw type_error ("number is not a uint");
return uint_t (m_value.r);
case SINT:
if (sint_t (uint_t (m_value.s)) != m_value.s)
throw type_error ("number is not a uint");
return m_value.s;
}
unreachable ();
}
///////////////////////////////////////////////////////////////////////////////
json::tree::number::operator json::tree::number::real_t (void) const
{
return real ();
}
//-----------------------------------------------------------------------------
json::tree::number::operator json::tree::number::sint_t (void) const
{
return sint ();
}
//-----------------------------------------------------------------------------
json::tree::number::operator json::tree::number::uint_t (void) const
{
return uint ();
}
2011-05-23 17:18:52 +10:00
2015-03-18 15:54:13 +11:00
///////////////////////////////////////////////////////////////////////////////
2012-04-19 16:41:10 +10:00
// Boolean
2011-05-23 17:18:52 +10:00
2015-03-18 15:44:46 +11:00
std::unique_ptr<json::tree::node>
json::tree::boolean::clone (void) const
{
return std::make_unique<json::tree::boolean> (m_value);
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
std::ostream&
2015-03-18 15:54:13 +11:00
json::tree::boolean::write (std::ostream &os) const
{
2012-04-12 14:09:33 +10:00
os << (m_value ? "true" : "false");
2011-05-23 17:18:52 +10:00
return os;
}
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
bool
json::tree::boolean::operator ==(const json::tree::boolean &rhs) const
2011-05-23 17:18:52 +10:00
{ return rhs.m_value == m_value; }
2015-03-18 15:54:13 +11:00
///////////////////////////////////////////////////////////////////////////////
2012-04-19 16:41:10 +10:00
// Null
2011-05-23 17:18:52 +10:00
2015-03-18 15:44:46 +11:00
std::unique_ptr<json::tree::node>
json::tree::null::clone (void) const
{
return std::make_unique<json::tree::null> ();
}
//-----------------------------------------------------------------------------
2011-05-23 17:18:52 +10:00
std::ostream&
2015-03-18 15:54:13 +11:00
json::tree::null::write (std::ostream &os) const
{
2011-05-23 17:18:52 +10:00
os << "null";
return os;
}
2015-03-18 15:54:13 +11:00
//-----------------------------------------------------------------------------
std::ostream&
json::tree::operator<< (std::ostream &os, const json::tree::node &n)
2012-04-12 14:09:33 +10:00
{ return n.write (os); }
2013-08-05 20:54:19 +10:00
//-----------------------------------------------------------------------------
// to_json
2017-01-05 15:06:49 +11:00
namespace json::tree {
2013-08-05 20:54:19 +10:00
template <>
std::unique_ptr<node>
io<bool>::serialise (const bool &b) {
return std::unique_ptr<node> (new boolean (b));
}
template <>
std::unique_ptr<node>
io<std::nullptr_t>::serialise (const std::nullptr_t &) {
2013-08-05 20:54:19 +10:00
return std::unique_ptr<node> (new null ());
}
template <>
std::unique_ptr<node>
io<std::string>::serialise (const std::string &s) {
return std::unique_ptr<node> (new string (s));
}
2013-08-05 22:39:34 +10:00
template <>
std::unique_ptr<node>
io<int32_t>::serialise (const int32_t &i) {
return std::unique_ptr<node> (new number (intmax_t {i}));
}
template <>
std::unique_ptr<node>
io<int64_t>::serialise (const int64_t &i) {
return std::unique_ptr<node> (new number (intmax_t {i}));
}
template <>
std::unique_ptr<node>
io<uint32_t>::serialise (const uint32_t &i) {
return std::unique_ptr<node> (new number (uintmax_t {i}));
2013-08-05 22:39:34 +10:00
}
template <>
std::unique_ptr<node>
io<uint64_t>::serialise (const uint64_t &i) {
return std::unique_ptr<node> (new number (uintmax_t {i}));
}
2013-08-05 22:39:34 +10:00
template <>
std::unique_ptr<node>
io<float>::serialise (const float &f) {
return std::unique_ptr<node> (new number (f));
}
2017-01-05 15:06:49 +11:00
}