aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/enum_range.h
blob: a9f78a291e8e59e684c1ceab42cfc2a158813fb7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#pragma once

#include <type_traits>

// This tiny header is to define value ranges at compile time in enums and enum class/struct types.
//
// enum class E1 {
//     A,
//     B,
//     C,
// };
// Y_DEFINE_ENUM_MINMAX(E1, A, C);
//
//     or
//
// enum class E2 {
//     A,
//     B,
//     C,
// };
// Y_DEFINE_ENUM_MAX(E2, C);
//
//     Notes:
//         * use Y_DEFINE_ENUM_MINMAX / Y_DEFINE_ENUM_MINMAX if your enum is defined in a namespace
//         * use Y_DEFINE_ENUM_MINMAX_F / Y_DEFINE_ENUM_MINMAX_F if your enum is defined in a class/struct
//         * use shortened version Y_DEFINE_ENUM_MAX / Y_DEFINE_ENUM_MAX_F if enum begin is 0
//         * add Y_DEFINE_xxx macro immediately after enum definition
//
//     Usage examples:
//         TEnumRange<E>::Min               // min value of range in enum type
//         TEnumRange<E>::Max               // max value of range in enum type
//         TEnumRange<E>::UnderlyingMin     // min value of range in underlying type
//         TEnumRange<E>::UnderlyingMax     // max value of range in underlying type

void _YRegisterEnumRange(...);

namespace NDetail::NEnumRange {

    template <typename E, E _Min, E _Max>
    struct TEnumRange {
        static_assert(std::is_enum_v<E>, "");

        using TEnum = E;
        using TUnderlying = std::underlying_type_t<TEnum>;

        static constexpr TEnum Min = _Min;
        static constexpr TEnum Max = _Max;

        static constexpr TUnderlying UnderlyingMin = static_cast<TUnderlying>(Min);
        static constexpr TUnderlying UnderlyingMax = static_cast<TUnderlying>(Max);

        static_assert(UnderlyingMin <= UnderlyingMax, "Invalid enum range");
    };
}

#define Y_DEFINE_ENUM_MINMAX_IMPL(PREFIX, E, Min, Max) \
    PREFIX ::NDetail::NEnumRange::TEnumRange<E, Min, Max> _YRegisterEnumRange(const E*)

#define Y_DEFINE_ENUM_MINMAX(E, Min, Max) \
    Y_DEFINE_ENUM_MINMAX_IMPL([[maybe_unused]], E, E::Min, E::Max)

#define Y_DEFINE_ENUM_MAX(E, Max) \
    Y_DEFINE_ENUM_MINMAX_IMPL([[maybe_unused]], E, E{}, E::Max)

#define Y_DEFINE_ENUM_MINMAX_FRIEND(E, Min, Max) \
    Y_DEFINE_ENUM_MINMAX_IMPL(friend, E, E::Min, E::Max)

#define Y_DEFINE_ENUM_MAX_FRIEND(E, Max) \
    Y_DEFINE_ENUM_MINMAX_IMPL(friend, E, E{}, E::Max)

template <typename E>
using TEnumRange = decltype(_YRegisterEnumRange(static_cast<E*>(nullptr)));