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"
58 #include "ace/checked_iterator.h"
62 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
69 class ALLOCATION_TRAITS
,
71 class generic_sequence
75 typedef ALLOCATION_TRAITS allocation_traits
;
76 typedef ELEMENT_TRAITS element_traits
;
77 typedef range_checking
<value_type
,true> range
;
79 /// Default constructor.
81 : maximum_(allocation_traits::default_maximum())
83 , buffer_(allocation_traits::default_buffer_allocation())
84 , release_(buffer_
!= 0)
88 /// Constructor with control of ownership.
89 explicit generic_sequence(CORBA::ULong maximum
)
92 , buffer_(allocbuf(maximum_
))
101 CORBA::Boolean release
)
110 generic_sequence(generic_sequence
const & rhs
)
116 if (rhs
.maximum_
== 0 || rhs
.buffer_
== 0)
118 maximum_
= rhs
.maximum_
;
119 length_
= rhs
.length_
;
122 generic_sequence
tmp(rhs
.maximum_
, rhs
.length_
,
123 allocation_traits::allocbuf_noinit(rhs
.maximum_
),
125 element_traits::initialize_range(
126 tmp
.buffer_
+ tmp
.length_
, tmp
.buffer_
+ tmp
.maximum_
);
127 element_traits::copy_range(
129 rhs
.buffer_
+ rhs
.length_
,
130 ACE_make_checked_array_iterator (tmp
.buffer_
, tmp
.length_
));
134 /// Assignment operator
135 generic_sequence
& operator=(generic_sequence
const & rhs
)
137 generic_sequence
tmp(rhs
);
151 /// Return the maximum length of the sequence
152 inline CORBA::ULong
maximum() const
157 /// Returns the state of the sequence release flag.
158 inline CORBA::Boolean
release() const
163 /// Returns the length of the sequence
164 inline CORBA::ULong
length() const
169 /// Set a new length for the sequence
170 void length(CORBA::ULong length
)
172 if (length
<= maximum_
)
176 buffer_
= allocbuf(maximum_
);
179 // Since allocbuf returns completely initialized buffer
180 // no further actions are required.
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_
);
204 generic_sequence
tmp(length
, length
,
205 allocation_traits::allocbuf_noinit(length
),
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(
214 ACE_make_checked_array_iterator (tmp
.buffer_
, tmp
.length_
));
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");
226 /// Get an element from the sequence
227 value_type
& operator[](CORBA::ULong i
)
229 range::check(i
, length_
, maximum_
, "operator[]() non-const");
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.
239 CORBA::ULong maximum
,
242 CORBA::Boolean release
)
244 generic_sequence
tmp(maximum
, length
, data
, release
);
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
258 buffer_
= allocbuf(maximum_
);
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
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
292 value_type
* get_buffer(CORBA::Boolean orphan
)
294 if (orphan
&& !release_
)
300 buffer_
= allocbuf(maximum_
);
311 generic_sequence tmp
;
313 tmp
.release_
= false;
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
);
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
345 mutable CORBA::Boolean release_
;
347 } // namespace details
350 TAO_END_VERSIONED_NAMESPACE_DECL
352 #endif // guard_generic_sequence_hpp