Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / support / BitFlags.h
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     constexpr BitFlags() : mValue(0) {}
50     BitFlags(const BitFlags & other) = default;
51     BitFlags & operator=(const BitFlags &) = default;
52
53     explicit BitFlags(FlagsEnum value) : mValue(static_cast<IntegerType>(value)) {}
54     explicit BitFlags(IntegerType value) : mValue(value) {}
55
56     template <typename... Args>
57     BitFlags(FlagsEnum flag, Args &&... args) : mValue(Or(flag, std::forward<Args>(args)...))
58     {}
59
60     template <typename... Args>
61     BitFlags(const BitFlags<FlagsEnum> & flags, Args &&... args) : mValue(Or(flags, std::forward<Args>(args)...))
62     {}
63
64     template <typename... Args>
65     BitFlags(IntegerType value, Args &&... args) : mValue(value | Or(std::forward<Args>(args)...))
66     {}
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     constexpr BitFlags & Set(FlagsEnum flag)
85     {
86         mValue |= static_cast<IntegerType>(flag);
87         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     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 &= ~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     constexpr BitFlags & Clear(FlagsEnum flag)
115     {
116         mValue &= static_cast<IntegerType>(~static_cast<IntegerType>(flag));
117         return *this;
118     }
119
120     /**
121      * Clear all flags.
122      */
123     BitFlags & ClearAll()
124     {
125         mValue = 0;
126         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     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     bool HasOnly(Args &&... args) const
148     {
149         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     bool HasAll(Args &&... args) const
161     {
162         const IntegerType all = Or(std::forward<Args>(args)...);
163         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     bool HasAny(Args &&... args) const
175     {
176         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     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     friend BitFlags<FlagsEnum> operator&(BitFlags<FlagsEnum> lhs, const BitFlags<FlagsEnum> & rhs)
196     {
197         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     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     BitFlags & SetRaw(IntegerType value)
214     {
215         mValue = value;
216         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     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     StorageType * RawStorage() { return &mValue; }
232
233 private:
234     // Find the union of BitFlags and/or FlagsEnum values.
235     template <typename... Args>
236     static constexpr IntegerType Or(FlagsEnum flag, Args &&... args)
237     {
238         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     static constexpr IntegerType Or(FlagsEnum value) { return static_cast<IntegerType>(value); }
246     static constexpr IntegerType Or(const BitFlags<FlagsEnum> & flags) { return flags.Raw(); }
247
248     StorageType mValue = 0;
249 };
250
251 } // namespace chip