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