Справочное руководство Ada 2005
13.13.2 Потоковые атрибуты
Операционные атрибуты Write, Read, Output и Input преобразуют значения в поток элементов и восстанавливают значения из потока.
Статическая семантика
Для каждого подтипа S элементарного типа T определён следующий атрибут представления:
S'Stream_Size
Обозначает количество битов, занимаемых в потоке элементами подтипа S. Таким образом, количество потоковых элементов, необходимых для элемента элементарного типа T, равно:
T'Stream_Size / Ada.Streams.Stream_Element'Size
Значение этого атрибута является целым числом типа universal_integer и кратно Stream_Element'Size.
Stream_Size может быть указан для подтипов с помощью описания_атрибута; выражение в таком описании должно быть статическим, неотрицательным и кратным Stream_Element'Size.
Рекомендации по реализации
Если не указано иначе, значение Stream_Size для элементарного типа должно быть равно количеству битов, соответствующему минимальному количеству потоковых элементов, требуемых первым подтипом типа, округлённому до ближайшего кратного или множителя размера слова, также кратному размеру потокового элемента.
Рекомендуемый уровень поддержки атрибута Stream_Size:
- Определение Stream_Size должно поддерживаться для дискретного или фиксированного типа T, если указанное Stream_Size кратно Stream_Element'Size и не меньше размера первого подтипа T, и не больше размера наибольшего типа того же элементарного класса (целое со знаком, целое по модулю, перечисление, обычная фиксированная точка или десятичная фиксированная точка).
Статическая семантика
Для каждого подтипа S конкретного типа T определены следующие атрибуты.
S'Write
S'Write обозначает процедуру со следующей спецификацией:
procedure S'Write(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T)
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T)
S'Write записывает значение Item в Stream.
S'Read
S'Read обозначает процедуру со следующей спецификацией:
procedure S'Read(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out T)
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out T)
S'Read считывает значение Item из Stream.
Для немеченых производных типов атрибут Write (соответственно, Read) наследуется в соответствии с правилами, указанными в 13.1, если атрибут доступен для родительского типа в момент объявления T. Для меченых производных типов эти атрибуты не наследуются, а используются стандартные реализации.
Стандартные реализации атрибутов Write и Read, где доступны, выполняются следующим образом:
Для элементарных типов Read считывает (и Write записывает) количество потоковых элементов, подразумеваемое Stream_Size для типа T; представление этих потоковых элементов определяется реализацией. Для составных типов атрибут Write или Read для каждого компонента вызывается в каноническом порядке, при котором изменение последней размерности происходит быстрее всего для массива и в порядке позиционных агрегатов для записи. Границы не включаются в поток, если T является типом массива. Если T является дискриминируемым типом, дискриминанты включаются только если они имеют значения по умолчанию. Если T является меченым типом, метка не включается. Для расширений типов атрибут Write или Read для родительского типа вызывается, за которым следуют атрибуты Write или Read каждого компонента расширяющей части в каноническом порядке. Для ограниченного расширения типа, если атрибут родительского типа или любого предкового типа T доступен где-либо в непосредственной области видимости T, а атрибут родительского типа или тип любого из компонентов расширения недоступен в точке заморозки T, тогда атрибут T должен быть задан напрямую.
Constraint_Error генерируется предопределённым атрибутом Write, если значение элементарного элемента находится вне диапазона представляемых значений с использованием Stream_Size битов. Для типа целого со знаком, типа перечисления или типа с фиксированной точкой диапазон является беззнаковым только если код целого числа для нижней границы первого подтипа неотрицателен, и симметричный диапазон со знаком, охватывающий все значения первого подтипа, потребовал бы более Stream_Size битов; в противном случае диапазон является со знаком.
Для каждого подтипа S'Class класса типа T'Class:
S'Class'Write
S'Class'Write обозначает процедуру со следующей спецификацией:
procedure S'Class'Write(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T'Class)
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T'Class)
Перенаправляется на подпрограмму, обозначаемую атрибутом Write конкретного типа, идентифицируемого меткой Item.
S'Class'Read
S'Class'Read обозначает процедуру со следующей спецификацией:
procedure S'Class'Read(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out T'Class)
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out T'Class)
Перенаправляется на подпрограмму, обозначаемую атрибутом Read конкретного типа, идентифицируемого меткой Item.
Рекомендации по реализации
Этот абзац был удалён.
Статическая семантика
Для каждого подтипа S конкретного типа T определены следующие атрибуты.
S'Output
S'Output обозначает процедуру со следующей спецификацией:
procedure S'Output(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T)
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T)
S'Output записывает значение Item в Stream, включая любые границы или дискриминанты.
S'Input
S'Input обозначает функцию со следующей спецификацией:
function S'Input(
Stream : not null access Ada.Streams.Root_Stream_Type'Class)
return T
Stream : not null access Ada.Streams.Root_Stream_Type'Class)
return T
S'Input считывает и возвращает одно значение из Stream, используя любые границы или дискриминанты, записанные соответствующим S'Output, чтобы определить, сколько считывать.
Для немеченых производных типов атрибут Output (соответственно, Input) наследуется в соответствии с правилами, указанными в 13.1, если атрибут доступен для родительского типа в момент объявления T. Для меченых производных типов эти атрибуты не наследуются, а используются стандартные реализации.
Стандартные реализации атрибутов Output и Input, где доступны, выполняются следующим образом:
- Если T является типом массива, S'Output сначала записывает границы, а S'Input сначала считывает границы. Если T имеет дискриминанты без значений по умолчанию, S'Output сначала записывает дискриминанты (используя S'Write для каждого), а S'Input сначала считывает дискриминанты (используя S'Read для каждого).
- Затем S'Output вызывает S'Write для записи значения Item в поток. S'Input затем создаёт объект (с границами или дискриминантами, если таковые имеются, взятыми из потока), передаёт его в S'Read и возвращает значение объекта. Стандартная инициализация и финализация объекта происходят (см. 3.3.1, 7.6 и 7.6.1).
Если T является абстрактным типом, то S'Input является абстрактной функцией.
Для каждого подтипа S'Class класса типа T'Class:
S'Class'Output
S'Class'Output обозначает процедуру со следующей спецификацией:
procedure S'Class'Output(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T'Class)
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T'Class)
Сначала записывает внешнюю метку Item в Stream (вызывая String'Output(Stream, Tags.External_Tag(Item'Tag)) — см. 3.9), а затем перенаправляется на подпрограмму, обозначаемую атрибутом Output конкретного типа, идентифицируемого меткой. Tag_Error генерируется, если метка Item идентифицирует тип, объявленный на уровне доступности глубже, чем уровень S.
S'Class'Input
S'Class'Input обозначает функцию со следующей спецификацией:
function S'Class'Input(
Stream : not null access Ada.Streams.Root_Stream_Type'Class)
return T'Class
Stream : not null access Ada.Streams.Root_Stream_Type'Class)
return T'Class
Сначала считывает внешний тег из потока Stream и определяет соответствующий внутренний тег (вызывая Tags.Descendant_Tag(String'Input(Stream), S'Tag), что может вызвать ошибку Tag_Error — см. 3.9) и затем перенаправляет выполнение на подпрограмму, обозначенную атрибутом Input конкретного типа, определённого внутренним тегом; возвращает результат. Если конкретный тип, определённый внутренним тегом, не покрывается T'Class или является абстрактным, генерируется ошибка Constraint_Error.
В реализации по умолчанию Read и Input для составного типа для каждого скалярного компонента, являющегося дискриминантом или чей component_declaration содержит default_expression, выполняется проверка, принадлежит ли значение, возвращённое Read для компонента, его подтипу. Если проверка не пройдена, генерируется ошибка Constraint_Error. Для других скалярных компонентов проверка не выполняется. Для каждого компонента типа доступа, если реализация может определить, что значение, возвращённое Read для компонента, не является значением его подтипа, генерируется ошибка Constraint_Error. Если значение не является значением подтипа и эта ошибка не обнаружена, компонент имеет аномальное значение, что может привести к ошибочному выполнению (см. 13.9.1). В реализации по умолчанию Read для составного типа с дискриминантами по умолчанию, если фактический параметр Read ограничен, выполняется проверка, совпадают ли дискриминанты, считанные из потока, с дискриминантами фактического параметра. Если проверка не пройдена, генерируется ошибка Constraint_Error.
Не определено, в какой момент и в каком порядке выполняются эти проверки. В частности, если ошибка Constraint_Error возникает из-за неудачи одной из этих проверок, не определено, сколько элементов потока было прочитано из потока.
В реализации по умолчанию Read и Input для типа, ошибка End_Error генерируется, если конец потока достигается до завершения чтения значения типа.
Потоково-ориентированные атрибуты могут быть заданы для любого типа через attribute_definition_clause. Имя подпрограммы, указанное в таком предложении, не должно обозначать абстрактную подпрограмму. Кроме того, если потоково-ориентированный атрибут задан для типа интерфейса с помощью attribute_definition_clause, имя подпрограммы, указанное в предложении, должно статически обозначать пустую процедуру.
Потоково-ориентированный атрибут для подтипа определенного типа T доступен в тех местах, где выполняется одно из следующих условий:
- T — неограниченный тип.
- Обозначитель атрибута attribute_designator равен Read (соответственно Write), а T — ограниченное расширение записи, и атрибут Read (соответственно Write) доступен для родительского типа T и для типов всех компонентов расширения.
- T — ограниченный неопределённый производный тип, и атрибут был унаследован для типа.
- Обозначитель атрибута attribute_designator равен Input (соответственно Output), а T — ограниченный тип, и атрибут Read (соответственно Write) доступен для T.
- Атрибут был задан с помощью attribute_definition_clause, и attribute_definition_clause виден.
Потоково-ориентированный атрибут для подтипа типа всего класса T'Class доступен в тех местах, где выполняется одно из следующих условий:
- T — неограниченный тип;
- атрибут был задан с помощью attribute_definition_clause, и attribute_definition_clause виден; или
- соответствующий атрибут T доступен, при условии, что если T имеет частичный вид, соответствующий атрибут доступен в конце видимой части, где T объявлен.
Ссылка на атрибут attribute_reference для одного из потоково-ориентированных атрибутов является недопустимой, если атрибут не доступен в месте ссылки attribute_reference. Кроме того, ссылка на атрибут attribute_reference для T'Input недопустима, если T — абстрактный тип.
В parameter_and_result_profile для потоково-ориентированных атрибутов подтип параметра Item — базовый подтип T, если T — скалярный тип, и первый подтип в противном случае. То же правило применяется к результату атрибута Input.
Для attribute_definition_clause, задающего один из этих атрибутов, подтип параметра Item должен быть базовым подтипом, если скалярный, и первым подтипом в противном случае. То же правило применяется к результату функции Input.
Говорят, что тип поддерживает внешнюю потоковую передачу, если атрибуты Read и Write предоставляются для отправки значений такого типа между активными разделами, причём Write обрабатывает представление, а Read — распаковывает представление. Ограниченный тип поддерживает внешнюю потоковую передачу только если для него доступны атрибуты Read и Write. Тип с частью типа доступа поддерживает внешнюю потоковую передачу только если этот тип доступа или тип какой-либо части, содержащей компонент типа доступа, имеет атрибуты Read и Write, заданные с помощью attribute_definition_clause, и этот attribute_definition_clause виден. Анонимный тип доступа не поддерживает внешнюю потоковую передачу. Все остальные типы поддерживают внешнюю потоковую передачу.
Ошибочное выполнение
Если внутренний тег, возвращённый Descendant_Tag для T'Class'Input, идентифицирует тип, который не является на уровне библиотеки и чей тег не создан или не существует в разделе в момент вызова, выполнение является ошибочным.
Требования к реализации
Для каждого подтипа S языка-определённого неограниченного конкретного типа T, выходной сигнал, сгенерированный S'Output или S'Write, должен быть читаем S'Input или S'Read соответственно. Это правило действует и между разделами, если реализация соответствует приложению о распределённых системах.
Если Constraint_Error возникает при вызове Read из-за неудачи одной из вышеуказанных проверок, реализация должна гарантировать, что дискриминанты фактического параметра Read не будут изменены.
Разрешения для реализации
Количество вызовов, выполняемых предопределённой реализацией потоково-ориентированных атрибутов на операциях Read и Write типа потока, не определено. Реализация может использовать это разрешение для выполнения внутренней буферизации. Однако все вызовы операций Read и Write типа потока, необходимые для реализации явного вызова потоково-ориентированного атрибута, должны быть выполнены до возврата этого вызова. Явный вызов — это вызов, явно присутствующий в тексте программы, возможно, через обобщённую инстанциацию (см. 12.3).
ПРИМЕЧАНИЯ
33 Для определённого подтипа S типа T, требуются только T'Write и T'Read для передачи произвольного значения подтипа через поток. Для неопределённого подтипа S типа T, обычно потребуются T'Output и T'Input, так как T'Write и T'Read не передают границы, дискриминанты или теги.
34 Пользовательские атрибуты S'Class не наследуются другими типами всего класса, унаследованными от S.
Примеры
Пример пользовательского атрибута Write:
procedure My_Write(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : My_Integer'Base);
for My_Integer'Write use My_Write;
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : My_Integer'Base);
for My_Integer'Write use My_Write;