|  | /* | 
|  | * Copyright (C) 2019 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef SRC_TRACE_PROCESSOR_DB_TABLE_H_ | 
|  | #define SRC_TRACE_PROCESSOR_DB_TABLE_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <limits> | 
|  | #include <numeric> | 
|  | #include <vector> | 
|  |  | 
|  | #include "perfetto/base/logging.h" | 
|  | #include "perfetto/ext/base/optional.h" | 
|  | #include "src/trace_processor/containers/string_pool.h" | 
|  | #include "src/trace_processor/db/column.h" | 
|  | #include "src/trace_processor/db/typed_column.h" | 
|  |  | 
|  | namespace perfetto { | 
|  | namespace trace_processor { | 
|  |  | 
|  | // Represents a table of data with named, strongly typed columns. | 
|  | class Table { | 
|  | public: | 
|  | // Iterator over the rows of the table. | 
|  | class Iterator { | 
|  | public: | 
|  | Iterator(const Table* table) : table_(table) { | 
|  | for (const auto& rm : table->row_maps()) { | 
|  | its_.emplace_back(rm.IterateRows()); | 
|  | } | 
|  | } | 
|  |  | 
|  | Iterator(Iterator&&) noexcept = default; | 
|  | Iterator& operator=(Iterator&&) = default; | 
|  |  | 
|  | // Advances the iterator to the next row of the table. | 
|  | void Next() { | 
|  | for (auto& it : its_) { | 
|  | it.Next(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Returns whether the row the iterator is pointing at is valid. | 
|  | operator bool() const { return its_[0]; } | 
|  |  | 
|  | // Returns the value at the current row for column |col_idx|. | 
|  | SqlValue Get(uint32_t col_idx) const { | 
|  | const auto& col = table_->columns_[col_idx]; | 
|  | return col.GetAtIdx(its_[col.row_map_idx_].row()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Iterator(const Iterator&) = delete; | 
|  | Iterator& operator=(const Iterator&) = delete; | 
|  |  | 
|  | const Table* table_ = nullptr; | 
|  | std::vector<RowMap::Iterator> its_; | 
|  | }; | 
|  |  | 
|  | // Helper class storing the schema of the table. This allows decisions to be | 
|  | // made about operations on the table without materializing the table - this | 
|  | // may be expensive for dynamically computed tables. | 
|  | // | 
|  | // Subclasses of Table usually provide a method (named Schema()) to statically | 
|  | // generate an instance of this class. | 
|  | struct Schema { | 
|  | struct Column { | 
|  | std::string name; | 
|  | SqlValue::Type type; | 
|  | bool is_id; | 
|  | bool is_sorted; | 
|  | bool is_hidden; | 
|  | }; | 
|  | std::vector<Column> columns; | 
|  | }; | 
|  |  | 
|  | Table(); | 
|  | virtual ~Table(); | 
|  |  | 
|  | // We explicitly define the move constructor here because we need to update | 
|  | // the Table pointer in each column in the table. | 
|  | Table(Table&& other) noexcept { *this = std::move(other); } | 
|  | Table& operator=(Table&& other) noexcept; | 
|  |  | 
|  | // Filters the Table using the specified filter constraints. | 
|  | Table Filter( | 
|  | const std::vector<Constraint>& cs, | 
|  | RowMap::OptimizeFor optimize_for = RowMap::OptimizeFor::kMemory) const { | 
|  | return Apply(FilterToRowMap(cs, optimize_for)); | 
|  | } | 
|  |  | 
|  | // Filters the Table using the specified filter constraints optionally | 
|  | // specifying what the returned RowMap should optimize for. | 
|  | // Returns a RowMap which, if applied to the table, would contain the rows | 
|  | // post filter. | 
|  | RowMap FilterToRowMap( | 
|  | const std::vector<Constraint>& cs, | 
|  | RowMap::OptimizeFor optimize_for = RowMap::OptimizeFor::kMemory) const { | 
|  | RowMap rm(0, row_count_, optimize_for); | 
|  | for (const Constraint& c : cs) { | 
|  | columns_[c.col_idx].FilterInto(c.op, c.value, &rm); | 
|  | } | 
|  | return rm; | 
|  | } | 
|  |  | 
|  | // Applies the given RowMap to the current table by picking out the rows | 
|  | // specified in the RowMap to be present in the output table. | 
|  | // Note: the RowMap should not reorder this table; this is guaranteed if the | 
|  | // passed RowMap is generated using |FilterToRowMap|. | 
|  | Table Apply(RowMap rm) const { | 
|  | Table table = CopyExceptRowMaps(); | 
|  | table.row_count_ = rm.size(); | 
|  | for (const RowMap& map : row_maps_) { | 
|  | table.row_maps_.emplace_back(map.SelectRows(rm)); | 
|  | PERFETTO_DCHECK(table.row_maps_.back().size() == table.row_count()); | 
|  | } | 
|  | return table; | 
|  | } | 
|  |  | 
|  | // Sorts the Table using the specified order by constraints. | 
|  | Table Sort(const std::vector<Order>& od) const; | 
|  |  | 
|  | // Joins |this| table with the |other| table using the values of column |left| | 
|  | // of |this| table to lookup the row in |right| column of the |other| table. | 
|  | // | 
|  | // Concretely, for each row in the returned table we lookup the value of | 
|  | // |left| in |right|. The found row is used as the values for |other|'s | 
|  | // columns in the returned table. | 
|  | // | 
|  | // This means we obtain the following invariants: | 
|  | //  1. this->size() == ret->size() | 
|  | //  2. this->Rows()[i].Get(j) == ret->Rows()[i].Get(j) | 
|  | // | 
|  | // It also means there are few restrictions on the data in |left| and |right|: | 
|  | //  * |left| is not allowed to have any nulls. | 
|  | //  * |left|'s values must exist in |right| | 
|  | Table LookupJoin(JoinKey left, const Table& other, JoinKey right); | 
|  |  | 
|  | template <typename T> | 
|  | Table ExtendWithColumn(const char* name, | 
|  | std::unique_ptr<NullableVector<T>> sv, | 
|  | uint32_t flags) const { | 
|  | PERFETTO_DCHECK(sv->size() == row_count_); | 
|  | uint32_t size = sv->size(); | 
|  | uint32_t row_map_count = static_cast<uint32_t>(row_maps_.size()); | 
|  | Table ret = Copy(); | 
|  | ret.columns_.push_back(Column::WithOwnedStorage( | 
|  | name, std::move(sv), flags, &ret, GetColumnCount(), row_map_count)); | 
|  | ret.row_maps_.emplace_back(RowMap(0, size)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | // Returns the column at index |idx| in the Table. | 
|  | const Column& GetColumn(uint32_t idx) const { return columns_[idx]; } | 
|  |  | 
|  | // Returns the column with the given name or nullptr otherwise. | 
|  | const Column* GetColumnByName(const char* name) const { | 
|  | auto it = std::find_if( | 
|  | columns_.begin(), columns_.end(), | 
|  | [name](const Column& col) { return strcmp(col.name(), name) == 0; }); | 
|  | if (it == columns_.end()) | 
|  | return nullptr; | 
|  | return &*it; | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | const TypedColumn<T>* GetTypedColumnByName(const char* name) const { | 
|  | return TypedColumn<T>::FromColumn(GetColumnByName(name)); | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | const IdColumn<T>* GetIdColumnByName(const char* name) const { | 
|  | return IdColumn<T>::FromColumn(GetColumnByName(name)); | 
|  | } | 
|  |  | 
|  | // Returns the number of columns in the Table. | 
|  | uint32_t GetColumnCount() const { | 
|  | return static_cast<uint32_t>(columns_.size()); | 
|  | } | 
|  |  | 
|  | // Returns an iterator into the Table. | 
|  | Iterator IterateRows() const { return Iterator(this); } | 
|  |  | 
|  | uint32_t row_count() const { return row_count_; } | 
|  | const std::vector<RowMap>& row_maps() const { return row_maps_; } | 
|  |  | 
|  | protected: | 
|  | Table(StringPool* pool, const Table* parent); | 
|  |  | 
|  | std::vector<RowMap> row_maps_; | 
|  | std::vector<Column> columns_; | 
|  | uint32_t row_count_ = 0; | 
|  |  | 
|  | StringPool* string_pool_ = nullptr; | 
|  |  | 
|  | private: | 
|  | friend class Column; | 
|  |  | 
|  | Table Copy() const; | 
|  | Table CopyExceptRowMaps() const; | 
|  | }; | 
|  |  | 
|  | }  // namespace trace_processor | 
|  | }  // namespace perfetto | 
|  |  | 
|  | #endif  // SRC_TRACE_PROCESSOR_DB_TABLE_H_ |