diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2023-06-07 16:41:32 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2023-06-07 16:41:32 +0200 |
| commit | aa7c021962f529f3ed2f482fd6f02e5497532a8a (patch) | |
| tree | c8a3eff796c94f757cc8ae7d3b2324f53038e0c3 /source | |
| parent | 741b6d177865f20908b1b290c5170025964d3d9a (diff) | |
| download | newtype-aa7c021962f529f3ed2f482fd6f02e5497532a8a.tar.xz newtype-aa7c021962f529f3ed2f482fd6f02e5497532a8a.zip | |
project: begin restructuring
Diffstat (limited to 'source')
21 files changed, 4283 insertions, 0 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt new file mode 100644 index 0000000..0bd0876 --- /dev/null +++ b/source/CMakeLists.txt @@ -0,0 +1,88 @@ +cmake_minimum_required(VERSION "3.25.0") + +project("newtype" + LANGUAGES CXX + DESCRIPTION "A library of types and functions to create strong type aliases" +) + +enable_testing() + +# Project dependencies + +find_package("Catch2" "3.1" + COMPONENTS "Catch2WithMain" + REQUIRED +) + +include("Catch") + +# Project Options + +option(BUILD_EXAMPLES "Build the library examples" OFF) + +# 'newtype' library + +add_library("${PROJECT_NAME}" INTERFACE) + +target_include_directories("${PROJECT_NAME}" INTERFACE + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include> +) + +target_compile_features("${PROJECT_NAME}" INTERFACE + "cxx_std_20" +) + +install(TARGETS "${PROJECT_NAME}" + EXPORT "${PROJECT_NAME}Targets" + PUBLIC_HEADER DESTINATION "include" +) + +install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/" + DESTINATION "include" +) + +add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS "${PROJECT_NAME}") + +# 'newtype' tests + +add_executable("${PROJECT_NAME}_tests" + "test/src/arithmetic.cpp" + # "test/src/conversion_suite.cpp" + # "test/src/derivation_clause_suite.cpp" + # "test/src/equality_comparison_suite.cpp" + # "test/src/hash_suite.cpp" + # "test/src/io_operators_suite.cpp" + # "test/src/iterable_suite.cpp" + # "test/src/new_type_constructor_suite.cpp" + # "test/src/relational_operators_suite.cpp" +) + +target_link_libraries("${PROJECT_NAME}_tests" + "${PROJECT_NAME}::${PROJECT_NAME}" + "Catch2::Catch2WithMain" +) + +target_compile_options("${PROJECT_NAME}_tests" PRIVATE + "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall>" + "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wextra>" + "$<$<CXX_COMPILER_ID:GNU,Clang>:-Werror>" + "$<$<CXX_COMPILER_ID:GNU,Clang>:-pedantic-errors>" +) + +catch_discover_tests("${PROJECT_NAME}_tests") + +# 'newtype' examples + +if(BUILD_EXAMPLES) + function(add_example NAME) + add_executable("ex_${NAME}" + "examples/src/${NAME}.cpp" + ) + target_link_libraries("ex_${NAME}" "${PROJECT_NAME}") + endfunction() + + add_example("basic_usage") + add_example("basic_usage_with_show") + add_example("basic_usage_with_read") +endif() diff --git a/source/examples/src/basic_usage.cpp b/source/examples/src/basic_usage.cpp new file mode 100644 index 0000000..35d1d2c --- /dev/null +++ b/source/examples/src/basic_usage.cpp @@ -0,0 +1,39 @@ +#include <newtype/newtype.hpp> + +#include <iostream> + +using Width = nt::new_type<unsigned int, struct width_tag>; +using Height = nt::new_type<unsigned int, struct height_tag>; +using Area = nt::new_type<unsigned int, struct area_tag>; + +struct Rectangle +{ + constexpr Rectangle(Width w, Height h) + : width{w} + , height{h} + { + } + + auto constexpr area() const noexcept -> Area + { + return {width.decay() * height.decay()}; + } + +private: + Width width; + Height height; +}; + +int main() +{ + auto w{0u}, h{0u}; + + std::cin >> w >> h; + + auto width = Width{w}; + auto height = Height{h}; + + auto rect = Rectangle{width, height}; + + std::cout << rect.area().decay() << '\n'; +}
\ No newline at end of file diff --git a/source/examples/src/basic_usage_with_read.cpp b/source/examples/src/basic_usage_with_read.cpp new file mode 100644 index 0000000..2dabe2e --- /dev/null +++ b/source/examples/src/basic_usage_with_read.cpp @@ -0,0 +1,39 @@ +#include <newtype/derivable.hpp> +#include <newtype/deriving.hpp> +#include <newtype/newtype.hpp> + +#include <iostream> + +using Width = nt::new_type<unsigned int, struct width_tag, deriving(nt::Read)>; +using Height = nt::new_type<unsigned int, struct height_tag, deriving(nt::Read)>; +using Area = nt::new_type<unsigned int, struct area_tag, deriving(nt::Show)>; + +struct Rectangle +{ + constexpr Rectangle(Width w, Height h) + : width{w} + , height{h} + { + } + + auto constexpr area() const noexcept -> Area + { + return {width.decay() * height.decay()}; + } + +private: + Width width; + Height height; +}; + +int main() +{ + auto width = Width{}; + auto height = Height{}; + + std::cin >> width >> height; + + auto rect = Rectangle{width, height}; + + std::cout << rect.area() << '\n'; +}
\ No newline at end of file diff --git a/source/examples/src/basic_usage_with_show.cpp b/source/examples/src/basic_usage_with_show.cpp new file mode 100644 index 0000000..4bb68f6 --- /dev/null +++ b/source/examples/src/basic_usage_with_show.cpp @@ -0,0 +1,41 @@ +#include <newtype/derivable.hpp> +#include <newtype/deriving.hpp> +#include <newtype/newtype.hpp> + +#include <iostream> + +using Width = nt::new_type<unsigned int, struct width_tag>; +using Height = nt::new_type<unsigned int, struct height_tag>; +using Area = nt::new_type<unsigned int, struct area_tag, deriving(nt::Show)>; + +struct Rectangle +{ + constexpr Rectangle(Width w, Height h) + : width{w} + , height{h} + { + } + + auto constexpr area() const noexcept -> Area + { + return {width.decay() * height.decay()}; + } + +private: + Width width; + Height height; +}; + +int main() +{ + auto w{0u}, h{0u}; + + std::cin >> w >> h; + + auto width = Width{w}; + auto height = Height{h}; + + auto rect = Rectangle{width, height}; + + std::cout << rect.area() << '\n'; +}
\ No newline at end of file diff --git a/source/include/newtype/derivable.hpp b/source/include/newtype/derivable.hpp new file mode 100644 index 0000000..c798c59 --- /dev/null +++ b/source/include/newtype/derivable.hpp @@ -0,0 +1,32 @@ +#ifndef NEWTYPE_DERIVABLE_HPP +#define NEWTYPE_DERIVABLE_HPP + +#include "newtype/version.hpp" + +namespace nt +{ + + template<typename DerivableTag> + struct derivable final + { + using tag_type = DerivableTag; + }; + + inline namespace derivables + { + + auto constexpr Arithmetic = derivable<struct arithmetic_tag>{}; + auto constexpr EqBase = derivable<struct eq_base_tag>{}; + auto constexpr Hash = derivable<struct hash_tag>{}; + auto constexpr ImplicitConversion = derivable<struct implicit_conversion_tag>{}; + auto constexpr Indirection = derivable<struct indirection_tag>{}; + auto constexpr Iterable = derivable<struct iterable_tag>{}; + auto constexpr Read = derivable<struct read_tag>{}; + auto constexpr Relational = derivable<struct relational_tag>{}; + auto constexpr Show = derivable<struct show_tag>{}; + + } // namespace derivables + +} // namespace nt + +#endif
\ No newline at end of file diff --git a/source/include/newtype/derivation_clause.hpp b/source/include/newtype/derivation_clause.hpp new file mode 100644 index 0000000..6de70e1 --- /dev/null +++ b/source/include/newtype/derivation_clause.hpp @@ -0,0 +1,70 @@ +#ifndef NEWTYPE_DERIVATION_CLAUSE_HPP +#define NEWTYPE_DERIVATION_CLAUSE_HPP + +#include "newtype/derivable.hpp" +#include "newtype/version.hpp" + +#include <type_traits> + +namespace nt +{ + + template<typename... DerivableTags> + struct derivation_clause + { + constexpr derivation_clause(derivable<DerivableTags>...) noexcept + { + } + + template<typename DerivableTag> + auto constexpr operator()(derivable<DerivableTag>) const noexcept -> bool + { + return (std::is_same_v<DerivableTags, DerivableTag> || ...); + } + + template<typename DerivableTag, typename... RemainingDerivableTags> + auto constexpr operator()(derivable<DerivableTag>, derivable<RemainingDerivableTags>...) const noexcept -> bool + { + return (*this)(derivable<DerivableTag>{}) && (*this)(derivable<RemainingDerivableTags>{}...); + } + + template<typename... OtherDerivableTags> + auto constexpr operator<(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool + { + return (sizeof...(DerivableTags) < sizeof...(OtherDerivableTags)) && other(derivable<DerivableTags>{}...); + } + + template<typename... OtherDerivableTags> + auto constexpr operator>(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool + { + return other < *this; + } + + template<typename... OtherDerivableTags> + auto constexpr operator==(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool + { + return sizeof...(DerivableTags) == sizeof...(OtherDerivableTags) && other(derivable<DerivableTags>{}...); + } + + template<typename... OtherDerivableTags> + auto constexpr operator!=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool + { + return !(*this == other); + } + + template<typename... OtherDerivableTags> + auto constexpr operator<=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool + { + return *this < other || *this == other; + } + + template<typename... OtherDerivableTags> + auto constexpr operator>=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool + { + return *this > other || *this == other; + } + }; + +} // namespace nt + +#endif
\ No newline at end of file diff --git a/source/include/newtype/deriving.hpp b/source/include/newtype/deriving.hpp new file mode 100644 index 0000000..ae10bab --- /dev/null +++ b/source/include/newtype/deriving.hpp @@ -0,0 +1,21 @@ +#ifndef NEWTYPE_DERIVING_HPP +#define NEWTYPE_DERIVING_HPP + +#include "newtype/derivable.hpp" +#include "newtype/derivation_clause.hpp" +#include "newtype/version.hpp" + +#include <type_traits> + +namespace nt +{ + + template<typename... DerivableTags> + auto constexpr deriving(derivable<DerivableTags>... features) noexcept -> derivation_clause<DerivableTags...> + { + return {features...}; + } + +} // namespace nt + +#endif
\ No newline at end of file diff --git a/source/include/newtype/impl/new_type_iterator_types.hpp b/source/include/newtype/impl/new_type_iterator_types.hpp new file mode 100644 index 0000000..2ea8274 --- /dev/null +++ b/source/include/newtype/impl/new_type_iterator_types.hpp @@ -0,0 +1,66 @@ +#ifndef NEWTYPE_IMPL_NEW_TYPE_ITERATOR_TYPES_HPP +#define NEWTYPE_IMPL_NEW_TYPE_ITERATOR_TYPES_HPP + +#include "newtype/version.hpp" + +#include <type_traits> + +namespace nt::impl +{ + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_iterator + { + }; + + template<typename T> + struct new_type_iterator<T, true, std::void_t<typename T::iterator>> + { + using iterator = typename T::iterator; + }; + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_const_iterator + { + }; + + template<typename T> + struct new_type_const_iterator<T, true, std::void_t<typename T::const_iterator>> + { + using const_iterator = typename T::const_iterator; + }; + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_reverse_iterator + { + }; + + template<typename T> + struct new_type_reverse_iterator<T, true, std::void_t<typename T::reverse_iterator>> + { + using reverse_iterator = typename T::reverse_iterator; + }; + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_const_reverse_iterator + { + }; + + template<typename T> + struct new_type_const_reverse_iterator<T, true, std::void_t<typename T::const_reverse_iterator>> + { + using const_reverse_iterator = typename T::const_reverse_iterator; + }; + + template<typename T, bool Enabled> + struct new_type_iterator_types + : new_type_iterator<T, Enabled> + , new_type_const_iterator<T, Enabled> + , new_type_reverse_iterator<T, Enabled> + , new_type_const_reverse_iterator<T, Enabled> + { + }; + +} // namespace nt::impl + +#endif
\ No newline at end of file diff --git a/source/include/newtype/impl/new_type_storage.hpp b/source/include/newtype/impl/new_type_storage.hpp new file mode 100644 index 0000000..f7842af --- /dev/null +++ b/source/include/newtype/impl/new_type_storage.hpp @@ -0,0 +1,139 @@ +#ifndef NEWTYPE_IMPL_NEW_TYPE_STORAGE_HPP +#define NEWTYPE_IMPL_NEW_TYPE_STORAGE_HPP + +#include "newtype/version.hpp" + +#include <type_traits> +#include <utility> + +namespace nt::impl +{ + + template<typename BaseType, typename TagType> + struct new_type_storage + { + constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v<BaseType>) + : m_value{} + { + } + + constexpr new_type_storage(BaseType const & value) + : m_value{value} + { + } + + constexpr new_type_storage(BaseType && value) + : m_value{std::move(value)} + { + } + + BaseType m_value; + }; + + template<typename BaseType, typename TagType, bool = std::is_default_constructible_v<BaseType>> + struct new_type_constructor : new_type_storage<BaseType, TagType> + { + using new_type_storage<BaseType, TagType>::new_type_storage; + }; + + template<typename BaseType, typename TagType> + struct new_type_constructor<BaseType, TagType, false> : new_type_storage<BaseType, TagType> + { + using new_type_storage<BaseType, TagType>::new_type_storage; + + constexpr new_type_constructor() = delete; + }; + + template<typename BaseType, typename TagType, bool = std::is_copy_constructible_v<BaseType>> + struct new_type_copy_constructor : new_type_constructor<BaseType, TagType> + { + using new_type_constructor<BaseType, TagType>::new_type_constructor; + + constexpr new_type_copy_constructor(new_type_copy_constructor const &) = default; + constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; + auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; + auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_copy_constructor<BaseType, TagType, false> : new_type_constructor<BaseType, TagType> + { + using new_type_constructor<BaseType, TagType>::new_type_constructor; + + constexpr new_type_copy_constructor(new_type_copy_constructor const &) = delete; + constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; + constexpr new_type_copy_constructor(BaseType const &) = delete; + auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; + auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; + }; + + template<typename BaseType, typename TagType, bool = std::is_move_constructible_v<BaseType>> + struct new_type_move_constructor : new_type_copy_constructor<BaseType, TagType> + { + using new_type_copy_constructor<BaseType, TagType>::new_type_copy_constructor; + + constexpr new_type_move_constructor(new_type_move_constructor const &) = default; + constexpr new_type_move_constructor(new_type_move_constructor &&) = default; + auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; + auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_move_constructor<BaseType, TagType, false> : new_type_copy_constructor<BaseType, TagType> + { + using new_type_copy_constructor<BaseType, TagType>::new_type_copy_constructor; + + constexpr new_type_move_constructor(new_type_move_constructor const &) = default; + constexpr new_type_move_constructor(new_type_move_constructor &&) = delete; + constexpr new_type_move_constructor(BaseType &&) = delete; + auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; + auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; + }; + + template<typename BaseType, typename TagType, bool = std::is_copy_assignable_v<BaseType>> + struct new_type_copy_assignment : new_type_move_constructor<BaseType, TagType> + { + using new_type_move_constructor<BaseType, TagType>::new_type_move_constructor; + + constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; + constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; + auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; + auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_copy_assignment<BaseType, TagType, false> : new_type_move_constructor<BaseType, TagType> + { + using new_type_move_constructor<BaseType, TagType>::new_type_move_constructor; + + constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; + constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; + auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; + auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = delete; + }; + + template<typename BaseType, typename TagType, bool = std::is_move_assignable_v<BaseType>> + struct new_type_move_assignment : new_type_copy_assignment<BaseType, TagType> + { + using new_type_copy_assignment<BaseType, TagType>::new_type_copy_assignment; + + constexpr new_type_move_assignment(new_type_move_assignment const &) = default; + constexpr new_type_move_assignment(new_type_move_assignment &&) = default; + auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; + auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_move_assignment<BaseType, TagType, false> : new_type_copy_assignment<BaseType, TagType> + { + using new_type_copy_assignment<BaseType, TagType>::new_type_copy_assignment; + + constexpr new_type_move_assignment(new_type_move_assignment const &) = default; + constexpr new_type_move_assignment(new_type_move_assignment &&) = default; + auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; + auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = delete; + }; + +} // namespace nt::impl + +#endif diff --git a/source/include/newtype/impl/type_traits_extensions.hpp b/source/include/newtype/impl/type_traits_extensions.hpp new file mode 100644 index 0000000..dc41649 --- /dev/null +++ b/source/include/newtype/impl/type_traits_extensions.hpp @@ -0,0 +1,853 @@ +#ifndef NEWTYPE_IMPL_TYPE_TRAITS_EXTENSIONS_HPP +#define NEWTYPE_IMPL_TYPE_TRAITS_EXTENSIONS_HPP + +#include "newtype/version.hpp" + +#include <cstddef> +#include <functional> +#include <iosfwd> +#include <type_traits> + +namespace nt::impl +{ + + inline namespace equality_comparable + { + + template<typename T, typename = void> + struct is_equality_comparable : std::false_type + { + }; + + template<typename T> + struct is_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr is_equality_comparable_v = is_equality_comparable<T>::value; + + template<typename T, typename = void> + struct is_nothrow_equality_comparable : std::false_type + { + }; + + template<typename T> + struct is_nothrow_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() == std::declval<T const &>())> + { + }; + + template<typename T> + auto constexpr is_nothrow_equality_comparable_v = is_nothrow_equality_comparable<T>::value; + + template<typename T, typename = void> + struct is_inequality_comparable : std::false_type + { + }; + + template<typename T> + struct is_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr is_inequality_comparable_v = is_inequality_comparable<T>::value; + + template<typename T, typename = void> + struct is_nothrow_inequality_comparable : std::false_type + { + }; + + template<typename T> + struct is_nothrow_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() != std::declval<T const &>())> + { + }; + + template<typename T> + auto constexpr is_nothrow_inequality_comparable_v = is_nothrow_inequality_comparable<T>::value; + + } // namespace equality_comparable + + inline namespace relationally_comparable + { + + template<typename T, typename = void> + struct is_less_than_comparable : std::false_type + { + }; + + template<typename T> + struct is_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr is_less_than_comparable_v = is_less_than_comparable<T>::value; + + template<typename T, typename = void> + struct is_nothrow_less_than_comparable : std::false_type + { + }; + + template<typename T> + struct is_nothrow_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() < std::declval<T const &>())> + { + }; + + template<typename T> + auto constexpr is_nothrow_less_than_comparable_v = is_nothrow_less_than_comparable<T>::value; + + template<typename T, typename = void> + struct is_greater_than_comparable : std::false_type + { + }; + + template<typename T> + struct is_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr is_greater_than_comparable_v = is_greater_than_comparable<T>::value; + + template<typename T, typename = void> + struct is_nothrow_greater_than_comparable : std::false_type + { + }; + + template<typename T> + struct is_nothrow_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() > std::declval<T const &>())> + { + }; + + template<typename T> + auto constexpr is_nothrow_greater_than_comparable_v = is_nothrow_greater_than_comparable<T>::value; + + template<typename T, typename = void> + struct is_less_than_equal_to_comparable : std::false_type + { + }; + + template<typename T> + struct is_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr is_less_than_equal_to_comparable_v = is_less_than_equal_to_comparable<T>::value; + + template<typename T, typename = void> + struct is_nothrow_less_than_equal_to_comparable : std::false_type + { + }; + + template<typename T> + struct is_nothrow_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() <= std::declval<T const &>())> + { + }; + + template<typename T> + auto constexpr is_nothrow_less_than_equal_to_comparable_v = is_nothrow_less_than_equal_to_comparable<T>::value; + + template<typename T, typename = void> + struct is_greater_than_equal_to_comparable : std::false_type + { + }; + + template<typename T> + struct is_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>> + : std::true_type + { + }; + + template<typename T> + auto constexpr is_greater_than_equal_to_comparable_v = is_greater_than_equal_to_comparable<T>::value; + + template<typename T, typename = void> + struct is_nothrow_greater_than_equal_to_comparable : std::false_type + { + }; + + template<typename T> + struct is_nothrow_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<T const &>() >= std::declval<T const &>())> + { + }; + + template<typename T> + auto constexpr is_nothrow_greater_than_equal_to_comparable_v = is_nothrow_greater_than_equal_to_comparable<T>::value; + } // namespace relationally_comparable + + inline namespace iostreamable + { + + template<typename StreamType, typename T, typename = void> + struct is_output_streamable : std::false_type + { + }; + + template<typename StreamType, typename T> + struct is_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>> + : std::true_type + { + }; + + template<typename StreamType, typename T> + auto constexpr is_output_streamable_v = is_output_streamable<StreamType, T>::value; + + template<typename StreamType, typename T, typename = void> + struct is_nothrow_output_streamable : std::false_type + { + }; + + template<typename StreamType, typename T> + struct is_nothrow_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>> + : std::bool_constant<noexcept(std::declval<StreamType &>() << std::declval<T const &>())> + { + }; + + template<typename StreamType, typename T> + auto constexpr is_nothrow_output_streamable_v = is_nothrow_output_streamable<StreamType, T>::value; + + template<typename StreamType, typename T, typename = void> + struct is_input_streamable : std::false_type + { + }; + + template<typename StreamType, typename T> + struct is_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>> : std::true_type + { + }; + + template<typename StreamType, typename T> + auto constexpr is_input_streamable_v = is_input_streamable<StreamType, T>::value; + + template<typename StreamType, typename T, typename = void> + struct is_nothrow_input_streamable : std::false_type + { + }; + + template<typename StreamType, typename T> + struct is_nothrow_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>> + : std::bool_constant<noexcept(std::declval<StreamType &>() >> std::declval<T &>())> + { + }; + + template<typename StreamType, typename T> + auto constexpr is_nothrow_input_streamable_v = is_nothrow_input_streamable<StreamType, T>::value; + + } // namespace iostreamable + + inline namespace arithmetic + { + + template<typename T, typename = void> + struct is_addable : std::false_type + { + }; + + template<typename T> + struct is_addable<T, std::void_t<decltype(std::declval<T const &>() + std::declval<T const &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr is_addable_v = is_addable<T>::value; + + template<typename T, typename = void> + struct is_nothrow_addable : std::false_type + { + }; + + template<typename T> < |
