// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // 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. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_UTIL_TUPLE_H // // Utilities for std::tuple // namespace ircd { namespace util { template constexpr bool is_tuple() { return is_specialization_of::value; } template constexpr typename std::enable_if(), size_t>::type size() { return std::tuple_size::value; } template constexpr size_t size(const std::tuple &t) { return size>(); } // // Iteration of a tuple // // for_each(tuple, [](auto&& elem) { ... }); template constexpr typename std::enable_if>::value, void>::type for_each(std::tuple &t, func&& f) {} template constexpr typename std::enable_if>::value, void>::type for_each(const std::tuple &t, func&& f) {} template constexpr typename std::enable_if>::value, void>::type for_each(const std::tuple &t, func&& f) { f(std::get(t)); for_each(t, std::forward(f)); } template constexpr typename std::enable_if>::value, void>::type for_each(std::tuple &t, func&& f) { f(std::get(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 ssize_t 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 ssize_t size { std::tuple_size>::value }; rfor_each(t, std::forward(f)); } // // Iteration of a tuple until() style: your closure returns true to continue, false // to break. until() then remains true to the end, or returns false if not. template constexpr typename std::enable_if>::value, bool>::type until(std::tuple &t, func&& f) { return true; } template constexpr typename std::enable_if>::value, bool>::type until(const std::tuple &t, func&& f) { return true; } template constexpr typename std::enable_if>::value, bool>::type until(std::tuple &t, func&& f) { using value_type = typename std::tuple_element>::type; return f(static_cast(std::get(t)))? until(t, f) : false; } template constexpr typename std::enable_if>::value, bool>::type until(const std::tuple &t, func&& f) { using value_type = typename std::tuple_element>::type; return f(static_cast(std::get(t)))? until(t, f) : false; } // // 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, 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, 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)); } // // test() is a logical inversion of until() for intuitive find()-like // boolean semantics. // template constexpr auto test(std::tuple &t, func&& f) { return !until(t, [&f](auto&& arg) { return !f(arg); }); } template constexpr auto rtest(std::tuple &t, func&& f) { return !runtil(t, [&f](auto&& arg) { return !f(arg); }); } // // Kronecker delta // template constexpr typename std::enable_if::type kronecker_delta(const std::tuple &t, func&& f) { using value_type = typename std::tuple_element>::type; f(static_cast(std::get(t))); } template constexpr typename std::enable_if::type kronecker_delta(std::tuple &t, func&& f) { using value_type = typename std::tuple_element>::type; f(static_cast(std::get(t))); } template constexpr typename std::enable_if<(i < j), void>::type kronecker_delta(const std::tuple &t, func&& f) { kronecker_delta(t, std::forward(f)); } template constexpr typename std::enable_if<(i < j), void>::type kronecker_delta(std::tuple &t, func&& f) { kronecker_delta(t, std::forward(f)); } // // 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)) }; } } // namespace util } // namespace ircd