/* * * Copyright (c) 2020-2021 Project CHIP Authors * Copyright (c) 2013-2017 Nest Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * This file defines functions for manipulating Boolean flags in * a bitfield. * */ #pragma once #include #include #include namespace chip { /** * Stores bit flags in a type safe manner. * * @tparam FlagsEnum is an `enum` or (preferably) `enum class` type. * @tparam StorageType is the underlying storage type (like uint16_t, uint32_t etc.) * and defaults to the underlying storage type of `FlagsEnum`. */ template > class BitFlags { public: static_assert(sizeof(StorageType) >= sizeof(FlagsEnum), "All flags should fit in the storage type"); using IntegerType = StorageType; constexpr BitFlags() : mValue(0) {} BitFlags(const BitFlags & other) = default; BitFlags & operator=(const BitFlags &) = default; explicit constexpr BitFlags(FlagsEnum value) : mValue(static_cast(value)) {} explicit constexpr BitFlags(IntegerType value) : mValue(value) {} template constexpr BitFlags(FlagsEnum flag, Args &&... args) : mValue(Or(flag, std::forward(args)...)) {} template constexpr BitFlags(const BitFlags & flags, Args &&... args) : mValue(Or(flags, std::forward(args)...)) {} template constexpr BitFlags(IntegerType value, Args &&... args) : mValue(value | Or(std::forward(args)...)) {} /** * Set flag(s). * * @param other Flag(s) to set. Any flags not set in @a other are unaffected. */ BitFlags & Set(const BitFlags & other) { mValue |= other.mValue; return *this; } /** * Set flag(s). * * @param flag Typed flag(s) to set. Any flags not in @a v are unaffected. */ constexpr BitFlags & Set(FlagsEnum flag) { mValue |= static_cast(flag); return *this; } /** * Set or clear flag(s). * * @param flag Typed flag(s) to set or clear. Any flags not in @a flag are unaffected. * @param isSet If true, set the flag; if false, clear it. */ constexpr BitFlags & Set(FlagsEnum flag, bool isSet) { return isSet ? Set(flag) : Clear(flag); } /** * Clear flag(s). * * @param other Typed flag(s) to clear. Any flags not in @a other are unaffected. */ BitFlags & Clear(const BitFlags & other) { mValue &= static_cast(~static_cast(other.mValue)); return *this; } /** * Clear flag(s). * * @param flag Typed flag(s) to clear. Any flags not in @a flag are unaffected. */ constexpr BitFlags & Clear(FlagsEnum flag) { mValue &= static_cast(~static_cast(flag)); return *this; } /** * Clear all flags. */ BitFlags & ClearAll() { mValue = 0; return *this; } /** * Check whether flag(s) are set. * * @param flag Flag(s) to test. * @returns True if any flag in @a flag is set, otherwise false. */ constexpr bool Has(FlagsEnum flag) const { return (mValue & static_cast(flag)) != 0; } /** * Check that no flags outside the arguments are set. * * @param args Flags to test. Arguments can be BitFlags, BitFlags, or FlagsEnum. * @returns True if no flag is set other than those passed. * False if any flag is set other than those passed. * * @note Flags passed need not be set; this test only requires that no *other* flags be set. */ template bool HasOnly(Args &&... args) const { return (mValue & Or(std::forward(args)...)) == mValue; } /** * Check that all given flags are set. * * @param args Flags to test. Arguments can be BitFlags, BitFlags, or FlagsEnum. * @returns True if all given flags are set. * False if any given flag is not set. */ template bool HasAll(Args &&... args) const { const IntegerType all = Or(std::forward(args)...); return (mValue & all) == all; } /** * Check that at least one of the given flags is set. * * @param args Flags to test. Arguments can be BitFlags, BitFlags, or FlagsEnum. * @returns True if all given flags are set. * False if any given flag is not set. */ template bool HasAny(Args &&... args) const { return (mValue & Or(std::forward(args)...)) != 0; } /** * Check that at least one flag is set. * * @returns True if any flag is set, false otherwise. */ bool HasAny() const { return mValue != 0; } /** * Find the logical intersection of flags. * * @param lhs Some flags. * @param rhs Some flags. * @returns Flags set in both @a lhs and @a rhs. * * @note: A multi-argument `BitFlags` constructor serves the function of `operator|`. */ friend BitFlags operator&(BitFlags lhs, const BitFlags & rhs) { return BitFlags(lhs.mValue & rhs.mValue); } /** * Get the flags as the type FlagsEnum. * * @note This allows easily storing flags as a base FlagsEnum in a POD type, * and enables equality comparisons. */ operator FlagsEnum() const { return static_cast(mValue); } /** * Set and/or clear all flags with a value of the underlying storage type. * * @param value New storage value. */ BitFlags & SetRaw(IntegerType value) { mValue = value; return *this; } /** * Get the flags as the underlying integer type. * * @note This is intended to be used only to store flags into a raw binary record. */ constexpr IntegerType Raw() const { return mValue; } /** * Get the address of the flags as a pointer to the underlying integer type. * * @note This is intended to be used only to read flags from a raw binary record. */ StorageType * RawStorage() { return &mValue; } private: // Find the union of BitFlags and/or FlagsEnum values. template static constexpr IntegerType Or(FlagsEnum flag, Args &&... args) { return static_cast(flag) | Or(std::forward(args)...); } template static constexpr IntegerType Or(const BitFlags & flags, Args &&... args) { return flags.mValue | Or(std::forward(args)...); } static constexpr IntegerType Or(FlagsEnum value) { return static_cast(value); } static constexpr IntegerType Or(const BitFlags & flags) { return flags.Raw(); } StorageType mValue = 0; }; } // namespace chip