1 #pragma once
2
3 #include <bit>
4 #include <cstdint>
5 #include <type_traits>
6
7 namespace lg2
8 {
9 namespace details
10 {
11
12 /** Type to hold a set of logging flags. */
13 template <typename... Fs>
14 struct log_flag
15 {
16 /** Combined bit-set value of the held flags. */
17 static constexpr auto value = (0 | ... | Fs::value);
18 };
19
20 /** Constant for the "zero" flag. */
21 static constexpr auto log_flag_seq_start =
22 std::integral_constant<uint64_t, 0>{};
23
24 /** Concept to determine if a type is one of the defined flag types. */
25 template <typename T>
26 concept log_flags = requires { T::i_am_a_lg2_flag_type; };
27
28 /** Operator to combine log_flag sets together. */
29 template <log_flags... As, log_flags... Bs>
operator |(const log_flag<As...>,const log_flag<Bs...>)30 constexpr auto operator|(const log_flag<As...>, const log_flag<Bs...>)
31 {
32 return details::log_flag<As..., Bs...>{};
33 }
34
35 /** Static check to determine if a prohibited flag is found in a flag set. */
36 template <log_flags... Fs, log_flags F>
prohibit(log_flag<Fs...>,log_flag<F>)37 constexpr void prohibit(log_flag<Fs...>, log_flag<F>)
38 {
39 static_assert(!(... || std::is_same_v<Fs, F>),
40 "Prohibited flag found for value type.");
41 }
42
43 /** Static check to determine if any conflicting flags are found in a flag set.
44 */
45 template <log_flags... As, log_flags... Bs>
one_from_set(log_flag<As...> a,log_flag<Bs...> b)46 constexpr void one_from_set(log_flag<As...> a, log_flag<Bs...> b)
47 {
48 static_assert(std::popcount(a.value & b.value) < 2,
49 "Conflicting flags found for value type.");
50 }
51
52 } // namespace details
53
54 // Macro used to define all of the logging flags as a sequence of bitfields.
55 // - Creates a struct-type where the `value` is 1 bit higher than the previous
56 // so that it can be combined together with other flags using `log_flag`.
57 // - Creates a static instance of the flag in the `lg2` namespace.
58 #define PHOSPHOR_LOG2_DECLARE_FLAG(flagname, prev) \
59 namespace details \
60 { \
61 struct flag_##flagname \
62 { \
63 static constexpr uint64_t value = \
64 prev.value == log_flag_seq_start.value ? 1 : (prev.value << 1); \
65 \
66 static constexpr bool i_am_a_lg2_flag_type = true; \
67 }; \
68 } \
69 static constexpr auto flagname = \
70 details::log_flag<details::flag_##flagname>()
71
72 // Set of supported logging flags.
73 // Please keep these sorted!
74 PHOSPHOR_LOG2_DECLARE_FLAG(bin, log_flag_seq_start);
75 PHOSPHOR_LOG2_DECLARE_FLAG(dec, bin);
76 PHOSPHOR_LOG2_DECLARE_FLAG(field8, dec);
77 PHOSPHOR_LOG2_DECLARE_FLAG(field16, field8);
78 PHOSPHOR_LOG2_DECLARE_FLAG(field32, field16);
79 PHOSPHOR_LOG2_DECLARE_FLAG(field64, field32);
80 PHOSPHOR_LOG2_DECLARE_FLAG(floating, field64);
81 PHOSPHOR_LOG2_DECLARE_FLAG(hex, floating);
82 PHOSPHOR_LOG2_DECLARE_FLAG(signed_val, hex);
83 PHOSPHOR_LOG2_DECLARE_FLAG(str, signed_val);
84 PHOSPHOR_LOG2_DECLARE_FLAG(unsigned_val, str);
85
86 #undef PHOSPHOR_LOG2_DECLARE_FLAG
87
88 /** Handy scope-level `using` to get the format flags. */
89 #define PHOSPHOR_LOG2_USING_FLAGS \
90 using lg2::bin; \
91 using lg2::dec; \
92 using lg2::field8; \
93 using lg2::field16; \
94 using lg2::field32; \
95 using lg2::field64; \
96 using lg2::floating; \
97 using lg2::hex; \
98 using lg2::signed_val; \
99 using lg2::str; \
100 using lg2::unsigned_val
101
102 } // namespace lg2
103