unique_any now could take over ownership of boost::any content

This commit is contained in:
Antony Polukhin
2023-05-14 19:43:19 +03:00
parent a42f3d750c
commit 9bbc302378
6 changed files with 159 additions and 31 deletions
+5 -12
View File
@@ -20,6 +20,7 @@
#include <boost/any/bad_any_cast.hpp>
#include <boost/any/fwd.hpp>
#include <boost/any/detail/placeholder.hpp>
#include <boost/type_index.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/decay.hpp>
@@ -240,20 +241,10 @@ namespace boost
public: // types (public so any_cast can be non-friend)
#endif
/// @cond
class BOOST_SYMBOL_VISIBLE placeholder
class BOOST_SYMBOL_VISIBLE placeholder: public boost::anys::detail::placeholder
{
public: // structors
virtual ~placeholder()
{
}
public: // queries
virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0;
public:
virtual placeholder * clone() const = 0;
};
template<typename ValueType>
@@ -302,6 +293,8 @@ namespace boost
template<typename ValueType>
friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT;
friend class boost::anys::unique_any;
#else
public: // representation (public so any_cast can be non-friend)
+33
View File
@@ -0,0 +1,33 @@
// Copyright Antony Polukhin, 2021-2023.
//
// 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_ANY_ANYS_DETAIL_PLACEHOLDER_HPP
#define BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/type_index.hpp>
/// @cond
namespace boost {
namespace anys {
namespace detail {
class BOOST_SYMBOL_VISIBLE placeholder {
public:
virtual ~placeholder() {}
virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0;
};
} // namespace detail
} // namespace anys
} // namespace boost
/// @endcond
#endif // #ifndef BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP
+3 -1
View File
@@ -19,7 +19,9 @@
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) || \
defined(BOOST_NO_CXX11_CONSTEXPR) || \
defined(BOOST_NO_CXX11_NULLPTR) || \
defined(BOOST_NO_CXX11_NOEXCEPT) || \
defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || \
defined(BOOST_NO_CXX11_FINAL) || \
@@ -48,10 +50,10 @@ template<std::size_t OptimizeForSize = sizeof(void*), std::size_t OptimizeForAli
class basic_any;
namespace detail {
template <class T>
struct is_basic_any: public boost::false_type {};
template<std::size_t OptimizeForSize, std::size_t OptimizeForAlignment>
struct is_basic_any<boost::anys::basic_any<OptimizeForSize, OptimizeForAlignment> > : public boost::true_type {};
+25 -18
View File
@@ -39,6 +39,7 @@
#include <boost/any/fwd.hpp>
#include <boost/any/bad_any_cast.hpp>
#include <boost/any/detail/placeholder.hpp>
#include <boost/type_index.hpp>
@@ -78,7 +79,7 @@ public:
/// \throws std::bad_alloc or any exceptions arising from the move or
/// copy constructor of the contained type.
template<typename T>
unique_any(T&& value)
unique_any(T&& value, typename std::enable_if<!std::is_same<T&&, boost::any&&>::value>::type* = nullptr)
: content(new holder< typename std::decay<T>::type >(std::forward<T>(value)))
{
static_assert(
@@ -87,10 +88,26 @@ public:
);
static_assert(
!boost::anys::detail::is_some_any< typename std::decay<T>::type >::value,
"unique_any could be only moved and could not be constructoed from "
"other types of any."
!std::is_same<unique_any, typename std::decay<T>::type >::value,
"boost::anys::unique_any could not be copied, only moved."
);
static_assert(
!std::is_same<boost::any, typename std::decay<T>::type >::value,
"boost::anys::unique_any could be constructed from an rvalue of boost::any, "
"not a lvalue."
);
}
/// Moves the content of `boost::any` into *this.
///
/// \throws Nothing.
/// \post `value.empty()` is true.
template <class BoostAny>
unique_any(BoostAny&& value, typename std::enable_if<std::is_same<BoostAny&&, boost::any&&>::value>::type* = nullptr) noexcept
{
content.reset(value.content);
value.content = nullptr;
}
/// Inplace constructs `T` from forwarded `args...`,
@@ -156,7 +173,7 @@ public:
template<class T, class... Args>
typename std::decay<T>::type& emplace(Args&&... args) {
auto* raw_ptr = new holder<typename std::decay<T>::type>(std::forward<Args>(args)...);
content = std::unique_ptr<placeholder>(raw_ptr);
content = std::unique_ptr<boost::anys::detail::placeholder>(raw_ptr);
return raw_ptr->held;
}
@@ -170,7 +187,7 @@ public:
template<class T, class U, class... Args>
typename std::decay<T>::type& emplace(std::initializer_list<U> il, Args&&... args) {
auto* raw_ptr = new holder<typename std::decay<T>::type>(il, std::forward<Args>(args)...);
content = std::unique_ptr<placeholder>(raw_ptr);
content = std::unique_ptr<boost::anys::detail::placeholder>(raw_ptr);
return raw_ptr->held;
}
@@ -209,18 +226,8 @@ public:
private: // types
/// @cond
class BOOST_SYMBOL_VISIBLE placeholder
{
public:
virtual ~placeholder()
{
}
virtual const boost::typeindex::type_info& type() const noexcept = 0;
};
template<typename T>
class holder final: public placeholder
class holder final: public boost::anys::detail::placeholder
{
public:
template <class... Args>
@@ -248,7 +255,7 @@ private: // representation
template<typename T>
friend T * unsafe_any_cast(unique_any *) noexcept;
std::unique_ptr<placeholder> content;
std::unique_ptr<boost::anys::detail::placeholder> content;
/// @endcond
};
+2
View File
@@ -25,6 +25,8 @@ test-suite unique_any :
[ run move.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : no_rtti_unique_move ]
[ run emplace.cpp : : : : unique_emplace ]
[ run emplace.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : no_rtti_unique_emplace ]
[ run from_any.cpp : : : : unique_from_any ]
[ run from_any.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : no_rtti_unique_from_any ]
[ compile-fail any_cast_cv_failed.cpp : : unique_any_cast_cd_failed ]
[ compile-fail temporary_to_ref_failed.cpp : : unique_temporary_to_ref_failed ]
[ compile-fail cv_to_rv_failed.cpp : : unique_cv_to_rv_failed ]
+91
View File
@@ -0,0 +1,91 @@
// Copyright Antony Polukhin, 2013-2023.
//
// 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/any.hpp>
#include <boost/any/unique_any.hpp>
#include <boost/core/lightweight_test.hpp>
#include <vector>
void test_basic() {
boost::any from = 42;
boost::anys::unique_any a(std::move(from));
BOOST_TEST(from.empty());
BOOST_TEST(a.has_value());
BOOST_TEST_EQ(boost::any_cast<int>(a), 42);
BOOST_TEST_EQ(boost::anys::any_cast<int>(a), 42);
BOOST_TEST_EQ(boost::any_cast<int&>(a), 42);
BOOST_TEST_EQ(boost::anys::any_cast<int&>(a), 42);
boost::anys::unique_any b = std::move(a);
BOOST_TEST(!a.has_value());
BOOST_TEST(b.has_value());
BOOST_TEST_EQ(boost::any_cast<int&>(b), 42);
b.reset();
BOOST_TEST(!b.has_value());
}
void test_const() {
boost::any from = 42;
const boost::anys::unique_any a = std::move(from);
BOOST_TEST(a.has_value());
BOOST_TEST_EQ(boost::any_cast<int>(a), 42);
BOOST_TEST_EQ(boost::anys::any_cast<int>(a), 42);
BOOST_TEST_EQ(boost::any_cast<const int&>(a), 42);
BOOST_TEST_EQ(boost::anys::any_cast<const int&>(a), 42);
}
void test_bad_any_cast() {
boost::any from = 42;
const boost::anys::unique_any a = std::move(from);
try {
boost::any_cast<char>(a);
BOOST_TEST(false);
} catch (const boost::bad_any_cast&) {
}
try {
boost::any_cast<int*>(a);
BOOST_TEST(false);
} catch (const boost::bad_any_cast&) {
}
}
struct counting_destroy {
static int destructor_called;
~counting_destroy() {
++destructor_called;
}
};
int counting_destroy::destructor_called = 0;
void test_destructor() {
boost::any from = counting_destroy{};
BOOST_TEST_EQ(counting_destroy::destructor_called, 1);
boost::anys::unique_any a = std::move(from);
BOOST_TEST_EQ(counting_destroy::destructor_called, 1);
a.reset();
BOOST_TEST_EQ(counting_destroy::destructor_called, 2);
}
int main() {
test_basic();
test_const();
test_bad_any_cast();
test_destructor();
return boost::report_errors();
}