summaryrefslogtreecommitdiff
path: root/TAO/tao/Generic_Sequence_T.h
diff options
context:
space:
mode:
authorJohnny Willemsen <jwillemsen@remedy.nl>2006-04-19 09:10:19 +0000
committerJohnny Willemsen <jwillemsen@remedy.nl>2006-04-19 09:10:19 +0000
commitf9606f4f257e642e04f8c84315b0c8f323fe65e6 (patch)
treea681f895cf5a9b8a4f7ab6603ee4fd3a55ca0305 /TAO/tao/Generic_Sequence_T.h
parent10fc1a52ad4bc0d1d3d6716d18f77d04022bd2a8 (diff)
downloadATCD-f9606f4f257e642e04f8c84315b0c8f323fe65e6.tar.gz
ChangeLogTag: Wed Apr 19 07:44:49 UTC 2006 Johnny Willemsen <jwillemsen@remedy.nl>
Diffstat (limited to 'TAO/tao/Generic_Sequence_T.h')
-rw-r--r--TAO/tao/Generic_Sequence_T.h319
1 files changed, 319 insertions, 0 deletions
diff --git a/TAO/tao/Generic_Sequence_T.h b/TAO/tao/Generic_Sequence_T.h
new file mode 100644
index 00000000000..a9786082b5d
--- /dev/null
+++ b/TAO/tao/Generic_Sequence_T.h
@@ -0,0 +1,319 @@
+#ifndef guard_generic_sequence_hpp
+#define guard_generic_sequence_hpp
+/**
+ * @file
+ *
+ * @brief Implement the generic version of CORBA sequences.
+ *
+ * All CORBA sequences are based on this class template. The behavior
+ * of this class is controlled by two sets of traits. First, the
+ * ALLOCATION_TRAITS control how buffers are allocated and
+ * initialized. Since this is where most of the variation between
+ * unbounded and bounded sequences is found, the ALLOCATION_TRAITS can
+ * be thought as the bounded aspect of the sequence.
+ *
+ * Second, the element traits control how are elements copied,
+ * initialized and released. Value-like types, such as integers and
+ * structures, have trivial initialization and release requirements
+ * (their constructor/destructors do the job!) But reference-like
+ * types, such as strings and object references, have more complicated
+ * requirements. This is yet another aspect of the sequences, we can
+ * call it the "element copy semantics" or something.
+ *
+ * Oh, and let us not forget the type that the sequences encapsulates.
+ *
+ * The intent is not for sequences to simply derive or instantiate this
+ * type. Instead, different each sequence type is written using
+ * composition. They instantiate a generic sequence with the correct
+ * traits, and implement the adapt the generic sequence interface to
+ * whatever requirements the spec may impose. For example, replace()
+ * has different number of arguments in bounded vs. unbounded
+ * sequences, and operator[] returns different types depending on the
+ * underlying type of the sequence.
+ *
+ * This class offers the strong exception-safety guarantee, as long as
+ * destructors and release operations do not throw.
+ *
+ * This class is not thread-safe. Thread-safe collections are mostly
+ * useless anyways.
+ *
+ * In general the performance characteristics of the class depends on
+ * the traits. Obviously, they can only be expressed on the number of
+ * element constructor and destructor calls. If the constructor takes
+ * O(K) time that is not the sequence fault!
+ *
+ * All accessors are O(1), single-element modifiers are O(1), multiple
+ * element modifiers are O(n + m) where n is the number of elements
+ * originally in the sequence, and m is the number of elements left in
+ * the sequence afterwards.
+ *
+ * Beware:
+ * - get_buffer(true) may modify multiple elements
+ * - length(CORBA::ULong) may modify multiple elements!
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan
+ */
+
+#include "tao/Range_Checking_T.h"
+
+#include <algorithm>
+
+TAO_BEGIN_VERSIONED_NAMESPACE_DECL
+
+namespace TAO
+{
+namespace details
+{
+
+template<typename T,
+ class ALLOCATION_TRAITS,
+ class ELEMENT_TRAITS>
+class generic_sequence
+{
+public:
+ typedef T value_type;
+ typedef ALLOCATION_TRAITS allocation_traits;
+ typedef ELEMENT_TRAITS element_traits;
+ typedef range_checking<value_type,true> range;
+
+ /// Default constructor.
+ generic_sequence()
+ : maximum_(allocation_traits::default_maximum())
+ , length_(0)
+ , buffer_(allocation_traits::default_buffer_allocation())
+ , release_(true)
+ {
+ }
+
+ /// Constructor with control of ownership.
+ explicit generic_sequence(CORBA::ULong maximum)
+ : maximum_(maximum)
+ , length_(0)
+ , buffer_(allocbuf(maximum_))
+ , release_(true)
+ {
+ }
+
+ generic_sequence(
+ CORBA::ULong maximum,
+ CORBA::ULong length,
+ value_type * data,
+ CORBA::Boolean release)
+ : maximum_(maximum)
+ , length_(length)
+ , buffer_(data)
+ , release_(release)
+ {
+ }
+
+ /// Copy constructor
+ generic_sequence(generic_sequence const & rhs)
+ : maximum_(0)
+ , length_(0)
+ , buffer_(0)
+ , release_(false)
+ {
+ generic_sequence tmp(rhs.maximum_);
+ tmp.length_ = rhs.length_;
+ element_traits::copy_range(
+ rhs.buffer_, rhs.buffer_ + rhs.length_, tmp.buffer_);
+ swap(tmp);
+ }
+
+ /// Assignment operator
+ generic_sequence & operator=(generic_sequence const & rhs)
+ {
+ generic_sequence tmp(rhs);
+ swap(tmp);
+ return * this;
+ }
+
+ /// Destructor.
+ ~generic_sequence()
+ {
+ if (release_)
+ {
+ freebuf(buffer_);
+ }
+ }
+
+ /// Return the maximum length of the sequence
+ inline CORBA::ULong maximum() const
+ {
+ return maximum_;
+ }
+
+ /// Returns the state of the sequence release flag.
+ inline CORBA::Boolean release() const
+ {
+ return release_;
+ }
+
+ /// Returns the length of the sequence
+ inline CORBA::ULong length() const
+ {
+ return length_;
+ }
+
+ /// Set a new length for the sequence
+ void length(CORBA::ULong length)
+ {
+ if (length <= maximum_ || length <= length_)
+ {
+ if (length_ < length)
+ {
+ // TODO This code does not provide the strong-exception
+ // guarantee, but it does provide the weak-exception
+ // guarantee. The problem would appear when
+ // initialize_range() raises an exception after several
+ // elements have been modified. One could argue that
+ // this problem is irrelevant, as the elements already
+ // modified are unreachable to conforming applications.
+ element_traits::initialize_range(
+ buffer_ + length_, buffer_ + length);
+ }
+ length_ = length;
+ return;
+ }
+
+ generic_sequence tmp(length); tmp.length_ = length;
+ element_traits::copy_range(
+ buffer_, buffer_ + length_, tmp.buffer_);
+ element_traits::initialize_range(
+ tmp.buffer_ + length_, tmp.buffer_ + length);
+
+ swap(tmp);
+ }
+
+ /// Get a const element from the sequence
+ value_type const & operator[](CORBA::ULong i) const
+ {
+ range::check(i, length_, maximum_, "operator[]() const");
+ return buffer_[i];
+ }
+
+ /// Get an element from the sequence
+ value_type & operator[](CORBA::ULong i)
+ {
+ range::check(i, length_, maximum_, "operator[]() non-const");
+ return buffer_[i];
+ }
+
+ /**
+ * Allows the buffer underlying a sequence to be replaced. The
+ * parameters to replace() are identical in type, order, and purpose
+ * to those for the <T *data> constructor for the sequence.
+ */
+ void replace(
+ CORBA::ULong maximum,
+ CORBA::ULong length,
+ value_type * data,
+ CORBA::Boolean release)
+ {
+ generic_sequence tmp(maximum, length, data, release);
+ swap(tmp);
+ }
+
+ /**
+ * This function allows read-only access to the sequence buffer.
+ * The sequence returns its buffer, allocating one of one has not
+ * yet been allocated. No direct modification of the returned
+ * buffer by the caller is permitted.
+ */
+ value_type const * get_buffer() const
+ {
+ if (buffer_ == 0)
+ {
+ buffer_ = allocbuf(maximum_);
+ }
+ return buffer_;
+ }
+
+ /// Allows read-write access to the underlying buffer.
+ /**
+ * If @a orphan is FALSE the sequence returns a pointer to its buffer,
+ * allocating one if it has not yet done so. The number of elements in the
+ * buffer can be determined from the sequence length() accessor.
+ *
+ * If the @a orphan argument to get_buffer() is FALSE, the sequence
+ * maintains ownership of the underlying buffer. Elements in the
+ * returned buffer may be directly replaced by the caller. For
+ * sequences of strings, wide strings, and object references, the
+ * caller must use the sequence <release> accessor to determine
+ * whether elements should be freed (using <string_free>,
+ * <wstring_free>, or <CORBA::release> for strings, wide strings,
+ * and object references, respective) before being directly assigned
+ * to.
+ *
+ * If the @a orphan argument to @a get_buffer is TRUE, the sequence
+ * yields ownership of the buffer to the caller. If @a orphan is
+ * TRUE and the sequence does not own its buffer (i.e., its
+ * release_ flag is FALSE), the return value is a null pointer. If
+ * the buffer is taken from the sequence using this form of
+ * get_buffer(), the sequence reverts to the same state it would
+ * have if constructed using its default constructor. The caller
+ * becomes responsible for eventually freeing each element of the
+ * returned buffer (for strings, wide string, and object
+ * references), and then freeing the returned buffer itself using
+ * freebuf().
+ */
+ value_type * get_buffer(CORBA::Boolean orphan)
+ {
+ if (orphan && !release_)
+ {
+ return 0;
+ }
+ if (buffer_ == 0)
+ {
+ buffer_ = allocbuf(maximum_);
+ }
+ if (!orphan)
+ {
+ return buffer_;
+ }
+
+ generic_sequence tmp;
+ swap(tmp);
+ tmp.release_ = false;
+
+ return tmp.buffer_;
+ }
+
+ void swap(generic_sequence & rhs) throw()
+ {
+ std::swap(maximum_, rhs.maximum_);
+ std::swap(length_, rhs.length_);
+ std::swap(buffer_, rhs.buffer_);
+ std::swap(release_, rhs.release_);
+ }
+
+ static value_type * allocbuf(CORBA::ULong maximum)
+ {
+ return allocation_traits::allocbuf(maximum);
+ }
+
+ static void freebuf(value_type * buffer)
+ {
+ allocation_traits::freebuf(buffer);
+ }
+
+private:
+ /// The maximum number of elements the buffer can contain.
+ CORBA::ULong maximum_;
+ /// The current number of elements in the buffer.
+ CORBA::ULong length_;
+ /// The buffer with all the elements
+ mutable value_type * buffer_;
+ /// If true then the sequence should release the buffer when it is
+ /// destroyed.
+ CORBA::Boolean release_;
+};
+
+} // namespace details
+} // namespace TAO
+
+TAO_END_VERSIONED_NAMESPACE_DECL
+
+#endif // guard_generic_sequence_hpp