From 90b5a3736a901873954e5a3a829a20e821535e72 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 6 Dec 2005 13:26:13 +0000 Subject: [PATCH] =?UTF-8?q?Pointer=20utilities=20added=20(proposed=20by=20?= =?UTF-8?q?Ion=20Gazta=C3=B1aga)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [SVN r31932] --- include/boost/pointer_cast.hpp | 45 +++++++++++ include/boost/pointer_to_other.hpp | 55 +++++++++++++ pointer_cast.html | 105 ++++++++++++++++++++++++ test/Jamfile | 2 + test/Jamfile.v2 | 2 + test/pointer_cast_test.cpp | 126 +++++++++++++++++++++++++++++ test/pointer_to_other_test.cpp | 74 +++++++++++++++++ 7 files changed, 409 insertions(+) create mode 100644 include/boost/pointer_cast.hpp create mode 100644 include/boost/pointer_to_other.hpp create mode 100644 pointer_cast.html create mode 100644 test/pointer_cast_test.cpp create mode 100644 test/pointer_to_other_test.cpp diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp new file mode 100644 index 0000000..5a5bec0 --- /dev/null +++ b/include/boost/pointer_cast.hpp @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 2005. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_POINTER_CAST_HPP +#define BOOST_POINTER_CAST_HPP + +namespace boost { + +//static_pointer_cast overload for raw pointers +template +inline T* static_pointer_cast(U *ptr) +{ + return static_cast(ptr); +} + +//dynamic_pointer_cast overload for raw pointers +template +inline T* dynamic_pointer_cast(U *ptr) +{ + return dynamic_cast(ptr); +} + +//const_pointer_cast overload for raw pointers +template +inline T* const_pointer_cast(U *ptr) +{ + return const_cast(ptr); +} + +//reinterpret_pointer_cast overload for raw pointers +template +inline T* reinterpret_pointer_cast(U *ptr) +{ + return reinterpret_cast(ptr); +} + +} // namespace boost + +#endif //BOOST_POINTER_CAST_HPP diff --git a/include/boost/pointer_to_other.hpp b/include/boost/pointer_to_other.hpp new file mode 100644 index 0000000..1cf2627 --- /dev/null +++ b/include/boost/pointer_to_other.hpp @@ -0,0 +1,55 @@ +#ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED +#define BOOST_POINTER_TO_OTHER_HPP_INCLUDED + +// +// pointer_to_other.hpp +// +// (C) Copyright Ion Gaztaņaga 2005. +// Copyright (c) 2005 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/smart_ptr/pointer_to_other.html +// + +namespace boost +{ + +// Defines the same pointer type (raw or smart) to another pointee type + +template +struct pointer_to_other; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template +struct pointer_to_other< T*, U > +{ + typedef U* type; +}; + +} // namespace boost + +#endif // #ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED diff --git a/pointer_cast.html b/pointer_cast.html new file mode 100644 index 0000000..8f14795 --- /dev/null +++ b/pointer_cast.html @@ -0,0 +1,105 @@ + + + + pointer_cast.hpp + + +

C++ BoostPointer + cast functions

+

The pointer cast functions (boost::static_pointer_cast boost::dynamic_pointer_cast + boost::reinterpret_pointer_cast boost::const_pointer_cast) + provide a way to write generic pointer castings for raw pointers. The functions + are defined in boost/pointer_cast.hpp.

+

There is test/example code in pointer_cast_test.cpp.

+

Rationale

+

Boost smart pointers usually overload those functions to provide a mechanism to + emulate pointers casts. For example, boost::shared_ptr<...> implements + a static pointer cast this way:

+
+template<class T, class U>
+    shared_ptr<T> static_pointer_cast(shared_ptr<U> const &r);
+
+

Pointer cast functions from boost/pointer_cast.hpp + are overloads of boost::static_pointer_cast, boost::dynamic_pointer_cast, + boost::reinterpret_pointer_cast and boost::const_pointer_cast + for raw pointers. This way when developing pointer type independent classes, + for example, memory managers or shared memory compatible classes, the same code + can be used for raw and smart pointers.

+

Synopsis

