2011-06-21 20:26:32 +10:00
|
|
|
/*
|
|
|
|
* This file is part of libgim.
|
|
|
|
*
|
|
|
|
* libgim is free software: you can redistribute it and/or modify it under the
|
|
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
|
|
* Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
* version.
|
2014-05-20 14:11:28 +10:00
|
|
|
*
|
2011-06-21 20:26:32 +10:00
|
|
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
2014-05-20 14:11:28 +10:00
|
|
|
*
|
2011-06-21 20:26:32 +10:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
2015-02-02 23:00:38 +11:00
|
|
|
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
|
2011-06-21 20:26:32 +10:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2011-05-23 17:18:52 +10:00
|
|
|
#include "json.hpp"
|
2012-04-12 16:06:28 +10:00
|
|
|
|
|
|
|
#include "debug.hpp"
|
2011-05-23 17:18:52 +10:00
|
|
|
#include "io.hpp"
|
2012-04-12 16:06:28 +10:00
|
|
|
#include "maths.hpp"
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
#include <algorithm>
|
2013-08-05 22:39:44 +10:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <deque>
|
|
|
|
#include <iomanip>
|
2011-05-23 17:18:52 +10:00
|
|
|
#include <sstream>
|
2013-08-05 22:39:44 +10:00
|
|
|
#include <stdexcept>
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2013-08-05 22:39:44 +10:00
|
|
|
#include <fcntl.h>
|
2011-05-23 17:18:52 +10:00
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
2013-08-05 22:39:44 +10:00
|
|
|
#include <sys/types.h>
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
2011-10-01 01:58:10 +10:00
|
|
|
using namespace util;
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2011-05-23 17:18:52 +10:00
|
|
|
%%{
|
2015-02-02 23:00:38 +11:00
|
|
|
# JSON (rfc7159)
|
2011-05-23 17:18:52 +10:00
|
|
|
machine json;
|
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
action trace { if (false) std::cerr << *p; }
|
|
|
|
action success { __success = true; }
|
|
|
|
action failure { }
|
|
|
|
|
|
|
|
action new_line { ++line; }
|
|
|
|
|
|
|
|
action first { parsed.push_back ({ type::UNKNOWN, p, p}); }
|
|
|
|
action last { parsed.back ().last = p; }
|
|
|
|
|
|
|
|
action tag_nul { parsed.back ().tag = type::NUL; }
|
|
|
|
action tag_boolean { parsed.back ().tag = type::BOOLEAN; }
|
|
|
|
action tag_string { parsed.back ().tag = type::STRING; }
|
|
|
|
action tag_integer { parsed.back ().tag = type::INTEGER; }
|
|
|
|
action tag_real { parsed.back ().tag = type::REAL; }
|
|
|
|
|
|
|
|
action tag_object_begin { parsed.push_back ({ type::OBJECT_BEGIN, p, p + 1 }); }
|
|
|
|
action tag_object_end { parsed.push_back ({ type::OBJECT_END, p, p + 1 }); }
|
|
|
|
action tag_array_begin { parsed.push_back ({ type::ARRAY_BEGIN, p, p + 1 }); }
|
|
|
|
action tag_array_end { parsed.push_back ({ type::ARRAY_END, p, p + 1 }); }
|
|
|
|
|
|
|
|
# Line counter
|
|
|
|
lines = (
|
|
|
|
any | '\n' @new_line
|
|
|
|
)*;
|
|
|
|
|
|
|
|
# UTF-8 (rfc3629)
|
|
|
|
utf8_tail = 0x80..0xbf;
|
|
|
|
|
|
|
|
utf8_1 = 0x00..0x7f;
|
|
|
|
utf8_2 = 0xc2..0xdf utf8_tail;
|
|
|
|
utf8_3 = 0xe0 0xa0..0xbf utf8_tail |
|
|
|
|
0xe1..0xec utf8_tail{2} |
|
|
|
|
0xed 0x80..0x9f utf8_tail |
|
|
|
|
0xee..0xef utf8_tail{2};
|
|
|
|
utf8_4 = 0xf0 0x90..0xbf utf8_tail{2} |
|
|
|
|
0xf1..0xf3 utf8_tail{3} |
|
|
|
|
0xf4 0x80..0x8f utf8_tail{2};
|
|
|
|
|
|
|
|
|
|
|
|
utf8 = utf8_1 | utf8_2 | utf8_3 | utf8_4;
|
|
|
|
|
|
|
|
# Utility
|
|
|
|
ws = 0x20 | 0x09 | 0x0A | 0x0D;
|
|
|
|
array_start = '[';
|
|
|
|
array_end = ']';
|
|
|
|
object_start = '{';
|
|
|
|
object_end = '}';
|
|
|
|
|
|
|
|
# Strings
|
|
|
|
char =
|
|
|
|
(utf8 - ["\\])
|
|
|
|
| "\\" (
|
|
|
|
[\\"/bfnrt]
|
|
|
|
| "u" xdigit{4}
|
|
|
|
)
|
|
|
|
;
|
|
|
|
|
|
|
|
string = ('"' char* '"') >first >tag_string %*last;
|
|
|
|
|
|
|
|
# numbers
|
|
|
|
int = '0' | [1-9] digit*;
|
|
|
|
|
|
|
|
frac = '.' digit+;
|
|
|
|
e = 'e'i[+\-]?;
|
|
|
|
exp = e digit+;
|
|
|
|
|
|
|
|
number = (
|
|
|
|
'-'?
|
|
|
|
int
|
|
|
|
(frac >tag_real)?
|
|
|
|
exp?
|
|
|
|
) >tag_integer;
|
|
|
|
|
|
|
|
# wrapper types
|
|
|
|
array = array_start @{ fhold; fcall array_members; } array_end;
|
|
|
|
object = object_start @{ fhold; fcall object_members; } object_end;
|
|
|
|
|
|
|
|
# simple types; case sensitive literals
|
|
|
|
bool = ("true" | "false") >tag_boolean;
|
|
|
|
nul = "null" >tag_nul;
|
|
|
|
literal = bool | nul;
|
|
|
|
|
|
|
|
value = object | array | (number | string | literal) >first %last;
|
|
|
|
|
|
|
|
# Complex
|
|
|
|
member = string ws* ':' ws* value;
|
|
|
|
|
|
|
|
array_members := ((
|
|
|
|
array_start >tag_array_begin ws* (value ws* (',' ws* value ws*)*)? array_end >tag_array_end
|
|
|
|
) & lines)
|
|
|
|
@{ fhold; fret; } $trace $!failure;
|
|
|
|
|
|
|
|
object_members := ((
|
|
|
|
object_start >tag_object_begin ws* (member ws* (',' ws* member ws*)*)? object_end >tag_object_end
|
|
|
|
) & lines)
|
|
|
|
@{ fhold; fret; } $trace $!failure;
|
|
|
|
|
|
|
|
# meta types
|
|
|
|
document := ((ws* value ws*) & lines)
|
|
|
|
%success
|
|
|
|
$!failure
|
|
|
|
$trace;
|
|
|
|
|
|
|
|
variable stack ragelstack;
|
|
|
|
prepush { ragelstack.push_back (0); }
|
|
|
|
postpop { ragelstack.pop_back (); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
write data;
|
|
|
|
}%%
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
std::ostream& operator<< (std::ostream &os, json::flat::type);
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
std::vector<json::flat::item>
|
|
|
|
json::flat::parse (const char *first, const char *last)
|
|
|
|
{
|
|
|
|
const char *p = first;
|
|
|
|
const char *pe = last;
|
|
|
|
const char *eof = pe;
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
std::deque<int> ragelstack;
|
|
|
|
std::vector<item> parsed;
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
size_t line = 0;
|
|
|
|
int cs, top;
|
|
|
|
bool __success = false;
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
%%write init;
|
|
|
|
%%write exec;
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
if (!__success)
|
|
|
|
throw parse_error (line, "parse error");
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
return parsed;
|
|
|
|
}
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
std::vector<json::flat::item>
|
|
|
|
json::flat::parse (const boost::filesystem::path &path)
|
|
|
|
{
|
|
|
|
util::mapped_file f (path);
|
|
|
|
return parse ((const char *)f.cbegin (), (const char*)f.cend ());
|
|
|
|
}
|
2012-04-20 18:06:30 +10:00
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-20 18:06:30 +10:00
|
|
|
// External support
|
|
|
|
|
|
|
|
template <>
|
|
|
|
bool
|
2015-02-02 23:00:38 +11:00
|
|
|
is_integer (const json::tree::number &node)
|
|
|
|
{
|
2012-04-20 18:06:30 +10:00
|
|
|
return is_integer (node.native ());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
bool
|
2015-02-02 23:00:38 +11:00
|
|
|
is_integer (const json::tree::node &node)
|
|
|
|
{
|
2012-04-20 18:06:30 +10:00
|
|
|
return node.is_number () &&
|
|
|
|
is_integer (node.as_number ());
|
|
|
|
}
|
|
|
|
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Node
|
2015-02-02 23:00:38 +11:00
|
|
|
static std::vector<json::flat::item>::const_iterator
|
|
|
|
parse (std::vector<json::flat::item>::const_iterator first,
|
|
|
|
std::vector<json::flat::item>::const_iterator last,
|
|
|
|
std::unique_ptr<json::tree::node> &output);
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static std::vector<json::flat::item>::const_iterator
|
|
|
|
parse (std::vector<json::flat::item>::const_iterator first,
|
|
|
|
std::vector<json::flat::item>::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 (cursor, last, value);
|
|
|
|
parent.insert (std::move (value));
|
|
|
|
}
|
|
|
|
|
|
|
|
unreachable ();
|
2012-04-26 18:18:09 +10:00
|
|
|
}
|
2012-04-12 14:08:41 +10:00
|
|
|
|
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static std::vector<json::flat::item>::const_iterator
|
|
|
|
parse (std::vector<json::flat::item>::const_iterator first,
|
|
|
|
std::vector<json::flat::item>::const_iterator last,
|
|
|
|
json::tree::object &parent)
|
|
|
|
{
|
|
|
|
for (auto cursor = first; cursor != last; ) {
|
|
|
|
if (cursor->tag == json::flat::type::OBJECT_END)
|
|
|
|
return cursor + 1;
|
2012-04-12 14:08:41 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
CHECK_EQ (cursor->tag, json::flat::type::STRING);
|
2012-04-12 14:08:41 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
std::string key (cursor->first + 1, cursor->last - 1);
|
|
|
|
++cursor;
|
|
|
|
|
|
|
|
std::unique_ptr<json::tree::node> val;
|
|
|
|
cursor = ::parse (cursor, last, val);
|
|
|
|
|
|
|
|
parent.insert (key, std::move (val));
|
|
|
|
}
|
|
|
|
|
|
|
|
unreachable ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static std::vector<json::flat::item>::const_iterator
|
|
|
|
parse (std::vector<json::flat::item>::const_iterator first,
|
|
|
|
std::vector<json::flat::item>::const_iterator last,
|
|
|
|
std::unique_ptr<json::tree::node> &output)
|
|
|
|
{
|
|
|
|
CHECK (first != last);
|
|
|
|
CHECK (output.get () == nullptr);
|
|
|
|
|
|
|
|
switch (first->tag) {
|
|
|
|
case json::flat::type::NUL:
|
|
|
|
output.reset (new json::tree::null ());
|
|
|
|
return first + 1;
|
|
|
|
|
|
|
|
case json::flat::type::BOOLEAN:
|
|
|
|
CHECK (*first->first == 't' || *first->first == 'f');
|
|
|
|
output.reset (new json::tree::boolean (*first->first == 't'));
|
|
|
|
return first + 1;
|
|
|
|
|
|
|
|
case json::flat::type::STRING:
|
|
|
|
CHECK_NEQ (first->first, first->last);
|
|
|
|
output.reset (new json::tree::string (first->first + 1, first->last - 1));
|
|
|
|
return first + 1;
|
|
|
|
|
|
|
|
case json::flat::type::INTEGER:
|
|
|
|
case json::flat::type::REAL:
|
|
|
|
output.reset (new json::tree::number (std::atof (first->first)));
|
|
|
|
return first + 1;
|
|
|
|
|
|
|
|
case json::flat::type::ARRAY_BEGIN: {
|
|
|
|
auto value = std::make_unique<json::tree::array> ();
|
|
|
|
auto cursor = ::parse (first + 1, last, *value);
|
|
|
|
output = std::move (value);
|
|
|
|
return cursor;
|
|
|
|
}
|
2012-04-12 14:08:41 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
case json::flat::type::OBJECT_BEGIN: {
|
|
|
|
auto value = std::make_unique<json::tree::object> ();
|
|
|
|
auto cursor = ::parse (first + 1, last, *value);
|
|
|
|
output = std::move (value);
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
unreachable ();
|
2015-01-18 15:36:43 +11:00
|
|
|
}
|
2015-02-02 23:00:38 +11:00
|
|
|
}
|
2012-04-12 14:08:41 +10:00
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
std::unique_ptr<json::tree::node>
|
|
|
|
json::tree::parse (const boost::filesystem::path &path)
|
|
|
|
{
|
|
|
|
util::mapped_file f (path);
|
|
|
|
return parse ((const char*)f.cbegin (), (const char*)f.cend ());
|
2012-04-12 14:08:41 +10:00
|
|
|
}
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
std::unique_ptr<json::tree::node>
|
|
|
|
json::tree::parse (const std::string &path)
|
|
|
|
{ return parse (path.c_str (), path.c_str () + path.size ()); }
|
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
std::unique_ptr<json::tree::node>
|
|
|
|
json::tree::parse (const char *start)
|
2012-04-12 14:08:41 +10:00
|
|
|
{ return parse (start, start + strlen (start)); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2012-04-12 14:11:22 +10:00
|
|
|
void
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::write (const json::tree::node &node, std::ostream &os)
|
2012-04-12 14:11:22 +10:00
|
|
|
{ node.write (os); }
|
|
|
|
|
|
|
|
|
2015-02-02 23:00:38 +11:00
|
|
|
std::unique_ptr<json::tree::node>
|
|
|
|
json::tree::parse (const char *first, const char *last)
|
|
|
|
{
|
|
|
|
std::unique_ptr<json::tree::node> output;
|
|
|
|
auto data = json::flat::parse (first, last);
|
|
|
|
auto end = ::parse (data.cbegin (), data.cend (), output);
|
|
|
|
|
|
|
|
CHECK (end == data.cend ());
|
|
|
|
(void)end;
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Type conversion
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::object&
|
|
|
|
json::tree::node::as_object (void) const
|
2012-04-13 11:23:13 +10:00
|
|
|
{ throw type_error ("node is not an object"); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::array&
|
|
|
|
json::tree::node::as_array (void) const
|
2012-04-13 11:23:13 +10:00
|
|
|
{ throw type_error ("node is not an array"); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::string&
|
|
|
|
json::tree::node::as_string (void) const
|
2012-04-13 11:23:13 +10:00
|
|
|
{ throw type_error ("node is not a string"); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::number&
|
|
|
|
json::tree::node::as_number (void) const
|
2012-04-13 11:23:13 +10:00
|
|
|
{ throw type_error ("node is not a number"); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::boolean&
|
|
|
|
json::tree::node::as_boolean (void) const
|
2012-04-13 11:23:13 +10:00
|
|
|
{ throw type_error ("node is not a boolean"); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::null&
|
|
|
|
json::tree::node::as_null (void) const
|
2012-04-13 11:23:13 +10:00
|
|
|
{ throw type_error ("node is not a null"); }
|
2012-04-13 11:15:08 +10:00
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Global operatoers
|
|
|
|
|
2011-05-23 17:18:52 +10:00
|
|
|
bool
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::node::operator!= (const node &rhs) const
|
2011-05-23 17:18:52 +10:00
|
|
|
{ return !(*this == rhs); }
|
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
bool json::tree::node::operator==(const char *rhs) const {
|
2012-04-19 16:41:54 +10:00
|
|
|
try {
|
2012-04-20 18:07:42 +10:00
|
|
|
return as_string ().native () == rhs;
|
2015-02-02 21:22:38 +11:00
|
|
|
} catch (const json::tree::type_error&) {
|
2012-04-19 16:41:54 +10:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2012-01-04 17:05:40 +11:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::node&
|
|
|
|
json::tree::node::operator[] (const std::string &key) const
|
2012-04-12 16:08:06 +10:00
|
|
|
{ return as_object ()[key]; }
|
2011-09-23 13:45:09 +10:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::node&
|
|
|
|
json::tree::node::operator[] (unsigned int idx) const
|
2012-04-12 16:08:06 +10:00
|
|
|
{ return as_array()[idx]; }
|
2011-09-23 13:45:09 +10:00
|
|
|
|
2012-04-19 16:41:10 +10:00
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Object
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::object::~object ()
|
2012-04-12 16:09:49 +10:00
|
|
|
{ ; }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
|
|
|
bool
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::object::operator ==(const json::tree::object &rhs) const {
|
2011-05-23 17:18:52 +10:00
|
|
|
for (auto i = rhs.m_values.begin (), j = m_values.begin ();
|
|
|
|
i != rhs.m_values.end () && j != m_values.end ();
|
|
|
|
++i, ++j)
|
|
|
|
{
|
|
|
|
if (i->first != j->first)
|
|
|
|
return false;
|
|
|
|
if ((*i->second) != (*j->second))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::object::insert (const std::string &_key, unique_ptr<json::tree::node> &&value)
|
2012-04-12 16:09:49 +10:00
|
|
|
{ m_values[_key] = move(value); }
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
const json::tree::node&
|
|
|
|
json::tree::object::operator[](const std::string &key) const {
|
2011-05-23 17:18:52 +10:00
|
|
|
auto value = m_values.find (key);
|
|
|
|
if (value == m_values.end ()) {
|
|
|
|
ostringstream ss;
|
|
|
|
ss << "no key: " << key;
|
2015-02-02 21:22:38 +11:00
|
|
|
throw json::tree::error (ss.str());
|
2011-05-23 17:18:52 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
return *value->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-20 18:09:23 +10:00
|
|
|
bool
|
2015-02-02 21:22:38 +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 ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-19 16:44:35 +10:00
|
|
|
void
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::object::clear (void)
|
2012-04-19 16:44:35 +10:00
|
|
|
{ m_values.clear (); }
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::object::erase (const std::string &key) {
|
2012-04-19 16:44:35 +10:00
|
|
|
auto pos = m_values.find (key);
|
|
|
|
if (pos == m_values.end ())
|
2015-02-02 21:22:38 +11:00
|
|
|
throw json::tree::error ("erasing invalid key");
|
2012-04-19 16:44:35 +10:00
|
|
|
|
|
|
|
m_values.erase (key);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-02 21:22:38 +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-02-02 21:22:38 +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 (); }
|
|
|
|
|
|
|
|
|
2011-05-23 17:18:52 +10:00
|
|
|
std::ostream&
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::object::write (std::ostream &os) const {
|
2012-04-12 14:09:33 +10:00
|
|
|
os << "{\n";
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Array
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::array::~array()
|
|
|
|
{
|
|
|
|
m_values.clear ();
|
|
|
|
}
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
|
|
|
void
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::array::insert (unique_ptr<json::tree::node> &&_value)
|
|
|
|
{
|
|
|
|
m_values.push_back (move (_value));
|
|
|
|
}
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
|
|
|
bool
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::array::operator ==(const json::tree::array &rhs) const {
|
2011-05-23 17:18:52 +10:00
|
|
|
for (auto i = rhs.m_values.begin (), j = m_values.begin ();
|
|
|
|
i != rhs.m_values.end () && j != m_values.end ();
|
|
|
|
++i, ++j)
|
|
|
|
{ if ((**i) != (**j)) return false; }
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::ostream&
|
2015-02-02 21:22:38 +11:00
|
|
|
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
|
|
|
{
|
2014-05-20 14:11:28 +10:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// String
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
std::ostream&
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::string::write (std::ostream &os) const {
|
2011-05-23 17:18:52 +10:00
|
|
|
os << '"' << m_value << '"';
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2015-02-02 21:22:38 +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; }
|
|
|
|
|
|
|
|
|
2012-04-20 18:18:47 +10:00
|
|
|
bool
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::string::operator ==(const char *rhs) const
|
2012-04-20 18:18:47 +10:00
|
|
|
{ return rhs == m_value; }
|
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Number
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
std::ostream&
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::number::write (std::ostream &os) const {
|
2013-08-05 22:39:44 +10:00
|
|
|
os << setprecision (numeric_limits<double>::digits10) << m_value;
|
2011-05-23 17:18:52 +10:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::number::operator ==(const json::tree::number &rhs) const
|
2011-05-23 17:18:52 +10:00
|
|
|
{ return almost_equal (rhs.m_value, m_value); }
|
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Boolean
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
std::ostream&
|
2015-02-02 21:22:38 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::boolean::operator ==(const json::tree::boolean &rhs) const
|
2011-05-23 17:18:52 +10:00
|
|
|
{ return rhs.m_value == m_value; }
|
|
|
|
|
|
|
|
|
2013-08-05 20:12:04 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2012-04-19 16:41:10 +10:00
|
|
|
// Null
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
std::ostream&
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::null::write (std::ostream &os) const {
|
2011-05-23 17:18:52 +10:00
|
|
|
os << "null";
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
|
|
|
ostream&
|
2015-02-02 21:22:38 +11:00
|
|
|
json::tree::operator <<(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
|
|
|
|
|
2015-02-02 21:22:38 +11:00
|
|
|
namespace json { namespace 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<nullptr_t>::serialise (const nullptr_t &) {
|
|
|
|
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<int>::serialise (const int &i) {
|
|
|
|
return std::unique_ptr<node> (new number (i));
|
|
|
|
}
|
|
|
|
|
2014-09-01 16:25:24 +10:00
|
|
|
template <>
|
|
|
|
std::unique_ptr<node>
|
|
|
|
io<size_t>::serialise (const size_t &i) {
|
|
|
|
return std::unique_ptr<node> (new number (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));
|
|
|
|
}
|
2015-02-02 21:22:38 +11:00
|
|
|
} }
|
2015-02-02 23:00:38 +11:00
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
std::ostream&
|
|
|
|
operator<< (std::ostream &os, json::flat::type t)
|
|
|
|
{
|
|
|
|
switch (t) {
|
|
|
|
case json::flat::type::STRING: os << "STRING"; break;
|
|
|
|
case json::flat::type::NUL: os << "NUL"; break;
|
|
|
|
case json::flat::type::BOOLEAN: os << "BOOLEAN"; break;
|
|
|
|
case json::flat::type::INTEGER: os << "INTEGER"; break;
|
|
|
|
case json::flat::type::REAL: os << "REAL"; break;
|
|
|
|
|
|
|
|
case json::flat::type::OBJECT_BEGIN: os << "OBJECT_BEGIN"; break;
|
|
|
|
case json::flat::type::OBJECT_END: os << "OBJECT_END"; break;
|
|
|
|
case json::flat::type::ARRAY_BEGIN: os << "ARRAY_BEGIN"; break;
|
|
|
|
case json::flat::type::ARRAY_END: os << "ARRAY_END"; break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
unreachable ();
|
|
|
|
}
|
|
|
|
|
|
|
|
return os;
|
|
|
|
}
|