As discussed in Section 5.4, SIDL supports both normal and raw arrays (i.e., r-arrays). Normal SIDL arrays can be used by any supported language; whereas, r-arrays are restricted to numeric types. This subsection discusses both within the context of C++ bindings.
Although it is feasible to expose the underlying C array API to create,
destroy and access normal array elements and meta-data, the C++ bindings
provide a sidl::array<T> template mechanism that is more in keeping
with C++ idioms.
For SIDL built-in types, template specializations of sidl::array<T>
are defined in sidl_ucxx.hxx.
The array template is specialized in the corresponding stub header for
SIDL interfaces and classes.
The extensive use of template specialization is used in an effort
to hide details that the array implementation shifts between
the C++ type externally, and the C-based types stored in the IOR.
(See basearray in sidl_ucxx.hxx for the traits classes
and grungy implementation details.)
For example, the process to create a one-dimensional SIDL array of prime
numbers is
int32_t len = 10; // array length=10 int32_t dim = 1; // one dimensional int32_t lower[1] = {0}; // zero offset int32_t upper[1] = {len-1}; int32_t prime = nextPrime(0); // create a SIDL array of primes. sidl::array<int32_t> a = sidl::array<int32_t>::createRow(dim, lower, upper); for( int i=0; i<len; ++i ) { prime = nextPrime( prime ); a.set(i, v); }
Of course, the example above is only one way to create an array. The list of member functions for all C++ array classes is:
// constructors array ( ior_array_t * src ); // internal array ( const array & src ); // copy constructor // destructor ~array() ; // create row-size of 1 to 7 dimensions static array<T> createRow( int32_t dimen, const int32_t lower[], const int32_t upper[]); // create column-wise of 1 to 7 dimensions static array<T> createCol( int32_t dimen, const int32_t lower[], const int32_t upper[]); // create 1-D array of specified length static array<T> create1d( int32_t len ); // create 1-D array of specified length and init static array<T> create1d(int32_t len, ior_item_internal_t data) // create 2-D array of specified extents static array<T> create2dCol( int32_t m, int32_t n); // create 2-D array of specified extents static array<T> create2dRow( int32_t m, int32_t n); // get a slice of the array array<T> slice( int32_t dimen, const int32_t numElem[], const int32_t *srcStart = 0, const int32_t *srcStride = 0, const int32_t *newStart = 0); void borrow( item_ior_t * first_element, int32_t dimen, const int32_t lower[], const int32_t upper[], const int32_t stride[]); void ensure( int32_t dimen, array_ordering ordering ); void addRef(); void deleteRef(); // get/set cxx_item_t get(int32_t i); cxx_item_t get(int32_t i1, int32_t i2); cxx_item_t get(int32_t i1, int32_t i2, int32_t i3); cxx_item_t get(int32_t i1, int32_t i2, int32_t i3, int32_t i4); cxx_item_t get(int32_t i1, int32_t i2, int32_t i3, int32_t i4, int32_t i5); cxx_item_t get(int32_t i1, int32_t i2, int32_t i3, int32_t i4, int32_t i5, int32_t i6); cxx_item_t get(int32_t i1, int32_t i2, int32_t i3, int32_t i4, int32_t i5, int32_t i6, int32_t i7); cxx_item_t get(const int32_t *indices); void set(int32_t i, cxx_item_t elem); void set(int32_t i1, int32_t i2, cxx_item_t elem); void set(int32_t i1, int32_t i2, int32_t i3, cxx_item_t elem); void set(int32_t i1, int32_t i2, int32_t i3, int32_t i4, cxx_item_t elem); void set(int32_t i1, int32_t i2, int32_t i3, int32_t i4, int32_t i5, cxx_item_t elem); void set(int32_t i1, int32_t i2, int32_t i3, int32_t i4, int32_t i5, int32_t i6, cxx_item_t elem); void set(int32_t i1, int32_t i2, int32_t i3, int32_t i4, int32_t i5, int32_t i6, int32_t i7, cxx_item_t elem); void set(const int32_t *indices, cxx_item_t elem); // [] overloaded to be same as get(i) cxx_item_t operator[](int32_t i) const ; bool is1dPacked() const; // returns STL forward iterator iff 1DPacked, else null iterator begin(); // returns STL forward iterator iff 1DPacked, else null const_iterator begin(); // returns STL forward iterator iff 1DPacked, else null iterator end(); // returns STL forward iterator iff 1DPacked, else null const_iterator end(); const int32_t* first() const; int32_t* first(); void copy( const array< T >& src ); // other accessors int32_t dimen() const; int32_t lower( int32_t dim ) const; int32_t upper( int32_t dim ) const; int32_t stride( int32_t dim ) const; bool _is_nil() const; bool _not_nil() const; // get a const pointer to the actual array ior const array_ior_t* _get_ior() const; // get a non-const pointer to the actual array ior array_ior_t* _get_ior(); void _set_ior( ior_array_t * s); array& operator =(const array &rhs); array& operator =(const basearray &rhs);
where
cxx_array_t,
cxx_item_t,
ior_array_t,
ior_item_t,
ior_item_internal_t,
iterator,
const_iterator,
pointer, and
value_type are all public typedefs in the array class.
Table 5.3 provides a brief description of each
function in the array API.
The values of these typedefs are determined by traits classes, which are a fairly standard, albeit advanced, C++ templating idiom. Refer to any advanced C++ text for a detailed explanation. Both the array_traits<> and array<> template specializations for int32_t are reproduced below. More built-in types and the UCxx stubs for user-defined types can be found in sidl_ucxx.hxx.
// template specialization for array_traits<int32_t> template<> struct array_traits<int32_t> { typedef array<int32_t> cxx_array_t; typedef int32_t cxx_item_t; typedef struct sidl_int__array ior_array_t; typedef int32_t ior_item_t; typedef const int32_t* ior_item_internal_t; typedef cxx_item_t value_type; typedef value_type* pointer; typedef const value_type* const_pointer; }; template<> class array< int32_t > : public basearray { public: typedef basearray Base; typedef array_traits<int32_t>::cxx_array_t cxx_array_t; typedef array_traits<int32_t>::cxx_item_t cxx_item_t; typedef array_traits<int32_t>::ior_array_t ior_array_t; typedef array_traits<int32_t>::ior_item_t ior_item_t; typedef array_traits<int32_t>::ior_item_internal_t ior_item_internal_t; typedef array_iter< array_traits<int32_t> > iterator; typedef const_array_iter< array_traits<int32_t> > const_iterator; typedef array_traits< int32_t > ::pointer pointer; typedef array_traits< int32_t > ::value_type value_type; // lots of methods to follow }
The C++ mapping for r-arrays is essentially identical to the mapping for C (see Section 6.2.3). The only difference is that the C++ client header provides an overloaded version of each method containing an r-array taking normal SIDL arrays instead of raw data. For example, the solve method from Section 5.4 produces the following code in the header file.
void solve (/*in*/ double* A, /*inout*/ double* x, /*in*/ double* b, /*in*/ int32_t m, /*in*/ int32_t n) throw (); void solve (/*in*/ ::sidl::array<double> A, /*inout*/ ::sidl::array<double>& x, /*in*/ ::sidl::array<double> b) throw();
Multi-dimensional arrays, such as A in the above example, are stored in column-major order. Babel provides macros to access r-array data correctly. In this case, for example, RarrayElem2(A, i, j, m) can be used to access the element in row i and column j. In addition, memory can be accessed by stride one by making the row index the inner loop and the column index the outer. Similar macros are available in sidlArray.h for arrays of dimension 1 through 7.