0
0
Fork 0
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:
Jason Volk 2017-09-12 10:02:27 -07:00
parent 6c9ad5e513
commit f8fc03e57b
5 changed files with 139 additions and 33 deletions

View file

@ -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 &);
}; };

View file

@ -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,

View file

@ -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

View file

@ -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 = {});

View file

@ -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 &