/*============================================================================= Copyright (c) 2011-2017 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_UTILITY_COMPARISON_HPP #define SPROUT_UTILITY_COMPARISON_HPP #include #include namespace sprout { // // comparison_forwarder // template class comparison_forwarder { public: typedef Compare compare_type; private: sprout::value_holder comp_; public: explicit SPROUT_CONSTEXPR comparison_forwarder(compare_type const& comp) : comp_(comp) {} SPROUT_CONSTEXPR compare_type const& comp() const { return comp_; } }; template<> class comparison_forwarder {}; // // operator->* // template inline SPROUT_CONSTEXPR sprout::comparison_forwarder operator->*(sprout::comparison_forwarder<>, Compare const& comp) { return sprout::comparison_forwarder(comp); } // // comp // namespace { SPROUT_STATIC_CONSTEXPR sprout::comparison_forwarder<> comp = {}; } // anonymous-namespace // // comparison_holder // template class comparison_holder { public: typedef T value_type; typedef Compare compare_type; private: sprout::value_holder value_; sprout::value_holder comp_; public: SPROUT_CONSTEXPR comparison_holder(value_type const& value, compare_type const& comp) : value_(value), comp_(comp) {} SPROUT_CONSTEXPR value_type const& get() const { return value_; } SPROUT_CONSTEXPR compare_type const& comp() const { return comp_; } }; template class comparison_holder { public: typedef T value_type; private: sprout::value_holder value_; public: explicit SPROUT_CONSTEXPR comparison_holder(value_type const& value) : value_(value) {} SPROUT_CONSTEXPR value_type const& get() const { return value_; } }; // // operator% // template inline SPROUT_CONSTEXPR sprout::comparison_holder operator%(sprout::comparison_forwarder const& lhs, T const& rhs) { return sprout::comparison_holder(rhs, lhs.comp()); } template inline SPROUT_CONSTEXPR sprout::comparison_holder operator%(sprout::comparison_forwarder<>, T const& rhs) { return sprout::comparison_holder(rhs); } // // comparison_base // template class comparison_base { public: typedef T value_type; typedef Compare compare_type; private: sprout::value_holder value_; sprout::value_holder comp_; bool cond_; public: SPROUT_CONSTEXPR comparison_base() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL comparison_base(comparison_base const&) = default; SPROUT_CONSTEXPR comparison_base(value_type const& value, compare_type const& comp) : value_(value), comp_(comp), cond_(true) {} SPROUT_CONSTEXPR value_type const& get() const { return value_; } SPROUT_CONSTEXPR compare_type const& comp() const { return comp_; } SPROUT_CONSTEXPR operator bool() const { return cond_; } SPROUT_CONSTEXPR bool operator!() const { return !cond_; } }; template class comparison_base { public: typedef T value_type; private: sprout::value_holder value_; bool cond_; public: SPROUT_CONSTEXPR comparison_base() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL comparison_base(comparison_base const&) = default; explicit SPROUT_CONSTEXPR comparison_base(value_type const& value) : value_(value), cond_(true) {} SPROUT_CONSTEXPR value_type const& get() const { return value_; } SPROUT_CONSTEXPR operator bool() const { return cond_; } SPROUT_CONSTEXPR bool operator!() const { return !cond_; } }; // // less_comparison // template class less_comparison : public sprout::comparison_base { public: typedef sprout::comparison_base base_type; typedef typename base_type::value_type value_type; typedef typename base_type::compare_type compare_type; public: SPROUT_CONSTEXPR less_comparison() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL less_comparison(less_comparison const&) = default; SPROUT_CONSTEXPR less_comparison(value_type const& value, compare_type const& comp) : base_type(value, comp) {} }; template class less_comparison : public sprout::comparison_base { public: typedef sprout::comparison_base base_type; typedef typename base_type::value_type value_type; public: SPROUT_CONSTEXPR less_comparison() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL less_comparison(less_comparison const&) = default; explicit SPROUT_CONSTEXPR less_comparison(value_type const& value) : base_type(value) {} }; // // operator< // operator<= // template inline SPROUT_CONSTEXPR sprout::less_comparison operator<(sprout::comparison_forwarder const& lhs, T const& rhs) { return sprout::less_comparison(rhs, lhs.comp()); } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<(sprout::comparison_forwarder<>, T const& rhs) { return sprout::less_comparison(rhs); } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<=(sprout::comparison_forwarder const& lhs, T const& rhs) { return sprout::less_comparison(rhs, lhs.comp()); } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<=(sprout::comparison_forwarder<>, T const& rhs) { return sprout::less_comparison(rhs); } // // operator< // template inline SPROUT_CONSTEXPR sprout::less_comparison operator<(sprout::comparison_holder const& lhs, U const& rhs) { return lhs.comp()(lhs.get(), rhs) ? sprout::less_comparison(rhs, lhs.comp()) : sprout::less_comparison() ; } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<(sprout::comparison_holder const& lhs, U const& rhs) { return lhs.get() < rhs ? sprout::less_comparison(rhs) : sprout::less_comparison() ; } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<(sprout::less_comparison const& lhs, U const& rhs) { return lhs.comp()(lhs.get(), rhs) ? sprout::less_comparison(rhs, lhs.comp()) : sprout::less_comparison() ; } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<(sprout::less_comparison const& lhs, U const& rhs) { return lhs && lhs.get() < rhs ? sprout::less_comparison(rhs) : sprout::less_comparison() ; } // // operator<= // template inline SPROUT_CONSTEXPR sprout::less_comparison operator<=(sprout::comparison_holder const& lhs, U const& rhs) { return !lhs.comp()(rhs, lhs.get()) ? sprout::less_comparison(rhs, lhs.comp()) : sprout::less_comparison() ; } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<=(sprout::comparison_holder const& lhs, U const& rhs) { return lhs.get() <= rhs ? sprout::less_comparison(rhs) : sprout::less_comparison() ; } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<=(sprout::less_comparison const& lhs, U const& rhs) { return !lhs.comp()(rhs, lhs.get()) ? sprout::less_comparison(rhs, lhs.comp()) : sprout::less_comparison() ; } template inline SPROUT_CONSTEXPR sprout::less_comparison operator<=(sprout::less_comparison const& lhs, U const& rhs) { return lhs && lhs.get() <= rhs ? sprout::less_comparison(rhs) : sprout::less_comparison() ; } // // operator> // operator>= // operator== // operator!= // template SPROUT_NON_CONSTEXPR void operator>(sprout::less_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator>=(sprout::less_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator==(sprout::less_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator!=(sprout::less_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL // // greater_comparison // template class greater_comparison : public sprout::comparison_base { public: typedef sprout::comparison_base base_type; typedef typename base_type::value_type value_type; typedef typename base_type::compare_type compare_type; public: SPROUT_CONSTEXPR greater_comparison() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL greater_comparison(greater_comparison const&) = default; SPROUT_CONSTEXPR greater_comparison(value_type const& value, compare_type const& comp) : base_type(value, comp) {} }; template class greater_comparison : public sprout::comparison_base { public: typedef sprout::comparison_base base_type; typedef typename base_type::value_type value_type; public: SPROUT_CONSTEXPR greater_comparison() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL greater_comparison(greater_comparison const&) = default; explicit SPROUT_CONSTEXPR greater_comparison(value_type const& value) : base_type(value) {} }; // // operator> // operator>= // template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>(sprout::comparison_forwarder const& lhs, T const& rhs) { return sprout::greater_comparison(rhs, lhs.comp()); } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>(sprout::comparison_forwarder<>, T const& rhs) { return sprout::greater_comparison(rhs); } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>=(sprout::comparison_forwarder const& lhs, T const& rhs) { return sprout::greater_comparison(rhs, lhs.comp()); } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>=(sprout::comparison_forwarder<>, T const& rhs) { return sprout::greater_comparison(rhs); } // // operator> // template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>(sprout::comparison_holder const& lhs, U const& rhs) { return lhs.comp()(rhs, lhs.get()) ? sprout::greater_comparison(rhs, lhs.comp()) : sprout::greater_comparison() ; } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>(sprout::comparison_holder const& lhs, U const& rhs) { return rhs < lhs.get() ? sprout::greater_comparison(rhs) : sprout::greater_comparison() ; } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>(sprout::greater_comparison const& lhs, U const& rhs) { return lhs.comp()(rhs, lhs.get()) ? sprout::greater_comparison(rhs, lhs.comp()) : sprout::greater_comparison() ; } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>(sprout::greater_comparison const& lhs, U const& rhs) { return lhs && rhs < lhs.get() ? sprout::greater_comparison(rhs) : sprout::greater_comparison() ; } // // operator>= // template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>=(sprout::comparison_holder const& lhs, U const& rhs) { return !lhs.comp()(lhs.get(), rhs) ? sprout::greater_comparison(rhs, lhs.comp()) : sprout::greater_comparison() ; } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>=(sprout::comparison_holder const& lhs, U const& rhs) { return !(lhs.get() < rhs) ? sprout::greater_comparison(rhs) : sprout::greater_comparison() ; } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>=(sprout::greater_comparison const& lhs, U const& rhs) { return !lhs.comp()(lhs.get(), rhs) ? sprout::greater_comparison(rhs, lhs.comp()) : sprout::greater_comparison() ; } template inline SPROUT_CONSTEXPR sprout::greater_comparison operator>=(sprout::greater_comparison const& lhs, U const& rhs) { return lhs && !(lhs.get() < rhs) ? sprout::greater_comparison(rhs) : sprout::greater_comparison() ; } // // operator< // operator<= // operator== // operator!= // template SPROUT_NON_CONSTEXPR void operator<(sprout::greater_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator<=(sprout::greater_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator==(sprout::greater_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator!=(sprout::greater_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL // // equal_comparison // template class equal_comparison : public sprout::comparison_base { public: typedef sprout::comparison_base base_type; typedef typename base_type::value_type value_type; typedef typename base_type::compare_type compare_type; public: SPROUT_CONSTEXPR equal_comparison() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL equal_comparison(equal_comparison const&) = default; SPROUT_CONSTEXPR equal_comparison(value_type const& value, compare_type const& comp) : base_type(value, comp) {} }; template class equal_comparison : public sprout::comparison_base { public: typedef sprout::comparison_base base_type; typedef typename base_type::value_type value_type; public: SPROUT_CONSTEXPR equal_comparison() SPROUT_DEFAULTED_DEFAULT_CONSTRUCTOR_DECL equal_comparison(equal_comparison const&) = default; explicit SPROUT_CONSTEXPR equal_comparison(value_type const& value) : base_type(value) {} }; // // operator== // template inline SPROUT_CONSTEXPR sprout::equal_comparison operator==(sprout::comparison_forwarder const& lhs, T const& rhs) { return sprout::equal_comparison(rhs, lhs.comp()); } template inline SPROUT_CONSTEXPR sprout::equal_comparison operator==(sprout::comparison_forwarder<>, T const& rhs) { return sprout::equal_comparison(rhs); } // // operator== // template inline SPROUT_CONSTEXPR sprout::equal_comparison operator==(sprout::comparison_holder const& lhs, U const& rhs) { return !lhs.comp()(lhs.get(), rhs) && !lhs.comp()(rhs, lhs.get()) ? sprout::equal_comparison(rhs, lhs.comp()) : sprout::equal_comparison() ; } template inline SPROUT_CONSTEXPR sprout::equal_comparison operator==(sprout::comparison_holder const& lhs, U const& rhs) { return !(lhs.get() < rhs) && !(rhs < lhs.get()) ? sprout::equal_comparison(rhs) : sprout::equal_comparison() ; } template inline SPROUT_CONSTEXPR sprout::equal_comparison operator==(sprout::equal_comparison const& lhs, U const& rhs) { return !lhs.comp()(lhs.get(), rhs) && !lhs.comp()(rhs, lhs.get()) ? sprout::equal_comparison(rhs, lhs.comp()) : sprout::equal_comparison() ; } template inline SPROUT_CONSTEXPR sprout::equal_comparison operator==(sprout::equal_comparison const& lhs, U const& rhs) { return lhs && !(lhs.get() < rhs) && !(rhs < lhs.get()) ? sprout::equal_comparison(rhs) : sprout::equal_comparison() ; } // // operator< // operator<= // operator> // operator>= // operator!= // template SPROUT_NON_CONSTEXPR void operator<(sprout::equal_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator<=(sprout::equal_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator>(sprout::equal_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator>=(sprout::equal_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL template SPROUT_NON_CONSTEXPR void operator!=(sprout::equal_comparison const&, U const&) SPROUT_DELETED_FUNCTION_DECL } // namespace sprout #endif // #ifndef SPROUT_UTILITY_COMPARISON_HPP