File: aggregation.py

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (223 lines) | stat: -rw-r--r-- 7,849 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from dataclasses import dataclass
from enum import Enum
from typing import Optional


class AggregationKind(Enum):
  """Allowed aggregation types for data that uses "aggregate" declaration."""
  NONE = "none"
  ARRAY = "array"
  MAP = "map"


@dataclass
class AggregationDetails:
  """Aggregation rules, if specified by the processed JSON file."""
  kind: AggregationKind
  name: Optional[str]
  export_items: bool
  elements: dict[str, str]
  map_key_type: Optional[str]

  def GetSortedArrayElements(self) -> list[str]:
    """Returns sorted list of names of all elements."""
    return sorted(self.elements.keys())

  def GetSortedMapElements(self) -> list[tuple[str, str]]:
    """Returns sorted mapping of all elements, including aliases."""
    keys = sorted(self.elements.keys())
    return [(key, self.elements[key]) for key in keys]


def GetAggregationDetails(description) -> AggregationDetails:
  """Extracts aggregation details from a JSON structure.

  This function processes a JSON data object to determine its aggregation
  properties. Aggregation details are specified within an optional "aggregation"
  descriptor in the JSON input. If the descriptor is missing, no aggregation is
  performed.

  **Aggregation Descriptor Structure:**
      - `type` (str): Defines the aggregation type. Options include:
          - `"none"`: No aggregation (default/implied if descriptor is missing).
          - `"array"`: Uses `std::span<Type>` for aggregation.
          - `"map"`: Uses `base::fixed_flat_map<std::string_view, Type>` for
            aggregation.
      - `name` (str): The name assigned to the generated array or map.
      - `export_items` (bool, optional): Whether aggregated items should be
        exported (defaults to `true`).
      - `map_aliases` (dict[str, str]) - if the aggregation `type` is set to
        `"map"`, this field allows specifying additional aliases - elements
        pointing to already defined structures.
      - `map_key_type` (str) - the type representing the map key. Must be a
        constexpr-constructible from const char[].

  **Default Behavior:**
      - If the `aggregation` descriptor is missing, the function defaults to:
          - `type = "none"`
          - `export_items = True`
      - The `name` field is only relevant when aggregation is `array` or `map`.

  **Parameters:**
      description (dict): input JSON data file (not schema).

  **Returns:**
      AggregationDetails populated with relevant fields. This is always
      returned, even if the data object does not include aggregation descriptor.
  """
  aggregation = description.get('aggregation', {})
  kind = AggregationKind(aggregation.get('type', 'none'))
  name = aggregation.get('name', None)
  export_items = aggregation.get('export_items', True)
  map_aliases = aggregation.get('map_aliases', {})
  map_key_type = None

  if kind != AggregationKind.NONE and not name:
    raise Exception("Aggregation container needs a `name`.")

  elements = {}
  for element in description.get('elements', {}).keys():
    elements.update({element: element})

  confirmed_aliases = {}
  if kind == AggregationKind.MAP:
    map_key_type = aggregation.get('map_key_type', 'std::string_view')
    for alias, element in map_aliases.items():
      # Confirmation check for duplicate entries.
      # Note: we do not need to verify duplicate aliases, because `map_aliases`
      # is already a dict - all keys should be unique.
      if elements.get(alias, None):
        raise Exception(f"Alias `{alias}` already defined as element.")

      # Detect that alias does not point to a valid element.
      if not elements.get(element, None):
        raise Exception(f"Aliased element `{element}` does not exist.")

      confirmed_aliases.update({alias: element})
    elements.update(confirmed_aliases)

  return AggregationDetails(kind, name, export_items, elements, map_key_type)


def GenerateCCAggregation(type_name: str,
                          aggregation: AggregationDetails) -> Optional[str]:
  """
    Generates C++ aggregation code based on the aggregation kind.

    Parameters:
        type_name (str): The type name to be used in the aggregation.
        aggregation (AggregationDetails): The aggregation details.

    Returns:
        Optional[str]: The generated C++ aggregation code if applicable, otherwise None.
    """
  if aggregation.kind == AggregationKind.ARRAY:
    return _GenerateCCArray(type_name, aggregation)

  if aggregation.kind == AggregationKind.MAP:
    return _GenerateCCMap(type_name, aggregation)

  return None


def _GenerateCCArray(type_name: str, aggregation: AggregationDetails) -> str:
  """
    Generates C++ code for an array aggregation.

    Parameters:
        type_name (str): The type name to be used in the aggregation.
        aggregation (AggregationDetails): The aggregation details.

    Returns:
        str: The generated C++ array aggregation code.
    """
  res = f'\nconst auto {aggregation.name} =\n'
  res += f'    std::array<const {type_name}*, {len(aggregation.elements)}>'

  res += '({{\n'
  for element_name in aggregation.elements.values():
    res += f'  &{element_name},\n'
  res += '}});\n'
  return res


def _GenerateCCMap(type_name: str, aggregation: AggregationDetails) -> str:
  """
    Generates C++ code for a map aggregation.

    Parameters:
        type_name (str): The type name to be used in the aggregation.
        aggregation (AggregationDetails): The aggregation details.

    Returns:
        str: The generated C++ map aggregation code.
    """
  key_type = aggregation.map_key_type

  res = f'\nconst auto {aggregation.name} =\n'
  res += f'    base::MakeFixedFlatMap<{key_type}, const {type_name}*>'

  res += '({\n'
  for (alias_name, element_name) in aggregation.GetSortedMapElements():
    res += f'  {{{key_type}("{alias_name}"), &{element_name}}},\n'
  res += '});\n'
  return res


def GenerateHHAggregation(type_name: str,
                          aggregation: AggregationDetails) -> Optional[str]:
  """
    Generates header file aggregation code based on the aggregation kind.

    Parameters:
        type_name (str): The type name to be used in the aggregation.
        aggregation (AggregationDetails): The aggregation details.

    Returns:
        Optional[str]: The generated header file aggregation code if applicable, otherwise None.
    """
  if aggregation.kind == AggregationKind.ARRAY:
    return _GenerateHHArray(type_name, aggregation)

  if aggregation.kind == AggregationKind.MAP:
    return _GenerateHHMap(type_name, aggregation)

  return None


def _GenerateHHArray(type_name: str, aggregation: AggregationDetails) -> str:
  """
    Generates header file code for an array aggregation.

    Parameters:
        type_name (str): The type name to be used in the aggregation.
        aggregation (AggregationDetails): The aggregation details.

    Returns:
        str: The generated header file array aggregation declaration.
    """
  res = '\nextern const '
  res += f'std::array<const {type_name}*, {len(aggregation.elements)}> '
  res += f'{aggregation.name};\n'
  return res


def _GenerateHHMap(type_name: str, aggregation: AggregationDetails) -> str:
  """
    Generates header file code for a map aggregation.

    Parameters:
        type_name (str): The type name to be used in the aggregation.
        aggregation (AggregationDetails): The aggregation details.

    Returns:
        str: The generated header file map aggregation declaration.
    """
  res = '\nextern const '
  res += f'base::fixed_flat_map<{aggregation.map_key_type}, '
  res += f'const {type_name}*, {len(aggregation.GetSortedMapElements())}> '
  res += f'{aggregation.name};\n'
  return res