mirror of
https://github.com/matrix-construct/construct
synced 2025-01-13 16:33:53 +01:00
ircd::json: Cleanup/improve grammar; improve linear array parse (incomplete).
This commit is contained in:
parent
4b7372c4a8
commit
710d959a63
7 changed files with 435 additions and 294 deletions
|
@ -32,7 +32,7 @@ IRCD_EXCEPTION(error, type_error);
|
||||||
IRCD_EXCEPTION(error, not_found);
|
IRCD_EXCEPTION(error, not_found);
|
||||||
|
|
||||||
struct doc;
|
struct doc;
|
||||||
struct array;
|
struct arr;
|
||||||
|
|
||||||
struct val;
|
struct val;
|
||||||
struct obj;
|
struct obj;
|
||||||
|
@ -51,7 +51,7 @@ type type(const string_view &);
|
||||||
} // namespace json
|
} // namespace json
|
||||||
} // namespace ircd
|
} // namespace ircd
|
||||||
|
|
||||||
#include "json/array.h"
|
#include "json/arr.h"
|
||||||
#include "json/doc.h"
|
#include "json/doc.h"
|
||||||
#include "json/val.h"
|
#include "json/val.h"
|
||||||
#include "json/obj.h"
|
#include "json/obj.h"
|
||||||
|
|
169
include/ircd/json/arr.h
Normal file
169
include/ircd/json/arr.h
Normal 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());
|
||||||
|
}
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -38,7 +38,7 @@ struct doc
|
||||||
using reference = value_type &;
|
using reference = value_type &;
|
||||||
using iterator = const_iterator;
|
using iterator = const_iterator;
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using difference_type = size_t;
|
using difference_type = ptrdiff_t;
|
||||||
using key_compare = std::less<member>;
|
using key_compare = std::less<member>;
|
||||||
|
|
||||||
bool contains(const string_view &) const;
|
bool contains(const string_view &) const;
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct obj
|
||||||
bool erase(const string_view &name);
|
bool erase(const string_view &name);
|
||||||
|
|
||||||
obj(std::initializer_list<member>);
|
obj(std::initializer_list<member>);
|
||||||
explicit obj(const doc &d);
|
obj(const doc &d);
|
||||||
obj() = default;
|
obj() = default;
|
||||||
obj(obj &&) = default;
|
obj(obj &&) = default;
|
||||||
obj(const obj &) = delete;
|
obj(const obj &) = delete;
|
||||||
|
|
|
@ -29,9 +29,10 @@ struct val
|
||||||
{
|
{
|
||||||
union // xxx std::variant
|
union // xxx std::variant
|
||||||
{
|
{
|
||||||
|
uint64_t integer;
|
||||||
const char *string;
|
const char *string;
|
||||||
const struct obj *object;
|
const struct obj *object;
|
||||||
uint64_t integer;
|
const struct array *array;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t len : 59;
|
uint64_t len : 59;
|
||||||
|
@ -39,6 +40,7 @@ struct val
|
||||||
uint64_t serial : 1;
|
uint64_t serial : 1;
|
||||||
uint64_t alloc : 1;
|
uint64_t alloc : 1;
|
||||||
|
|
||||||
|
public:
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
|
|
||||||
operator string_view() const;
|
operator string_view() const;
|
||||||
|
@ -56,7 +58,7 @@ struct val
|
||||||
val() = default;
|
val() = default;
|
||||||
val(val &&) noexcept;
|
val(val &&) noexcept;
|
||||||
val(const val &) = delete;
|
val(const val &) = delete;
|
||||||
val &operator=(val &&) = default;
|
val &operator=(val &&) noexcept;
|
||||||
val &operator=(const val &) = delete;
|
val &operator=(const val &) = delete;
|
||||||
~val() noexcept;
|
~val() noexcept;
|
||||||
|
|
||||||
|
@ -105,7 +107,7 @@ ircd::json::val::val(const struct obj &object,
|
||||||
inline
|
inline
|
||||||
ircd::json::val::val(val &&other)
|
ircd::json::val::val(val &&other)
|
||||||
noexcept
|
noexcept
|
||||||
:string{other.string}
|
:integer{other.integer}
|
||||||
,len{other.len}
|
,len{other.len}
|
||||||
,type{other.type}
|
,type{other.type}
|
||||||
,serial{other.serial}
|
,serial{other.serial}
|
||||||
|
@ -114,6 +116,21 @@ noexcept
|
||||||
other.alloc = false;
|
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
|
inline bool
|
||||||
ircd::json::operator<(const val &a, const val &b)
|
ircd::json::operator<(const val &a, const val &b)
|
||||||
{
|
{
|
||||||
|
|
430
ircd/json.cc
430
ircd/json.cc
|
@ -64,161 +64,85 @@ using karma::attr_cast;
|
||||||
|
|
||||||
template<class it>
|
template<class it>
|
||||||
struct input
|
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
|
// insignificant whitespaces
|
||||||
qi::rule<it> SP { lit('\x20'), "space" };
|
rule<> SP { lit('\x20') ,"space" };
|
||||||
qi::rule<it> HT { lit('\x09'), "horizontal tab" };
|
rule<> HT { lit('\x09') ,"horizontal tab" };
|
||||||
qi::rule<it> CR { lit('\x0D'), "carriage return" };
|
rule<> CR { lit('\x0D') ,"carriage return" };
|
||||||
qi::rule<it> LF { lit('\x0A'), "line feed" };
|
rule<> LF { lit('\x0A') ,"line feed" };
|
||||||
|
|
||||||
// whitespace skipping
|
// whitespace skipping
|
||||||
qi::rule<it> WS { SP | HT | CR | LF, "whitespace" };
|
rule<> WS { SP | HT | CR | LF ,"whitespace" };
|
||||||
qi::rule<it> ws { *(WS), "whitespace monoid" };
|
rule<> ws { *(WS) ,"whitespace monoid" };
|
||||||
qi::rule<it> wsp { +(WS), "whitespace semigroup" };
|
rule<> wsp { +(WS) ,"whitespace semigroup" };
|
||||||
|
|
||||||
// structural
|
// structural
|
||||||
qi::rule<it> object_begin { lit('{'), "object begin" };
|
rule<> object_begin { lit('{') ,"object begin" };
|
||||||
qi::rule<it> object_end { lit('}'), "object end" };
|
rule<> object_end { lit('}') ,"object end" };
|
||||||
qi::rule<it> array_begin;
|
rule<> array_begin { lit('[') ,"array begin" };
|
||||||
qi::rule<it> array_end;
|
rule<> array_end { lit(']') ,"array end" };
|
||||||
qi::rule<it> name_sep;
|
rule<> name_sep { lit(':') ,"name sep" };
|
||||||
qi::rule<it> value_sep;
|
rule<> value_sep { lit(',') ,"value sep" };
|
||||||
|
|
||||||
// literal
|
// literal
|
||||||
qi::rule<it, string_view> lit_true;
|
rule<string_view> lit_true { lit("true") ,"literal true" };
|
||||||
qi::rule<it, string_view> lit_false;
|
rule<string_view> lit_false { lit("false") ,"literal false" };
|
||||||
qi::rule<it, string_view> lit_null;
|
rule<string_view> lit_null { lit("null") ,"literal null" };
|
||||||
|
|
||||||
qi::rule<it> quote;
|
rule<> quote { lit("\"") ,"quote" };
|
||||||
qi::rule<it, string_view> chars;
|
rule<string_view> chars { raw[*(char_ - quote)] ,"characters" };
|
||||||
qi::rule<it, string_view> string;
|
rule<string_view> string { quote >> chars >> quote ,"string" };
|
||||||
|
rule<string_view> name { string ,"name" };
|
||||||
|
|
||||||
qi::rule<it, string_view> boolean;
|
rule<string_view> boolean { lit_true | lit_false ,"boolean" };
|
||||||
qi::rule<it, string_view> literal;
|
rule<string_view> literal { lit_true | lit_false | lit_null ,"literal" };
|
||||||
qi::rule<it, string_view> number;
|
rule<string_view> number { raw[double_] ,"number" };
|
||||||
qi::rule<it, string_view> array;
|
|
||||||
qi::rule<it, string_view> object;
|
|
||||||
|
|
||||||
qi::rule<it, string_view> name;
|
rule<string_view> array
|
||||||
qi::rule<it, string_view> value;
|
{
|
||||||
qi::rule<it, doc::member> member;
|
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>
|
template<class it>
|
||||||
struct output
|
struct output
|
||||||
:karma::grammar<it, unused_type>
|
:karma::grammar<it, unused_type>
|
||||||
|
@ -239,13 +163,13 @@ struct output
|
||||||
rule<> wsp { +(WS) ,"whitespace semigroup" };
|
rule<> wsp { +(WS) ,"whitespace semigroup" };
|
||||||
|
|
||||||
// structural
|
// structural
|
||||||
rule<> object_begin { lit('{') ,"object begin" };
|
rule<> object_begin { lit('{') ,"object begin" };
|
||||||
rule<> object_end { lit('}') ,"object end" };
|
rule<> object_end { lit('}') ,"object end" };
|
||||||
rule<> array_begin { lit('[') ,"array begin" };
|
rule<> array_begin { lit('[') ,"array begin" };
|
||||||
rule<> array_end { lit(']') ,"array end" };
|
rule<> array_end { lit(']') ,"array end" };
|
||||||
rule<> name_sep { lit(':') ,"name separator" };
|
rule<> name_sep { lit(':') ,"name separator" };
|
||||||
rule<> value_sep { lit(',') ,"value separator" };
|
rule<> value_sep { lit(',') ,"value separator" };
|
||||||
rule<> quote { lit('"') ,"quote" };
|
rule<> quote { lit('"') ,"quote" };
|
||||||
|
|
||||||
rule<string_view> lit_true { karma::string("true") ,"literal true" };
|
rule<string_view> lit_true { karma::string("true") ,"literal true" };
|
||||||
rule<string_view> lit_false { karma::string("false") ,"literal false" };
|
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> boolean { lit_true | lit_false ,"boolean" };
|
||||||
rule<string_view> literal { lit_true | lit_false | lit_null ,"literal" };
|
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> string { quote << chars << quote ,"string" };
|
||||||
|
|
||||||
rule<string_view> number { double_ ,"number" };
|
rule<string_view> number { double_ ,"number" };
|
||||||
|
@ -262,8 +186,8 @@ struct output
|
||||||
rule<string_view> name { string ,"name" };
|
rule<string_view> name { string ,"name" };
|
||||||
rule<string_view> value { rule<string_view>{} ,"value" };
|
rule<string_view> value { rule<string_view>{} ,"value" };
|
||||||
|
|
||||||
rule<const json::array &> elems { (value % value_sep) ,"elements" };
|
rule<const json::arr &> elems { (value % value_sep) ,"elements" };
|
||||||
rule<const json::array &> array { array_begin << elems << array_end ,"array" };
|
rule<const json::arr &> array { array_begin << elems << array_end ,"array" };
|
||||||
|
|
||||||
rule<doc::member> member { name << name_sep << value ,"member" };
|
rule<doc::member> member { name << name_sep << value ,"member" };
|
||||||
rule<const json::doc &> members { (member % value_sep) ,"members" };
|
rule<const json::doc &> members { (member % value_sep) ,"members" };
|
||||||
|
@ -301,10 +225,12 @@ struct ostreamer
|
||||||
}
|
}
|
||||||
const ostreamer;
|
const ostreamer;
|
||||||
|
|
||||||
doc serialize(const obj &, char *&start, char *const &stop);
|
size_t print(char *const &buf, const size_t &max, const arr &);
|
||||||
size_t print(char *const &buf, const size_t &max, const obj &);
|
|
||||||
size_t print(char *const &buf, const size_t &max, const doc &);
|
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::member &);
|
||||||
std::ostream &operator<<(std::ostream &, const doc &);
|
std::ostream &operator<<(std::ostream &, const doc &);
|
||||||
std::ostream &operator<<(std::ostream &, const obj &);
|
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 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([&]
|
const auto recurse_document([&]
|
||||||
{
|
{
|
||||||
char *out(const_cast<char *>(a.data()));
|
char *out(const_cast<char *>(a.data()));
|
||||||
|
@ -332,7 +265,7 @@ ircd::json::printer::printer()
|
||||||
if(likely(!a.empty())) switch(a.front())
|
if(likely(!a.empty())) switch(a.front())
|
||||||
{
|
{
|
||||||
case '{': recurse_document(); break;
|
case '{': recurse_document(); break;
|
||||||
case '[': c = false; break;
|
case '[': recurse_array(); break;
|
||||||
case '"': break;
|
case '"': break;
|
||||||
case '0': break;
|
case '0': break;
|
||||||
case '1': break;
|
case '1': break;
|
||||||
|
@ -363,6 +296,13 @@ ircd::json::ostreamer::ostreamer()
|
||||||
{
|
{
|
||||||
const auto recursor([this](auto &a, auto &b, auto &c)
|
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([&]
|
const auto recurse_document([&]
|
||||||
{
|
{
|
||||||
char *out(const_cast<char *>(a.data()));
|
char *out(const_cast<char *>(a.data()));
|
||||||
|
@ -379,7 +319,7 @@ ircd::json::ostreamer::ostreamer()
|
||||||
if(likely(!a.empty())) switch(a.front())
|
if(likely(!a.empty())) switch(a.front())
|
||||||
{
|
{
|
||||||
case '{': recurse_document(); break;
|
case '{': recurse_document(); break;
|
||||||
case '[': c = false; break;
|
case '[': recurse_array(); break;
|
||||||
case '"': break;
|
case '"': break;
|
||||||
case '0': break;
|
case '0': break;
|
||||||
case '1': break;
|
case '1': break;
|
||||||
|
@ -447,6 +387,18 @@ ircd::json::serialize(const obj &obj,
|
||||||
serialize(*val.object, out, stop);
|
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 print_member([&](const obj::member &member)
|
||||||
{
|
{
|
||||||
const auto generate_name
|
const auto generate_name
|
||||||
|
@ -458,9 +410,11 @@ ircd::json::serialize(const obj &obj,
|
||||||
|
|
||||||
switch(member.second.type)
|
switch(member.second.type)
|
||||||
{
|
{
|
||||||
case OBJECT: print_object(member.second); break;
|
|
||||||
case STRING: print_string(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)
|
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)
|
const auto stream_object([&osi, &s](const val &val)
|
||||||
{
|
{
|
||||||
if(val.serial)
|
if(val.serial)
|
||||||
{
|
{
|
||||||
karma::generate(osi, ostreamer.document, string_view{val});
|
karma::generate(osi, ostreamer.document, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,15 +463,30 @@ ircd::json::operator<<(std::ostream &s, const obj &obj)
|
||||||
s << *val.object;
|
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)
|
const auto stream_member([&](const obj::member &member)
|
||||||
{
|
{
|
||||||
karma::generate(osi, ostreamer.name << ostreamer.name_sep, string_view(member.first));
|
karma::generate(osi, ostreamer.name << ostreamer.name_sep, string_view(member.first));
|
||||||
|
|
||||||
switch(member.second.type)
|
switch(member.second.type)
|
||||||
{
|
{
|
||||||
case OBJECT: stream_object(member.second); break;
|
|
||||||
case STRING: stream_string(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)
|
switch(v.type)
|
||||||
{
|
{
|
||||||
|
case STRING:
|
||||||
|
s << string_view(v);
|
||||||
|
break;
|
||||||
|
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
if(v.serial)
|
if(v.serial)
|
||||||
s << string_view(v);
|
s << string_view(v);
|
||||||
|
@ -612,12 +585,15 @@ ircd::json::operator<<(std::ostream &s, const val &v)
|
||||||
s << *v.object;
|
s << *v.object;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STRING:
|
case ARRAY:
|
||||||
s << string_view(v);
|
if(v.serial)
|
||||||
|
s << string_view(v);
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw type_error("cannot stream value");
|
throw type_error("cannot stream value type[%d]", int(v.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -627,10 +603,11 @@ inline
|
||||||
ircd::json::val::~val()
|
ircd::json::val::~val()
|
||||||
noexcept
|
noexcept
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case OBJECT: if(alloc) delete object; break;
|
|
||||||
case STRING: if(alloc) delete[] string; break;
|
case STRING: if(alloc) delete[] string; break;
|
||||||
|
case OBJECT: if(alloc) delete object; break;
|
||||||
|
//case ARRAY: if(alloc) delete array; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -640,17 +617,48 @@ const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case OBJECT: if(!serial) return std::string(*object);
|
case STRING:
|
||||||
case STRING: return std::string{string_view(*this)};
|
return std::string(unquote(string_view(*this)));
|
||||||
default: throw type_error("cannot stringify type");
|
|
||||||
|
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()
|
ircd::json::val::operator string_view()
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
return serial? string_view { string, len }:
|
switch(type)
|
||||||
throw type_error("Value not a string");
|
{
|
||||||
|
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
|
size_t
|
||||||
|
@ -659,11 +667,14 @@ const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case OBJECT: return serial? len : object->size();
|
|
||||||
case STRING: return 1 + len + 1;
|
|
||||||
case NUMBER: return lex_cast(integer).size();
|
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
|
size_t
|
||||||
|
@ -671,11 +682,6 @@ ircd::json::print(char *const &buf,
|
||||||
const size_t &max,
|
const size_t &max,
|
||||||
const doc &doc)
|
const doc &doc)
|
||||||
{
|
{
|
||||||
static const auto throws([]
|
|
||||||
{
|
|
||||||
throw print_error("The JSON generator failed to print document");
|
|
||||||
});
|
|
||||||
|
|
||||||
if(unlikely(!max))
|
if(unlikely(!max))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -762,7 +768,7 @@ const
|
||||||
parser.object_begin >> parser.ws >> (parser.object_end | member)
|
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))
|
if(!qi::phrase_parse(ret.start, ret.stop, parse_begin, parser.WS, ret.state))
|
||||||
ret.start = ret.stop;
|
ret.start = ret.stop;
|
||||||
|
|
||||||
|
@ -776,12 +782,60 @@ const
|
||||||
return { string_view::end(), string_view::end() };
|
return { string_view::end(), string_view::end() };
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::json::array::const_iterator &
|
size_t
|
||||||
ircd::json::array::const_iterator::operator++()
|
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
|
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{};
|
state = string_view{};
|
||||||
|
@ -791,8 +845,8 @@ ircd::json::array::const_iterator::operator++()
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::json::array::const_iterator
|
ircd::json::arr::const_iterator
|
||||||
ircd::json::array::begin()
|
ircd::json::arr::begin()
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
static const qi::rule<const char *, string_view> parse_begin
|
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])
|
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))
|
if(!qi::phrase_parse(ret.start, ret.stop, parse_begin, parser.WS, ret.state))
|
||||||
ret.start = ret.stop;
|
ret.start = ret.stop;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::json::array::const_iterator
|
ircd::json::arr::const_iterator
|
||||||
ircd::json::array::end()
|
ircd::json::arr::end()
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
return { state.end(), state.end() };
|
return { string_view::end(), string_view::end() };
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ircd::json::type
|
enum ircd::json::type
|
||||||
|
|
Loading…
Reference in a new issue