xref: /aosp_15_r20/external/perfetto/include/perfetto/protozero/field.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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