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