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  * $Id: Generic_Sequence_T.h 79667 2007-09-20 07:13:20Z johnnyw $
00055  *
00056  * @author Carlos O'Ryan
00057  */
00058 
00059 #include "tao/Range_Checking_T.h"
00060 #include "ace/checked_iterator.h"
00061 
00062 #include <algorithm>
00063 
00064 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00065 
00066 namespace TAO
00067 {
00068 namespace details
00069 {
00070 
00071 template<typename T,
00072          class ALLOCATION_TRAITS,
00073          class ELEMENT_TRAITS>
00074 class generic_sequence
00075 {
00076 public:
00077   typedef T value_type;
00078   typedef ALLOCATION_TRAITS allocation_traits;
00079   typedef ELEMENT_TRAITS element_traits;
00080   typedef range_checking<value_type,true> range;
00081 
00082   /// Default constructor.
00083   generic_sequence()
00084     : maximum_(allocation_traits::default_maximum())
00085     , length_(0)
00086     , buffer_(allocation_traits::default_buffer_allocation())
00087     , release_(buffer_ != 0)
00088   {
00089   }
00090 
00091   /// Constructor with control of ownership.
00092   explicit generic_sequence(CORBA::ULong maximum)
00093     : maximum_(maximum)
00094     , length_(0)
00095     , buffer_(allocbuf(maximum_))
00096     , release_(true)
00097   {
00098   }
00099 
00100   generic_sequence(
00101       CORBA::ULong maximum,
00102       CORBA::ULong length,
00103       value_type * data,
00104       CORBA::Boolean release)
00105     : maximum_(maximum)
00106     , length_(length)
00107     , buffer_(data)
00108     , release_(release)
00109   {
00110   }
00111 
00112   /// Copy constructor
00113   generic_sequence(generic_sequence const & rhs)
00114     : maximum_(0)
00115     , length_(0)
00116     , buffer_(0)
00117     , release_(false)
00118   {
00119     if (rhs.maximum_ == 0) return;
00120     generic_sequence tmp(rhs.maximum_);
00121     tmp.length_ = rhs.length_;
00122     element_traits::copy_range(
00123         rhs.buffer_,
00124         rhs.buffer_ + rhs.length_,
00125         ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
00126     swap(tmp);
00127   }
00128 
00129   /// Assignment operator
00130   generic_sequence & operator=(generic_sequence const & rhs)
00131   {
00132     generic_sequence tmp(rhs);
00133     swap(tmp);
00134     return * this;
00135   }
00136 
00137   /// Destructor.
00138   ~generic_sequence()
00139   {
00140     if (release_)
00141     {
00142       freebuf(buffer_);
00143     }
00144   }
00145 
00146   /// Return the maximum length of the sequence
00147   inline CORBA::ULong maximum() const
00148   {
00149     return maximum_;
00150   }
00151 
00152   /// Returns the state of the sequence release flag.
00153   inline CORBA::Boolean release() const
00154   {
00155     return release_;
00156   }
00157 
00158   /// Returns the length of the sequence
00159   inline CORBA::ULong length() const
00160   {
00161     return length_;
00162   }
00163 
00164   /// Set a new length for the sequence
00165   void length(CORBA::ULong length)
00166   {
00167     if (length <= maximum_ || length <= length_)
00168     {
00169       if (buffer_ == 0)
00170         {
00171           buffer_ = allocbuf(maximum_);
00172           release_ = true;
00173         }
00174 
00175       if (length_ < length)
00176       {
00177         // TODO This code does not provide the strong-exception
00178         //      guarantee, but it does provide the weak-exception
00179         //      guarantee.  The problem would appear when
00180         //      initialize_range() raises an exception after several
00181         //      elements have been modified.  One could argue that
00182         //      this problem is irrelevant, as the elements already
00183         //      modified are unreachable to conforming applications.
00184         element_traits::initialize_range(
00185             buffer_ + length_, buffer_ + length);
00186       }
00187       length_ = length;
00188       return;
00189     }
00190 
00191     generic_sequence tmp(length);
00192     tmp.length_ = length;
00193     element_traits::copy_range(
00194       buffer_,
00195       buffer_ + length_,
00196       ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
00197     element_traits::initialize_range(
00198         tmp.buffer_ + length_, tmp.buffer_ + length);
00199 
00200     swap(tmp);
00201   }
00202 
00203   /// Get a const element from the sequence
00204   value_type const & operator[](CORBA::ULong i) const
00205   {
00206     range::check(i, length_, maximum_, "operator[]() const");
00207     return buffer_[i];
00208   }
00209 
00210   /// Get an element from the sequence
00211   value_type & operator[](CORBA::ULong i)
00212   {
00213     range::check(i, length_, maximum_, "operator[]() non-const");
00214     return buffer_[i];
00215   }
00216 
00217   /**
00218    * Allows the buffer underlying a sequence to be replaced.  The
00219    * parameters to replace() are identical in type, order, and purpose
00220    * to those for the <T *data> constructor for the sequence.
00221    */
00222   void replace(
00223       CORBA::ULong maximum,
00224       CORBA::ULong length,
00225       value_type * data,
00226       CORBA::Boolean release)
00227   {
00228     generic_sequence tmp(maximum, length, data, release);
00229     swap(tmp);
00230   }
00231 
00232   /**
00233    * This function allows read-only access to the sequence buffer.
00234    * The sequence returns its buffer, allocating one of one has not
00235    * yet been allocated.  No direct modification of the returned
00236    * buffer by the caller is permitted.
00237    */
00238   value_type const * get_buffer() const
00239   {
00240     if (buffer_ == 0)
00241     {
00242       buffer_ = allocbuf(maximum_);
00243       release_ = true;
00244     }
00245     return buffer_;
00246   }
00247 
00248   /// Allows read-write access to the underlying buffer.
00249   /**
00250    * If @a orphan is FALSE the sequence returns a pointer to its buffer,
00251    * allocating one if it has not yet done so.  The number of elements in the
00252    * buffer can be determined from the sequence length() accessor.
00253    *
00254    * If the @a orphan argument to get_buffer() is FALSE, the sequence
00255    * maintains ownership of the underlying buffer.  Elements in the
00256    * returned buffer may be directly replaced by the caller.  For
00257    * sequences of strings, wide strings, and object references, the
00258    * caller must use the sequence @c release accessor to determine
00259    * whether elements should be freed (using @c string_free,
00260    * @c wstring_free, or @c CORBA::release for strings, wide strings,
00261    * and object references, respective) before being directly assigned
00262    * to.
00263    *
00264    * If the @a orphan argument to @a get_buffer is TRUE, the sequence
00265    * yields ownership of the buffer to the caller.  If @a orphan is
00266    * TRUE and the sequence does not own its buffer (i.e., its
00267    * release_ flag is FALSE), the return value is a null pointer.  If
00268    * the buffer is taken from the sequence using this form of
00269    * get_buffer(), the sequence reverts to the same state it would
00270    * have if constructed using its default constructor.  The caller
00271    * becomes responsible for eventually freeing each element of the
00272    * returned buffer (for strings, wide string, and object
00273    * references), and then freeing the returned buffer itself using
00274    * freebuf().
00275    */
00276   value_type * get_buffer(CORBA::Boolean orphan)
00277   {
00278     if (orphan && !release_)
00279     {
00280       return 0;
00281     }
00282     if (buffer_ == 0)
00283     {
00284       buffer_ = allocbuf(maximum_);
00285       if (!orphan)
00286         {
00287           release_ = true;
00288         }
00289     }
00290     if (!orphan)
00291     {
00292       return buffer_;
00293     }
00294 
00295     generic_sequence tmp;
00296     swap(tmp);
00297     tmp.release_ = false;
00298 
00299     return tmp.buffer_;
00300   }
00301 
00302   void swap(generic_sequence & rhs) throw()
00303   {
00304     std::swap(maximum_, rhs.maximum_);
00305     std::swap(length_, rhs.length_);
00306     std::swap(buffer_, rhs.buffer_);
00307     std::swap(release_, rhs.release_);
00308   }
00309 
00310   static value_type * allocbuf(CORBA::ULong maximum)
00311   {
00312     return allocation_traits::allocbuf(maximum);
00313   }
00314 
00315   static void freebuf(value_type * buffer)
00316   {
00317     allocation_traits::freebuf(buffer);
00318   }
00319 
00320 private:
00321   /// The maximum number of elements the buffer can contain.
00322   CORBA::ULong maximum_;
00323   /// The current number of elements in the buffer.
00324   CORBA::ULong length_;
00325   /// The buffer with all the elements
00326   mutable value_type * buffer_;
00327   /// If true then the sequence should release the buffer when it is
00328   /// destroyed.
00329   mutable CORBA::Boolean release_;
00330 };
00331 
00332 } // namespace details
00333 } // namespace TAO
00334 
00335 TAO_END_VERSIONED_NAMESPACE_DECL
00336 
00337 #endif // guard_generic_sequence_hpp

Generated on Tue Feb 2 17:37:51 2010 for TAO by  doxygen 1.4.7