// ccutl.different feature guard {{{ #ifndef CCUTL_DIFFERENT_INCLUDED #define CCUTL_DIFFERENT_INCLUDED // ccutl.different feature guard }}} /* C++20 | | __| __| | | __| | ( ( | | | | \___| \___| \__,_| \__| _| ccutl Core Utilities [ccutl.different]: describes a set of types with at least one variation Copyright (C) 2020, 2021 Justin Collier This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the internalied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #include <cstdint> #include <type_traits> #ifndef CCUTL_NAMESPACE #define CCUTL_NAMESPACE ctl #endif namespace CCUTL_NAMESPACE { // ccutl.targ {{{ // ccutl.targ feature guard {{{ #ifndef CCUTL_TARG_INCLUDED #define CCUTL_TARG_INCLUDED // ccutl.targ feature guard }}} // detail {{{ namespace detail { namespace targ { /// primary template for targ_::impl template <std::size_t, std::size_t, class...> struct impl; /// end of iteration; type represents first type template <std::size_t targ, class First, class... Rest> struct impl<targ, targ, First, Rest...> { using type = First; }; /// iterates until i reaches target template <std::size_t targ, std::size_t i, class First, class... Rest> struct impl<targ, i, First, Rest...> { using type = typename impl<targ, i + 1, Rest...>::type; }; /// helper typedef for impl::type template <std::size_t targ, class... Pack> using type = typename impl<targ, 0, Pack...>::type; /// checks if idx can be used to index Ts... template <std::size_t idx, class... Ts> inline constexpr bool valid_indexable_pack = sizeof...(Ts) > 0 && idx < sizeof...(Ts); } // namespace targ } // namespace detail // detail }}} /* */ // clang-format off /** * represents the type template argument at index idx * * \code * #include "ctl/targ.h" * using x0 = ctl::targ<0, int, float, double>; // int * using x1 = ctl::targ<1, int, float, double>; // float * using x2 = ctl::targ<2, int, float, double>; // double * \endcode * * \anchor targ * \ingroup ccutl */ template <std::size_t idx, class... Ts> requires detail::targ::valid_indexable_pack<idx, Ts...> using targ = detail::targ::type<idx, Ts...>; /* */ // clang-format on // ccutl.targ version guard {{{ #define CCUTL_TARG_VERSION_MAJOR 0 #define CCUTL_TARG_VERSION_MINOR 3 #define CCUTL_TARG_VERSION_PATCH 2 #elif CCUTL_TARG_VERSION_MAJOR != 0 #error ccutl.targ major version mismatch #elif CCUTL_TARG_VERSION_MINOR != 3 #error ccutl.targ minor version mismatch #elif CCUTL_TARG_VERSION_PATCH != 2 #warning ccutl.targ patch version mismatch #endif // ccutl.targ version guard }}} // ccutl.targ }}} // ccutl.same {{{ // ccutl.same feature guard {{{ #ifndef CCUTL_SAME_INCLUDED #define CCUTL_SAME_INCLUDED // ccutl.same feature guard }}} // detail {{{ namespace detail { namespace same { /// checks if First, Rest... are the same /// adheres to the spirit of the same_as conceptual redundancy; /// (same_as = std::is_same_v<T, U> and std::is_same_v<U, T>) /// all types are bidirectionally compared with each other template <std::size_t i, class First, class... Rest> [[nodiscard]] inline constexpr bool impl() noexcept { if constexpr (i == sizeof...(Rest)) { return true; } else if constexpr (sizeof...(Rest) == 1) { // pack is not really expanded with the ellipses (sizeof 1) return (std::is_same_v<First, Rest> && ...); } else /* i < sizeof...(Rest) and sizeof...(Rest) > 1 */ { constexpr bool this_comparison = (std::is_same_v<ctl::targ<i, First, Rest...>, Rest> && ...); // recurse with First pushed to end to ensure two-way comparison return this_comparison && impl<i + 1, Rest..., First>(); } } } // namespace same } // namespace detail // detail }}} /** * describes a set of types with no variation * * \code * #include "ctl/same.h" * static_assert( same<int, int, int>); * static_assert(!same<int, int &, int>); * \endcode * * \anchor same * \ingroup ccutl */ template <class... Ts> concept same = sizeof...(Ts) > 0 and detail::same::impl<0, Ts...>(); // ccutl.same version guard {{{ #define CCUTL_SAME_VERSION_MAJOR 0 #define CCUTL_SAME_VERSION_MINOR 3 #define CCUTL_SAME_VERSION_PATCH 2 #elif CCUTL_SAME_VERSION_MAJOR != 0 #error ccutl.same major version mismatch #elif CCUTL_SAME_VERSION_MINOR != 3 #error ccutl.same minor version mismatch #elif CCUTL_SAME_VERSION_PATCH != 2 #warning ccutl.same patch version mismatch #endif // ccutl.same version guard }}} // ccutl.same }}} /** * describes a set of types with at least one variation * * \code * #include "ctl/different.h" * auto x0 = ctl::different<int, int, int>; // false * auto x1 = ctl::different<int, int &, int>; // true * \endcode * * \anchor different * \ingroup ccutl */ template <class... Ts> concept different = !same<Ts...>; } // namespace CCUTL_NAMESPACE // ccutl.different version guard {{{ #define CCUTL_DIFFERENT_VERSION_MAJOR 0 #define CCUTL_DIFFERENT_VERSION_MINOR 3 #define CCUTL_DIFFERENT_VERSION_PATCH 2 #elif CCUTL_DIFFERENT_VERSION_MAJOR != 0 #error ccutl.different major version mismatch #elif CCUTL_DIFFERENT_VERSION_MINOR != 3 #error ccutl.different minor version mismatch #elif CCUTL_DIFFERENT_VERSION_PATCH != 2 #warning ccutl.different patch version mismatch #endif // vim: fmr={{{,}}} fdm=marker // ccutl.different version guard }}}