Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines functions for manipulating Boolean flags in
22 : * a bitfield.
23 : *
24 : */
25 :
26 : #pragma once
27 :
28 : #include <stdint.h>
29 :
30 : #include <type_traits>
31 : #include <utility>
32 :
33 : namespace chip {
34 :
35 : /**
36 : * Stores bit flags in a type safe manner.
37 : *
38 : * @tparam FlagsEnum is an `enum` or (preferably) `enum class` type.
39 : * @tparam StorageType is the underlying storage type (like uint16_t, uint32_t etc.)
40 : * and defaults to the underlying storage type of `FlagsEnum`.
41 : */
42 : template <typename FlagsEnum, typename StorageType = typename std::underlying_type_t<FlagsEnum>>
43 : class BitFlags
44 : {
45 : public:
46 : static_assert(sizeof(StorageType) >= sizeof(FlagsEnum), "All flags should fit in the storage type");
47 : using IntegerType = StorageType;
48 :
49 148260 : constexpr BitFlags() : mValue(0) {}
50 : BitFlags(const BitFlags & other) = default;
51 : BitFlags & operator=(const BitFlags &) = default;
52 :
53 4697 : explicit constexpr BitFlags(FlagsEnum value) : mValue(static_cast<IntegerType>(value)) {}
54 2884 : explicit constexpr BitFlags(IntegerType value) : mValue(value) {}
55 :
56 : template <typename... Args>
57 18919 : constexpr BitFlags(FlagsEnum flag, Args &&... args) : mValue(Or(flag, std::forward<Args>(args)...))
58 18919 : {}
59 :
60 : template <typename... Args>
61 : constexpr BitFlags(const BitFlags<FlagsEnum> & flags, Args &&... args) : mValue(Or(flags, std::forward<Args>(args)...))
62 : {}
63 :
64 : template <typename... Args>
65 24 : constexpr BitFlags(IntegerType value, Args &&... args) : mValue(value | Or(std::forward<Args>(args)...))
66 24 : {}
67 :
68 : /**
69 : * Set flag(s).
70 : *
71 : * @param other Flag(s) to set. Any flags not set in @a other are unaffected.
72 : */
73 : BitFlags & Set(const BitFlags & other)
74 : {
75 : mValue |= other.mValue;
76 : return *this;
77 : }
78 :
79 : /**
80 : * Set flag(s).
81 : *
82 : * @param flag Typed flag(s) to set. Any flags not in @a v are unaffected.
83 : */
84 6730013 : constexpr BitFlags & Set(FlagsEnum flag)
85 : {
86 6730013 : mValue |= static_cast<IntegerType>(flag);
87 6730013 : return *this;
88 : }
89 :
90 : /**
91 : * Set or clear flag(s).
92 : *
93 : * @param flag Typed flag(s) to set or clear. Any flags not in @a flag are unaffected.
94 : * @param isSet If true, set the flag; if false, clear it.
95 : */
96 256287 : constexpr BitFlags & Set(FlagsEnum flag, bool isSet) { return isSet ? Set(flag) : Clear(flag); }
97 :
98 : /**
99 : * Clear flag(s).
100 : *
101 : * @param other Typed flag(s) to clear. Any flags not in @a other are unaffected.
102 : */
103 : BitFlags & Clear(const BitFlags & other)
104 : {
105 : mValue &= static_cast<IntegerType>(~static_cast<IntegerType>(other.mValue));
106 : return *this;
107 : }
108 :
109 : /**
110 : * Clear flag(s).
111 : *
112 : * @param flag Typed flag(s) to clear. Any flags not in @a flag are unaffected.
113 : */
114 179644 : constexpr BitFlags & Clear(FlagsEnum flag)
115 : {
116 179644 : mValue &= static_cast<IntegerType>(~static_cast<IntegerType>(flag));
117 179644 : return *this;
118 : }
119 :
120 : /**
121 : * Clear all flags.
122 : */
123 35182 : BitFlags & ClearAll()
124 : {
125 35182 : mValue = 0;
126 35182 : return *this;
127 : }
128 :
129 : /**
130 : * Check whether flag(s) are set.
131 : *
132 : * @param flag Flag(s) to test.
133 : * @returns True if any flag in @a flag is set, otherwise false.
134 : */
135 13931800 : constexpr bool Has(FlagsEnum flag) const { return (mValue & static_cast<IntegerType>(flag)) != 0; }
136 :
137 : /**
138 : * Check that no flags outside the arguments are set.
139 : *
140 : * @param args Flags to test. Arguments can be BitFlags<FlagsEnum>, BitFlags<FlagsEnum>, or FlagsEnum.
141 : * @returns True if no flag is set other than those passed.
142 : * False if any flag is set other than those passed.
143 : *
144 : * @note Flags passed need not be set; this test only requires that no *other* flags be set.
145 : */
146 : template <typename... Args>
147 2937 : bool HasOnly(Args &&... args) const
148 : {
149 2937 : return (mValue & Or(std::forward<Args>(args)...)) == mValue;
150 : }
151 :
152 : /**
153 : * Check that all given flags are set.
154 : *
155 : * @param args Flags to test. Arguments can be BitFlags<FlagsEnum>, BitFlags<FlagsEnum>, or FlagsEnum.
156 : * @returns True if all given flags are set.
157 : * False if any given flag is not set.
158 : */
159 : template <typename... Args>
160 30126 : bool HasAll(Args &&... args) const
161 : {
162 30126 : const IntegerType all = Or(std::forward<Args>(args)...);
163 30126 : return (mValue & all) == all;
164 : }
165 :
166 : /**
167 : * Check that at least one of the given flags is set.
168 : *
169 : * @param args Flags to test. Arguments can be BitFlags<FlagsEnum>, BitFlags<FlagsEnum>, or FlagsEnum.
170 : * @returns True if all given flags are set.
171 : * False if any given flag is not set.
172 : */
173 : template <typename... Args>
174 2926 : bool HasAny(Args &&... args) const
175 : {
176 2926 : return (mValue & Or(std::forward<Args>(args)...)) != 0;
177 : }
178 :
179 : /**
180 : * Check that at least one flag is set.
181 : *
182 : * @returns True if any flag is set, false otherwise.
183 : */
184 6603483 : bool HasAny() const { return mValue != 0; }
185 :
186 : /**
187 : * Find the logical intersection of flags.
188 : *
189 : * @param lhs Some flags.
190 : * @param rhs Some flags.
191 : * @returns Flags set in both @a lhs and @a rhs.
192 : *
193 : * @note: A multi-argument `BitFlags` constructor serves the function of `operator|`.
194 : */
195 5 : friend BitFlags<FlagsEnum> operator&(BitFlags<FlagsEnum> lhs, const BitFlags<FlagsEnum> & rhs)
196 : {
197 5 : return BitFlags<FlagsEnum>(lhs.mValue & rhs.mValue);
198 : }
199 :
200 : /**
201 : * Get the flags as the type FlagsEnum.
202 : *
203 : * @note This allows easily storing flags as a base FlagsEnum in a POD type,
204 : * and enables equality comparisons.
205 : */
206 103 : operator FlagsEnum() const { return static_cast<FlagsEnum>(mValue); }
207 :
208 : /**
209 : * Set and/or clear all flags with a value of the underlying storage type.
210 : *
211 : * @param value New storage value.
212 : */
213 90831 : BitFlags & SetRaw(IntegerType value)
214 : {
215 90831 : mValue = value;
216 90831 : return *this;
217 : }
218 :
219 : /**
220 : * Get the flags as the underlying integer type.
221 : *
222 : * @note This is intended to be used only to store flags into a raw binary record.
223 : */
224 99412 : constexpr IntegerType Raw() const { return mValue; }
225 :
226 : /**
227 : * Get the address of the flags as a pointer to the underlying integer type.
228 : *
229 : * @note This is intended to be used only to read flags from a raw binary record.
230 : */
231 17 : StorageType * RawStorage() { return &mValue; }
232 :
233 : private:
234 : // Find the union of BitFlags and/or FlagsEnum values.
235 : template <typename... Args>
236 55836 : static constexpr IntegerType Or(FlagsEnum flag, Args &&... args)
237 : {
238 55836 : return static_cast<IntegerType>(flag) | Or(std::forward<Args>(args)...);
239 : }
240 : template <typename... Args>
241 : static constexpr IntegerType Or(const BitFlags<FlagsEnum> & flags, Args &&... args)
242 : {
243 : return flags.mValue | Or(std::forward<Args>(args)...);
244 : }
245 53087 : static constexpr IntegerType Or(FlagsEnum value) { return static_cast<IntegerType>(value); }
246 1795 : static constexpr IntegerType Or(const BitFlags<FlagsEnum> & flags) { return flags.Raw(); }
247 :
248 : StorageType mValue = 0;
249 : };
250 :
251 : } // namespace chip
|