summaryrefslogtreecommitdiff
path: root/libs/conversion
diff options
context:
space:
mode:
Diffstat (limited to 'libs/conversion')
-rw-r--r--libs/conversion/README.md16
-rw-r--r--libs/conversion/cast.htm66
-rw-r--r--libs/conversion/index.html8
-rw-r--r--libs/conversion/test/implicit_cast.cpp2
-rw-r--r--libs/conversion/test/polymorphic_cast_test.cpp222
5 files changed, 301 insertions, 13 deletions
diff --git a/libs/conversion/README.md b/libs/conversion/README.md
new file mode 100644
index 000000000..35f99751a
--- /dev/null
+++ b/libs/conversion/README.md
@@ -0,0 +1,16 @@
+#[Boost.Conversion](http://boost.org/libs/conversion)
+Boost.Conversion is one of the [Boost C++ Libraries](http://github.com/boostorg). This library improves program safety and clarity by performing otherwise messy conversions.
+
+### Test results
+
+@ | Build | Tests coverage | More info
+----------------|-------------- | -------------- |-----------
+Develop branch: | [![Build Status](https://travis-ci.org/apolukhin/conversion.svg?branch=develop)](https://travis-ci.org/apolukhin/conversion) | [![Coverage Status](https://coveralls.io/repos/apolukhin/conversion/badge.png?branch=develop)](https://coveralls.io/r/apolukhin/conversion?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/conversion.html)
+Master branch: | [![Build Status](https://travis-ci.org/apolukhin/conversion.svg?branch=master)](https://travis-ci.org/apolukhin/conversion) | [![Coverage Status](https://coveralls.io/repos/apolukhin/conversion/badge.png?branch=master)](https://coveralls.io/r/apolukhin/conversion?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/conversion.html)
+
+
+[Open Issues](https://svn.boost.org/trac/boost/query?status=!closed&component=conversion&or&status=!closed&component=lexical_cast)
+
+### License
+
+Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
diff --git a/libs/conversion/cast.htm b/libs/conversion/cast.htm
index 208b960f2..e1c466d56 100644
--- a/libs/conversion/cast.htm
+++ b/libs/conversion/cast.htm
@@ -26,10 +26,12 @@
<h2><a name="Cast Functions">Cast Functions</a></h2>
- <p>The header <a href="../../boost/polymorphic_cast.hpp">boost/polymorphic_cast.hpp</a> provides <code>
- <a href="#Polymorphic_cast">polymorphic_cast</a> and</code> <a href=
- "#Polymorphic_cast"><code>polymorphic_downcast</code></a> function templates designed to
- complement the C++ built-in casts.</p>
+ <p>The header <a href="../../boost/polymorphic_cast.hpp">boost/polymorphic_cast.hpp</a> provides
+ <code><a href="#Polymorphic_cast">polymorphic_cast</a></code> and
+ <code><a href="#Polymorphic_cast">polymorphic_downcast</a></code>
+ function templates designed to complement the C++ built-in casts.</p> <p>The header <a href="../../boost/polymorphic_pointer_cast.hpp">boost/polymorphic_pointer_cast.hpp</a> provides
+ <code><a href="#Polymorphic_cast">polymorphic_pointer_cast</a></code> and
+ <code><a href="#Polymorphic_cast">polymorphic_pointer_downcast</a></code> function templates.
<p>The program <a href="test/cast_test.cpp">cast_test.cpp</a> can be used to
verify these function templates work as expected.</p>
@@ -78,7 +80,7 @@
<b>Warning:</b> Because <code>polymorphic_downcast</code> uses assert(), it
violates the One Definition Rule (ODR) if NDEBUG is inconsistently
defined across translation units. [See ISO Std 3.2]
-</p><p>
+ <p>
For crosscasts, or when the success of a cast can only be known at
runtime, or when efficiency is not important,
<code>polymorphic_cast</code> is preferred. </p>
@@ -88,7 +90,18 @@
whether a given interface is supported; in that case a return of 0 isn't
an error condition.</p>
- <h3>polymorphic_cast and polymorphic_downcast synopsis</h3>
+ <p>While <code>polymorphic_downcast</code> and <code>polymorphic_cast</code> work with built-in pointer types only,
+ <code>polymorphic_pointer_downcast</code> and <code>polymorphic_pointer_cast</code> are more generic versions
+ with support for any pointer type for which the following expressions would be valid:<br><br>
+
+ <p> For <code>polymorphic_pointer_downcast</code>:</p>
+ <code>&nbsp;&nbsp;static_pointer_cast&lt;Derived&gt;(p);<br>&nbsp;&nbsp;dynamic_pointer_cast&lt;Derived&gt;(p);</code><br><br>
+
+ <p> For <code>polymorphic_pointer_cast</code>:</p>
+ <code>&nbsp;&nbsp;dynamic_pointer_cast&lt;Derived&gt;(p);<br>&nbsp;&nbsp;!p; // conversion to bool with negation</code><br><br>
+ <p>This includes C++ built-in pointers, <code>std::shared_ptr, boost::shared_ptr, boost::intrusive_ptr</code>, etc.</p>
+
+ <h3>polymorphic_cast, polymorphic_downcast, polymorphic_pointer_cast and polymorphic_pointer_downcast synopsis</h3>
<blockquote>
<pre>namespace boost {
@@ -103,6 +116,16 @@ inline Derived polymorphic_downcast(Base* x);
// Effects: assert( dynamic_cast&lt;Derived&gt;(x) == x );
// Returns: static_cast&lt;Derived&gt;(x)
+template &lt;class Derived, class Base&gt;
+inline auto polymorphic_pointer_cast(Base x);
+// Throws: std::bad_cast if ( dynamic_pointer_cast&lt;Derived&gt;(x) == 0 )
+// Returns: dynamic_pointer_cast&lt;Derived&gt;(x)
+
+template &lt;class Derived, class Base&gt;
+inline auto polymorphic_pointer_downcast(Base x);
+// Effects: assert( dynamic_pointer_cast&lt;Derived&gt;(x) == x );
+// Returns: static_pointer_cast&lt;Derived&gt;(x)
+
}
</pre>
</blockquote>
@@ -122,14 +145,41 @@ void f( Fruit * fruit ) {
</pre>
</blockquote>
+ <h3>polymorphic_pointer_downcast example</h3>
+
+ <blockquote>
+<pre>#include &lt;boost/polymorphic_pointer_cast.hpp&gt;
+
+class Fruit { public: virtual ~Fruit(){} };
+class Banana : public Fruit {};
+
+// use one of these:
+
+typedef Fruit* FruitPtr;
+typedef std::shared_ptr&lt;Fruit&gt; FruitPtr;
+typedef boost::shared_ptr&lt;Fruit&gt; FruitPtr;
+typedef boost::intrusive_ptr&lt;Fruit&gt; FruitPtr;
+
+void f(FruitPtr fruit)
+{
+ // ... logic which leads us to believe it is a banana
+ auto banana = boost::polymorphic_pointer_downcast&lt;Banana&gt;(fruit);
+ ...
+}
+</pre>
+ </blockquote>
+
<h3>History</h3>
<p><code>polymorphic_cast</code> was suggested by Bjarne Stroustrup in "The C++
Programming Language".<br>
<code>polymorphic_downcast</code> was contributed by <a href=
- "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a>.<code><br>
+ "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a>.<br>
+ <code>polymorphic_pointer_downcast</code> was contributed by <a href=
+ "http://www.boost.org/people/boris_rasin.htm">Boris Rasin</a> and
+ <code>polymorphic_pointer_cast</code> by Antony Polukhin.<br>
An old
- numeric_cast</code> that was contributed by <a href=
+ <code>numeric_cast</code> that was contributed by <a href=
"http://www.boost.org/people/kevlin_henney.htm">Kevlin Henney</a> is now superseeded by the <a href="../numeric/conversion/doc/html/index.html">Boost Numeric Conversion Library</a></p>
<hr>
diff --git a/libs/conversion/index.html b/libs/conversion/index.html
index fbfe63a5b..afc39d3f7 100644
--- a/libs/conversion/index.html
+++ b/libs/conversion/index.html
@@ -27,10 +27,14 @@ Standard's built-in casts.</p>
Conversion Library is
supplied by several headers:</p>
<ul>
- <li>The <a href="cast.htm">boost/cast</a> header provides <b>polymorphic_cast&lt;&gt;</b>
- and <b>polymorphic_downcast&lt;&gt;</b> to perform safe casting between
+ <li>The <a href="cast.htm">boost/polymorphic_cast.hpp and boost/polymorphic_pointer_cast.hpp</a>
+ headers provide <b>polymorphic_cast&lt;&gt;</b>,
+ <b>polymorphic_downcast&lt;&gt;</b> and <b>polymorphic_pointer_downcast&lt;&gt;</b> to perform safe casting between
polymorphic types.<br>
</li>
+ <li>The boost/implicit_cast.hpp header provides <b>implicit_cast&lt;&gt;</b>
+ to perform implicit casts only (no down-cast, no void*->T*, no U->T if T has only explicit constructors for U).<br>
+ </li>
<li>The <a href="../../doc/html/boost_lexical_cast.html">boost/lexical_cast</a> header provides <b>lexical_cast&lt;&gt;</b>
general literal text conversions, such as an <code>int</code> represented as
a <code>string</code>, or vice-versa.</li>
diff --git a/libs/conversion/test/implicit_cast.cpp b/libs/conversion/test/implicit_cast.cpp
index 0cad067cf..eaca42a83 100644
--- a/libs/conversion/test/implicit_cast.cpp
+++ b/libs/conversion/test/implicit_cast.cpp
@@ -29,7 +29,7 @@ int main()
type<foo> f = check_return(boost::implicit_cast<foo>("hello"));
type<long> z = check_return(boost::implicit_cast<long>(foo("hello")));
- // warning supression:
+ // warning suppression:
(void)x;
(void)f;
(void)z;
diff --git a/libs/conversion/test/polymorphic_cast_test.cpp b/libs/conversion/test/polymorphic_cast_test.cpp
index b3f139768..db448503f 100644
--- a/libs/conversion/test/polymorphic_cast_test.cpp
+++ b/libs/conversion/test/polymorphic_cast_test.cpp
@@ -1,9 +1,11 @@
//
-// Test boost::polymorphic_cast, boost::polymorphic_downcast
+// Test boost::polymorphic_cast, boost::polymorphic_downcast and
+// boost::polymorphic_pointer_cast, boost::polymorphic_pointer_downcast
//
// Copyright 1999 Beman Dawes
// Copyright 1999 Dave Abrahams
// Copyright 2014 Peter Dimov
+// Copyright 2014 Boris Rasin, Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0.
//
@@ -12,8 +14,13 @@
#define BOOST_ENABLE_ASSERT_HANDLER
#include <boost/polymorphic_cast.hpp>
+#include <boost/polymorphic_pointer_cast.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+#include <boost/smart_ptr/intrusive_ref_counter.hpp>
#include <boost/core/lightweight_test.hpp>
#include <string>
+#include <memory>
static bool expect_assertion = false;
static int assertion_failed_count = 0;
@@ -37,7 +44,7 @@ void boost::assertion_failed( char const * expr, char const * function, char con
//
-struct Base
+struct Base : boost::intrusive_ref_counter<Base>
{
virtual ~Base() {}
virtual std::string kind() { return "Base"; }
@@ -97,6 +104,67 @@ static void test_polymorphic_cast()
delete base;
}
+static void test_polymorphic_pointer_cast()
+{
+ Base * base = new Derived;
+
+ Derived * derived;
+
+ try
+ {
+ derived = boost::polymorphic_pointer_cast<Derived>( base );
+
+ BOOST_TEST( derived != 0 );
+
+ if( derived != 0 )
+ {
+ BOOST_TEST_EQ( derived->kind(), "Derived" );
+ }
+ }
+ catch( std::bad_cast const& )
+ {
+ BOOST_ERROR( "boost::polymorphic_pointer_cast<Derived>( base ) threw std::bad_cast" );
+ }
+
+ Base2 * base2;
+
+ try
+ {
+ base2 = boost::polymorphic_pointer_cast<Base2>( base ); // crosscast
+
+ BOOST_TEST( base2 != 0 );
+
+ if( base2 != 0 )
+ {
+ BOOST_TEST_EQ( base2->kind2(), "Base2" );
+ }
+ }
+ catch( std::bad_cast const& )
+ {
+ BOOST_ERROR( "boost::polymorphic_pointer_cast<Base2>( base ) threw std::bad_cast" );
+ }
+
+ boost::shared_ptr<Base> sp_base( base );
+ boost::shared_ptr<Base2> sp_base2;
+ try
+ {
+ sp_base2 = boost::polymorphic_pointer_cast<Base2>( sp_base ); // crosscast
+
+ BOOST_TEST( sp_base2 != 0 );
+
+ if( sp_base2 != 0 )
+ {
+ BOOST_TEST_EQ( base2->kind2(), "Base2" );
+ }
+ }
+ catch( std::bad_cast const& )
+ {
+ BOOST_ERROR( "boost::polymorphic_pointer_cast<Base2>( sp_base ) threw std::bad_cast" );
+ }
+
+ // we do not `delete base;` because sahred_ptr is holding base
+}
+
static void test_polymorphic_downcast()
{
Base * base = new Derived;
@@ -115,6 +183,70 @@ static void test_polymorphic_downcast()
delete base;
}
+static void test_polymorphic_pointer_downcast_builtin()
+{
+ Base * base = new Derived;
+
+ Derived * derived = boost::polymorphic_pointer_downcast<Derived>( base );
+
+ BOOST_TEST( derived != 0 );
+
+ if( derived != 0 )
+ {
+ BOOST_TEST_EQ( derived->kind(), "Derived" );
+ }
+
+ // polymorphic_pointer_downcast can't do crosscasts
+
+ delete base;
+}
+
+static void test_polymorphic_pointer_downcast_boost_shared()
+{
+ boost::shared_ptr<Base> base (new Derived);
+
+ boost::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
+
+ BOOST_TEST( derived != 0 );
+
+ if( derived != 0 )
+ {
+ BOOST_TEST_EQ( derived->kind(), "Derived" );
+ }
+}
+
+static void test_polymorphic_pointer_downcast_intrusive()
+{
+ boost::intrusive_ptr<Base> base (new Derived);
+
+ boost::intrusive_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
+
+ BOOST_TEST( derived != 0 );
+
+ if( derived != 0 )
+ {
+ BOOST_TEST_EQ( derived->kind(), "Derived" );
+ }
+}
+
+#ifndef BOOST_NO_CXX11_SMART_PTR
+
+static void test_polymorphic_pointer_downcast_std_shared()
+{
+ std::shared_ptr<Base> base (new Derived);
+
+ std::shared_ptr<Derived> derived = boost::polymorphic_pointer_downcast<Derived>( base );
+
+ BOOST_TEST( derived != 0 );
+
+ if( derived != 0 )
+ {
+ BOOST_TEST_EQ( derived->kind(), "Derived" );
+ }
+}
+
+#endif
+
static void test_polymorphic_cast_fail()
{
Base * base = new Base;
@@ -124,6 +256,21 @@ static void test_polymorphic_cast_fail()
delete base;
}
+static void test_polymorphic_pointer_cast_fail()
+{
+ Base * base = new Base;
+ BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( base ), std::bad_cast );
+ delete base;
+
+ BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::shared_ptr<Base>(new Base) ), std::bad_cast );
+
+#ifndef BOOST_NO_CXX11_SMART_PTR
+ BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( std::shared_ptr<Base>(new Base) ), std::bad_cast );
+#endif
+
+ BOOST_TEST_THROWS( boost::polymorphic_pointer_cast<Derived>( boost::intrusive_ptr<Base>(new Base) ), std::bad_cast );
+}
+
static void test_polymorphic_downcast_fail()
{
Base * base = new Base;
@@ -139,12 +286,83 @@ static void test_polymorphic_downcast_fail()
delete base;
}
+static void test_polymorphic_pointer_downcast_builtin_fail()
+{
+ Base * base = new Base;
+
+ int old_count = assertion_failed_count;
+ expect_assertion = true;
+
+ boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
+
+ BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
+ expect_assertion = false;
+
+ delete base;
+}
+
+static void test_polymorphic_pointer_downcast_boost_shared_fail()
+{
+ boost::shared_ptr<Base> base (new Base);
+
+ int old_count = assertion_failed_count;
+ expect_assertion = true;
+
+ boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
+
+ BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
+ expect_assertion = false;
+}
+
+#ifndef BOOST_NO_CXX11_SMART_PTR
+
+static void test_polymorphic_pointer_downcast_std_shared_fail()
+{
+ std::shared_ptr<Base> base (new Base);
+
+ int old_count = assertion_failed_count;
+ expect_assertion = true;
+
+ boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
+
+ BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
+ expect_assertion = false;
+}
+
+#endif
+
+static void test_polymorphic_pointer_downcast_intrusive_fail()
+{
+ boost::intrusive_ptr<Base> base (new Base);
+
+ int old_count = assertion_failed_count;
+ expect_assertion = true;
+
+ boost::polymorphic_pointer_downcast<Derived>( base ); // should assert
+
+ BOOST_TEST_EQ( assertion_failed_count, old_count + 1 );
+ expect_assertion = false;
+}
+
int main()
{
test_polymorphic_cast();
+ test_polymorphic_pointer_cast();
test_polymorphic_downcast();
+ test_polymorphic_pointer_downcast_builtin();
+ test_polymorphic_pointer_downcast_boost_shared();
+ test_polymorphic_pointer_downcast_intrusive();
test_polymorphic_cast_fail();
+ test_polymorphic_pointer_cast_fail();
test_polymorphic_downcast_fail();
+ test_polymorphic_pointer_downcast_builtin_fail();
+ test_polymorphic_pointer_downcast_boost_shared_fail();
+ test_polymorphic_pointer_downcast_intrusive_fail();
+
+#ifndef BOOST_NO_CXX11_SMART_PTR
+ test_polymorphic_pointer_downcast_std_shared();
+ test_polymorphic_pointer_downcast_std_shared_fail();
+#endif
return boost::report_errors();
}