1 // Copyright 2021 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <cstdint> 17 18 #include "pw_log_tokenized/config.h" 19 20 namespace pw { 21 namespace log_tokenized { 22 namespace internal { 23 24 // Internal class for managing the metadata bit fields. 25 template <typename T, unsigned kBits, unsigned kShift> 26 struct BitField { 27 public: GetBitField28 static constexpr T Get(T value) { return (value >> kShift) & kMask; } ShiftBitField29 static constexpr T Shift(T value) { 30 return (value <= kMask ? value : T(0)) << kShift; 31 } 32 33 private: 34 static constexpr T kMask = (T(1) << kBits) - 1; 35 }; 36 37 template <typename T, unsigned kShift> 38 class BitField<T, 0, kShift> { 39 public: Get(T)40 static constexpr T Get(T) { return 0; } Shift(T)41 static constexpr T Shift(T) { return 0; } 42 }; 43 44 } // namespace internal 45 46 // This class, which is aliased to pw::log_tokenized::Metadata below, is used to 47 // access the log metadata packed into the tokenizer's payload argument. 48 // 49 /// `GenericMetadata` facilitates the creation and interpretation of packed 50 /// log metadata payloads. The `GenericMetadata` class allows flags, log level, 51 /// line number, and a module identifier to be packed into bit fields of 52 /// configurable size. 53 /// 54 /// Typically, the `Metadata` alias should be used instead. 55 template <unsigned kLevelBits, 56 unsigned kLineBits, 57 unsigned kFlagBits, 58 unsigned kModuleBits, 59 typename T = uintptr_t> 60 class GenericMetadata { 61 public: 62 template <T log_level = 0, T module = 0, T flags = 0, T line = 0> Set()63 static constexpr GenericMetadata Set() { 64 static_assert(log_level < (1 << kLevelBits), "The level is too large!"); 65 static_assert(line < (1 << kLineBits), "The line number is too large!"); 66 static_assert(flags < (1 << kFlagBits), "The flags are too large!"); 67 static_assert(module < (1 << kModuleBits), "The module is too large!"); 68 69 return GenericMetadata(BitsFromMetadata(log_level, module, flags, line)); 70 } 71 72 /// Only use this constructor for creating metadata from runtime values. This 73 /// constructor is unable to warn at compilation when values will not fit in 74 /// the specified bit field widths. GenericMetadata(T log_level,T module,T flags,T line)75 constexpr GenericMetadata(T log_level, T module, T flags, T line) 76 : value_(BitsFromMetadata(log_level, module, flags, line)) {} 77 GenericMetadata(T value)78 constexpr GenericMetadata(T value) : value_(value) {} 79 80 /// The log level of this message. level()81 constexpr T level() const { return Level::Get(value_); } 82 83 /// The line number of the log call. The first line in a file is 1. If the 84 /// line number is 0, it was too large to be stored. line_number()85 constexpr T line_number() const { return Line::Get(value_); } 86 87 /// The flags provided to the log call. flags()88 constexpr T flags() const { return Flags::Get(value_); } 89 90 /// The 16-bit tokenized version of the module name 91 /// (@c_macro{PW_LOG_MODULE_NAME}). module()92 constexpr T module() const { return Module::Get(value_); } 93 94 /// The underlying packed metadata. value()95 constexpr T value() const { return value_; } 96 97 private: 98 using Level = internal::BitField<T, kLevelBits, 0>; 99 using Line = internal::BitField<T, kLineBits, kLevelBits>; 100 using Flags = internal::BitField<T, kFlagBits, kLevelBits + kLineBits>; 101 using Module = 102 internal::BitField<T, kModuleBits, kLevelBits + kLineBits + kFlagBits>; 103 BitsFromMetadata(T log_level,T module,T flags,T line)104 static constexpr T BitsFromMetadata(T log_level, T module, T flags, T line) { 105 return Level::Shift(log_level) | Module::Shift(module) | 106 Flags::Shift(flags) | Line::Shift(line); 107 } 108 109 T value_; 110 111 static_assert(kLevelBits + kLineBits + kFlagBits + kModuleBits <= 112 sizeof(value_) * 8); 113 }; 114 115 /// The `Metadata` alias simplifies the bit field width templatization of 116 /// `GenericMetadata` by pulling from this module's configuration options. In 117 /// most cases, it's recommended to use `Metadata` to create or read metadata 118 /// payloads. 119 /// 120 /// A `Metadata` object can be created from a `uint32_t`. 121 using Metadata = GenericMetadata<PW_LOG_TOKENIZED_LEVEL_BITS, 122 PW_LOG_TOKENIZED_LINE_BITS, 123 PW_LOG_TOKENIZED_FLAG_BITS, 124 PW_LOG_TOKENIZED_MODULE_BITS>; 125 126 } // namespace log_tokenized 127 } // namespace pw 128