2017-08-23 23:32:28 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2017 Charybdis Development Team
|
|
|
|
* Copyright (C) 2017 Jason Volk <jason@zemos.net>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice is present in all copies.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
2017-08-26 06:39:36 +02:00
|
|
|
#define HAVE_IRCD_JSON_TUPLE_H
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
namespace ircd {
|
|
|
|
namespace json {
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
struct tuple_base
|
2017-08-23 23:32:28 +02:00
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
// class must be empty for EBO
|
2017-08-23 23:32:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<class... T>
|
2017-08-26 06:39:36 +02:00
|
|
|
struct tuple
|
|
|
|
:tuple_base
|
2017-08-23 23:32:28 +02:00
|
|
|
,std::tuple<T...>
|
|
|
|
{
|
|
|
|
using tuple_type = std::tuple<T...>;
|
|
|
|
|
|
|
|
static constexpr size_t size()
|
|
|
|
{
|
|
|
|
return std::tuple_size<tuple_type>();
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
using std::tuple<T...>::tuple;
|
2017-08-23 23:32:28 +02:00
|
|
|
};
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple>
|
|
|
|
using tuple_type = typename tuple::tuple_type;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple>
|
|
|
|
using tuple_size = std::tuple_size<tuple_type<tuple>>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
template<size_t i,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple>
|
|
|
|
using tuple_element = typename std::tuple_element<i, tuple_type<tuple>>::type;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr auto &
|
2017-08-26 06:39:36 +02:00
|
|
|
stdcast(const tuple &o)
|
2017-08-23 23:32:28 +02:00
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
return static_cast<const typename tuple::tuple_type &>(o);
|
2017-08-23 23:32:28 +02:00
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr auto &
|
2017-08-26 06:39:36 +02:00
|
|
|
stdcast(tuple &o)
|
2017-08-23 23:32:28 +02:00
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
return static_cast<typename tuple::tuple_type &>(o);
|
2017-08-23 23:32:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class... T>
|
|
|
|
constexpr auto
|
2017-08-26 06:39:36 +02:00
|
|
|
size(const tuple<T...> &t)
|
2017-08-23 23:32:28 +02:00
|
|
|
{
|
|
|
|
return t.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i,
|
|
|
|
class... T>
|
|
|
|
constexpr auto &
|
2017-08-26 06:39:36 +02:00
|
|
|
get(const tuple<T...> &t)
|
2017-08-23 23:32:28 +02:00
|
|
|
{
|
|
|
|
return std::get<i>(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i,
|
|
|
|
class... T>
|
|
|
|
constexpr auto &
|
2017-08-26 06:39:36 +02:00
|
|
|
get(tuple<T...> &t)
|
2017-08-23 23:32:28 +02:00
|
|
|
{
|
|
|
|
return std::get<i>(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr const char *
|
2017-08-26 06:39:36 +02:00
|
|
|
reflect(const tuple &t)
|
2017-08-23 23:32:28 +02:00
|
|
|
{
|
|
|
|
return t._member_(i);
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
#define IRCD_MEMBERS(_vals_...) \
|
|
|
|
static constexpr const char *_member_(const size_t i) \
|
|
|
|
{ \
|
|
|
|
constexpr const char *const val[] \
|
|
|
|
{ \
|
|
|
|
_vals_ \
|
|
|
|
}; \
|
|
|
|
\
|
|
|
|
return val[i]; \
|
|
|
|
}
|
|
|
|
|
2017-08-23 23:32:28 +02:00
|
|
|
template<size_t i,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i == tuple_size<tuple>::value, void>::type
|
|
|
|
for_each(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{}
|
|
|
|
|
|
|
|
template<size_t i,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i == tuple_size<tuple>::value, void>::type
|
|
|
|
for_each(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{}
|
|
|
|
|
|
|
|
template<size_t i = 0,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>::value, void>::type
|
|
|
|
for_each(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
f(reflect<i>(t), static_cast<const type &>(get<i>(t)));
|
|
|
|
for_each<i + 1>(t, std::forward<function>(f));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i = 0,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>::value, void>::type
|
|
|
|
for_each(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
f(reflect<i>(t), static_cast<type &>(get<i>(t)));
|
|
|
|
for_each<i + 1>(t, std::forward<function>(f));
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
|
|
|
ssize_t i>
|
|
|
|
constexpr
|
|
|
|
typename std::enable_if<(i < 0), void>::type
|
2017-08-26 06:39:36 +02:00
|
|
|
rfor_each(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
|
|
|
ssize_t i>
|
|
|
|
constexpr
|
|
|
|
typename std::enable_if<(i < 0), void>::type
|
2017-08-26 06:39:36 +02:00
|
|
|
rfor_each(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
2017-08-26 06:39:36 +02:00
|
|
|
ssize_t i = tuple_size<tuple>() - 1>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>(), void>::type
|
|
|
|
rfor_each(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
f(reflect<i>(t), static_cast<const type &>(get<i>(t)));
|
2017-08-26 06:39:36 +02:00
|
|
|
rfor_each<tuple, function, i - 1>(t, std::forward<function>(f));
|
2017-08-23 23:32:28 +02:00
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
2017-08-26 06:39:36 +02:00
|
|
|
ssize_t i = tuple_size<tuple>() - 1>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>(), void>::type
|
|
|
|
rfor_each(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
f(reflect<i>(t), static_cast<type &>(get<i>(t)));
|
2017-08-26 06:39:36 +02:00
|
|
|
rfor_each<tuple, function, i - 1>(t, std::forward<function>(f));
|
2017-08-23 23:32:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i == tuple_size<tuple>::value, bool>::type
|
|
|
|
until(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i == tuple_size<tuple>::value, bool>::type
|
|
|
|
until(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i = 0,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>::value, bool>::type
|
|
|
|
until(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
const auto &value(static_cast<const type &>(get<i>(t)));
|
|
|
|
return f(reflect<i>(t), value)?
|
|
|
|
until<i + 1>(t, std::forward<function>(f)):
|
|
|
|
false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t i = 0,
|
2017-08-26 06:39:36 +02:00
|
|
|
class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>::value, bool>::type
|
|
|
|
until(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
auto &value(static_cast<type &>(get<i>(t)));
|
|
|
|
return f(reflect<i>(t), value)?
|
|
|
|
until<i + 1>(t, std::forward<function>(f)):
|
|
|
|
false;
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
|
|
|
ssize_t i>
|
|
|
|
constexpr
|
|
|
|
typename std::enable_if<(i < 0), bool>::type
|
2017-08-26 06:39:36 +02:00
|
|
|
runtil(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
|
|
|
ssize_t i>
|
|
|
|
constexpr
|
|
|
|
typename std::enable_if<(i < 0), bool>::type
|
2017-08-26 06:39:36 +02:00
|
|
|
runtil(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
2017-08-26 06:39:36 +02:00
|
|
|
ssize_t i = tuple_size<tuple>() - 1>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>::value, bool>::type
|
|
|
|
runtil(const tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
const auto &value(static_cast<const type &>(get<i>(t)));
|
|
|
|
return f(reflect<i>(t), value)?
|
2017-08-26 06:39:36 +02:00
|
|
|
runtil<tuple, function, i - 1>(t, std::forward<function>(f)):
|
2017-08-23 23:32:28 +02:00
|
|
|
false;
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function,
|
2017-08-26 06:39:36 +02:00
|
|
|
ssize_t i = tuple_size<tuple>() - 1>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr
|
2017-08-26 06:39:36 +02:00
|
|
|
typename std::enable_if<i < tuple_size<tuple>::value, bool>::type
|
|
|
|
runtil(tuple &t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
2017-08-26 06:39:36 +02:00
|
|
|
using type = tuple_element<i, tuple>;
|
2017-08-23 23:32:28 +02:00
|
|
|
|
|
|
|
auto &value(static_cast<type &>(get<i>(t)));
|
|
|
|
return f(reflect<i>(t), value)?
|
2017-08-26 06:39:36 +02:00
|
|
|
runtil<tuple, function, i - 1>(t, std::forward<function>(f)):
|
2017-08-23 23:32:28 +02:00
|
|
|
false;
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr size_t
|
2017-08-26 06:39:36 +02:00
|
|
|
indexof(tuple&& t,
|
2017-08-23 23:32:28 +02:00
|
|
|
const string_view &name)
|
|
|
|
{
|
|
|
|
size_t ret(0);
|
|
|
|
const auto res(until(t, [&ret, &name]
|
|
|
|
(const string_view &key, auto&& member)
|
|
|
|
{
|
|
|
|
if(key == name)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
++ret;
|
|
|
|
return true;
|
|
|
|
}));
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
return !res? ret : throw std::out_of_range("tuple has no member with that name");
|
2017-08-23 23:32:28 +02:00
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr bool
|
2017-08-26 06:39:36 +02:00
|
|
|
at(tuple&& t,
|
2017-08-23 23:32:28 +02:00
|
|
|
const string_view &name,
|
|
|
|
function&& f)
|
|
|
|
{
|
|
|
|
return until(t, [&name, &f]
|
|
|
|
(const string_view &key, auto&& member)
|
|
|
|
{
|
|
|
|
if(key != name)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
f(member);
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple>
|
2017-08-23 23:32:28 +02:00
|
|
|
constexpr void
|
2017-08-26 06:39:36 +02:00
|
|
|
keys(tuple&& t,
|
2017-08-23 23:32:28 +02:00
|
|
|
const std::function<void (string_view)> &f)
|
|
|
|
{
|
|
|
|
for_each(t, [&f]
|
|
|
|
(const char *const key, auto&& member)
|
|
|
|
{
|
|
|
|
f(key);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple,
|
2017-08-23 23:32:28 +02:00
|
|
|
class function>
|
|
|
|
constexpr void
|
2017-08-26 06:39:36 +02:00
|
|
|
values(tuple&& t,
|
2017-08-23 23:32:28 +02:00
|
|
|
function&& f)
|
|
|
|
{
|
|
|
|
for_each(t, [&f]
|
|
|
|
(const char *const key, auto&& member)
|
|
|
|
{
|
|
|
|
f(member);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:39:36 +02:00
|
|
|
template<class tuple>
|
|
|
|
tuple &
|
|
|
|
assign_tuple(tuple &ret,
|
|
|
|
const json::object &object)
|
|
|
|
{
|
|
|
|
std::for_each(std::begin(object), std::end(object), [&ret](auto &&member)
|
|
|
|
{
|
|
|
|
at(ret, member.first, [&member](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 tuple_error("member \"%s\" must convert to '%s'",
|
|
|
|
member.first,
|
|
|
|
typeid(target_type).name());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class tuple>
|
|
|
|
tuple
|
|
|
|
make_tuple(const json::object &object)
|
|
|
|
{
|
|
|
|
tuple ret;
|
|
|
|
assign_tuple(ret, object);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-23 23:32:28 +02:00
|
|
|
} // namespace json
|
|
|
|
} // namespace ircd
|