Spec-Zone.ru › Ada 2022
Справочник по Ada (Ada 2022)

4.3.5 Агрегаты контейнеров

В container_aggregate значения задаются для элементов контейнера; для positional_container_aggregate элементы задаются последовательно; для named_container_aggregate элементы задаются с помощью последовательности пар ключ/значение или с помощью итератора. Аспект Aggregate типа aggregate определяет, как элементы объединяются для формирования контейнера.
Для типа, отличного от типа массива, можно указать следующие операционные аспекты, связанные с типом:
Aggregate
Этот аспект представляет собой aggregate в виде:
(Empty => имя[,
Add_Named => процедура_имя][,
Add_Unnamed => процедура_имя][,
New_Indexed => функция_имя,
Assign_Indexed => процедура_имя])
Тип, для которого указан этот аспект, известен как тип контейнера аспекта Aggregate. Для процедура_имя необходимо указать хотя бы одно из Add_Named, Add_Unnamed или Assign_Indexed. Если указан Add_Named, то не должны быть указаны Add_Unnamed или Assign_Indexed. Должны быть указаны либо оба, либо ни один из New_Indexed и Assign_Indexed.

Правила разрешения имен

Указанное для Empty имя аспекта Aggregate должно обозначать константу типа контейнера или обозначать ровно одну функцию с типом результата типа контейнера, у которой нет параметров или есть один параметр in типа целого со знаком.
Указанное для Add_Unnamed имя процедуры аспекта Aggregate должно обозначать ровно одну процедуру с двумя параметрами, первый — параметр in out типа контейнера, а второй — параметр in некоторого не ограниченного типа, называемого типом элемента типа контейнера.
Указанное для New_Indexed имя функции аспекта Aggregate должно обозначать ровно одну функцию с типом результата типа контейнера и двумя параметрами одного дискретного типа, при этом этот тип является типом ключа типа контейнера.
Указанное для Add_Named или Assign_Indexed имя процедуры аспекта Aggregate должно обозначать ровно одну процедуру с тремя параметрами: первый — параметр in out типа контейнера, второй — параметр in не ограниченного типа (тип ключа типа контейнера), и третий — параметр in не ограниченного типа, называемого типом элемента типа контейнера.

Правила легальности

Если тип контейнера аспекта Aggregate является типом-частностью, то полный тип типа контейнера не должен быть типом массива. Если тип контейнера ограничен, то указанное для Empty имя должно обозначать функцию, а не объект-константу.
Для аспекта Aggregate тип ключа Assign_Indexed должен быть таким же, как и тип параметров New_Indexed. Кроме того, если указаны как Add_Unnamed, так и Assign_Indexed, то конечные параметры должны быть одного типа — типа элемента типа контейнера.

Статическая семантика

Аспект Aggregate не может быть переопределен (см. 13.1.1).

Синтаксис

container_aggregate ::=
null_container_aggregate
| positional_container_aggregate
| named_container_aggregate
null_container_aggregate ::= '[' ']'
positional_container_aggregate ::= '[' выражение{, выражение} ']'
named_container_aggregate ::= '[' container_element_association_list ']'
container_element_association_list ::=
container_element_association {, container_element_association}
container_element_association ::=
key_choice_list => выражение
| key_choice_list => <>
| iterated_element_association
key_choice_list ::= key_choice {'|' key_choice}
key_choice ::= ключ_выражение | discrete_range
iterated_element_association ::=
for loop_parameter_specification[ use ключ_выражение] => выражение
| for iterator_specification[ use ключ_выражение] => выражение

Правила разрешения имен

Ожидаемый тип для container_aggregate должен быть одним типом, для которого был задан аспект Aggregate. Ожидаемый тип для каждого выражения агрегата контейнера — тип элемента ожидаемого типа.
Ожидаемый тип для ключ_выражение или discrete_range key_choice — тип ключа ожидаемого типа aggregate.

Правила легальности

