1 #ifndef guard_generic_sequence_hpp
2 #define guard_generic_sequence_hpp
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
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.
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"
61 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
68 class ALLOCATION_TRAITS
,
70 class generic_sequence
74 typedef ALLOCATION_TRAITS allocation_traits
;
75 typedef ELEMENT_TRAITS element_traits
;
76 typedef range_checking
<value_type
,true> range
;
78 /// Default constructor.
80 : maximum_(allocation_traits::default_maximum())
82 , buffer_(allocation_traits::default_buffer_allocation())
83 , release_(buffer_
!= 0)
87 /// Constructor with control of ownership.
88 explicit generic_sequence(CORBA::ULong maximum
)
91 , buffer_(allocbuf(maximum_
))
100 CORBA::Boolean release
)
109 generic_sequence(generic_sequence
const & rhs
)
115 if (rhs
.maximum_
== 0 || rhs
.buffer_
== 0)
117 maximum_
= rhs
.maximum_
;
118 length_
= rhs
.length_
;
121 generic_sequence
tmp(rhs
.maximum_
, rhs
.length_
,
122 allocation_traits::allocbuf_noinit(rhs
.maximum_
),
124 element_traits::initialize_range(
125 tmp
.buffer_
+ tmp
.length_
, tmp
.buffer_
+ tmp
.maximum_
);
126 element_traits::copy_range(
128 rhs
.buffer_
+ rhs
.length_
,
133 /// Assignment operator
134 generic_sequence
& operator=(generic_sequence
const & rhs
)
136 generic_sequence
tmp(rhs
);
150 /// Return the maximum length of the sequence
151 inline CORBA::ULong
maximum() const
156 /// Returns the state of the sequence release flag.
157 inline CORBA::Boolean
release() const
162 /// Returns the length of the sequence
163 inline CORBA::ULong
length() const
168 /// Set a new length for the sequence
169 void length(CORBA::ULong length
)
171 if (length
<= maximum_
)
175 buffer_
= allocbuf(maximum_
);
178 // Since allocbuf returns completely initialized buffer
179 // no further actions are required.
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_
);
203 generic_sequence
tmp(length
, length
,
204 allocation_traits::allocbuf_noinit(length
),
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(
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");
225 /// Get an element from the sequence
226 value_type
& operator[](CORBA::ULong i
)
228 range::check(i
, length_
, maximum_
, "operator[]() non-const");
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.
238 CORBA::ULong maximum
,
241 CORBA::Boolean release
)
243 generic_sequence
tmp(maximum
, length
, data
, release
);
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
257 buffer_
= allocbuf(maximum_
);
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
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
291 value_type
* get_buffer(CORBA::Boolean orphan
)
293 if (orphan
&& !release_
)
299 buffer_
= allocbuf(maximum_
);
310 generic_sequence tmp
;
312 tmp
.release_
= false;
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
);
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
344 mutable CORBA::Boolean release_
;
346 } // namespace details
349 TAO_END_VERSIONED_NAMESPACE_DECL
351 #endif // guard_generic_sequence_hpp