=default for generated implementation copy ctor
[ACE_TAO.git] / TAO / tao / Generic_Sequence_T.h
blobef8632fbd889b143d67f8c23c9765597028ac499
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"
59 #include <algorithm>
61 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
63 namespace TAO
65 namespace details
67 template<typename T,
68 class ALLOCATION_TRAITS,
69 class ELEMENT_TRAITS>
70 class generic_sequence
72 public:
73 typedef T value_type;
74 typedef ALLOCATION_TRAITS allocation_traits;
75 typedef ELEMENT_TRAITS element_traits;
76 typedef range_checking<value_type,true> range;
78 /// Default constructor.
79 generic_sequence()
80 : maximum_(allocation_traits::default_maximum())
81 , length_(0)
82 , buffer_(allocation_traits::default_buffer_allocation())
83 , release_(buffer_ != 0)
87 /// Constructor with control of ownership.
88 explicit generic_sequence(CORBA::ULong maximum)
89 : maximum_(maximum)
90 , length_(0)
91 , buffer_(allocbuf(maximum_))
92 , release_(true)
96 generic_sequence(
97 CORBA::ULong maximum,
98 CORBA::ULong length,
99 value_type * data,
100 CORBA::Boolean release)
101 : maximum_(maximum)
102 , length_(length)
103 , buffer_(data)
104 , release_(release)
108 /// Copy constructor
109 generic_sequence(generic_sequence const & rhs)
110 : maximum_(0)
111 , length_(0)
112 , buffer_(0)
113 , release_(false)
115 if (rhs.maximum_ == 0 || rhs.buffer_ == 0)
117 maximum_ = rhs.maximum_;
118 length_ = rhs.length_;
119 return;
121 generic_sequence tmp(rhs.maximum_, rhs.length_,
122 allocation_traits::allocbuf_noinit(rhs.maximum_),
123 true);
124 element_traits::initialize_range(
125 tmp.buffer_ + tmp.length_, tmp.buffer_ + tmp.maximum_);
126 element_traits::copy_range(
127 rhs.buffer_,
128 rhs.buffer_ + rhs.length_,
129 tmp.buffer_);
130 swap(tmp);
133 /// Assignment operator
134 generic_sequence & operator=(generic_sequence const & rhs)
136 generic_sequence tmp(rhs);
137 swap(tmp);
138 return * this;
141 /// Destructor.
142 ~generic_sequence()
144 if (release_)
146 freebuf(buffer_);
150 /// Return the maximum length of the sequence
151 inline CORBA::ULong maximum() const
153 return maximum_;
156 /// Returns the state of the sequence release flag.
157 inline CORBA::Boolean release() const
159 return release_;
162 /// Returns the length of the sequence
163 inline CORBA::ULong length() const
165 return length_;
168 /// Set a new length for the sequence
169 void length(CORBA::ULong length)
171 if (length <= maximum_)
173 if (buffer_ == 0)
175 buffer_ = allocbuf(maximum_);
176 release_ = true;
177 length_ = length;
178 // Since allocbuf returns completely initialized buffer
179 // no further actions are required.
180 return;
183 // When sequence doesn't own a buffer it's not allowed
184 // to change it in any way.
185 if (length < length_ && release_)
187 // TODO This code does not provide the strong-exception
188 // guarantee, but it does provide the weak-exception
189 // guarantee. The problem would appear when
190 // initialize_range() raises an exception after several
191 // elements have been modified. One could argue that
192 // this problem is irrelevant, as the elements already
193 // modified are unreachable to conforming applications.
194 element_traits::release_range(
195 buffer_ + length, buffer_ + length_);
196 element_traits::initialize_range(
197 buffer_ + length, buffer_ + length_);
199 length_ = length;
200 return;
203 generic_sequence tmp(length, length,
204 allocation_traits::allocbuf_noinit(length),
205 true);
206 // First do initialize_range. If it will throw then tmp will be
207 // destructed but *this will remain unchanged.
208 element_traits::initialize_range(
209 tmp.buffer_ + length_, tmp.buffer_ + length);
210 element_traits::copy_swap_range(
211 buffer_,
212 buffer_ + length_,
213 tmp.buffer_);
215 swap(tmp);
218 /// Get a const element from the sequence
219 value_type const & operator[](CORBA::ULong i) const
221 range::check(i, length_, maximum_, "operator[]() const");
222 return buffer_[i];
225 /// Get an element from the sequence
226 value_type & operator[](CORBA::ULong i)
228 range::check(i, length_, maximum_, "operator[]() non-const");
229 return buffer_[i];
233 * Allows the buffer underlying a sequence to be replaced. The
234 * parameters to replace() are identical in type, order, and purpose
235 * to those for the <T *data> constructor for the sequence.
237 void replace(
238 CORBA::ULong maximum,
239 CORBA::ULong length,
240 value_type * data,
241 CORBA::Boolean release)
243 generic_sequence tmp(maximum, length, data, release);
244 swap(tmp);
248 * This function allows read-only access to the sequence buffer.
249 * The sequence returns its buffer, allocating one of one has not
250 * yet been allocated. No direct modification of the returned
251 * buffer by the caller is permitted.
253 value_type const * get_buffer() const
255 if (buffer_ == 0)
257 buffer_ = allocbuf(maximum_);
258 release_ = true;
260 return buffer_;
263 /// Allows read-write access to the underlying buffer.
265 * If @a orphan is FALSE the sequence returns a pointer to its buffer,
266 * allocating one if it has not yet done so. The number of elements in the
267 * buffer can be determined from the sequence length() accessor.
269 * If the @a orphan argument to get_buffer() is FALSE, the sequence
270 * maintains ownership of the underlying buffer. Elements in the
271 * returned buffer may be directly replaced by the caller. For
272 * sequences of strings, wide strings, and object references, the
273 * caller must use the sequence @c release accessor to determine
274 * whether elements should be freed (using @c string_free,
275 * @c wstring_free, or @c CORBA::release for strings, wide strings,
276 * and object references, respective) before being directly assigned
277 * to.
279 * If the @a orphan argument to @a get_buffer is TRUE, the sequence
280 * yields ownership of the buffer to the caller. If @a orphan is
281 * TRUE and the sequence does not own its buffer (i.e., its
282 * release_ flag is FALSE), the return value is a null pointer. If
283 * the buffer is taken from the sequence using this form of
284 * get_buffer(), the sequence reverts to the same state it would
285 * have if constructed using its default constructor. The caller
286 * becomes responsible for eventually freeing each element of the
287 * returned buffer (for strings, wide string, and object
288 * references), and then freeing the returned buffer itself using
289 * freebuf().
291 value_type * get_buffer(CORBA::Boolean orphan)
293 if (orphan && !release_)
295 return 0;
297 if (buffer_ == 0)
299 buffer_ = allocbuf(maximum_);
300 if (!orphan)
302 release_ = true;
305 if (!orphan)
307 return buffer_;
310 generic_sequence tmp;
311 swap(tmp);
312 tmp.release_ = false;
314 return tmp.buffer_;
317 void swap(generic_sequence & rhs) noexcept
319 std::swap(maximum_, rhs.maximum_);
320 std::swap(length_, rhs.length_);
321 std::swap(buffer_, rhs.buffer_);
322 std::swap(release_, rhs.release_);
325 static value_type * allocbuf(CORBA::ULong maximum)
327 return allocation_traits::allocbuf(maximum);
330 static void freebuf(value_type * buffer)
332 allocation_traits::freebuf(buffer);
335 private:
336 /// The maximum number of elements the buffer can contain.
337 CORBA::ULong maximum_;
338 /// The current number of elements in the buffer.
339 CORBA::ULong length_;
340 /// The buffer with all the elements
341 mutable value_type * buffer_;
342 /// If true then the sequence should release the buffer when it is
343 /// destroyed.
344 mutable CORBA::Boolean release_;
346 } // namespace details
347 } // namespace TAO
349 TAO_END_VERSIONED_NAMESPACE_DECL
351 #endif // guard_generic_sequence_hpp