diff --git a/include/ircd/util.h b/include/ircd/util.h index 40622ae40..61e7691c1 100644 --- a/include/ircd/util.h +++ b/include/ircd/util.h @@ -128,6 +128,7 @@ using custom_ptr = std::unique_ptr>; template +constexpr typename std::enable_if>::value, void>::type for_each(std::tuple &t, func&& f) @@ -136,6 +137,7 @@ for_each(std::tuple &t, template +constexpr typename std::enable_if>::value, void>::type for_each(const std::tuple &t, func&& f) @@ -144,6 +146,7 @@ for_each(const std::tuple &t, template +constexpr typename std::enable_if>::value, void>::type for_each(const std::tuple &t, func&& f) @@ -155,6 +158,7 @@ for_each(const std::tuple &t, template +constexpr typename std::enable_if>::value, void>::type for_each(std::tuple &t, func&& f) @@ -163,6 +167,84 @@ for_each(std::tuple &t, for_each(t, std::forward(f)); } +// +// Circuits for reverse iteration of a tuple +// +// rfor_each(tuple, [](auto&& elem) { ... }); + +template +constexpr +typename std::enable_if::type +rfor_each(const std::tuple &t, + func&& f) +{} + +template +constexpr +typename std::enable_if::type +rfor_each(std::tuple &t, + func&& f) +{} + +template +constexpr +typename std::enable_if<(i > 0), void>::type +rfor_each(const std::tuple &t, + func&& f) +{ + f(std::get(t)); + rfor_each(t, std::forward(f)); +} + +template +constexpr +typename std::enable_if<(i > 0), void>::type +rfor_each(std::tuple &t, + func&& f) +{ + f(std::get(t)); + rfor_each(t, std::forward(f)); +} + +template +constexpr +typename std::enable_if<(i == -1), void>::type +rfor_each(const std::tuple &t, + func&& f) +{ + constexpr const auto size + { + std::tuple_size>::value + }; + + rfor_each(t, std::forward(f)); +} + +template +constexpr +typename std::enable_if<(i == -1), void>::type +rfor_each(std::tuple &t, + func&& f) +{ + constexpr const auto size + { + std::tuple_size>::value + }; + + rfor_each(t, std::forward(f)); +} // // Iteration of a tuple until() style: your closure returns true to continue, false @@ -171,6 +253,7 @@ for_each(std::tuple &t, template +constexpr typename std::enable_if>::value, bool>::type until(std::tuple &t, func&& f) @@ -181,6 +264,7 @@ until(std::tuple &t, template +constexpr typename std::enable_if>::value, bool>::type until(const std::tuple &t, func&& f) @@ -191,6 +275,7 @@ until(const std::tuple &t, template +constexpr typename std::enable_if>::value, bool>::type until(std::tuple &t, func&& f) @@ -201,6 +286,7 @@ until(std::tuple &t, template +constexpr typename std::enable_if>::value, bool>::type until(const std::tuple &t, func&& f) @@ -209,6 +295,88 @@ until(const std::tuple &t, } +// +// Circuits for reverse iteration of a tuple +// +// runtil(tuple, [](auto&& elem) -> bool { ... }); + +template +constexpr +typename std::enable_if::type +runtil(const std::tuple &t, + func&& f) +{ + return true; +} + +template +constexpr +typename std::enable_if::type +runtil(std::tuple &t, + func&& f) +{ + return true; +} + +template +constexpr +typename std::enable_if<(i > 0), bool>::type +runtil(const std::tuple &t, + func&& f) +{ + return f(std::get(t))? runtil(t, std::forward(f)) : false; +} + +template +constexpr +typename std::enable_if<(i > 0), bool>::type +runtil(std::tuple &t, + func&& f) +{ + return f(std::get(t))? runtil(t, std::forward(f)) : false; +} + +template +constexpr +typename std::enable_if<(i == -1), bool>::type +runtil(const std::tuple &t, + func&& f) +{ + constexpr const auto size + { + std::tuple_size>::value + }; + + return runtil(t, std::forward(f)); +} + +template +constexpr +typename std::enable_if<(i == -1), bool>::type +runtil(std::tuple &t, + func&& f) +{ + constexpr const auto size + { + std::tuple_size>::value + }; + + return runtil(t, std::forward(f)); +} + + // For conforming enums include a _NUM_ as the last element, // then num_of() works template @@ -903,5 +1071,56 @@ struct unique_iterator }; +// +// Get the index of a tuple element by address at runtime +// +template +size_t +indexof(tuple &t, const void *const &ptr) +{ + size_t ret(0); + const auto closure([&ret, &ptr] + (auto &elem) + { + if(reinterpret_cast(std::addressof(elem)) == ptr) + return false; + + ++ret; + return true; + }); + + if(unlikely(until(t, closure))) + throw std::out_of_range("no member of this tuple with that address"); + + return ret; +} + +// +// Tuple layouts are not standard layouts; we can only do this at runtime +// +template +off_t +tuple_offset(const tuple &t) +{ + return + { + reinterpret_cast(std::addressof(std::get(t))) - + reinterpret_cast(std::addressof(t)) + }; +} + + +// +// Compile-time comparison of string literals +// +constexpr bool +_constexpr_equal(const char *a, + const char *b) +{ + return *a == *b && (*a == '\0' || _constexpr_equal(a + 1, b + 1)); +} + + } // namespace util } // namespace ircd