Merge pull request #8 from cdglove/runtime_cast

Add the concept of runtime_cast to type index as an emulation of dynamic_cast..
This commit is contained in:
Antony Polukhin
2016-09-29 00:45:39 +04:00
committed by GitHub
14 changed files with 789 additions and 0 deletions
+1
View File
@@ -11,6 +11,7 @@ doxygen autodoc
:
[ glob ../../../boost/type_index.hpp ]
[ glob ../../../boost/type_index/*.hpp ]
[ glob ../../../boost/type_index/runtime_cast/*.hpp ]
:
<doxygen:param>EXTRACT_ALL=NO
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
+7
View File
@@ -246,6 +246,10 @@ Depending on the `typeid()` availability TypeIndex library will choose an optima
[macroref BOOST_TYPE_INDEX_REGISTER_CLASS] macro is a helper macro that places some virtual helper functions or
expands to nothing.
[macroref BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS] macro is a helper macro that places the same
helpers as BOOST_TYPE_INDEX_REGISTER_CLASS plus some additional helpers for boost::typeindex::runtime_cast
to function.
Issues with cross module type comparison on a bugged compilers are bypassed by directly comparing strings with type
(latest versions of those compilers resolved that issue using exactly the same approach).
@@ -262,6 +266,9 @@ Issues with cross module type comparison on a bugged compilers are bypassed by d
[import ../examples/inheritance.cpp]
[section Getting through the inheritance to receive a real type name ] [type_index_derived_example] [endsect]
[import ../examples/runtime_cast.cpp]
[section Using runtime_cast where RTTI is unavailable or undesirable ] [type_index_runtime_cast_example] [endsect]
[import ../examples/exact_types_match.cpp]
[section Exact type matching: storing type with const, volatile and reference qualifiers] [type_index_exact_type_match_example] [endsect]
+2
View File
@@ -17,6 +17,8 @@
#include <boost/type_index.hpp>
#include <iostream>
#include <stdexcept>
#include <cstdlib>
//<-
// Making `#include <cassert>` visible in docs, while actually using hand-made check
// instead of `assert`. This is required to verify correct behavior even if NDEBUG
+11
View File
@@ -13,6 +13,7 @@
*/
#include <boost/type_index.hpp>
#include <boost/type_index/runtime_cast/register_runtime_class.hpp>
#include <iostream>
struct A {
@@ -21,6 +22,7 @@ struct A {
};
struct B: public A { BOOST_TYPE_INDEX_REGISTER_CLASS };
struct C: public B { BOOST_TYPE_INDEX_REGISTER_CLASS };
struct D: public C { BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS) };
void print_real_type(const A& a) {
std::cout << boost::typeindex::type_id_runtime(a).pretty_name() << '\n';
@@ -31,6 +33,15 @@ int main() {
const A& c_as_a = c;
print_real_type(c_as_a); // Outputs `struct C`
print_real_type(B()); // Outputs `struct B`
/*`
It's also possible to use type_id_runtime with the BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS, which adds additional
information for runtime_cast to work.
*/
D d;
const A& d_as_a = d;
print_real_type(d_as_a); // Outputs `struct D`
}
//] [/type_index_derived_example]
+90
View File
@@ -0,0 +1,90 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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)
//
//[type_index_runtime_cast_example
/*`
The following example shows that `runtime_cast` is able to find a valid pointer
in various class hierarchies regardless of inheritance or type relation.
Example works with and without RTTI."
*/
#include <boost/type_index/runtime_cast.hpp>
#include <iostream>
struct A {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
virtual ~A()
{}
};
struct B {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
virtual ~B()
{}
};
struct C : A {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((A))
};
struct D : B {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((B))
};
struct E : C, D {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((C)(D))
};
int main() {
C c;
A* a = &c;
if(C* cp = boost::typeindex::runtime_cast<C*>(a)) {
std::cout << "Yes, a points to a C: "
<< a << "->" << cp << '\n';
}
else {
std::cout << "Error: Expected a to point to a C" << '\n';
}
if(E* ce = boost::typeindex::runtime_cast<E*>(a)) {
std::cout << "Error: Expected a to not points to an E: "
<< a << "->" << ce << '\n';
}
else {
std::cout << "But, a does not point to an E" << '\n';
}
E e;
C* cp2 = &e;
if(D* dp = boost::typeindex::runtime_cast<D*>(cp2)) {
std::cout << "Yes, we can cross-cast from a C* to a D* when we actually have an E: "
<< cp2 << "->" << dp << '\n';
}
else {
std::cout << "Error: Expected cp to point to a D" << '\n';
}
/*`
Alternatively, we can use runtime_pointer_cast so we don't need to specity the target as a pointer.
This works for smart_ptr types too.
*/
A* ap = &e;
if(B* bp = boost::typeindex::runtime_pointer_cast<B>(ap)) {
std::cout << "Yes, we can cross-cast and up-cast at the same time."
<< ap << "->" << bp << '\n';
}
else {
std::cout << "Error: Expected ap to point to a B" << '\n';
}
return 0;
}
//] [/type_index_runtime_cast_example]
+28
View File
@@ -0,0 +1,28 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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_TYPE_INDEX_RUNTIME_CAST_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_HPP
/// \file runtime_cast.hpp
/// \brief Contains the basic utilities necessary to fully emulate
/// dynamic_cast for language level constructs (raw pointers and references).
///
/// boost::typeindex::runtime_cast is a drop in replacement for dynamic_cast
/// that can be used in situations where traditional rtti is either unavailable
/// or undesirable.
#include <boost/type_index/runtime_cast/register_runtime_class.hpp>
#include <boost/type_index/runtime_cast/pointer_cast.hpp>
#include <boost/type_index/runtime_cast/reference_cast.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_HPP
@@ -0,0 +1,46 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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_TYPE_INDEX_RUNTIME_CAST_BOOST_SHARED_PTR_CAST_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_BOOST_SHARED_PTR_CAST_HPP
/// \file boost_shared_ptr_cast.hpp
/// \brief Contains the overload of boost::typeindex::runtime_pointer_cast for
/// boost::shared_ptr types.
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
/// \brief Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's
/// stored pointer using a runtime_cast.
///
/// The new shared_ptr will share ownership with u, except that it is empty if the runtime_cast
/// performed by runtime_pointer_cast returns a null pointer.
/// \tparam T The desired target type to return a pointer of.
/// \tparam U A complete class type of the source instance pointed to from u.
/// \return If there exists a valid conversion from U* to T*, returns a boost::shared_ptr<T>
/// that points to an address suitably offset from u.
/// If no such conversion exists, returns boost::shared_ptr<T>();
template<typename T, typename U>
boost::shared_ptr<T> runtime_pointer_cast(boost::shared_ptr<U> const& u) {
T* value = detail::runtime_cast_impl<T>(u.get(), boost::is_base_and_derived<T, U>());
if(value)
return boost::shared_ptr<T>(u, value);
return boost::shared_ptr<T>();
}
}} // namespace boost::typeindex
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_BOOST_SHARED_PTR_CAST_HPP
@@ -0,0 +1,57 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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_TYPE_INDEX_RUNTIME_CAST_DETAIL_RUNTIME_CAST_IMPL_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_DETAIL_RUNTIME_CAST_IMPL_HPP
/// \file pointer_class.hpp
/// \brief Contains the overload of boost::typeindex::runtime_cast for
/// pointer types.
///
/// boost::typeindex::runtime_cast can be used to emulate dynamic_cast
/// functionality on platorms that don't provide it or should the user
/// desire opt in functionality instead of enabling it system wide.
#include <boost/type_index.hpp>
#include <boost/type_traits/integral_constant.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
namespace detail {
template<typename T, typename U>
T* runtime_cast_impl(U* u, boost::true_type) BOOST_NOEXCEPT {
return u;
}
template<typename T, typename U>
T const* runtime_cast_impl(U const* u, boost::true_type) BOOST_NOEXCEPT {
return u;
}
template<typename T, typename U>
T* runtime_cast_impl(U* u, boost::false_type) BOOST_NOEXCEPT {
return const_cast<T*>(static_cast<T const*>(
u->boost_type_index_find_instance_(boost::typeindex::type_id<T>())
));
}
template<typename T, typename U>
T const* runtime_cast_impl(U const* u, boost::false_type) BOOST_NOEXCEPT {
return static_cast<T const*>(u->boost_type_index_find_instance_(boost::typeindex::type_id<T>()));
}
} // namespace detail
}} // namespace boost::typeindex
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_DETAIL_RUNTIME_CAST_IMPL_HPP
@@ -0,0 +1,74 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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_TYPE_INDEX_RUNTIME_CAST_POINTER_CAST_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_POINTER_CAST_HPP
/// \file pointer_class.hpp
/// \brief Contains the function overloads of boost::typeindex::runtime_cast for
/// pointer types.
#include <boost/type_index.hpp>
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy.
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
/// \tparam U A complete class type of the source instance, u.
/// \return If there exists a valid conversion from U* to T, returns a T that points to
/// an address suitably offset from u. If no such conversion exists, returns NULL.
template<typename T, typename U>
T runtime_cast(U* u) BOOST_NOEXCEPT {
typedef typename boost::remove_pointer<T>::type impl_type;
return detail::runtime_cast_impl<impl_type>(u, boost::is_base_and_derived<T, U>());
}
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy.
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
/// \tparam U A complete class type of the source instance, u.
/// \return If there exists a valid conversion from U* to T, returns a T that points to
/// an address suitably offset from u. If no such conversion exists, returns NULL.
template<typename T, typename U>
T runtime_cast(U const* u) BOOST_NOEXCEPT {
typedef typename boost::remove_pointer<T>::type impl_type;
return detail::runtime_cast_impl<impl_type>(u, boost::is_base_and_derived<T, U>());
}
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance
/// hierarchy.
/// \tparam T The desired target type to return a pointer to.
/// \tparam U A complete class type of the source instance, u.
/// \return If there exists a valid conversion from U const* to T*, returns a T*
/// that points to an address suitably offset from u.
/// If no such conversion exists, returns NULL.
template<typename T, typename U>
T* runtime_pointer_cast(U* u) BOOST_NOEXCEPT {
return detail::runtime_cast_impl<T>(u, boost::is_base_and_derived<T, U>());
}
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance
/// hierarchy.
/// \tparam T The desired target type to return a pointer to.
/// \tparam U A complete class type of the source instance, u.
/// \return If there exists a valid conversion from U const* to T const*, returns a T const*
/// that points to an address suitably offset from u.
/// If no such conversion exists, returns NULL.
template<typename T, typename U>
T const* runtime_pointer_cast(U const* u) BOOST_NOEXCEPT {
return detail::runtime_cast_impl<T>(u, boost::is_base_and_derived<T, U>());
}
}} // namespace boost::typeindex
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_POINTER_CAST_HPP
@@ -0,0 +1,65 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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_TYPE_INDEX_RUNTIME_CAST_REFERENCE_CAST_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_REFERENCE_CAST_HPP
/// \file reference_cast.hpp
/// \brief Contains the overload of boost::typeindex::runtime_cast for
/// reference types.
#include <boost/core/addressof.hpp>
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#include <boost/throw_exception.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
/// \brief Indicates that runtime_cast was unable to perform the desired cast operation
/// because the source instance was not also an instance of the target type.
struct bad_runtime_cast : std::exception
{};
/// \brief Safely converts references to classes up, down, and sideways along the inheritance hierarchy.
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
/// \tparam U A complete class type of the source instance, u.
/// \return If there exists a valid conversion from U& to T, returns a T that references an address
/// suitably offset from u. If no such conversion exists, throws boost::typeindex::bad_runtime_cast.
template<typename T, typename U>
T& runtime_cast(U& u) {
typedef typename boost::remove_reference<T>::type impl_type;
impl_type* value = detail::runtime_cast_impl<impl_type>(
boost::addressof(u), boost::is_base_and_derived<T, U>());
if(!value)
BOOST_THROW_EXCEPTION(bad_runtime_cast());
return *value;
}
/// \brief Safely converts references to classes up, down, and sideways along the inheritance hierarchy.
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
/// \tparam U A complete class type of the source instance, u.
/// \return If there exists a valid conversion from U const& to T const, returns a T const that references an address
/// suitably offset from u. If no such conversion exists, throws boost::typeindex::bad_runtime_cast.
template<typename T, typename U>
T const& runtime_cast(U const& u) {
typedef typename boost::remove_reference<T>::type impl_type;
impl_type* value = detail::runtime_cast_impl<impl_type>(
boost::addressof(u), boost::is_base_and_derived<T, U>());
if(!value)
BOOST_THROW_EXCEPTION(bad_runtime_cast());
return *value;
}
}} // namespace boost::typeindex
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REFERENCE_CAST_HPP
@@ -0,0 +1,88 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
/// \file register_runtime_class.hpp
/// \brief Contains the macro BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
#include <boost/type_index.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
namespace detail {
template<typename T>
inline type_index runtime_class_construct_type_id(T const*) {
return type_id<T>();
}
} // namespace detail
/// @cond
#define BOOST_TYPE_INDEX_CHECK_BASE_(r, data, Base) \
if(void const* ret_val = this->Base::boost_type_index_find_instance_(idx)) return ret_val;
/// @endcond
/// \def BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
/// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast
///
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS generates a virtual function
/// in the current class that, when combined with the supplied base class information, allows
/// boost::typeindex::runtime_cast to accurately convert between dynamic types of instances of
/// the current class.
///
/// \b Example:
/// \code
/// struct base1 {
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
/// virtual ~base1();
/// };
///
/// struct base2 {
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
/// virtual ~base2();
/// };
///
/// struct derived1 : base1 {
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1))
/// };
///
/// struct derived2 : base1, base2 {
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1)(base2))
/// };
///
/// ...
///
/// base1* pb1 = get_object();
/// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1))
/// { /* ... */ }
/// \endcode
///
/// \param base_class_seq A Boost.Preprocessor sequence of the current class' direct bases, or
/// BOOST_PP_SEQ_NIL if this class has no direct base classes.
#define BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(base_class_seq) \
BOOST_TYPE_INDEX_REGISTER_CLASS \
virtual void const* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) const BOOST_NOEXCEPT { \
if(idx == boost::typeindex::detail::runtime_class_construct_type_id(this)) \
return this; \
BOOST_PP_SEQ_FOR_EACH(BOOST_TYPE_INDEX_CHECK_BASE_, _, base_class_seq) \
return NULL; \
}
}} // namespace boost::typeindex
#define BOOST_TYPE_INDEX_NO_BASE_CLASS BOOST_PP_SEQ_NIL
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
@@ -0,0 +1,46 @@
//
// Copyright (c) Chris Glover, 2016.
//
//
// 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_TYPE_INDEX_RUNTIME_CAST_STD_SHARED_PTR_CAST_HPP
#define BOOST_TYPE_INDEX_RUNTIME_CAST_STD_SHARED_PTR_CAST_HPP
/// \file std_shared_ptr_cast.hpp
/// \brief Contains the overload of boost::typeindex::runtime_pointer_cast for
/// std::shared_ptr types.
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <memory>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
namespace boost { namespace typeindex {
/// \brief Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's
/// stored pointer using a runtime_cast.
///
/// The new shared_ptr will share ownership with u, except that it is empty if the runtime_cast
/// performed by runtime_pointer_cast returns a null pointer.
/// \tparam T The desired target type to return a pointer of.
/// \tparam U A complete class type of the source instance pointed to from u.
/// \return If there exists a valid conversion from U* to T*, returns a std::shared_ptr<T>
/// that points to an address suitably offset from u.
/// If no such conversion exists, returns std::shared_ptr<T>();
template<typename T, typename U>
std::shared_ptr<T> runtime_pointer_cast(std::shared_ptr<U> const& u) {
T* value = detail::runtime_cast_impl<T>(u.get(), boost::is_base_and_derived<T, U>());
if(value)
return std::shared_ptr<T>(u, value);
return std::shared_ptr<T>();
}
}} // namespace boost::typeindex
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_STD_SHARED_PTR_CAST_HPP
+1
View File
@@ -40,6 +40,7 @@ exe testing_crossmodule_anonymous_no_rtti : testing_crossmodule_anonymous.cpp te
test-suite type_index
:
[ run type_index_test.cpp ]
[ run type_index_runtime_cast_test.cpp ]
[ run type_index_constexpr_test.cpp ]
[ run type_index_test.cpp : : : <rtti>off $(norttidefines) : type_index_test_no_rtti ]
[ run ctti_print_name.cpp : : : <test-info>always_show_run_output ]
+273
View File
@@ -0,0 +1,273 @@
//
// Copyright Chris Glover, 2016.
//
// 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 <boost/type_index/runtime_cast.hpp>
// #include <boost/type_index/runtime_reference_cast.hpp>
#include <boost/type_index/runtime_cast.hpp>
#include <boost/type_index/runtime_cast/std_shared_ptr_cast.hpp>
#include <boost/type_index/runtime_cast/boost_shared_ptr_cast.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/core/lightweight_test.hpp>
// Classes include a member variable "name" with the
// name of the class hard coded so we can be sure that
// the pointer offsets are all working, since we're doing
// a cast from void* at some point.
#define IMPLEMENT_CLASS(type_name) \
type_name() : name( #type_name ) {} \
std::string name;
struct base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
IMPLEMENT_CLASS(base)
};
struct single_derived : base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
IMPLEMENT_CLASS(single_derived)
};
struct base1 {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
IMPLEMENT_CLASS(base1)
};
struct base2 {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
IMPLEMENT_CLASS(base2)
};
struct multiple_derived : base1, base2 {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1)(base2))
IMPLEMENT_CLASS(multiple_derived)
};
struct baseV1 : virtual base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
IMPLEMENT_CLASS(baseV1)
};
struct baseV2 : virtual base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
IMPLEMENT_CLASS(baseV2)
};
struct multiple_virtual_derived : baseV1, baseV2 {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((baseV1)(baseV2))
IMPLEMENT_CLASS(multiple_virtual_derived)
};
struct unrelated {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
IMPLEMENT_CLASS(unrelated)
};
struct unrelated_with_base : base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
IMPLEMENT_CLASS(unrelated_with_base)
};
struct unrelatedV1 : virtual base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
IMPLEMENT_CLASS(unrelatedV1)
};
struct level1_a : base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
IMPLEMENT_CLASS(level1_a)
};
struct level1_b : base {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
IMPLEMENT_CLASS(level1_b)
};
struct level2 : level1_a, level1_b {
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((level1_a)(level1_b))
IMPLEMENT_CLASS(level2)
};
void no_base()
{
using namespace boost::typeindex;
base b;
base* b2 = runtime_pointer_cast<base>(&b);
BOOST_TEST_NE(b2, (base*)NULL);
BOOST_TEST_EQ(b2->name, "base");
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&b), (unrelated*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<single_derived>(&b), (single_derived*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelatedV1>(&b), (unrelatedV1*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(&b), (unrelated_with_base*)NULL);
}
void single_base()
{
using namespace boost::typeindex;
single_derived d;
base* b = &d;
single_derived* d2 = runtime_pointer_cast<single_derived>(b);
BOOST_TEST_NE(d2, (single_derived*)NULL);
BOOST_TEST_EQ(d2->name, "single_derived");
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b), (unrelated_with_base*)NULL);
}
void multiple_base()
{
using namespace boost::typeindex;
multiple_derived d;
base1* b1 = &d;
multiple_derived* d2 = runtime_pointer_cast<multiple_derived>(b1);
BOOST_TEST_NE(d2, (multiple_derived*)NULL);
BOOST_TEST_EQ(d2->name, "multiple_derived");
base2* b2 = runtime_pointer_cast<base2>(b1);
BOOST_TEST_NE(b2, (base2*)NULL);
BOOST_TEST_EQ(b2->name, "base2");
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b1), (unrelated*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b1), (unrelated_with_base*)NULL);
}
void virtual_base()
{
using namespace boost::typeindex;
multiple_virtual_derived d;
base* b = &d;
multiple_virtual_derived* d2 = runtime_pointer_cast<multiple_virtual_derived>(b);
baseV1* bv1 = runtime_pointer_cast<baseV1>(b);
baseV2* bv2 = runtime_pointer_cast<baseV2>(b);
BOOST_TEST_NE(d2, (multiple_virtual_derived*)NULL);
BOOST_TEST_EQ(d2->name, "multiple_virtual_derived");
BOOST_TEST_NE(bv1, (baseV1*)NULL);
BOOST_TEST_EQ(bv1->name, "baseV1");
BOOST_TEST_NE(bv2, (baseV2*)NULL);
BOOST_TEST_EQ(bv2->name, "baseV2");
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL);
BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b), (unrelated_with_base*)NULL);
}
void pointer_interface()
{
using namespace boost::typeindex;
single_derived d;
base* b = &d;
single_derived* d2 = runtime_cast<single_derived*>(b);
BOOST_TEST_NE(d2, (single_derived*)NULL);
BOOST_TEST_EQ(d2->name, "single_derived");
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
}
void reference_interface()
{
using namespace boost::typeindex;
single_derived d;
base& b = d;
single_derived& d2 = runtime_cast<single_derived&>(b);
BOOST_TEST_EQ(d2.name, "single_derived");
try {
unrelated& u = runtime_cast<unrelated&>(b);
(void)u;
BOOST_TEST(!"should throw bad_runtime_cast");
}
catch(boost::typeindex::bad_runtime_cast&) {
}
catch(...) {
BOOST_TEST(!"should throw bad_runtime_cast");
}
}
void const_pointer_interface()
{
using namespace boost::typeindex;
const single_derived d;
base const* b = &d;
single_derived const* d2 = runtime_cast<single_derived const*>(b);
BOOST_TEST_NE(d2, (single_derived*)NULL);
BOOST_TEST_EQ(d2->name, "single_derived");
BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
}
void const_reference_interface()
{
using namespace boost::typeindex;
const single_derived d;
base const& b = d;
single_derived const& d2 = runtime_cast<single_derived const&>(b);
BOOST_TEST_EQ(d2.name, "single_derived");
try {
unrelated const& u = runtime_cast<unrelated const&>(b);
(void)u;
BOOST_TEST(!"should throw bad_runtime_cast");
}
catch(boost::typeindex::bad_runtime_cast&) {
}
catch(...) {
BOOST_TEST(!"should throw bad_runtime_cast");
}
}
void diamond_non_virtual()
{
using namespace boost::typeindex;
level2 inst;
level1_a* l1a = &inst;
base* b1 = l1a;
level1_b* l1_b = runtime_cast<level1_b*>(b1);
BOOST_TEST_EQ(l1_b->name, "level1_b");
BOOST_TEST_NE(l1_b, (level1_b*)NULL);
}
void boost_shared_ptr()
{
using namespace boost::typeindex;
boost::shared_ptr<single_derived> d = boost::make_shared<single_derived>();
boost::shared_ptr<base> b = d;
boost::shared_ptr<single_derived> d2 = runtime_pointer_cast<single_derived>(b);
BOOST_TEST_NE(d2, boost::shared_ptr<single_derived>());
BOOST_TEST_EQ(d2->name, "single_derived");
}
void std_shared_ptr()
{
using namespace boost::typeindex;
std::shared_ptr<single_derived> d = std::make_shared<single_derived>();
std::shared_ptr<base> b = d;
std::shared_ptr<single_derived> d2 = runtime_pointer_cast<single_derived>(b);
BOOST_TEST_NE(d2, std::shared_ptr<single_derived>());
BOOST_TEST_EQ(d2->name, "single_derived");
}
int main() {
no_base();
single_derived();
multiple_base();
virtual_base();
pointer_interface();
reference_interface();
const_pointer_interface();
const_reference_interface();
diamond_non_virtual();
boost_shared_ptr();
std_shared_ptr();
return boost::report_errors();
}