0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-17 15:30:52 +01:00

ircd::json: Recursive tuple members.

This commit is contained in:
Jason Volk 2017-09-20 19:33:50 -07:00
parent 7f548cee1c
commit 44f3d2cd27
3 changed files with 158 additions and 96 deletions

View file

@ -204,10 +204,25 @@ const
if(stale) if(stale)
{ {
for(const auto &cell : row) for(const auto &cell : row)
if(cell.valid(idx->first)) {
json::set(v, cell.col(), cell.val()); const column &c{cell};
const database::descriptor &desc{describe(c)};
if(desc.type.second == typeid(string_view))
{
if(cell.valid(idx->first))
json::set(v, cell.col(), cell.val());
else
json::set(v, cell.col(), string_view{});
}
else else
json::set(v, cell.col(), string_view{}); {
if(cell.valid(idx->first))
json::set(v, cell.col(), byte_view<string_view>{cell.val()});
else
json::set(v, cell.col(), byte_view<string_view>{string_view{}});
}
}
stale = false; stale = false;
} }

View file

@ -43,17 +43,13 @@ struct ircd::json::property
operator const T &() const; operator const T &() const;
operator T &(); operator T &();
property(T&& value); property(T&& value)
:value{value}
{}
property() = default; property() = default;
}; };
template<const char *const &name,
class T>
ircd::json::property<name, T>::property(T&& value)
:value{value}
{
}
template<const char *const &name, template<const char *const &name,
class T> class T>
ircd::json::property<name, T>::operator ircd::json::property<name, T>::operator

View file

