1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef INCLUDE_PERFETTO_PROTOZERO_FIELD_H_ 18 #define INCLUDE_PERFETTO_PROTOZERO_FIELD_H_ 19 20 #include <stdint.h> 21 22 #include <string> 23 24 #include "perfetto/base/logging.h" 25 #include "perfetto/protozero/contiguous_memory_range.h" 26 #include "perfetto/protozero/proto_utils.h" 27 28 namespace protozero { 29 30 struct ConstBytes { 31 const uint8_t* data; 32 size_t size; 33 }; 34 35 struct ConstChars { 36 // Allow implicit conversion to perfetto's base::StringView without depending 37 // on perfetto/base or viceversa. 38 static constexpr bool kConvertibleToStringView = true; ToStdStringConstChars39 std::string ToStdString() const { return std::string(data, size); } 40 41 const char* data; 42 size_t size; 43 }; 44 45 // A protobuf field decoded by the protozero proto decoders. It exposes 46 // convenience accessors with minimal debug checks. 47 // This class is used both by the iterator-based ProtoDecoder and by the 48 // one-shot TypedProtoDecoder. 49 // If the field is not valid the accessors consistently return zero-integers or 50 // null strings. 51 class Field { 52 public: valid()53 inline bool valid() const { return id_ != 0; } id()54 inline uint16_t id() const { return id_; } 55 explicit inline operator bool() const { return valid(); } 56 type()57 inline proto_utils::ProtoWireType type() const { 58 auto res = static_cast<proto_utils::ProtoWireType>(type_); 59 PERFETTO_DCHECK(res == proto_utils::ProtoWireType::kVarInt || 60 res == proto_utils::ProtoWireType::kLengthDelimited || 61 res == proto_utils::ProtoWireType::kFixed32 || 62 res == proto_utils::ProtoWireType::kFixed64); 63 return res; 64 } 65 as_bool()66 inline bool as_bool() const { 67 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt); 68 return static_cast<bool>(int_value_); 69 } 70 as_uint32()71 inline uint32_t as_uint32() const { 72 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 73 type() == proto_utils::ProtoWireType::kFixed32); 74 return static_cast<uint32_t>(int_value_); 75 } 76 as_int32()77 inline int32_t as_int32() const { 78 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 79 type() == proto_utils::ProtoWireType::kFixed32); 80 return static_cast<int32_t>(int_value_); 81 } 82 as_uint64()83 inline uint64_t as_uint64() const { 84 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 85 type() == proto_utils::ProtoWireType::kFixed32 || 86 type() == proto_utils::ProtoWireType::kFixed64); 87 return int_value_; 88 } 89 as_int64()90 inline int64_t as_int64() const { 91 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 92 type() == proto_utils::ProtoWireType::kFixed32 || 93 type() == proto_utils::ProtoWireType::kFixed64); 94 return static_cast<int64_t>(int_value_); 95 } 96 as_float()97 inline float as_float() const { 98 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kFixed32); 99 float res; 100 uint32_t value32 = static_cast<uint32_t>(int_value_); 101 memcpy(&res, &value32, sizeof(res)); 102 return res; 103 } 104 as_double()105 inline double as_double() const { 106 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kFixed64); 107 double res; 108 memcpy(&res, &int_value_, sizeof(res)); 109 return res; 110 } 111 as_string()112 inline ConstChars as_string() const { 113 PERFETTO_DCHECK(!valid() || 114 type() == proto_utils::ProtoWireType::kLengthDelimited); 115 return ConstChars{reinterpret_cast<const char*>(data()), size_}; 116 } 117 as_std_string()118 inline std::string as_std_string() const { return as_string().ToStdString(); } 119 as_bytes()120 inline ConstBytes as_bytes() const { 121 PERFETTO_DCHECK(!valid() || 122 type() == proto_utils::ProtoWireType::kLengthDelimited); 123 return ConstBytes{data(), size_}; 124 } 125 data()126 inline const uint8_t* data() const { 127 PERFETTO_DCHECK(!valid() || 128 type() == proto_utils::ProtoWireType::kLengthDelimited); 129 return reinterpret_cast<const uint8_t*>(int_value_); 130 } 131 size()132 inline size_t size() const { 133 PERFETTO_DCHECK(!valid() || 134 type() == proto_utils::ProtoWireType::kLengthDelimited); 135 return size_; 136 } 137 raw_int_value()138 inline uint64_t raw_int_value() const { return int_value_; } 139 initialize(uint16_t id,uint8_t type,uint64_t int_value,uint32_t size)140 inline void initialize(uint16_t id, 141 uint8_t type, 142 uint64_t int_value, 143 uint32_t size) { 144 id_ = id; 145 type_ = type; 146 int_value_ = int_value; 147 size_ = size; 148 } 149 150 private: 151 // Fields are deliberately not initialized to keep the class trivially 152 // constructible. It makes a large perf difference for ProtoDecoder. 153 154 uint64_t int_value_; // In kLengthDelimited this contains the data() addr. 155 uint32_t size_; // Only valid when when type == kLengthDelimited. 156 uint16_t id_; // Proto field ordinal. 157 uint8_t type_; // proto_utils::ProtoWireType. 158 }; 159 160 // The Field struct is used in a lot of perf-sensitive contexts. 161 static_assert(sizeof(Field) == 16, "Field struct too big"); 162 163 } // namespace protozero 164 165 #endif // INCLUDE_PERFETTO_PROTOZERO_FIELD_H_ 166