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

ircd::json: Improve stringification interface et al.

This commit is contained in:
Jason Volk 2017-09-08 07:47:07 -07:00
parent 77ba8696d9
commit 147a49a86c
11 changed files with 375 additions and 305 deletions

View file

@ -83,6 +83,11 @@ namespace ircd::json
using path = std::initializer_list<string_view>; using path = std::initializer_list<string_view>;
std::ostream &operator<<(std::ostream &, const path &); std::ostream &operator<<(std::ostream &, const path &);
size_t serialized(const string_view &);
template<class... T> string_view stringify(const mutable_buffer &&mb, T&&... t);
template<class... T> size_t print(char *const &buf, const size_t &max, T&&... t);
template<class... T> std::string string(T&&... t);
} }
#include "json/array.h" #include "json/array.h"
@ -99,6 +104,55 @@ namespace ircd
using json::operator<<; using json::operator<<;
} }
//
// Convenience template for const rvalue mutable_buffers or basically
// allowing a bracket initialization of a mutable_buffer in the argument
// to stringify()
//
template<class... T>
ircd::string_view
ircd::json::stringify(const mutable_buffer &&mb,
T&&... t)
{
mutable_buffer mbc(mb);
return stringify(mbc, std::forward<T>(t)...);
}
//
// Convenience template using the syntax print(buf, sizeof(buf), ...)
// which stringifies with null termination into buffer.
//
template<class... T>
size_t
ircd::json::print(char *const &buf,
const size_t &max,
T&&... t)
{
if(!max)
return 0;
mutable_buffer mb{buf, max - 1};
const auto sv(stringify(mb, std::forward<T>(t)...));
assert(sv.size() < max);
buf[sv.size()] = '\0';
return sv.size();
}
//
// Convenience template using the syntax string(...) which returns
// an std::string of the printed JSON
//
template<class... T>
std::string
ircd::json::string(T&&... t)
{
std::string ret;
ret.resize(serialized(std::forward<T>(t)...), char{});
const auto buf{const_cast<char *>(ret.data())};
print(buf, ret.size() + 1, std::forward<T>(t)...);
return ret;
}
inline std::ostream & inline std::ostream &
ircd::json::operator<<(std::ostream &s, const path &p) ircd::json::operator<<(std::ostream &s, const path &p)
{ {

View file

@ -57,8 +57,7 @@ struct ircd::json::array
using string_view::string_view; using string_view::string_view;
friend array serialize(const array &, char *&buf, char *const &stop); friend string_view stringify(mutable_buffer &, const array &);
friend size_t print(char *const &buf, const size_t &max, const array &);
friend std::ostream &operator<<(std::ostream &, const array &); friend std::ostream &operator<<(std::ostream &, const array &);
}; };

View file

@ -47,26 +47,24 @@ struct ircd::json::builder
builder(const builder *const &parent, const members *const &); builder(const builder *const &parent, const members *const &);
builder(const builder *const &parent, member); builder(const builder *const &parent, member);
friend string_view stringify(char *const &buf, const size_t &max, const builder &); friend string_view stringify(mutable_buffer &, const builder &);
}; };
inline ircd::string_view inline ircd::string_view
ircd::json::stringify(char *const &buf, ircd::json::stringify(mutable_buffer &head,
const size_t &max,
const builder &builder) const builder &builder)
{ {
size_t i(0); const auto num{builder.count()};
const auto num(builder.count());
const member *m[num]; const member *m[num];
size_t i(0);
builder.for_each([&i, &m] builder.for_each([&i, &m]
(const auto &member) (const auto &member)
{ {
m[i++] = &member; m[i++] = &member;
}); });
char *p(buf); return stringify(head, m, m + num);
char *const e(buf + max);
return serialize(m, m + num, p, e);
} }
inline inline

View file

