A descriptor array is a mechanism which allows descriptors to be aggregated in a convenient way.
Descriptor arrays build on the behaviour supplied by the Dynamic Arrays API and provides normal array operations for inserting, appending, deleting, and accessing elements.
There are two types of descriptor array, based on the way data is represented by the array:
an array whose elements consist of non-modifiable pointer descriptors.
an array whose elements consist of memory pointers.
Either array can be used to represent descriptor data. The difference between them is based on the way they are implemented, and this determines which one is most suitable for a given situation.
NOTE: All
array classes are provided in variants for narrow and wide characters (for
example, CDesC8Array
and CDesC16Array
).
These concrete types can be used directly, but it is usual to use typedefs
(for example, CDesCArray) that are conditionally defined
to map to the wide or narrow characters depending on the build. Only the conditional
types are used below.
Descriptor arrays has three key concepts - descriptor
array protocol (MDesC16Array
), general descriptor array (CDesC16Array
)
and pointer descriptor array (CPtrC16Array
).
Descriptor array protocol
This array defines an interface implemented by all descriptor array classes, and hence provides a degree of polymorphism. It provides a count function, and can return a TPtrC for an indexed element.
The interface is defined by MDesCArray.
General descriptor array
This array accepts elements of any descriptor type. For each descriptor added, it creates a new heap descriptor (HBufC) and copies the contents into it.
The base class is CDesCArray. Derived classes provide storage in flat arrays (CDesCArrayFlat) and segmented arrays (CDesCArraySeg).
Pointer descriptor array
This array holds only TPtrC descriptor elements, that is, the descriptor type that points to data stored elsewhere. The data pointed to by the TPtrC descriptors is not copied or moved.
The pointer descriptor array is CPtrCArray. It implements MDesCArray, and can be used polymorphically with general descriptor arrays.
The array is supplied in two variants:
the 16-bit variant CPtrC16Array
containing TPtrC16
types.
the 8-bit variant CPtrC8Array
containing TPtrC8
types.
The array is also supplied as a build independent type, CPtrCArray.
This is used whenever the descriptor elements are used to represent text strings.
By using the build independent type, the appropriate variant, either 16-bit
or 8-bit, is selected at build time depending on whether the _UNICODE
macro
has been defined or not.
Binary data always requires the 8-bit variant, regardless of the build, and this should be explicitly used in program code.
Explicit use of the 16-bit variant is rare.
The elements of this type of array
consist of non-modifiable pointer descriptors. These pointer descriptors represent
the data of the descriptors added to the array. The following diagram illustrates
this. The diagram is also true for TPtrC8
and TPtrC16
.
Figure: Array of non-modifiable pointer descriptor elements
NOTE: delete() and reset() removes the non-modifiable pointer descriptors from the array but does not delete the data or descriptors that they point to.
The elements of this type of array consist of pointers to heap descriptors.
When
a descriptor is added to this type of array, a heap descriptor is allocated,
taking its data from the supplied descriptor. The pointer to this heap descriptor
is added as an array element. The following diagram illustrates this. The
diagram is also true for HBufC8
and HBufC16
.
Figure: Array of pointer elements
There are two implementations of the array, one using a flat buffer and the other using a segmented buffer.
The flat buffer implementation is supplied in two variants:
the 16-bit variant implemented
using a flat buffer, a CDesC16ArrayFlat
, constructed from TDesC16
types.
the 8-bit variant implemented
using a flat buffer, a CDesC8ArrayFlat
, constructed from TDesC8
types.
The segmented buffer implementation is supplied in two variants:
the 16-bit variant implemented
using a segmented buffer, a CDesC16ArraySeg
, constructed
from TDesC16
types.
the 8-bit variant implemented
using a segmented buffer, a CDesC8ArraySeg
, constructed
from TDesC8
types.
Both array implementations are also supplied as build independent
types, CDesCArrayFlat and CDesCArraySeg.
These are used whenever the descriptors are used to represent text strings.
By using the build independent types, the appropriate variants, either 16-bit
or 8-bit, are selected at build time depending on whether the _UNICODE
macro
has been defined or not.
Binary data always requires the 8-bit variants, regardless of the build, and this should be explicitly used in program code.
Explicit use of the 16-bit variants is rare.
NOTE: delete() and reset() removes the pointers from the array and also deletes the heap descriptors that they point to.
The advantages of using one type over the other are subtle.
When using an array of non-modifiable pointer descriptors, the data represented by each TPtrC exists independently of the TPtrC itself. The memory required by the array is that required to contain the TPtrC elements. The data represented by the TPtrC descriptors is not copied or moved. On the other hand, that same data must be guaranteed to remain in memory if the array is to have any purpose.
When using an array of pointers, a new heap descriptor is allocated for each descriptor to be added to the array. This increases the total memory requirements of the array. On the other hand, each array element is smaller because the size of a pointer is slightly smaller than the size of a TPtrC object. The original descriptor data can also be safely discarded once it has been added to the array.
This type also has the advantage that there is no commitment to a concrete descriptor type.
The following diagram illustrates the relationship between the descriptor array concrete classes and the base classes which support them.
Figure: The class relationships for CDesCArrayFlat & CDesCArraySeg
Figure: The class relationships for CPtrCArray
An array of non-modifiable pointer descriptors, a CPtrCArray type, provides a function which can copy elements from any descriptor array.
The source descriptor array must be one which satisfies the protocol defined by the MDesCArray mixin class. Add the new TPtrC elements to the CPtrCArray array to represent the source data.
The implementation of the copy does not and cannot depend on the type of the source descriptor array,that is, whether it is a CPtrCArray type or a CDesCArray type. However, the following diagram shows the effect of the copy operation based on the concrete type of the source array.
Figure: Copying descriptor arrays
Descriptor arrays are supplied in two variants:
the 16-bit variant for 16-bit descriptors. These descriptors are used for handling Unicode strings and double byte valued data.
the 8-bit variant for 8-bit variant descriptors. These descriptors are used for handling non-Unicode strings and single byte valued data. (binary data).
Descriptor arrays are also supplied as build independent types. These are used for descriptors which are used to represent text strings.
By
using build independent types, the appropriate variant, either 16-bit or 8-bit,
is selected at build time depending on whether the _UNICODE
macro
has been defined or not.
Binary data always requires the 8-bit variant regardless of the build, and it must be explicitly used in program code. Explicit use of the 16-bit variant is rare. With a few exceptions, the behaviour of both 8-bit and 16-bit variants is the same.
The MDesCArray
class is a mixin which
defines a protocol for:
returning the number of elements in a descriptor array
returning a non-modifiable pointer descriptor, a TPtrC type representing a specific indexed element.
The use of the mixin permits a degree of polymorphism amongst the descriptor array classes. It permits the number of descriptor array elements to be returned and a TPtrC type for a specific descriptor array element to be returned without knowing the specific concrete descriptor array type being accessed.
The following code fragments illustrate how the MDesCArray mixin class is used to return:
the number of descriptor elements in a descriptor array.
a TPtrC representing a specific indexed descriptor element.
The code uses the build independent forms but the code is equally valid while using the explicit 8-bit or 16-bit variants.
In this case, CDesCArrayFlat, CDesCArraySeg and CPtrCArray can be handled by the single function foo()
.
... CDesCArrayFlat* descflat = new( ELeave ) CDesCArrayFlat( 4 ); CDesCArraySeg* descseg = new( ELeave ) CDesCArraySeg( 4 ); CPtrCArray* ptrc = new( ELeave ) CPtrCArray( 4 ); ... ... // add descriptor elements to all three arrays ... foo( descflat ); foo( descseg ); foo( ptrc ); ...
void foo( MDesCArray* anArray ) { .. TInt somenumber = anArray->MdcaCount(); TPtrC someptrc = anArray->MdcaPoint( someindexvalue ); .. }