1 /*
2  * Copyright (C) 2020 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 SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_INTERNAL_H_
18 #define SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_INTERNAL_H_
19 
20 #include "src/trace_processor/db/column.h"
21 
22 namespace perfetto {
23 namespace trace_processor {
24 namespace tc_internal {
25 
26 // Serializer converts between the "public" type used by the rest of trace
27 // processor and the type we store in the NullableVector.
28 template <typename T, typename Enabled = void>
29 struct Serializer {
30   using serialized_type = T;
31 
SerializeSerializer32   static serialized_type Serialize(T value) { return value; }
DeserializeSerializer33   static T Deserialize(serialized_type value) { return value; }
34 
SerializeSerializer35   static base::Optional<serialized_type> Serialize(base::Optional<T> value) {
36     return value;
37   }
DeserializeSerializer38   static base::Optional<T> Deserialize(base::Optional<serialized_type> value) {
39     return value;
40   }
41 };
42 
43 template <typename T>
44 using is_id = std::is_base_of<BaseId, T>;
45 
46 // Specialization of Serializer for id types.
47 template <typename T>
48 struct Serializer<T, typename std::enable_if<is_id<T>::value>::type> {
49   using serialized_type = uint32_t;
50 
51   static serialized_type Serialize(T value) { return value.value; }
52   static T Deserialize(serialized_type value) { return T{value}; }
53 
54   static base::Optional<serialized_type> Serialize(base::Optional<T> value) {
55     return value ? base::make_optional(Serialize(*value)) : base::nullopt;
56   }
57   static base::Optional<T> Deserialize(base::Optional<serialized_type> value) {
58     return value ? base::make_optional(Deserialize(*value)) : base::nullopt;
59   }
60 };
61 
62 // Specialization of Serializer for StringPool types.
63 template <>
64 struct Serializer<StringPool::Id> {
65   using serialized_type = StringPool::Id;
66 
67   static serialized_type Serialize(StringPool::Id value) { return value; }
68   static StringPool::Id Deserialize(serialized_type value) { return value; }
69 
70   static serialized_type Serialize(base::Optional<StringPool::Id> value) {
71     // Since StringPool::Id == 0 is always treated as null, rewrite
72     // base::nullopt -> 0 to remove an extra check at filter time for
73     // base::nullopt. Instead, that code can assume that the NullableVector
74     // layer always returns a valid id and can handle the nullability at the
75     // stringpool level.
76     // TODO(lalitm): remove this special casing if we migrate all tables over
77     // to macro tables and find that we can remove support for null stringids
78     // in the stringpool.
79     return value ? Serialize(*value) : StringPool::Id::Null();
80   }
81   static base::Optional<serialized_type> Deserialize(
82       base::Optional<StringPool::Id> value) {
83     return value;
84   }
85 };
86 
87 // TypeHandler (and it's specializations) allow for specialied handling of
88 // functions of a TypedColumn based on what is being stored inside.
89 // Default implementation of TypeHandler.
90 template <typename T, typename Enable = void>
91 struct TypeHandler {
92   using non_optional_type = T;
93   using get_type = T;
94   using sql_value_type =
95       typename Serializer<non_optional_type>::serialized_type;
96 
97   static constexpr bool is_optional = false;
98   static constexpr bool is_string = false;
99 
100   template <typename SerializedType>
101   static SerializedType Get(const NullableVector<SerializedType>& nv,
102                             uint32_t idx) {
103     return nv.GetNonNull(idx);
104   }
105 
106   static bool Equals(T a, T b) {
107     // We need to use equal_to here as it could be T == double and because we
108     // enable all compile time warnings, we will get complaints if we just use
109     // a == b.
110     return std::equal_to<T>()(a, b);
111   }
112 };
113 
114 // Specialization for Optional types.
115 template <typename T>
116 struct TypeHandler<base::Optional<T>> {
117   using non_optional_type = T;
118   using get_type = base::Optional<T>;
119   using sql_value_type =
120       typename Serializer<non_optional_type>::serialized_type;
121 
122   static constexpr bool is_optional = true;
123   static constexpr bool is_string = false;
124 
125   template <typename SerializedType>
126   static base::Optional<SerializedType> Get(
127       const NullableVector<SerializedType>& nv,
128       uint32_t idx) {
129     return nv.Get(idx);
130   }
131 
132   static bool Equals(base::Optional<T> a, base::Optional<T> b) {
133     // We need to use equal_to here as it could be T == double and because we
134     // enable all compile time warnings, we will get complaints if we just use
135     // a == b. This is the same reason why we can't also just use equal_to using
136     // a and b directly because the optional implementation of equality uses
137     // == which again causes complaints.
138     return a.has_value() == b.has_value() &&
139            (!a.has_value() || std::equal_to<T>()(*a, *b));
140   }
141 };
142 
143 // Specialization for Optional<StringId> types.
144 template <>
145 struct TypeHandler<StringPool::Id> {
146   // get_type removes the base::Optional since we convert base::nullopt ->
147   // StringPool::Id::Null (see Serializer<StringPool> above).
148   using non_optional_type = StringPool::Id;
149   using get_type = StringPool::Id;
150   using sql_value_type = NullTermStringView;
151 
152   static constexpr bool is_optional = false;
153   static constexpr bool is_string = true;
154 
155   static StringPool::Id Get(const NullableVector<StringPool::Id>& nv,
156                             uint32_t idx) {
157     return nv.GetNonNull(idx);
158   }
159 
160   static bool Equals(StringPool::Id a, StringPool::Id b) { return a == b; }
161 };
162 
163 // Specialization for Optional<StringId> types.
164 template <>
165 struct TypeHandler<base::Optional<StringPool::Id>> {
166   // get_type removes the base::Optional since we convert base::nullopt ->
167   // StringPool::Id::Null (see Serializer<StringPool> above).
168   using non_optional_type = StringPool::Id;
169   using get_type = base::Optional<StringPool::Id>;
170   using sql_value_type = NullTermStringView;
171 
172   // is_optional is false again because we always unwrap
173   // base::Optional<StringPool::Id> into StringPool::Id.
174   static constexpr bool is_optional = false;
175   static constexpr bool is_string = true;
176 
177   static base::Optional<StringPool::Id> Get(
178       const NullableVector<StringPool::Id>& nv,
179       uint32_t idx) {
180     StringPool::Id id = nv.GetNonNull(idx);
181     return id.is_null() ? base::nullopt : base::make_optional(id);
182   }
183 
184   static bool Equals(base::Optional<StringPool::Id> a,
185                      base::Optional<StringPool::Id> b) {
186     // To match our handling of treating base::nullopt ==
187     // StringPool::Id::Null(), ensure that they both compare equal to each
188     // other.
189     return a == b || (!a && b->is_null()) || (!b && a->is_null());
190   }
191 };
192 
193 }  // namespace tc_internal
194 }  // namespace trace_processor
195 }  // namespace perfetto
196 
197 #endif  // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_INTERNAL_H_
198