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