Wednesday, April 19, 2006

Sequence Declaration in IDL and its C++ mapping

CORBA IDL Series Continued (Part 6)

Sequences are also referred to as Templatized types. It is basically a one dimensional array with two exta characteritsics -
  1. Maximum size fixed at compile time
  2. Length which is determined at runtime
Sequences could be bounded or unbounded. For bounded sequences, the runtime length cannot be greater than the bounded sequence max length. If this is attempted in VisiBroker, BAD_PARAM exception is thrown.

Declaration in IDL

<sequence_type> ::= “sequence” “<” <simple_type_spec> “,”
<positive_int_const> “>”
| “sequence” “<” <simple_type_spec> “>”

C++ Mapping

Sequences map to a class in C++.

There are four types of constructors -
  1. Default Constructor
  2. Max Value Constructor
  3. Data Constructor
  4. Copy Constructor
Default constructor initializes length to 0 for both types of sequences. For unbounded sequences, max length is further initialized to 0. The release flag is set to true, meaning that the memory is owned by the sequence.

Max length constructor is only provided for unbounded sequences, which initializes the max length to the input parameter. Later however, if the length is increased or resized, this max length can be ignored. This is not provided for bounded sequences. The release flag is also true here.

Data constructor allows external data to be initialized into the sequence. This is called T* constructor. This constructor takes a pointer to an array of data, length of the input array, a max length for unbounded sequences and a release flag which suggests whether the sequence is to own the array or not. If the release flag is true, then the array should have been allocated using allocbuf() function call. The Sequence will then use the freebuf call to release the array.

Copy constructor initializes the new sequence with the same max length and length as that of the other array and then copies each element one by one and sets the release flag to true

Assignment operator similarly first deallocates each of the current content one by one and then makes a copy of the other sequence and sets the release flag to true

length() accessor and modifiers allow resizing the sequence.

maximum() returns the max length

Subscript operators operator[] is overloaded so that it can be used as both an lvalue and an rvalue. When used as lvalue, the data at the index is supposed to be written into.

There is an interesting case when the types contained in the sequence are string, wstring, any type of interface or valuetype. The issue occurs whenever, the allocbuf() function for the sequence is mapped to return a type T** instead of T* - is return an array of pointers instead of an array of objects. In this case, if the release flag is false, when using lvalue subscript operator, the mapping cant just deallocate the old contents. The mapping will automatically take care of this for the user. So, if the release flag is true, then the content is automatically deleted, otherwise not. This is illustrated in the following example -
// IDL
typedef sequence StringSeq;

// C++
char *static_arr[] = {"one", "two", "three"};
char **dyn_arr = StringSeq::allocbuf();
dyn_arr[0] = string_dup("one");
dyn_arr[1] = string_dup("two");
dyn_arr[2] = string_dup("three");
StringSeq seq1(3, static_arr);
StringSeq seq2(3, dyn_arr, TRUE);
seq1[1] = "2"; // no free, no copy
char *str = string_dup("2");
seq2[1] = str; // free old storage, no copy

get_buffer() and replace provide further capability to get the underlying content of the sequence and to replace the contents with new data.

Sequence_var

Sequence vars when assigned contant pointers to sequences do not duplicate the contents of the sequence but only increment the reference count.