![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Package Data_Decomposition Package Data_Decomposition provides resources that allow data values written with the Portable_Transfer package to be converted back into their original discrete, record, or array
definitions.This package and Portable_Transfer are part of the Data Decomposition Annex and are an optional ASIS capability.
This capability is available in Rational ASIS.
For more information, click on a topic:
Resources in Package Data_DecompositionThe resources (excluding types and constants) in package Data_Decomposition fall into several functional groups, as shown below.
To see detailed reference information, click on the name of a resource:
Component properties:
Component_Declaration Is_Array Is_Identical Is_Record Component_Indication Is_Equal Is_Nil
Obtaining components and nested components:
All_Named_Components Discriminant_Components Array_Components Record_Components
Accessing array elements:
Array_Index Array_Iterator Next Array_Indexes Done Reset
Runtime representation queries:
Array_Length Last_Bit Size First_Bit Position
Data-stream construction, extraction, and conversion:
Component_Data_Stream Portable_Constrained_Subtype Construct_Artificial_Data_Stream
Key Concepts for Package Data_DecompositionPackage Data_Decomposition provides resources that allow data values written with the Portable_Transfer package to be converted back into their original discrete, record, or array definitions. To see more information, click on a topic:
- "Data Streams and Component Types"
- "Type-Definition Model Kinds"
- "Component Properties"
- "Obtaining Components and Nested Components"
- "Accessing Array Elements"
- "Runtime Representation Functions"
- "Constructing Artificial Data Streams"
- "Decomposing Data Streams"
- "Converting Data Streams to Variables"
Data Streams and Component Types
A data stream is an array that contains the encoding of the value of a variable. The variable can be of a scalar, array, or record type. Not all type definitions can be correctly encoded, however. See "Type-Definition Model Kinds" for a description of the kinds of type models defined by ASIS and those that can be encoded.
Variables are converted into data streams with the subprograms in package Portable_Data. They are converted back into variables by instantiations of generics from this package.
Note: It is also possible to create an artificial data stream. This is a stream that contains only discriminant values; it is created with the Construct_Artificial_Data_Stream function. See "Constructing Artificial Data Streams" for more information.
When data streams represent composite structures such as records and arrays, they are constructed so as to allow extraction of the individual components. All that is needed to perform an extraction is a handle to a component.
Component Types
The Record_Component and Array_Component types describe components; the first describes a single component of a record, and the second describes an array. Each record or array component contains sufficient information to extract the component's data stream from a data stream of the enclosing component.
Once a data stream is obtained that represents a simple static type, or a simple dynamic type for which the discriminants are known (see "Type-Definition Model Kinds"), the data stream can be converted into a value of the type.
For more information, click on a topic:
Record Components
The Record_Component_List type defines an array of Record-_Component values. Values of this type are returned by functions that identify only the discriminants or the discriminants and components of a record. See "Obtaining Components and Nested Components" for more information.
A data stream representing a record value can be converted into its component data streams by extracting the streams from the record's stream. The conversion is performed by using a Re-cord_Component that describes one of the record's discriminants or components (see "Constructing Artificial Data Streams").
Array Components
The Array_Component_List type defines an array of Array-_Component values. The Array_Component_List type is defined for completeness and is not used by the ASIS interfaces.
A data stream representing an array value can be converted into data streams that represent the individual elements of the array. The conversion is performed by using an Array_Component in conjunction with a dimensional index, a linear index, or an array iterator (see "Constructing Artificial Data Streams" and "Accessing Array Elements").
Type-Definition Model Kinds
The type-definition model kinds used by ASIS are not intrinsic to Ada. They exist to categorize and simplify reference to the kinds of type definitions that packages Data_Decomposition and Portable_Transfer can correctly encode.
The type-definition model kinds range from simple and static to complex and dynamic, based on whether the definition includes discriminants and variant parts and how the values for those discriminants are obtained.
The Type_Model_Kinds type enumerates the three kinds of models. Descriptions of the characteristics of each model kind and examples of the type definitions defined by each model kind appear in the areas listed below.
You can use the Type_Model_Kind function to determine the type model kind for a particular type definition or component.
Click on a topic for more information:
Simple Static Types
Simple static types contain no variants and have a single fixed 'Size attribute value. All components and attributes are thus themselves static and/or fully constrained. The size and position of all components of the type can be determined without regard to constraints. For example:
type Static_Record is record F1, F2 : Natural; C1 : Character; A1 : String (1 .. 5); end record;
type Static_Discriminated (X : Boolean) is record F1, F2 : Natural; C1 : Character; end record;
type Static_Array is array (Integer range 1 .. 100) of Boolean;type Static_Enum is (One, Two, Three);type Static_Integer is range 1 .. 512;type Static_Float is digits 15 range -100.0 .. 100.0;type Static_Fixed is delta 0.1 range -100.0 .. 100.0;Note that simple static types can include discriminant associations (as in the Static_Discriminated record). The record cannot contain a variant part, however.
Simple Dynamic Types
Simple dynamic types contain one or more components or attributes whose size, position, or value depends on the value of one or more constraints assigned during execution. This means that the size, position, and number of components can be determined only by reference to the values of the constraints.
These types can be encoded correctly because the discriminant values are stored within an instance of the type, making them available at runtime for placement into the stream. For example:
type Dynamic_Length (Length : Natural) is record S1 : String (1 .. Length); end record;type Dynamic_Variant (When : Boolean) is record case When is When True => C1 : Character When False => null; end case; end record;Arrays with an unconstrained subtype, whose 'Length, 'First, and 'Last attribute values depend on dynamic index constraints, can also be processed because these attribute values can be obtained at runtime and can be placed in the data stream constructed from the array. For example:
I : Integer := Some_Function;type Dynamic_Array is array (Integer range I .. I + 10) of Boolean;type Heap_Array is array (Integer range <>) of Boolean;type Access_Array is access Heap_Array;X : Access_Array := new Heap_Array (1 .. 100);Complex Dynamic Types
Complex dynamic types contain components whose size or position depends on the values of externally defined, nonstatic values that are not stored within instances of the type. The attribute values for the components of an instance of these types cannot be determined without knowing these externally defined values.
These types cannot be encoded correctly because the values of the discriminants are not stored within an instance of the type, so they are not obtainable at runtime.
N : Natural := Some_Function;type Complex_Record is record S1 : String (1 .. N); end record;Component Properties
Uninitialized record and array component variables test as Is_Nil. An uninitialized component variable is both Is_Equal and Is_Identical to either the Nil_Record_Component or Nil_Array-_Component value, as appropriate.
Two component variables test as Is_Equal if they represent the same component, from the same record or array type, from the same compilation unit. The compilation units need not be from the same library.
Two component variables test as Is_Identical if they are Is_Equal and the compilation units have been obtained from the same library.
A component that represents an array subtype tests as Is_Array. A component that represents a record subtype tests as Is_Record. A component that represents a scalar type tests as neither Is_Array nor Is_Record.
Every non-nil component has an associated declaration. You can use the Component_Declaration function to obtain the ASIS element that represents the declaration.
Every component that tests as Is_Array has an associated subtype indication (Ada83 LRM 3.6(2), Ada95 LRM 3.6(2)). You can use the Subtype-
_Indication function to obtain the element that represents the indication.Obtaining Components and Nested Components
Ada supports a rich set of type-definition capabilities. This includes the ability to nest types, including record and array definitions, to essentially arbitrary depths. For example, a record definition can consist of composite elements, with each com-posite element consisting of its own composites, and so on.
To decompose a data stream of arbitrary complexity, you must be able to decompose the record structure itself. Three functions, described below, assist with decomposition. Each requires at least a type definition, record component, or array component and returns the constituent component or components.
1 If a simple dynamic model type is specified, a data stream containing appropriate discriminant values must be provided so that the correct variant components can be identified.
Each returned component can itself represent a record or array type. You can continue calling these functions to obtain nested components until a component represents a scalar type.
To obtain all the components of a record type definition, use the All_Named_Components function. This function returns an array of entity name definitions (see package Expressions, "Expression Kinds, Types, and Object Names"). One element is returned for each component in the record; the elements returned are not based on discriminant values.
The returned list allows you to quickly determine whether an element of a particular name exists anywhere within a record.
Accessing Array Elements
An array object is a composite object consisting of components that have the same subtype (Ada83 LRM 3.6(1), Ada95 LRM 3.6(1)). An array object is characterized by:
- The number of indices (the dimensionality of the array)
- The type and position of each index
- The lower and upper bounds for each index
- The type and possible constraint of the array elements
Arrays present special problems in decomposition. Unlike records, an array component does not describe a single value; it describes the entire array. There is one array element (value) for each index value, in each dimension, of an array.
Consider the following declarations:
type Team is (Home, Visitor);
type Quarter is range 1 .. 4;
type Scoring
is array (Home, Quarter) of Natural;
- Has two indices (a dimensionality of two).
Indices are represented by the Team and Quarter type, in that order. The Team type has a range of Home .. Visitor; the Quarter type has a range of 1 .. 4.
- Has array elements that are Natural values.
This array type definition is used to illustrate the three methods of array decomposition.
Click here for more information on array decomposition.
Array Decomposition
Arrays are decomposed in three ways. The only difference between the methods is how an array element is described, so each method has a corresponding data type. The methods and their associated types are described in these sections:
The following functions accept a dimensional index value, a linear index value, or an iterator and return information related to the identified element:
The Component_Data_Stream function provides the data stream corresponding to a particular component. The other functions provide attribute data for the component.
Dimensional Indexes
You can identify a particular element in an array by specifying a value for the index in each dimension of the array; this method is similar to standard Ada subscripting. The Dimension_Indexes type is used to specify the index values.
The Dimension_Indexes type is an array whose elements are Asis.Asis_Positive values. Each element in the array represents a dimension of the array being decomposed, and the value specifies the relative index value in that dimension.
Note: The range of any dimension's index value is 1 .. Array-_Length, not 'First .. 'Last. Index values are thus relative and not identical to the values that appear in your application. ASIS uses relative indexes because the actual index values might not be available to an application.
If you know what element you are interested in, you can initialize a Dimension_Indexes variable to the appropriate values. This variable, with the array component, then can be used to obtain the data stream or attribute information for the element.
The relationship between index values and dimensional index values is illustrated by the following:
Team Dimensional Index Values
Home (1, 1) (1, 2) (1, 3) (1, 4)
Visitor (2, 1) (2, 2) (2, 3) (2, 4)
Quarter 1 2 3 4
A method of iterating over all elements of an array is also provided (see "Iterators"). The dimensional index value of the element currently referenced by an iterator can be obtained with the Array_Indexes function. Iterators step the rightmost dimension's index value fastest.
Linear Indexes
A linear index value is an Asis.Asis_Positive number. The range of linear index values for any particular array is 1 .. N, where the upper bound is returned by the Array_Length function and represents the product of the lengths (the 'Length attribute value) of each dimension.
If you know what element you are interested in, you can initialize a variable to the appropriate linear index value. This variable, with the array component, then can be used to obtain the data stream or attribute information for the element.
The relationship between index values and linear index values is illustrated by the following:
Team Linear Index Values
Home (1) (2) (3) (4)
Visitor (5) (6) (7) (8)
Quarter 1 2 3 4
A method of iterating over all elements of an array is also pro-vided (see "Iterators"). The linear index value of the element currently referenced by an iterator can be obtained with the Array_Index function.
Iterators
The final method of accessing array elements is with an iterator.
Iterators are represented by the Array_Component_Iterator private type. An iterator either references an actual array element or references beyond all the elements of the array. If the reference is beyond the array, the iterator is said to be done.
The following subprograms are provided for the initialization, query, and control of iterators:
For information on using iterators, click here.
Using Iterators
- 1. . Initialize the iterator by calling the Array_Iterator function with an array component.
- 2. . Verify that the iterator has not exceeded the number of elements in the array by calling the Done function. The Done function returns True immediately after the initialization of an iterator if the array is a nil array.
- 3. . Use the iterator to obtain attribute or data-stream values.
- 4. . Step the iterator to the next element with the Next procedure.
Each iterator is independent and maintains its own state information. Iterators can be assigned to one another, and each iterator operates independently.
The order of array-element access with an iterator is illustrated by the following:
![]()
Runtime Representation Functions
The runtime representation functions return attribute information. The attribute values available and the corresponding function names are described in the following table:
Attribute Name Function Name References
'Length Array_Length LRM Annex A(24, 25),
13.6.2, and 3.8.2
'First_Bit First_Bit LRM Annex A(16) and
13.7.2
'Last_Bit Last_Bit LRM Annex A(23) and
13.7.2
'Position Position LRM Annex A(34) and
13.7.2
'Size Size LRM Annex A(41, 42) and 13.7.2
The above functions are overloaded, with several different parameter profiles, as indicated by the following table:
Function
NameType Definition Array/Record Component Array Iterator
Array_Length1 Y
First_Bit Y Y
Last_Bit Y Y
Position Y Y
Size Ya Y
1 If a simple dynamic model type is specified, a data stream containing appropriate discriminant values must be provided so that the correct variant components can be identified.
Constructing Artificial Data Streams
Variables typically are converted into data streams with the subprograms in package Portable_Transfer. These data streams represent actual data values and are typically used for subsequent component extraction and conversion. These data streams contain values for all appropriate discriminants and components.
If only attribute values are required, the only component values that need to exist in the stream are those that represent the discriminants. The discriminant values are all that is required to identify the appropriate variant parts and thus size and locate the components. The data streams that represent records partially defined in this way are called artificial data streams; they are constructed with the Construct_Artificial_Data_Stream function.
The construction of an artificial data stream is an iterative process and can require one call to Construct_Artificial_Data-_Stream for each discriminant in the record. For each call, a type definition, a data stream, a record component representing a discriminant, and the value for the discriminant must all be specified. The function returns a data stream with the discriminant value placed into the appropriate location. The initial call specifies a nil data stream; this directs the function to initialize the stream before installing the first discriminant value.
You need not specify all discriminant values; only those in the selected variant parts need be specified. It is good practice, however, to specify all values.
Decomposing Data Streams
Data streams can represent simple scalar values or complex records. The definitions of these structures can be decomposed with the functions that return the components (see "Obtaining Components and Nested Components"). With the component definitions, the component streams can be extracted with the Component_Data_Stream function.
Remember that a record or array component contains sufficient information to extract that component from a stream of the appropriate type. The resulting stream can in turn be described in terms of its components and similarly decomposed. This decomposition can continue until a scalar type is reached.
Decomposition is not required to convert a data stream into a value; the conversion can be performed at any point where a fully constrained subtype representing the value can be declared.
Converting Data Streams to Variables
Conversion of a data stream into a variable is accomplished with the Portable_Constrained_Subtype generic function. As is indicated by the name, the function works only if the actual parameter represents a constrained subtype. The actual parameter to the instantiation can represent a scalar type, such as System-.Integer, a simple static type, or a constrained instance of a simple dynamic type. The function converts the specified data stream into an instance of the type.
A common technique is to decompose a data stream to obtain the discriminant values needed to define the constrained sub-type. The constrained subtype is then defined, the generic is instantiated with this type, and the conversion is performed.
Depending on the implementation of the Portable_Constrained-_Subtype generic function and the compiler being used, conversion of a data stream to an inappropriate type can cause the Constraint_Error exception to be raised. Conversion of a data stream to an incorrect type or an incorrectly discriminated type can cause various runtime exceptions.
Rational Software Corporation
http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2001, Rational Software Corporation. All rights reserved. |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |