$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r54418 - sandbox/monotonic/libs/monotonic/test/clones
From: christian.schladetsch_at_[hidden]
Date: 2009-06-27 21:07:41
Author: cschladetsch
Date: 2009-06-27 21:07:40 EDT (Sat, 27 Jun 2009)
New Revision: 54418
URL: http://svn.boost.org/trac/boost/changeset/54418
Log:
udpoated
Text files modified: 
   sandbox/monotonic/libs/monotonic/test/clones/main.cpp |   187 +++++++++++++++++++++++++++++---------- 
   1 files changed, 140 insertions(+), 47 deletions(-)
Modified: sandbox/monotonic/libs/monotonic/test/clones/main.cpp
==============================================================================
--- sandbox/monotonic/libs/monotonic/test/clones/main.cpp	(original)
+++ sandbox/monotonic/libs/monotonic/test/clones/main.cpp	2009-06-27 21:07:40 EDT (Sat, 27 Jun 2009)
@@ -1,79 +1,172 @@
+//
+// test cases for ptr_container and clone_allocator issues
+//
 
 #include <iostream>
-#include <vector>
 #include <boost/ptr_container/ptr_vector.hpp>
 #include <boost/monotonic/allocator.hpp>
 
 using namespace std;
 using namespace boost;
 
-struct type_number
-{
-	int value;
-	enum 
+namespace boost 
+{ 
+	//namespace ptr_container {
+
+	namespace cloneable 
         {
-		None = 0,
-		Base = 1,
-		Derived = 2,
-	};
-	type_number(int n = None) : value(n) { }
-};
 
-struct base
-{
-	type_number type;
+		// common base for all base types for hierachies
+		struct base_base
+		{
+			virtual ~base_base() { }
+
+			// this can't work because it doesnt have an allocator :/
+			virtual base_base *clone() const = 0;
+		};
+
+		template <class Derived>
+		struct base : base_base
+		{
+			typedef Derived derived_type;
+
+			// idea: pass the allocator to a non-virtual clone_with(alloc) method in the base.
+			// must be disabled at compile-time for types that are not boost::is_convertible<base<D> *, D*>
+			template <class Alloc>
+			static derived_type *clone_with(Alloc &alloc)
+			{
+				derived_type *copy = alloc.allocate(1);
+				// passing ctor args is an outstanding issue; can be helped by:
+				//	1. over-riding clone_with in derived
+				//  2. using super-set allocators with variadic template args for construct method
+				alloc.construct(copy);	
+				return copy;
+			}
+		};
+		
+		struct allocator
+		{
+			template< class U >
+			static U* allocate_clone( const U& r )
+			{
+				// this is not allocated using the parent containers custom allocator
+				return r.clone();
+			}
+
+			template< class U >
+			static void deallocate_clone( const U* clone )
+			{
+				// this is not de-allocated using the parent containers custom allocator
+				//! ??clone->deallocate();??
+				//! delete clone;			// this is not correct either; also calls dtor
+
+				// this is not correct either, but seems the best we can do...?
+				std::allocator<char> alloc;
+				U *ptr = const_cast<U *>(clone);
+				alloc.deallocate(reinterpret_cast<char *>(ptr), 1);
+			}
+
+			// idea: pass allocator to the clone_allocator.
+			// allocator rebind could be done in the ptr_container.
+			template< class U, class Alloc >
+			static U* allocate_clone( const U& r, Alloc &alloc )
+			{
+				typedef typename Alloc::template rebind<U>::other my_alloc(alloc);
+				return r.clone_with(my_alloc);
+			}
+
+			// idea: this is not even needed? 
+			// allocator rebind could be done in the ptr_container
+			template< class U, class Alloc >
+			static U* deallocate_clone( const U* r, Alloc &alloc )
+			{
+				typedef typename Alloc::template rebind<U>::other my_alloc(alloc);
+				my_alloc.deallocate(const_cast<U *>(r));
+			}
+		};
 
-	explicit base(type_number t) : type(t) { }
-	virtual ~base() { }
+	} // namespace cloneable
 
-	virtual base *clone() const = 0;
-};
+} // namespace boost
+
+// client code...
 
-struct derived : base
+struct derived : cloneable::base<derived>
 {
         int num;
-	explicit derived(int n) : base(type_number::Derived), num(n) { }
 
-	base *clone() const
+	derived() : num(0) { }
+	explicit derived(int n) : num(n) { }
+
+	// this can't work
+	cloneable::base_base *clone() const
         {
+		// this is really no good as it doesnt use the correct allocator
                 return new derived(num);
         }
 };
 
-struct clone_allocator
+struct derived2 : cloneable::base<derived2>
 {
-	template< class U >
-	static U* allocate_clone( const U& r )
-	{
-		return r.clone();
-	}
+	string str;
+
+	derived2() { }
+	explicit derived2(string const &n) : str(n) { }
 
-	template< class U >
-	static void deallocate_clone( const U* clone )
+	// this can't work
+	cloneable::base_base *clone() const
         {
-		if (clone)
-			clone->U::~U();
+		// this is really no good as it doesnt use the correct allocator
+		return new derived2(str);
         }
 };
 
+/*
+
+namespace boost { namespace ptr_container {
+
+// idea: switch allocator type ordering, default to cloneable::allcoator
+template <class T, class Al = std::allocator<T>, class CloneAl = cloneable::allocator>
+class ptr_vector;
+
+}}
+
+*/
+
 int main()
 {
-	typedef ptr_vector<base, clone_allocator, monotonic::allocator<int> > vec;
-	// why ptr_vector<..> p(n) resize the vector to have n default-constructed elements? 
-	// it only reserves n elements at the moment...
-	//vec bases(1);
-	//bases[0] = derived(42);  // throws out of range error
-
-	//vec bases;
-	//bases.resize(1);			// doesnt work because it cannot instantiate an abstract class
-	//bases[0] = derived(42);
-
-	vec bases;
-	bases.push_back(new derived(42));
-
-	vec copy = bases;
-	BOOST_ASSERT(copy.size() == 1);
-	BOOST_ASSERT(copy.at(0).type.value == type_number::Derived);
+	typedef ptr_vector<cloneable::base_base, cloneable::allocator, monotonic::allocator<int> > vec;
+
+	{
+		vec bases;
+		BOOST_ASSERT(bases.get_allocator().get_storage() == &monotonic::static_storage<>::get_storage());
+
+		//! bases.push_back(new derived(42));					// this doesn't use the custom allocator!
+		//! derived *obj = bases.get_allocator().allocate(1);	// this has to be recast
+
+		// do a dance to get the object into the container...
+		typedef vec::allocator_type::template rebind<derived>::other derived_alloc_type;
+		derived_alloc_type derived_alloc(bases.get_allocator());
+		derived *obj = derived_alloc.allocate(1);
+		//! derived_alloc.construct(obj, 42);		// can't pass ctor args to a v1 allocator
+		new (obj) derived(42);						// bypassing allocator::construct :/
+
+		// finally get the correctly allocated object into the container
+		bases.push_back(obj);
+
+		// idea: use variadic template arguments for push_back etc: 
+		// default to use BOOST_PP for C++03
+		//! bases.push_back<derived>(ctor_args...);
+
+		// ...promptly breaks everything by using the heap to make the clones in copy :/
+		vec copy = bases;
+
+		// idea: could be fixed by using base<derived>::clone_with(orig, rebind(alloc)) in the ptr_container...
+
+		// doesn't work because the clones were put on the heap. could work with cloneable:: ?
+		monotonic::static_storage<>::release();
+	}
+
         return 0;
 }