Ожидаемый тип для positional_container_aggregate должен иметь аспект Aggregate, который включает указание процедуры Add_Unnamed или Assign_Indexed. Ожидаемый тип для named_container_aggregate, который содержит один или несколько iterated_element_associationс ключ_выражение, должен иметь аспект Aggregate, который включает указание процедуры Add_Named. Ожидаемый тип для named_container_aggregate, содержащий один или несколько key_choice_list, должен иметь аспект Aggregate, который включает указание процедуры Add_Named или Assign_Indexed. null_container_aggregate может быть любого типа с аспектом Aggregate.
Агрегат контейнера, отличный от пустого, называется индексированным агрегатом, если ожидаемый тип T агрегата в аспекте Aggregate указывает процедуру Assign_Indexed, и либо не указана процедура Add_Unnamed для типа, либо агрегат является named_container_aggregate с container_element_association, который содержит key_choice_list или loop_parameter_specification. Тип ключа индексированного агрегата также называется типом индекса агрегата.
END_OF_DOCUMENT_MARKER
Ассоциация container_element_association с <> вместо expression или с key_choice, являющимся discrete_range, разрешена только в индексированном агрегате.
Для iterated_element_association без key_expression, если aggregate является индексированным агрегатом или ожидаемый тип aggregate указывает процедуру Add_Named в своём аспекте Aggregate, то тип параметра цикла iterated_element_association должен быть таким же, как тип ключа aggregate.
Для named_container_aggregate, являющегося индексированным агрегатом, все container_element_association должны содержать либо key_choice_list, либо loop_parameter_specification без key_expression или iterator_filter. Кроме того, для такого агрегата должно выполняться одно из следующих условий:
  • все key_choice являются статическими выражениями или статическими диапазонами, и каждый loop_parameter_specification должен иметь discrete_subtype_definition, определяющий непустой статический диапазон, и множество значений типа индекса, покрытых key_choice и discrete_subtype_definition, должно образовывать непрерывный диапазон значений без дубликатов; или
  • должен быть ровно один container_element_association, и если он имеет key_choice_list, список должен содержать ровно один key_choice.

Динамическая семантика

Вычисление container_aggregate начинается с создания анонимного объекта A ожидаемого типа T, инициализированного следующим образом:
  • если aggregate является индексированным агрегатом, из результата вызова функции New_Indexed; фактические параметры в этом вызове представляют нижнюю и верхнюю границы aggregate, и определяются следующим образом:
если aggregate является positional_container_aggregate, нижняя граница - это нижняя граница подтипа параметра ключа процедуры Add_Indexed, а верхняя граница имеет номер позиции, который является суммой номера позиции нижней границы и на единицу меньше числа expression в aggregate;
если aggregate является named_container_aggregate, нижняя граница - это минимальное значение, покрываемое key_choice_list или нижняя граница диапазона, определённого discrete_subtype_definition loop_parameter_specification; верхняя граница - это максимальное значение, покрываемое key_choice_list или верхняя граница диапазона, определённого discrete_subtype_definition loop_parameter_specification.
  • если aggregate не является индексированным агрегатом, путём присваивания из константы Empty или из вызова функции Empty, заданной в аспекте Aggregate. В случае функции Empty с формальным параметром фактический параметр имеет следующее значение:
для null_container_aggregate, значение ноль;
для positional_container_aggregate, число expressions;
для named_container_aggregate без iterated_element_association, число key_expressions;
для named_container_aggregate, где каждый iterated_element_association содержит loop_parameter_specification, общее число элементов, заданных всеми container_element_associations;
в противном случае - реализуемое значение.
Затем вычисление выполняется следующим образом:
  • для null_container_aggregate, анонимный объект A является результатом;
  • для positional_container_aggregate типа со специфической процедурой Add_Unnamed, каждое expression вычисляется в произвольном порядке, и процедура Add_Unnamed вызывается последовательно с анонимным объектом A в качестве первого параметра и результатом вычисления каждого expression в качестве второго параметра, в порядке expressions;
  • для positional_container_aggregate, являющегося индексированным агрегатом, каждое expression вычисляется в произвольном порядке, и процедура Assign_Indexed вызывается последовательно с анонимным объектом A в качестве первого параметра, значением ключа во втором параметре, вычисляемым путём начала с нижней границы подтипа формального параметра ключа процедуры Assign_Indexed и взятия преемника этого значения для каждого последующего expression, и результатом вычисления каждого expression в качестве третьего параметра;
  • для named_container_aggregate типа с процедурой Add_Named в его аспекте Aggregate, container_element_associations вычисляются в произвольном порядке:
для container_element_association с key_choice_list, для каждого key_choice списка в произвольном порядке, key_choice вычисляется так же, как и expression container_element_association (в произвольном порядке), и процедура Add_Named вызывается один раз для каждого значения, покрытого key_choice, с анонимным объектом A в качестве первого параметра, значением из key_choice в качестве второго параметра и результатом вычисления expression в качестве третьего параметра;
для container_element_association с iterated_element_association, сначала iterated_element_association уточняется, затем выполняется итерация, и для каждого значения, условно производимого итерацией (см. 5.5 и 5.5.2), процедура Add_Named вызывается с анонимным объектом A в качестве первого параметра, результатом вычисления expression в качестве третьего параметра, и:
если есть key_expression, результатом вычисления key_expression в качестве второго параметра;
в противном случае, с параметром цикла как вторым параметром;
  • для named_container_aggregate, являющегося индексированным агрегатом, вычисление происходит, как описано выше для случая Add_Named, но с вызовом процедуры Assign_Indexed вместо Add_Named; в случае container_element_association с <> вместо выражения, соответствующий вызов Assign_Indexed не выполняется, оставляя компонент в том состоянии, в котором он был после возвращения из функции New_Indexed;
  • для любого другого named_container_aggregate, container_element_association (которые обязательно являются iterated_element_associations) вычисляются в заданном порядке; каждое такое вычисление состоит из двух шагов:
