tp: migrate ThreadTable, ProcessTable, AndroidLogsTable to Python

This CL introduces the actual conversion of Python generated tables to
C++ and migrates three of the trickier tables over

Change-Id: I443ea5ce823868ec974a442de3a55b83307ffa49
diff --git a/python/generators/trace_processor_table/serialize.py b/python/generators/trace_processor_table/serialize.py
new file mode 100644
index 0000000..43ca5cd
--- /dev/null
+++ b/python/generators/trace_processor_table/serialize.py
@@ -0,0 +1,249 @@
+# Copyright (C) 2022 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.
+
+from typing import List
+from typing import Optional
+
+from python.generators.trace_processor_table.public import Alias
+from python.generators.trace_processor_table.public import Column
+from python.generators.trace_processor_table.public import ColumnFlag
+from python.generators.trace_processor_table.public import Table
+from python.generators.trace_processor_table.util import parse_type
+from python.generators.trace_processor_table.util import typed_column_type
+from python.generators.trace_processor_table.util import to_cpp_flags
+
+
+class ColumnSerializer:
+  """Functions for serializing a single Column in a table into C++."""
+
+  def __init__(self, table: Table, col_index: int):
+    self.col_index = col_index
+    self.col = table.columns[col_index]
+    self.name = self.col.name
+    self.flags = self.col.flags
+    self.typed_column_type = typed_column_type(table, self.col)
+    self.cpp_type = parse_type(table, self.col.type).cpp_type_with_optionality()
+
+  def colindex(self) -> str:
+    return f'    static constexpr uint32_t {self.name} = {self.col_index};'
+
+  def coltype_enum(self) -> str:
+    return f'    using {self.name} = {self.typed_column_type};'
+
+  def row_field(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    return f'    {self.cpp_type} {self.name};'
+
+  def row_param(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    return f'{self.cpp_type} in_{self.name} = {{}}'
+
+  def row_initializer(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    return f'{self.name}(std::move(in_{self.name}))'
+
+  def flag(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    default = f'ColumnType::{self.name}::default_flags()'
+    if self.flags == ColumnFlag.NONE:
+      flags = default
+    else:
+      flags = f'static_cast<uint32_t>({to_cpp_flags(self.flags)}) | {default}'
+    return f'''
+      static constexpr uint32_t {self.name} = {flags};
+    '''
+
+  def storage_init(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+
+    storage = f'ColumnStorage<ColumnType::{self.name}::stored_type>'
+    # TODO(lalitm): add support for dense columns.
+    return f'''{self.name}_({storage}::Create<false>())'''
+
+  def column_init(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    return f'''
+    columns_.emplace_back("{self.name}", &{self.name}_, ColumnFlag::{self.name},
+                          this, static_cast<uint32_t>(columns_.size()),
+                          overlay_count);
+    '''
+
+  def shrink_to_fit(self) -> Optional[str]:
+    if self.col._is_auto_added_id:
+      return None
+    return f'    {self.name}_.ShrinkToFit();'
+
+  def append(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    return f'    mutable_{self.name}()->Append(std::move(row.{self.name}));'
+
+  def accessor(self) -> Optional[str]:
+    inner = f'columns_[ColumnIndex::{self.name}]'
+    return f'''
+  const {self.typed_column_type}& {self.name}() const {{
+    return static_cast<const ColumnType::{self.name}&>({inner});
+  }}
+  '''
+
+  def mutable_accessor(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    return f'''
+  {self.typed_column_type}* mutable_{self.name}() {{
+    return static_cast<ColumnType::{self.name}*>(
+        &columns_[ColumnIndex::{self.name}]);
+  }}
+  '''
+
+  def storage(self) -> Optional[str]:
+    if self.col._is_auto_added_id or self.col._is_auto_added_type:
+      return None
+    name = self.name
+    return f'  ColumnStorage<ColumnType::{name}::stored_type> {name}_;'
+
+
+class TableSerializer(object):
+  """Functions for seralizing a single Table into C++."""
+
+  def __init__(self, table: Table):
+    self.table = table
+    self.table_name = table.class_name
+    self.column_serializers = [
+        ColumnSerializer(table, i) for i in range(len(table.columns))
+    ]
+
+  def foreach_col(self, serialize_fn, delimiter='\n') -> str:
+    lines = []
+    for c in self.column_serializers:
+      serialized = serialize_fn(c)
+      if serialized:
+        lines.append(serialized.lstrip('\n').rstrip())
+    return delimiter.join(lines).strip()
+
+  def id_defn(self) -> str:
+    return '''
+  struct Id : public BaseId {
+    Id() = default;
+    explicit constexpr Id(uint32_t v) : BaseId(v) {}
+  };
+  static_assert(std::is_trivially_destructible<Id>::value,
+                "Inheritance used without trivial destruction");
+    '''
+
+  def row_struct(self) -> str:
+    param = self.foreach_col(
+        ColumnSerializer.row_param, delimiter=',\n        ')
+    row_init = self.foreach_col(
+        ColumnSerializer.row_initializer, delimiter=',\n          ')
+    return f'''
+  struct Row : public macros_internal::RootParentTable::Row {{
+    Row({param})
+        : macros_internal::RootParentTable::Row(nullptr),
+          {row_init} {{
+      type_ = "{self.table.sql_name}";
+    }}
+    {self.foreach_col(ColumnSerializer.row_field)}
+  }};
+    '''
+
+  def constructor(self) -> str:
+    col_init = self.foreach_col(
+        ColumnSerializer.storage_init, delimiter=',\n        ')
+    return f'''
+  explicit {self.table_name}(StringPool* pool)
+      : macros_internal::MacroTable(pool, nullptr),
+        {col_init} {{
+    uint32_t overlay_count = static_cast<uint32_t>(overlays_.size()) - 1;
+    {self.foreach_col(ColumnSerializer.column_init)}
+  }}
+    '''
+
+  def serialize(self) -> str:
+    return f'''
+class {self.table_name} : public macros_internal::MacroTable {{
+ public:
+  {self.id_defn().lstrip()}
+  struct ColumnIndex {{
+    {self.foreach_col(ColumnSerializer.colindex)}
+  }};
+  struct ColumnType {{
+    {self.foreach_col(ColumnSerializer.coltype_enum)}
+  }};
+  {self.row_struct().strip()}
+  struct IdAndRow {{
+    uint32_t row;
+  }};
+  struct ColumnFlag {{
+    {self.foreach_col(ColumnSerializer.flag)}
+  }};
+
+  {self.constructor().strip()}
+  ~{self.table_name}() override;
+
+  static const char* Name() {{ return "{self.table.sql_name}"; }}
+
+  void ShrinkToFit() {{
+    {self.foreach_col(ColumnSerializer.shrink_to_fit)}
+  }}
+
+  IdAndRow Insert(const Row& row) {{
+    uint32_t row_number = row_count();
+    type_.Append(string_pool_->InternString(row.type()));
+    {self.foreach_col(ColumnSerializer.append)}
+    UpdateSelfOverlayAfterInsert();
+    return IdAndRow{{row_number}};
+  }}
+
+  {self.foreach_col(ColumnSerializer.accessor)}
+
+  {self.foreach_col(ColumnSerializer.mutable_accessor)}
+
+ private:
+  {self.foreach_col(ColumnSerializer.storage)}
+}};
+  '''.strip('\n')
+
+
+def serialize_header(ifdef_guard: str, tables: List[Table],
+                     include_paths: List[str]) -> str:
+  """Serializes a table header file containing the given set of tables."""
+  include_paths_str = '\n'.join([f'#include "{i}"' for i in include_paths])
+  tables_str = '\n\n'.join([TableSerializer(t).serialize() for t in tables])
+  return f'''
+#ifndef {ifdef_guard}
+#define {ifdef_guard}
+
+#include "src/trace_processor/tables/macros.h"
+
+{include_paths_str}
+
+namespace perfetto {{
+namespace trace_processor {{
+namespace tables {{
+
+{tables_str.strip()}
+
+}}  // namespace tables
+}}  // namespace trace_processor
+}}  // namespace perfetto
+
+#endif  // {ifdef_guard}
+  '''.strip()