xref: /aosp_15_r20/external/pigweed/pw_log_tokenized/public/pw_log_tokenized/metadata.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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