diff --git a/.clang-format b/.clang-format index ab8d39f..b0e9d66 100644 --- a/.clang-format +++ b/.clang-format @@ -84,7 +84,7 @@ IndentCaseLabels: true IndentExternBlock: Indent IndentGotoLabels: true IndentPPDirectives: BeforeHash -IndentRequires: false +IndentRequiresClause: true IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: true diff --git a/CMakeLists.txt b/CMakeLists.txt index b13cf5d..40f0e75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,13 +48,19 @@ set(HYPERION_PLATFORM_INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/include/hyperion" ) set(HYPERION_PLATFORM_HEADERS - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts.h" "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/index.h" "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/list.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits.h" "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/value.h" "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/algorithms.h" "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/algorithms/all_of.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts/comparable.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts/operator_able.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts/std_supplemental.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits/is_comparable.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits/is_operator_able.h" + "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits/std_supplemental.h" ) add_library(hyperion_mpl INTERFACE) diff --git a/include/hyperion/mpl/algorithms.h b/include/hyperion/mpl/algorithms.h index 8b7da54..a36ebd1 100644 --- a/include/hyperion/mpl/algorithms.h +++ b/include/hyperion/mpl/algorithms.h @@ -24,3 +24,10 @@ /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. + +#ifndef HYPERION_MPL_ALGORITHMS_H +#define HYPERION_MPL_ALGORITHMS_H + +#include <hyperion/mpl/algorithms/all_of.h> + +#endif // HYPERION_MPL_ALGORITHMS_H diff --git a/include/hyperion/mpl/concepts.h b/include/hyperion/mpl/concepts.h index 598cb0e..93b9aa8 100644 --- a/include/hyperion/mpl/concepts.h +++ b/include/hyperion/mpl/concepts.h @@ -25,3 +25,11 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. +#ifndef HYPERION_MPL_CONCEPTS_H +#define HYPERION_MPL_CONCEPTS_H + +#include <hyperion/mpl/concepts/comparable.h> +#include <hyperion/mpl/concepts/operator_able.h> +#include <hyperion/mpl/concepts/std_supplemental.h> + +#endif // HYPERION_MPL_CONCEPTS_H diff --git a/include/hyperion/mpl/concepts/comparable.h b/include/hyperion/mpl/concepts/comparable.h new file mode 100644 index 0000000..a079e7a --- /dev/null +++ b/include/hyperion/mpl/concepts/comparable.h @@ -0,0 +1,113 @@ +/// @file comparable.h +/// @author Braxton Salyer <braxtonsalyer@gmail.com> +/// @brief Meta-programming C++20 concepts to determine if two types are comparable +/// in various ways +/// @version 0.1 +/// @date 2024-01-27 +/// +/// MIT License +/// @copyright Copyright (c) 2024 Braxton Salyer <braxtonsalyer@gmail.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to +/// deal in the Software without restriction, including without limitation the +/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +/// sell copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. + +#ifndef HYPERION_MPL_CONCEPTS_COMPARABLE_H +#define HYPERION_MPL_CONCEPTS_COMPARABLE_H + +#include <hyperion/mpl/type_traits/is_comparable.h> + +namespace hyperion::mpl::concepts { + + template<typename TLhs, typename TRhs> + concept EqualityComparable = type_traits::is_equality_comparable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs> + concept InequalityComparable = type_traits::is_inequality_comparable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs> + concept LessThanComparable = type_traits::is_less_than_comparable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs> + concept LessThanOrEqualComparable = type_traits::is_less_than_or_equal_comparable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs> + concept GreaterThanComparable = type_traits::is_greater_than_comparable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs> + concept GreaterThanOrEqualComparable + = type_traits::is_greater_than_or_equal_comparable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs> + concept ThreeWayComparable = type_traits::is_three_way_comparable_v<TLhs, TRhs>; + + namespace _test { + + struct not_comparable { }; + + static_assert(EqualityComparable<int, int>, + "hyperion::mpl::concepts::EqualityComparable test case 1 failing"); + static_assert(EqualityComparable<int, double>, + "hyperion::mpl::concepts::EqualityComparable test case 2 failing"); + static_assert(!EqualityComparable<int, not_comparable>, + "hyperion::mpl::concepts::EqualityComparable test case 3 failing"); + + static_assert(InequalityComparable<int, int>, + "hyperion::mpl::concepts::InequalityComparable test case 1 failing"); + static_assert(InequalityComparable<int, double>, + "hyperion::mpl::concepts::InequalityComparable test case 2 failing"); + static_assert(!InequalityComparable<int, not_comparable>, + "hyperion::mpl::concepts::InequalityComparable test case 3 failing"); + + static_assert(LessThanComparable<int, int>, + "hyperion::mpl::concepts::LessThanComparable test case 1 failing"); + static_assert(LessThanComparable<int, double>, + "hyperion::mpl::concepts::LessThanComparable test case 2 failing"); + static_assert(!LessThanComparable<int, not_comparable>, + "hyperion::mpl::concepts::LessThanComparable test case 3 failing"); + + static_assert(LessThanOrEqualComparable<int, int>, + "hyperion::mpl::concepts::LessThanOrEqualComparable test case 1 failing"); + static_assert(LessThanOrEqualComparable<int, double>, + "hyperion::mpl::concepts::LessThanOrEqualComparable test case 2 failing"); + static_assert(!LessThanOrEqualComparable<int, not_comparable>, + "hyperion::mpl::concepts::LessThanOrEqualComparable test case 3 failing"); + + static_assert(GreaterThanComparable<int, int>, + "hyperion::mpl::concepts::GreaterThanComparable test case 1 failing"); + static_assert(GreaterThanComparable<int, double>, + "hyperion::mpl::concepts::GreaterThanComparable test case 2 failing"); + static_assert(!GreaterThanComparable<int, not_comparable>, + "hyperion::mpl::concepts::GreaterThanComparable test case 3 failing"); + + static_assert(GreaterThanOrEqualComparable<int, int>, + "hyperion::mpl::concepts::GreaterThanOrEqualComparable test case 1 failing"); + static_assert(GreaterThanOrEqualComparable<int, double>, + "hyperion::mpl::concepts::GreaterThanOrEqualComparable test case 2 failing"); + static_assert(!GreaterThanOrEqualComparable<int, not_comparable>, + "hyperion::mpl::concepts::GreaterThanOrEqualComparable test case 3 failing"); + + static_assert(ThreeWayComparable<int, int>, + "hyperion::mpl::concepts::ThreeWayComparable test case 1 failing"); + static_assert(ThreeWayComparable<int, double>, + "hyperion::mpl::concepts::ThreeWayComparable test case 2 failing"); + static_assert(!ThreeWayComparable<int, not_comparable>, + "hyperion::mpl::concepts::ThreeWayComparable test case 3 failing"); + } // namespace _test +} // namespace hyperion::mpl::concepts + +#endif // HYPERION_MPL_CONCEPTS_IS_COMPARABLE_H diff --git a/include/hyperion/mpl/concepts/operator_able.h b/include/hyperion/mpl/concepts/operator_able.h new file mode 100644 index 0000000..78889f0 --- /dev/null +++ b/include/hyperion/mpl/concepts/operator_able.h @@ -0,0 +1,80 @@ +/// @file operator_able.h +/// @author Braxton Salyer <braxtonsalyer@gmail.com> +/// @brief Meta-programming C++20 concept definitions to determine if a type +/// (or types) support an operator +/// @version 0.1 +/// @date 2024-01-27 +/// +/// MIT License +/// @copyright Copyright (c) 2024 Braxton Salyer <braxtonsalyer@gmail.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to +/// deal in the Software without restriction, including without limitation the +/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +/// sell copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. + +#ifndef HYPERION_MPL_CONCEPTS_OPERATOR_ABLE_H +#define HYPERION_MPL_CONCEPTS_OPERATOR_ABLE_H + +#include <hyperion/mpl/type_traits/is_operator_able.h> + +namespace hyperion::mpl::concepts { + + template<typename TLhs> + concept UnaryPlusable = type_traits::is_unary_plusable_v<TLhs>; + + template<typename TLhs> + concept UnaryMinusable = type_traits::is_unary_minusable_v<TLhs>; + + template<typename TLhs> + concept BinaryNotable = type_traits::is_binary_notable_v<TLhs>; + + template<typename TLhs> + concept BooleanNotable = type_traits::is_boolean_notable_v<TLhs>; + + template<typename TLhs> + concept Addressable = type_traits::is_addressable_v<TLhs>; + + template<typename TLhs> + concept Arrowable = type_traits::is_arrowable_v<TLhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept Addable = type_traits::is_addable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept Subtractable = type_traits::is_subtractable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept Multipliable = type_traits::is_multipliable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept Dividible = type_traits::is_dividible_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept BinaryAndable = type_traits::is_binary_andable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept BinaryOrable = type_traits::is_binary_orable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept BooleanAndable = type_traits::is_boolean_andable_v<TLhs, TRhs>; + + template<typename TLhs, typename TRhs = TLhs> + concept BooleanOrable = type_traits::is_boolean_orable_v<TLhs, TRhs>; + +} // namespace hyperion::mpl::concepts + +#endif // HYPERION_MPL_CONCEPTS_OPERATOR_ABLE_H diff --git a/include/hyperion/mpl/concepts/std_supplemental.h b/include/hyperion/mpl/concepts/std_supplemental.h new file mode 100644 index 0000000..13359f3 --- /dev/null +++ b/include/hyperion/mpl/concepts/std_supplemental.h @@ -0,0 +1,41 @@ +/// @file std_supplemental.h +/// @author Braxton Salyer <braxtonsalyer@gmail.com> +/// @brief Supplemental C++20 concept definitions to those provided in +/// `#include <concepts>` to provide functionality missing from the standard +/// @version 0.1 +/// @date 2024-01-27 +/// +/// MIT License +/// @copyright Copyright (c) 2024 Braxton Salyer <braxtonsalyer@gmail.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in all +/// copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#ifndef HYPERION_MPL_CONCEPTS_STD_SUPPLEMENTAL_H +#define HYPERION_MPL_CONCEPTS_STD_SUPPLEMENTAL_H + +#include <hyperion/mpl/type_traits/std_supplemental.h> + +namespace hyperion::mpl::concepts { + + template<typename TType> + concept TriviallyMovable = type_traits::is_trivially_movable_v<TType>; + +} // namespace hyperion::mpl::concepts + +#endif // HYPERION_MPL_CONCEPTS_STD_SUPPLEMENTAL_H diff --git a/include/hyperion/mpl/type_traits.h b/include/hyperion/mpl/type_traits.h index 27dd840..b6851e8 100644 --- a/include/hyperion/mpl/type_traits.h +++ b/include/hyperion/mpl/type_traits.h @@ -25,3 +25,11 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. +#ifndef HYPERION_MPL_TYPE_TRAITS_H +#define HYPERION_MPL_TYPE_TRAITS_H + +#include <hyperion/mpl/type_traits/is_comparable.h> +#include <hyperion/mpl/type_traits/is_operator_able.h> +#include <hyperion/mpl/type_traits/std_supplemental.h> + +#endif // HYPERION_MPL_TYPE_TRAITS_H diff --git a/include/hyperion/mpl/type_traits/is_comparable.h b/include/hyperion/mpl/type_traits/is_comparable.h new file mode 100644 index 0000000..71044a2 --- /dev/null +++ b/include/hyperion/mpl/type_traits/is_comparable.h @@ -0,0 +1,227 @@ +/// @file is_comparable.h +/// @author Braxton Salyer <braxtonsalyer@gmail.com> +/// @brief Meta-programming type traits to determine if two types are comparable +/// in various ways +/// @version 0.1 +/// @date 2024-01-27 +/// +/// MIT License +/// @copyright Copyright (c) 2024 Braxton Salyer <braxtonsalyer@gmail.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to +/// deal in the Software without restriction, including without limitation the +/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +/// sell copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. + +#ifndef HYPERION_MPL_TYPE_TRAITS_IS_COMPARABLE_H +#define HYPERION_MPL_TYPE_TRAITS_IS_COMPARABLE_H + +#include <hyperion/platform/def.h> + +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + #include <compare> +#endif // HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + +#include <type_traits> + +namespace hyperion::mpl::type_traits { + + // clang-format off + + template<typename TLhs, typename TRhs> + struct is_equality_comparable + : std::bool_constant<requires(const TLhs& lhs, const TRhs& rhs) { + lhs == rhs; + rhs == lhs; + }> + {}; + + // clang-format on + + template<typename TLhs, typename TRhs> + static inline constexpr auto is_equality_comparable_v + = is_equality_comparable<TLhs, TRhs>::value; + // clang-format off + + template<typename TLhs, typename TRhs> + struct is_inequality_comparable + : std::bool_constant<requires(const TLhs& lhs, const TRhs& rhs) { + lhs != rhs; + rhs != lhs; + }> + {}; + + // clang-format on + + template<typename TLhs, typename TRhs> + static inline constexpr auto is_inequality_comparable_v + = is_inequality_comparable<TLhs, TRhs>::value; + // clang-format off + + template<typename TLhs, typename TRhs> + struct is_less_than_comparable + : std::bool_constant<requires(const TLhs& lhs, const TRhs& rhs) { + lhs < rhs; + rhs < lhs; + }> + {}; + + // clang-format on + + template<typename TLhs, typename TRhs> + static inline constexpr auto is_less_than_comparable_v + = is_less_than_comparable<TLhs, TRhs>::value; + // clang-format off + + template<typename TLhs, typename TRhs> + struct is_less_than_or_equal_comparable + : std::bool_constant<requires(const TLhs& lhs, const TRhs& rhs) { + lhs <= rhs; + rhs <= lhs; + }> + {}; + + // clang-format on + + template<typename TLhs, typename TRhs> + static inline constexpr auto is_less_than_or_equal_comparable_v + = is_less_than_or_equal_comparable<TLhs, TRhs>::value; + // clang-format off + + template<typename TLhs, typename TRhs> + struct is_greater_than_comparable + : std::bool_constant<requires(const TLhs& lhs, const TRhs& rhs) { + lhs > rhs; + rhs > lhs; + }> + {}; + + // clang-format on + + template<typename TLhs, typename TRhs> + static inline constexpr auto is_greater_than_comparable_v + = is_greater_than_comparable<TLhs, TRhs>::value; + // clang-format off + + template<typename TLhs, typename TRhs> + struct is_greater_than_or_equal_comparable + : std::bool_constant<requires(const TLhs& lhs, const TRhs& rhs) { + lhs >= rhs; + rhs >= lhs; + }> + {}; + + // clang-format on + + template<typename TLhs, typename TRhs> + static inline constexpr auto is_greater_than_or_equal_comparable_v + = is_greater_than_or_equal_comparable<TLhs, TRhs>::value; + // clang-format off + + template<typename TLhs, typename TRhs> + struct is_three_way_comparable : std::false_type { +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + using result_type = void; +#endif + }; + + template<typename TLhs, typename TRhs> + requires std::three_way_comparable_with<TLhs, TRhs> + struct is_three_way_comparable<TLhs, TRhs> : std::true_type { +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + using result_type = std::compare_three_way_result_t<TLhs, TRhs>; +#endif + }; + // clang-format on + + template<typename TLhs, typename TRhs> + static inline constexpr auto is_three_way_comparable_v + = is_three_way_comparable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs> + using three_way_compare_result_t = typename is_three_way_comparable<TLhs, TRhs>::result_type; + + namespace _test { + + struct not_comparable { }; + + static_assert(is_equality_comparable_v<int, int>, + "hyperion::mpl::type_traits::is_equality_comparable test case 1 failing"); + static_assert(is_equality_comparable_v<int, double>, + "hyperion::mpl::type_traits::is_equality_comparable test case 2 failing"); + static_assert(!is_equality_comparable_v<int, not_comparable>, + "hyperion::mpl::type_traits::is_equality_comparable test case 3 failing"); + + static_assert(is_inequality_comparable_v<int, int>, + "hyperion::mpl::type_traits::is_inequality_comparable test case 1 failing"); + static_assert(is_inequality_comparable_v<int, double>, + "hyperion::mpl::type_traits::is_inequality_comparable test case 2 failing"); + static_assert(!is_inequality_comparable_v<int, not_comparable>, + "hyperion::mpl::type_traits::is_inequality_comparable test case 3 failing"); + + static_assert(is_less_than_comparable_v<int, int>, + "hyperion::mpl::type_traits::is_less_than_comparable test case 1 failing"); + static_assert(is_less_than_comparable_v<int, double>, + "hyperion::mpl::type_traits::is_less_than_comparable test case 2 failing"); + static_assert(!is_less_than_comparable_v<int, not_comparable>, + "hyperion::mpl::type_traits::is_less_than_comparable test case 3 failing"); + + static_assert( + is_less_than_or_equal_comparable_v<int, int>, + "hyperion::mpl::type_traits::is_less_than_or_equal_comparable test case 1 failing"); + static_assert( + is_less_than_or_equal_comparable_v<int, double>, + "hyperion::mpl::type_traits::is_less_than_or_equal_comparable test case 2 failing"); + static_assert( + !is_less_than_or_equal_comparable_v<int, not_comparable>, + "hyperion::mpl::type_traits::is_less_than_or_equal_comparable test case 3 failing"); + + static_assert(is_greater_than_comparable_v<int, int>, + "hyperion::mpl::type_traits::is_greater_than_comparable test case 1 failing"); + static_assert(is_greater_than_comparable_v<int, double>, + "hyperion::mpl::type_traits::is_greater_than_comparable test case 2 failing"); + static_assert(!is_greater_than_comparable_v<int, not_comparable>, + "hyperion::mpl::type_traits::is_greater_than_comparable test case 3 failing"); + + static_assert( + is_greater_than_or_equal_comparable_v<int, int>, + "hyperion::mpl::type_traits::is_greater_than_or_equal_comparable test case 1 failing"); + static_assert( + is_greater_than_or_equal_comparable_v<int, double>, + "hyperion::mpl::type_traits::is_greater_than_or_equal_comparable test case 2 failing"); + static_assert( + !is_greater_than_or_equal_comparable_v<int, not_comparable>, + "hyperion::mpl::type_traits::is_greater_than_or_equal_comparable test case 3 failing"); + + static_assert(is_three_way_comparable_v<int, int>, + "hyperion::mpl::type_traits::is_three_way_comparable test case 1 failing"); + static_assert(is_three_way_comparable_v<int, double>, + "hyperion::mpl::type_traits::is_three_way_comparable test case 2 failing"); + static_assert(!is_three_way_comparable_v<int, not_comparable>, + "hyperion::mpl::type_traits::is_three_way_comparable test case 3 failing"); + +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + static_assert(std::same_as<three_way_compare_result_t<int, int>, std::strong_ordering>, + "hyperion::mpl::type_traits::is_three_way_comparable test case 1 failing"); + static_assert(std::same_as<three_way_compare_result_t<int, double>, std::partial_ordering>, + "hyperion::mpl::type_traits::is_three_way_comparable test case 2 failing"); + static_assert(std::same_as<three_way_compare_result_t<int, not_comparable>, void>, + "hyperion::mpl::type_traits::is_three_way_comparable test case 3 failing"); +#endif // HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + } // namespace _test +} // namespace hyperion::mpl::type_traits + +#endif // HYPERION_MPL_TYPE_TRAITS_IS_COMPARABLE_H diff --git a/include/hyperion/mpl/type_traits/is_operator_able.h b/include/hyperion/mpl/type_traits/is_operator_able.h new file mode 100644 index 0000000..6822c63 --- /dev/null +++ b/include/hyperion/mpl/type_traits/is_operator_able.h @@ -0,0 +1,302 @@ +/// @file is_operator_able.h +/// @author Braxton Salyer <braxtonsalyer@gmail.com> +/// @brief Meta-programming type traits to determine if a type (or types) +/// support an operator +/// @version 0.1 +/// @date 2024-01-27 +/// +/// MIT License +/// @copyright Copyright (c) 2024 Braxton Salyer <braxtonsalyer@gmail.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to +/// deal in the Software without restriction, including without limitation the +/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +/// sell copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. + +#ifndef HYPERION_MPL_TYPE_TRAITS_IS_OPERATOR_ABLE_H +#define HYPERION_MPL_TYPE_TRAITS_IS_OPERATOR_ABLE_H + +#include <type_traits> + +namespace hyperion::mpl::type_traits { + + template<typename TLhs> + struct is_unary_plusable : std::false_type { + using result_type = void; + }; + + template<typename TLhs> + requires requires(const TLhs& lhs) { +lhs; } + struct is_unary_plusable<TLhs> : std::true_type { + using result_type = decltype(+std::declval<TLhs>()); + }; + + template<typename TLhs> + static inline constexpr auto is_unary_plusable_v = is_unary_plusable<TLhs>::value; + + template<typename TLhs> + using unary_plus_result_t = typename is_unary_plusable<TLhs>::result_type; + + template<typename TLhs> + struct is_unary_minusable : std::false_type { + using result_type = void; + }; + + template<typename TLhs> + requires requires(const TLhs& lhs) { -lhs; } + struct is_unary_minusable<TLhs> : std::true_type { + using result_type = decltype(-std::declval<TLhs>()); + }; + + template<typename TLhs> + static inline constexpr auto is_unary_minusable_v = is_unary_minusable<TLhs>::value; + + template<typename TLhs> + using unary_minus_result_t = typename is_unary_minusable<TLhs>::result_type; + + template<typename TLhs> + struct is_binary_notable : std::false_type { + using result_type = void; + }; + + template<typename TLhs> + requires requires(const TLhs& lhs) { ~lhs; } + struct is_binary_notable<TLhs> : std::true_type { + using result_type = decltype(~std::declval<TLhs>()); + }; + + template<typename TLhs> + static inline constexpr auto is_binary_notable_v = is_binary_notable<TLhs>::value; + + template<typename TLhs> + using binary_not_result_t = typename is_binary_notable<TLhs>::result_type; + + template<typename TLhs> + struct is_boolean_notable : std::false_type { + using result_type = void; + }; + + template<typename TLhs> + requires requires(const TLhs& lhs) { !lhs; } + struct is_boolean_notable<TLhs> : std::true_type { + using result_type = decltype(!std::declval<TLhs>()); + }; + + template<typename TLhs> + static inline constexpr auto is_boolean_notable_v = is_boolean_notable<TLhs>::value; + + template<typename TLhs> + using boolean_not_result_t = typename is_boolean_notable<TLhs>::result_type; + + template<typename TLhs> + struct is_addressable : std::false_type { + using result_type = void; + }; + + template<typename TLhs> + requires requires(const TLhs& lhs) { &lhs; } + struct is_addressable<TLhs> : std::true_type { + using result_type = decltype(&std::declval<TLhs>()); + }; + + template<typename TLhs> + static inline constexpr auto is_addressable_v = is_addressable<TLhs>::value; + + template<typename TLhs> + using address_result_t = typename is_addressable<TLhs>::result_type; + + template<typename TLhs> + struct is_arrowable : std::false_type { + using result_type = void; + }; + + template<typename TLhs> + requires std::is_pointer_v<TLhs> || requires(const TLhs& lhs) { lhs.operator->(); } + struct is_arrowable<TLhs> : std::true_type { + using result_type = std::conditional_t<std::is_pointer_v<TLhs>, + std::remove_pointer_t<TLhs>, + decltype(std::declval<TLhs>().operator->())>; + }; + + template<typename TLhs> + static inline constexpr auto is_arrowable_v = is_arrowable<TLhs>::value; + + template<typename TLhs> + using arrow_result_t = typename is_arrowable<TLhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_addable : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs + rhs; + rhs + lhs; + } + struct is_addable<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() + std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_addable_v = is_addable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using add_result_t = typename is_addable<TLhs, TRhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_subtractable : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs - rhs; + rhs - lhs; + } + struct is_subtractable<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() - std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_subtractable_v = is_subtractable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using subtract_result_t = typename is_subtractable<TLhs, TRhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_multipliable : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs* rhs; + rhs* lhs; + } + struct is_multipliable<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() * std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_multipliable_v = is_multipliable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using multiply_result_t = typename is_multipliable<TLhs, TRhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_dividible : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs / rhs; + rhs / lhs; + } + struct is_dividible<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() / std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_dividible_v = is_dividible<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using divide_result_t = typename is_dividible<TLhs, TRhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_binary_andable : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs & rhs; + rhs & lhs; + } + struct is_binary_andable<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() & std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_binary_andable_v = is_binary_andable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using binary_and_result_t = typename is_binary_andable<TLhs, TRhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_binary_orable : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs | rhs; + rhs | lhs; + } + struct is_binary_orable<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() | std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_binary_orable_v = is_binary_orable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using binary_or_result_t = typename is_binary_orable<TLhs, TRhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_boolean_andable : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs&& rhs; + rhs&& lhs; + } + struct is_boolean_andable<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() && std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_boolean_andable_v = is_boolean_andable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using boolean_and_result_t = typename is_boolean_andable<TLhs, TRhs>::result_type; + + template<typename TLhs, typename TRhs = TLhs> + struct is_boolean_orable : std::false_type { + using result_type = void; + }; + + template<typename TLhs, typename TRhs> + requires requires(const TLhs& lhs, const TRhs& rhs) { + lhs || rhs; + rhs || lhs; + } + struct is_boolean_orable<TLhs, TRhs> : std::true_type { + using result_type = decltype(std::declval<TLhs>() || std::declval<TRhs>()); + }; + + template<typename TLhs, typename TRhs = TLhs> + static inline constexpr auto is_boolean_orable_v = is_boolean_orable<TLhs, TRhs>::value; + + template<typename TLhs, typename TRhs = TLhs> + using boolean_or_result_t = typename is_boolean_orable<TLhs, TRhs>::result_type; + +} // namespace hyperion::mpl::type_traits + +#endif // HYPERION_MPL_TYPE_TRAITS_IS_OPERATOR_ABLE_H diff --git a/include/hyperion/mpl/type_traits/std_supplemental.h b/include/hyperion/mpl/type_traits/std_supplemental.h new file mode 100644 index 0000000..203773f --- /dev/null +++ b/include/hyperion/mpl/type_traits/std_supplemental.h @@ -0,0 +1,45 @@ +/// @file std_supplemental.h +/// @author Braxton Salyer <braxtonsalyer@gmail.com> +/// @brief Supplemental type traits to those provided in `#include <type_traits>` +/// to provide functionality missing from the standard +/// @version 0.1 +/// @date 2024-01-27 +/// +/// MIT License +/// @copyright Copyright (c) 2024 Braxton Salyer <braxtonsalyer@gmail.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in all +/// copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#ifndef HYPERION_MPL_TYPE_TRAITS_STD_SUPPLEMENTAL_H +#define HYPERION_MPL_TYPE_TRAITS_STD_SUPPLEMENTAL_H + +#include <type_traits> + +namespace hyperion::mpl::type_traits { + + template<typename TType> + struct is_trivially_movable + : public std::bool_constant<std::is_trivially_move_constructible_v<TType> + && std::is_trivially_move_assignable_v<TType>> { }; + + template<typename TType> + static inline constexpr auto is_trivially_movable_v = is_trivially_movable<TType>::value; +} // namespace hyperion::mpl::type_traits + +#endif // HYPERION_MPL_TYPE_TRAITS_STD_SUPPLEMENTAL_H diff --git a/include/hyperion/mpl/value.h b/include/hyperion/mpl/value.h index f1fcb35..51df672 100644 --- a/include/hyperion/mpl/value.h +++ b/include/hyperion/mpl/value.h @@ -8,19 +8,380 @@ /// @copyright Copyright (c) 2024 Braxton Salyer <braxtonsalyer@gmail.com> /// /// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is +/// of this software and associated documentation files (the "Software"), to +/// deal in the Software without restriction, including without limitation the +/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +/// sell copies of the Software, and to permit persons to whom the Software is /// furnished to do so, subject to the following conditions: /// -/// The above copyright notice and this permission notice shall be included in all -/// copies or substantial portions of the Software. +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. + +#ifndef HYPERION_MPL_VALUE_H +#define HYPERION_MPL_VALUE_H + +#include <hyperion/mpl/concepts/comparable.h> +#include <hyperion/mpl/concepts/operator_able.h> +#include <hyperion/platform/def.h> +#include <hyperion/platform/types.h> + +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + #include <compare> +#endif // HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + +#include <concepts> +#include <type_traits> + +namespace hyperion::mpl { + + // clang-format off + + template<typename TType> + struct is_value_type + : std::bool_constant<requires { + TType::value; + }> + {}; + + template<typename TType> + static inline constexpr auto is_value_type_v = is_value_type<TType>::value; + + template<typename TType> + concept ValueType = is_value_type_v<TType>; + // clang-format on + + template<auto TValue, typename TType = decltype(TValue)> + struct Value { + static inline constexpr auto value = TValue; + + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + [[nodiscard]] constexpr operator decltype(value)() noexcept { + return value; + } + }; + + template<char... TChars> + [[nodiscard]] static inline constexpr auto operator""_value() noexcept { + constexpr auto parsed = detail::parse_literal<usize>(detail::string_literal<TChars...>{}); + detail::check_literal_status<parsed.status>(); + return Value<parsed.value>{}; + } + + template<auto TValue> + [[nodiscard]] constexpr auto + value_of([[maybe_unused]] const Value<TValue>& value) noexcept -> decltype(TValue) { + return TValue; + } + + template<ValueType TType> + requires(!std::same_as<TType, Value<TType::value>>) + [[nodiscard]] constexpr auto + value_of([[maybe_unused]] const TType& value) noexcept -> decltype(TType::value) { + return TType::value; + } + + template<ValueType TType> + requires(!std::same_as<TType, Value<TType::value>>) + [[nodiscard]] constexpr auto + as_value([[maybe_unused]] const TType& value) noexcept -> Value<TType::value> { + return {}; + } + + template<auto TLhs> + requires concepts::UnaryPlusable<decltype(TLhs)> + [[nodiscard]] constexpr auto + operator+([[maybe_unused]] const Value<TLhs>& value) noexcept -> Value<TLhs> { + return {}; + } + + template<auto TLhs> + requires concepts::UnaryMinusable<decltype(TLhs)> + [[nodiscard]] constexpr auto + operator-([[maybe_unused]] const Value<TLhs>& value) noexcept -> Value<-TLhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::Addable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator+([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs + TRhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::Subtractable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator-([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs - TRhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::Dividible<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator/([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs / TRhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::Multipliable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator*([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs * TRhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::BooleanAndable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator&&([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs && TRhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::BooleanOrable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator||([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs || TRhs> { + return {}; + } + + template<auto TLhs> + requires concepts::BooleanNotable<decltype(TLhs)> + [[nodiscard]] constexpr auto + operator!([[maybe_unused]] const Value<TLhs>& lhs) noexcept -> Value<!TLhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::BinaryAndable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator&([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs & TRhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::BinaryOrable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator|([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs | TRhs> { + return {}; + } + + template<auto TLhs> + requires concepts::BinaryNotable<decltype(TLhs)> + [[nodiscard]] constexpr auto + operator~([[maybe_unused]] const Value<TLhs>& lhs) noexcept -> Value<~TLhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::EqualityComparable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator==([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs == TRhs> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::InequalityComparable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator!=([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs != TRhs> { + return {}; + } + +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + + template<auto TLhs, auto TRhs> + requires concepts::ThreeWayComparable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator<=>([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<TLhs <=> TRhs> { + return {}; + } + +#else + + template<auto TLhs, auto TRhs> + requires concepts::LessThanComparable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator<([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<(TLhs < TRhs)> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::LessThanOrEqualComparable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator<=([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<(TLhs <= TRhs)> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::GreaterThanComparable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator>([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<(TLhs > TRhs)> { + return {}; + } + + template<auto TLhs, auto TRhs> + requires concepts::GreaterThanOrEqualComparable<decltype(TLhs), decltype(TRhs)> + [[nodiscard]] constexpr auto + operator>=([[maybe_unused]] const Value<TLhs>& lhs, + [[maybe_unused]] const Value<TRhs>& rhs) noexcept -> Value<(TLhs >= TRhs)> { + return {}; + } + +#endif // HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + + namespace _test { + + static_assert(ValueType<Value<true>>, + "hyperion::mpl::ValueType not satisfied by hyperion::mpl::Value " + "(implementation failing)"); + static_assert(ValueType<std::bool_constant<true>>, + "hyperion::mpl::ValueType not satisfied by std::bool_constant " + "(implementation failing)"); + + static_assert(value_of(Value<3>{}) == 3, "hyperion::mpl::value_of test case 1 (failing)"); + static_assert(value_of(std::integral_constant<int, 3>{}) == 3, + "hyperion::mpl::value_of test case 2 (failing)"); + static_assert(Value<3>{} == 3, + "hyperion::mpl::Value implicit conversion test case (failing)"); + + static_assert(std::same_as<decltype(as_value(std::integral_constant<int, 3>{})), Value<3>>, + "hyperion::mpl::as_value test case 1 (failing)"); + + static_assert(Value<3>{} == 3_value, + "hyperion::mpl::operator" + "_value test case 1 (failing)"); + + static_assert(+Value<3>{} == 3, "hyperion::mpl::operator+(Value) test case 1 (failing)"); + static_assert(-Value<3>{} == -3, "hyperion::mpl::operator-(Value) test case 1 (failing)"); + + static_assert(Value<1>{} + Value<2>{} == 3, + "hyperion::mpl::operator+(Value, Value) test case 1 (failing)"); + static_assert(Value<1>{} + Value<-2>{} == -1, + "hyperion::mpl::operator+(Value, Value) test case 2 (failing)"); + + static_assert(Value<1>{} - Value<2>{} == -1, + "hyperion::mpl::operator-(Value, Value) test case 1 (failing)"); + static_assert(Value<1>{} - Value<-2>{} == 3, + "hyperion::mpl::operator-(Value, Value) test case 2 (failing)"); + + static_assert(Value<2>{} * Value<2>{} == 4, + "hyperion::mpl::operator*(Value, Value) test case 1 (failing)"); + static_assert(Value<2>{} * Value<-2>{} == -4, + "hyperion::mpl::operator*(Value, Value) test case 2 (failing)"); + + static_assert(Value<2>{} / Value<2>{} == 1, + "hyperion::mpl::operator*(Value, Value) test case 1 (failing)"); + static_assert(Value<2>{} / Value<-2>{} == -1, + "hyperion::mpl::operator*(Value, Value) test case 2 (failing)"); + + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + static_assert((Value<true>{} && Value<false>{}) == false, + "hyperion::mpl::operator&&(Value, Value) test case 1 (failing)"); + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + static_assert((Value<true>{} && Value<true>{}) == true, + "hyperion::mpl::operator&&(Value, Value) test case 2 (failing)"); + + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + static_assert((Value<true>{} || Value<false>{}) == true, + "hyperion::mpl::operator||(Value, Value) test case 1 (failing)"); + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + static_assert((Value<false>{} || Value<false>{}) == false, + "hyperion::mpl::operator||(Value, Value) test case 2 (failing)"); + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + static_assert((Value<true>{} || Value<true>{}) == true, + "hyperion::mpl::operator||(Value, Value) test case 3 (failing)"); + + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + static_assert(!Value<true>{} == false, + "hyperion::mpl::operator!(Value) test case 1 (failing)"); + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + static_assert(!Value<false>{} == true, + "hyperion::mpl::operator!(Value) test case 2 (failing)"); + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + static_assert((Value<0b1100_usize>{} & Value<0b0011_usize>{}) == 0, + "hyperion::mpl::operator&(Value, Value) test case 1 (failing)"); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + static_assert((Value<0b0110_usize>{} & Value<0b1100_usize>{}) == 0b0100_usize, + "hyperion::mpl::operator&(Value, Value) test case 2 (failing)"); + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + static_assert((Value<0b1100_usize>{} | Value<0b0011_usize>{}) == 0b1111_usize, + "hyperion::mpl::operator&(Value, Value) test case 1 (failing)"); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + static_assert((Value<0b0110_usize>{} | Value<0b1100_usize>{}) == 0b1110_usize, + "hyperion::mpl::operator&(Value, Value) test case 2 (failing)"); + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + static_assert(~Value<0b0011_usize>{} == (~0b0011_usize), + "hyperion::mpl::operator~(Value) test case 1 (failing)"); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + static_assert(~Value<0b1100_usize>{} == (~0b1100_usize), + "hyperion::mpl::operator~(Value) test case 2 (failing)"); + + static_assert(Value<1>{} == Value<1>{}, + "hyperion::mpl::operator==(Value, Value) test case 1 failing"); + static_assert(!(Value<1>{} == Value<2>{}), + "hyperion::mpl::operator==(Value, Value) test case 2 failing"); + + static_assert(Value<1>{} != Value<2>{}, + "hyperion::mpl::operator!=(Value, Value) test case 1 failing"); + static_assert(!(Value<1>{} != Value<1>{}), + "hyperion::mpl::operator!=(Value, Value) test case 2 failing"); + + static_assert(Value<1>{} < Value<2>{}, + "hyperion::mpl::operator<(Value, Value) test case 1 failing"); + static_assert(!(Value<1>{} < Value<1>{}), + "hyperion::mpl::operator<(Value, Value) test case 2 failing"); + + static_assert(Value<1>{} <= Value<1>{}, + "hyperion::mpl::operator<=(Value, Value) test case 1 failing"); + static_assert(Value<1>{} <= Value<2>{}, + "hyperion::mpl::operator<=(Value, Value) test case 2 failing"); + static_assert(!(Value<1>{} <= Value<0>{}), + "hyperion::mpl::operator<=(Value, Value) test case 3 failing"); + + static_assert(Value<2>{} > Value<1>{}, + "hyperion::mpl::operator>(Value, Value) test case 1 failing"); + static_assert(!(Value<1>{} > Value<1>{}), + "hyperion::mpl::operator>(Value, Value) test case 2 failing"); + + static_assert(Value<1>{} >= Value<1>{}, + "hyperion::mpl::operator>=(Value, Value) test case 1 failing"); + static_assert(Value<2>{} >= Value<1>{}, + "hyperion::mpl::operator>=(Value, Value) test case 2 failing"); + static_assert(!(Value<0>{} >= Value<1>{}), + "hyperion::mpl::operator>=(Value, Value) test case 3 failing"); + +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + static_assert((Value<1>{} <=> Value<1>{}) == std::strong_ordering::equal, + "hyperion::mpl::operator<=>(Value, Value) test case 1 failing"); + static_assert(Value<2>{} <=> Value<1>{} == std::strong_ordering::greater, + "hyperion::mpl::operator<=>(Value, Value) test case 2 failing"); + static_assert(Value<0>{} <=> Value<1>{} == std::strong_ordering::less, + "hyperion::mpl::operator<=>(Value, Value) test case 3 failing"); +#endif + } // namespace _test +} // namespace hyperion::mpl + +#endif // HYPERION_MPL_VALUE_H diff --git a/src/main.cpp b/src/main.cpp index 62577d1..2b53e37 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,15 @@ +#include <hyperion/mpl/algorithms.h> +#include <hyperion/mpl/concepts.h> +#include <hyperion/mpl/index.h> +#include <hyperion/mpl/list.h> +#include <hyperion/mpl/type_traits.h> +#include <hyperion/mpl/value.h> #include <hyperion/platform/types.h> -using namespace hyperion; // NOLINT(google-build-using-namespace) +using namespace hyperion; // NOLINT(google-build-using-namespace) +using namespace hyperion::mpl; // NOLINT(google-build-using-namespace) [[nodiscard]] auto main([[maybe_unused]] i32 argc, [[maybe_unused]] const char* const* argv) -> i32 { - return 0_i32; + return static_cast<i32>(0_value); } diff --git a/xmake.lua b/xmake.lua index 0647739..4b0dfdb 100644 --- a/xmake.lua +++ b/xmake.lua @@ -49,10 +49,19 @@ local hyperion_mpl_headers = { "$(projectdir)/include/hyperion/mpl/type_traits.h", "$(projectdir)/include/hyperion/mpl/value.h", } - local hyperion_mpl_algorithms_headers = { "$(projectdir)/include/hyperion/mpl/algorithms/all_of.h", } +local hyperion_mpl_concepts_headers = { + "$(projectdir)/include/hyperion/mpl/concepts/comparable.h", + "$(projectdir)/include/hyperion/mpl/concepts/operator_able.h", + "$(projectdir)/include/hyperion/mpl/concepts/std_supplemental.h", +} +local hyperion_mpl_type_traits_headers = { + "$(projectdir)/include/hyperion/mpl/type_traits/is_comparable.h", + "$(projectdir)/include/hyperion/mpl/type_traits/is_operator_able.h", + "$(projectdir)/include/hyperion/mpl/type_traits/std_supplemental.h", +} target("hyperion_mpl", function() set_kind("headeronly") @@ -60,17 +69,19 @@ target("hyperion_mpl", function() add_includedirs("$(projectdir)/include", { public = true }) add_headerfiles(hyperion_mpl_headers, { prefixdir = "hyperion/mpl", public = true }) add_headerfiles(hyperion_mpl_algorithms_headers, { prefixdir = "hyperion/mpl/algorithms", public = true }) + add_headerfiles(hyperion_mpl_concepts_headers, { prefixdir = "hyperion/mpl/concepts", public = true }) + add_headerfiles(hyperion_mpl_type_traits_headers, { prefixdir = "hyperion/mpl/type_traits", public = true }) set_default(true) on_config(function(target) - import("hyperion_compiler_settings", {alias = "settings"}) + import("hyperion_compiler_settings", { alias = "settings" }) settings.set_compiler_settings(target) end) add_options("hyperion_enable_tracy") - add_packages("doctest", {public = true}) - add_packages("hyperion_platform", {public = true}) + add_packages("doctest", { public = true }) + add_packages("hyperion_platform", { public = true }) if has_package("tracy") then - add_packages("tracy", {public = true}) + add_packages("tracy", { public = true }) end end) @@ -81,7 +92,7 @@ target("hyperion_mpl_main", function() add_deps("hyperion_mpl") set_default(true) on_config(function(target) - import("hyperion_compiler_settings", {alias = "settings"}) + import("hyperion_compiler_settings", { alias = "settings" }) settings.set_compiler_settings(target) end) end)