mirror of
https://github.com/matrix-construct/construct
synced 2024-10-01 13:18:58 +02:00
ircd::json: Improve value semantics and various fixes.
This commit is contained in:
parent
6c9ad5e513
commit
f8fc03e57b
5 changed files with 139 additions and 33 deletions
|
@ -60,6 +60,7 @@ struct ircd::json::array
|
||||||
using string_view::string_view;
|
using string_view::string_view;
|
||||||
|
|
||||||
friend string_view stringify(mutable_buffer &, const array &);
|
friend string_view stringify(mutable_buffer &, const array &);
|
||||||
|
friend string_view stringify(mutable_buffer &, const std::vector<json::object> &);
|
||||||
friend std::ostream &operator<<(std::ostream &, const array &);
|
friend std::ostream &operator<<(std::ostream &, const array &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,10 @@
|
||||||
namespace ircd::json
|
namespace ircd::json
|
||||||
{
|
{
|
||||||
struct member;
|
struct member;
|
||||||
using members = std::initializer_list<member>;
|
|
||||||
|
|
||||||
size_t serialized(const member *const &begin, const member *const &end);
|
size_t serialized(const member *const &begin, const member *const &end);
|
||||||
size_t serialized(const members &);
|
|
||||||
|
|
||||||
string_view stringify(mutable_buffer &, const member *const *const &begin, const member *const *const &end);
|
string_view stringify(mutable_buffer &, const member *const *const &begin, const member *const *const &end);
|
||||||
string_view stringify(mutable_buffer &, const member *const &begin, const member *const &end);
|
string_view stringify(mutable_buffer &, const member *const &begin, const member *const &end);
|
||||||
string_view stringify(mutable_buffer &, const members &);
|
|
||||||
|
|
||||||
string_view stringify(mutable_buffer &, const std::vector<json::object> &);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A pair of json::value representing an object member.
|
/// A pair of json::value representing an object member.
|
||||||
|
@ -67,6 +61,14 @@ struct ircd::json::member
|
||||||
friend std::ostream &operator<<(std::ostream &, const member &);
|
friend std::ostream &operator<<(std::ostream &, const member &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace ircd::json
|
||||||
|
{
|
||||||
|
using members = std::initializer_list<member>;
|
||||||
|
|
||||||
|
size_t serialized(const members &);
|
||||||
|
string_view stringify(mutable_buffer &, const members &);
|
||||||
|
}
|
||||||
|
|
||||||
template<class K,
|
template<class K,
|
||||||
class V>
|
class V>
|
||||||
ircd::json::member::member(const K &k,
|
ircd::json::member::member(const K &k,
|
||||||
|
|
|
@ -49,15 +49,17 @@ struct ircd::json::value
|
||||||
const struct array *array;
|
const struct array *array;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t len : 58;
|
uint64_t len : 57; ///< length indicator
|
||||||
enum type type : 3;
|
enum type type : 3; ///< json::type indicator
|
||||||
uint64_t serial : 1;
|
uint64_t serial : 1; ///< only string* is used. type indicates JSON
|
||||||
uint64_t alloc : 1;
|
uint64_t alloc : 1; ///< indicates the pointer for type is owned
|
||||||
uint64_t floats : 1;
|
uint64_t floats : 1; ///< for NUMBER type, integer or floating
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool null() const;
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
size_t serialized() const;
|
bool undefined() const;
|
||||||
|
|
||||||
operator string_view() const;
|
operator string_view() const;
|
||||||
explicit operator double() const;
|
explicit operator double() const;
|
||||||
explicit operator int64_t() const;
|
explicit operator int64_t() const;
|
||||||
|
@ -65,14 +67,14 @@ struct ircd::json::value
|
||||||
|
|
||||||
template<class T> explicit value(const T &specialized);
|
template<class T> explicit value(const T &specialized);
|
||||||
template<size_t N> value(const char (&)[N]);
|
template<size_t N> value(const char (&)[N]);
|
||||||
|
value(const char *const &s);
|
||||||
value(const string_view &sv, const enum type &);
|
value(const string_view &sv, const enum type &);
|
||||||
value(const string_view &sv);
|
value(const string_view &sv);
|
||||||
value(const char *const &s);
|
|
||||||
value(const index *const &); // alloc = false
|
value(const index *const &); // alloc = false
|
||||||
value(std::unique_ptr<index>); // alloc = true
|
value(std::unique_ptr<index>); // alloc = true
|
||||||
value();
|
value();
|
||||||
value(value &&) noexcept;
|
value(value &&) noexcept;
|
||||||
value(const value &) = delete;
|
value(const value &);
|
||||||
value &operator=(value &&) noexcept;
|
value &operator=(value &&) noexcept;
|
||||||
value &operator=(const value &) = delete;
|
value &operator=(const value &) = delete;
|
||||||
~value() noexcept;
|
~value() noexcept;
|
||||||
|
@ -202,12 +204,22 @@ ircd::json::value::value(const T &t)
|
||||||
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
ircd::json::value::value(const char (&str)[N])
|
ircd::json::value::value(const char (&str)[N])
|
||||||
:value{string_view{str}}
|
:string{str}
|
||||||
|
,len{strnlen(str, N)}
|
||||||
|
,type{json::type(str, std::nothrow)}
|
||||||
|
,serial{true}
|
||||||
|
,alloc{false}
|
||||||
|
,floats{false}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
ircd::json::value::value(const char *const &s)
|
ircd::json::value::value(const char *const &s)
|
||||||
:value{string_view{s}}
|
:string{s}
|
||||||
|
,len{strlen(s)}
|
||||||
|
,type{json::type(s, std::nothrow)}
|
||||||
|
,serial{true}
|
||||||
|
,alloc{false}
|
||||||
|
,floats{false}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
|
@ -228,6 +240,33 @@ noexcept
|
||||||
other.alloc = false;
|
other.alloc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
ircd::json::value::value(const value &other)
|
||||||
|
:integer{other.integer}
|
||||||
|
,len{other.len}
|
||||||
|
,type{other.type}
|
||||||
|
,serial{other.serial}
|
||||||
|
,alloc{other.alloc}
|
||||||
|
,floats{other.floats}
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case NUMBER:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LITERAL:
|
||||||
|
case STRING:
|
||||||
|
assert(serial);
|
||||||
|
assert(!alloc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OBJECT:
|
||||||
|
case ARRAY:
|
||||||
|
assert(serial);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline ircd::json::value &
|
inline ircd::json::value &
|
||||||
ircd::json::value::operator=(value &&other)
|
ircd::json::value::operator=(value &&other)
|
||||||
noexcept
|
noexcept
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct ircd::m::error
|
||||||
template<class... args> error(const string_view &errcode, const char *const &fmt, args&&...);
|
template<class... args> error(const string_view &errcode, const char *const &fmt, args&&...);
|
||||||
error(const http::code &, const json::object &object = {});
|
error(const http::code &, const json::object &object = {});
|
||||||
error(const http::code &, const json::index &idx);
|
error(const http::code &, const json::index &idx);
|
||||||
|
error(const http::code &, const json::iov &);
|
||||||
error(const http::code &);
|
error(const http::code &);
|
||||||
error(std::string = {});
|
error(std::string = {});
|
||||||
|
|
||||||
|
|
97
ircd/json.cc
97
ircd/json.cc
|
@ -963,7 +963,7 @@ const
|
||||||
if(serial)
|
if(serial)
|
||||||
return std::string(string_view(*this));
|
return std::string(string_view(*this));
|
||||||
else
|
else
|
||||||
return std::string(*object);
|
return json::string(*object);
|
||||||
|
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
if(serial)
|
if(serial)
|
||||||
|
@ -991,9 +991,16 @@ const
|
||||||
case STRING:
|
case STRING:
|
||||||
return unquote(string_view{string, len});
|
return unquote(string_view{string, len});
|
||||||
|
|
||||||
|
case NUMBER:
|
||||||
|
if(serial)
|
||||||
|
return string_view{string, len};
|
||||||
|
else if(floats)
|
||||||
|
return byte_view<string_view>{floating};
|
||||||
|
else
|
||||||
|
return byte_view<string_view>{integer};
|
||||||
|
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
case NUMBER:
|
|
||||||
case LITERAL:
|
case LITERAL:
|
||||||
if(serial)
|
if(serial)
|
||||||
return string_view{string, len};
|
return string_view{string, len};
|
||||||
|
@ -1013,6 +1020,7 @@ const
|
||||||
return likely(!floats)? integer : floating;
|
return likely(!floats)? integer : floating;
|
||||||
|
|
||||||
case STRING:
|
case STRING:
|
||||||
|
assert(serial);
|
||||||
return lex_cast<int64_t>(string_view(*this));
|
return lex_cast<int64_t>(string_view(*this));
|
||||||
|
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
|
@ -1033,6 +1041,7 @@ const
|
||||||
return likely(floats)? floating : integer;
|
return likely(floats)? floating : integer;
|
||||||
|
|
||||||
case STRING:
|
case STRING:
|
||||||
|
assert(serial);
|
||||||
return lex_cast<double>(string_view(*this));
|
return lex_cast<double>(string_view(*this));
|
||||||
|
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
|
@ -1044,6 +1053,36 @@ const
|
||||||
throw type_error("value type[%d] is not a float", int(type));
|
throw type_error("value type[%d] is not a float", int(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ircd::json::value::undefined()
|
||||||
|
const
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case NUMBER:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case STRING:
|
||||||
|
return string == nullptr;
|
||||||
|
|
||||||
|
case OBJECT:
|
||||||
|
return serial? string == nullptr:
|
||||||
|
object? object->empty():
|
||||||
|
true;
|
||||||
|
|
||||||
|
case ARRAY:
|
||||||
|
return serial? string == nullptr:
|
||||||
|
array? array == nullptr:
|
||||||
|
true;
|
||||||
|
|
||||||
|
case LITERAL:
|
||||||
|
return serial? string == nullptr:
|
||||||
|
true;
|
||||||
|
};
|
||||||
|
|
||||||
|
throw type_error("deciding if a type[%u] is undefined is undefined", int(type));
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ircd::json::value::empty()
|
ircd::json::value::empty()
|
||||||
const
|
const
|
||||||
|
@ -1054,32 +1093,56 @@ const
|
||||||
case STRING: return !len;
|
case STRING: return !len;
|
||||||
case OBJECT: return serial? !len : object? object->empty() : true;
|
case OBJECT: return serial? !len : object? object->empty() : true;
|
||||||
case ARRAY: return serial? !len : array? false : true; //TODO: XXX arr
|
case ARRAY: return serial? !len : array? false : true; //TODO: XXX arr
|
||||||
case LITERAL: return !len;
|
case LITERAL: return serial? !len : true;
|
||||||
};
|
};
|
||||||
|
|
||||||
throw type_error("deciding if a type[%u] is empty is undefined", int(type));
|
throw type_error("deciding if a type[%u] is empty is undefined", int(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
bool
|
||||||
ircd::json::serialized(const value &value)
|
ircd::json::value::null()
|
||||||
{
|
|
||||||
return value.serialized();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
ircd::json::value::serialized()
|
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case NUMBER: return lex_cast(integer).size();
|
case NUMBER:
|
||||||
case STRING: return 1 + len + 1;
|
return floats? !(floating > 0.0 || floating < 0.0):
|
||||||
case OBJECT: return serial? len : object->serialized();
|
bool(integer);
|
||||||
case ARRAY: return serial? len : 2;
|
|
||||||
case LITERAL: return len;
|
case STRING:
|
||||||
|
return string == nullptr;
|
||||||
|
|
||||||
|
case OBJECT:
|
||||||
|
return serial? string == nullptr:
|
||||||
|
object? object->empty():
|
||||||
|
true;
|
||||||
|
|
||||||
|
case ARRAY:
|
||||||
|
return serial? string == nullptr:
|
||||||
|
array? array == nullptr:
|
||||||
|
true;
|
||||||
|
|
||||||
|
case LITERAL:
|
||||||
|
return serial? string == nullptr:
|
||||||
|
true;
|
||||||
};
|
};
|
||||||
|
|
||||||
throw type_error("deciding the size of a type[%u] is undefined", int(type));
|
throw type_error("deciding if a type[%u] is null is undefined", int(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ircd::json::serialized(const value &v)
|
||||||
|
{
|
||||||
|
switch(v.type)
|
||||||
|
{
|
||||||
|
case NUMBER: return lex_cast(v.integer).size();
|
||||||
|
case STRING: return 1 + v.len + 1;
|
||||||
|
case OBJECT: return v.serial? v.len : serialized(*v.object);
|
||||||
|
case ARRAY: return v.serial? v.len : 2;
|
||||||
|
case LITERAL: return v.len;
|
||||||
|
};
|
||||||
|
|
||||||
|
throw type_error("deciding the size of a type[%u] is undefined", int(v.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &
|
std::ostream &
|
||||||
|
|
Loading…
Reference in a new issue