@ -44,7 +44,7 @@ struct ircd::json::index
bool empty() const; bool empty() const;
size_t count() const; size_t count() const;
size_t size() const; size_t serialized() const;
const_iterator find(const string_view &name) const; const_iterator find(const string_view &name) const;
bool has(const string_view &name) const; bool has(const string_view &name) const;
@ -70,8 +70,8 @@ struct ircd::json::index
friend index &operator+=(index &, const object &); // integration friend index &operator+=(index &, const object &); // integration
friend index operator+(const object &, const object &); // integral friend index operator+(const object &, const object &); // integral
friend object serialize(const index &, char *&start, char *const &stop); friend size_t serialized(const index &);
friend size_t print(char *const &buf, const size_t &max, const index &); friend string_view stringify(mutable_buffer &, const index &);
friend std::ostream &operator<<(std::ostream &, const index &); friend std::ostream &operator<<(std::ostream &, const index &);
}; };

View file

@ -34,20 +34,16 @@
namespace ircd::json namespace ircd::json
{ {
struct member; struct member;
size_t size(const member *const &begin, const member *const &end);
object serialize(const member *const *const &begin, const member *const *const &end, char *&start, char *const &stop);
object serialize(const member *const &begin, const member *const &end, char *&start, char *const &stop);
size_t print(char *const &buf, const size_t &max, const member *const &begin, const member *const &end);
std::string string(const member *const &begin, const member *const &end);
using members = std::initializer_list<member>; using members = std::initializer_list<member>;
object serialize(const members &, char *&start, char *const &stop);
size_t print(char *const &buf, const size_t &max, const members &);
std::string string(const members &);
array serialize(const std::vector<json::object> &, char *&start, char *const &stop); size_t serialized(const member *const &begin, const member *const &end);
string_view stringify(char *const &buf, const size_t &max, const members &); 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 &begin, const member *const &end);
string_view stringify(mutable_buffer &, const members &);
string_view stringify(mutable_buffer &, const std::vector<json::object> &);
} }
struct ircd::json::member struct ircd::json::member
@ -67,6 +63,8 @@ struct ircd::json::member
friend bool operator!=(const member &a, const string_view &b); friend bool operator!=(const member &a, const string_view &b);
friend bool operator<(const member &a, const string_view &b); friend bool operator<(const member &a, const string_view &b);
friend size_t serialized(const member &);
friend string_view stringify(mutable_buffer &, const member &);
friend std::ostream &operator<<(std::ostream &, const member &); friend std::ostream &operator<<(std::ostream &, const member &);
}; };

View file

@ -111,9 +111,8 @@ struct ircd::json::object
explicit operator std::string() const; explicit operator std::string() const;
// rewrite onto streams or buffers etc // rewrite onto streams or buffers etc
friend string_view stringify(mutable_buffer &, const object &);
friend std::ostream &operator<<(std::ostream &, const object &); friend std::ostream &operator<<(std::ostream &, const object &);
friend object serialize(const object &, char *&buf, char *const &stop);
friend size_t print(char *const &buf, const size_t &max, const object &);
}; };
struct ircd::json::object::member struct ircd::json::object::member
@ -131,6 +130,7 @@ struct ircd::json::object::member
friend bool operator>(const member &, const member &); friend bool operator>(const member &, const member &);
// writes a single member onto stream // writes a single member onto stream
friend string_view stringify(mutable_buffer &, const object::member &);
friend std::ostream &operator<<(std::ostream &, const object::member &); friend std::ostream &operator<<(std::ostream &, const object::member &);
}; };

View file

