0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd::json: Cleanup/improve grammar; improve linear array parse (incomplete).

This commit is contained in:
Jason Volk 2017-03-17 20:32:32 -07:00
parent 4b7372c4a8
commit 710d959a63
7 changed files with 435 additions and 294 deletions

View file

@ -32,7 +32,7 @@ IRCD_EXCEPTION(error, type_error);
IRCD_EXCEPTION(error, not_found);
struct doc;
struct array;
struct arr;
struct val;
struct obj;
@ -51,7 +51,7 @@ type type(const string_view &);
} // namespace json
} // namespace ircd
#include "json/array.h"
#include "json/arr.h"
#include "json/doc.h"
#include "json/val.h"
#include "json/obj.h"

169
include/ircd/json/arr.h Normal file
View file

@ -0,0 +1,169 @@
/*
* Copyright (C) 2017 Charybdis Development Team
* Copyright (C) 2017 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_JSON_ARR_H
namespace ircd {
namespace json {
struct arr
:string_view
{
struct const_iterator;
using value_type = const string_view;
using pointer = value_type *;
using reference = value_type &;
using iterator = const_iterator;
using size_type = size_t;
using difference_type = ptrdiff_t;
bool contains(const string_view &) const;
const_iterator end() const;
const_iterator begin() const;
size_t count() const;
const_iterator find(size_t i) const;
string_view at(size_t i) const;
string_view operator[](size_t i) const;
using string_view::string_view;
friend arr serialize(const arr &, char *&buf, char *const &stop);
friend size_t print(char *const &buf, const size_t &max, const arr &);
friend std::ostream &operator<<(std::ostream &, const arr &);
};
struct arr::const_iterator
{
using value_type = const string_view;
using pointer = value_type *;
using reference = value_type &;
using difference_type = size_t;
using iterator_category = std::forward_iterator_tag;
protected:
friend class arr;
const char *start;
const char *stop;
string_view state;
const_iterator(const char *const &start, const char *const &stop)
:start{start}
,stop{stop}
{}
public:
value_type *operator->() const { return &state; }
value_type &operator*() const { return *operator->(); }
const_iterator &operator++();
friend bool operator==(const arr::const_iterator &, const arr::const_iterator &);
friend bool operator!=(const arr::const_iterator &, const arr::const_iterator &);
friend bool operator<=(const arr::const_iterator &, const arr::const_iterator &);
friend bool operator>=(const arr::const_iterator &, const arr::const_iterator &);
friend bool operator<(const arr::const_iterator &, const arr::const_iterator &);
friend bool operator>(const arr::const_iterator &, const arr::const_iterator &);
};
inline bool
operator==(const arr::const_iterator &a, const arr::const_iterator &b)
{
return a.start == b.start;
}
inline bool
operator!=(const arr::const_iterator &a, const arr::const_iterator &b)
{
return a.start != b.start;
}
inline bool
operator<=(const arr::const_iterator &a, const arr::const_iterator &b)
{
return a.start <= b.start;
}
inline bool
operator>=(const arr::const_iterator &a, const arr::const_iterator &b)
{
return a.start >= b.start;
}
inline bool
operator<(const arr::const_iterator &a, const arr::const_iterator &b)
{
return a.start < b.start;
}
inline bool
operator>(const arr::const_iterator &a, const arr::const_iterator &b)
{
return a.start > b.start;
}
} // namespace json
} // namespace ircd
inline bool
ircd::json::arr::contains(const string_view &s)
const
{
return s.begin() >= this->string_view::begin() &&
s.end() <= this->string_view::end();
}
inline ircd::string_view
ircd::json::arr::operator[](size_t i)
const
{
const auto it(find(i));
return it != end()? *it : string_view{};
}
inline ircd::string_view
ircd::json::arr::at(size_t i)
const
{
const auto it(find(i));
return likely(it != end())? *it : throw not_found("[%zu]", i);
}
inline ircd::json::arr::const_iterator
ircd::json::arr::find(size_t i)
const
{
auto it(begin());
for(; it != end() && i; ++it, i--);
return it;
}
inline size_t
ircd::json::arr::count()
const
{
return std::distance(begin(), end());
}

View file

@ -1,99 +0,0 @@
/*
* Copyright (C) 2017 Charybdis Development Team
* Copyright (C) 2017 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_JSON_ARRAY_H
namespace ircd {
namespace json {
struct array
{
struct const_iterator;
using value_type = const string_view;
using pointer = value_type *;
using reference = value_type &;
using iterator = const_iterator;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
using key_compare = std::less<string_view>;
string_view state;
operator string_view() const { return state; }
const_iterator end() const;
const_iterator begin() const;
bool empty() const;
size_t size() const;
array(const string_view &state = {})
:state{state}
{}
};
struct array::const_iterator
{
using value_type = const string_view;
using pointer = value_type *;
using reference = value_type &;
using difference_type = size_t;
using iterator_category = std::forward_iterator_tag;
protected:
friend class array;
const char *start;
const char *stop;
string_view state;
const_iterator(const char *const &start, const char *const &stop)
:start{start}
,stop{stop}
{}
public:
auto operator==(const const_iterator &o) const { return start == o.start && stop == o.stop; }
auto operator!=(const const_iterator &o) const { return !(*this == o); }
value_type *operator->() const { return &state; }
value_type &operator*() const { return *operator->(); }
const_iterator &operator++();
};
} // namespace json
} // namespace ircd
inline size_t
ircd::json::array::size()
const
{
return std::distance(begin(), end());
}
inline bool
ircd::json::array::empty()
const
{
return state.empty();
}

View file

@ -38,7 +38,7 @@ struct doc
using reference = value_type &;
using iterator = const_iterator;
using size_type = size_t;
using difference_type = size_t;
using difference_type = ptrdiff_t;
using key_compare = std::less<member>;
bool contains(const string_view &) const;

View file

@ -62,7 +62,7 @@ struct obj
bool erase(const string_view &name);
obj(std::initializer_list<member>);
explicit obj(const doc &d);
obj(const doc &d);
obj() = default;
obj(obj &&) = default;
obj(const obj &) = delete;

View file

@ -29,9 +29,10 @@ struct val
{
union // xxx std::variant
{
uint64_t integer;
const char *string;
const struct obj *object;
uint64_t integer;
const struct array *array;
};
uint64_t len : 59;
@ -39,6 +40,7 @@ struct val
uint64_t serial : 1;
uint64_t alloc : 1;
public:
size_t size() const;
operator string_view() const;
@ -56,7 +58,7 @@ struct val
val() = default;
val(val &&) noexcept;
val(const val &) = delete;
val &operator=(val &&) = default;
val &operator=(val &&) noexcept;
val &operator=(const val &) = delete;
~val() noexcept;
@ -105,7 +107,7 @@ ircd::json::val::val(const struct obj &object,
inline
ircd::json::val::val(val &&other)
noexcept
:string{other.string}
:integer{other.integer}
,len{other.len}
,type{other.type}
,serial{other.serial}
@ -114,6 +116,21 @@ noexcept
other.alloc = false;
}
inline
ircd::json::val &
ircd::json::val::operator=(val &&other)
noexcept
{
this->~val();
integer = other.integer;
len = other.len;
type = other.type;
serial = other.serial;
alloc = other.alloc;
other.alloc = false;
return *this;
}
inline bool
ircd::json::operator<(const val &a, const val &b)
{

View file

@ -64,161 +64,85 @@ using karma::attr_cast;
template<class it>
struct input
:qi::grammar<it, string_view>
:qi::grammar<it, unused_type>
{
template<class T = unused_type> using rule = qi::rule<it, T>;
// insignificant whitespaces
qi::rule<it> SP { lit('\x20'), "space" };
qi::rule<it> HT { lit('\x09'), "horizontal tab" };
qi::rule<it> CR { lit('\x0D'), "carriage return" };
qi::rule<it> LF { lit('\x0A'), "line feed" };
rule<> SP { lit('\x20') ,"space" };
rule<> HT { lit('\x09') ,"horizontal tab" };
rule<> CR { lit('\x0D') ,"carriage return" };
rule<> LF { lit('\x0A') ,"line feed" };
// whitespace skipping
qi::rule<it> WS { SP | HT | CR | LF, "whitespace" };
qi::rule<it> ws { *(WS), "whitespace monoid" };
qi::rule<it> wsp { +(WS), "whitespace semigroup" };
rule<> WS { SP | HT | CR | LF ,"whitespace" };
rule<> ws { *(WS) ,"whitespace monoid" };
rule<> wsp { +(WS) ,"whitespace semigroup" };
// structural
qi::rule<it> object_begin { lit('{'), "object begin" };
qi::rule<it> object_end { lit('}'), "object end" };
qi::rule<it> array_begin;
qi::rule<it> array_end;
qi::rule<it> name_sep;
qi::rule<it> value_sep;
rule<> object_begin { lit('{') ,"object begin" };
rule<> object_end { lit('}') ,"object end" };
rule<> array_begin { lit('[') ,"array begin" };
rule<> array_end { lit(']') ,"array end" };
rule<> name_sep { lit(':') ,"name sep" };
rule<> value_sep { lit(',') ,"value sep" };
// literal
qi::rule<it, string_view> lit_true;
qi::rule<it, string_view> lit_false;
qi::rule<it, string_view> lit_null;
rule<string_view> lit_true { lit("true") ,"literal true" };
rule<string_view> lit_false { lit("false") ,"literal false" };
rule<string_view> lit_null { lit("null") ,"literal null" };
qi::rule<it> quote;
qi::rule<it, string_view> chars;
qi::rule<it, string_view> string;
rule<> quote { lit("\"") ,"quote" };
rule<string_view> chars { raw[*(char_ - quote)] ,"characters" };
rule<string_view> string { quote >> chars >> quote ,"string" };
rule<string_view> name { string ,"name" };
qi::rule<it, string_view> boolean;
qi::rule<it, string_view> literal;
qi::rule<it, string_view> number;
qi::rule<it, string_view> array;
qi::rule<it, string_view> object;
rule<string_view> boolean { lit_true | lit_false ,"boolean" };
rule<string_view> literal { lit_true | lit_false | lit_null ,"literal" };
rule<string_view> number { raw[double_] ,"number" };
qi::rule<it, string_view> name;
qi::rule<it, string_view> value;
qi::rule<it, doc::member> member;
rule<string_view> array
{
array_begin >> -(omit[ws >> value >> ws] % value_sep) >> ws >> array_end
,"array"
};
qi::rule<it, int> type;
rule<string_view> object
{
object_begin >> -(omit[ws >> member >> ws] % value_sep) >> ws >> object_end
,"object"
};
input();
rule<string_view> value
{
lit_false | lit_true | lit_null | object | array | number | string
,"value"
};
rule<doc::member> member
{
name >> ws >> name_sep >> ws >> value
,"member"
};
rule<int> type
{
(omit[object_begin] >> attr(json::OBJECT)) |
(omit[array_begin] >> attr(json::ARRAY)) |
(omit[quote] >> attr(json::STRING)) |
(omit[number] >> attr(json::NUMBER)) |
(omit[literal] >> attr(json::LITERAL))
,"type"
};
input()
:input::base_type{rule<>{}}
{
array %= array_begin >> -(omit[ws >> value >> ws] % value_sep) >> ws >> array_end;
object %= object_begin >> -(omit[ws >> member >> ws] % value_sep) >> ws >> object_end;
}
};
template<class it>
input<it>::input()
:input<it>::base_type
{
object
}
,array_begin
{
lit('[')
,"array begin"
}
,array_end
{
lit(']')
,"array end"
}
,name_sep
{
lit(':')
,"name separator"
}
,value_sep
{
lit(',')
,"value separator"
}
,lit_true
{
lit("true")
,"literal true"
}
,lit_false
{
lit("false")
,"literal false"
}
,lit_null
{
lit("null")
,"literal null"
}
,quote
{
lit('\"')
,"quote"
}
,chars
{
raw[*(char_ - quote)]
,"string"
}
,string
{
quote >> chars >> quote
,"string"
}
,boolean
{
lit_true | lit_false
,"boolean"
}
,literal
{
lit_true | lit_false | lit_null
,"literal"
}
,number
{
raw[double_]
,"number"
}
,array
{
array_begin >> -(omit[ws >> value >> ws] % value_sep) >> ws >> array_end
,"array"
}
,object
{
object_begin >> -(omit[ws >> member >> ws] % value_sep) >> ws >> object_end
,"object"
}
,name
{
string
,"name"
}
,value
{
lit_false | lit_true | lit_null | object | array | number | string
,"value"
}
,member
{
name >> -ws >> name_sep >> -ws >> value
,"member"
}
,type
{
(omit[object_begin] >> attr(json::OBJECT)) |
(omit[quote] >> attr(json::STRING)) |
(omit[number] >> attr(json::NUMBER)) |
(omit[literal] >> attr(json::LITERAL)) |
(omit[array_begin] >> attr(json::ARRAY))
,"type"
}
{
array %= array_begin >> -(omit[ws >> value >> ws] % value_sep) >> ws >> array_end;
object %= object_begin >> -(omit[ws >> member >> ws] % value_sep) >> ws >> object_end;
}
template<class it>
struct output
:karma::grammar<it, unused_type>
@ -239,13 +163,13 @@ struct output
rule<> wsp { +(WS) ,"whitespace semigroup" };
// structural
rule<> object_begin { lit('{') ,"object begin" };
rule<> object_end { lit('}') ,"object end" };
rule<> array_begin { lit('[') ,"array begin" };
rule<> array_end { lit(']') ,"array end" };
rule<> name_sep { lit(':') ,"name separator" };
rule<> value_sep { lit(',') ,"value separator" };
rule<> quote { lit('"') ,"quote" };
rule<> object_begin { lit('{') ,"object begin" };
rule<> object_end { lit('}') ,"object end" };
rule<> array_begin { lit('[') ,"array begin" };
rule<> array_end { lit(']') ,"array end" };
rule<> name_sep { lit(':') ,"name separator" };
rule<> value_sep { lit(',') ,"value separator" };
rule<> quote { lit('"') ,"quote" };
rule<string_view> lit_true { karma::string("true") ,"literal true" };
rule<string_view> lit_false { karma::string("false") ,"literal false" };
@ -254,7 +178,7 @@ struct output
rule<string_view> boolean { lit_true | lit_false ,"boolean" };
rule<string_view> literal { lit_true | lit_false | lit_null ,"literal" };
rule<string_view> chars { *(~char_("\"")) ,"chars" };
rule<string_view> chars { *(~char_("\"")) ,"characters" };
rule<string_view> string { quote << chars << quote ,"string" };
rule<string_view> number { double_ ,"number" };
@ -262,8 +186,8 @@ struct output
rule<string_view> name { string ,"name" };
rule<string_view> value { rule<string_view>{} ,"value" };
rule<const json::array &> elems { (value % value_sep) ,"elements" };
rule<const json::array &> array { array_begin << elems << array_end ,"array" };
rule<const json::arr &> elems { (value % value_sep) ,"elements" };
rule<const json::arr &> array { array_begin << elems << array_end ,"array" };
rule<doc::member> member { name << name_sep << value ,"member" };
rule<const json::doc &> members { (member % value_sep) ,"members" };
@ -301,10 +225,12 @@ struct ostreamer
}
const ostreamer;
doc serialize(const obj &, char *&start, char *const &stop);
size_t print(char *const &buf, const size_t &max, const obj &);
size_t print(char *const &buf, const size_t &max, const arr &);
size_t print(char *const &buf, const size_t &max, const doc &);
size_t print(char *const &buf, const size_t &max, const obj &);
doc serialize(const obj &, char *&start, char *const &stop);
std::ostream &operator<<(std::ostream &, const arr &);
std::ostream &operator<<(std::ostream &, const doc::member &);
std::ostream &operator<<(std::ostream &, const doc &);
std::ostream &operator<<(std::ostream &, const obj &);
@ -316,6 +242,13 @@ ircd::json::printer::printer()
{
const auto recursor([this](auto &a, auto &b, auto &c)
{
const auto recurse_array([&]
{
char *out(const_cast<char *>(a.data()));
karma::generate(out, maxwidth(a.size())[array], json::arr(a));
a.resize(size_t(out - a.data()));
});
const auto recurse_document([&]
{
char *out(const_cast<char *>(a.data()));
@ -332,7 +265,7 @@ ircd::json::printer::printer()
if(likely(!a.empty())) switch(a.front())
{
case '{': recurse_document(); break;
case '[': c = false; break;
case '[': recurse_array(); break;
case '"': break;
case '0': break;
case '1': break;
@ -363,6 +296,13 @@ ircd::json::ostreamer::ostreamer()
{
const auto recursor([this](auto &a, auto &b, auto &c)
{
const auto recurse_array([&]
{
char *out(const_cast<char *>(a.data()));
const auto count(print(out, a.size() + 1, json::arr(a)));
a.resize(count);
});
const auto recurse_document([&]
{
char *out(const_cast<char *>(a.data()));
@ -379,7 +319,7 @@ ircd::json::ostreamer::ostreamer()
if(likely(!a.empty())) switch(a.front())
{
case '{': recurse_document(); break;
case '[': c = false; break;
case '[': recurse_array(); break;
case '"': break;
case '0': break;
case '1': break;
@ -447,6 +387,18 @@ ircd::json::serialize(const obj &obj,
serialize(*val.object, out, stop);
});
const auto print_array([&stop, &out](const val &val)
{
if(val.serial)
{
karma::generate(out, maxwidth(stop - out)[printer.array] | eps[throws], val);
return;
}
//assert(val.object);
//serialize(*val.object, out, stop);
});
const auto print_member([&](const obj::member &member)
{
const auto generate_name
@ -458,9 +410,11 @@ ircd::json::serialize(const obj &obj,
switch(member.second.type)
{
case OBJECT: print_object(member.second); break;
case STRING: print_string(member.second); break;
default: throw type_error("Cannot stream unsupported member type");
case OBJECT: print_object(member.second); break;
case ARRAY: print_array(member.second); break;
default:
throw type_error("Cannot stream unsupported member type");
}
});
@ -494,14 +448,14 @@ ircd::json::operator<<(std::ostream &s, const obj &obj)
const auto stream_string([&osi](const val &val)
{
karma::generate(osi, ostreamer.string, string_view{val});
karma::generate(osi, ostreamer.string, val);
});
const auto stream_object([&osi, &s](const val &val)
{
if(val.serial)
{
karma::generate(osi, ostreamer.document, string_view{val});
karma::generate(osi, ostreamer.document, val);
return;
}
@ -509,15 +463,30 @@ ircd::json::operator<<(std::ostream &s, const obj &obj)
s << *val.object;
});
const auto stream_array([&osi, &s](const val &val)
{
if(val.serial)
{
karma::generate(osi, ostreamer.array, val);
return;
}
assert(0);
//assert(val.object);
//s << *val.object;
});
const auto stream_member([&](const obj::member &member)
{
karma::generate(osi, ostreamer.name << ostreamer.name_sep, string_view(member.first));
switch(member.second.type)
{
case OBJECT: stream_object(member.second); break;
case STRING: stream_string(member.second); break;
default: throw type_error("cannot stream unsupported member type");
case OBJECT: stream_object(member.second); break;
case ARRAY: stream_array(member.second); break;
default:
throw type_error("cannot stream unsupported member type");
}
});
@ -605,6 +574,10 @@ ircd::json::operator<<(std::ostream &s, const val &v)
{
switch(v.type)
{
case STRING:
s << string_view(v);
break;
case OBJECT:
if(v.serial)
s << string_view(v);
@ -612,12 +585,15 @@ ircd::json::operator<<(std::ostream &s, const val &v)
s << *v.object;
break;
case STRING:
s << string_view(v);
case ARRAY:
if(v.serial)
s << string_view(v);
else
assert(0);
break;
default:
throw type_error("cannot stream value");
throw type_error("cannot stream value type[%d]", int(v.type));
}
return s;
@ -627,10 +603,11 @@ inline
ircd::json::val::~val()
noexcept
{
switch(type)
switch(type)
{
case OBJECT: if(alloc) delete object; break;
case STRING: if(alloc) delete[] string; break;
case OBJECT: if(alloc) delete object; break;
//case ARRAY: if(alloc) delete array; break;
default: break;
}
}
@ -640,17 +617,48 @@ const
{
switch(type)
{
case OBJECT: if(!serial) return std::string(*object);
case STRING: return std::string{string_view(*this)};
default: throw type_error("cannot stringify type");
case STRING:
return std::string(unquote(string_view(*this)));
case OBJECT:
if(serial)
return std::string(string_view(*this));
else
return std::string(*object);
case ARRAY:
if(serial)
return std::string(string_view(*this));
else
break;
default:
break;
}
throw type_error("cannot stringify type[%d]", int(type));
}
ircd::json::val::operator string_view()
const
{
return serial? string_view { string, len }:
throw type_error("Value not a string");
switch(type)
{
case STRING:
return unquote(string_view{string, len});
case ARRAY:
case OBJECT:
if(serial)
return string_view{string, len};
else
break;
default:
break;
}
throw type_error("value type[%d] is not a string", int(type));
}
size_t
@ -659,11 +667,14 @@ const
{
switch(type)
{
case OBJECT: return serial? len : object->size();
case STRING: return 1 + len + 1;
case NUMBER: return lex_cast(integer).size();
default: throw type_error("cannot size type");
case STRING: return 1 + len + 1;
case OBJECT: return serial? len : object->size();
case ARRAY: return serial? len : 2;
default: break;
};
throw type_error("cannot size type[%u]", int(type));
}
size_t
@ -671,11 +682,6 @@ ircd::json::print(char *const &buf,
const size_t &max,
const doc &doc)
{
static const auto throws([]
{
throw print_error("The JSON generator failed to print document");
});
if(unlikely(!max))
return 0;
@ -762,7 +768,7 @@ const
parser.object_begin >> parser.ws >> (parser.object_end | member)
};
iterator ret(string_view::begin(), string_view::end());
const_iterator ret(string_view::begin(), string_view::end());
if(!qi::phrase_parse(ret.start, ret.stop, parse_begin, parser.WS, ret.state))
ret.start = ret.stop;
@ -776,12 +782,60 @@ const
return { string_view::end(), string_view::end() };
}
ircd::json::array::const_iterator &
ircd::json::array::const_iterator::operator++()
size_t
ircd::json::print(char *const &buf,
const size_t &max,
const arr &arr)
{
if(unlikely(!max))
return 0;
char *out(buf);
serialize(arr, out, out + (max - 1));
*out = '\0';
return std::distance(buf, out);
}
ircd::json::arr
ircd::json::serialize(const arr &a,
char *&out,
char *const &stop)
{
static const auto throws([]
{
throw print_error("The JSON generator failed to print array");
});
const karma::rule<char *, const json::arr &> grammar
{
printer.array_begin << (printer.value % printer.value_sep) << printer.array_end
};
char *const start(out);
karma::generate(out, maxwidth(stop - start)[grammar] | eps[throws], a);
return string_view{start, out};
}
std::ostream &
ircd::json::operator<<(std::ostream &s, const arr &arr)
{
const auto &os(ostreamer);
static const auto throws([]
{
throw print_error("The JSON generator failed to output array to stream");
});
karma::ostream_iterator<char> osi(s);
karma::generate(osi, os.array | eps[throws], arr);
return s;
}
ircd::json::arr::const_iterator &
ircd::json::arr::const_iterator::operator++()
{
static const qi::rule<const char *, string_view> parse_next
{
(parser.array_end | (parser.value_sep >> parser.ws >> raw[parser.value]))
parser.array_end | (parser.value_sep >> parser.ws >> raw[parser.value])
};
state = string_view{};
@ -791,8 +845,8 @@ ircd::json::array::const_iterator::operator++()
return *this;
}
ircd::json::array::const_iterator
ircd::json::array::begin()
ircd::json::arr::const_iterator
ircd::json::arr::begin()
const
{
static const qi::rule<const char *, string_view> parse_begin
@ -800,18 +854,18 @@ const
parser.array_begin >> parser.ws >> (parser.array_end | raw[parser.value])
};
iterator ret(state.begin(), state.end());
const_iterator ret(string_view::begin(), string_view::end());
if(!qi::phrase_parse(ret.start, ret.stop, parse_begin, parser.WS, ret.state))
ret.start = ret.stop;
return ret;
}
ircd::json::array::const_iterator
ircd::json::array::end()
ircd::json::arr::const_iterator
ircd::json::arr::end()
const
{
return { state.end(), state.end() };
return { string_view::end(), string_view::end() };
}
enum ircd::json::type