1.
iterated_element_association обрабатывается;
2.
выполняется итерация, и для каждого значения, условно произведённого итерацией (см. 5.5 и 5.5.2), вызывается процедура Add_Unnamed с анонимным объектом A в качестве первого параметра и результатом вычисления выражения в качестве второго параметра.

Примеры

Примеры указания аспекта Aggregate для Set_Type, Map_Type и Vector_Type:
-- Set_Type — это контейнерный тип, похожий на множество.
type Set_Type is private
with Aggregate => (Empty => Empty_Set,
Add_Unnamed => Include);
function Empty_Set return Set_Type;
subtype Small_Int is Integer range -1000..1000;
procedure Include (S : in out Set_Type; N : in Small_Int);
-- Map_Type — это контейнерный тип, похожий на карту.
type Map_Type is private
with Aggregate => (Empty => Empty_Map,
Add_Named => Add_To_Map);
procedure Add_To_Map (M : in out Map_Type;
Key : in Integer;
Value : in String);
Empty_Map : constant Map_Type;
-- Vector_Type — это изменяемый массив-подобный контейнерный тип.
type Vector_Type is private
with Aggregate => (Empty => Empty_Vector,
Add_Unnamed => Append_One,
New_Indexed => New_Vector,
Assign_Indexed => Assign_Element);
function Empty_Vector (Capacity : Integer := 0) return Vector_Type;
procedure Append_One (V : in out Vector_Type; New_Item : in String);
procedure Assign_Element (V : in out Vector_Type;
Index : in Positive;
Item : in String);
function New_Vector (First, Last : Positive) return Vector_Type
with Pre => First = Positive'First;
-- Векторы всегда индексируются, начиная с нижней границы их индексного подтипа.
-- Приватная часть не показана.
Примеры контейнерных агрегатов для Set_Type, Map_Type и Vector_Type:
-- Пример агрегатов, использующих Set_Type.
S : Set_Type;
-- Присвоить пустое множество S:
S := [];
-- Эквивалентно:
S := Empty_Set;
-- Позиционный агрегат множества:
S := [1, 2];
-- Эквивалентно:
S := Empty_Set;
Include (S, 1);
Include (S, 2);
-- Агрегат множества с iterated_element_association:
S := [for Item in 1 .. 5 => Item * 2];
-- Эквивалентно:
S := Empty_Set;
for Item in 1 .. 5 loop
Include (S, Item * 2);
end loop;
-- Агрегат множества, состоящий из двух iterated_element_association:
S := [for Item in 1 .. 5 => Item,
for Item in 1 .. 5 => -Item];
-- Эквивалентно (при условии семантики множества):
S := Empty_Set;
for Item in 1 .. 5 loop
Include (S, Item);
end loop;
for Item in -5 .. -1 loop
Include (S, Item);
end loop;
-- Примеры агрегатов, использующих Map_Type.
M : Map_Type;
-- Простой именованный агрегат карты:
M := [12 => "дом", 14 => "бежевый"];
-- Эквивалентно:
M := Empty_Map;
Add_To_Map (M, 12, "дом");
Add_To_Map (M, 14, "бежевый");
-- Определите таблицу пар:
type Pair is record
Key : Integer;
Value : access constant String;
end record;
Table : constant array(Positive range <>) of Pair :=
[(Key => 33, Value => new String'("приятная строка")),
(Key => 44, Value => new String'("ещё лучшая строка"))];
-- Агрегат карты, использующий iterated_element_association
-- и ключ_выражение, созданный из таблицы пар ключ/значение:
M := [for P of Table use P.Key => P.Value.all];
-- Эквивалентно:
M := Empty_Map;
for P of Table loop
Add_To_Map (M, P.Key, P.Value.all);
end loop;
-- Создайте таблицу изображений для массива целых чисел:
Keys : constant array(Positive range <>) of Integer := [2, 3, 5, 7, 11];
-- Агрегат карты, где значения, произведённые
-- iterated_element_association, имеют тот же тип, что и ключ
-- (следовательно, отдельное ключ_выражение не требуется):
M := [for Key of Keys => Integer'Image (Key)];
-- Эквивалентно:
M := Empty_Map;
for Key of Keys loop
Add_To_Map (M, Key, Integer'Image (Key));
end loop;
-- Примеры агрегатов, использующих Vector_Type.
V : Vector_Type;
-- Позиционный агрегат вектора:
V := ["abc", "def"];
-- Эквивалентно:
V := Empty_Vector (2);
Append_One (V, "abc");
Append_One (V, "def");
-- Индексированный агрегат вектора:
V := [1 => "это", 2 => "есть", 3 => "а", 4 => "тест"];
-- Эквивалентно:
V := New_Vector (1, 4);
Assign_Element (V, 1, "это");
Assign_Element (V, 2, "есть");
Assign_Element (V, 3, "а");
Assign_Element (V, 4, "тест");


Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API