@ -257,7 +257,7 @@ at(const tuple &t)
using value_type = tuple_value_type<tuple, idx>; using value_type = tuple_value_type<tuple, idx>;
//TODO: does tcmalloc zero this or huh? //TODO: undefined
if(ret == value_type{}) if(ret == value_type{})
throw not_found("%s", name); throw not_found("%s", name);
@ -281,7 +281,7 @@ at(tuple &t)
using value_type = tuple_value_type<tuple, idx>; using value_type = tuple_value_type<tuple, idx>;
//TODO: does tcmalloc zero this or huh? //TODO: undefined
if(ret == value_type{}) if(ret == value_type{})
throw not_found("%s", name); throw not_found("%s", name);
@ -306,29 +306,32 @@ get(const tuple<T...> &t,
using value_type = tuple_value_type<tuple<T...>, idx>; using value_type = tuple_value_type<tuple<T...>, idx>;
//TODO: does tcmalloc zero this or huh? //TODO: undefined
return ret != value_type{}? ret : def; return ret != value_type{}? ret : def;
} }
template<const char *const &name,
class... T>
tuple_value_type<tuple<T...>, indexof<tuple<T...>>(name)> &
get(tuple<T...> &t)
{
constexpr size_t idx
{
indexof<tuple<T...>>(name)
};
return val<idx>(t);
}
template<const char *const &name, template<const char *const &name,
class... T> class... T>
tuple_value_type<tuple<T...>, indexof<tuple<T...>>(name)> & tuple_value_type<tuple<T...>, indexof<tuple<T...>>(name)> &
get(tuple<T...> &t, get(tuple<T...> &t,
tuple_value_type<tuple<T...>, indexof<tuple<T...>>(name)> &def) tuple_value_type<tuple<T...>, indexof<tuple<T...>>(name)> &def)
{ {
constexpr size_t idx //TODO: undefined
{ auto &ret{get<name, T...>(t)};
indexof<tuple<T...>>(name) using value_type = decltype(ret);
};
auto &ret
{
val<idx>(t)
};
using value_type = tuple_value_type<tuple<T...>, idx>;
//TODO: does tcmalloc zero this or huh?
return ret != value_type{}? ret : def; return ret != value_type{}? ret : def;
} }
@ -544,82 +547,151 @@ at(const tuple &t,
at<tuple, function, i + 1>(t, name, std::forward<function>(f)); at<tuple, function, i + 1>(t, name, std::forward<function>(f));
} }
template<class dst,
class src>
typename std::enable_if
<
std::is_convertible<src, dst>::value,
void>::type
_assign(dst &d,
src&& s)
{
d = std::forward<src>(s);
}
template<class dst,
class src>
typename std::enable_if
<
std::is_arithmetic<dst>() &&
std::is_base_of<std::string_view, typename std::remove_reference<src>::type>() &&
!std::is_base_of<ircd::byte_view<ircd::string_view>, typename std::remove_reference<src>::type>(),
void>::type
_assign(dst &d,
src&& s)
try
{
d = lex_cast<dst>(std::forward<src>(s));
}
catch(const bad_lex_cast &e)
{
throw parse_error("cannot convert '%s' to '%s'",
demangle<src>(),
demangle<dst>());
}
template<class dst,
class src>
typename std::enable_if
<
std::is_arithmetic<dst>() &&
std::is_base_of<ircd::byte_view<ircd::string_view>, typename std::remove_reference<src>::type>(),
void>::type
_assign(dst &d,
src&& s)
{
d = byte_view<dst>(std::forward<src>(s));
}
template<class dst,
class src>
typename std::enable_if
<
std::is_base_of<std::string_view, dst>() &&
std::is_pod<typename std::remove_reference<src>::type>(),
void>::type
_assign(dst &d,
src&& s)
{
d = byte_view<dst>(std::forward<src>(s));
}
template<class dst,
class src>
typename std::enable_if
<
ircd::json::is_tuple<dst>(),
void>::type
_assign(dst &d,
src&& s)
{
d = dst{std::forward<src>(s)};
}
template<class V, template<class V,
class... T> class... T>
tuple<T...> & tuple<T...> &
set(tuple<T...> &t, set(tuple<T...> &t,
const string_view &key, const string_view &key,
const V &val) V&& val)
try
{ {
at(t, key, [&key, &val] at(t, key, [&key, &val]
(auto &target) (auto &target)
{ {
using target_type = decltype(target); _assign(target, std::forward<V>(val));
using cast_type = typename std::remove_reference<target_type>::type;
target = byte_view<cast_type>(val);
}); });
return t; return t;
} }
catch(const std::exception &e)
{
throw parse_error("failed to set member '%s': %s",
key,
e.what());
}
template<class... T>
tuple<T...> &
set(tuple<T...> &t,
const string_view &key,
const json::value &value)
{
switch(type(value))
{
case type::STRING:
case type::LITERAL:
set(t, key, string_view{value});
break;
case type::NUMBER:
if(value.floats)
set(t, key, value.floating);
else
set(t, key, value.integer);
break;
case type::OBJECT:
case type::ARRAY:
if(unlikely(!value.serial))
throw print_error("Type %s must be JSON to be used by tuple member '%s'",
reflect(type(value)),
key);
set(t, key, string_view{value});
break;
}
return t;
}
template<class... T> template<class... T>
tuple<T...>::tuple(const json::object &object) tuple<T...>::tuple(const json::object &object)
{ {
//TODO: is tcmalloc zero-initializing all tuple elements, or is something else doing that?
std::for_each(std::begin(object), std::end(object), [this] std::for_each(std::begin(object), std::end(object), [this]
(const auto &member) (const auto &member)
{ {
at(*this, member.first, [&member] set(*this, member.first, member.second);
(auto &target)
{
using target_type = decltype(target);
using cast_type = typename std::remove_reference<target_type>::type; try
{
target = lex_cast<cast_type>(member.second);
}
catch(const bad_lex_cast &e)
{
throw parse_error("member '%s' must convert to '%s'",
member.first,
typeid(target_type).name());
}
});
}); });
} }
template<class... T> template<class... T>
tuple<T...>::tuple(const json::iov &iov) tuple<T...>::tuple(const json::iov &iov)
{ {
//TODO: is tcmalloc zero-initializing all tuple elements, or is something else doing that?
std::for_each(std::begin(iov), std::end(iov), [this] std::for_each(std::begin(iov), std::end(iov), [this]
(const auto &member) (const auto &member)
{ {
switch(type(member.second)) set(*this, member.first, member.second);
{
case type::OBJECT:
case type::ARRAY:
if(unlikely(!member.second.serial))
throw print_error("iov member '%s' must be JSON to be used by the tuple",
string_view{member.first});
default:
break;
}
at(*this, member.first, [&member]
(auto &target)
{
using target_type = decltype(target);
using cast_type = typename std::remove_reference<target_type>::type; try
{
target = static_cast<cast_type>(member.second);
}
catch(const bad_lex_cast &e)
{
throw parse_error("member '%s' must convert to '%s'",
member.first,
typeid(target_type).name());
}
});
}); });
} }
@ -629,28 +701,7 @@ tuple<T...>::tuple(const std::initializer_list<member> &members)
std::for_each(std::begin(members), std::end(members), [this] std::for_each(std::begin(members), std::end(members), [this]
(const auto &member) (const auto &member)
{ {
switch(type(member.second)) set(*this, member.first, member.second);
{
case type::STRING:
case type::LITERAL:
set(*this, member.first, string_view{member.second});
break;
case type::NUMBER:
if(member.second.floats)
set(*this, member.first, member.second.floating);
else
set(*this, member.first, member.second.integer);
break;
case type::ARRAY:
case type::OBJECT:
if(!member.second.serial)
throw parse_error("Unserialized value not supported yet");
set(*this, member.first, string_view{member.second});
break;
}
}); });
} }