toctave

t(iny)octave
git clone https://0xff.ir/g/toctave.git
Log | Files | Refs | README

enum_ops.hpp (12841B)


      1 /*
      2     Copyright 2013 Adobe
      3     Distributed under the Boost Software License, Version 1.0.
      4     (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      5 */
      6 /**************************************************************************************************/
      7 
      8 #ifndef STLAB_ENUM_OPS_HPP
      9 #define STLAB_ENUM_OPS_HPP
     10 
     11 /**************************************************************************************************/
     12 
     13 #include <type_traits>
     14 
     15 /**************************************************************************************************/
     16 
     17 /*!
     18     \defgroup enum_ops Typesafe Integers and Bit Fields (enums)
     19     \ingroup utility
     20 
     21     \section Description Description
     22 
     23     \c enum_ops provides optional typesafe bitset and arithmetic operations for enumeration types.
     24     Without these typesafe operations, the compiler will promote the operand(s) to the appropriate
     25     integral type, and the result will be an integral type. When the typesafe operations have been
     26     defined for an enumeration type, \c E, the result will be of type \c E exactly when the
     27     operand(s) are of type \c E.
     28 
     29     \c auto stlab_enable_bitmask_enum(E) -> std::true_type;
     30     enables the bitset operations <code>~, |, &, ^, |=, &=, ^= </code>
     31     for enumeration type \c E.
     32 
     33     \c auto stlab_enable_arithmetic_enum(E) -> std::true_type;
     34     enables the typesafe arithmetic operations <code>+, -, *, /,
     35     %, +=, *=, -=, /=, \%=</code> for enumeration type \c E.
     36 
     37     \section Definition Definition
     38 
     39     Defined in \link enum_ops.hpp <code>stlab/enum_ops.hpp</code> \endlink
     40 
     41     \section Example Example
     42 
     43     The following is an example of code that will compile:
     44     \dontinclude enum_ops_example.cpp
     45     \skip start_of_example
     46     \until end_of_example
     47 
     48     The following is contains an example of code that will not compile
     49     since the typesafe operators have not been defined.
     50 
     51     \dontinclude enum_ops_example_fail.cpp
     52     \skip start_of_example
     53     \until end_of_example
     54 */
     55 
     56 /**************************************************************************************************/
     57 
     58 namespace stlab {
     59 
     60 /**************************************************************************************************/
     61 
     62 auto stlab_enable_bitmask_enum(...) -> std::false_type;
     63 auto stlab_enable_arithmetic_enum(...) -> std::false_type;
     64 
     65 /**************************************************************************************************/
     66 
     67 namespace implementation {
     68 
     69 /**************************************************************************************************/
     70 
     71 template <class T>
     72 using has_enabled_bitmask_t = decltype(stlab_enable_bitmask_enum(std::declval<T>()));
     73 
     74 template <class T>
     75 constexpr bool has_enabled_bitmask = has_enabled_bitmask_t<T>::value;
     76 
     77 template <class T>
     78 using has_enabled_arithmetic_t = decltype(stlab_enable_arithmetic_enum(std::declval<T>()));
     79 
     80 template <class T>
     81 constexpr bool has_enabled_arithmetic = has_enabled_arithmetic_t<T>::value;
     82 
     83 template <class T, class U>
     84 using enable_if_bitmask_or_arithmetic =
     85     std::enable_if_t<std::disjunction_v<stlab::implementation::has_enabled_bitmask_t<T>,
     86                                         stlab::implementation::has_enabled_arithmetic_t<T>>,
     87                      U>;
     88 
     89 template <class, bool>
     90 struct safe_underlying_type;
     91 
     92 template <class T>
     93 struct safe_underlying_type<T, true> {
     94     using type = std::underlying_type_t<T>;
     95 };
     96 
     97 template <class T>
     98 struct safe_underlying_type<T, false> {
     99     using type = void;
    100 };
    101 
    102 template <class T>
    103 using safe_underlying_type_t = typename safe_underlying_type<T, std::is_enum<T>::value>::type;
    104 
    105 template <class U, class T>
    106 using is_convertible_to_underlying =
    107     std::is_convertible<U, stlab::implementation::safe_underlying_type_t<T>>;
    108 
    109 /**************************************************************************************************/
    110 
    111 } // namespace implementation
    112 
    113 /**************************************************************************************************/
    114 
    115 } // namespace stlab
    116 
    117 /**************************************************************************************************/
    118 
    119 template <class T>
    120 constexpr auto operator&(T lhs, T rhs)
    121     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
    122     using underlying = std::underlying_type_t<T>;
    123     return static_cast<T>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
    124 }
    125 
    126 template <class T>
    127 constexpr auto operator~(T a)
    128     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
    129     using underlying = std::underlying_type_t<T>;
    130     return static_cast<T>(~static_cast<underlying>(a));
    131 }
    132 
    133 template <class T>
    134 constexpr auto operator|(T lhs, T rhs)
    135     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
    136     using underlying = std::underlying_type_t<T>;
    137     return static_cast<T>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
    138 }
    139 
    140 template <class T>
    141 constexpr auto operator^(T lhs, T rhs)
    142     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
    143     using underlying = std::underlying_type_t<T>;
    144     return static_cast<T>(static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
    145 }
    146 
    147 template <class T>
    148 constexpr auto operator<<(T lhs, std::size_t rhs)
    149     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
    150     using underlying = std::make_unsigned<std::underlying_type_t<T>>;
    151 
    152     return lhs = static_cast<underlying>(lhs) << static_cast<underlying>(rhs);
    153 }
    154 
    155 template <class T>
    156 constexpr auto operator>>(T lhs, std::size_t rhs)
    157     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
    158     using underlying = std::make_unsigned<std::underlying_type_t<T>>;
    159 
    160     return lhs = static_cast<underlying>(lhs) >> static_cast<underlying>(rhs);
    161 }
    162 
    163 template <class T>
    164 constexpr auto operator^=(T& lhs, T rhs)
    165     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
    166     return lhs = lhs ^ rhs;
    167 }
    168 
    169 template <class T>
    170 constexpr auto operator&=(T& lhs, T rhs)
    171     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
    172     return lhs = lhs & rhs;
    173 }
    174 
    175 template <class T>
    176 constexpr auto operator|=(T& lhs, T rhs)
    177     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
    178     return lhs = lhs | rhs;
    179 }
    180 
    181 template <class T>
    182 constexpr auto operator<<=(T& lhs, std::size_t rhs)
    183     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
    184     return lhs = lhs << rhs;
    185 }
    186 
    187 template <class T>
    188 constexpr auto operator>>=(T& lhs, std::size_t rhs)
    189     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
    190     return lhs = lhs >> rhs;
    191 }
    192 
    193 template <class T, class U>
    194 constexpr auto operator-(T lhs, U rhs)
    195     -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T> &&
    196                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    197                         T> {
    198     using underlying = std::underlying_type_t<T>;
    199     return static_cast<T>(static_cast<underlying>(lhs) - static_cast<underlying>(rhs));
    200 }
    201 
    202 /**************************************************************************************************/
    203 
    204 template <class T>
    205 constexpr auto operator+(T a)
    206     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
    207     using underlying = std::underlying_type_t<T>;
    208     return static_cast<T>(+static_cast<underlying>(a));
    209 }
    210 
    211 template <class T>
    212 constexpr auto operator-(T a)
    213     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
    214     using underlying = std::underlying_type_t<T>;
    215     return static_cast<T>(-static_cast<underlying>(a));
    216 }
    217 
    218 template <class T>
    219 constexpr auto operator+(T lhs, T rhs)
    220     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
    221     using underlying = std::underlying_type_t<T>;
    222     return static_cast<T>(static_cast<underlying>(lhs) + static_cast<underlying>(rhs));
    223 }
    224 
    225 template <class T>
    226 constexpr auto operator-(T lhs, T rhs)
    227     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
    228     using underlying = std::underlying_type_t<T>;
    229     return static_cast<T>(static_cast<underlying>(lhs) - static_cast<underlying>(rhs));
    230 }
    231 
    232 template <class T, class U>
    233 constexpr auto operator*(T lhs, U rhs)
    234     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
    235                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    236                         T> {
    237     using underlying = std::underlying_type_t<T>;
    238     return static_cast<T>(static_cast<underlying>(lhs) * rhs);
    239 }
    240 
    241 template <class U, class T>
    242 constexpr auto operator*(U lhs, T rhs)
    243     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
    244                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    245                         T> {
    246     using underlying = std::underlying_type_t<T>;
    247     return static_cast<T>(lhs * static_cast<underlying>(rhs));
    248 }
    249 
    250 template <class T, class U>
    251 constexpr auto operator/(T lhs, U rhs)
    252     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
    253                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    254                         T> {
    255     using underlying = std::underlying_type_t<T>;
    256     return static_cast<T>(static_cast<underlying>(lhs) / rhs);
    257 }
    258 
    259 template <class T, class U>
    260 constexpr auto operator%(T lhs, U rhs)
    261     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
    262                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    263                         T> {
    264     using underlying = std::underlying_type_t<T>;
    265     return static_cast<T>(static_cast<underlying>(lhs) % rhs);
    266 }
    267 
    268 template <class T>
    269 constexpr auto operator+=(T& lhs, T rhs)
    270     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
    271     return lhs = lhs + rhs;
    272 }
    273 
    274 template <class T>
    275 constexpr auto operator-=(T& lhs, T rhs)
    276     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
    277     return lhs = lhs - rhs;
    278 }
    279 
    280 template <class T, class U>
    281 constexpr auto operator*=(T& lhs, U rhs)
    282     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
    283                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    284                         T&> {
    285     return lhs = lhs * rhs;
    286 }
    287 
    288 template <class T, class U>
    289 constexpr auto operator/=(T& lhs, U rhs)
    290     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
    291                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    292                         T&> {
    293     return lhs = lhs / rhs;
    294 }
    295 
    296 template <class T, class U>
    297 constexpr auto operator%=(T& lhs, U rhs)
    298     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
    299                             stlab::implementation::is_convertible_to_underlying<U, T>::value,
    300                         T&> {
    301     return lhs = lhs % rhs;
    302 }
    303 
    304 template <class T>
    305 constexpr auto operator++(T& lhs)
    306     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
    307     return lhs += static_cast<T>(1);
    308 }
    309 
    310 template <class T>
    311 constexpr auto operator++(T& lhs, int)
    312     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
    313     T result = lhs;
    314     lhs += static_cast<T>(1);
    315     return result;
    316 }
    317 
    318 template <class T>
    319 constexpr auto operator--(T& lhs)
    320     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
    321     return lhs -= static_cast<T>(1);
    322 }
    323 
    324 template <class T>
    325 constexpr auto operator--(T& lhs, int)
    326     -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
    327     T result = lhs;
    328     lhs -= static_cast<T>(1);
    329     return result;
    330 }
    331 
    332 /**************************************************************************************************/
    333 
    334 template <class T>
    335 constexpr auto operator==(T lhs, std::nullptr_t)
    336     -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> {
    337     return !lhs;
    338 }
    339 
    340 template <class T>
    341 constexpr auto operator==(std::nullptr_t, T rhs)
    342     -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> {
    343     return !rhs;
    344 }
    345 
    346 template <class T>
    347 constexpr auto operator!=(T lhs, std::nullptr_t rhs)
    348     -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> {
    349     return !(lhs == rhs);
    350 }
    351 
    352 template <class T>
    353 constexpr auto operator!=(std::nullptr_t lhs, T rhs)
    354     -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> {
    355     return !(lhs == rhs);
    356 }
    357 
    358 template <class T>
    359 constexpr auto operator!(T lhs) -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> {
    360     return !static_cast<bool>(lhs);
    361 }
    362 
    363 /**************************************************************************************************/
    364 
    365 #endif
    366 
    367 /**************************************************************************************************/