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 // This class, which is aliased to pw::log_tokenized::Metadata below, is used to 45 // access the log metadata packed into the tokenizer's payload argument. 46 template <unsigned kLevelBits, 47 unsigned kLineBits, 48 unsigned kFlagBits, 49 unsigned kModuleBits, 50 typename T = uintptr_t> 51 class GenericMetadata { 52 public: 53 template <T log_level = 0, T module = 0, T flags = 0, T line = 0> Set()54 static constexpr GenericMetadata Set() { 55 static_assert(log_level < (1 << kLevelBits), "The level is too large!"); 56 static_assert(line < (1 << kLineBits), "The line number is too large!"); 57 static_assert(flags < (1 << kFlagBits), "The flags are too large!"); 58 static_assert(module < (1 << kModuleBits), "The module is too large!"); 59 60 return GenericMetadata(Level::Shift(log_level) | Module::Shift(module) | 61 Flags::Shift(flags) | Line::Shift(line)); 62 } 63 GenericMetadata(T value)64 constexpr GenericMetadata(T value) : bits_(value) {} 65 66 // The log level of this message. level()67 constexpr T level() const { return Level::Get(bits_); } 68 69 // The line number of the log call. The first line in a file is 1. If the line 70 // number is 0, it was too large to be stored. line_number()71 constexpr T line_number() const { return Line::Get(bits_); } 72 73 // The flags provided to the log call. flags()74 constexpr T flags() const { return Flags::Get(bits_); } 75 76 // The 16 bit tokenized version of the module name (PW_LOG_MODULE_NAME). module()77 constexpr T module() const { return Module::Get(bits_); } 78 79 private: 80 using Level = BitField<T, kLevelBits, 0>; 81 using Line = BitField<T, kLineBits, kLevelBits>; 82 using Flags = BitField<T, kFlagBits, kLevelBits + kLineBits>; 83 using Module = BitField<T, kModuleBits, kLevelBits + kLineBits + kFlagBits>; 84 85 T bits_; 86 87 static_assert(kLevelBits + kLineBits + kFlagBits + kModuleBits <= 88 sizeof(bits_) * 8); 89 }; 90 91 } // namespace internal 92 93 using Metadata = internal::GenericMetadata<PW_LOG_TOKENIZED_LEVEL_BITS, 94 PW_LOG_TOKENIZED_LINE_BITS, 95 PW_LOG_TOKENIZED_FLAG_BITS, 96 PW_LOG_TOKENIZED_MODULE_BITS>; 97 98 } // namespace log_tokenized 99 } // namespace pw 100