forked from facebook/rocksdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdata_structure.h
186 lines (153 loc) · 5.34 KB
/
data_structure.h
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#pragma once
#include <assert.h>
#include <cstddef>
#include <cstdint>
#include <vector>
#include "rocksdb/rocksdb_namespace.h"
namespace ROCKSDB_NAMESPACE {
namespace detail {
int CountTrailingZeroBitsForSmallEnumSet(uint64_t);
} // namespace detail
// Represents a set of values of some enum type with a small number of
// possible enumerators. For now, it supports enums where no enumerator
// exceeds 63 when converted to int.
template <typename ENUM_TYPE, ENUM_TYPE MAX_ENUMERATOR>
class SmallEnumSet {
private:
using StateT = uint64_t;
static constexpr int kStateBits = sizeof(StateT) * 8;
static constexpr int kMaxMax = kStateBits - 1;
static constexpr int kMaxValue = static_cast<int>(MAX_ENUMERATOR);
static_assert(kMaxValue >= 0);
static_assert(kMaxValue <= kMaxMax);
public:
// construct / create
SmallEnumSet() : state_(0) {}
template <class... TRest>
/*implicit*/ constexpr SmallEnumSet(const ENUM_TYPE e, TRest... rest) {
*this = SmallEnumSet(rest...).With(e);
}
// Return the set that includes all valid values, assuming the enum
// is "dense" (includes all values converting to 0 through kMaxValue)
static constexpr SmallEnumSet All() {
StateT tmp = StateT{1} << kMaxValue;
return SmallEnumSet(RawStateMarker(), tmp | (tmp - 1));
}
// equality
bool operator==(const SmallEnumSet& that) const {
return this->state_ == that.state_;
}
bool operator!=(const SmallEnumSet& that) const { return !(*this == that); }
// query
// Return true if the input enum is contained in the "Set".
bool Contains(const ENUM_TYPE e) const {
int value = static_cast<int>(e);
assert(value >= 0 && value <= kMaxValue);
StateT tmp = 1;
return state_ & (tmp << value);
}
bool empty() const { return state_ == 0; }
// iterator
class const_iterator {
public:
// copy
const_iterator(const const_iterator& that) = default;
const_iterator& operator=(const const_iterator& that) = default;
// move
const_iterator(const_iterator&& that) noexcept = default;
const_iterator& operator=(const_iterator&& that) noexcept = default;
// equality
bool operator==(const const_iterator& that) const {
assert(set_ == that.set_);
return this->pos_ == that.pos_;
}
bool operator!=(const const_iterator& that) const {
return !(*this == that);
}
// ++iterator
const_iterator& operator++() {
if (pos_ < kMaxValue) {
pos_ = set_->SkipUnset(pos_ + 1);
} else {
pos_ = kStateBits;
}
return *this;
}
// iterator++
const_iterator operator++(int) {
auto old = *this;
++*this;
return old;
}
ENUM_TYPE operator*() const {
assert(pos_ <= kMaxValue);
return static_cast<ENUM_TYPE>(pos_);
}
private:
friend class SmallEnumSet;
const_iterator(const SmallEnumSet* set, int pos) : set_(set), pos_(pos) {}
const SmallEnumSet* set_;
int pos_;
};
const_iterator begin() const { return const_iterator(this, SkipUnset(0)); }
const_iterator end() const { return const_iterator(this, kStateBits); }
// mutable ops
// Modifies the set (if needed) to include the given value. Returns true
// iff the set was modified.
bool Add(const ENUM_TYPE e) {
int value = static_cast<int>(e);
assert(value >= 0 && value <= kMaxValue);
StateT old_state = state_;
state_ |= (StateT{1} << value);
return old_state != state_;
}
// Modifies the set (if needed) not to include the given value. Returns true
// iff the set was modified.
bool Remove(const ENUM_TYPE e) {
int value = static_cast<int>(e);
assert(value >= 0 && value <= kMaxValue);
StateT old_state = state_;
state_ &= ~(StateT{1} << value);
return old_state != state_;
}
// applicative ops
// Return a new set based on this one with the additional value(s) inserted
constexpr SmallEnumSet With(const ENUM_TYPE e) const {
int value = static_cast<int>(e);
assert(value >= 0 && value <= kMaxValue);
return SmallEnumSet(RawStateMarker(), state_ | (StateT{1} << value));
}
template <class... TRest>
constexpr SmallEnumSet With(const ENUM_TYPE e1, const ENUM_TYPE e2,
TRest... rest) const {
return With(e1).With(e2, rest...);
}
// Return a new set based on this one excluding the given value(s)
constexpr SmallEnumSet Without(const ENUM_TYPE e) const {
int value = static_cast<int>(e);
assert(value >= 0 && value <= kMaxValue);
return SmallEnumSet(RawStateMarker(), state_ & ~(StateT{1} << value));
}
template <class... TRest>
constexpr SmallEnumSet Without(const ENUM_TYPE e1, const ENUM_TYPE e2,
TRest... rest) const {
return Without(e1).Without(e2, rest...);
}
private:
int SkipUnset(int pos) const {
StateT tmp = state_ >> pos;
if (tmp == 0) {
return kStateBits;
} else {
return pos + detail::CountTrailingZeroBitsForSmallEnumSet(tmp);
}
}
struct RawStateMarker {};
explicit SmallEnumSet(RawStateMarker, StateT state) : state_(state) {}
StateT state_;
};
} // namespace ROCKSDB_NAMESPACE