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 #include <string_view> 24 #include <vector> 25 26 #include "perfetto/base/logging.h" 27 #include "perfetto/protozero/contiguous_memory_range.h" 28 #include "perfetto/protozero/proto_utils.h" 29 30 namespace protozero { 31 32 struct ConstBytes { ToStdStringConstBytes33 std::string ToStdString() const { 34 return std::string(reinterpret_cast<const char*>(data), size); 35 } 36 37 const uint8_t* data; 38 size_t size; 39 }; 40 41 struct ConstChars { 42 // Allow implicit conversion to perfetto's base::StringView without depending 43 // on perfetto/base or viceversa. 44 static constexpr bool kConvertibleToStringView = true; 45 static constexpr bool kHashable = true; ToStdStringConstChars46 std::string ToStdString() const { return {data, size}; } ToStdStringViewConstChars47 std::string_view ToStdStringView() const { return {data, size}; } 48 49 const char* data; 50 size_t size; 51 }; 52 53 // A protobuf field decoded by the protozero proto decoders. It exposes 54 // convenience accessors with minimal debug checks. 55 // This class is used both by the iterator-based ProtoDecoder and by the 56 // one-shot TypedProtoDecoder. 57 // If the field is not valid the accessors consistently return zero-integers or 58 // null strings. 59 class Field { 60 public: valid()61 bool valid() const { return id_ != 0; } id()62 uint32_t id() const { return id_; } 63 explicit operator bool() const { return valid(); } 64 type()65 proto_utils::ProtoWireType type() const { 66 auto res = static_cast<proto_utils::ProtoWireType>(type_); 67 PERFETTO_DCHECK(res == proto_utils::ProtoWireType::kVarInt || 68 res == proto_utils::ProtoWireType::kLengthDelimited || 69 res == proto_utils::ProtoWireType::kFixed32 || 70 res == proto_utils::ProtoWireType::kFixed64); 71 return res; 72 } 73 as_bool()74 bool as_bool() const { 75 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt); 76 return static_cast<bool>(int_value_); 77 } 78 as_uint32()79 uint32_t as_uint32() const { 80 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 81 type() == proto_utils::ProtoWireType::kFixed32); 82 return static_cast<uint32_t>(int_value_); 83 } 84 as_int32()85 int32_t as_int32() const { 86 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 87 type() == proto_utils::ProtoWireType::kFixed32); 88 return static_cast<int32_t>(int_value_); 89 } 90 as_sint32()91 int32_t as_sint32() const { 92 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt); 93 return proto_utils::ZigZagDecode(static_cast<uint32_t>(int_value_)); 94 } 95 as_uint64()96 uint64_t as_uint64() const { 97 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 98 type() == proto_utils::ProtoWireType::kFixed32 || 99 type() == proto_utils::ProtoWireType::kFixed64); 100 return int_value_; 101 } 102 as_int64()103 int64_t as_int64() const { 104 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt || 105 type() == proto_utils::ProtoWireType::kFixed32 || 106 type() == proto_utils::ProtoWireType::kFixed64); 107 return static_cast<int64_t>(int_value_); 108 } 109 as_sint64()110 int64_t as_sint64() const { 111 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kVarInt); 112 return proto_utils::ZigZagDecode(static_cast<uint64_t>(int_value_)); 113 } 114 as_float()115 float as_float() const { 116 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kFixed32); 117 float res; 118 uint32_t value32 = static_cast<uint32_t>(int_value_); 119 memcpy(&res, &value32, sizeof(res)); 120 return res; 121 } 122 as_double()123 double as_double() const { 124 PERFETTO_DCHECK(!valid() || type() == proto_utils::ProtoWireType::kFixed64); 125 double res; 126 memcpy(&res, &int_value_, sizeof(res)); 127 return res; 128 } 129 as_string()130 ConstChars as_string() const { 131 PERFETTO_DCHECK(!valid() || 132 type() == proto_utils::ProtoWireType::kLengthDelimited); 133 return ConstChars{reinterpret_cast<const char*>(data()), size_}; 134 } 135 as_std_string()136 std::string as_std_string() const { return as_string().ToStdString(); } 137 as_bytes()138 ConstBytes as_bytes() const { 139 PERFETTO_DCHECK(!valid() || 140 type() == proto_utils::ProtoWireType::kLengthDelimited); 141 return ConstBytes{data(), size_}; 142 } 143 data()144 const uint8_t* data() const { 145 PERFETTO_DCHECK(!valid() || 146 type() == proto_utils::ProtoWireType::kLengthDelimited); 147 return reinterpret_cast<const uint8_t*>(int_value_); 148 } 149 size()150 size_t size() const { 151 PERFETTO_DCHECK(!valid() || 152 type() == proto_utils::ProtoWireType::kLengthDelimited); 153 return size_; 154 } 155 raw_int_value()156 uint64_t raw_int_value() const { return int_value_; } 157 initialize(uint32_t id,uint8_t type,uint64_t int_value,uint32_t size)158 void initialize(uint32_t id, 159 uint8_t type, 160 uint64_t int_value, 161 uint32_t size) { 162 id_ = id & kMaxId; 163 type_ = type; 164 int_value_ = int_value; 165 size_ = size; 166 } 167 168 // For use with templates. This is used by RepeatedFieldIterator::operator*(). get(bool * val)169 void get(bool* val) const { *val = as_bool(); } get(uint32_t * val)170 void get(uint32_t* val) const { *val = as_uint32(); } get(int32_t * val)171 void get(int32_t* val) const { *val = as_int32(); } get(uint64_t * val)172 void get(uint64_t* val) const { *val = as_uint64(); } get(int64_t * val)173 void get(int64_t* val) const { *val = as_int64(); } get(float * val)174 void get(float* val) const { *val = as_float(); } get(double * val)175 void get(double* val) const { *val = as_double(); } get(std::string * val)176 void get(std::string* val) const { *val = as_std_string(); } get(ConstChars * val)177 void get(ConstChars* val) const { *val = as_string(); } get(ConstBytes * val)178 void get(ConstBytes* val) const { *val = as_bytes(); } get_signed(int32_t * val)179 void get_signed(int32_t* val) const { *val = as_sint32(); } get_signed(int64_t * val)180 void get_signed(int64_t* val) const { *val = as_sint64(); } 181 182 // For enum types. 183 template <typename T, 184 typename = typename std::enable_if<std::is_enum<T>::value, T>::type> get(T * val)185 void get(T* val) const { 186 *val = static_cast<T>(as_int32()); 187 } 188 189 // Serializes the field back into a proto-encoded byte stream and appends it 190 // to |dst|. |dst| is resized accordingly. 191 void SerializeAndAppendTo(std::string* dst) const; 192 193 // Serializes the field back into a proto-encoded byte stream and appends it 194 // to |dst|. |dst| is resized accordingly. 195 void SerializeAndAppendTo(std::vector<uint8_t>* dst) const; 196 197 static constexpr uint32_t kMaxId = (1 << 24) - 1; // See id_ : 24 below. 198 private: 199 template <typename Container> 200 void SerializeAndAppendToInternal(Container* dst) const; 201 202 // Fields are deliberately not initialized to keep the class trivially 203 // constructible. It makes a large perf difference for ProtoDecoder. 204 uint64_t int_value_; // In kLengthDelimited this contains the data() addr. 205 uint32_t size_; // Only valid when when type == kLengthDelimited. 206 207 // Note: MSVC and clang-cl require bit-fields to be of the same type, hence 208 // the `: 8` below rather than uint8_t. 209 uint32_t id_ : 24; // Proto field ordinal. 210 uint32_t type_ : 8; // proto_utils::ProtoWireType. 211 }; 212 // The Field struct is used in a lot of perf-sensitive contexts. 213 static_assert(sizeof(Field) == 16, "Field struct too big"); 214 215 } // namespace protozero 216 217 #endif // INCLUDE_PERFETTO_PROTOZERO_FIELD_H_ 218