Last active
July 21, 2025 21:43
-
-
Save snhobbs/b1cbf0ff98e0f62eaab3f1b47fca5ca9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED | |
| #define ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED | |
| #if defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| import std; | |
| #else | |
| #include <type_traits> | |
| #include <initializer_list> | |
| #include <utility> | |
| #endif | |
| #if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1922 | |
| #define STRONG_CONSTEXPR | |
| #else | |
| #define STRONG_CONSTEXPR constexpr | |
| #endif | |
| #if __cplusplus >= 201703L | |
| #define STRONG_NODISCARD [[nodiscard]] | |
| #else | |
| #define STRONG_NODISCARD | |
| #endif | |
| namespace strong { | |
| struct uninitialized_t { | |
| }; | |
| static constexpr uninitialized_t uninitialized{}; | |
| template<typename M, typename T> | |
| using modifier = typename M::template modifier<T>; | |
| struct default_constructible { | |
| template<typename T> | |
| class modifier { | |
| }; | |
| }; | |
| namespace impl { | |
| template<typename T> | |
| constexpr bool supports_default_construction( | |
| const ::strong::default_constructible::modifier<T> *) | |
| { | |
| return true; | |
| } | |
| template<typename T, typename ... V> | |
| using WhenConstructible = std::enable_if_t<std::is_constructible<T, V...>::value>; | |
| } | |
| template<typename T, typename Tag, typename ... M> | |
| class type : public modifier<M, type<T, Tag, M...>> ... { | |
| public: | |
| template<typename TT = T, typename = std::enable_if_t<std::is_trivially_constructible<TT>{}>> | |
| explicit type(uninitialized_t) | |
| noexcept | |
| { | |
| } | |
| template<typename type_ = type, | |
| bool = impl::supports_default_construction( | |
| static_cast<type_ *>(nullptr))> | |
| constexpr | |
| type() | |
| noexcept(noexcept(T{})) | |
| : _val{} | |
| { | |
| } | |
| template<typename U, | |
| typename = impl::WhenConstructible<T, std::initializer_list<U>>> | |
| constexpr | |
| explicit | |
| type( | |
| std::initializer_list<U> us | |
| ) | |
| noexcept(noexcept(T{us})) | |
| : _val{us} | |
| { | |
| } | |
| template<typename ... U, | |
| typename = std::enable_if_t< | |
| std::is_constructible<T, U &&...>::value && (sizeof...(U) > 0)>> | |
| constexpr | |
| explicit | |
| type( | |
| U &&... u) | |
| noexcept(std::is_nothrow_constructible<T, U...>::value) | |
| : _val(std::forward<U>(u)...) | |
| {} | |
| friend STRONG_CONSTEXPR void swap(type &a, type &b) noexcept( | |
| std::is_nothrow_move_constructible<T>::value && | |
| std::is_nothrow_move_assignable<T>::value | |
| ) | |
| { | |
| using std::swap; | |
| swap(a._val, b._val); | |
| } | |
| STRONG_NODISCARD | |
| constexpr T &value_of() & noexcept | |
| { return _val; } | |
| STRONG_NODISCARD | |
| constexpr const T &value_of() const & noexcept | |
| { return _val; } | |
| STRONG_NODISCARD | |
| constexpr T &&value_of() && noexcept | |
| { return std::move(_val); } | |
| STRONG_NODISCARD | |
| constexpr const T &&value_of() const && noexcept | |
| { return std::move(_val); } | |
| STRONG_NODISCARD | |
| friend constexpr T &value_of(type &t) noexcept | |
| { return t._val; } | |
| STRONG_NODISCARD | |
| friend constexpr const T &value_of(const type &t) noexcept | |
| { return t._val; } | |
| STRONG_NODISCARD | |
| friend constexpr T &&value_of(type &&t) noexcept | |
| { return std::move(t)._val; } | |
| STRONG_NODISCARD | |
| friend constexpr const T &&value_of(const type &&t) noexcept | |
| { return std::move(t)._val; } | |
| T _val; | |
| }; | |
| namespace impl { | |
| template<typename T, typename Tag, typename ... Ms> | |
| constexpr bool is_strong_type_func(const strong::type<T, Tag, Ms...> *) | |
| { return true; } | |
| constexpr bool is_strong_type_func(...) | |
| { return false; } | |
| template<typename T, typename Tag, typename ... Ms> | |
| constexpr T underlying_type(strong::type<T, Tag, Ms...> *); | |
| } | |
| template<typename T> | |
| struct is_strong_type : std::integral_constant<bool, impl::is_strong_type_func( | |
| static_cast<T *>(nullptr))> { | |
| }; | |
| template<typename T, bool = is_strong_type<T>::value> | |
| struct underlying_type { | |
| using type = decltype(impl::underlying_type(static_cast<T *>(nullptr))); | |
| }; | |
| template<typename T> | |
| struct underlying_type<T, false> { | |
| using type = T; | |
| }; | |
| template<typename T> | |
| using underlying_type_t = typename underlying_type<T>::type; | |
| namespace impl { | |
| template<typename T> | |
| using WhenStrongType = std::enable_if_t<is_strong_type<std::decay_t<T>>::value>; | |
| template<typename T> | |
| using WhenNotStrongType = std::enable_if_t<!is_strong_type<std::decay_t<T>>::value>; | |
| template< | |
| typename T, | |
| typename = impl::WhenNotStrongType<T>> | |
| constexpr | |
| T && | |
| access(T &&t) | |
| noexcept | |
| { | |
| return std::forward<T>(t); | |
| } | |
| template< | |
| typename T, | |
| typename = impl::WhenStrongType<T>> | |
| STRONG_NODISCARD | |
| constexpr | |
| auto | |
| access(T &&t) | |
| noexcept | |
| -> decltype(value_of(std::forward<T>(t))) | |
| { | |
| return value_of(std::forward<T>(t)); | |
| } | |
| template <typename T> | |
| struct require_copy_constructible | |
| { | |
| static constexpr bool value = std::is_copy_constructible<underlying_type_t<T>>::value; | |
| static_assert(value, "underlying type must be copy constructible"); | |
| }; | |
| template <typename T> | |
| struct require_move_constructible | |
| { | |
| static constexpr bool value = std::is_move_constructible<underlying_type_t<T>>::value; | |
| static_assert(value, "underlying type must be move constructible"); | |
| }; | |
| template <typename T> | |
| struct require_copy_assignable | |
| { | |
| static constexpr bool value = std::is_copy_assignable<underlying_type_t<T>>::value; | |
| static_assert(value, "underlying type must be copy assignable"); | |
| }; | |
| template <typename T> | |
| struct require_move_assignable | |
| { | |
| static constexpr bool value = std::is_move_assignable<underlying_type_t<T>>::value; | |
| static_assert(value, "underlying type must be move assignable"); | |
| }; | |
| template <typename ...> | |
| static constexpr bool always_false = false; | |
| template <bool> struct valid_type; | |
| template <> | |
| struct valid_type<true> {}; | |
| template<typename ...> | |
| using void_t = void; | |
| template <typename Needle, typename Type, typename Modifier> | |
| static constexpr bool modifier_is | |
| = std::is_base_of<modifier<Needle, Type>, modifier<Modifier,Type>>::value; | |
| template <typename Needle, typename Type, typename Haystack> | |
| static | |
| constexpr | |
| bool | |
| type_implements | |
| = std::is_base_of<modifier<Needle, Type>, modifier<Haystack, Type>>::value; | |
| #if __cplusplus >= 201703 | |
| template < | |
| template <typename...> class Modifier, | |
| typename Needle, | |
| typename Type, | |
| typename ... Ms | |
| > | |
| static | |
| constexpr | |
| bool | |
| modifier_is<Needle, Type, Modifier<Ms...>> | |
| = (std::is_base_of<modifier<Needle, Type>, modifier<Modifier<Ms>, Type>>::value || ...); | |
| template < | |
| template <typename ...> class Modifier, | |
| typename ... Needles, | |
| typename Type, | |
| typename ... Haystack | |
| > | |
| static | |
| constexpr | |
| bool type_implements<Modifier<Needles...>, Type, Modifier<Haystack...>> | |
| = (modifier_is<Modifier<Needles>, Type, Modifier<Haystack...>> && ...); | |
| #else | |
| template <typename ...> | |
| struct conjunction; | |
| template <typename T, typename ... Ts> | |
| struct conjunction<T, Ts...> | |
| : std::integral_constant<bool, T::value && conjunction<Ts...>::value> | |
| {}; | |
| template <> | |
| struct conjunction<> : std::true_type {}; | |
| template <typename ...> | |
| struct disjunction; | |
| template <typename T, typename ... Ts> | |
| struct disjunction<T, Ts...> | |
| : std::integral_constant<bool, T::value || disjunction<Ts...>::value> | |
| {}; | |
| template <> | |
| struct disjunction<> : std::false_type {}; | |
| template < | |
| template <typename...> class Modifier, | |
| typename Needle, | |
| typename Type, | |
| typename ... Ms | |
| > | |
| static | |
| constexpr | |
| bool | |
| modifier_is<Needle, Type, Modifier<Ms...>> | |
| = disjunction< | |
| std::is_base_of< | |
| modifier<Needle, Type>, | |
| modifier<Modifier<Ms>, Type> | |
| >... | |
| >::value; | |
| template < | |
| template <typename ...> class Modifier, | |
| typename ... Needles, | |
| typename Type, | |
| typename ... Haystack | |
| > | |
| static | |
| constexpr | |
| bool | |
| type_implements<Modifier<Needles...>, Type, Modifier<Haystack...>> | |
| = conjunction< | |
| std::integral_constant< | |
| bool, | |
| modifier_is< | |
| Modifier<Needles>, | |
| Type, | |
| Modifier<Haystack...> | |
| > | |
| >... | |
| >::value; | |
| #endif | |
| template <typename T, typename M> | |
| static constexpr bool type_is = false; | |
| #if __cplusplus >= 201703L | |
| template <typename T, typename Tag, typename ... Ms, typename M> | |
| static constexpr bool type_is<strong::type<T, Tag, Ms...>, M> | |
| = (impl::type_implements<M, strong::type<T, Tag, Ms...>, Ms> || ...); | |
| #else | |
| template <typename T, typename Tag, typename ... Ms, typename M> | |
| static constexpr bool type_is<strong::type<T, Tag, Ms...>, M> | |
| = impl::disjunction<std::integral_constant<bool, impl::type_implements<M, strong::type<T, Tag, Ms...>, Ms>>...>::value; | |
| #endif | |
| template <typename T, typename Tag, typename ... Ms> | |
| type<T, Tag, Ms...> get_strong_(const type<T, Tag, Ms...>*); | |
| template <typename T> | |
| using get_strong = decltype(get_strong_(static_cast<T*>(nullptr))); | |
| } | |
| template <typename T, typename M> | |
| static constexpr bool type_is_v = impl::type_is<impl::get_strong<T>, M>; | |
| template <typename T, typename M> | |
| using type_is = std::integral_constant<bool, type_is_v<T,M>>; | |
| } | |
| #endif //ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_EQUALITY_HPP | |
| #define STRONG_TYPE_EQUALITY_HPP | |
| namespace strong | |
| { | |
| struct equality | |
| { | |
| template <typename T, typename = void> | |
| class modifier { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type must be equality comparable"); | |
| }; | |
| }; | |
| template <typename T, typename Tag, typename ... M> | |
| class equality::modifier< | |
| ::strong::type<T, Tag, M...>, | |
| impl::void_t<decltype(std::declval<const T&>() == std::declval<const T&>())> | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator==( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const T&>() == std::declval<const T&>())) | |
| -> decltype(std::declval<const T&>() == std::declval<const T&>()) | |
| { | |
| return value_of(lh) == value_of(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator!=( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const T&>() != std::declval<const T&>())) | |
| -> decltype(std::declval<const T&>() != std::declval<const T&>()) | |
| { | |
| return value_of(lh) != value_of(rh); | |
| } | |
| }; | |
| } | |
| #endif //STRONG_TYPE_EQUALITY_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_EQUALITY_WITH_HPP | |
| #define STRONG_TYPE_EQUALITY_WITH_HPP | |
| namespace strong | |
| { | |
| namespace impl | |
| { | |
| template <typename T, typename Other, typename = void> | |
| class typed_equality { | |
| static_assert(impl::always_false<T, Other>, | |
| "Underlying type must be equality comparable with target type"); | |
| }; | |
| template <typename T, typename Other> | |
| class typed_equality< | |
| T, | |
| Other, | |
| impl::void_t<decltype(std::declval<const underlying_type_t<T>&>() == std::declval<const underlying_type_t<Other>&>())> | |
| > | |
| { | |
| private: | |
| using TT = underlying_type_t<T>; | |
| using OT = underlying_type_t<Other>; | |
| public: | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator==(const T& lh, const Other& rh) | |
| noexcept(noexcept(std::declval<const TT&>() == std::declval<const OT&>())) | |
| -> decltype(std::declval<const TT&>() == std::declval<const OT&>()) | |
| { | |
| return value_of(lh) == impl::access(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator==(const Other& lh, const T& rh) | |
| noexcept(noexcept(std::declval<const OT&>() == std::declval<const TT&>())) | |
| -> decltype(std::declval<const OT&>() == std::declval<const TT&>()) | |
| { | |
| return impl::access(lh) == value_of(rh) ; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator!=(const T& lh, const Other rh) | |
| noexcept(noexcept(std::declval<const TT&>() != std::declval<const OT&>())) | |
| -> decltype(std::declval<const TT&>() != std::declval<const OT&>()) | |
| { | |
| return value_of(lh) != impl::access(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator!=(const Other& lh, const T& rh) | |
| noexcept(noexcept(std::declval<const OT&>() != std::declval<const TT&>())) | |
| -> decltype(std::declval<const OT&>() != std::declval<const TT&>()) | |
| { | |
| return impl::access(lh) != value_of(rh) ; | |
| } | |
| }; | |
| } | |
| template <typename ... Ts> | |
| struct equality_with | |
| { | |
| template <typename T> | |
| class modifier : public impl::typed_equality<T, Ts>... | |
| { | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_EQUALITY_WITH_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_ORDERED_HPP | |
| #define STRONG_TYPE_ORDERED_HPP | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #if __cpp_impl_three_way_comparison && __has_include(<compare>) | |
| #include <compare> | |
| #endif | |
| #endif | |
| namespace strong | |
| { | |
| struct ordered | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type must support ordering relations using <, <=, > and >="); | |
| }; | |
| }; | |
| template <typename T, typename Tag, typename ... M> | |
| class ordered::modifier< | |
| ::strong::type<T, Tag, M...>, | |
| impl::void_t< | |
| decltype((std::declval<T>() < std::declval<T>())), | |
| decltype((std::declval<T>() <= std::declval<T>())), | |
| decltype((std::declval<T>() > std::declval<T>())), | |
| decltype((std::declval<T>() >= std::declval<T>()))> | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator<( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const T&>() < std::declval<const T&>())) | |
| -> decltype(std::declval<const T&>() < std::declval<const T&>()) | |
| { | |
| return value_of(lh) < value_of(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator<=( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const T&>() <= std::declval<const T&>())) | |
| -> decltype(std::declval<const T&>() <= std::declval<const T&>()) | |
| { | |
| return value_of(lh) <= value_of(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator>( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const T&>() > std::declval<const T&>())) | |
| -> decltype(std::declval<const T&>() > std::declval<const T&>()) | |
| { | |
| return value_of(lh) > value_of(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator>=( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const T&>() >= std::declval<const T&>())) | |
| -> decltype(std::declval<const T&>() >= std::declval<const T&>()) | |
| { | |
| return value_of(lh) >= value_of(rh); | |
| } | |
| }; | |
| #if __cpp_impl_three_way_comparison && __has_include(<compare>) | |
| namespace detail | |
| { | |
| template<typename Ordering> | |
| struct spaceship_ordering { | |
| template <typename> | |
| struct modifier; | |
| }; | |
| template<typename Ordering> | |
| template<typename T, typename Tag, typename ... Ms> | |
| struct spaceship_ordering<Ordering>::modifier<::strong::type<T, Tag, Ms...>> | |
| { | |
| using type = ::strong::type<T, Tag, Ms...>; | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| Ordering | |
| operator<=>( | |
| const type &lh, | |
| const type &rh) | |
| noexcept(noexcept(std::declval<const T &>() <=> std::declval<const T &>())) | |
| requires std::is_convertible_v<decltype(std::declval<const T&>() <=> std::declval<const T&>()), Ordering> | |
| { | |
| return value_of(lh) <=> value_of(rh); | |
| } | |
| }; | |
| } | |
| using strongly_ordered = detail::spaceship_ordering<std::strong_ordering>; | |
| using weakly_ordered = detail::spaceship_ordering<std::weak_ordering>; | |
| using partially_ordered = detail::spaceship_ordering<std::partial_ordering>; | |
| #endif | |
| } | |
| #endif //STRONG_TYPE_ORDERED_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_ORDERED_WITH_HPP | |
| #define STRONG_TYPE_ORDERED_WITH_HPP | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #if __cpp_impl_three_way_comparison && __has_include(<compare>) | |
| #include <compare> | |
| #endif | |
| #endif | |
| namespace strong | |
| { | |
| namespace impl | |
| { | |
| template <typename T, typename Other, typename = void> | |
| class typed_ordering | |
| { | |
| static_assert(impl::always_false<T, Other>, | |
| "Underlying type must support ordering relations with target type using operators <, <=, > and >="); | |
| }; | |
| template <typename T, typename Other> | |
| class typed_ordering< | |
| T, | |
| Other, | |
| impl::void_t< | |
| decltype((std::declval<underlying_type_t<T>>() < std::declval<underlying_type_t<Other>>())), | |
| decltype((std::declval<underlying_type_t<T>>() <= std::declval<underlying_type_t<Other>>())), | |
| decltype((std::declval<underlying_type_t<T>>() > std::declval<underlying_type_t<Other>>())), | |
| decltype((std::declval<underlying_type_t<T>>() >= std::declval<underlying_type_t<Other>>())) | |
| > | |
| > | |
| { | |
| private: | |
| using TT = underlying_type_t<T>; | |
| using OT = underlying_type_t<Other>; | |
| public: | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator<(const T& lh, const Other& rh) | |
| noexcept(noexcept(std::declval<const TT&>() < std::declval<const OT&>())) | |
| -> decltype(std::declval<const TT&>() < std::declval<const OT&>()) | |
| { | |
| return value_of(lh) < impl::access(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator<(const Other& lh, const T& rh) | |
| noexcept(noexcept(std::declval<const OT&>() < std::declval<const TT&>())) | |
| -> decltype(std::declval<const OT&>() < std::declval<const TT&>()) | |
| { | |
| return impl::access(lh) < value_of(rh) ; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator<=(const T& lh, const Other& rh) | |
| noexcept(noexcept(std::declval<const TT&>() <= std::declval<const OT&>())) | |
| -> decltype(std::declval<const TT&>() <= std::declval<const OT&>()) | |
| { | |
| return value_of(lh) <= impl::access(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator<=(const Other& lh, const T& rh) | |
| noexcept(noexcept(std::declval<const OT&>() <= std::declval<const TT&>())) | |
| -> decltype(std::declval<const OT&>() <= std::declval<const TT&>()) | |
| { | |
| return impl::access(lh) <= value_of(rh) ; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator>(const T& lh, const Other& rh) | |
| noexcept(noexcept(std::declval<const TT&>() > std::declval<const OT&>())) | |
| -> decltype(std::declval<const TT&>() > std::declval<const OT&>()) | |
| { | |
| return value_of(lh) > impl::access(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator>(const Other& lh, const T& rh) | |
| noexcept(noexcept(std::declval<const OT&>() > std::declval<const TT&>())) | |
| -> decltype(std::declval<const OT&>() > std::declval<const TT&>()) | |
| { | |
| return impl::access(lh) > value_of(rh) ; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator>=(const T& lh, const Other& rh) | |
| noexcept(noexcept(std::declval<const TT&>() >= std::declval<const OT&>())) | |
| -> decltype(std::declval<const TT&>() >= std::declval<const OT&>()) | |
| { | |
| return value_of(lh) >= impl::access(rh); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator>=(const Other& lh, const T& rh) | |
| noexcept(noexcept(std::declval<const OT&>() >= std::declval<const TT&>())) | |
| -> decltype(std::declval<const OT&>() >= std::declval<const TT&>()) | |
| { | |
| return impl::access(lh) >= value_of(rh) ; | |
| } | |
| }; | |
| } | |
| template <typename ... Ts> | |
| struct ordered_with | |
| { | |
| template <typename T> | |
| class modifier : public impl::typed_ordering<T, Ts>... | |
| { | |
| }; | |
| }; | |
| #if __cpp_impl_three_way_comparison && __has_include(<compare>) | |
| namespace detail | |
| { | |
| template <typename Ordering, typename T, typename Other> | |
| struct typed_spaceship_ordering_with | |
| { | |
| private: | |
| using TT = underlying_type_t<T>; | |
| using OT = underlying_type_t<Other>; | |
| public: | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| Ordering | |
| operator<=>( | |
| const T& lh, | |
| const Other& rh) | |
| noexcept(noexcept(std::declval<const TT&>() <=> std::declval<const OT&>())) | |
| requires std::is_convertible_v<decltype(std::declval<const TT&>() <=> std::declval<const OT&>()), Ordering> | |
| { | |
| return value_of(lh) <=> impl::access(rh); | |
| } | |
| }; | |
| template <typename Ordering, typename ... Ts> | |
| struct spaceship_ordering_with | |
| { | |
| template <typename T> | |
| struct modifier : public typed_spaceship_ordering_with<Ordering, T, Ts>... | |
| { | |
| }; | |
| }; | |
| } | |
| template <typename ... Ts> | |
| using strongly_ordered_with = detail::spaceship_ordering_with<std::strong_ordering, Ts...>; | |
| template <typename ... Ts> | |
| using weakly_ordered_with = detail::spaceship_ordering_with<std::weak_ordering, Ts...>; | |
| template <typename ... Ts> | |
| using partially_ordered_with = detail::spaceship_ordering_with<std::partial_ordering, Ts...>; | |
| #endif | |
| } | |
| #endif //STRONG_TYPE_ORDERED_WITH_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_SEMIREGULAR_HPP | |
| #define STRONG_TYPE_SEMIREGULAR_HPP | |
| namespace strong | |
| { | |
| namespace impl | |
| { | |
| template <typename T> | |
| struct require_semiregular | |
| : valid_type<require_copy_constructible<T>::value && | |
| require_move_constructible<T>::value && | |
| require_copy_assignable<T>::value && | |
| require_move_assignable<T>::value> | |
| { | |
| }; | |
| } | |
| struct semiregular | |
| { | |
| template <typename> | |
| class modifier; | |
| }; | |
| template <typename T, typename Tag, typename ... M> | |
| class semiregular::modifier<::strong::type<T, Tag, M...>> | |
| : public default_constructible::modifier<T> | |
| , private impl::require_semiregular<T> | |
| { | |
| }; | |
| } | |
| #endif //STRONG_TYPE_SEMIREGULAR_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_REGULAR_HPP | |
| #define STRONG_TYPE_REGULAR_HPP | |
| namespace strong | |
| { | |
| struct regular | |
| { | |
| template <typename T> | |
| class modifier | |
| : public semiregular::modifier<T> | |
| , public equality::modifier<T> | |
| { | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_REGULAR_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_UNIQUE_HPP | |
| #define STRONG_TYPE_UNIQUE_HPP | |
| namespace strong { | |
| struct unique { | |
| template<typename T> | |
| class modifier | |
| : private impl::valid_type< | |
| impl::require_move_constructible<T>::value && | |
| impl::require_move_assignable<T>::value | |
| > { | |
| public: | |
| constexpr modifier() = default; | |
| modifier(const modifier &) = delete; | |
| constexpr modifier(modifier &&) noexcept = default; | |
| modifier &operator=(const modifier &) = delete; | |
| constexpr modifier &operator=(modifier &&) noexcept = default; | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_UNIQUE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_INVOCABLE_HPP | |
| #define STRONG_TYPE_INVOCABLE_HPP | |
| namespace strong | |
| { | |
| struct invocable | |
| { | |
| template <typename> | |
| class modifier; | |
| }; | |
| template <typename T, typename Tag, typename ... Ms> | |
| class invocable::modifier<type<T, Tag, Ms...>> | |
| { | |
| using type = strong::type<T, Tag, Ms...>; | |
| public: | |
| template <typename ... Args, typename R = decltype(std::declval<T&>()(std::declval<Args>()...))> | |
| STRONG_CONSTEXPR | |
| R operator()(Args&& ... args) & | |
| noexcept (noexcept(std::declval<T&>()(std::declval<Args>()...))) | |
| { | |
| return call(static_cast<type&>(*this), std::forward<Args>(args)...); | |
| } | |
| template <typename ... Args, typename R = decltype(std::declval<T&&>()(std::declval<Args>()...))> | |
| STRONG_CONSTEXPR | |
| R operator()(Args&& ... args) && | |
| noexcept (noexcept(std::declval<T&&>()(std::declval<Args>()...))) | |
| { | |
| return call(static_cast<type&&>(std::move(*this)), std::forward<Args>(args)...); | |
| } | |
| template <typename ... Args, typename R = decltype(std::declval<const T&>()(std::declval<Args>()...))> | |
| STRONG_CONSTEXPR | |
| R operator()(Args&& ... args) const & | |
| noexcept (noexcept(std::declval<const T&>()(std::declval<Args>()...))) | |
| { | |
| return call(static_cast<const type&>(*this), std::forward<Args>(args)...); | |
| } | |
| template <typename ... Args, typename R = decltype(std::declval<const T&&>()(std::declval<Args>()...))> | |
| STRONG_CONSTEXPR | |
| R operator()(Args&& ... args) const && | |
| noexcept (noexcept(std::declval<const T&&>()(std::declval<Args>()...))) | |
| { | |
| return call(static_cast<const type&&>(std::move(*this)), std::forward<Args>(args)...); | |
| } | |
| private: | |
| template <typename Self, typename ... Ts> | |
| static STRONG_CONSTEXPR decltype(auto) call(Self&& self, Ts&& ... ts) | |
| { | |
| return value_of(std::forward<Self>(self))(std::forward<Ts>(ts)...); | |
| } | |
| }; | |
| } | |
| #endif //STRONG_TYPE_INVOCABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_ISTREAMABLE_HPP | |
| #define STRONG_TYPE_ISTREAMABLE_HPP | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #include <istream> | |
| #endif | |
| namespace strong | |
| { | |
| struct istreamable | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type must support stream input via operator>>"); | |
| }; | |
| template <typename T> | |
| class modifier<T, impl::void_t<decltype(std::declval<std::istream&>() >> std::declval<underlying_type_t<T>&>())>> | |
| { | |
| public: | |
| friend | |
| std::istream& | |
| operator>>( | |
| std::istream &is, | |
| T &t) | |
| { | |
| return is >> value_of(t); | |
| } | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_ISTREAMABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_OSTREAMABLE_HPP | |
| #define STRONG_TYPE_OSTREAMABLE_HPP | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #include <ostream> | |
| #endif | |
| namespace strong | |
| { | |
| struct ostreamable | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type support stream output via operator<<"); | |
| }; | |
| template <typename T> | |
| class modifier<T, impl::void_t<decltype(std::declval<std::ostream&>() << std::declval<const underlying_type_t<T>&>())>> | |
| { | |
| public: | |
| friend | |
| std::ostream& | |
| operator<<( | |
| std::ostream &os, | |
| const T &t) | |
| { | |
| return os << value_of(t); | |
| } | |
| }; | |
| }; | |
| template<typename T> | |
| using is_ostreamable = std::is_base_of<ostreamable::modifier<T>, T>; | |
| } | |
| #endif //STRONG_TYPE_OSTREAMABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_IOSTREAMABLE_HPP | |
| #define STRONG_TYPE_IOSTREAMABLE_HPP | |
| namespace strong | |
| { | |
| struct iostreamable | |
| { | |
| template <typename T> | |
| class modifier | |
| : public ostreamable::modifier<T> | |
| , public istreamable::modifier<T> | |
| { | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_IOSTREAMABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_INCREMENTABLE_HPP | |
| #define STRONG_TYPE_INCREMENTABLE_HPP | |
| namespace strong { | |
| struct incrementable | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type must be incrementable"); | |
| }; | |
| template <typename T> | |
| class modifier<T, impl::void_t<decltype(++std::declval<underlying_type_t<T>&>())>> | |
| { | |
| public: | |
| friend | |
| STRONG_CONSTEXPR | |
| T& | |
| operator++(T& t) | |
| noexcept(noexcept(++std::declval<T&>().value_of())) | |
| { | |
| ++value_of(t); | |
| return t; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| T | |
| operator++(T& t, int) | |
| { | |
| auto copy = t; | |
| ++t; | |
| return copy; | |
| } | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_INCREMENTABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_DECREMENTABLE_HPP | |
| #define STRONG_TYPE_DECREMENTABLE_HPP | |
| namespace strong | |
| { | |
| struct decrementable | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "underlying type must be decrementable"); | |
| }; | |
| template <typename T> | |
| class modifier<T, impl::void_t<decltype(--std::declval<underlying_type_t<T>&>())>> | |
| { | |
| public: | |
| friend | |
| STRONG_CONSTEXPR | |
| T& | |
| operator--(T& t) | |
| noexcept(noexcept(--std::declval<T&>().value_of())) | |
| { | |
| --value_of(t); | |
| return t; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| T | |
| operator--(T& t, int) | |
| { | |
| auto copy = t; | |
| --t; | |
| return copy; | |
| } | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_DECREMENTABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_BICREMENTABLE_HPP | |
| #define STRONG_TYPE_BICREMENTABLE_HPP | |
| namespace strong | |
| { | |
| struct bicrementable | |
| { | |
| template <typename T> | |
| class modifier | |
| : public incrementable::modifier<T> | |
| , public decrementable::modifier<T> | |
| { | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_BICREMENTABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_BOOLEAN_HPP | |
| #define STRONG_TYPE_BOOLEAN_HPP | |
| namespace strong | |
| { | |
| struct boolean | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type must be convertible to bool"); | |
| }; | |
| template <typename T> | |
| class modifier<T, impl::void_t<decltype(static_cast<bool>(std::declval<const underlying_type_t<T>>()))>> | |
| { | |
| public: | |
| STRONG_NODISCARD | |
| explicit | |
| STRONG_CONSTEXPR | |
| operator bool() | |
| const | |
| noexcept(noexcept(static_cast<bool>(value_of(std::declval<const T&>())))) | |
| { | |
| const auto& self = static_cast<const T&>(*this); | |
| return static_cast<bool>(value_of(self)); | |
| } | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_BOOLEAN_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_POINTER_HPP | |
| #define STRONG_TYPE_POINTER_HPP | |
| namespace strong | |
| { | |
| struct pointer | |
| { | |
| template <typename T, typename = void> | |
| class modifier; | |
| }; | |
| template <typename T> | |
| class pointer::modifier<T, void> | |
| { | |
| static_assert(impl::always_false<T>, "Underlying type must support dereferencing with operator*"); | |
| }; | |
| template <typename T, typename Tag, typename ... M> | |
| class pointer::modifier<::strong::type<T, Tag, M...>, impl::void_t<decltype(*std::declval<T>())>> | |
| { | |
| using type = strong::type<T, Tag, M...>; | |
| public: | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator==( | |
| const type& t, | |
| std::nullptr_t) | |
| noexcept(noexcept(std::declval<const TT&>() == nullptr)) | |
| -> decltype(std::declval<const TT&>() == nullptr) | |
| { | |
| return value_of(t) == nullptr; | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator==( | |
| std::nullptr_t, | |
| const type& t) | |
| noexcept(noexcept(nullptr == std::declval<const TT&>())) | |
| -> decltype(nullptr == std::declval<const TT&>()) | |
| { | |
| return value_of(t) == nullptr; | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator!=( | |
| const type& t, | |
| std::nullptr_t) | |
| noexcept(noexcept(std::declval<const TT&>() != nullptr)) | |
| -> decltype(std::declval<const TT&>() != nullptr) | |
| { | |
| return value_of(t) != nullptr; | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator!=( | |
| std::nullptr_t, | |
| const type& t) | |
| noexcept(noexcept(nullptr != std::declval<const TT&>())) | |
| -> decltype(nullptr != std::declval<const TT&>()) | |
| { | |
| return value_of(t) != nullptr; | |
| } | |
| STRONG_NODISCARD | |
| STRONG_CONSTEXPR | |
| decltype(*std::declval<const T&>()) | |
| operator*() | |
| const | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return *value_of(self); | |
| } | |
| STRONG_NODISCARD | |
| STRONG_CONSTEXPR | |
| decltype(&(*std::declval<const T&>())) operator->() const { return &operator*();} | |
| }; | |
| } | |
| #endif //STRONG_TYPE_POINTER_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_HASHABLE_HPP | |
| #define STRONG_TYPE_HASHABLE_HPP | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #include <functional> | |
| #endif | |
| namespace strong | |
| { | |
| struct hashable | |
| { | |
| template <typename T> | |
| class modifier{}; | |
| }; | |
| } | |
| namespace std { | |
| template<typename T, typename Tag, typename ... M> | |
| struct hash<::strong::type<T, Tag, M...>> | |
| : std::conditional_t< | |
| std::is_base_of< | |
| ::strong::hashable::modifier< | |
| ::strong::type<T, Tag, M...> | |
| >, | |
| ::strong::type<T, Tag, M...> | |
| >::value, | |
| hash<T>, | |
| std::false_type> | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| STRONG_NODISCARD | |
| decltype(auto) | |
| operator()( | |
| const ::strong::hashable::modifier<type> &t) | |
| const | |
| noexcept(noexcept(std::declval<hash<T>>()( | |
| value_of(std::declval<const type &>())))) | |
| { | |
| auto &tt = static_cast<const type &>(t); | |
| return hash<T>::operator()(value_of(tt)); | |
| } | |
| }; | |
| } | |
| #endif //STRONG_TYPE_HASHABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_DIFFERENCE_HPP | |
| #define STRONG_TYPE_DIFFERENCE_HPP | |
| namespace strong | |
| { | |
| namespace impl | |
| { | |
| struct conditionally_ordered | |
| { | |
| template <typename T> | |
| class modifier; | |
| }; | |
| template <typename T, typename Tag, typename ... M> | |
| class conditionally_ordered::modifier<::strong::type<T, Tag, M...>> | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator<( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const TT&>() < std::declval<const TT&>())) | |
| -> decltype(std::declval<const TT&>() < std::declval<const TT&>()) | |
| { | |
| return value_of(lh) < value_of(rh); | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator<=( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const TT&>() <= std::declval<const TT&>())) | |
| -> decltype(std::declval<const TT&>() <= std::declval<const TT&>()) | |
| { | |
| return value_of(lh) <= value_of(rh); | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator>( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const TT&>() > std::declval<const TT&>())) | |
| -> decltype(std::declval<const TT&>() > std::declval<const TT&>()) | |
| { | |
| return value_of(lh) > value_of(rh); | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto | |
| operator>=( | |
| const type& lh, | |
| const type& rh) | |
| noexcept(noexcept(std::declval<const TT&>() >= std::declval<const TT&>())) | |
| -> decltype(std::declval<const TT&>() >= std::declval<const TT&>()) | |
| { | |
| return value_of(lh) >= value_of(rh); | |
| } | |
| }; | |
| } | |
| struct difference | |
| { | |
| template <typename T> | |
| class modifier; | |
| }; | |
| template <typename T, typename Tag, typename ... M> | |
| class difference::modifier<::strong::type<T, Tag, M...>> | |
| : public impl::conditionally_ordered::modifier<::strong::type<T, Tag, M...>> | |
| , public equality::modifier<::strong::type<T, Tag, M...>> | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| friend | |
| STRONG_CONSTEXPR | |
| type& operator+=(type& lh, const type& rh) | |
| noexcept(noexcept(value_of(lh) += value_of(rh))) | |
| { | |
| value_of(lh) += value_of(rh); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& operator-=(type& lh, const type& rh) | |
| noexcept(noexcept(value_of(lh) -= value_of(rh))) | |
| { | |
| value_of(lh) -= value_of(rh); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& operator*=(type& lh, const T& rh) | |
| noexcept(noexcept(value_of(lh) *= rh)) | |
| { | |
| value_of(lh) *= rh; | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& operator/=(type& lh, const T& rh) | |
| noexcept(noexcept(value_of(lh) /= rh)) | |
| { | |
| value_of(lh) /= rh; | |
| return lh; | |
| } | |
| template <typename TT = T, typename = decltype(std::declval<TT&>()%= std::declval<const TT&>())> | |
| friend | |
| STRONG_CONSTEXPR | |
| type& operator%=(type& lh, const T& rh) | |
| noexcept(noexcept(value_of(lh) %= rh)) | |
| { | |
| value_of(lh)%= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type operator+(type lh, const type& rh) | |
| { | |
| lh += rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type operator-(type lh, const type& rh) | |
| { | |
| lh -= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type operator*(type lh, const T& rh) | |
| { | |
| lh *= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type operator*(const T& lh, type rh) | |
| { | |
| rh *= lh; | |
| return rh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type operator/(type lh, const T& rh) | |
| { | |
| lh /= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| T operator/(const type& lh, const type& rh) | |
| { | |
| return value_of(lh) / value_of(rh); | |
| } | |
| template <typename TT = T, typename = decltype(std::declval<TT&>() %= std::declval<const TT&>())> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type operator%(type lh, const T& rh) | |
| noexcept(noexcept(lh%= rh)) | |
| { | |
| lh %= rh; | |
| return lh; | |
| } | |
| template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| T operator%(type lh, type rh) | |
| noexcept(noexcept(value_of(lh) % value_of(rh))) | |
| { | |
| return value_of(lh) % value_of(rh); | |
| } | |
| }; | |
| } | |
| #endif //STRONG_TYPE_DIFFERENCE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_AFFINE_POINT_HPP | |
| #define STRONG_TYPE_AFFINE_POINT_HPP | |
| namespace strong | |
| { | |
| template <typename D = void> | |
| struct affine_point | |
| { | |
| template <typename T> | |
| class modifier; | |
| }; | |
| namespace impl | |
| { | |
| template <typename T, typename = void> | |
| struct subtractable : std::false_type {}; | |
| template <typename T> | |
| struct subtractable<T, void_t<decltype(std::declval<const T&>() - std::declval<const T&>())>> | |
| : std::true_type {}; | |
| } | |
| template <typename D> | |
| template <typename T, typename Tag, typename ... M> | |
| class affine_point<D>::modifier<::strong::type<T, Tag, M...>> | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| static_assert(impl::subtractable<T>::value, "it must be possible to subtract instances of your underlying type"); | |
| using base_diff_type = decltype(std::declval<const T&>() - std::declval<const T&>()); | |
| public: | |
| using difference = std::conditional_t<std::is_same<D, void>{}, strong::type<base_diff_type, Tag, strong::difference>, D>; | |
| static_assert(std::is_constructible<difference, base_diff_type>::value, ""); | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| difference | |
| operator-( | |
| const type& lh, | |
| const type& rh) | |
| { | |
| return difference(value_of(lh) - value_of(rh)); | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator+=( | |
| type& lh, | |
| const difference& d) | |
| noexcept(noexcept(value_of(lh) += impl::access(d))) | |
| { | |
| value_of(lh) += impl::access(d); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator-=( | |
| type& lh, | |
| const difference& d) | |
| noexcept(noexcept(value_of(lh) -= impl::access(d))) | |
| { | |
| value_of(lh) -= impl::access(d); | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator+( | |
| type lh, | |
| const difference& d) | |
| { | |
| return lh += d; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator+( | |
| const difference& d, | |
| type rh) | |
| { | |
| return rh+= d; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator-( | |
| type lh, | |
| const difference& d) | |
| { | |
| return lh -= d; | |
| } | |
| }; | |
| } | |
| #endif //STRONG_TYPE_AFFINE_POINT_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_ARITHMETIC_HPP | |
| #define STRONG_TYPE_ARITHMETIC_HPP | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #include <limits> | |
| #endif | |
| namespace strong | |
| { | |
| struct arithmetic { | |
| template<typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type must support arithmeric operations"); | |
| }; | |
| }; | |
| template <typename T, typename Tag, typename ... Ms> | |
| class arithmetic::modifier<strong::type<T, Tag, Ms...>, impl::void_t<decltype(std::declval<T>() * std::declval<T>() - std::declval<T>() / std::declval<T>())>> | |
| { | |
| using type = strong::type<T, Tag, Ms...>; | |
| public: | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator-( | |
| const type &lh) | |
| { | |
| return type{-value_of(lh)}; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator+=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) += value_of(rh))) | |
| { | |
| value_of(lh) += value_of(rh); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator-=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) -= value_of(rh))) | |
| { | |
| value_of(lh) -= value_of(rh); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator*=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) *= value_of(rh))) | |
| { | |
| value_of(lh) *= value_of(rh); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator/=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) /= value_of(rh))) | |
| { | |
| value_of(lh) /= value_of(rh); | |
| return lh; | |
| } | |
| template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())> | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator%=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) %= value_of(rh))) | |
| { | |
| value_of(lh) %= value_of(rh); | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator+( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh += rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator-( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh -= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator*( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh *= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator/( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh /= rh; | |
| return lh; | |
| } | |
| template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator%( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh %= rh; | |
| return lh; | |
| } | |
| }; | |
| } | |
| template <typename T, typename Tag, typename ... Ms> | |
| #if defined(__cpp_concepts) | |
| requires strong::type_is_v<strong::type<T, Tag, Ms...>, strong::arithmetic> | |
| class std::numeric_limits<strong::type<T, Tag, Ms...>> | |
| : public std::numeric_limits<T> | |
| #else | |
| class std::numeric_limits<strong::type<T, Tag, Ms...>> | |
| : public std::conditional< | |
| strong::type_is_v<strong::type<T, Tag, Ms...>, strong::arithmetic>, | |
| std::numeric_limits<T>, | |
| std::numeric_limits<void> | |
| >::type | |
| #endif | |
| { | |
| using type = strong::type<T, Tag, Ms...>; | |
| public: | |
| STRONG_NODISCARD static constexpr type min() noexcept { return type{std::numeric_limits<T>::min()};} | |
| STRONG_NODISCARD static constexpr type lowest() noexcept { return type{std::numeric_limits<T>::lowest()};} | |
| STRONG_NODISCARD static constexpr type max() noexcept { return type{std::numeric_limits<T>::max()};} | |
| STRONG_NODISCARD static constexpr type epsilon() noexcept { return type{std::numeric_limits<T>::epsilon()};} | |
| STRONG_NODISCARD static constexpr type round_error() noexcept { return type{std::numeric_limits<T>::round_error()};} | |
| STRONG_NODISCARD static constexpr type infinity() noexcept { return type{std::numeric_limits<T>::infinity()};} | |
| STRONG_NODISCARD static constexpr type quiet_NaN() noexcept { return type{std::numeric_limits<T>::quiet_NaN()};} | |
| STRONG_NODISCARD static constexpr type signaling_NaN() noexcept { return type{std::numeric_limits<T>::signaling_NaN()};} | |
| STRONG_NODISCARD static constexpr type denorm_min() noexcept { return type{std::numeric_limits<T>::denorm_min()};} | |
| }; | |
| #endif //STRONG_TYPE_ARITHMETIC_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_BITARITHMETIC_HPP | |
| #define STRONG_TYPE_BITARITHMETIC_HPP | |
| namespace strong | |
| { | |
| struct bitarithmetic | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T>, | |
| "Underlying type must support bitarithmetic operations &, | and ^"); | |
| }; | |
| template <typename T, typename Tag, typename ... Ms> | |
| class modifier<type<T, Tag, Ms...>, impl::void_t<decltype(((std::declval<T&>() |= std::declval<T>()) &= std::declval<T>()) ^= std::declval<T>())>> | |
| { | |
| using type = strong::type<T, Tag, Ms...>; | |
| public: | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator&=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) &= value_of(rh))) | |
| { | |
| value_of(lh) = T(value_of(lh) & value_of(rh)); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator|=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) |= value_of(rh))) | |
| { | |
| value_of(lh) = T(value_of(lh) | value_of(rh)); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator^=( | |
| type &lh, | |
| const type &rh) | |
| noexcept(noexcept(value_of(lh) ^= value_of(rh))) | |
| { | |
| value_of(lh) = T(value_of(lh) ^ value_of(rh)); | |
| return lh; | |
| } | |
| template <typename C> | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator<<=( | |
| type &lh, | |
| C c) | |
| noexcept(noexcept(value_of(lh) <<= c)) | |
| { | |
| value_of(lh) = T(value_of(lh) << c); | |
| return lh; | |
| } | |
| template <typename C> | |
| friend | |
| STRONG_CONSTEXPR | |
| type& | |
| operator>>=( | |
| type &lh, | |
| C c) | |
| noexcept(noexcept(value_of(lh) >>= c)) | |
| { | |
| value_of(lh) = T(value_of(lh) >> c); | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator~( | |
| const type &lh) | |
| { | |
| auto v = value_of(lh); | |
| return type(T(~v)); | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator&( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh &= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator|( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh |= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator^( | |
| type lh, | |
| const type &rh) | |
| { | |
| lh ^= rh; | |
| return lh; | |
| } | |
| template <typename C> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator<<( | |
| type lh, | |
| C c) | |
| { | |
| lh <<= c; | |
| return lh; | |
| } | |
| template <typename C> | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| type | |
| operator>>( | |
| type lh, | |
| C c) | |
| { | |
| lh >>= c; | |
| return lh; | |
| } | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_BITARITHMETIC_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_INDEXED_HPP | |
| #define STRONG_TYPE_INDEXED_HPP | |
| namespace strong | |
| { | |
| template <typename I = void> | |
| struct indexed | |
| { | |
| template <typename T, typename = void> | |
| class modifier | |
| { | |
| static_assert(impl::always_false<T, I>, | |
| "Underlying type must support indexing using operator[]"); | |
| }; | |
| }; | |
| template <> | |
| struct indexed<void> { | |
| template<typename> | |
| class modifier; | |
| template <typename T, typename Tag, typename ... Ms> | |
| class modifier<type<T, Tag, Ms...>> { | |
| using ref = T&; | |
| using cref = const T&; | |
| using rref = T&&; | |
| using type = strong::type<T, Tag, Ms...>; | |
| public: | |
| template<typename I> | |
| STRONG_NODISCARD | |
| auto | |
| operator[]( | |
| const I &i) | |
| const & | |
| noexcept(noexcept(std::declval<cref>()[impl::access(i)])) | |
| -> decltype(std::declval<cref>()[impl::access(i)]) { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self)[impl::access(i)]; | |
| } | |
| template<typename I> | |
| STRONG_NODISCARD | |
| auto | |
| operator[]( | |
| const I &i) | |
| & | |
| noexcept(noexcept(std::declval<ref>()[impl::access(i)])) | |
| -> decltype(std::declval<ref>()[impl::access(i)]) { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(self)[impl::access(i)]; | |
| } | |
| template<typename I> | |
| STRONG_NODISCARD | |
| auto | |
| operator[]( | |
| const I &i) | |
| && | |
| noexcept(noexcept(std::declval<rref>()[impl::access(i)])) | |
| -> decltype(std::declval<rref>()[impl::access(i)]) { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(std::move(self))[impl::access(i)]; | |
| } | |
| template<typename I, typename C = cref> | |
| STRONG_NODISCARD | |
| auto | |
| at( | |
| const I &i) | |
| const & | |
| -> decltype(std::declval<C>().at(impl::access(i))) { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).at(impl::access(i)); | |
| } | |
| template<typename I, typename R = ref> | |
| STRONG_NODISCARD | |
| auto | |
| at( | |
| const I &i) | |
| & | |
| -> decltype(std::declval<R>().at(impl::access(i))) { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(self).at(impl::access(i)); | |
| } | |
| template<typename I, typename R = rref> | |
| STRONG_NODISCARD | |
| auto | |
| at( | |
| const I &i) | |
| && | |
| -> decltype(std::declval<R>().at(impl::access(i))) { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(std::move(self)).at(impl::access(i)); | |
| } | |
| }; | |
| }; | |
| template <typename I> | |
| template <typename T, typename Tag, typename ... M> | |
| class indexed<I>::modifier< | |
| type<T, Tag, M...>, | |
| impl::void_t< decltype( std::declval<const T&>()[std::declval<underlying_type_t<I>>()] ) > | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| STRONG_NODISCARD | |
| auto | |
| operator[]( | |
| const I& i) | |
| const & | |
| noexcept(noexcept(std::declval<const T&>()[impl::access(i)])) | |
| -> decltype(std::declval<const T&>()[impl::access(i)]) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self)[impl::access(i)]; | |
| } | |
| STRONG_NODISCARD | |
| auto | |
| operator[]( | |
| const I& i) | |
| & | |
| noexcept(noexcept(std::declval<T&>()[impl::access(i)])) | |
| -> decltype(std::declval<T&>()[impl::access(i)]) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(self)[impl::access(i)]; | |
| } | |
| STRONG_NODISCARD | |
| auto | |
| operator[]( | |
| const I& i) | |
| && | |
| noexcept(noexcept(std::declval<T&&>()[impl::access(i)])) | |
| -> decltype(std::declval<T&&>()[impl::access(i)]) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(std::move(self))[impl::access(i)]; | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| auto | |
| at( | |
| const I& i) | |
| const & | |
| -> decltype(std::declval<const TT&>().at(impl::access(i))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).at(impl::access(i)); | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| auto | |
| at( | |
| const I& i) | |
| & | |
| -> decltype(std::declval<TT&>().at(impl::access(i))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(self).at(impl::access(i)); | |
| } | |
| template <typename TT = T> | |
| STRONG_NODISCARD | |
| auto | |
| at( | |
| const I& i) | |
| && | |
| -> decltype(std::declval<TT&&>().at(impl::access(i))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return value_of(std::move(self)).at(impl::access(i)); | |
| } | |
| }; | |
| } | |
| #endif //STRONG_TYPE_INDEXED_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_ITERATOR_HPP | |
| #define STRONG_TYPE_ITERATOR_HPP | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #include <iterator> | |
| #endif | |
| #if __cplusplus >= 202002L && (((! defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000)) && (!defined(__GLIBCXX__) || __GLIBCXX__ >= 20230528L)) | |
| #define STRONG_TYPE_CONTIGUOUS_ITERATOR 1 | |
| #else | |
| #define STRONG_TYPE_CONTIGUOUS_ITERATOR 0 | |
| #endif | |
| namespace strong | |
| { | |
| namespace internal { | |
| template <typename I, typename = void> | |
| struct iterator_traits | |
| { | |
| using iterator_category = std::input_iterator_tag; | |
| using difference_type = typename I::difference_type; | |
| using reference = decltype(*std::declval<I>()); | |
| using value_type = std::remove_cv_t<std::remove_reference_t<reference>>; | |
| using pointer = value_type*; | |
| }; | |
| template <typename I> | |
| struct iterator_traits<I, impl::void_t<typename I::iterator_category>> | |
| { | |
| using iterator_category = typename I::iterator_category; | |
| using difference_type = typename I::difference_type; | |
| using reference = decltype(*std::declval<I>()); | |
| using value_type = std::remove_cv_t<std::remove_reference_t<reference>>; | |
| using pointer = value_type*; | |
| }; | |
| template <typename T> | |
| struct iterator_traits<T*, void> | |
| { | |
| #if STRONG_TYPE_CONTIGUOUS_ITERATOR | |
| using iterator_category = std::contiguous_iterator_tag; | |
| #else | |
| using iterator_category = std::random_access_iterator_tag; | |
| #endif | |
| using difference_type = std::ptrdiff_t; | |
| using value_type = T; | |
| using reference = T&; | |
| using pointer = T*; | |
| }; | |
| } | |
| class iterator | |
| { | |
| public: | |
| template <typename I, | |
| typename category = typename internal::iterator_traits<underlying_type_t<I>>::iterator_category> | |
| class modifier | |
| : public pointer::modifier<I> | |
| , public incrementable::modifier<I> | |
| { | |
| public: | |
| using difference_type = typename internal::iterator_traits<underlying_type_t<I>>::difference_type; | |
| using value_type = typename internal::iterator_traits<underlying_type_t<I>>::value_type; | |
| using pointer = typename internal::iterator_traits<underlying_type_t<I>>::pointer; | |
| using reference = typename internal::iterator_traits<underlying_type_t<I>>::reference; | |
| using iterator_category = typename internal::iterator_traits<underlying_type_t<I>>::iterator_category; | |
| }; | |
| template <typename I> | |
| class modifier<I, std::forward_iterator_tag> | |
| : public modifier<I, std::input_iterator_tag> | |
| , public strong::equality::modifier<I> | |
| {}; | |
| template <typename I> | |
| class modifier<I, std::bidirectional_iterator_tag> | |
| : public modifier<I, std::forward_iterator_tag> | |
| , public decrementable::modifier<I> | |
| { | |
| }; | |
| template <typename I> | |
| class modifier<I, std::random_access_iterator_tag> | |
| : public modifier<I, std::bidirectional_iterator_tag> | |
| , public affine_point<typename std::iterator_traits<underlying_type_t<I>>::difference_type>::template modifier<I> | |
| , public indexed<>::modifier<I> | |
| , public ordered::modifier<I> | |
| { | |
| }; | |
| #if STRONG_TYPE_CONTIGUOUS_ITERATOR | |
| template <typename I> | |
| class modifier<I, std::contiguous_iterator_tag> | |
| : public modifier<I, std::bidirectional_iterator_tag> | |
| , public affine_point<typename std::iterator_traits<underlying_type_t<I>>::difference_type>::template modifier<I> | |
| , public indexed<>::modifier<I> | |
| , public ordered::modifier<I> | |
| { | |
| }; | |
| #endif | |
| }; | |
| } | |
| #endif //STRONG_TYPE_ITERATOR_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_RANGE_HPP | |
| #define STRONG_TYPE_RANGE_HPP | |
| #if __has_include(<ranges>) | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| # include <ranges> | |
| #endif | |
| #endif | |
| #if defined(_MSC_VER) && __cpp_lib_ranges >= 202110L | |
| # define STRONG_TYPE_HAS_RANGES | |
| #endif | |
| #if __cplusplus >= 202101L | |
| # if (not defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) && (__cpp_lib_ranges >= 202106L) | |
| # define STRONG_TYPE_HAS_RANGES | |
| # endif | |
| # if (not defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000) | |
| # define STRONG_TYPE_HAS_RANGES | |
| # endif | |
| #endif | |
| namespace strong | |
| { | |
| namespace internal { | |
| struct not_an_iterator {}; | |
| #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) | |
| template <typename T> | |
| auto begin_type(T* t) -> decltype(std::ranges::begin(*t)); | |
| #else | |
| template <typename T> | |
| auto begin_type(T* t) -> decltype(t->begin()); | |
| #endif | |
| auto begin_type(...) -> not_an_iterator; | |
| #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) | |
| template <typename T> | |
| auto const_begin_type(const T* t) -> decltype(std::ranges::begin(*t)); | |
| #else | |
| template <typename T> | |
| auto const_begin_type(const T* t) -> decltype(t->begin()); | |
| #endif | |
| auto const_begin_type(...) -> not_an_iterator; | |
| #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) | |
| template <typename T> | |
| auto end_type(T* t) -> decltype(std::ranges::end(*t)); | |
| #else | |
| template <typename T> | |
| auto end_type(T* t) -> decltype(t->end()); | |
| #endif | |
| auto end_type(...) -> not_an_iterator; | |
| #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) | |
| template <typename T> | |
| auto const_end_type(const T* t) -> decltype(std::ranges::end(*t)); | |
| #else | |
| template <typename T> | |
| auto const_end_type(const T* t) -> decltype(t->end()); | |
| #endif | |
| auto const_end_type(...) -> not_an_iterator; | |
| #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) | |
| template <typename T> | |
| auto cbegin_type(const T* t) -> decltype(std::ranges::cbegin(*t)); | |
| #else | |
| template <typename T> | |
| auto cbegin_type(const T* t) -> decltype(t->cbegin()); | |
| #endif | |
| auto cbegin_type(...) -> not_an_iterator; | |
| #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) | |
| template <typename T> | |
| auto cend_type(const T* t) -> decltype(std::ranges::cend(*t)); | |
| #else | |
| template <typename T> | |
| auto cend_type(const T* t) -> decltype(t->cend()); | |
| #endif | |
| auto cend_type(...) -> not_an_iterator; | |
| template <typename T> | |
| struct begin_end_traits | |
| { | |
| using begin_iterator = decltype(begin_type(std::declval<T*>())); | |
| using const_begin_iterator = decltype(const_begin_type(std::declval<const T*>())); | |
| using end_iterator = decltype(end_type(std::declval<T*>())); | |
| using const_end_iterator = decltype(const_end_type(std::declval<const T*>())); | |
| using cbegin_iterator = decltype(cbegin_type(std::declval<const T*>())); | |
| using cend_iterator = decltype(cend_type(std::declval<const T*>())); | |
| }; | |
| constexpr bool is_random_access(std::random_access_iterator_tag) { return true;} | |
| constexpr bool is_random_access(std::input_iterator_tag) { return false;} | |
| constexpr bool is_random_access(std::output_iterator_tag) { return false;} | |
| } | |
| #if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230601L)) | |
| #define STRONG_TYPE_BEGIN(x) std::ranges::begin(x) | |
| #define STRONG_TYPE_END(x) std::ranges::end(x) | |
| #define STRONG_TYPE_CBEGIN(x) std::ranges::cbegin(x) | |
| #define STRONG_TYPE_CEND(x) std::ranges::cend(x) | |
| #else | |
| #define STRONG_TYPE_BEGIN(x) x.begin() | |
| #define STRONG_TYPE_END(x) x.end() | |
| #define STRONG_TYPE_CBEGIN(x) x.cbegin() | |
| #define STRONG_TYPE_CEND(x) x.cend() | |
| #endif | |
| class range | |
| { | |
| public: | |
| template < | |
| typename R, | |
| typename = typename internal::begin_end_traits<underlying_type_t<R>>::begin_iterator, | |
| typename = typename internal::begin_end_traits<underlying_type_t<R>>::end_iterator, | |
| typename = typename internal::begin_end_traits<underlying_type_t<R>>::const_begin_iterator, | |
| typename = typename internal::begin_end_traits<underlying_type_t<R>>::const_end_iterator, | |
| typename = typename internal::begin_end_traits<underlying_type_t<R>>::cbegin_iterator, | |
| typename = typename internal::begin_end_traits<underlying_type_t<R>>::cend_iterator> | |
| class modifier; | |
| }; | |
| template <typename R> | |
| class range::modifier< | |
| R, | |
| internal::not_an_iterator, internal::not_an_iterator, | |
| internal::not_an_iterator, internal::not_an_iterator, | |
| internal::not_an_iterator, internal::not_an_iterator | |
| > | |
| { | |
| static_assert(impl::always_false<R>, | |
| "Underlying type must have begin() and end()"); | |
| }; | |
| template <typename T, typename Tag, typename ... M, typename r_iterator> | |
| class range::modifier< | |
| type<T, Tag, M...>, | |
| r_iterator, r_iterator, | |
| r_iterator, r_iterator, | |
| r_iterator, r_iterator> | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits<r_iterator>::iterator_category{}); | |
| public: | |
| using const_iterator = std::conditional_t<random_access, | |
| ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<r_iterator>, strong::ordered_with<r_iterator>>, | |
| ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<r_iterator>> | |
| >; | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| begin() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| end() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| cbegin() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| cend() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_CEND(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_CEND(value_of(self))}; | |
| } | |
| template <typename TT = const T&> | |
| STRONG_NODISCARD | |
| constexpr | |
| decltype(std::declval<TT>().size()) | |
| size() | |
| const | |
| noexcept(noexcept(std::declval<TT>().size())) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).size(); | |
| } | |
| }; | |
| template <typename T, typename Tag, typename ... M, typename r_iterator, typename r_const_iterator> | |
| class range::modifier< | |
| type<T, Tag, M...>, | |
| r_iterator, r_iterator, | |
| r_const_iterator, r_const_iterator, | |
| r_const_iterator, r_const_iterator | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits<r_iterator>::iterator_category{}); | |
| public: | |
| using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>; | |
| using const_iterator = std::conditional_t<random_access, | |
| ::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>, strong::ordered_with<iterator>>, | |
| ::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>> | |
| >; | |
| STRONG_NODISCARD | |
| constexpr | |
| iterator | |
| begin() | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| iterator | |
| end() | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return iterator{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| begin() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| end() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| cbegin() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| cend() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_CEND(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_CEND(value_of(self))}; | |
| } | |
| template <typename TT = const T&> | |
| STRONG_NODISCARD | |
| constexpr | |
| decltype(std::declval<TT>().size()) | |
| size() | |
| const | |
| noexcept(noexcept(std::declval<TT>().size())) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).size(); | |
| } | |
| }; | |
| template <typename T, typename Tag, typename ... M, typename r_iterator, typename r_const_iterator, typename r_sentinel> | |
| class range::modifier< | |
| type<T, Tag, M...>, | |
| r_iterator, r_sentinel, | |
| r_iterator, r_sentinel, | |
| r_const_iterator, r_sentinel | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits<r_iterator>::iterator_category{}); | |
| public: | |
| using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>; | |
| using const_iterator = std::conditional_t<random_access, | |
| ::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>, strong::ordered_with<iterator>>, | |
| ::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>> | |
| >; | |
| using sentinel = strong::type<r_sentinel, Tag, strong::equality_with<iterator, const_iterator>>; | |
| STRONG_NODISCARD | |
| constexpr | |
| iterator | |
| begin() | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| sentinel | |
| end() | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return sentinel{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| iterator | |
| begin() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| sentinel | |
| end() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return sentinel{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| cbegin() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| sentinel | |
| cend() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_CEND(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return sentinel{STRONG_TYPE_CEND(value_of(self))}; | |
| } | |
| template <typename TT = const T&> | |
| STRONG_NODISCARD | |
| constexpr | |
| decltype(std::declval<TT>().size()) | |
| size() | |
| const | |
| noexcept(noexcept(std::declval<TT>().size())) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).size(); | |
| } | |
| }; | |
| template <typename T, typename Tag, typename ... M, typename r_iterator> | |
| class range::modifier< | |
| type<T, Tag, M...>, | |
| r_iterator, r_iterator, | |
| internal::not_an_iterator, internal::not_an_iterator, | |
| internal::not_an_iterator, internal::not_an_iterator | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>; | |
| STRONG_NODISCARD | |
| constexpr | |
| iterator | |
| begin() | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| iterator | |
| end() | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return iterator{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| template <typename TT = const T&> | |
| STRONG_NODISCARD | |
| constexpr | |
| decltype(std::declval<TT>().size()) | |
| size() | |
| const | |
| noexcept(noexcept(std::declval<TT>().size())) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).size(); | |
| } | |
| }; | |
| template <typename T, typename Tag, typename ... M, typename r_iterator, typename r_sentinel> | |
| class range::modifier< | |
| type<T, Tag, M...>, | |
| r_iterator, r_sentinel, | |
| internal::not_an_iterator, internal::not_an_iterator, | |
| internal::not_an_iterator, internal::not_an_iterator | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>; | |
| using sentinel = ::strong::type<r_sentinel, Tag, strong::equality_with<iterator>>; | |
| STRONG_NODISCARD | |
| constexpr | |
| iterator | |
| begin() | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| sentinel | |
| end() | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<type&>(*this); | |
| return sentinel{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| template <typename TT = const T&> | |
| STRONG_NODISCARD | |
| constexpr | |
| decltype(std::declval<TT>().size()) | |
| size() | |
| const | |
| noexcept(noexcept(std::declval<TT>().size())) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).size(); | |
| } | |
| }; | |
| template <typename T, typename Tag, typename ... M, typename r_const_iterator, typename r_sentinel> | |
| class range::modifier< | |
| type<T, Tag, M...>, | |
| internal::not_an_iterator, internal::not_an_iterator, | |
| r_const_iterator, r_sentinel, | |
| internal::not_an_iterator, internal::not_an_iterator | |
| > | |
| { | |
| using type = ::strong::type<T, Tag, M...>; | |
| public: | |
| using const_iterator = ::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible>; | |
| using sentinel = ::strong::type<r_sentinel, Tag, strong::equality_with<const_iterator>>; | |
| STRONG_NODISCARD | |
| constexpr | |
| const_iterator | |
| begin() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return const_iterator{STRONG_TYPE_BEGIN(value_of(self))}; | |
| } | |
| STRONG_NODISCARD | |
| constexpr | |
| sentinel | |
| end() | |
| const | |
| noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>()))) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return sentinel{STRONG_TYPE_END(value_of(self))}; | |
| } | |
| template <typename TT = const T&> | |
| STRONG_NODISCARD | |
| constexpr | |
| decltype(std::declval<TT>().size()) | |
| size() | |
| const | |
| noexcept(noexcept(std::declval<TT>().size())) | |
| { | |
| auto& self = static_cast<const type&>(*this); | |
| return value_of(self).size(); | |
| } | |
| }; | |
| } | |
| #endif //STRONG_TYPE_RANGE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_CONVERTIBLE_TO_HPP | |
| #define STRONG_TYPE_CONVERTIBLE_TO_HPP | |
| namespace strong | |
| { | |
| namespace impl | |
| { | |
| template<typename T, typename D, typename = void> | |
| struct converter | |
| { | |
| static_assert(always_false<T, D>, | |
| "Underlying type must be convertible to target type"); | |
| }; | |
| template <typename T, typename Tag, typename ... Ms, typename D> | |
| struct converter< | |
| strong::type<T, Tag, Ms...>, | |
| D, | |
| impl::void_t<decltype(static_cast<D>(std::declval<const T&>()))> | |
| > | |
| { | |
| STRONG_CONSTEXPR explicit operator D() const | |
| noexcept(noexcept(static_cast<D>(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const strong::type<T, Tag, Ms...>&>(*this); | |
| return static_cast<D>(value_of(self)); | |
| } | |
| }; | |
| } | |
| template <typename ... Ts> | |
| struct convertible_to | |
| { | |
| template <typename T> | |
| struct modifier : impl::converter<T, Ts>... | |
| { | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_CONVERTIBLE_TO_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP | |
| #define STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP | |
| namespace strong | |
| { | |
| namespace impl { | |
| template<typename T, typename D, typename = void> | |
| struct implicit_converter | |
| { | |
| static_assert(impl::always_false<T,D>, | |
| "Underlying type must be convertible to target type"); | |
| }; | |
| template <typename T, typename Tag, typename ... Ms, typename D> | |
| struct implicit_converter< | |
| strong::type<T, Tag, Ms...>, | |
| D, | |
| void_t<decltype(static_cast<D>(std::declval<const T&>()))> | |
| > | |
| { | |
| STRONG_CONSTEXPR operator D() const | |
| noexcept(noexcept(static_cast<D>(std::declval<const T&>()))) | |
| { | |
| auto& self = static_cast<const strong::type<T, Tag, Ms...>&>(*this); | |
| return static_cast<D>(value_of(self)); | |
| } | |
| }; | |
| } | |
| template <typename ... Ts> | |
| struct implicitly_convertible_to | |
| { | |
| template <typename T> | |
| struct modifier : impl::implicit_converter<T, Ts>... | |
| { | |
| }; | |
| }; | |
| } | |
| #endif //STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_FORMATTABLE_HPP | |
| #define STRONG_TYPE_FORMATTABLE_HPP | |
| #ifndef STRONG_HAS_STD_FORMAT | |
| #if __has_include(<version>) | |
| #include <version> | |
| #if defined(__cpp_lib_format) && __cpp_lib_format >= 201907 | |
| #define STRONG_HAS_STD_FORMAT 1 | |
| #endif | |
| #endif | |
| #endif | |
| #ifndef STRONG_HAS_STD_FORMAT | |
| #define STRONG_HAS_STD_FORMAT 0 | |
| #endif | |
| #ifndef STRONG_HAS_FMT_FORMAT | |
| #if __has_include(<fmt/format.h>) | |
| #define STRONG_HAS_FMT_FORMAT 1 | |
| #else | |
| #define STRONG_HAS_FMT_FORMAT 0 | |
| #endif | |
| #endif | |
| #if STRONG_HAS_STD_FORMAT | |
| #if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY) | |
| #include <format> | |
| #endif | |
| #endif | |
| #if STRONG_HAS_FMT_FORMAT | |
| #include <fmt/format.h> | |
| #include <fmt/ostream.h> | |
| #endif | |
| namespace strong | |
| { | |
| struct formattable | |
| { | |
| template <typename T> | |
| class modifier{}; | |
| }; | |
| template <typename T> | |
| using is_formattable = std::is_base_of<formattable::modifier<T>, T>; | |
| } | |
| #if STRONG_HAS_STD_FORMAT | |
| namespace std | |
| { | |
| template<typename T, typename Tag, typename... M, typename Char> | |
| requires std::is_base_of_v<::strong::formattable::modifier<::strong::type<T, Tag, M...>>, | |
| ::strong::type<T, Tag, M...>> | |
| struct formatter<::strong::type<T, Tag, M...>, Char> : formatter<T, Char> | |
| { | |
| template<typename FormatContext, typename Type> | |
| STRONG_CONSTEXPR | |
| decltype(auto) | |
| format(const Type& t, FormatContext& fc) const | |
| noexcept(noexcept(std::declval<formatter<T, Char>>().format(std::declval<const T&>(), fc))) | |
| { | |
| return formatter<T, Char>::format(value_of(t), fc); | |
| } | |
| template<typename FormatContext, typename Type> | |
| STRONG_CONSTEXPR | |
| decltype(auto) | |
| format(const Type& t, FormatContext& fc) | |
| noexcept(noexcept(std::declval<formatter<T, Char>>().format(std::declval<const T&>(), fc))) | |
| { | |
| return formatter<T, Char>::format(value_of(t), fc); | |
| } | |
| }; | |
| } | |
| #endif | |
| #if STRONG_HAS_FMT_FORMAT | |
| namespace strong { | |
| template <typename T, typename Char> | |
| struct formatter; | |
| template <typename T, typename Tag, typename ... M, typename Char> | |
| struct formatter<type<T, Tag, M...>, Char> : fmt::formatter<T, Char> | |
| { | |
| template<typename FormatContext, typename Type> | |
| STRONG_CONSTEXPR | |
| decltype(auto) | |
| format(const Type& t, FormatContext& fc) const | |
| noexcept(noexcept(std::declval<fmt::formatter<T, Char>>().format(std::declval<const T&>(), fc))) | |
| { | |
| return fmt::formatter<T, Char>::format(value_of(t), fc); | |
| } | |
| template<typename FormatContext, typename Type> | |
| STRONG_CONSTEXPR | |
| decltype(auto) | |
| format(const Type& t, FormatContext& fc) | |
| noexcept(noexcept(std::declval<fmt::formatter<T, Char>>().format(std::declval<const T&>(), fc))) | |
| { | |
| return fmt::formatter<T, Char>::format(value_of(t), fc); | |
| } | |
| }; | |
| #if FMT_VERSION >= 90000 | |
| template <typename T, typename Char, bool = is_formattable<T>::value> | |
| struct select_formatter; | |
| template <typename T, typename Char> | |
| struct select_formatter<T, Char, true> | |
| { | |
| using type = formatter<T, Char>; | |
| }; | |
| template <typename T, typename Char> | |
| struct select_formatter<T, Char, false> | |
| { | |
| using type = fmt::ostream_formatter; | |
| }; | |
| #endif | |
| } | |
| namespace fmt | |
| { | |
| #if FMT_VERSION >= 90000 | |
| template <typename T, typename Tag, typename ... M, typename Char> | |
| struct formatter<::strong::type<T, Tag, M...>, | |
| Char, | |
| ::strong::impl::void_t<std::enable_if_t<::strong::is_ostreamable<::strong::type<T, Tag, M...>>::value || | |
| ::strong::is_formattable<::strong::type<T, Tag, M...>>::value>>> | |
| : ::strong::select_formatter<::strong::type<T, Tag, M...>, Char>::type | |
| { | |
| }; | |
| #else | |
| template<typename T, typename Tag, typename... M, typename Char> | |
| struct formatter<::strong::type<T, Tag, M...>, | |
| Char, | |
| ::strong::impl::void_t<std::enable_if_t<::strong::is_formattable<::strong::type<T, Tag, M...>>::value>> | |
| > | |
| : ::strong::formatter<::strong::type<T, Tag, M...>, Char> | |
| { | |
| }; | |
| #endif | |
| } | |
| #endif | |
| #endif //STRONG_TYPE_FORMATTABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef STRONG_TYPE_SCALABLE_HPP | |
| #define STRONG_TYPE_SCALABLE_HPP | |
| namespace strong | |
| { | |
| namespace impl | |
| { | |
| template <typename ...> | |
| struct first_type; | |
| template <typename T> | |
| struct first_type<T> | |
| { | |
| using type = T; | |
| }; | |
| template <typename T, typename ...Ts> | |
| struct first_type<T, Ts...> { | |
| using type = T; | |
| }; | |
| template <typename ... Ts> | |
| using first_type_t = typename first_type<Ts...>::type; | |
| template <typename T, typename Other, typename = void> | |
| class typed_scalable | |
| { | |
| static_assert(impl::always_false<T, Other>, | |
| "Underlying type must be multiplyable and divisible by other type"); | |
| }; | |
| template <typename T, typename Other> | |
| class typed_scalable< | |
| T, | |
| Other, | |
| impl::void_t<decltype((std::declval<underlying_type_t<T>&>()/=std::declval<underlying_type_t<Other>>())*=std::declval<underlying_type_t<Other>>())> | |
| > | |
| { | |
| using TT = underlying_type_t<T>; | |
| using OT = underlying_type_t<Other>; | |
| public: | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator/=(T& lh, const Other& rh) | |
| noexcept(noexcept(std::declval<TT&>() / std::declval<const OT&>()) | |
| && std::is_nothrow_move_assignable<TT>::value) | |
| -> T& | |
| { | |
| value_of(lh) = static_cast<TT>(value_of(lh) / impl::access(rh)); | |
| return lh; | |
| } | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator*=(T& lh, const Other& rh) | |
| noexcept(noexcept(std::declval<TT&>() * std::declval<const OT&>()) | |
| && std::is_nothrow_move_assignable<TT>::value) | |
| -> T& | |
| { | |
| value_of(lh) = static_cast<TT>(value_of(lh) * impl::access(rh)); | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator/(T lh, const Other& rh) | |
| noexcept(noexcept(lh /= rh)) | |
| -> T | |
| { | |
| lh /= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator*(T lh, const Other& rh) | |
| noexcept(noexcept(lh *= rh)) | |
| -> T | |
| { | |
| lh *= rh; | |
| return lh; | |
| } | |
| STRONG_NODISCARD | |
| friend | |
| STRONG_CONSTEXPR | |
| auto operator*(const Other& lh, T rh) | |
| noexcept(noexcept(rh *= lh)) | |
| -> T | |
| { | |
| rh *= lh; | |
| return rh; | |
| } | |
| }; | |
| } | |
| template <typename ... Ts> | |
| struct scalable_with | |
| { | |
| template <typename T> | |
| class modifier : public impl::typed_scalable<T, Ts>... | |
| { | |
| public: | |
| using scalable_modifier_result_type = impl::first_type_t<Ts...>; | |
| }; | |
| }; | |
| } | |
| template < | |
| typename TT, | |
| typename UT = strong::underlying_type_t<TT>, | |
| typename R = typename TT::scalable_modifier_result_type, | |
| typename = std::enable_if_t<std::is_constructible<R, decltype(std::declval<const UT&>() / std::declval<const UT&>())>::value> | |
| > | |
| STRONG_NODISCARD | |
| inline | |
| STRONG_CONSTEXPR | |
| auto operator/(const TT& lh, const TT& rh) | |
| noexcept(noexcept(std::declval<const UT&>() / std::declval<const UT&>())) | |
| -> R | |
| { | |
| return R{value_of(lh) / value_of(rh)}; | |
| } | |
| #endif //STRONG_TYPE_SCALABLE_HPP | |
| /* | |
| * strong_type C++14/17/20 strong typedef library | |
| * | |
| * Copyright (C) Björn Fahller | |
| * | |
| * Use, modification and distribution is subject to the | |
| * Boost Software License, Version 1.0. (See accompanying | |
| * file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| * | |
| * Project home: https://github.com/rollbear/strong_type | |
| */ | |
| #ifndef ROLLBEAR_STRONG_TYPE_HPP_INCLUDED | |
| #define ROLLBEAR_STRONG_TYPE_HPP_INCLUDED | |
| #endif //ROLLBEAR_STRONG_TYPE_HPP_INCLUDED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment