From aa7c021962f529f3ed2f482fd6f02e5497532a8a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 7 Jun 2023 16:41:32 +0200 Subject: project: begin restructuring --- source/CMakeLists.txt | 88 +++ source/examples/src/basic_usage.cpp | 39 + source/examples/src/basic_usage_with_read.cpp | 39 + source/examples/src/basic_usage_with_show.cpp | 41 + source/include/newtype/derivable.hpp | 32 + source/include/newtype/derivation_clause.hpp | 70 ++ source/include/newtype/deriving.hpp | 21 + .../newtype/impl/new_type_iterator_types.hpp | 66 ++ source/include/newtype/impl/new_type_storage.hpp | 139 ++++ .../newtype/impl/type_traits_extensions.hpp | 853 +++++++++++++++++++++ source/include/newtype/newtype.hpp | 550 +++++++++++++ source/include/newtype/version.hpp | 23 + source/test/src/arithmetic.cpp | 300 ++++++++ source/test/src/conversion_suite.cpp | 201 +++++ source/test/src/derivation_clause_suite.cpp | 312 ++++++++ source/test/src/equality_comparison_suite.cpp | 188 +++++ source/test/src/hash_suite.cpp | 69 ++ source/test/src/io_operators_suite.cpp | 121 +++ source/test/src/iterable_suite.cpp | 719 +++++++++++++++++ source/test/src/new_type_constructor_suite.cpp | 91 +++ source/test/src/relational_operators_suite.cpp | 321 ++++++++ 21 files changed, 4283 insertions(+) create mode 100644 source/CMakeLists.txt create mode 100644 source/examples/src/basic_usage.cpp create mode 100644 source/examples/src/basic_usage_with_read.cpp create mode 100644 source/examples/src/basic_usage_with_show.cpp create mode 100644 source/include/newtype/derivable.hpp create mode 100644 source/include/newtype/derivation_clause.hpp create mode 100644 source/include/newtype/deriving.hpp create mode 100644 source/include/newtype/impl/new_type_iterator_types.hpp create mode 100644 source/include/newtype/impl/new_type_storage.hpp create mode 100644 source/include/newtype/impl/type_traits_extensions.hpp create mode 100644 source/include/newtype/newtype.hpp create mode 100644 source/include/newtype/version.hpp create mode 100644 source/test/src/arithmetic.cpp create mode 100644 source/test/src/conversion_suite.cpp create mode 100644 source/test/src/derivation_clause_suite.cpp create mode 100644 source/test/src/equality_comparison_suite.cpp create mode 100644 source/test/src/hash_suite.cpp create mode 100644 source/test/src/io_operators_suite.cpp create mode 100644 source/test/src/iterable_suite.cpp create mode 100644 source/test/src/new_type_constructor_suite.cpp create mode 100644 source/test/src/relational_operators_suite.cpp (limited to 'source') 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 + $ + $ +) + +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 + "$<$:-Wall>" + "$<$:-Wextra>" + "$<$:-Werror>" + "$<$:-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 + +#include + +using Width = nt::new_type; +using Height = nt::new_type; +using Area = nt::new_type; + +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 +#include +#include + +#include + +using Width = nt::new_type; +using Height = nt::new_type; +using Area = nt::new_type; + +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 +#include +#include + +#include + +using Width = nt::new_type; +using Height = nt::new_type; +using Area = nt::new_type; + +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 + struct derivable final + { + using tag_type = DerivableTag; + }; + + inline namespace derivables + { + + auto constexpr Arithmetic = derivable{}; + auto constexpr EqBase = derivable{}; + auto constexpr Hash = derivable{}; + auto constexpr ImplicitConversion = derivable{}; + auto constexpr Indirection = derivable{}; + auto constexpr Iterable = derivable{}; + auto constexpr Read = derivable{}; + auto constexpr Relational = derivable{}; + auto constexpr Show = derivable{}; + + } // 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 + +namespace nt +{ + + template + struct derivation_clause + { + constexpr derivation_clause(derivable...) noexcept + { + } + + template + auto constexpr operator()(derivable) const noexcept -> bool + { + return (std::is_same_v || ...); + } + + template + auto constexpr operator()(derivable, derivable...) const noexcept -> bool + { + return (*this)(derivable{}) && (*this)(derivable{}...); + } + + template + auto constexpr operator<(derivation_clause other) const noexcept -> bool + { + return (sizeof...(DerivableTags) < sizeof...(OtherDerivableTags)) && other(derivable{}...); + } + + template + auto constexpr operator>(derivation_clause other) const noexcept -> bool + { + return other < *this; + } + + template + auto constexpr operator==(derivation_clause other) const noexcept -> bool + { + return sizeof...(DerivableTags) == sizeof...(OtherDerivableTags) && other(derivable{}...); + } + + template + auto constexpr operator!=(derivation_clause other) const noexcept -> bool + { + return !(*this == other); + } + + template + auto constexpr operator<=(derivation_clause other) const noexcept -> bool + { + return *this < other || *this == other; + } + + template + auto constexpr operator>=(derivation_clause 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 + +namespace nt +{ + + template + auto constexpr deriving(derivable... features) noexcept -> derivation_clause + { + 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 + +namespace nt::impl +{ + + template> + struct new_type_iterator + { + }; + + template + struct new_type_iterator> + { + using iterator = typename T::iterator; + }; + + template> + struct new_type_const_iterator + { + }; + + template + struct new_type_const_iterator> + { + using const_iterator = typename T::const_iterator; + }; + + template> + struct new_type_reverse_iterator + { + }; + + template + struct new_type_reverse_iterator> + { + using reverse_iterator = typename T::reverse_iterator; + }; + + template> + struct new_type_const_reverse_iterator + { + }; + + template + struct new_type_const_reverse_iterator> + { + using const_reverse_iterator = typename T::const_reverse_iterator; + }; + + template + struct new_type_iterator_types + : new_type_iterator + , new_type_const_iterator + , new_type_reverse_iterator + , new_type_const_reverse_iterator + { + }; + +} // 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 +#include + +namespace nt::impl +{ + + template + struct new_type_storage + { + constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v) + : 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> + struct new_type_constructor : new_type_storage + { + using new_type_storage::new_type_storage; + }; + + template + struct new_type_constructor : new_type_storage + { + using new_type_storage::new_type_storage; + + constexpr new_type_constructor() = delete; + }; + + template> + struct new_type_copy_constructor : new_type_constructor + { + using new_type_constructor::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 + struct new_type_copy_constructor : new_type_constructor + { + using new_type_constructor::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> + struct new_type_move_constructor : new_type_copy_constructor + { + using new_type_copy_constructor::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 + struct new_type_move_constructor : new_type_copy_constructor + { + using new_type_copy_constructor::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> + struct new_type_copy_assignment : new_type_move_constructor + { + using new_type_move_constructor::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 + struct new_type_copy_assignment : new_type_move_constructor + { + using new_type_move_constructor::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> + struct new_type_move_assignment : new_type_copy_assignment + { + using new_type_copy_assignment::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 + struct new_type_move_assignment : new_type_copy_assignment + { + using new_type_copy_assignment::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 +#include +#include +#include + +namespace nt::impl +{ + + inline namespace equality_comparable + { + + template + struct is_equality_comparable : std::false_type + { + }; + + template + struct is_equality_comparable() == std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_equality_comparable_v = is_equality_comparable::value; + + template + struct is_nothrow_equality_comparable : std::false_type + { + }; + + template + struct is_nothrow_equality_comparable() == std::declval())>> + : std::bool_constant() == std::declval())> + { + }; + + template + auto constexpr is_nothrow_equality_comparable_v = is_nothrow_equality_comparable::value; + + template + struct is_inequality_comparable : std::false_type + { + }; + + template + struct is_inequality_comparable() != std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_inequality_comparable_v = is_inequality_comparable::value; + + template + struct is_nothrow_inequality_comparable : std::false_type + { + }; + + template + struct is_nothrow_inequality_comparable() != std::declval())>> + : std::bool_constant() != std::declval())> + { + }; + + template + auto constexpr is_nothrow_inequality_comparable_v = is_nothrow_inequality_comparable::value; + + } // namespace equality_comparable + + inline namespace relationally_comparable + { + + template + struct is_less_than_comparable : std::false_type + { + }; + + template + struct is_less_than_comparable() < std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_less_than_comparable_v = is_less_than_comparable::value; + + template + struct is_nothrow_less_than_comparable : std::false_type + { + }; + + template + struct is_nothrow_less_than_comparable() < std::declval())>> + : std::bool_constant() < std::declval())> + { + }; + + template + auto constexpr is_nothrow_less_than_comparable_v = is_nothrow_less_than_comparable::value; + + template + struct is_greater_than_comparable : std::false_type + { + }; + + template + struct is_greater_than_comparable() > std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_greater_than_comparable_v = is_greater_than_comparable::value; + + template + struct is_nothrow_greater_than_comparable : std::false_type + { + }; + + template + struct is_nothrow_greater_than_comparable() > std::declval())>> + : std::bool_constant() > std::declval())> + { + }; + + template + auto constexpr is_nothrow_greater_than_comparable_v = is_nothrow_greater_than_comparable::value; + + template + struct is_less_than_equal_to_comparable : std::false_type + { + }; + + template + struct is_less_than_equal_to_comparable() <= std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_less_than_equal_to_comparable_v = is_less_than_equal_to_comparable::value; + + template + struct is_nothrow_less_than_equal_to_comparable : std::false_type + { + }; + + template + struct is_nothrow_less_than_equal_to_comparable() <= std::declval())>> + : std::bool_constant() <= std::declval())> + { + }; + + template + auto constexpr is_nothrow_less_than_equal_to_comparable_v = is_nothrow_less_than_equal_to_comparable::value; + + template + struct is_greater_than_equal_to_comparable : std::false_type + { + }; + + template + struct is_greater_than_equal_to_comparable() >= std::declval())>> + : std::true_type + { + }; + + template + auto constexpr is_greater_than_equal_to_comparable_v = is_greater_than_equal_to_comparable::value; + + template + struct is_nothrow_greater_than_equal_to_comparable : std::false_type + { + }; + + template + struct is_nothrow_greater_than_equal_to_comparable() >= std::declval())>> + : std::bool_constant() >= std::declval())> + { + }; + + template + auto constexpr is_nothrow_greater_than_equal_to_comparable_v = is_nothrow_greater_than_equal_to_comparable::value; + } // namespace relationally_comparable + + inline namespace iostreamable + { + + template + struct is_output_streamable : std::false_type + { + }; + + template + struct is_output_streamable() << std::declval())>> + : std::true_type + { + }; + + template + auto constexpr is_output_streamable_v = is_output_streamable::value; + + template + struct is_nothrow_output_streamable : std::false_type + { + }; + + template + struct is_nothrow_output_streamable() << std::declval())>> + : std::bool_constant() << std::declval())> + { + }; + + template + auto constexpr is_nothrow_output_streamable_v = is_nothrow_output_streamable::value; + + template + struct is_input_streamable : std::false_type + { + }; + + template + struct is_input_streamable() >> std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_input_streamable_v = is_input_streamable::value; + + template + struct is_nothrow_input_streamable : std::false_type + { + }; + + template + struct is_nothrow_input_streamable() >> std::declval())>> + : std::bool_constant() >> std::declval())> + { + }; + + template + auto constexpr is_nothrow_input_streamable_v = is_nothrow_input_streamable::value; + + } // namespace iostreamable + + inline namespace arithmetic + { + + template + struct is_addable : std::false_type + { + }; + + template + struct is_addable() + std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_addable_v = is_addable::value; + + template + struct is_nothrow_addable : std::false_type + { + }; + + template + struct is_nothrow_addable() + std::declval())>> + : std::bool_constant() + std::declval())> + { + }; + + template + auto constexpr is_nothrow_addable_v = is_nothrow_addable::value; + + template + struct is_subtractable : std::false_type + { + }; + + template + struct is_subtractable() - std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_subtractable_v = is_subtractable::value; + + template + struct is_nothrow_subtractable : std::false_type + { + }; + + template + struct is_nothrow_subtractable() - std::declval())>> + : std::bool_constant() - std::declval())> + { + }; + + template + auto constexpr is_nothrow_subtractable_v = is_nothrow_subtractable::value; + + template + struct is_multipliable : std::false_type + { + }; + + template + struct is_multipliable() * std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_multipliable_v = is_multipliable::value; + + template + struct is_nothrow_multipliable : std::false_type + { + }; + + template + struct is_nothrow_multipliable() * std::declval())>> + : std::bool_constant() * std::declval())> + { + }; + + template + auto constexpr is_nothrow_multipliable_v = is_nothrow_multipliable::value; + + template + struct is_dividable : std::false_type + { + }; + + template + struct is_dividable() / std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_dividable_v = is_dividable::value; + + template + struct is_nothrow_dividable : std::false_type + { + }; + + template + struct is_nothrow_dividable() / std::declval())>> + : std::bool_constant() / std::declval())> + { + }; + + template + auto constexpr is_nothrow_dividable_v = is_nothrow_dividable::value; + + } // namespace arithmetic + + inline namespace compound_arithmetic + { + + template + struct is_add_assignable : std::false_type + { + }; + + template + struct is_add_assignable() += std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_add_assignable_v = is_add_assignable::value; + + template + struct is_nothrow_add_assignable : std::false_type + { + }; + + template + struct is_nothrow_add_assignable() += std::declval())>> + : std::bool_constant() += std::declval())> + { + }; + + template + auto constexpr is_nothrow_add_assignable_v = is_nothrow_add_assignable::value; + + template + struct is_subtract_assignable : std::false_type + { + }; + + template + struct is_subtract_assignable() -= std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_subtract_assignable_v = is_subtract_assignable::value; + + template + struct is_nothrow_subtract_assignable : std::false_type + { + }; + + template + struct is_nothrow_subtract_assignable() -= std::declval())>> + : std::bool_constant() -= std::declval())> + { + }; + + template + auto constexpr is_nothrow_subtract_assignable_v = is_nothrow_subtract_assignable::value; + + template + struct is_multiply_assignable : std::false_type + { + }; + + template + struct is_multiply_assignable() *= std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_multiply_assignable_v = is_multiply_assignable::value; + + template + struct is_nothrow_multiply_assignable : std::false_type + { + }; + + template + struct is_nothrow_multiply_assignable() *= std::declval())>> + : std::bool_constant() *= std::declval())> + { + }; + + template + auto constexpr is_nothrow_multiply_assignable_v = is_nothrow_multiply_assignable::value; + + template + struct is_divide_assignable : std::false_type + { + }; + + template + struct is_divide_assignable() /= std::declval())>> : std::true_type + { + }; + + template + auto constexpr is_divide_assignable_v = is_divide_assignable::value; + + template + struct is_nothrow_divide_assignable : std::false_type + { + }; + + template + struct is_nothrow_divide_assignable() /= std::declval())>> + : std::bool_constant() /= std::declval())> + { + }; + + template + auto constexpr is_nothrow_divide_assignable_v = is_nothrow_divide_assignable::value; + + } // namespace compound_arithmetic + + inline namespace std_support + { + + template + struct is_hashable : std::false_type + { + }; + + template + struct is_hashable const &>()(std::declval()))>> + : std::is_same const &>()(std::declval()))> + { + }; + + template + auto constexpr is_hashable_v = is_hashable::value; + + } // namespace std_support + + inline namespace iterable_begin + { + template + struct has_free_begin : std::false_type + { + }; + + template + struct has_free_begin()))>> + : std::is_same()))>> + { + }; + + template + struct has_free_begin()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_begin_v = has_free_begin::value; + + template + struct has_member_begin : std::false_type + { + }; + + template + struct has_member_begin().begin())>> + : std::is_same().begin())>> + { + }; + + template + struct has_member_begin().begin())>> + : std::is_same().begin())>> + { + }; + + template + auto constexpr has_member_begin_v = has_member_begin::value; + + template + struct has_begin : std::disjunction, has_member_begin> + { + }; + + template + auto constexpr has_begin_v = has_begin::value; + } // namespace iterable_begin + + inline namespace iterable_cbegin + { + template + struct has_free_cbegin : std::false_type + { + }; + + template + struct has_free_cbegin()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_cbegin_v = has_free_cbegin::value; + + template + struct has_member_cbegin : std::false_type + { + }; + + template + struct has_member_cbegin().cbegin())>> + : std::is_same().cbegin())> + { + }; + + template + auto constexpr has_member_cbegin_v = has_member_cbegin::value; + + template + struct has_cbegin : std::disjunction, has_member_cbegin> + { + }; + + template + auto constexpr has_cbegin_v = has_cbegin::value; + } // namespace iterable_cbegin + + inline namespace iterable_rbegin + { + template + struct has_free_rbegin : std::false_type + { + }; + + template + struct has_free_rbegin()))>> + : std::is_same()))>> + { + }; + + template + struct has_free_rbegin()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_rbegin_v = has_free_rbegin::value; + + template + struct has_member_rbegin : std::false_type + { + }; + + template + struct has_member_rbegin().rbegin())>> + : std::is_same().rbegin())>> + { + }; + + template + struct has_member_rbegin().rbegin())>> + : std::is_same().rbegin())>> + { + }; + + template + auto constexpr has_member_rbegin_v = has_member_rbegin::value; + + template + struct has_rbegin : std::disjunction, has_member_rbegin> + { + }; + + template + auto constexpr has_rbegin_v = has_rbegin::value; + } // namespace iterable_rbegin + + inline namespace iterable_crbegin + { + template + struct has_free_crbegin : std::false_type + { + }; + + template + struct has_free_crbegin()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_crbegin_v = has_free_crbegin::value; + + template + struct has_member_crbegin : std::false_type + { + }; + + template + struct has_member_crbegin().crbegin())>> + : std::is_same().crbegin())>> + { + }; + + template + auto constexpr has_member_crbegin_v = has_member_crbegin::value; + + template + struct has_crbegin : std::disjunction, has_member_crbegin> + { + }; + + template + auto constexpr has_crbegin_v = has_crbegin::value; + } // namespace iterable_crbegin + + inline namespace iterable_end + { + template + struct has_free_end : std::false_type + { + }; + + template + struct has_free_end()))>> + : std::is_same()))>> + { + }; + + template + struct has_free_end()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_end_v = has_free_end::value; + + template + struct has_member_end : std::false_type + { + }; + + template + struct has_member_end().end())>> + : std::is_same().end())>> + { + }; + + template + struct has_member_end().end())>> + : std::is_same().end())>> + { + }; + + template + auto constexpr has_member_end_v = has_member_end::value; + + template + struct has_end : std::disjunction, has_member_end> + { + }; + + template + auto constexpr has_end_v = has_end::value; + } // namespace iterable_end + + inline namespace iterable_cend + { + template + struct has_free_cend : std::false_type + { + }; + + template + struct has_free_cend()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_cend_v = has_free_cend::value; + + template + struct has_member_cend : std::false_type + { + }; + + template + struct has_member_cend().cend())>> + : std::is_same().cend())> + { + }; + + template + auto constexpr has_member_cend_v = has_member_cend::value; + + template + struct has_cend : std::disjunction, has_member_cend> + { + }; + + template + auto constexpr has_cend_v = has_cend::value; + } // namespace iterable_cend + + inline namespace iterable_rend + { + template + struct has_free_rend : std::false_type + { + }; + + template + struct has_free_rend()))>> + : std::is_same()))>> + { + }; + + template + struct has_free_rend()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_rend_v = has_free_rend::value; + + template + struct has_member_rend : std::false_type + { + }; + + template + struct has_member_rend().rend())>> + : std::is_same().rend())>> + { + }; + + template + struct has_member_rend().rend())>> + : std::is_same().rend())>> + { + }; + + template + auto constexpr has_member_rend_v = has_member_rend::value; + + template + struct has_rend : std::disjunction, has_member_rend> + { + }; + + template + auto constexpr has_rend_v = has_rend::value; + } // namespace iterable_rend + + inline namespace iterable_crend + { + template + struct has_free_crend : std::false_type + { + }; + + template + struct has_free_crend()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_crend_v = has_free_crend::value; + + template + struct has_member_crend : std::false_type + { + }; + + template + struct has_member_crend().crend())>> + : std::is_same().crend())>> + { + }; + + template + auto constexpr has_member_crend_v = has_member_crend::value; + + template + struct has_crend : std::disjunction, has_member_crend> + { + }; + + template + auto constexpr has_crend_v = has_crend::value; + } // namespace iterable_crend + +} // namespace nt::impl + +#endif \ No newline at end of file diff --git a/source/include/newtype/newtype.hpp b/source/include/newtype/newtype.hpp new file mode 100644 index 0000000..e2704f3 --- /dev/null +++ b/source/include/newtype/newtype.hpp @@ -0,0 +1,550 @@ +#ifndef NEWTYPE_NEWTYPE_HPP +#define NEWTYPE_NEWTYPE_HPP + +#include "newtype/derivable.hpp" +#include "newtype/deriving.hpp" +#include "newtype/impl/new_type_iterator_types.hpp" +#include "newtype/impl/new_type_storage.hpp" +#include "newtype/impl/type_traits_extensions.hpp" +#include "newtype/version.hpp" + +#include +#include +#include +#include + +namespace nt +{ + + template + class new_type + : impl::new_type_move_assignment + , public impl::new_type_iterator_types + { + static_assert(!std::is_reference_v, "The base type must not be a reference type"); + static_assert(!std::is_void_v>, "The base type must not be possibly cv-qualified void"); + + template + auto friend operator>>(std::basic_istream &, new_type &) noexcept( + impl::is_nothrow_input_streamable_v, BaseTypeT>) + -> std::enable_if_t, BaseTypeT>, + std::basic_istream> &; + + template + auto constexpr friend + operator+=(new_type & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_add_assignable_v) + -> std::enable_if_t, + new_type &>; + + template + auto constexpr friend + operator-=(new_type & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_subtract_assignable_v) + -> std::enable_if_t, + new_type &>; + + template + auto constexpr friend + operator*=(new_type & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_multiply_assignable_v) + -> std::enable_if_t, + new_type &>; + + template + auto constexpr friend + operator/=(new_type & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_divide_assignable_v) + -> std::enable_if_t, + new_type &>; + + template + auto constexpr friend begin(new_type & obj) + -> std::enable_if_t, + typename new_type::iterator>; + + template + auto constexpr friend begin(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator>; + + template + auto constexpr friend cbegin(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator>; + + template + auto constexpr friend rbegin(new_type & obj) + -> std::enable_if_t, + typename new_type::reverse_iterator>; + + template + auto constexpr friend rbegin(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator>; + + template + auto constexpr friend crbegin(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator>; + + template + auto constexpr friend end(new_type & obj) + -> std::enable_if_t, + typename new_type::iterator>; + + template + auto constexpr friend end(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator>; + + template + auto constexpr friend cend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator>; + + template + auto constexpr friend rend(new_type & obj) + -> std::enable_if_t, + typename new_type::reverse_iterator>; + + template + auto constexpr friend rend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator>; + + template + auto constexpr friend crend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator>; + + using super = impl::new_type_move_assignment; + + public: + using base_type = BaseType; + using tag_type = TagType; + using derivation_clause_type = decltype(DerivationClause); + + auto constexpr static derivation_clause = DerivationClause; + + using super::super; + + constexpr new_type() noexcept(std::is_nothrow_default_constructible_v) = default; + constexpr new_type(new_type const &) noexcept(std::is_nothrow_copy_constructible_v) = default; + constexpr new_type(new_type &&) noexcept(std::is_nothrow_move_constructible_v) = default; + + auto constexpr operator=(new_type const &) noexcept(std::is_nothrow_copy_assignable_v) -> new_type & = default; + auto constexpr operator=(new_type &&) noexcept(std::is_nothrow_move_assignable_v) -> new_type & = default; + + auto constexpr decay() const noexcept(std::is_nothrow_copy_constructible_v) -> BaseType + { + return this->m_value; + } + + template * = nullptr> + constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v) + { + return decay(); + } + + template * = nullptr> + explicit constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v) + { + return decay(); + } + + template + auto constexpr operator->() noexcept -> std::enable_if_t + { + return std::addressof(this->m_value); + } + + template + auto constexpr operator->() const noexcept -> std::enable_if_t + { + return std::addressof(this->m_value); + } + + template * = nullptr> + auto constexpr begin() + -> std::enable_if_t, typename NewType::iterator> + { + return this->m_value.begin(); + } + + template + auto constexpr begin() const -> std::enable_if_t, + typename NewType::const_iterator> + { + return this->m_value.begin(); + } + + template + auto constexpr cbegin() const -> std::enable_if_t, + typename NewType::const_iterator> + { + return this->m_value.cbegin(); + } + + template * = nullptr> + auto constexpr rbegin() + -> std::enable_if_t, typename NewType::reverse_iterator> + { + return this->m_value.rbegin(); + } + + template + auto constexpr rbegin() const -> std::enable_if_t, + typename NewType::const_reverse_iterator> + { + return this->m_value.rbegin(); + } + + template + auto constexpr crbegin() const -> std::enable_if_t, + typename NewType::const_reverse_iterator> + { + return this->m_value.crbegin(); + } + + template * = nullptr> + auto constexpr end() + -> std::enable_if_t, typename NewType::iterator> + { + return this->m_value.end(); + } + + template + auto constexpr end() const -> std::enable_if_t, + typename NewType::const_iterator> + { + return this->m_value.end(); + } + + template + auto constexpr cend() const -> std::enable_if_t, + typename NewType::const_iterator> + { + return this->m_value.cend(); + } + + template * = nullptr> + auto constexpr rend() + -> std::enable_if_t, typename NewType::reverse_iterator> + { + return this->m_value.rend(); + } + + template + auto constexpr rend() const -> std::enable_if_t, + typename NewType::const_reverse_iterator> + { + return this->m_value.rend(); + } + + template + auto constexpr crend() const -> std::enable_if_t, + typename NewType::const_reverse_iterator> + { + return this->m_value.crend(); + } + }; + + template + auto constexpr + operator==(new_type const & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs.decay() == rhs.decay(); + } + + template + auto constexpr operator==(new_type const & lhs, + BaseType const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs.decay() == rhs; + } + + template + auto constexpr + operator==(BaseType const & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_equality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs == rhs.decay(); + } + + template + auto constexpr + operator!=(new_type const & lhs, + new_type const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs.decay() != rhs.decay(); + } + + template + auto constexpr operator!=(new_type const & lhs, + BaseType const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v) + -> std::enable_if_t, bool> + { + return lhs.decay() != rhs; + } + + template + auto c