C++ bindings for CORBA Sequence types

An Interface Definition Language (IDL) sequence type is mapped to a C++ class that behaves like an array with a current length (how many elements are stored) and a maximum length (how much storage is currently allocated). The array indexing operator [] is used to read and write sequence elements. The indexing begins at zero. It is the programmer's responsibility to check the current sequence length to prevent accessing the sequence beyond its bounds. The length and maximum of the sequence are not increased automatically to accommodate new elements; the programmer must explicitly increase them.

There are two kinds of sequences: bounded and unbounded. A bounded sequence has a maximum length that is part of the IDL sequence type and cannot be changed. An unbounded sequence has a flexible maximum length that can be set during construction and modified during processing. In either case, the maximum length determines the amount of buffer storage used by the sequence to hold its elements.

The sequence class contains a member function ULong length() to query the number of elements in the sequence. Another member function, length(ULong newLength), indicates the number of elements in the sequence. Increasing the length causes new elements to be added to the end of the sequence. These new elements are default constructed (similar to the default construction of fields for an IDL struct). Decreasing the length causes the elements at the end of the seqence to be released (if the sequence owns the buffer). The length of a bounded sequence cannot exceed the maximum length. If the length of an unbounded sequence is increased past the maximum, the sequence allocates a new buffer and copies the sequence elements to the new buffer.

The buffer, used by the sequence, can either be managed (owned) by the sequence or managed by the client code. By default, the sequence manages its own storage. The release() method indicates whether the sequence manages the buffer (release() returns TRUE if the sequence manages the buffer). Under most circumstances, it is advisable to let the sequence manage its own buffer.

There are a number of methods available to control the management of the sequence's buffer. The programmer must allocate a buffer using the allocbuf function. The allocated buffer is given to the sequence using either the specialized constructor seq(ULong max, ULong length, Data* buffer, Boolean release) or the replace(ULong max, ULong length, Data* buffer, Boolean release) method. During processing, the programmer can query the buffer directly using the const Data* get_buffer() const method or can modify the buffer using the Data* get_buffer(Boolean orphan) method. If the orphan flag is set to TRUE, the sequence yields ownership of the buffer to the client.

The destructor destroys each of the sequence elements if the sequence owns the buffer.

The copy constructor creates a new sequence with the same maximum and length as the input sequence and copies the sequence elements to the storage that the sequence owns. The assignment operator performs a deep copy and releases the previous sequence elements, if the sequence owns the buffer. This operator behaves as if the destructor was run and is followed by the copy constructor.

The allocbuf function allocates enough storage for the specified number of sequence elements. Each sequence element is initialized using its default constructor. The string elements are initialized to the empty string and the object reference elements are initialized to nil object references. NULL is returned if the storage cannot be allocated for any reason. If ownership of the allocated buffer is not transferred to a sequence, the buffer should be subsequently freed using the freebuf function. The freebuf function ensures the following before the buffer is deleted:

Neither allocbuf nor freebuf throw CORBA exceptions.

As with structs, sequences use special auxiliary classes for automatic storage management of string and object reference elements. These auxiliary classes manage strings and object references just as the associated _var classes do.

If a storage-managed sequence's elements are object references, assignment to an element (using operator[]) automatically releases the previous value. If the source of the assignment is an object reference pointer, the sequence assumes ownership of the pointer and no _duplicate is done. If the source is an object reference (_var object, struct field, array element, etc.), a _duplicate is done automatically.

If a storage-managed sequence's elements are strings, assignment to an element (using operator[]) automatically frees the previous string. As with assigning to String_vars, assigning a char* to a string element does not make a copy, but assigns a const char *, a String_var, or another struct, union, array, sequence. A string member automatically makes a copy. Thus, never assign a string literal (such as "abc") to an element without an explicit cast to const char*. When assigning a char* that occupies static storage (rather than one that was dynamically allocated), the caller can use CORBA::string_dup to duplicate the string before assigning it.

There is a corresponding _var type defined for every sequence class.The _var type for a sequence provides an overloaded operator[] that delegates to the underlying sequence.

The following example illustrates loading and accessing the elements of a sequence. It illustrates a recursive sequence whose entries are structs of the same type that contain the sequence. The IDL that follows is used in the succeeding example:

struct S 
{
   long sf1;
   sequence sf2;
};
typedef sequence Sseq;

The following is an example program that creates and loads a sequence of type Sseq and then prints out its contents:

#include seq_C.cpp
#include stdio.h
main()
{
   int i,j;
   Sseq seq;      // create an Sseq
   seq.length(3); // set length of seq to 3
   for (i=0; i<3; i++) { // index the three S structs in seq
   seq[i].sf1 = i;    // place a number in the i-indexed struct
   seq[i].sf2.length(i+1); // set length of the sequence in
   //   the i-indexed struct
   for (j=0; j<i+1; j++) // index the i+1 S structs in the sequence
   //  in the i-indexed struct
   seq[i].sf2[j].sf1 = (i+1)*10+j; // place a number in 
   //   the j-indexed struct 
}
// OK. Print out what you have created!
printf("seq = (%d sequence elements)\n", seq.length());
for (i=0; i<3; i++) 
{
   printf("   struct[%d] = {\n", i);
   printf("      sf1 = %d\n", seq[i].sf1);
   printf("      sf2 = (%d sequence elements)\n",
   seq[i].sf2[j].length());
   for (j=0; j<i+1; j++)  
   {
      printf("         struct[%d] = \n",j);
      printf("            sf1 = %d\n", seq[i].sf2[j].sf1);
      printf("            sf2 = (%d sequence elements)\n",
      seq[i].sf2[j].sf2.length());
      printf("         }\n");
      }
   printf("   }\n");
   }
} 

Note: The previous program never explicitly constructs any data of type S, even though the sequences contain structs of this type. The reason is that when a sequence buffer is allocated, default constructors are run for each of the buffer elements. When the previous program sets the length of a sequence of S structs (either at the top level for the seq variable or for the sf2 field of an S struct in seq), the resulting buffer is populated automatically with default structs of type S.

The output from the previous program is:

seq = (3 sequence elements)
   struct[0] = {
      sf1 = 0
      sf2 = (1 sequence elements)
         struct[0] = {
            sf1 = 10
            sf2 = (0 sequence elements)
         }
   }
   struct[1] = {
      sf1 = 1
      sf2 = (2 sequence elements)
         struct[0] = {
            sf1 = 20
            sf2 = (0 sequence elements)
         }
         struct[1] = {
            sf1 = 21
            sf2 = (0 sequence elements)
         }   
   }
   struct[2] = {
      sf1 = 2
      sf2 = (3 sequence elements)
         struct[0] = {
            sf1 = 30
            sf2 = (0 sequence elements)
         }
         struct[1] = {
            sf1 = 31
            sf2 = (0 sequence elements)
         }
         struct[2] = {
            sf1 = 32
            sf2 = (0 sequence elements)
         }
   }


Related reference
CORBA C++ bindings for data types



Searchable topic ID:   rcor_copseq
Last updated: Jun 21, 2007 8:07:48 PM CDT    WebSphere Business Integration Server Foundation, Version 5.0.2
http://publib.boulder.ibm.com/infocenter/wasinfo/index.jsp?topic=/com.ibm.wasee.doc/info/ee/corba/ref/rcor_copseq.html

Library | Support | Terms of Use | Feedback