0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-05-19 19:33:45 +02:00

ircd::util: Refactor tuple tools w/ if constexpr; remove until().

This commit is contained in:
Jason Volk 2022-06-30 12:21:14 -07:00
parent 4cf3476e7b
commit 642165a8bd
2 changed files with 123 additions and 252 deletions

View file

@ -44,45 +44,66 @@ size(const std::tuple<args...> &t)
// //
// for_each(tuple, [](auto&& elem) { ... }); // for_each(tuple, [](auto&& elem) { ... });
template<size_t i,
class func,
class... args>
constexpr typename std::enable_if<i == std::tuple_size<std::tuple<args...>>::value, void>::type
for_each(std::tuple<args...> &t,
func&& f)
{}
template<size_t i,
class func,
class... args>
constexpr
typename std::enable_if<i == std::tuple_size<std::tuple<args...>>::value, void>::type
for_each(const std::tuple<args...> &t,
func&& f)
{}
template<size_t i = 0, template<size_t i = 0,
class func, class func,
class... args> class... args>
constexpr constexpr inline bool
typename std::enable_if<i < std::tuple_size<std::tuple<args...>>::value, void>::type
for_each(const std::tuple<args...> &t, for_each(const std::tuple<args...> &t,
func&& f) func&& f)
{ {
f(std::get<i>(t)); if constexpr(i < size<std::tuple<args...>>())
for_each<i+1>(t, std::forward<func>(f)); {
using closure_result = std::invoke_result_t
<
decltype(f), decltype(std::get<i>(t))
>;
constexpr bool terminable
{
std::is_same<closure_result, bool>()
};
if constexpr(terminable)
{
if(!f(std::get<i>(t)))
return false;
}
else f(std::get<i>(t));
return for_each<i + 1, func, args...>(t, std::forward<func>(f));
}
else return true;
} }
template<size_t i = 0, template<size_t i = 0,
class func, class func,
class... args> class... args>
constexpr constexpr inline bool
typename std::enable_if<i < std::tuple_size<std::tuple<args...>>::value, void>::type
for_each(std::tuple<args...> &t, for_each(std::tuple<args...> &t,
func&& f) func&& f)
{ {
f(std::get<i>(t)); if constexpr(i < size<std::tuple<args...>>())
for_each<i+1>(t, std::forward<func>(f)); {
using closure_result = std::invoke_result_t
<
decltype(f), decltype(std::get<i>(t))
>;
constexpr bool terminable
{
std::is_same<closure_result, bool>()
};
if constexpr(terminable)
{
if(!f(std::get<i>(t)))
return false;
}
else f(std::get<i>(t));
return for_each<i + 1, func, args...>(t, std::forward<func>(f));
}
else return true;
} }
// //
@ -90,234 +111,92 @@ for_each(std::tuple<args...> &t,
// //
// rfor_each(tuple, [](auto&& elem) { ... }); // rfor_each(tuple, [](auto&& elem) { ... });
template<ssize_t i, template<class func,
class func, class... args,
class... args> ssize_t i = size<std::tuple<args...>>() - 1>
constexpr constexpr inline bool
typename std::enable_if<i == 0, void>::type
rfor_each(const std::tuple<args...> &t,
func&& f)
{}
template<ssize_t i,
class func,
class... args>
constexpr
typename std::enable_if<i == 0, void>::type
rfor_each(std::tuple<args...> &t,
func&& f)
{}
template<ssize_t i,
class func,
class... args>
constexpr
typename std::enable_if<(i > 0), void>::type
rfor_each(const std::tuple<args...> &t, rfor_each(const std::tuple<args...> &t,
func&& f) func&& f)
{ {
f(std::get<i - 1>(t)); if constexpr(i >= 0)
rfor_each<i - 1>(t, std::forward<func>(f)); {
using closure_result = std::invoke_result_t
<
decltype(f), decltype(std::get<i>(t))
>;
constexpr bool terminable
{
std::is_same<closure_result, bool>()
};
if constexpr(terminable)
{
if(!f(std::get<i>(t)))
return false;
}
else f(std::get<i>(t));
return rfor_each<func, args..., i - 1>(t, std::forward<func>(f));
}
else return true;
} }
template<ssize_t i, template<class func,
class func, class... args,
class... args> ssize_t i = size<std::tuple<args...>>() - 1>
constexpr constexpr inline bool
typename std::enable_if<(i > 0), void>::type
rfor_each(std::tuple<args...> &t, rfor_each(std::tuple<args...> &t,
func&& f) func&& f)
{ {
f(std::get<i - 1>(t)); if constexpr(i >= 0)
rfor_each<i - 1>(t, std::forward<func>(f));
}
template<ssize_t i = -1,
class func,
class... args>
constexpr
typename std::enable_if<(i == -1), void>::type
rfor_each(const std::tuple<args...> &t,
func&& f)
{
constexpr const ssize_t size
{ {
std::tuple_size<std::tuple<args...>>::value using closure_result = std::invoke_result_t
}; <
decltype(f), decltype(std::get<i>(t))
>;
rfor_each<size>(t, std::forward<func>(f)); constexpr bool terminable
} {
std::is_same<closure_result, bool>()
};
template<ssize_t i = -1, if constexpr(terminable)
class func, {
class... args> if(!f(std::get<i>(t)))
constexpr return false;
typename std::enable_if<(i == -1), void>::type }
rfor_each(std::tuple<args...> &t, else f(std::get<i>(t));
func&& f)
{
constexpr const ssize_t size
{
std::tuple_size<std::tuple<args...>>::value
};
rfor_each<size>(t, std::forward<func>(f)); return rfor_each<func, args..., i - 1>(t, std::forward<func>(f));
}
else return true;
} }
// //
// Iteration of a tuple until() style: your closure returns true to continue, false // test() is a logical inversion of for_each() for intuitive find()-like
// to break. until() then remains true to the end, or returns false if not.
template<size_t i,
class func,
class... args>
constexpr
typename std::enable_if<i == std::tuple_size<std::tuple<args...>>::value, bool>::type
until(std::tuple<args...> &t,
func&& f)
{
return true;
}
template<size_t i,
class func,
class... args>
constexpr
typename std::enable_if<i == std::tuple_size<std::tuple<args...>>::value, bool>::type
until(const std::tuple<args...> &t,
func&& f)
{
return true;
}
template<size_t i = 0,
class func,
class... args>
constexpr
typename std::enable_if<i < std::tuple_size<std::tuple<args...>>::value, bool>::type
until(std::tuple<args...> &t,
func&& f)
{
using value_type = typename std::tuple_element<i, std::tuple<args...>>::type;
return f(static_cast<value_type &>(std::get<i>(t)))? until<i+1>(t, f) : false;
}
template<size_t i = 0,
class func,
class... args>
constexpr
typename std::enable_if<i < std::tuple_size<std::tuple<args...>>::value, bool>::type
until(const std::tuple<args...> &t,
func&& f)
{
using value_type = typename std::tuple_element<i, std::tuple<args...>>::type;
return f(static_cast<const value_type &>(std::get<i>(t)))? until<i+1>(t, f) : false;
}
//
// Circuits for reverse iteration of a tuple
//
// runtil(tuple, [](auto&& elem) -> bool { ... });
template<ssize_t i,
class func,
class... args>
constexpr
typename std::enable_if<i == 0, bool>::type
runtil(const std::tuple<args...> &t,
func&& f)
{
return true;
}
template<ssize_t i,
class func,
class... args>
constexpr
typename std::enable_if<i == 0, bool>::type
runtil(std::tuple<args...> &t,
func&& f)
{
return true;
}
template<ssize_t i,
class func,
class... args>
constexpr
typename std::enable_if<(i > 0), bool>::type
runtil(const std::tuple<args...> &t,
func&& f)
{
return f(std::get<i - 1>(t))? runtil<i - 1>(t, f) : false;
}
template<ssize_t i,
class func,
class... args>
constexpr typename std::enable_if<(i > 0), bool>::type
runtil(std::tuple<args...> &t,
func&& f)
{
return f(std::get<i - 1>(t))? runtil<i - 1>(t, f) : false;
}
template<ssize_t i = -1,
class func,
class... args>
constexpr typename std::enable_if<(i == -1), bool>::type
runtil(const std::tuple<args...> &t,
func&& f)
{
constexpr const auto size
{
std::tuple_size<std::tuple<args...>>::value
};
return runtil<size>(t, std::forward<func>(f));
}
template<ssize_t i = -1,
class func,
class... args>
constexpr typename std::enable_if<(i == -1), bool>::type
runtil(std::tuple<args...> &t,
func&& f)
{
constexpr const auto size
{
std::tuple_size<std::tuple<args...>>::value
};
return runtil<size>(t, std::forward<func>(f));
}
//
// test() is a logical inversion of until() for intuitive find()-like
// boolean semantics. // boolean semantics.
// //
template<size_t i, template<class func,
class func,
class... args> class... args>
constexpr auto constexpr inline auto
test(std::tuple<args...> &t, test(const std::tuple<args...> &t,
func&& f) func&& f)
{ {
return !until(t, [&f](auto&& arg) return !for_each(t, [&f](const auto &arg)
{ {
return !f(arg); return !f(arg);
}); });
} }
template<size_t i, template<class func,
class func,
class... args> class... args>
constexpr auto constexpr inline auto
rtest(std::tuple<args...> &t, rtest(const std::tuple<args...> &t,
func&& f) func&& f)
{ {
return !runtil(t, [&f](auto&& arg) return !rfor_each(t, [&f](const auto &arg)
{ {
return !f(arg); return !f(arg);
}); });
@ -331,8 +210,7 @@ template<size_t j,
size_t i, size_t i,
class func, class func,
class... args> class... args>
constexpr constexpr typename std::enable_if<i == j, void>::type
typename std::enable_if<i == j, void>::type
kronecker_delta(const std::tuple<args...> &t, kronecker_delta(const std::tuple<args...> &t,
func&& f) func&& f)
{ {
@ -344,8 +222,7 @@ template<size_t i,
size_t j, size_t j,
class func, class func,
class... args> class... args>
constexpr constexpr typename std::enable_if<i == j, void>::type
typename std::enable_if<i == j, void>::type
kronecker_delta(std::tuple<args...> &t, kronecker_delta(std::tuple<args...> &t,
func&& f) func&& f)
{ {
@ -357,8 +234,7 @@ template<size_t j,
size_t i = 0, size_t i = 0,
class func, class func,
class... args> class... args>
constexpr constexpr typename std::enable_if<(i < j), void>::type
typename std::enable_if<(i < j), void>::type
kronecker_delta(const std::tuple<args...> &t, kronecker_delta(const std::tuple<args...> &t,
func&& f) func&& f)
{ {
@ -369,19 +245,16 @@ template<size_t j,
size_t i = 0, size_t i = 0,
class func, class func,
class... args> class... args>
constexpr constexpr typename std::enable_if<(i < j), void>::type
typename std::enable_if<(i < j), void>::type
kronecker_delta(std::tuple<args...> &t, kronecker_delta(std::tuple<args...> &t,
func&& f) func&& f)
{ {
kronecker_delta<j, i + 1>(t, std::forward<func>(f)); kronecker_delta<j, i + 1>(t, std::forward<func>(f));
} }
// /// Get the index of a tuple element by address at runtime
// Get the index of a tuple element by address at runtime
//
template<class tuple> template<class tuple>
size_t inline size_t
indexof(tuple &t, const void *const &ptr) indexof(tuple &t, const void *const &ptr)
{ {
size_t ret(0); size_t ret(0);
@ -401,12 +274,10 @@ indexof(tuple &t, const void *const &ptr)
return ret; return ret;
} }
// //// Tuple layouts are not standard layouts; we can only do this at runtime
// Tuple layouts are not standard layouts; we can only do this at runtime
//
template<size_t index, template<size_t index,
class tuple> class tuple>
off_t inline off_t
tuple_offset(const tuple &t) tuple_offset(const tuple &t)
{ {
return off_t return off_t

View file

@ -768,9 +768,9 @@ const
return ret; return ret;
}); });
return !until(types, [&](auto type) return test(types, [&](const auto type)
{ {
return !visit_type<decltype(type)>(val, closure); return visit_type<decltype(type)>(val, closure);
}); });
} }
@ -854,9 +854,9 @@ const
return ret; return ret;
}); });
return !until(types, [&](auto type) return test(types, [&](const auto type)
{ {
return !visit_type<decltype(type)>(val, closure); return visit_type<decltype(type)>(val, closure);
}); });
} }
@ -940,9 +940,9 @@ const
return ret; return ret;
}); });
return !until(types, [&](auto type) return test(types, [&](const auto type)
{ {
return !visit_type<decltype(type)>(val, closure); return visit_type<decltype(type)>(val, closure);
}); });
} }
@ -1023,9 +1023,9 @@ const
return ret; return ret;
}); });
return !until(types, [&](auto type) return test(types, [&](const auto type)
{ {
return !visit_type<decltype(type)>(val, closure); return visit_type<decltype(type)>(val, closure);
}); });
} }
@ -1106,9 +1106,9 @@ const
return ret; return ret;
}); });
return !until(types, [&](auto type) return test(types, [&](const auto type)
{ {
return !visit_type<decltype(type)>(val, closure); return visit_type<decltype(type)>(val, closure);
}); });
} }
@ -1217,9 +1217,9 @@ const
return ret; return ret;
}); });
return !until(types, [&](auto type) return test(types, [&](const auto type)
{ {
return !visit_type<decltype(type)>(val, closure); return visit_type<decltype(type)>(val, closure);
}); });
} }