Generic_Sequence_T.h

Go to the documentation of this file.
00001 #ifndef guard_generic_sequence_hpp
00002 #define guard_generic_sequence_hpp
00003 /**
00004  * @file
00005  *
00006  * @brief Implement the generic version of CORBA sequences.
00007  *
00008  * All CORBA sequences are based on this class template.  The behavior
00009  * of this class is controlled by two sets of traits.  First, the
00010  * ALLOCATION_TRAITS control how buffers are allocated and
00011  * initialized.  Since this is where most of the variation between
00012  * unbounded and bounded sequences is found, the ALLOCATION_TRAITS can
00013  * be thought as the bounded aspect of the sequence.
00014  *
00015  * Second, the element traits control how are elements copied,
00016  * initialized and released.  Value-like types, such as integers and
00017  * structures, have trivial initialization and release requirements
00018  * (their constructor/destructors do the job!)   But reference-like
00019  * types, such as strings and object references, have more complicated
00020  * requirements.  This is yet another aspect of the sequences, we can
00021  * call it the "element copy semantics" or something.
00022  *
00023  * Oh, and let us not forget the type that the sequences encapsulates.
00024  *
00025  * The intent is not for sequences to simply derive or instantiate this
00026  * type.  Instead, different each sequence type is written using
00027  * composition.  They instantiate a generic sequence with the correct
00028  * traits, and implement the adapt the generic sequence interface to
00029  * whatever requirements the spec may impose.  For example, replace()
00030  * has different number of arguments in bounded vs. unbounded
00031  * sequences, and operator[] returns different types depending on the
00032  * underlying type of the sequence.
00033  *
00034  * This class offers the strong exception-safety guarantee, as long as
00035  * destructors and release operations do not throw.
00036  *
00037  * This class is not thread-safe.  Thread-safe collections are mostly
00038  * useless anyways.
00039  *
00040  * In general the performance characteristics of the class depends on
00041  * the traits.  Obviously, they can only be expressed on the number of
00042  * element constructor and destructor calls.  If the constructor takes
00043  * O(K) time that is not the sequence fault!
00044  *
00045  * All accessors are O(1), single-element modifiers are O(1), multiple
00046  * element modifiers are O(n + m) where n is the number of elements
00047  * originally in the sequence, and m is the number of elements left in
00048  * the sequence afterwards.
00049  *
00050  * Beware:
00051  * - get_buffer(true) may modify multiple elements
00052  * - length(CORBA::ULong) may modify multiple elements!
00053  *
00054  * Generic_Sequence_T.h,v 1.3 2006/05/11 10:33:49 jwillemsen Exp
00055  *
00056  * @author Carlos O'Ryan
00057  */
00058 
00059 #include "tao/Range_Checking_T.h"
00060 
00061 #include <algorithm>
00062 
00063 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00064 
00065 namespace TAO
00066 {
00067 namespace details
00068 {
00069 
00070 template<typename T,
00071          class ALLOCATION_TRAITS,
00072          class ELEMENT_TRAITS>
00073 class generic_sequence
00074 {
00075 public:
00076   typedef T value_type;
00077   typedef ALLOCATION_TRAITS allocation_traits;
00078   typedef ELEMENT_TRAITS element_traits;
00079   typedef range_checking<value_type,true> range;
00080 
00081   /// Default constructor.
00082   generic_sequence()
00083     : maximum_(allocation_traits::default_maximum())
00084     , length_(0)
00085     , buffer_(allocation_traits::default_buffer_allocation())
00086     , release_(true)
00087   {
00088   }
00089 
00090   /// Constructor with control of ownership.
00091   explicit generic_sequence(CORBA::ULong maximum)
00092     : maximum_(maximum)
00093     , length_(0)
00094     , buffer_(allocbuf(maximum_))
00095     , release_(true)
00096   {
00097   }
00098 
00099   generic_sequence(
00100       CORBA::ULong maximum,
00101       CORBA::ULong length,
00102       value_type * data,
00103       CORBA::Boolean release)
00104     : maximum_(maximum)
00105     , length_(length)
00106     , buffer_(data)
00107     , release_(release)
00108   {
00109   }
00110 
00111   /// Copy constructor
00112   generic_sequence(generic_sequence const & rhs)
00113     : maximum_(0)
00114     , length_(0)
00115     , buffer_(0)
00116     , release_(false)
00117   {
00118     generic_sequence tmp(rhs.maximum_);
00119     tmp.length_ = rhs.length_;
00120     element_traits::copy_range(
00121         rhs.buffer_, rhs.buffer_ + rhs.length_, tmp.buffer_);
00122     swap(tmp);
00123   }
00124 
00125   /// Assignment operator
00126   generic_sequence & operator=(generic_sequence const & rhs)
00127   {
00128     generic_sequence tmp(rhs);
00129     swap(tmp);
00130     return * this;
00131   }
00132 
00133   /// Destructor.
00134   ~generic_sequence()
00135   {
00136     if (release_)
00137     {
00138       freebuf(buffer_);
00139     }
00140   }
00141 
00142   /// Return the maximum length of the sequence
00143   inline CORBA::ULong maximum() const
00144   {
00145     return maximum_;
00146   }
00147 
00148   /// Returns the state of the sequence release flag.
00149   inline CORBA::Boolean release() const
00150   {
00151     return release_;
00152   }
00153 
00154   /// Returns the length of the sequence
00155   inline CORBA::ULong length() const
00156   {
00157     return length_;
00158   }
00159 
00160   /// Set a new length for the sequence
00161   void length(CORBA::ULong length)
00162   {
00163     if (length <= maximum_ || length <= length_)
00164     {
00165       if (length_ < length)
00166       {
00167         // TODO This code does not provide the strong-exception
00168         //      guarantee, but it does provide the weak-exception
00169         //      guarantee.  The problem would appear when
00170         //      initialize_range() raises an exception after several
00171         //      elements have been modified.  One could argue that
00172         //      this problem is irrelevant, as the elements already
00173         //      modified are unreachable to conforming applications.
00174         element_traits::initialize_range(
00175             buffer_ + length_, buffer_ + length);
00176       }
00177       length_ = length;
00178       return;
00179     }
00180 
00181     generic_sequence tmp(length);
00182     tmp.length_ = length;
00183     element_traits::copy_range(
00184         buffer_, buffer_ + length_, tmp.buffer_);
00185     element_traits::initialize_range(
00186         tmp.buffer_ + length_, tmp.buffer_ + length);
00187 
00188     swap(tmp);
00189   }
00190 
00191   /// Get a const element from the sequence
00192   value_type const & operator[](CORBA::ULong i) const
00193   {
00194     range::check(i, length_, maximum_, "operator[]() const");
00195     return buffer_[i];
00196   }
00197 
00198   /// Get an element from the sequence
00199   value_type & operator[](CORBA::ULong i)
00200   {
00201     range::check(i, length_, maximum_, "operator[]() non-const");
00202     return buffer_[i];
00203   }
00204 
00205   /**
00206    * Allows the buffer underlying a sequence to be replaced.  The
00207    * parameters to replace() are identical in type, order, and purpose
00208    * to those for the <T *data> constructor for the sequence.
00209    */
00210   void replace(
00211       CORBA::ULong maximum,
00212       CORBA::ULong length,
00213       value_type * data,
00214       CORBA::Boolean release)
00215   {
00216     generic_sequence tmp(maximum, length, data, release);
00217     swap(tmp);
00218   }
00219 
00220   /**
00221    * This function allows read-only access to the sequence buffer.
00222    * The sequence returns its buffer, allocating one of one has not
00223    * yet been allocated.  No direct modification of the returned
00224    * buffer by the caller is permitted.
00225    */
00226   value_type const * get_buffer() const
00227   {
00228     if (buffer_ == 0)
00229     {
00230       buffer_ = allocbuf(maximum_);
00231     }
00232     return buffer_;
00233   }
00234 
00235   /// Allows read-write access to the underlying buffer.
00236   /**
00237    * If @a orphan is FALSE the sequence returns a pointer to its buffer,
00238    * allocating one if it has not yet done so.  The number of elements in the
00239    * buffer can be determined from the sequence length() accessor.
00240    *
00241    * If the @a orphan argument to get_buffer() is FALSE, the sequence
00242    * maintains ownership of the underlying buffer.  Elements in the
00243    * returned buffer may be directly replaced by the caller.  For
00244    * sequences of strings, wide strings, and object references, the
00245    * caller must use the sequence <release> accessor to determine
00246    * whether elements should be freed (using <string_free>,
00247    * <wstring_free>, or <CORBA::release> for strings, wide strings,
00248    * and object references, respective) before being directly assigned
00249    * to.
00250    *
00251    * If the @a orphan argument to @a get_buffer is TRUE, the sequence
00252    * yields ownership of the buffer to the caller.  If @a orphan is
00253    * TRUE and the sequence does not own its buffer (i.e., its
00254    * release_ flag is FALSE), the return value is a null pointer.  If
00255    * the buffer is taken from the sequence using this form of
00256    * get_buffer(), the sequence reverts to the same state it would
00257    * have if constructed using its default constructor.  The caller
00258    * becomes responsible for eventually freeing each element of the
00259    * returned buffer (for strings, wide string, and object
00260    * references), and then freeing the returned buffer itself using
00261    * freebuf().
00262    */
00263   value_type * get_buffer(CORBA::Boolean orphan)
00264   {
00265     if (orphan && !release_)
00266     {
00267       return 0;
00268     }
00269     if (buffer_ == 0)
00270     {
00271       buffer_ = allocbuf(maximum_);
00272     }
00273     if (!orphan)
00274     {
00275       return buffer_;
00276     }
00277 
00278     generic_sequence tmp;
00279     swap(tmp);
00280     tmp.release_ = false;
00281 
00282     return tmp.buffer_;
00283   }
00284 
00285   void swap(generic_sequence & rhs) throw()
00286   {
00287     std::swap(maximum_, rhs.maximum_);
00288     std::swap(length_, rhs.length_);
00289     std::swap(buffer_, rhs.buffer_);
00290     std::swap(release_, rhs.release_);
00291   }
00292 
00293   static value_type * allocbuf(CORBA::ULong maximum)
00294   {
00295     return allocation_traits::allocbuf(maximum);
00296   }
00297 
00298   static void freebuf(value_type * buffer)
00299   {
00300     allocation_traits::freebuf(buffer);
00301   }
00302 
00303 private:
00304   /// The maximum number of elements the buffer can contain.
00305   CORBA::ULong maximum_;
00306   /// The current number of elements in the buffer.
00307   CORBA::ULong length_;
00308   /// The buffer with all the elements
00309   mutable value_type * buffer_;
00310   /// If true then the sequence should release the buffer when it is
00311   /// destroyed.
00312   CORBA::Boolean release_;
00313 };
00314 
00315 } // namespace details
00316 } // namespace TAO
00317 
00318 TAO_END_VERSIONED_NAMESPACE_DECL
00319 
00320 #endif // guard_generic_sequence_hpp

Generated on Thu Nov 9 11:54:11 2006 for TAO by doxygen 1.3.6