+
+
+namespace boost {
+
+template<class T, class U>
+inline T* static_pointer_cast(U *ptr)
+  { return static_cast<T*>(ptr); }
+
+template<class T, class U>
+inline T* dynamic_pointer_cast(U *ptr)
+  { return dynamic_cast<T*>(ptr); }
+
+template<class T, class U>
+inline T* const_pointer_cast(U *ptr)
+  { return const_cast<T*>(ptr); }
+
+template<class T, class U>
+inline T* reinterpret_pointer_cast(U *ptr)
+  { return reinterpret_cast<T*>(ptr); }
+  
+} // namespace boost
+
+
+

As you can see from the above synopsis, the pointer cast functions are just + wrappers around standard C++ cast operators.

+

Example

+
+
+#include <boost/pointer_cast.hpp>
+#include <boost/shared_ptr.hpp>
+
+class base
+{
+public:
+
+   virtual ~base()
+   {
+   }
+};
+
+class derived: public base
+{
+};
+
+template <class BasePtr>
+void check_if_it_is_derived(const BasePtr &ptr)
+{
+   assert(boost::dynamic_pointer_cast<derived>(ptr) != 0);
+}
+
+int main()
+{
+   // Create a raw and a shared_ptr
+
+   base *ptr = new derived;
+   boost::shared_ptr<base> sptr(new derived);
+   
+   // Check that base pointer points actually to derived class
+
+   check_if_it_is_derived(ptr);
+   check_if_it_is_derived(sptr);
+   
+   // Ok!
+   
+   delete ptr;
+   return 0;
+}
+
+

The example demonstrates how the generic pointer casts help us create pointer + independent code.

+
+

Revised: $Date$

+

Copyright 2005 Ion Gaztaņaga. Use, modification, and distribution are subject to + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

