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> 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> 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> 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