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