diff options
author | coryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2004-09-23 01:45:39 +0000 |
---|---|---|
committer | coryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2004-09-23 01:45:39 +0000 |
commit | d3f32a32478e4c1200eef33f9a339438663cdf05 (patch) | |
tree | b400b69f2b698a064cdac8bc3f84d7053c685601 | |
parent | 519d35b8ffa9cea060f5c88c995d4188c969dd53 (diff) | |
download | ATCD-d3f32a32478e4c1200eef33f9a339438663cdf05.tar.gz |
Wed Sep 22 21:39:48 2004 Carlos O'Ryan <coryan@atdesk.com>
-rw-r--r-- | TAO/ChangeLog | 23 | ||||
-rw-r--r-- | TAO/tests/Sequence_Unit_Tests/allocation_traits.hpp | 50 | ||||
-rw-r--r-- | TAO/tests/Sequence_Unit_Tests/generic_sequence.hpp | 51 | ||||
-rw-r--r-- | TAO/tests/Sequence_Unit_Tests/string_traits.hpp | 6 | ||||
-rw-r--r-- | TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence.hpp | 9 | ||||
-rw-r--r-- | TAO/tests/Sequence_Unit_Tests/unbounded_string_sequence_ut.cpp | 72 |
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())); } }; |