// 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 { inline 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 inline bool for_each(const std::tuple &t, func&& f) { if constexpr(i < size>()) { using closure_result = std::invoke_result_t < decltype(f), decltype(std::get(t)) >; constexpr bool terminable { std::is_same() }; if constexpr(terminable) { if(!f(std::get(t))) return false; } else f(std::get(t)); return for_each(t, std::forward(f)); } else return true; } template constexpr inline bool for_each(std::tuple &t, func&& f) { if constexpr(i < size>()) { using closure_result = std::invoke_result_t < decltype(f), decltype(std::get(t)) >; constexpr bool terminable { std::is_same() }; if constexpr(terminable) { if(!f(std::get(t))) return false; } else f(std::get(t)); return for_each(t, std::forward(f)); } else return true; } // // Circuits for reverse iteration of a tuple // // rfor_each(tuple, [](auto&& elem) { ... }); template>() - 1> constexpr inline bool rfor_each(const std::tuple &t, func&& f) { if constexpr(i >= 0) { using closure_result = std::invoke_result_t < decltype(f), decltype(std::get(t)) >; constexpr bool terminable { std::is_same() }; if constexpr(terminable) { if(!f(std::get(t))) return false; } else f(std::get(t)); return rfor_each(t, std::forward(f)); } else return true; } template>() - 1> constexpr inline bool rfor_each(std::tuple &t, func&& f) { if constexpr(i >= 0) { using closure_result = std::invoke_result_t < decltype(f), decltype(std::get(t)) >; constexpr bool terminable { std::is_same() }; if constexpr(terminable) { if(!f(std::get(t))) return false; } else f(std::get(t)); return rfor_each(t, std::forward(f)); } else return true; } // // test() is a logical inversion of for_each() for intuitive find()-like // boolean semantics. // template constexpr inline auto test(const std::tuple &t, func&& f) { return !for_each(t, [&f](const auto &arg) { return !f(arg); }); } template constexpr inline auto rtest(const std::tuple &t, func&& f) { return !rfor_each(t, [&f](const 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 inline 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 inline off_t tuple_offset(const tuple &t) { return off_t { reinterpret_cast(std::addressof(std::get(t))) - reinterpret_cast(std::addressof(t)) }; } } // namespace util } // namespace ircd