@ -596,6 +596,22 @@ tuple<T...>::tuple(const std::initializer_list<member> &members)
}); });
} }
template<class tuple,
class it_a,
class it_b,
class closure>
constexpr void
_key_transform(it_a it,
const it_b end,
closure&& lambda)
{
for(size_t i(0); i < tuple::size() && it != end; ++i)
{
*it = lambda(key<tuple, i>());
++it;
}
}
template<class tuple, template<class tuple,
class it_a, class it_a,
class it_b> class it_b>
@ -603,11 +619,8 @@ constexpr void
_key_transform(it_a it, _key_transform(it_a it,
const it_b end) const it_b end)
{ {
for(size_t i(0); i < tuple::size(); ++i) for(size_t i(0); i < tuple::size() && it != end; ++i)
{ {
if(it == end)
break;
*it = key<tuple, i>(); *it = key<tuple, i>();
++it; ++it;
} }
@ -632,6 +645,28 @@ _key_transform(const tuple<T...> &tuple,
}); });
} }
template<class it_a,
class it_b,
class closure,
class... T>
void
_member_transform(const tuple<T...> &tuple,
it_a it,
const it_b end,
closure&& lambda)
{
until(tuple, [&it, &end, &lambda]
(const auto &key, const auto &val)
{
if(it == end)
return false;
*it = lambda(key, val);
++it;
return true;
});
}
template<class it_a, template<class it_a,
class it_b, class it_b,
class... T> class... T>
@ -640,46 +675,73 @@ _member_transform(const tuple<T...> &tuple,
it_a it, it_a it,
const it_b end) const it_b end)
{ {
for_each(tuple, [&it, &end] until(tuple, [&it, &end]
(const auto &key, const auto &val) (const auto &key, const auto &val)
{ {
if(it != end) if(it == end)
{ return false;
*it = { key, val };
++it; *it = { key, val };
} ++it;
return true;
}); });
} }
template<class... T> template<class T>
object constexpr bool
serialize(const tuple<T...> &tuple, serialized_lex_cast()
char *&start,
char *const &stop)
{ {
std::array<member, tuple.size()> members; using type = typename std::remove_reference<T>::type;
_member_transform(tuple, begin(members), end(members)); return std::is_arithmetic<type>::value;
return serialize(begin(members), end(members), start, stop); }
template<class T>
typename std::enable_if<serialized_lex_cast<T>(), size_t>::type
serialized(T&& t)
{
return lex_cast(t).size();
} }
template<class... T> template<class... T>
size_t size_t
print(char *const &buf, serialized(const tuple<T...> &t)
const size_t &max,
const tuple<T...> &tuple)
{ {
std::array<member, tuple.size()> members; constexpr const size_t member_count
_member_transform(tuple, begin(members), end(members)); {
return print(buf, max, begin(members), end(members)); tuple<T...>::size()
};
// Number of commas for this object is one less than the member count, or 0
const size_t commas
{
member_count? member_count - 1 : 0
};
// 2 for the {} and the comma count
const size_t overhead
{
2 + commas
};
std::array<size_t, member_count> sizes;
_member_transform(t, begin(sizes), end(sizes), []
(const string_view &key, auto&& val)
{
// " " :
return 1 + key.size() + 1 + 1 + serialized(val);
});
return std::accumulate(begin(sizes), end(sizes), overhead);
} }
template<class... T> template<class... T>
std::string string_view
string(const tuple<T...> &tuple) stringify(mutable_buffer &buf,
const tuple<T...> &tuple)
{ {
std::array<member, tuple.size()> members; std::array<member, tuple.size()> members;
_member_transform(tuple, begin(members), end(members)); _member_transform(tuple, begin(members), end(members));
return string(begin(members), end(members)); return stringify(buf, begin(members), end(members));
} }
template<class... T> template<class... T>

View file

@ -55,7 +55,7 @@ struct ircd::json::value
public: public:
bool empty() const; bool empty() const;
size_t size() const; size_t serialized() const;
operator string_view() const; operator string_view() const;
explicit operator std::string() const; explicit operator std::string() const;
@ -80,6 +80,9 @@ struct ircd::json::value
friend bool operator>=(const value &a, const value &b); friend bool operator>=(const value &a, const value &b);
friend bool operator<(const value &a, const value &b); friend bool operator<(const value &a, const value &b);
friend bool operator>(const value &a, const value &b); friend bool operator>(const value &a, const value &b);
friend size_t serialized(const value &);
friend string_view stringify(mutable_buffer &, const value &);
friend std::ostream &operator<<(std::ostream &, const value &); friend std::ostream &operator<<(std::ostream &, const value &);
}; };

View file

