Merge pull request #2216 from jwillemsen/jwi-cxxversionchecks
[ACE_TAO.git] / TAO / tao / Generic_Sequence_T.h
blobeca632bf6fac7e8d1423c0d54ddea02cf93ffa52
1 #ifndef guard_generic_sequence_hpp
2 #define guard_generic_sequence_hpp
3 /**
4 * @file Generic_Sequence_T.h
6 * @brief Implement the generic version of CORBA sequences.
8 * All CORBA sequences are based on this class template. The behavior
9 * of this class is controlled by two sets of traits. First, the
10 * ALLOCATION_TRAITS control how buffers are allocated and
11 * initialized. Since this is where most of the variation between
12 * unbounded and bounded sequences is found, the ALLOCATION_TRAITS can
13 * be thought as the bounded aspect of the sequence.
15 * Second, the element traits control how are elements copied,
16 * initialized and released. Value-like types, such as integers and
17 * structures, have trivial initialization and release requirements
18 * (their constructor/destructors do the job!) But reference-like
19 * types, such as strings and object references, have more complicated
20 * requirements. This is yet another aspect of the sequences, we can
21 * call it the "element copy semantics" or something.
23 * Oh, and let us not forget the type that the sequences encapsulates.
25 * The intent is not for sequences to simply derive or instantiate this
26 * type. Instead, different each sequence type is written using
27 * composition. They instantiate a generic sequence with the correct
28 * traits, and implement the adapt the generic sequence interface to
29 * whatever requirements the spec may impose. For example, replace()
30 * has different number of arguments in bounded vs. unbounded
31 * sequences, and operator[] returns different types depending on the
32 * underlying type of the sequence.
34 * This class offers the strong exception-safety guarantee, as long as
35 * destructors and release operations do not throw.
37 * This class is not thread-safe. Thread-safe collections are mostly
38 * useless anyways.
40 * In general the performance characteristics of the class depends on
41 * the traits. Obviously, they can only be expressed on the number of
42 * element constructor and destructor calls. If the constructor takes
43 * O(K) time that is not the sequence fault!
45 * All accessors are O(1), single-element modifiers are O(1), multiple
46 * element modifiers are O(n + m) where n is the number of elements
47 * originally in the sequence, and m is the number of elements left in
48 * the sequence afterwards.
50 * Beware:
51 * - get_buffer(true) may modify multiple elements
52 * - length(CORBA::ULong) may modify multiple elements!
54 * @author Carlos O'Ryan
57 #include "tao/Range_Checking_T.h"
58 #include "ace/checked_iterator.h"
60 #include <algorithm>
62 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
64 namespace TAO
66 namespace details
68 template<typename T,
69 class ALLOCATION_TRAITS,
70 class ELEMENT_TRAITS>
71 class generic_sequence
73 public:
74 typedef T value_type;
75 typedef ALLOCATION_TRAITS allocation_traits;
76 typedef ELEMENT_TRAITS element_traits;
77 typedef range_checking<value_type,true> range;
79 /// Default constructor.
80 generic_sequence()
81 : maximum_(allocation_traits::default_maximum())
82 , length_(0)
83 , buffer_(allocation_traits::default_buffer_allocation())
84 , release_(buffer_ != 0)
88 /// Constructor with control of ownership.
89 explicit generic_sequence(CORBA::ULong maximum)
90 : maximum_(maximum)
91 , length_(0)
92 , buffer_(allocbuf(maximum_))
93 , release_(true)
97 generic_sequence(
98 CORBA::ULong maximum,
99 CORBA::ULong length,
100 value_type * data,
101 CORBA::Boolean release)
102 : maximum_(maximum)
103 , length_(length)
104 , buffer_(data)
105 , release_(release)
109 /// Copy constructor
110 generic_sequence(generic_sequence const & rhs)
111 : maximum_(0)
112 , length_(0)
113 , buffer_(0)
114 , release_(false)
116 if (rhs.maximum_ == 0 || rhs.buffer_ == 0)
118 maximum_ = rhs.maximum_;
119 length_ = rhs.length_;
120 return;
122 generic_sequence tmp(rhs.maximum_, rhs.length_,
123 allocation_traits::allocbuf_noinit(rhs.maximum_),
124 true);
125 element_traits::initialize_range(
126 tmp.buffer_ + tmp.length_, tmp.buffer_ + tmp.maximum_);
127 element_traits::copy_range(
128 rhs.buffer_,
129 rhs.buffer_ + rhs.length_,
130 ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
131 swap(tmp);
134 /// Assignment operator
135 generic_sequence & operator=(generic_sequence const & rhs)
137 generic_sequence tmp(rhs);
138 swap(tmp);
139 return * this;
142 /// Destructor.
143 ~generic_sequence()
145 if (release_)
147 freebuf(buffer_);
151 /// Return the maximum length of the sequence
152 inline CORBA::ULong maximum() const
154 return maximum_;
157 /// Returns the state of the sequence release flag.
158 inline CORBA::Boolean release() const
160 return release_;
163 /// Returns the length of the sequence
164 inline CORBA::ULong length() const
166 return length_;
169 /// Set a new length for the sequence
170 void length(CORBA::ULong length)
172 if (length <= maximum_)
174 if (buffer_ == 0)
176 buffer_ = allocbuf(maximum_);
177 release_ = true;
178 length_ = length;
179 // Since allocbuf returns completely initialized buffer
180 // no further actions are required.
181 return;
184 // When sequence doesn't own a buffer it's not allowed
185 // to change it in any way.
186 if (length < length_ && release_)
188 // TODO This code does not provide the strong-exception
189 // guarantee, but it does provide the weak-exception
190 // guarantee. The problem would appear when
191 // initialize_range() raises an exception after several
192 // elements have been modified. One could argue that
193 // this problem is irrelevant, as the elements already
194 // modified are unreachable to conforming applications.
195 element_traits::release_range(
196 buffer_ + length, buffer_ + length_);
197 element_traits::initialize_range(
198 buffer_ + length, buffer_ + length_);
200 length_ = length;
201 return;
204 generic_sequence tmp(length, length,
205 allocation_traits::allocbuf_noinit(length),
206 true);
207 // First do initialize_range. If it will throw then tmp will be
208 // destructed but *this will remain unchanged.
209 element_traits::initialize_range(
210 tmp.buffer_ + length_, tmp.buffer_ + length);
211 element_traits::copy_swap_range(
212 buffer_,
213 buffer_ + length_,
214 ACE_make_checked_array_iterator (tmp.buffer_, tmp.length_));
216 swap(tmp);
219 /// Get a const element from the sequence
220 value_type const & operator[](CORBA::ULong i) const
222 range::check(i, length_, maximum_, "operator[]() const");
223 return buffer_[i];
226 /// Get an element from the sequence
227 value_type & operator[](CORBA::ULong i)
229 range::check(i, length_, maximum_, "operator[]() non-const");
230 return buffer_[i];
234 * Allows the buffer underlying a sequence to be replaced. The
235 * parameters to replace() are identical in type, order, and purpose
236 * to those for the <T *data> constructor for the sequence.
238 void replace(
239 CORBA::ULong maximum,
240 CORBA::ULong length,
241 value_type * data,
242 CORBA::Boolean release)
244 generic_sequence tmp(maximum, length, data, release);
245 swap(tmp);
249 * This function allows read-only access to the sequence buffer.
250 * The sequence returns its buffer, allocating one of one has not
251 * yet been allocated. No direct modification of the returned
252 * buffer by the caller is permitted.
254 value_type const * get_buffer() const
256 if (buffer_ == 0)
258 buffer_ = allocbuf(maximum_);
259 release_ = true;
261 return buffer_;
264 /// Allows read-write access to the underlying buffer.
266 * If @a orphan is FALSE the sequence returns a pointer to its buffer,
267 * allocating one if it has not yet done so. The number of elements in the
268 * buffer can be determined from the sequence length() accessor.
270 * If the @a orphan argument to get_buffer() is FALSE, the sequence
271 * maintains ownership of the underlying buffer. Elements in the
272 * returned buffer may be directly replaced by the caller. For
273 * sequences of strings, wide strings, and object references, the
274 * caller must use the sequence @c release accessor to determine
275 * whether elements should be freed (using @c string_free,
276 * @c wstring_free, or @c CORBA::release for strings, wide strings,
277 * and object references, respective) before being directly assigned
278 * to.
280 * If the @a orphan argument to @a get_buffer is TRUE, the sequence
281 * yields ownership of the buffer to the caller. If @a orphan is
282 * TRUE and the sequence does not own its buffer (i.e., its
283 * release_ flag is FALSE), the return value is a null pointer. If
284 * the buffer is taken from the sequence using this form of
285 * get_buffer(), the sequence reverts to the same state it would
286 * have if constructed using its default constructor. The caller
287 * becomes responsible for eventually freeing each element of the
288 * returned buffer (for strings, wide string, and object
289 * references), and then freeing the returned buffer itself using
290 * freebuf().
292 value_type * get_buffer(CORBA::Boolean orphan)
294 if (orphan && !release_)
296 return 0;
298 if (buffer_ == 0)
300 buffer_ = allocbuf(maximum_);
301 if (!orphan)
303 release_ = true;
306 if (!orphan)
308 return buffer_;
311 generic_sequence tmp;
312 swap(tmp);
313 tmp.release_ = false;
315 return tmp.buffer_;
318 void swap(generic_sequence & rhs) noexcept
320 std::swap(maximum_, rhs.maximum_);
321 std::swap(length_, rhs.length_);
322 std::swap(buffer_, rhs.buffer_);
323 std::swap(release_, rhs.release_);
326 static value_type * allocbuf(CORBA::ULong maximum)
328 return allocation_traits::allocbuf(maximum);
331 static void freebuf(value_type * buffer)
333 allocation_traits::freebuf(buffer);
336 private:
337 /// The maximum number of elements the buffer can contain.
338 CORBA::ULong maximum_;
339 /// The current number of elements in the buffer.
340 CORBA::ULong length_;
341 /// The buffer with all the elements
342 mutable value_type * buffer_;
343 /// If true then the sequence should release the buffer when it is
344 /// destroyed.
345 mutable CORBA::Boolean release_;
347 } // namespace details
348 } // namespace TAO
350 TAO_END_VERSIONED_NAMESPACE_DECL
352 #endif // guard_generic_sequence_hpp