diff --git a/Kernel/include_std/compare b/Kernel/include_std/compare new file mode 100644 index 00000000..1941cbec --- /dev/null +++ b/Kernel/include_std/compare @@ -0,0 +1,295 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#pragma once + +#include +#include +#include + +namespace std +{ + namespace __cmp_dtl + { + using type = signed char; + + enum order : type + { + less = -1, + equivalent = 0, + greater = 1, + unordered = 2 + }; + + struct __unspecified + { + consteval __unspecified(__unspecified *) noexcept {} + }; + }; + + class partial_ordering + { + private: + __cmp_dtl::type value; + + constexpr explicit partial_ordering(__cmp_dtl::order v) noexcept : value(__cmp_dtl::type(v)) {} + + friend class weak_ordering; + friend class strong_ordering; + + public: + static const partial_ordering less; + static const partial_ordering equivalent; + static const partial_ordering greater; + static const partial_ordering unordered; + + friend constexpr bool operator==(partial_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value == 0; } + friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default; + + friend constexpr bool operator<(partial_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value == -1; } + friend constexpr bool operator<(__cmp_dtl::__unspecified u, partial_ordering v) noexcept { return v.value == 1; } + + friend constexpr bool operator<=(partial_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value <= 0; } + friend constexpr bool operator<=(__cmp_dtl::__unspecified u, partial_ordering v) noexcept { return __cmp_dtl::type(v.value & 1) == v.value; } + + friend constexpr bool operator>(partial_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value == 1; } + friend constexpr bool operator>(__cmp_dtl::__unspecified u, partial_ordering v) noexcept { return v.value == -1; } + + friend constexpr bool operator>=(partial_ordering v, __cmp_dtl::__unspecified u) noexcept { return __cmp_dtl::type(v.value & 1) == v.value; } + friend constexpr bool operator>=(__cmp_dtl::__unspecified u, partial_ordering v) noexcept { return 0 >= v.value; } + + friend constexpr partial_ordering operator<=>(partial_ordering v, __cmp_dtl::__unspecified u) noexcept { return v; } + friend constexpr partial_ordering operator<=>(__cmp_dtl::__unspecified u, partial_ordering v) noexcept + { + if (v.value & 1) + return partial_ordering(__cmp_dtl::order(-v.value)); + else + return v; + } + }; + + inline constexpr partial_ordering partial_ordering::less(__cmp_dtl::order::less); + inline constexpr partial_ordering partial_ordering::equivalent(__cmp_dtl::order::equivalent); + inline constexpr partial_ordering partial_ordering::greater(__cmp_dtl::order::greater); + inline constexpr partial_ordering partial_ordering::unordered(__cmp_dtl::order::unordered); + + class weak_ordering + { + private: + __cmp_dtl::type value; + + constexpr explicit weak_ordering(__cmp_dtl::order v) noexcept : value(__cmp_dtl::type(v)) {} + + friend class strong_ordering; + + public: + static const weak_ordering less; + static const weak_ordering equivalent; + static const weak_ordering greater; + + constexpr operator partial_ordering() const noexcept + { + return partial_ordering(__cmp_dtl::order(value)); + } + + friend constexpr bool operator==(weak_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value == 0; } + friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default; + + friend constexpr bool operator<(weak_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value < 0; } + friend constexpr bool operator<(__cmp_dtl::__unspecified u, weak_ordering v) noexcept { return 0 < v.value; } + + friend constexpr bool operator<=(weak_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value <= 0; } + friend constexpr bool operator<=(__cmp_dtl::__unspecified u, weak_ordering v) noexcept { return 0 <= v.value; } + + friend constexpr bool operator>(weak_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value > 0; } + friend constexpr bool operator>(__cmp_dtl::__unspecified u, weak_ordering v) noexcept { return 0 > v.value; } + + friend constexpr bool operator>=(weak_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value >= 0; } + friend constexpr bool operator>=(__cmp_dtl::__unspecified u, weak_ordering v) noexcept { return 0 >= v.value; } + + friend constexpr weak_ordering operator<=>(weak_ordering v, __cmp_dtl::__unspecified u) noexcept { return v; } + friend constexpr weak_ordering operator<=>(__cmp_dtl::__unspecified u, weak_ordering v) noexcept { return weak_ordering(__cmp_dtl::order(-v.value)); } + }; + + inline constexpr weak_ordering weak_ordering::less(__cmp_dtl::order::less); + inline constexpr weak_ordering weak_ordering::equivalent(__cmp_dtl::order::equivalent); + inline constexpr weak_ordering weak_ordering::greater(__cmp_dtl::order::greater); + + class strong_ordering + { + private: + __cmp_dtl::type value; + + constexpr explicit strong_ordering(__cmp_dtl::order v) noexcept : value(__cmp_dtl::type(v)) {} + + public: + static const strong_ordering less; + static const strong_ordering equivalent; + static const strong_ordering equal; + static const strong_ordering greater; + + constexpr operator partial_ordering() const noexcept + { + return partial_ordering(__cmp_dtl::order(value)); + } + + constexpr operator weak_ordering() const noexcept + { + return weak_ordering(__cmp_dtl::order(value)); + } + + friend constexpr bool operator==(strong_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value == 0; } + friend constexpr bool operator==(strong_ordering v, strong_ordering w) noexcept = default; + + friend constexpr bool operator<(strong_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value < 0; } + friend constexpr bool operator<(__cmp_dtl::__unspecified u, strong_ordering v) noexcept { return 0 < v.value; } + + friend constexpr bool operator<=(strong_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value <= 0; } + friend constexpr bool operator<=(__cmp_dtl::__unspecified u, strong_ordering v) noexcept { return 0 <= v.value; } + + friend constexpr bool operator>(strong_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value > 0; } + friend constexpr bool operator>(__cmp_dtl::__unspecified u, strong_ordering v) noexcept { return 0 > v.value; } + + friend constexpr bool operator>=(strong_ordering v, __cmp_dtl::__unspecified u) noexcept { return v.value >= 0; } + friend constexpr bool operator>=(__cmp_dtl::__unspecified u, strong_ordering v) noexcept { return 0 >= v.value; } + + friend constexpr strong_ordering operator<=>(strong_ordering v, __cmp_dtl::__unspecified u) noexcept { return v; } + friend constexpr strong_ordering operator<=>(__cmp_dtl::__unspecified u, strong_ordering v) noexcept { return strong_ordering(__cmp_dtl::order(-v.value)); } + }; + + inline constexpr strong_ordering strong_ordering::less(__cmp_dtl::order::less); + inline constexpr strong_ordering strong_ordering::equivalent(__cmp_dtl::order::equivalent); + inline constexpr strong_ordering strong_ordering::equal(__cmp_dtl::order::equivalent); + inline constexpr strong_ordering strong_ordering::greater(__cmp_dtl::order::greater); + + constexpr bool is_eq(partial_ordering cmp) noexcept { return cmp == 0; } + constexpr bool is_neq(partial_ordering cmp) noexcept { return cmp != 0; } + constexpr bool is_lt(partial_ordering cmp) noexcept { return cmp < 0; } + constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <= 0; } + constexpr bool is_gt(partial_ordering cmp) noexcept { return cmp > 0; } + constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >= 0; } + + namespace detail + { + template + struct common_cmpcat_base + { + using type = void; + }; + + template <> + struct common_cmpcat_base<0u> + { + using type = std::strong_ordering; + }; + + template <> + struct common_cmpcat_base<2u> + { + using type = std::partial_ordering; + }; + + template <> + struct common_cmpcat_base<4u> + { + using type = std::weak_ordering; + }; + + template <> + struct common_cmpcat_base<6u> + { + using type = std::partial_ordering; + }; + } + + template + struct common_comparison_category + : detail::common_cmpcat_base<(0u | ... | + (std::is_same_v ? 0u + : std::is_same_v ? 4u + : std::is_same_v ? 2u + : 1u))> + { + }; + + template + using common_comparison_category_t = common_comparison_category::type; + + template + using compare_three_way_result_t = decltype(std::declval &>() <=> std::declval &>()); + + template + struct compare_three_way_result + { + }; + + template + requires requires { typename compare_three_way_result_t; } + struct compare_three_way_result + { + using type = compare_three_way_result_t; + }; + + struct compare_three_way + { + template + constexpr auto operator()(T &&t, U &&u) const + { + return std::forward(t) <=> std::forward(u); + } + + using is_transparent = void; + }; + + inline constexpr struct strong_order_fn + { + } strong_order; + + inline constexpr struct weak_order_fn + { + } weak_order; + + inline constexpr struct partial_order_fn + { + } partial_order; + + inline constexpr struct compare_strong_order_fallback_fn + { + } compare_strong_order_fallback; + + inline constexpr struct compare_weak_order_fallback_fn + { + } compare_weak_order_fallback; + + inline constexpr struct compare_partial_order_fallback_fn + { + } compare_partial_order_fallback; + + inline constexpr struct __SynthThreeWayCompare + { + template + constexpr auto operator()(const T &lhs, const U &rhs) const + { + if (lhs < rhs) + return weak_ordering::less; + else if (rhs < lhs) + return weak_ordering::greater; + else + return weak_ordering::equivalent; + } + } __synth_three_way = {}; +} diff --git a/Kernel/tests/stl/compare.cpp b/Kernel/tests/stl/compare.cpp new file mode 100644 index 00000000..01989121 --- /dev/null +++ b/Kernel/tests/stl/compare.cpp @@ -0,0 +1,53 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +#ifdef DEBUG + +#include +#include +#include +#include + +void test_stl_compare() +{ + debug("std::compare ..."); + + assert(std::strong_ordering::equal == (5 <=> 5)); + assert(std::strong_ordering::less == (3 <=> 5)); + assert(std::strong_ordering::greater == (7 <=> 5)); + + assert(std::weak_ordering::equivalent == (5.0 <=> 5.0)); + assert(std::weak_ordering::less == (3.0 <=> 5.0)); + assert(std::weak_ordering::greater == (7.0 <=> 5.0)); + + assert(std::partial_ordering::equivalent == (5.0 <=> 5.0)); + assert(std::partial_ordering::less == (3.0 <=> 5.0)); + assert(std::partial_ordering::greater == (7.0 <=> 5.0)); + assert(std::partial_ordering::unordered == (std::numeric_limits::quiet_NaN() <=> 5.0)); + + assert(std::strong_ordering::equal == (std::string("abc") <=> std::string("abc"))); + assert(std::strong_ordering::less == (std::string("abc") <=> std::string("bcd"))); + assert(std::strong_ordering::greater == (std::string("bcd") <=> std::string("abc"))); + + assert(std::strong_ordering::equal == (std::vector{1, 2, 3} <=> std::vector{1, 2, 3})); + assert(std::strong_ordering::less == (std::vector{1, 2, 3} <=> std::vector{1, 2, 4})); + assert(std::strong_ordering::greater == (std::vector{1, 2, 4} <=> std::vector{1, 2, 3})); + + debug("std::compare OK"); +} + +#endif // DEBUG