based

Opinionated utility library
git clone git://git.dimitrijedobrota.com/based.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit 5c23715f617524c3b0e7c9273fde573ebfc7582e
parent a58fad2587466536fbbb95a9b054c5f1d25f594c
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Mon, 5 May 2025 09:59:19 +0200

Enforce comaprison operation on enums

Diffstat:
M include/based/enum.hpp | +++++
M include/based/type_traits.hpp | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ---
M test/source/enum_test.cpp | +++++++++++++

3 files changed, 84 insertions(+), 3 deletions(-)


diff --git a/ include/based/enum.hpp b/ include/based/enum.hpp

@@ -104,6 +104,11 @@

\
static const type& get(Type idx); \
\
friend bool operator==(type lhs, type rhs) \
{ \
return lhs.value == rhs.value; \
} \
\
Type value; \
}; \
\

diff --git a/ include/based/type_traits.hpp b/ include/based/type_traits.hpp

@@ -37,6 +37,9 @@ template<class T, class U> struct is_same : false_type { };

template<class T> struct is_same<T, T> : true_type { };
template<class T, class U> constexpr bool is_same_v = is_same<T, U>::value;

template<typename T, typename U>
concept SameAs = is_same_v<T, U> && is_same_v<U, T>;

template<class T> struct remove_reference { using type = T; };
template<class T> struct remove_reference<T&> { using type = T; };
template<class T> struct remove_reference<T&&> { using type = T; };

@@ -76,6 +79,69 @@ struct is_instantiable<T, void_t<T<Ts...>>, Ts...> : true_type {};

template<template<class...> class T, class... Ts>
inline constexpr auto is_instantiable_v = is_instantiable<T, void, Ts...>::value;

template<typename T>
concept equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs == rhs} -> SameAs<bool>;
{rhs == lhs} -> SameAs<bool>;
};

template<typename T>
concept not_equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs != rhs} -> SameAs<bool>;
{rhs != lhs} -> SameAs<bool>;
};

template<typename T>
concept less_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs < rhs} -> SameAs<bool>;
{rhs < lhs} -> SameAs<bool>;
};

template<typename T>
concept greater_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs > rhs} -> SameAs<bool>;
{rhs > lhs} -> SameAs<bool>;
};

template<typename T>
concept less_equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs <= rhs} -> SameAs<bool>;
{rhs <= lhs} -> SameAs<bool>;
};

template<typename T>
concept greater_equal_comparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs >= rhs} -> SameAs<bool>;
{rhs >= lhs} -> SameAs<bool>;
};

template<typename T>
concept equality_comparable = requires {
requires(equal_comparable<T>);
requires(not_equal_comparable<T>);
};

template<typename T>
concept totally_ordered = requires {
requires(equality_comparable<T>);
requires(less_comparable<T>);
requires(greater_comparable<T>);
requires(less_equal_comparable<T>);
requires(greater_equal_comparable<T>);
};

// clang-format on

/* ----- Integer ----- */

@@ -109,9 +175,6 @@ template<typename T>

concept BareRegular = std::regular<bare_t<T>>;

template<typename T, typename U>
concept SameAs = is_same_v<T, U> && is_same_v<U, T>;

template<typename T, typename U>
concept BareSameAs = SameAs<bare_t<T>, bare_t<U>>;

/* ----- Iterator ----- */

diff --git a/ test/source/enum_test.cpp b/ test/source/enum_test.cpp

@@ -4,6 +4,8 @@


#include <catch2/catch_test_macros.hpp>

#include "based/type_traits.hpp"

struct test
{
BASED_ENUM_DECLARE(var, std::uint8_t, a, b, c)

@@ -55,3 +57,14 @@ TEST_CASE("names", "[enum/enum]")

REQUIRE(std::strcmp(test::var::type::names[test::var::b], "b") == 0);
REQUIRE(std::strcmp(test::var::type::names[test::var::c], "c") == 0);
}

TEST_CASE("operations", "[enum/enum]")
{
using based::SameAs;

STATIC_REQUIRE(based::equality_comparable<test::var::type>);
STATIC_REQUIRE(!based::less_comparable<test::var::type>);
STATIC_REQUIRE(!based::greater_comparable<test::var::type>);
STATIC_REQUIRE(!based::less_equal_comparable<test::var::type>);
STATIC_REQUIRE(!based::greater_equal_comparable<test::var::type>);
}