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