@ -248,6 +248,12 @@ struct printer
template<class generator> template<class generator>
bool operator()(char *&out, char *const &stop, generator&& gen) const; bool operator()(char *&out, char *const &stop, generator&& gen) const;
template<class... args>
bool operator()(mutable_buffer &out, args&&... a) const
{
return operator()(begin(out), end(out), std::forward<args>(a)...);
}
printer(); printer();
} }
const printer; const printer;
@ -259,23 +265,6 @@ struct ostreamer
} }
const ostreamer; const ostreamer;
size_t print(char *const &buf, const size_t &max, const array &);
size_t print(char *const &buf, const size_t &max, const object &);
size_t print(char *const &buf, const size_t &max, const index::member *const &begin, const index::member *const &end);
size_t print(char *const &buf, const size_t &max, const index &);
size_t print(char *const &buf, const size_t &max, const members &);
array serialize(const array &, char *&start, char *const &stop);
object serialize(const object &, char *&start, char *const &stop);
object serialize(const index::member *const &beg, const index::member *const &end, char *&start, char *const &stop);
object serialize(const index &, char *&start, char *const &stop);
object serialize(const members &, char *&start, char *const &stop);
std::ostream &operator<<(std::ostream &, const array &);
std::ostream &operator<<(std::ostream &, const object::member &);
std::ostream &operator<<(std::ostream &, const object &);
std::ostream &operator<<(std::ostream &, const index &);
} // namespace json } // namespace json
} // namespace ircd } // namespace ircd
@ -318,18 +307,26 @@ 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([&] const auto recurse_array([&a]
{ {
char *out(const_cast<char *>(a.data())); mutable_buffer mb
const auto r(serialize(json::array(a), out, out + a.size())); {
a.resize(size_t(out - r.data())); const_cast<char *>(a.data()), a.size()
};
const auto r(stringify(mb, json::array(a)));
a.resize(r.size());
}); });
const auto recurse_object([&] const auto recurse_object([&a]
{ {
char *out(const_cast<char *>(a.data())); mutable_buffer mb
const auto d(serialize(json::object(a), out, out + a.size())); {
a.resize(size_t(out - d.data())); const_cast<char *>(a.data()), a.size()
};
const auto r(stringify(mb, json::object(a)));
a.resize(r.size());
}); });
const auto quote_string([&] const auto quote_string([&]
@ -400,104 +397,20 @@ const
return karma::generate(out, gg); return karma::generate(out, gg);
} }
std::string
ircd::json::string(const members &list)
{
return string(std::begin(list), std::end(list));
}
std::string
ircd::json::string(const index::member *const &begin,
const index::member *const &end)
{
std::string ret(size(begin, end), char());
print(const_cast<char *>(ret.data()), ret.size() + 1, begin, end);
return ret;
}
size_t
ircd::json::print(char *const &buf,
const size_t &max,
const index &obj)
{
if(unlikely(!max))
return 0;
char *out(buf);
serialize(obj, out, out + (max - 1));
*out = '\0';
return out - buf;
}
ircd::string_view ircd::string_view
ircd::json::stringify(char *const &buf, ircd::json::stringify(mutable_buffer &buf,
const size_t &max, const std::vector<json::object> &v)
const members &list)
{ {
const auto len const auto print_member([&buf](const string_view &elem)
{ {
print(buf, max, std::begin(list), std::end(list)) //printer(buf, printer.elem, elem);
}; const auto cpsz(std::min(size(buf), elem.size()));
memcpy(begin(buf), elem.data(), cpsz);
return string_view{buf, len}; begin(buf) += cpsz;
}
size_t
ircd::json::print(char *const &buf,
const size_t &max,
const members &list)
{
return print(buf, max, std::begin(list), std::end(list));
}
size_t
ircd::json::print(char *const &buf,
const size_t &max,
const index::member *const &begin,
const index::member *const &end)
{
if(unlikely(!max))
return 0;
char *out(buf);
serialize(begin, end, out, out + (max - 1));
*out = '\0';
return out - buf;
}
ircd::json::object
ircd::json::serialize(const members &list,
char *&out,
char *const &stop)
{
return serialize(std::begin(list), std::end(list), out, stop);
}
ircd::json::object
ircd::json::serialize(const index &obj,
char *&out,
char *const &stop)
{
const index::member *const &begin(&obj.idx.front());
const index::member *const &end(begin + obj.idx.size());
return serialize(begin, end, out, stop);
}
ircd::json::array
ircd::json::serialize(const std::vector<json::object> &v,
char *&out,
char *const &stop)
{
const auto print_member([&out, &stop](const string_view &elem)
{
//printer(out, stop, printer.elem, elem);
const auto cpsz(std::min(size_t(stop - out), elem.size()));
memcpy(out, elem.data(), cpsz);
out += cpsz;
}); });
char *const start(out); char *const start(begin(buf));
printer(out, stop, printer.array_begin); printer(buf, printer.array_begin);
auto it(std::begin(v)); auto it(std::begin(v));
if(it != std::end(v)) if(it != std::end(v))
@ -505,66 +418,80 @@ ircd::json::serialize(const std::vector<json::object> &v,
print_member(*it); print_member(*it);
for(++it; it != std::end(v); ++it) for(++it; it != std::end(v); ++it)
{ {
printer(out, stop, printer.value_sep); printer(buf, printer.value_sep);
print_member(*it); print_member(*it);
} }
} }
printer(out, stop, printer.array_end); printer(buf, printer.array_end);
return string_view{start, out}; return string_view{start, begin(buf)};
} }
ircd::json::object ircd::string_view
ircd::json::serialize(const index::member *const &begin, ircd::json::stringify(mutable_buffer &buf,
const index::member *const &end, const members &list)
char *&out, {
char *const &stop) return stringify(buf, std::begin(list), std::end(list));
}
ircd::string_view
ircd::json::stringify(mutable_buffer &buf,
const index &obj)
{
const member *const &begin(&obj.idx.front());
const member *const &end(begin + obj.idx.size());
return stringify(buf, begin, end);
}
ircd::string_view
ircd::json::stringify(mutable_buffer &buf,
const member *const &begin,
const member *const &end)
{ {
const auto num(std::distance(begin, end)); const auto num(std::distance(begin, end));
const index::member *vec[num]; const member *vec[num];
for(auto i(0); i < num; ++i) for(auto i(0); i < num; ++i)
vec[i] = begin + i; vec[i] = begin + i;
return serialize(vec, vec + num, out, stop); return stringify(buf, vec, vec + num);
} }
ircd::json::object ircd::string_view
ircd::json::serialize(const index::member *const *const &begin, ircd::json::stringify(mutable_buffer &buf,
const index::member *const *const &end, const member *const *const &b,
char *&out, const member *const *const &e)
char *const &stop)
{ {
const auto print_string([&stop, &out](const value &value) const auto print_string([&buf](const value &value)
{ {
printer(out, stop, printer.string, string_view{value}); printer(buf, printer.string, string_view{value});
}); });
const auto print_literal([&stop, &out](const value &value) const auto print_literal([&buf](const value &value)
{ {
printer(out, stop, printer.literal, string_view{value}); printer(buf, printer.literal, string_view{value});
}); });
const auto print_object([&stop, &out](const value &value) const auto print_object([&buf](const value &value)
{ {
if(value.serial) if(value.serial)
{ {
printer(out, stop, printer.object, string_view{value}); printer(buf, printer.object, string_view{value});
return; return;
} }
assert(value.object); assert(value.object);
serialize(*value.object, out, stop); stringify(buf, *value.object);
}); });
const auto print_array([&stop, &out](const value &value) const auto print_array([&buf](const value &value)
{ {
if(value.serial) if(value.serial)
{ {
//printer(out, stop, printer.array, value); //printer(out, stop, printer.array, value);
const string_view data(value); const string_view data(value);
const auto cpsz(std::min(size_t(stop - out), data.size())); const auto cpsz(std::min(size(buf), data.size()));
memcpy(out, data.data(), cpsz); memcpy(begin(buf), data.data(), cpsz);
out += cpsz; begin(buf) += cpsz;
return; return;
} }
@ -573,27 +500,27 @@ ircd::json::serialize(const index::member *const *const &begin,
//serialize(*value.object, out, stop); //serialize(*value.object, out, stop);
}); });
const auto print_number([&stop, &out](const value &value) const auto print_number([&buf](const value &value)
{ {
if(value.serial) if(value.serial)
{ {
if(value.floats) if(value.floats)
printer(out, stop, double_, string_view{value}); printer(buf, double_, string_view{value});
else else
printer(out, stop, long_, string_view{value}); printer(buf, long_, string_view{value});
return; return;
} }
if(value.floats) if(value.floats)
printer(out, stop, double_, value.floating); printer(buf, double_, value.floating);
else else
printer(out, stop, long_, value.integer); printer(buf, long_, value.integer);
}); });
const auto print_member([&](const index::member &member) const auto print_member([&](const member &member)
{ {
printer(out, stop, printer.name << printer.name_sep, member.first); printer(buf, printer.name << printer.name_sep, member.first);
switch(member.second.type) switch(member.second.type)
{ {
@ -605,40 +532,48 @@ ircd::json::serialize(const index::member *const *const &begin,
} }
}); });
char *const start(out); char *const start(begin(buf));
printer(out, stop, printer.object_begin); printer(buf, printer.object_begin);
auto it(begin); auto it(b);
if(it != end) if(it != e)
{ {
print_member(**it); print_member(**it);
for(++it; it != end; ++it) for(++it; it != e; ++it)
{ {
printer(out, stop, printer.value_sep); printer(buf, printer.value_sep);
print_member(**it); print_member(**it);
} }
} }
printer(out, stop, printer.object_end); printer(buf, printer.object_end);
return string_view{start, out}; return string_view{start, begin(buf)};
} }
ircd::json::ostreamer::ostreamer() 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([&] const auto recurse_array([&a]
{ {
char *out(const_cast<char *>(a.data())); mutable_buffer mb
const auto r(serialize(json::array(a), out, out + a.size())); {
a.resize(size_t(out - r.data())); const_cast<char *>(a.data()), a.size()
};
const auto r(stringify(mb, json::array(a)));
a.resize(r.size());
}); });
const auto recurse_object([&] const auto recurse_object([&a]
{ {
char *out(const_cast<char *>(a.data())); mutable_buffer mb
const auto d(serialize(json::object(a), out, out + a.size())); {
a.resize(size_t(out - d.data())); const_cast<char *>(a.data()), a.size()
};
const auto r(stringify(mb, json::object(a)));
a.resize(r.size());
}); });
const auto quote_string([&] const auto quote_string([&]
@ -735,7 +670,7 @@ ircd::json::operator<<(std::ostream &s, const index &obj)
karma::generate(osi, long_, value.integer); karma::generate(osi, long_, value.integer);
}); });
const auto stream_member([&](const index::member &member) const auto stream_member([&](const 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));
@ -766,6 +701,30 @@ ircd::json::operator<<(std::ostream &s, const index &obj)
return s; return s;
} }
size_t
ircd::json::serialized(const members &m)
{
return serialized(std::begin(m), std::end(m));
}
size_t
ircd::json::serialized(const member *const &begin,
const member *const &end)
{
const size_t ret(1 + !std::distance(begin, end));
return std::accumulate(begin, end, ret, []
(auto ret, const auto &member)
{
return ret += serialized(member) + 1;
});
}
size_t
ircd::json::serialized(const member &member)
{
return serialized(member.first) + 1 + 1 + serialized(member.second);
}
ircd::json::index ircd::json::index
ircd::json::operator+(const object &left, const object &right) ircd::json::operator+(const object &left, const object &right)
{ {
@ -794,7 +753,7 @@ ircd::json::operator+=(index &left, const object &right)
if(deletion) // prevents adding the empty indicator as the new key! if(deletion) // prevents adding the empty indicator as the new key!
continue; continue;
left.idx.emplace_back(index::member{b}); left.idx.emplace_back(member{b});
continue; continue;
} }
@ -804,12 +763,12 @@ ircd::json::operator+=(index &left, const object &right)
continue; continue;
} }
auto &a(const_cast<index::member &>(*it)); auto &a(const_cast<member &>(*it));
switch(type(a.second)) switch(type(a.second))
{ {
default: default:
{ {
a = index::member{b}; a = member{b};
continue; continue;
} }
@ -825,7 +784,7 @@ ircd::json::operator+=(index &left, const object &right)
continue; continue;
} }
a = index::member{string_view{a.first}, std::move(merged)}; a = member{string_view{a.first}, std::move(merged)};
continue; continue;
} }
} }
@ -839,15 +798,15 @@ ircd::json::index::index(recursive_t recursive,
:idx{object.count()} :idx{object.count()}
{ {
std::transform(std::begin(object), std::end(object), std::begin(idx), [&] std::transform(std::begin(object), std::end(object), std::begin(idx), [&]
(const object::member &m) -> index::member (const object::member &m) -> member
{ {
switch(type(m.second)) switch(type(m.second))
{ {
case OBJECT: case OBJECT:
return index::member{m.first, std::make_unique<index>(recursive, m.second)}; return member{m.first, std::make_unique<index>(recursive, m.second)};
default: default:
return index::member{m}; return member{m};
}; };
}); });
} }
@ -856,9 +815,9 @@ ircd::json::index::index(const object &object)
:idx{object.count()} :idx{object.count()}
{ {
std::transform(std::begin(object), std::end(object), std::begin(idx), [] std::transform(std::begin(object), std::end(object), std::begin(idx), []
(const object::member &m) -> index::member (const object::member &m) -> member
{ {
return index::member{m}; return member{m};
}); });
} }
@ -945,35 +904,26 @@ const
} }
size_t size_t
ircd::json::size(const index::member *const &begin, ircd::json::serialized(const index &index)
const index::member *const &end)
{ {
const size_t ret(1 + !std::distance(begin, end)); return index.serialized();
return std::accumulate(begin, end, ret, []
(auto ret, const auto &member)
{
return ret += member.first.size() + 1 + 1 + member.second.size() + 1;
});
} }
size_t size_t
ircd::json::index::size() ircd::json::index::serialized()
const const
{ {
const size_t ret(1 + idx.empty()); const member *const &begin(&idx.front());
return std::accumulate(std::begin(idx), std::end(idx), ret, [] const member *const &end(begin + idx.size());
(auto ret, const auto &member) return json::serialized(begin, end);
{
return ret += member.first.size() + 1 + 1 + member.second.size() + 1;
});
} }
ircd::json::index::operator std::string() ircd::json::index::operator std::string()
const const
{ {
std::string ret(size(), char()); const member *const &begin(&idx.front());
ret.resize(print(const_cast<char *>(ret.data()), ret.size() + 1, *this)); const member *const &end(begin + idx.size());
return ret; return json::string(begin, end);
} }
ircd::json::value::~value() ircd::json::value::~value()
@ -1059,14 +1009,20 @@ const
} }
size_t size_t
ircd::json::value::size() ircd::json::serialized(const value &value)
{
return value.serialized();
}
size_t
ircd::json::value::serialized()
const const
{ {
switch(type) switch(type)
{ {
case NUMBER: return lex_cast(integer).size(); case NUMBER: return lex_cast(integer).size();
case STRING: return 1 + len + 1; case STRING: return 1 + len + 1;
case OBJECT: return serial? len : object->size(); case OBJECT: return serial? len : object->serialized();
case ARRAY: return serial? len : 2; case ARRAY: return serial? len : 2;
case LITERAL: return len; case LITERAL: return len;
}; };
@ -1165,33 +1121,22 @@ ircd::json::operator==(const value &a, const value &b)
return static_cast<string_view>(a) == static_cast<string_view>(b); return static_cast<string_view>(a) == static_cast<string_view>(b);
} }
size_t ircd::string_view
ircd::json::print(char *const &buf, ircd::json::stringify(mutable_buffer &buf,
const size_t &max, const object &object)
const object &object)
{
if(unlikely(!max))
return 0;
char *out(buf);
serialize(object, out, out + (max - 1));
*out = '\0';
return std::distance(buf, out);
}
ircd::json::object
ircd::json::serialize(const object &object,
char *&out,
char *const &stop)
{ {
static const auto throws([] static const auto throws([]
{ {
throw print_error("The JSON generator failed to print object"); throw print_error("The JSON generator failed to print object");
}); });
char *const start(out); char *const start(begin(buf));
karma::generate(out, maxwidth(stop - start)[printer.object] | eps[throws], object); karma::generate(begin(buf), maxwidth(size(buf))[printer.object] | eps[throws], object);
return string_view{start, out};
return string_view
{
start, begin(buf)
};
} }
std::ostream & std::ostream &
@ -1279,43 +1224,28 @@ const
return { string_view::end(), string_view::end() }; return { string_view::end(), string_view::end() };
} }
size_t ircd::string_view
ircd::json::print(char *const &buf, ircd::json::stringify(mutable_buffer &b,
const size_t &max, const array &a)
const array &arr)
{
if(unlikely(!max))
return 0;
char *out(buf);
serialize(arr, out, out + (max - 1));
*out = '\0';
return std::distance(buf, out);
}
ircd::json::array
ircd::json::serialize(const array &a,
char *&out,
char *const &stop)
{ {
static const auto throws([] static const auto throws([]
{ {
throw print_error("The JSON generator failed to print array"); throw print_error("The JSON generator failed to print array");
}); });
char *const start(out); char *const start(begin(b));
karma::generate(out, maxwidth(stop - out)[printer.array_begin] | eps[throws]); karma::generate(begin(b), maxwidth(size(b))[printer.array_begin] | eps[throws]);
auto it(begin(a)); auto it(begin(a));
if(it != end(a)) if(it != end(a))
{ {
karma::generate(out, maxwidth(stop - out)[printer.elem] | eps[throws], *it); karma::generate(begin(b), maxwidth(size(b))[printer.elem] | eps[throws], *it);
for(++it; it != end(a); ++it) for(++it; it != end(a); ++it)
karma::generate(out, maxwidth(stop - out)[printer.value_sep << printer.elem] | eps[throws], *it); karma::generate(begin(b), maxwidth(size(b))[printer.value_sep << printer.elem] | eps[throws], *it);
} }
karma::generate(out, maxwidth(stop - out)[printer.array_end] | eps[throws]); karma::generate(begin(b), maxwidth(size(b))[printer.array_end] | eps[throws]);
return string_view{start, out}; return string_view{start, begin(b)};
} }
std::ostream & std::ostream &
@ -1389,6 +1319,27 @@ const
return { string_view::end(), string_view::end() }; return { string_view::end(), string_view::end() };
} }
size_t
ircd::json::serialized(const string_view &s)
{
switch(type(s, std::nothrow))
{
case NUMBER:
case OBJECT:
case ARRAY:
case LITERAL:
return s.size();
case STRING:
break;
}
size_t ret(s.size());
ret += !startswith(s, '"');
ret += !endswith(s, '"');
return ret;
}
enum ircd::json::type enum ircd::json::type
ircd::json::type(const string_view &buf) ircd::json::type(const string_view &buf)
{ {

View file

@ -99,11 +99,11 @@ ircd::m::init::init()
modules.emplace("root.so"s, "root.so"s); modules.emplace("root.so"s, "root.so"s);
//TODO: conf obviously
listener = new ircd::listener listener = new ircd::listener
{ {
//TODO: conf obviously json::string(json::members
json::string {
({
{ "name", "Chat Matrix" }, { "name", "Chat Matrix" },
{ "host", "0.0.0.0" }, { "host", "0.0.0.0" },
{ "port", 8447 }, { "port", 8447 },
@ -141,7 +141,7 @@ ircd::m::bootstrap()
const auto type{"m.room.create"}; const auto type{"m.room.create"};
char content[512]; char content[512];
json::print(content, sizeof(content), print(content, sizeof(content), json::members
{ {
{ "creator", user_id }, { "creator", user_id },
}); });
@ -162,7 +162,7 @@ ircd::m::bootstrap()
const auto type{"m.room.member"}; const auto type{"m.room.member"};
char content[512]; char content[512];
json::print(content, sizeof(content), print(content, sizeof(content), json::members
{ {
{ "membership", "join" }, { "membership", "join" },
}); });
@ -438,7 +438,7 @@ ircd::m::room::membership(const m::id::user &user_id,
{ "type", "m.room.member" }, { "type", "m.room.member" },
{ "state_key", user_id }, { "state_key", user_id },
{ "sender", user_id }, { "sender", user_id },
{ "content", json::stringify(cbuf, sizeof(cbuf), content) } { "content", stringify(cbuf, content) }
}); });
} }

View file

@ -257,8 +257,13 @@ ircd::resource::response::response(client &client,
const http::code &code) const http::code &code)
try try
{ {
char cbuf[8192], *out(cbuf); char cbuf[8192];
const auto object(serialize(index, out, cbuf + sizeof(cbuf))); mutable_buffer buf{cbuf};
const json::object object
{
stringify(buf, index)
};
response(client, object, code); response(client, object, code);
} }
catch(const json::error &e) catch(const json::error &e)