People keep tripping over the old copyrights and copy-pasting them to new files. Search and replace "Cloudius Systems" with "ScyllaDB". Message-Id: <1460013664-25966-1-git-send-email-penberg@scylladb.com>
231 lines
5.9 KiB
C++
231 lines
5.9 KiB
C++
/*
|
|
* Copyright (C) 2015 ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* This file is part of Scylla.
|
|
*
|
|
* Scylla is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Scylla 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 Scylla. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <type_traits>
|
|
#include <limits>
|
|
|
|
/**
|
|
*
|
|
* Allows to take full advantage of compile-time information when operating
|
|
* on a set of enum values.
|
|
*
|
|
* Examples:
|
|
*
|
|
* enum class x { A, B, C };
|
|
* using my_enum = super_enum<x, x::A, x::B, x::C>;
|
|
* using my_enumset = enum_set<my_enum>;
|
|
*
|
|
* static_assert(my_enumset::frozen<x::A, x::B>::contains<x::A>(), "it should...");
|
|
*
|
|
* assert(my_enumset::frozen<x::A, x::B>::contains(my_enumset::prepare<x::A>()));
|
|
*
|
|
* assert(my_enumset::frozen<x::A, x::B>::contains(x::A));
|
|
*
|
|
*/
|
|
|
|
|
|
template<typename EnumType, EnumType... Items>
|
|
struct super_enum {
|
|
using enum_type = EnumType;
|
|
|
|
template<enum_type... values>
|
|
struct max {
|
|
static constexpr enum_type max_of(enum_type a, enum_type b) {
|
|
return a > b ? a : b;
|
|
}
|
|
|
|
template<enum_type first, enum_type second, enum_type... rest>
|
|
static constexpr enum_type get() {
|
|
return max_of(first, get<second, rest...>());
|
|
}
|
|
|
|
template<enum_type first>
|
|
static constexpr enum_type get() { return first; }
|
|
|
|
static constexpr enum_type value = get<values...>();
|
|
};
|
|
|
|
template<enum_type... values>
|
|
struct min {
|
|
static constexpr enum_type min_of(enum_type a, enum_type b) {
|
|
return a < b ? a : b;
|
|
}
|
|
|
|
template<enum_type first, enum_type second, enum_type... rest>
|
|
static constexpr enum_type get() {
|
|
return min_of(first, get<second, rest...>());
|
|
}
|
|
|
|
template<enum_type first>
|
|
static constexpr enum_type get() { return first; }
|
|
|
|
static constexpr enum_type value = get<values...>();
|
|
};
|
|
|
|
using sequence_type = typename std::underlying_type<enum_type>::type;
|
|
|
|
template<enum_type Elem>
|
|
static constexpr sequence_type sequence_for() {
|
|
return static_cast<sequence_type>(Elem);
|
|
}
|
|
|
|
static sequence_type sequence_for(enum_type elem) {
|
|
return static_cast<sequence_type>(elem);
|
|
}
|
|
|
|
static constexpr sequence_type max_sequence = sequence_for<max<Items...>::value>();
|
|
static constexpr sequence_type min_sequence = sequence_for<min<Items...>::value>();
|
|
|
|
static_assert(min_sequence >= 0, "negative enum values unsupported");
|
|
};
|
|
|
|
template<typename Enum>
|
|
class enum_set {
|
|
public:
|
|
using mask_type = size_t; // TODO: use the smallest sufficient type
|
|
using enum_type = typename Enum::enum_type;
|
|
private:
|
|
mask_type _mask;
|
|
constexpr enum_set(mask_type mask) : _mask(mask) {}
|
|
|
|
template<enum_type Elem>
|
|
static constexpr unsigned shift_for() {
|
|
return Enum::template sequence_for<Elem>();
|
|
}
|
|
public:
|
|
constexpr enum_set() : _mask(0) {}
|
|
|
|
static constexpr enum_set from_mask(mask_type mask) {
|
|
return enum_set(mask);
|
|
}
|
|
|
|
static inline mask_type mask_for(enum_type e) {
|
|
return mask_type(1) << Enum::sequence_for(e);
|
|
}
|
|
|
|
template<enum_type Elem>
|
|
static constexpr mask_type mask_for() {
|
|
return mask_type(1) << shift_for<Elem>();
|
|
}
|
|
|
|
struct prepared {
|
|
mask_type mask;
|
|
bool operator==(const prepared& o) const {
|
|
return mask == o.mask;
|
|
}
|
|
};
|
|
|
|
static prepared prepare(enum_type e) {
|
|
return {mask_for(e)};
|
|
}
|
|
|
|
template<enum_type e>
|
|
static constexpr prepared prepare() {
|
|
return {mask_for<e>()};
|
|
}
|
|
|
|
static_assert(std::numeric_limits<mask_type>::max() >= ((size_t)1 << Enum::max_sequence), "mask type too small");
|
|
|
|
template<enum_type e>
|
|
bool contains() const {
|
|
return bool(_mask & mask_for<e>());
|
|
}
|
|
|
|
bool contains(enum_type e) const {
|
|
return bool(_mask & mask_for(e));
|
|
}
|
|
|
|
template<enum_type e>
|
|
void remove() {
|
|
_mask &= ~mask_for<e>();
|
|
}
|
|
|
|
void remove(enum_type e) {
|
|
_mask &= ~mask_for(e);
|
|
}
|
|
|
|
template<enum_type e>
|
|
void set() {
|
|
_mask |= mask_for<e>();
|
|
}
|
|
|
|
template<enum_type e>
|
|
void set_if(bool condition) {
|
|
_mask |= mask_type(condition) << shift_for<e>();
|
|
}
|
|
|
|
void set(enum_type e) {
|
|
_mask |= mask_for(e);
|
|
}
|
|
|
|
explicit operator bool() const {
|
|
return bool(_mask);
|
|
}
|
|
|
|
mask_type mask() const {
|
|
return _mask;
|
|
}
|
|
|
|
template<enum_type... items>
|
|
struct frozen {
|
|
template<enum_type first>
|
|
static constexpr mask_type make_mask() {
|
|
return mask_for<first>();
|
|
}
|
|
|
|
static constexpr mask_type make_mask() {
|
|
return 0;
|
|
}
|
|
|
|
template<enum_type first, enum_type second, enum_type... rest>
|
|
static constexpr mask_type make_mask() {
|
|
return mask_for<first>() | make_mask<second, rest...>();
|
|
}
|
|
|
|
static constexpr mask_type mask = make_mask<items...>();
|
|
|
|
template<enum_type Elem>
|
|
static constexpr bool contains() {
|
|
return mask & mask_for<Elem>();
|
|
}
|
|
|
|
static bool contains(enum_type e) {
|
|
return mask & mask_for(e);
|
|
}
|
|
|
|
static bool contains(prepared e) {
|
|
return mask & e.mask;
|
|
}
|
|
|
|
static enum_set<Enum> unfreeze() {
|
|
return enum_set<Enum>(mask);
|
|
}
|
|
};
|
|
|
|
template<enum_type... items>
|
|
static enum_set<Enum> of() {
|
|
return frozen<items...>::unfreeze();
|
|
}
|
|
};
|