0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-01 19:22:53 +01:00

ircd::json: Improve object interface; remove dot traversal.

This commit is contained in:
Jason Volk 2017-08-23 02:36:54 -06:00
parent e99b22de6f
commit df87d820e1

View file

@ -63,26 +63,31 @@ struct object
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
using key_compare = std::less<member>; using key_compare = std::less<member>;
// fundamental
const_iterator end() const; const_iterator end() const;
const_iterator begin() const; const_iterator begin() const;
const_iterator find(const string_view &key) const;
bool has(const string_view &name) const; // util
const_iterator find(const string_view &name) const;
size_t count() const; size_t count() const;
bool has(const string_view &key) const;
string_view at(const string_view &name) const; // returns value or default
template<class T> T at(const string_view &name) const; template<class T> T get(const string_view &key, const T &def = T{}) const;
string_view operator[](const string_view &name) const; string_view get(const string_view &key, const string_view &def = {}) const;
template<class T = string_view> T get(const string_view &name, const T &def = T()) const;
string_view get(const string_view &name, const string_view &def = {}) const;
// returns value or throws not_found
template<class T> T at(const string_view &key) const;
string_view at(const string_view &key) const;
// returns value or empty
string_view operator[](const string_view &key) const;
// rewrite-copy into string
explicit operator std::string() const; explicit operator std::string() const;
// constructor
using string_view::string_view; using string_view::string_view;
friend object serialize(const object &, char *&buf, char *const &stop);
friend size_t print(char *const &buf, const size_t &max, const object &);
friend std::ostream &operator<<(std::ostream &, const object &);
}; };
struct object::member struct object::member
@ -136,88 +141,170 @@ struct object::const_iterator
friend bool operator>(const const_iterator &, const const_iterator &); friend bool operator>(const const_iterator &, const const_iterator &);
}; };
bool has(object, const path &path);
bool has(const object &, const string_view &key);
template<class T = string_view> T get(object, const path &, const T &def = T{});
template<class T = string_view> T get(const object &, const string_view &key, const T &def = T{});
template<class T = string_view> T at(object, const path &);
template<class T = string_view> T at(const object &, const string_view &key);
object serialize(const object &, char *&buf, char *const &stop);
size_t print(char *const &buf, const size_t &max, const object &);
std::ostream &operator<<(std::ostream &, const object &);
} // namespace json } // namespace json
} // namespace ircd } // namespace ircd
inline ircd::string_view template<class T>
ircd::json::object::get(const string_view &name, T
const string_view &def) ircd::json::at(const object &object,
const const string_view &key)
{ {
const string_view sv(operator[](name)); return object.at<T>(key);
return !sv.empty()? sv : def;
} }
template<class T> template<class T>
T T
ircd::json::object::get(const string_view &name, ircd::json::at(object object,
const T &def) const path &path)
{
const auto it(std::find_if(std::begin(path), std::end(path), [&object]
(const string_view &key)
{
const auto it(object.find(key));
if(it == std::end(object))
throw not_found("'%s'", key);
object = it->second;
return false;
}));
return lex_cast<T>(object);
}
template<class T>
T
ircd::json::get(const object &object,
const string_view &key,
const T &def)
{
return object.get<T>(key, def);
}
template<class T>
T
ircd::json::get(object object,
const path &path,
const T &def)
{
const auto it(std::find_if(std::begin(path), std::end(path), [&object]
(const string_view &key)
{
const auto it(object.find(key));
if(it == std::end(object))
return true;
object = it->second;
return false;
}));
return it == std::end(path)? lex_cast<T>(object) : def;
}
inline bool
ircd::json::has(const object &object,
const string_view &key)
{
return object.has(key);
}
inline bool
ircd::json::has(object object,
const path &path)
{
const auto it(std::find_if(std::begin(path), std::end(path), [&object]
(const string_view &key)
{
const auto val(object[key]);
if(val.empty())
return true;
object = val;
return false;
}));
// && path.size() ensures false for empty path.
return it == std::end(path) && path.size();
}
inline ircd::string_view
ircd::json::object::operator[](const string_view &key)
const
{
const auto it(find(key));
return it != end()? it->second : string_view{};
}
template<class T>
T
ircd::json::object::at(const string_view &key)
const try const try
{ {
const string_view sv(operator[](name)); return lex_cast<T>(at(key));
}
catch(const bad_lex_cast &e)
{
throw type_error("'%s' must cast to type %s",
key,
typeid(T).name());
}
inline ircd::string_view
ircd::json::object::at(const string_view &key)
const
{
const auto it(find(key));
if(it == end())
throw not_found("'%s'", key);
return it->second;
}
template<class T>
T
ircd::json::object::get(const string_view &key,
const T &def)
const try
{
const string_view sv(operator[](key));
return !sv.empty()? lex_cast<T>(sv) : def; return !sv.empty()? lex_cast<T>(sv) : def;
} }
catch(const bad_lex_cast &e) catch(const bad_lex_cast &e)
{ {
throw type_error("'%s' must cast to type %s", name, typeid(T).name()); throw type_error("'%s' must cast to type %s",
key,
typeid(T).name());
} }
inline ircd::string_view inline ircd::string_view
ircd::json::object::operator[](const string_view &name) ircd::json::object::get(const string_view &key,
const string_view &def)
const const
{ {
const auto p(split(name, '.')); const string_view sv(operator[](key));
const auto it(find(p.first)); return !sv.empty()? sv : def;
if(it == end())
return {};
if(!p.second.empty())
{
const object d(it->second);
return d[p.second];
}
return it->second;
}
template<class T>
T
ircd::json::object::at(const string_view &name)
const try
{
return lex_cast<T>(at(name));
}
catch(const bad_lex_cast &e)
{
throw type_error("'%s' must cast to type %s", name, typeid(T).name());
}
inline ircd::string_view
ircd::json::object::at(const string_view &name)
const
{
const auto p(split(name, '.'));
const auto it(find(p.first));
if(unlikely(it == end()))
throw not_found("'%s'", p.first);
if(!p.second.empty())
{
const object d(it->second);
return d.at(p.second);
}
return it->second;
} }
inline ircd::json::object::const_iterator inline ircd::json::object::const_iterator
ircd::json::object::find(const string_view &name) ircd::json::object::find(const string_view &key)
const const
{ {
return std::find_if(begin(), end(), [&name] return std::find_if(begin(), end(), [&key]
(const auto &member) (const auto &member)
{ {
return member.first == name; return member.first == key;
}); });
} }
@ -229,19 +316,10 @@ const
} }
inline bool inline bool
ircd::json::object::has(const string_view &name) ircd::json::object::has(const string_view &key)
const const
{ {
const auto p(split(name, '.')); return find(key) != end();
const auto it(find(p.first));
if(it == end())
return false;
if(p.second.empty())
return true;
const object d(it->second);
return d.has(p.second);
} }
inline bool inline bool