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_H_ 18 #define SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_ 19 20 #include "src/trace_processor/db/column.h" 21 #include "src/trace_processor/db/typed_column_internal.h" 22 23 namespace perfetto { 24 namespace trace_processor { 25 26 // TypedColumn<T> 27 // 28 // Introduction: 29 // TypedColumn exists to allow efficient access to the data in a Column without 30 // having to go through dynamic type checking. There are two main reasons for 31 // this: 32 // 1. Performance: dynamic type checking is not free and so if this is used 33 // in a particularily hot codepath, the typechecking can be a significant 34 // overhead. 35 // 2. Ergonomics: having to convert back and forth from/to SqlValue causes 36 // signifcant clutter in parts of the code which can already be quite hard 37 // to follow (e.g. trackers like StackProfileTracker which perform cross 38 // checking of various ids). 39 // 40 // Implementation: 41 // TypedColumn is implemented as a memberless subclass of Column. This allows 42 // us to reinterpret case from a Column* to a TypedColumn<T> where we know the 43 // type T. The methods of TypedColumn are type-specialized methods of Column 44 // which allow callers to pass raw types instead of using SqlValue. 45 // 46 // There are two helper classes (tc_internal::TypeHandler and 47 // tc_internal::Serializer) where we specialize behaviour which needs to be 48 // different based on T. See their class documentation and below for details 49 // on their purpose. 50 template <typename T> 51 struct TypedColumn : public Column { 52 private: 53 using TH = tc_internal::TypeHandler<T>; 54 55 // The non-optional type of the data in this column. 56 using non_optional_type = 57 typename tc_internal::TypeHandler<T>::non_optional_type; 58 59 // The type of data in this column (including Optional wrapper if the type 60 // should be optional). 61 using get_type = typename tc_internal::TypeHandler<T>::get_type; 62 63 // The type which should be passed to SqlValue functions. 64 using sql_value_type = typename tc_internal::TypeHandler<T>::sql_value_type; 65 66 using Serializer = tc_internal::Serializer<non_optional_type>; 67 68 public: 69 // The type which should be stored in the SparseVector. 70 // Used by the macro code when actually constructing the SparseVectors. 71 using serialized_type = typename Serializer::serialized_type; 72 73 // Returns the data in the column at index |row|. 74 // Function chosen when TH::is_optional == true. 75 template <bool is_optional = TH::is_optional> 76 typename std::enable_if<is_optional, get_type>::type operator[]( 77 uint32_t row) const { 78 return Serializer::Deserialize(sparse_vector().Get(row_map().Get(row))); 79 } 80 81 // Function chosen when TH::is_optional == false. 82 template <bool is_optional = TH::is_optional> 83 typename std::enable_if<!is_optional, get_type>::type operator[]( 84 uint32_t row) const { 85 return Serializer::Deserialize( 86 sparse_vector().GetNonNull(row_map().Get(row))); 87 } 88 89 // Special function only for string types to allow retrieving the string 90 // directly from the column. 91 template <bool is_string = TH::is_string> GetStringTypedColumn92 typename std::enable_if<is_string, NullTermStringView>::type GetString( 93 uint32_t row) const { 94 return string_pool().Get((*this)[row]); 95 } 96 97 // Sets the data in the column at index |row|. SetTypedColumn98 void Set(uint32_t row, non_optional_type v) { 99 auto serialized = Serializer::Serialize(v); 100 mutable_sparse_vector()->Set(row_map().Get(row), serialized); 101 } 102 103 // Inserts the value at the end of the column. AppendTypedColumn104 void Append(T v) { 105 mutable_sparse_vector()->Append(Serializer::Serialize(v)); 106 } 107 108 // Returns the row containing the given value in the Column. IndexOfTypedColumn109 base::Optional<uint32_t> IndexOf(sql_value_type v) const { 110 return Column::IndexOf(ToValue(v)); 111 } 112 ToVectorForTestingTypedColumn113 std::vector<get_type> ToVectorForTesting() const { 114 std::vector<T> result(row_map().size()); 115 for (uint32_t i = 0; i < row_map().size(); ++i) 116 result[i] = (*this)[i]; 117 return result; 118 } 119 120 // Helper functions to create constraints for the given value. eqTypedColumn121 Constraint eq(sql_value_type v) const { return eq_value(ToValue(v)); } gtTypedColumn122 Constraint gt(sql_value_type v) const { return gt_value(ToValue(v)); } ltTypedColumn123 Constraint lt(sql_value_type v) const { return lt_value(ToValue(v)); } neTypedColumn124 Constraint ne(sql_value_type v) const { return ne_value(ToValue(v)); } geTypedColumn125 Constraint ge(sql_value_type v) const { return ge_value(ToValue(v)); } leTypedColumn126 Constraint le(sql_value_type v) const { return le_value(ToValue(v)); } 127 128 // Implements equality between two items of type |T|. EqualsTypedColumn129 static constexpr bool Equals(T a, T b) { return TH::Equals(a, b); } 130 131 // Encodes the default flags for a column of the current type. default_flagsTypedColumn132 static constexpr uint32_t default_flags() { 133 return TH::is_optional ? Flag::kNoFlag : Flag::kNonNull; 134 } 135 136 // Converts the static type T into the dynamic SqlValue type of this column. SqlValueTypeTypedColumn137 static SqlValue::Type SqlValueType() { 138 return Column::ToSqlValueType<serialized_type>(); 139 } 140 141 // Reinterpret cast a Column to TypedColumn or crash if that is likely to be 142 // unsafe. FromColumnTypedColumn143 static const TypedColumn<T>* FromColumn(const Column* column) { 144 if (column->IsColumnType<serialized_type>() && 145 (column->IsNullable() == TH::is_optional) && !column->IsId()) { 146 return reinterpret_cast<const TypedColumn<T>*>(column); 147 } else { 148 PERFETTO_FATAL("Unsafe to convert Column to TypedColumn."); 149 } 150 } 151 152 private: ToValueTypedColumn153 static SqlValue ToValue(double value) { return SqlValue::Double(value); } ToValueTypedColumn154 static SqlValue ToValue(uint32_t value) { return SqlValue::Long(value); } ToValueTypedColumn155 static SqlValue ToValue(int64_t value) { return SqlValue::Long(value); } ToValueTypedColumn156 static SqlValue ToValue(NullTermStringView value) { 157 return SqlValue::String(value.c_str()); 158 } 159 sparse_vectorTypedColumn160 const SparseVector<serialized_type>& sparse_vector() const { 161 return Column::sparse_vector<serialized_type>(); 162 } mutable_sparse_vectorTypedColumn163 SparseVector<serialized_type>* mutable_sparse_vector() { 164 return Column::mutable_sparse_vector<serialized_type>(); 165 } 166 }; 167 168 // Represents a column containing ids. 169 // TODO(lalitm): think about unifying this with TypedColumn in the 170 // future. 171 template <typename Id> 172 struct IdColumn : public Column { 173 Id operator[](uint32_t row) const { return Id(row_map().Get(row)); } IndexOfIdColumn174 base::Optional<uint32_t> IndexOf(Id id) const { 175 return row_map().IndexOf(id.value); 176 } 177 178 // Helper functions to create constraints for the given value. eqIdColumn179 Constraint eq(uint32_t v) const { return eq_value(SqlValue::Long(v)); } gtIdColumn180 Constraint gt(uint32_t v) const { return gt_value(SqlValue::Long(v)); } ltIdColumn181 Constraint lt(uint32_t v) const { return lt_value(SqlValue::Long(v)); } neIdColumn182 Constraint ne(uint32_t v) const { return ne_value(SqlValue::Long(v)); } geIdColumn183 Constraint ge(uint32_t v) const { return ge_value(SqlValue::Long(v)); } leIdColumn184 Constraint le(uint32_t v) const { return le_value(SqlValue::Long(v)); } 185 }; 186 187 } // namespace trace_processor 188 } // namespace perfetto 189 190 #endif // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_H_ 191