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 106563 : constexpr BitFlags() : mValue(0) {} 50 : BitFlags(const BitFlags & other) = default; 51 : BitFlags & operator=(const BitFlags &) = default; 52 : 53 4337 : explicit constexpr BitFlags(FlagsEnum value) : mValue(static_cast<IntegerType>(value)) {} 54 2652 : explicit constexpr BitFlags(IntegerType value) : mValue(value) {} 55 : 56 : template <typename... Args> 57 17994 : constexpr BitFlags(FlagsEnum flag, Args &&... args) : mValue(Or(flag, std::forward<Args>(args)...)) 58 17994 : {} 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 22 : constexpr BitFlags(IntegerType value, Args &&... args) : mValue(value | Or(std::forward<Args>(args)...)) 66 22 : {} 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 4207451 : constexpr BitFlags & Set(FlagsEnum flag) 85 : { 86 4207451 : mValue |= static_cast<IntegerType>(flag); 87 4207451 : 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 221279 : 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 155395 : constexpr BitFlags & Clear(FlagsEnum flag) 115 : { 116 155395 : mValue &= static_cast<IntegerType>(~static_cast<IntegerType>(flag)); 117 155395 : return *this; 118 : } 119 : 120 : /** 121 : * Clear all flags. 122 : */ 123 31467 : BitFlags & ClearAll() 124 : { 125 31467 : mValue = 0; 126 31467 : 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 8823867 : 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 2697 : bool HasOnly(Args &&... args) const 148 : { 149 2697 : 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 21224 : bool HasAll(Args &&... args) const 161 : { 162 21224 : const IntegerType all = Or(std::forward<Args>(args)...); 163 21224 : 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 2612 : bool HasAny(Args &&... args) const 175 : { 176 2612 : 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 4094355 : 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 4 : friend BitFlags<FlagsEnum> operator&(BitFlags<FlagsEnum> lhs, const BitFlags<FlagsEnum> & rhs) 196 : { 197 4 : 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 74 : 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 72822 : BitFlags & SetRaw(IntegerType value) 214 : { 215 72822 : mValue = value; 216 72822 : 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 96858 : 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 8 : StorageType * RawStorage() { return &mValue; } 232 : 233 : private: 234 : // Find the union of BitFlags and/or FlagsEnum values. 235 : template <typename... Args> 236 44766 : static constexpr IntegerType Or(FlagsEnum flag, Args &&... args) 237 : { 238 44766 : 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 42867 : static constexpr IntegerType Or(FlagsEnum value) { return static_cast<IntegerType>(value); } 246 1636 : static constexpr IntegerType Or(const BitFlags<FlagsEnum> & flags) { return flags.Raw(); } 247 : 248 : StorageType mValue = 0; 249 : }; 250 : 251 : } // namespace chip