idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
flags.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
37#include <charconv>
38#include <concepts>
39#include <string>
40#include <type_traits>
41#include <utility>
42
43namespace idfxx {
44
55template<typename E>
56inline constexpr bool enable_flags_operators = false;
57
66template<typename E>
67concept flag_enum = std::is_enum_v<E> && enable_flags_operators<E>;
68
87template<flag_enum E>
88class flags {
89public:
91 using enum_type = E;
92
94 using underlying = std::underlying_type_t<E>;
95
97 underlying bits{};
98
99 constexpr explicit flags(underlying v) noexcept
100 : bits(v) {}
106 constexpr flags() noexcept = default;
107
116 constexpr flags(E e) noexcept
117 : bits(std::to_underlying(e)) {}
118
126 [[nodiscard]] constexpr flags operator|(flags other) const noexcept {
127 return flags{static_cast<underlying>(bits | other.bits)};
128 }
129
137 constexpr flags& operator|=(flags other) noexcept {
138 bits |= other.bits;
139 return *this;
140 }
141
149 [[nodiscard]] constexpr flags operator&(flags other) const noexcept {
150 return flags{static_cast<underlying>(bits & other.bits)};
151 }
152
160 constexpr flags& operator&=(flags other) noexcept {
161 bits &= other.bits;
162 return *this;
163 }
164
172 [[nodiscard]] constexpr flags operator^(flags other) const noexcept {
173 return flags{static_cast<underlying>(bits ^ other.bits)};
174 }
175
183 constexpr flags& operator^=(flags other) noexcept {
184 bits ^= other.bits;
185 return *this;
186 }
187
197 [[nodiscard]] constexpr flags operator-(flags other) const noexcept {
198 return flags{static_cast<underlying>(bits & ~other.bits)};
199 }
200
208 constexpr flags& operator-=(flags other) noexcept {
209 bits &= ~other.bits;
210 return *this;
211 }
212
221 [[nodiscard]] constexpr flags operator~() const noexcept { return flags{static_cast<underlying>(~bits)}; }
222
233 [[nodiscard]] constexpr bool contains(flags other) const noexcept {
234 return other.bits != 0 && (bits & other.bits) == other.bits;
235 }
236
246 [[nodiscard]] constexpr bool contains_any(flags other) const noexcept { return (bits & other.bits) != 0; }
247
253 [[nodiscard]] constexpr bool empty() const noexcept { return bits == 0; }
254
260 [[nodiscard]] constexpr explicit operator bool() const noexcept { return bits != 0; }
261
267 [[nodiscard]] constexpr bool operator==(flags const&) const noexcept = default;
268
276 [[nodiscard]] constexpr bool operator==(E e) const noexcept { return bits == std::to_underlying(e); }
277};
278
287template<flag_enum E>
289
299template<flag_enum E>
300[[nodiscard]] constexpr auto to_underlying(flags<E> f) noexcept {
301 return f.bits;
302}
303
311template<flag_enum E>
312[[nodiscard]] inline std::string to_string(flags<E> f) {
313 using underlying = typename flags<E>::underlying;
314 char buf[2 + sizeof(underlying) * 2];
315 buf[0] = '0';
316 buf[1] = 'x';
317 auto [ptr, ec] = std::to_chars(buf + 2, buf + sizeof(buf), to_underlying(f), 16);
318 return std::string(buf, ptr);
319}
320
321} // namespace idfxx
322
323// Free operators for flag enums, defined at global scope so that ADL finds them
324// regardless of which namespace the enum is declared in. They are constrained by
325// the flag_enum concept, so they only match opted-in enums.
326
338template<idfxx::flag_enum E>
339[[nodiscard]] constexpr idfxx::flags<E> operator|(E a, E b) noexcept {
340 return idfxx::flags<E>{a} | idfxx::flags<E>{b};
341}
342
351template<idfxx::flag_enum E>
352[[nodiscard]] constexpr idfxx::flags<E> operator&(E a, E b) noexcept {
353 return idfxx::flags<E>{a} & idfxx::flags<E>{b};
354}
355
364template<idfxx::flag_enum E>
365[[nodiscard]] constexpr idfxx::flags<E> operator^(E a, E b) noexcept {
366 return idfxx::flags<E>{a} ^ idfxx::flags<E>{b};
367}
368
376template<idfxx::flag_enum E>
377[[nodiscard]] constexpr idfxx::flags<E> operator~(E a) noexcept {
378 return ~idfxx::flags<E>{a};
379}
380
381#include "sdkconfig.h"
382#ifdef CONFIG_IDFXX_STD_FORMAT
384#include <algorithm>
385#include <format>
386namespace std {
387template<idfxx::flag_enum E>
388struct formatter<idfxx::flags<E>> {
389 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
390
391 template<typename FormatContext>
392 auto format(idfxx::flags<E> f, FormatContext& ctx) const {
393 auto s = to_string(f);
394 return std::copy(s.begin(), s.end(), ctx.out());
395 }
396};
397} // namespace std
399#endif // CONFIG_IDFXX_STD_FORMAT
400
// end of idfxx_core_flags // end of idfxx_core
Type-safe set of flags from a scoped enum.
Definition flags.hpp:88
constexpr flags operator|(flags other) const noexcept
Combines flags using bitwise OR.
Definition flags.hpp:126
constexpr bool operator==(flags const &) const noexcept=default
Equality comparison between flags objects.
std::underlying_type_t< E > underlying
The underlying integral type of the enum.
Definition flags.hpp:94
constexpr bool contains_any(flags other) const noexcept
Checks if any of the specified flags are set.
Definition flags.hpp:246
constexpr flags operator-(flags other) const noexcept
Clears specific flags (set difference).
Definition flags.hpp:197
constexpr bool contains(flags other) const noexcept
Checks if all specified flags are set.
Definition flags.hpp:233
constexpr flags() noexcept=default
Default constructor, initializes to empty flags (zero).
constexpr bool empty() const noexcept
Checks if no flags are set.
Definition flags.hpp:253
constexpr flags operator&(flags other) const noexcept
Intersects flags using bitwise AND.
Definition flags.hpp:149
constexpr bool operator==(E e) const noexcept
Equality comparison with an individual enum value.
Definition flags.hpp:276
constexpr flags operator^(flags other) const noexcept
Toggles flags using bitwise XOR.
Definition flags.hpp:172
constexpr flags & operator|=(flags other) noexcept
Combines flags in-place using bitwise OR.
Definition flags.hpp:137
constexpr flags & operator&=(flags other) noexcept
Intersects flags in-place using bitwise AND.
Definition flags.hpp:160
E enum_type
The scoped enum type.
Definition flags.hpp:91
constexpr flags operator~() const noexcept
Computes the bitwise complement.
Definition flags.hpp:221
constexpr flags & operator^=(flags other) noexcept
Toggles flags in-place using bitwise XOR.
Definition flags.hpp:183
constexpr flags & operator-=(flags other) noexcept
Clears specific flags in-place (set difference).
Definition flags.hpp:208
Concept for enums that have opted into flag operators.
Definition flags.hpp:67
constexpr idfxx::flags< E > operator|(E a, E b) noexcept
Combines two enum values into a flags object.
Definition flags.hpp:339
constexpr idfxx::flags< E > operator^(E a, E b) noexcept
Toggles two enum values into a flags object.
Definition flags.hpp:365
constexpr idfxx::flags< E > operator~(E a) noexcept
Computes the bitwise complement of an enum value.
Definition flags.hpp:377
constexpr idfxx::flags< E > operator&(E a, E b) noexcept
Intersects two enum values into a flags object.
Definition flags.hpp:352
std::string to_string(core_id c)
Returns a string representation of a CPU core identifier.
Definition cpu.hpp:52
Definition adc.hpp:48
constexpr bool enable_flags_operators
Opt-in trait for enabling flag operators on an enum.
Definition flags.hpp:56
flags(E) -> flags< E >
Class template argument deduction guide.
constexpr auto to_underlying(flags< E > f) noexcept
Returns the underlying integral value of a flags object.
Definition flags.hpp:300