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