summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcoryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-09-23 01:45:39 +0000
committercoryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2004-09-23 01:45:39 +0000
commitd3f32a32478e4c1200eef33f9a339438663cdf05 (patch)
treeb400b69f2b698a064cdac8bc3f84d7053c685601
parent519d35b8ffa9cea060f5c88c995d4188c969dd53 (diff)
downloadATCD-d3f32a32478e4c1200eef33f9a339438663cdf05.tar.gz
Wed Sep 22 21:39:48 2004 Carlos O'Ryan <coryan@atdesk.com>
-rw-r--r--TAO/ChangeLog23
-rw-r--r--TAO/tests/Sequence_Unit_Tests/allocation_traits.hpp50
-rw-r--r--TAO/tests/Sequence_Unit_Tests/generic_sequence.hpp51
-rw-r--r--TAO/tests/Sequence_Unit_Tests/string_traits.hpp6
-rw-r--r--TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence.hpp9
-rw-r--r--TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence_ut.cpp72
6 files changed, 202 insertions, 9 deletions
diff --git a/TAO/ChangeLog b/TAO/ChangeLog
index 6c9e4ca641e..1ea0bbf7ccc 100644
--- a/TAO/ChangeLog
+++ b/TAO/ChangeLog
@@ -1,3 +1,26 @@
+Wed Sep 22 21:39:48 2004 Carlos O'Ryan <coryan@atdesk.com>
+
+ * tests/Sequence_Unit_Tests/unbounded_string_sequence_ut.cpp:
+ Add test for freebuf(), this motivated the changes below.
+ Add test for to verify that index checking works.
+
+ * tests/Sequence_Unit_Tests/unbounded_string_sequence.hpp:
+ Enable the implementation of allocbuf() and freebuf().
+
+ * tests/Sequence_Unit_Tests/allocation_traits.hpp:
+ Because freebuf() has such crazy requirements for sequences of
+ reference-like types I had to implement special allocators for
+ those types. Basically they decorate the normal allocators and
+ call the ::release_range() and ::zero_range() traits in the
+ element type.
+
+ * tests/Sequence_Unit_Tests/generic_sequence.hpp:
+ Improved the documentation.
+ Moved the zeroing-out of buffers to the allocation traits.
+
+ * tests/Sequence_Unit_Tests/string_traits.hpp:
+ Add trait to release all the strings in a (buffer) range.
+
Wed Sep 22 20:41:44 2004 Carlos O'Ryan <coryan@atdesk.com>
* tests/Sequence_Unit_Tests/Bounded_Simple_Types.cpp:
diff --git a/TAO/tests/Sequence_Unit_Tests/allocation_traits.hpp b/TAO/tests/Sequence_Unit_Tests/allocation_traits.hpp
index a96f90516e7..24727f943ef 100644
--- a/TAO/tests/Sequence_Unit_Tests/allocation_traits.hpp
+++ b/TAO/tests/Sequence_Unit_Tests/allocation_traits.hpp
@@ -76,6 +76,56 @@ struct bounded_allocation_traits
/* static CORBA::ULong const MAXIMUM = MAX; */
};
+template<typename value_type, class reference_traits, bool dummy>
+struct unbounded_reference_allocation_traits
+ : public unbounded_allocation_traits<value_type,dummy>
+{
+ typedef unbounded_allocation_traits<value_type,dummy> base_allocation_traits;
+
+ inline static value_type * allocbuf(CORBA::ULong maximum)
+ {
+ value_type * buffer =
+ base_allocation_traits::allocbuf(maximum + 1);
+ reinterpret_cast<value_type*>(buffer[0]) = buffer + maximum + 1;
+
+ reference_traits::zero_range(buffer + 1, buffer + maximum + 1);
+
+ return buffer + 1;
+ }
+
+ inline static void freebuf(value_type * buffer)
+ {
+ if(buffer != 0)
+ {
+ value_type * begin = buffer - 1;
+ value_type * end = reinterpret_cast<value_type*>(*begin);
+ reference_traits::release_range(buffer, end);
+
+ buffer = begin;
+ }
+ base_allocation_traits::freebuf(buffer);
+ }
+};
+
+template<typename value_type, class reference_traits, CORBA::ULong MAX, bool dummy>
+struct bounded_reference_allocation_traits
+ : public bounded_allocation_traits<value_type,MAX,dummy>
+{
+ typedef bounded_allocation_traits<value_type,MAX,dummy> base_allocation_traits;
+
+ inline static value_type * allocbuf(CORBA::ULong /* maximum */)
+ {
+ value_type * buffer = base_allocation_traits::allocbuf(MAX);
+ reference_traits::zero_range(buffer, buffer + MAX);
+ }
+
+ inline static void freebuf(value_type * buffer)
+ {
+ reference_traits::release_range(buffer, buffer + MAX);
+ base_allocation_traits::freebuf(buffer);
+ }
+};
+
} // namespace details
} // namespace TAO
diff --git a/TAO/tests/Sequence_Unit_Tests/generic_sequence.hpp b/TAO/tests/Sequence_Unit_Tests/generic_sequence.hpp
index 77e07d21941..82beca6ba22 100644
--- a/TAO/tests/Sequence_Unit_Tests/generic_sequence.hpp
+++ b/TAO/tests/Sequence_Unit_Tests/generic_sequence.hpp
@@ -5,8 +5,51 @@
*
* @brief Implement the generic version of CORBA sequences.
*
- * All CORBA sequences are based on this class template. The
- * differences are encapsulated in a TRAITS template argument.
+ * 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 intantiate 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$
*
@@ -39,8 +82,6 @@ public:
, buffer_(allocation_traits::default_buffer_allocation())
, release_(true)
{
- element_traits::zero_range(
- buffer_, buffer_ + maximum_);
}
explicit generic_sequence(CORBA::ULong maximum)
@@ -49,8 +90,6 @@ public:
, buffer_(allocbuf(maximum_))
, release_(true)
{
- element_traits::zero_range(
- buffer_, buffer_ + maximum_);
}
generic_sequence(
diff --git a/TAO/tests/Sequence_Unit_Tests/string_traits.hpp b/TAO/tests/Sequence_Unit_Tests/string_traits.hpp
index 85bc08c0b75..638047253a8 100644
--- a/TAO/tests/Sequence_Unit_Tests/string_traits.hpp
+++ b/TAO/tests/Sequence_Unit_Tests/string_traits.hpp
@@ -44,6 +44,12 @@ struct string_traits_decorator
std::transform(begin, end, dst, &derived::duplicate);
}
+ inline static void release_range(
+ char_type ** begin, char_type ** end)
+ {
+ std::for_each(begin, end, &derived::release);
+ }
+
inline static char_type const * initialize_if_zero(char_type * & element)
{
if (element == 0)
diff --git a/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence.hpp b/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence.hpp
index fbc7297ad64..4b7f1124c1c 100644
--- a/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence.hpp
+++ b/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence.hpp
@@ -22,8 +22,9 @@ class unbounded_string_sequence
{
public:
typedef char * value_type;
- typedef details::unbounded_allocation_traits<char*,true> allocation_traits;
typedef details::string_traits<char,true> element_traits;
+ typedef details::unbounded_reference_allocation_traits<char*,element_traits,true> allocation_traits;
+
typedef details::string_sequence_element<char> element_type;
typedef details::generic_sequence<char*, allocation_traits, element_traits> implementation_type;
@@ -80,7 +81,10 @@ public:
inline void swap(unbounded_string_sequence & rhs) throw() {
impl_.swap(rhs.impl_);
}
- static char * * allocbuf(CORBA::ULong maximum) {
+#endif /* 0 */
+
+ static char * * allocbuf(CORBA::ULong maximum)
+ {
return implementation_type::allocbuf(maximum);
}
static void freebuf(char * * buffer)
@@ -88,7 +92,6 @@ public:
implementation_type::freebuf(buffer);
}
-#endif /* 0 */
private:
implementation_type impl_;
diff --git a/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence_ut.cpp b/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence_ut.cpp
index 78fce1590d9..3ec1725c7f6 100644
--- a/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence_ut.cpp
+++ b/TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence_ut.cpp
@@ -14,16 +14,24 @@
#include "unbounded_string_sequence.hpp"
+#include "ace/OS_NS_string.h"
+
#include <boost/test/unit_test.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
+#include <sstream>
+
using namespace boost::unit_test_framework;
using namespace TAO;
struct Tester
: public boost::enable_shared_from_this<Tester>
{
+ typedef char char_type;
+ typedef char * value_type;
+ typedef char const * const_value_type;
+
typedef TAO::details::string_traits<char,true> tested_element_traits;
typedef TAO::details::unbounded_allocation_traits<char*,true> tested_allocation_traits;
typedef TAO::details::range_checking<char*,true> range;
@@ -196,6 +204,64 @@ struct Tester
BOOST_CHECK(text != t);
}
+ void test_index_checking()
+ {
+ tested_sequence x;
+ x.length(8);
+
+ tested_sequence const & y = x;
+ char const * lhs = 0;
+ char const * rhs = 0;
+ BOOST_CHECK_THROW(lhs = y[32], std::range_error);
+ BOOST_CHECK_THROW(x[32] = rhs, std::range_error);
+ }
+
+ void test_copy_constructor_values()
+ {
+ tested_sequence a;
+ a.length(16);
+ for(CORBA::ULong i = 0; i != 16; ++i)
+ {
+ std::ostringstream os; os << (i*i);
+ a[i] = os.str().c_str();
+ }
+
+ expected_calls d(tested_element_traits::duplicate_calls);
+ expected_calls r(tested_element_traits::release_calls);
+ {
+ tested_sequence b(a);
+ BOOST_CHECK_MESSAGE(d.expect(16), d);
+
+ BOOST_CHECK_EQUAL(a.length(), b.length());
+ for(CORBA::ULong i = 0; i != a.length(); ++i)
+ {
+ BOOST_CHECK_MESSAGE(ACE_OS::strcmp(a[i], b[i]) == 0,
+ "Mismatched elements at index=" << i
+ << ", a=" << a[i]
+ << ", b=" << b[i]);
+ }
+ }
+ BOOST_CHECK_MESSAGE(r.expect(16), r);
+ }
+
+ void test_freebuf_releases_elements()
+ {
+ value_type * buffer = tested_sequence::allocbuf(32);
+ for(int i = 0; i != 32; ++i)
+ {
+ buffer[i] = tested_element_traits::duplicate("Foo bar baz");
+ }
+
+ expected_calls r(tested_element_traits::release_calls);
+ expected_calls f(tested_allocation_traits::freebuf_calls);
+
+ tested_sequence::freebuf(buffer);
+
+ BOOST_CHECK_MESSAGE(f.expect(0), f);
+ BOOST_CHECK_MESSAGE(r.expect(32), r);
+
+ }
+
void add_all(test_suite * ts)
{
ts->add(BOOST_CLASS_TEST_CASE(
@@ -219,6 +285,12 @@ struct Tester
ts->add(BOOST_CLASS_TEST_CASE(
&Tester::test_index_accessor,
shared_from_this()));
+ ts->add(BOOST_CLASS_TEST_CASE(
+ &Tester::test_index_checking,
+ shared_from_this()));
+ ts->add(BOOST_CLASS_TEST_CASE(
+ &Tester::test_copy_constructor_values,
+ shared_from_this()));
}
};