+ + diff --git a/test/Jamfile b/test/Jamfile index 9e92713..e97bfd0 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -31,6 +31,8 @@ DEPENDS all : smart_ptr ; [ compile-fail shared_ptr_assign_fail.cpp ] [ compile-fail shared_ptr_delete_fail.cpp ] [ run shared_ptr_alloc2_test.cpp ] + [ run pointer_cast_test.cpp ] + [ compile pointer_to_other_test.cpp ] ; # this one is too slow to run unless explicitly requested, and ALL diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c2237e4..2a6e91b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,5 +25,7 @@ import testing ; [ compile-fail shared_ptr_assign_fail.cpp ] [ compile-fail shared_ptr_delete_fail.cpp ] [ run shared_ptr_alloc2_test.cpp ] + [ run pointer_cast_test.cpp ] + [ compile pointer_to_other_test.cpp ] ; } diff --git a/test/pointer_cast_test.cpp b/test/pointer_cast_test.cpp new file mode 100644 index 0000000..0d5d652 --- /dev/null +++ b/test/pointer_cast_test.cpp @@ -0,0 +1,126 @@ +// +// pointer_cast_test.cpp - a test for boost/pointer_cast.hpp +// +// Copyright (c) 2005 Ion Gaztaņaga +// Copyright (c) 2005 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +#include +#include +#include + +#include + +namespace +{ + +// Let's create these inheritance relationship: +// +// base base2 +// | | +// derived +// | +// derived_derived +// + +class base +{ + public: + virtual ~base(){} + int filler [5]; +}; + +class base2 +{ +public: + + virtual ~base2(){} + int filler [5]; +}; + +class derived + : public base, public base2 +{ + int filler [5]; +}; + +class derived_derived + : public derived +{ + int filler [5]; +}; + +// And now some simple check functions + +template +bool check_dynamic_pointer_cast(const BasePtr &ptr) +{ + //Check that dynamic_pointer_cast versus dynamic_cast + return + //Correct cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Correct cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)) + && + //Incorrect cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Incorrect cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)); +} + +template +bool check_static_pointer_cast(const BasePtr &ptr) +{ + return + //Cast base -> derived -> base2 using static_pointer_cast + boost::get_pointer( + boost::static_pointer_cast( + boost::static_pointer_cast(ptr))) == + //Now the same with static_cast + static_cast(static_cast(boost::get_pointer(ptr))); +} + +template +bool check_const_pointer_cast(const BasePtr &ptr) +{ + return + //Unconst and const again using const_pointer_cast + boost::get_pointer( + boost::const_pointer_cast + (boost::const_pointer_cast(ptr))) == + //Now the same with const_cast + const_cast(const_cast(boost::get_pointer(ptr))); +} + +} + +int main() +{ + { + // Try casts with shared_ptr + + boost::shared_ptr ptr(new derived); + + BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); + BOOST_TEST( check_static_pointer_cast( ptr ) ); + BOOST_TEST( check_const_pointer_cast( ptr ) ); + } + + { + // Try casts with raw pointer + + boost::scoped_ptr ptr(new derived); + + BOOST_TEST( check_dynamic_pointer_cast( ptr.get() ) ); + BOOST_TEST( check_static_pointer_cast( ptr.get() ) ); + BOOST_TEST( check_const_pointer_cast( ptr.get() ) ); + } + + return boost::report_errors(); +} diff --git a/test/pointer_to_other_test.cpp b/test/pointer_to_other_test.cpp new file mode 100644 index 0000000..c2ee187 --- /dev/null +++ b/test/pointer_to_other_test.cpp @@ -0,0 +1,74 @@ +// +// pointer_to_other_test.cpp - a test for boost/pointer_to_other.hpp +// +// Copyright (c) 2005 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +#include +#include +#include +#include +#include + +#include + +template void assert_same_type( T** pt = 0, U** pu = 0 ) +{ + pt = pu; +} + +struct X; +struct Y; + +int main() +{ + // shared_ptr + + assert_same_type< boost::pointer_to_other< boost::shared_ptr, Y >::type, boost::shared_ptr >(); + assert_same_type< boost::pointer_to_other< boost::shared_ptr, void >::type, boost::shared_ptr >(); + assert_same_type< boost::pointer_to_other< boost::shared_ptr, Y >::type, boost::shared_ptr >(); + + // shared_array + + assert_same_type< boost::pointer_to_other< boost::shared_array, Y >::type, boost::shared_array >(); + assert_same_type< boost::pointer_to_other< boost::shared_array, void >::type, boost::shared_array >(); + assert_same_type< boost::pointer_to_other< boost::shared_array, Y >::type, boost::shared_array >(); + + // scoped_ptr + + assert_same_type< boost::pointer_to_other< boost::scoped_ptr, Y >::type, boost::scoped_ptr >(); + assert_same_type< boost::pointer_to_other< boost::scoped_ptr, void >::type, boost::scoped_ptr >(); + assert_same_type< boost::pointer_to_other< boost::scoped_ptr, Y >::type, boost::scoped_ptr >(); + + // scoped_array + + assert_same_type< boost::pointer_to_other< boost::scoped_array, Y >::type, boost::scoped_array >(); + assert_same_type< boost::pointer_to_other< boost::scoped_array, void >::type, boost::scoped_array >(); + assert_same_type< boost::pointer_to_other< boost::scoped_array, Y >::type, boost::scoped_array >(); + + // intrusive_ptr + + assert_same_type< boost::pointer_to_other< boost::intrusive_ptr, Y >::type, boost::intrusive_ptr >(); + assert_same_type< boost::pointer_to_other< boost::intrusive_ptr, void >::type, boost::intrusive_ptr >(); + assert_same_type< boost::pointer_to_other< boost::intrusive_ptr, Y >::type, boost::intrusive_ptr >(); + + // auto_ptr + + assert_same_type< boost::pointer_to_other< std::auto_ptr, Y >::type, std::auto_ptr >(); + assert_same_type< boost::pointer_to_other< std::auto_ptr, void >::type, std::auto_ptr >(); + assert_same_type< boost::pointer_to_other< std::auto_ptr, Y >::type, std::auto_ptr >(); + + // raw pointer + + assert_same_type< boost::pointer_to_other< X *, Y >::type, Y * >(); + assert_same_type< boost::pointer_to_other< X *, void >::type, void * >(); + assert_same_type< boost::pointer_to_other< void *, Y >::type, Y * >(); + + return 0; +}