diff --git a/include/boost/smart_ptr/detail/shared_count.hpp b/include/boost/smart_ptr/detail/shared_count.hpp index a3ae638..8dab621 100644 --- a/include/boost/smart_ptr/detail/shared_count.hpp +++ b/include/boost/smart_ptr/detail/shared_count.hpp @@ -22,28 +22,25 @@ # pragma warn -8027 // Functions containing try are not expanded inline #endif -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include #include -// In order to avoid circular dependencies with Boost.TR1 -// we make sure that our include of doesn't try to -// pull in the TR1 headers: that's why we use this header -// rather than including directly: -#include // std::auto_ptr -#include // std::less +#include +#include // std::auto_ptr +#include // std::less +#include // std::size_t #ifdef BOOST_NO_EXCEPTIONS # include // std::bad_alloc #endif -#include - #if defined( BOOST_SP_DISABLE_DEPRECATED ) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" @@ -103,6 +100,14 @@ template< class D > struct sp_convert_reference< D& > typedef sp_reference_wrapper< D > type; }; +template std::size_t sp_hash_pointer( T* p ) BOOST_NOEXCEPT +{ + boost::uintptr_t v = reinterpret_cast( p ); + + // match boost::hash + return static_cast( v + ( v >> 3 ) ); +} + class weak_count; class shared_count @@ -517,6 +522,11 @@ public: { return pi_? pi_->get_untyped_deleter(): 0; } + + std::size_t hash_value() const BOOST_SP_NOEXCEPT + { + return sp_hash_pointer( pi_ ); + } }; @@ -643,6 +653,11 @@ public: { return std::less()( pi_, r.pi_ ); } + + std::size_t hash_value() const BOOST_SP_NOEXCEPT + { + return sp_hash_pointer( pi_ ); + } }; inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ ) diff --git a/include/boost/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/smart_ptr/detail/sp_counted_impl.hpp index 1a46fb8..56b9efa 100644 --- a/include/boost/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_impl.hpp @@ -18,25 +18,21 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include - #if defined(BOOST_SP_USE_STD_ALLOCATOR) && defined(BOOST_SP_USE_QUICK_ALLOCATOR) # error BOOST_SP_USE_STD_ALLOCATOR and BOOST_SP_USE_QUICK_ALLOCATOR are incompatible. #endif -#include #include #include +#include #include +#include #if defined(BOOST_SP_USE_QUICK_ALLOCATOR) #include #endif -#if defined(BOOST_SP_USE_STD_ALLOCATOR) -#include // std::allocator -#endif - +#include // std::allocator, std::allocator_traits #include // std::size_t namespace boost diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index c8b2885..4264b06 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -14,23 +14,16 @@ // See http://www.boost.org/libs/smart_ptr/ for documentation. // -#include // for broken compiler workarounds - -// In order to avoid circular dependencies with Boost.TR1 -// we make sure that our include of doesn't try to -// pull in the TR1 headers: that's why we use this header -// rather than including directly: -#include // std::auto_ptr - -#include -#include -#include #include -#include #include #include #include #include +#include +#include +#include +#include +#include #if !defined(BOOST_SP_NO_ATOMIC_ACCESS) #include @@ -40,6 +33,7 @@ #include // for std::less #include // for std::bad_cast #include // for std::size_t +#include // for std::auto_ptr #if !defined(BOOST_NO_IOSTREAM) #if !defined(BOOST_NO_IOSFWD) @@ -787,6 +781,11 @@ public: return pn == rhs.pn; } + std::size_t owner_hash_value() const BOOST_SP_NOEXCEPT + { + return pn.hash_value(); + } + void * _internal_get_deleter( boost::detail::sp_typeinfo_ const & ti ) const BOOST_SP_NOEXCEPT { return pn.get_deleter( ti ); diff --git a/include/boost/smart_ptr/weak_ptr.hpp b/include/boost/smart_ptr/weak_ptr.hpp index ddc8bfb..16eea67 100644 --- a/include/boost/smart_ptr/weak_ptr.hpp +++ b/include/boost/smart_ptr/weak_ptr.hpp @@ -13,10 +13,11 @@ // See http://www.boost.org/libs/smart_ptr/ for documentation. // -#include // boost.TR1 include order fix #include #include #include +#include +#include namespace boost { @@ -247,6 +248,11 @@ public: return pn == rhs.pn; } + std::size_t owner_hash_value() const BOOST_SP_NOEXCEPT + { + return pn.hash_value(); + } + // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) @@ -280,6 +286,40 @@ template weak_ptr( shared_ptr ) -> weak_ptr; #endif +// hash_value + +template< class T > std::size_t hash_value( boost::weak_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return p.owner_hash_value(); +} + } // namespace boost +// std::hash, std::equal_to + +namespace std +{ + +#if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) + +template struct hash< ::boost::weak_ptr > +{ + std::size_t operator()( ::boost::weak_ptr const & p ) const BOOST_SP_NOEXCEPT + { + return p.owner_hash_value(); + } +}; + +#endif // #if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) + +template struct equal_to< ::boost::weak_ptr > +{ + bool operator()( ::boost::weak_ptr const & a, ::boost::weak_ptr const & b ) const BOOST_SP_NOEXCEPT + { + return a.owner_equals( b ); + } +}; + +} // namespace std + #endif // #ifndef BOOST_SMART_PTR_WEAK_PTR_HPP_INCLUDED diff --git a/test/Jamfile b/test/Jamfile index 3619273..69938e1 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -398,3 +398,8 @@ run weak_ptr_mt_test.cpp : : : multi ; compile sp_report_implementation.cpp ; + +run sp_owner_hash_value_test.cpp ; + +run wp_hash_test.cpp ; +run wp_hash_test2.cpp ; diff --git a/test/sp_owner_hash_value_test.cpp b/test/sp_owner_hash_value_test.cpp new file mode 100644 index 0000000..d1912b9 --- /dev/null +++ b/test/sp_owner_hash_value_test.cpp @@ -0,0 +1,85 @@ +// Copyright 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +int main() +{ + { + boost::shared_ptr p1( new int ); + boost::shared_ptr p2( p1 ); + + BOOST_TEST_EQ( p1.owner_hash_value(), p2.owner_hash_value() ); + + boost::shared_ptr p3( new int ); + + BOOST_TEST_NE( p1.owner_hash_value(), p3.owner_hash_value() ); + + boost::shared_ptr p4; + boost::shared_ptr p5; + + BOOST_TEST_EQ( p4.owner_hash_value(), p5.owner_hash_value() ); + BOOST_TEST_NE( p4.owner_hash_value(), p3.owner_hash_value() ); + + boost::shared_ptr p6( static_cast(0) ); + + BOOST_TEST_NE( p4.owner_hash_value(), p6.owner_hash_value() ); + + boost::shared_ptr p7( p1 ); + + BOOST_TEST_EQ( p1.owner_hash_value(), p7.owner_hash_value() ); + + boost::shared_ptr p8; + + BOOST_TEST_NE( p1.owner_hash_value(), p8.owner_hash_value() ); + BOOST_TEST_EQ( p4.owner_hash_value(), p8.owner_hash_value() ); + + boost::weak_ptr q1( p1 ); + + BOOST_TEST_EQ( p1.owner_hash_value(), q1.owner_hash_value() ); + + boost::weak_ptr q2( p1 ); + + BOOST_TEST_EQ( q1.owner_hash_value(), q2.owner_hash_value() ); + + boost::weak_ptr q3( p3 ); + + BOOST_TEST_NE( p1.owner_hash_value(), q3.owner_hash_value() ); + BOOST_TEST_NE( q1.owner_hash_value(), q3.owner_hash_value() ); + + boost::weak_ptr q4; + + BOOST_TEST_EQ( p4.owner_hash_value(), q4.owner_hash_value() ); + BOOST_TEST_NE( q1.owner_hash_value(), q4.owner_hash_value() ); + + boost::weak_ptr q5; + + BOOST_TEST_EQ( q4.owner_hash_value(), q5.owner_hash_value() ); + + boost::weak_ptr q7( p7 ); + + BOOST_TEST_EQ( p1.owner_hash_value(), q7.owner_hash_value() ); + BOOST_TEST_EQ( q1.owner_hash_value(), q7.owner_hash_value() ); + + p1.reset(); + p2.reset(); + p3.reset(); + p7.reset(); + + BOOST_TEST( q1.expired() ); + BOOST_TEST( q2.expired() ); + BOOST_TEST( q3.expired() ); + BOOST_TEST( q7.expired() ); + + BOOST_TEST_EQ( q1.owner_hash_value(), q2.owner_hash_value() ); + BOOST_TEST_EQ( q1.owner_hash_value(), q7.owner_hash_value() ); + + BOOST_TEST_NE( q1.owner_hash_value(), q3.owner_hash_value() ); + BOOST_TEST_NE( q1.owner_hash_value(), q4.owner_hash_value() ); + } + + return boost::report_errors(); +} diff --git a/test/wp_hash_test.cpp b/test/wp_hash_test.cpp new file mode 100644 index 0000000..b4b2878 --- /dev/null +++ b/test/wp_hash_test.cpp @@ -0,0 +1,76 @@ +// Copyright 2011, 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +int main() +{ + { + boost::hash< boost::weak_ptr > hasher; + + boost::shared_ptr p1, p2( p1 ), p3( new int ), p4( p3 ), p5( new int ); + boost::weak_ptr q1( p1 ), q2( p2 ), q3( p3 ), q4( p4 ), q5( p5 ); + + BOOST_TEST_EQ( hasher( q1 ), hasher( q2 ) ); + BOOST_TEST_NE( hasher( q1 ), hasher( q3 ) ); + BOOST_TEST_EQ( hasher( q3 ), hasher( q4 ) ); + BOOST_TEST_NE( hasher( q3 ), hasher( q5 ) ); + + p3.reset(); + p4.reset(); + p5.reset(); + + BOOST_TEST_EQ( hasher( q1 ), hasher( q2 ) ); + BOOST_TEST_NE( hasher( q1 ), hasher( q3 ) ); + BOOST_TEST_EQ( hasher( q3 ), hasher( q4 ) ); + BOOST_TEST_NE( hasher( q3 ), hasher( q5 ) ); + } + + { + boost::hash< boost::weak_ptr > hasher; + + boost::shared_ptr p1, p2( p1 ), p3( new int[1] ), p4( p3 ), p5( new int[1] ); + boost::weak_ptr q1( p1 ), q2( p2 ), q3( p3 ), q4( p4 ), q5( p5 ); + + BOOST_TEST_EQ( hasher( q1 ), hasher( q2 ) ); + BOOST_TEST_NE( hasher( q1 ), hasher( q3 ) ); + BOOST_TEST_EQ( hasher( q3 ), hasher( q4 ) ); + BOOST_TEST_NE( hasher( q3 ), hasher( q5 ) ); + + p3.reset(); + p4.reset(); + p5.reset(); + + BOOST_TEST_EQ( hasher( q1 ), hasher( q2 ) ); + BOOST_TEST_NE( hasher( q1 ), hasher( q3 ) ); + BOOST_TEST_EQ( hasher( q3 ), hasher( q4 ) ); + BOOST_TEST_NE( hasher( q3 ), hasher( q5 ) ); + } + + { + boost::hash< boost::weak_ptr > hasher; + + boost::shared_ptr p1, p2( p1 ), p3( new int[1] ), p4( p3 ), p5( new int[1] ); + boost::weak_ptr q1( p1 ), q2( p2 ), q3( p3 ), q4( p4 ), q5( p5 ); + + BOOST_TEST_EQ( hasher( q1 ), hasher( q2 ) ); + BOOST_TEST_NE( hasher( q1 ), hasher( q3 ) ); + BOOST_TEST_EQ( hasher( q3 ), hasher( q4 ) ); + BOOST_TEST_NE( hasher( q3 ), hasher( q5 ) ); + + p3.reset(); + p4.reset(); + p5.reset(); + + BOOST_TEST_EQ( hasher( q1 ), hasher( q2 ) ); + BOOST_TEST_NE( hasher( q1 ), hasher( q3 ) ); + BOOST_TEST_EQ( hasher( q3 ), hasher( q4 ) ); + BOOST_TEST_NE( hasher( q3 ), hasher( q5 ) ); + } + + return boost::report_errors(); +} diff --git a/test/wp_hash_test2.cpp b/test/wp_hash_test2.cpp new file mode 100644 index 0000000..77db2fd --- /dev/null +++ b/test/wp_hash_test2.cpp @@ -0,0 +1,61 @@ +// Copyright 2011, 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) + +int main() {} + +#else + +int main() +{ + { + boost::shared_ptr p1, p2( new int ); + boost::weak_ptr q1( p1 ), q2( p2 ), q3; + + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q1 ), q1.owner_hash_value() ); + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q2 ), q2.owner_hash_value() ); + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q3 ), q3.owner_hash_value() ); + + p2.reset(); + + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q2 ), q2.owner_hash_value() ); + } + + { + boost::shared_ptr p1, p2( new int[1] ); + boost::weak_ptr q1( p1 ), q2( p2 ), q3; + + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q1 ), q1.owner_hash_value() ); + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q2 ), q2.owner_hash_value() ); + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q3 ), q3.owner_hash_value() ); + + p2.reset(); + + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q2 ), q2.owner_hash_value() ); + } + + { + boost::shared_ptr p1, p2( new int[1] ); + boost::weak_ptr q1( p1 ), q2( p2 ), q3; + + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q1 ), q1.owner_hash_value() ); + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q2 ), q2.owner_hash_value() ); + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q3 ), q3.owner_hash_value() ); + + p2.reset(); + + BOOST_TEST_EQ( std::hash< boost::weak_ptr >()( q2 ), q2.owner_hash_value() ); + } + + return boost::report_errors(); +} + +#endif // #if defined(BOOST_NO_CXX11_HDR_FUNCTIONAL)