From 36ceaadfaa3eea2509916c6dfc089b24c4d88aec Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 29 Apr 2013 20:15:05 +0900 Subject: [PATCH] Improved reference-counted pointer --- ConfigureChecks.cmake | 115 ++++++++++++------ config-taglib.h.cmake | 15 ++- taglib/asf/asfattribute.h | 2 +- taglib/asf/asfpicture.h | 2 +- taglib/fileref.cpp | 2 +- taglib/fileref.h | 2 +- taglib/mp4/mp4coverart.h | 2 +- taglib/mp4/mp4item.h | 2 +- taglib/mpeg/mpegheader.h | 2 +- taglib/toolkit/tbytevector.cpp | 4 +- taglib/toolkit/tbytevector.h | 2 +- taglib/toolkit/tlist.h | 2 +- taglib/toolkit/tmap.h | 2 +- taglib/toolkit/trefcountptr.h | 208 +++++++++++++++++---------------- taglib/toolkit/tstring.h | 2 +- tests/CMakeLists.txt | 1 + tests/test_smartptr.cpp | 200 +++++++++++++++++++++++++++++++ 17 files changed, 409 insertions(+), 156 deletions(-) create mode 100644 tests/test_smartptr.cpp diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index b7bda179..c08f7377 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -6,60 +6,103 @@ include(CheckLibraryExists) include(CheckTypeSize) include(CheckCXXSourceCompiles) -# check for libz using the cmake supplied FindZLIB.cmake -find_package(ZLIB) -if(ZLIB_FOUND) - set(HAVE_ZLIB 1) -else() - set(HAVE_ZLIB 0) -endif() - # Determine whether or not your compiler supports move semantics. check_cxx_source_compiles(" - #ifdef __clang__ - # pragma clang diagnostic error \"-Wc++11-extensions\" - #endif - #include - int func(int &&x) { return x - 1; } - int main() { return func(std::move(1)); } + #ifdef __clang__ + # pragma clang diagnostic error \"-Wc++11-extensions\" + #endif + #include + int func(int &&x) { return x - 1; } + int main() { return func(std::move(1)); } " SUPPORT_MOVE_SEMANTICS) -# Determine whether or not your compiler supports template alias. -check_cxx_source_compiles(" - #ifdef __clang__ - # pragma clang diagnostic error \"-Wc++11-extensions\" - #endif - #include - template using myVector = std::vector; - int main() { return 0; } -" SUPPORT_TEMPLATE_ALIAS) - # Determine where shared_ptr is defined regardless of C++11 support. check_cxx_source_compiles(" - #include - int main() { std::tr1::shared_ptr x; return 0; } + #include + int main() { std::tr1::shared_ptr x; return 0; } " HAVE_STD_SHARED_PTR) -check_cxx_source_compiles(" +if(NOT HAVE_STD_SHARED_PTR) + check_cxx_source_compiles(" #include int main() { std::tr1::shared_ptr x; return 0; } -" HAVE_TR1_SHARED_PTR) + " HAVE_TR1_SHARED_PTR) + + if(NOT HAVE_TR1_SHARED_PTR) + check_cxx_source_compiles(" + #include + int main() { boost::shared_ptr x; return 0; } + " HAVE_BOOST_SHARED_PTR) + endif() +endif() + +# Determine which kind of atomic operations your compiler supports. +if(NOT HAVE_STD_SHARED_PTR AND NOT HAVE_TR1_SHARED_PTR AND NOT HAVE_BOOST_SHARED_PTR) + check_cxx_source_compiles(" + int main() { + volatile int x; + __sync_add_and_fetch(&x, 1); + int y = __sync_sub_and_fetch(&x, 1); + return 0; + } + " HAVE_GCC_ATOMIC) + + if(NOT HAVE_GCC_ATOMIC) + check_cxx_source_compiles(" + #include + int main() { + volatile int32_t x; + OSAtomicIncrement32Barrier(&x); + int32_t y = OSAtomicDecrement32Barrier(&x); + return 0; + } + " HAVE_MAC_ATOMIC) + + if(NOT HAVE_MAC_ATOMIC) + check_cxx_source_compiles(" + #include + int main() { + volatile LONG x; + InterlockedIncrement(&x); + LONG y = InterlockedDecrement(&x); + return 0; + } + " HAVE_WIN_ATOMIC) + + if(NOT HAVE_WIN_ATOMIC) + check_cxx_source_compiles(" + #include + int main() { + volatile int x; + __sync_add_and_fetch(&x, 1); + int y = __sync_sub_and_fetch(&x, 1); + return 0; + } + " HAVE_IA64_ATOMIC) + endif() + endif() + endif() +endif() -check_cxx_source_compiles(" - #include - int main() { boost::shared_ptr x; return 0; } -" HAVE_BOOST_SHARED_PTR) # Determine whether your compiler supports codecvt header. check_cxx_source_compiles(" - #include - int main() { std::codecvt_utf8_utf16 x; return 0; } +#include +int main() { std::codecvt_utf8_utf16 x; return 0; } " HAVE_CODECVT) +# check for libz using the cmake supplied FindZLIB.cmake +find_package(ZLIB) +if(ZLIB_FOUND) +set(HAVE_ZLIB 1) +else() +set(HAVE_ZLIB 0) +endif() + set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(CppUnit) if(NOT CppUnit_FOUND AND BUILD_TESTS) - message(STATUS "CppUnit not found, disabling tests.") - set(BUILD_TESTS OFF) + message(STATUS "CppUnit not found, disabling tests.") + set(BUILD_TESTS OFF) endif() diff --git a/config-taglib.h.cmake b/config-taglib.h.cmake index e57ff050..6d48cbf0 100644 --- a/config-taglib.h.cmake +++ b/config-taglib.h.cmake @@ -1,22 +1,25 @@ /* config-taglib.h. Generated by cmake from config-taglib.h.cmake */ -/* Define if you have libz */ -#cmakedefine HAVE_ZLIB 1 - /* Defined if your compiler supports the move semantics */ #cmakedefine SUPPORT_MOVE_SEMANTICS 1 -/* Defined if your compiler supports the template alias */ -#cmakedefine SUPPORT_TEMPLATE_ALIAS 1 - /* Defined if your compiler supports shared_ptr */ #cmakedefine HAVE_STD_SHARED_PTR 1 #cmakedefine HAVE_TR1_SHARED_PTR 1 #cmakedefine HAVE_BOOST_SHARED_PTR 1 +/* Defined if your compiler supports some atomic operations */ +#cmakedefine HAVE_GCC_ATOMIC 1 +#cmakedefine HAVE_MAC_ATOMIC 1 +#cmakedefine HAVE_WIN_ATOMIC 1 +#cmakedefine HAVE_IA64_ATOMIC 1 + /* Defined if your compiler has header */ #cmakedefine HAVE_CODECVT 1 +/* Define if you have libz */ +#cmakedefine HAVE_ZLIB 1 + #cmakedefine NO_ITUNES_HACKS 1 #cmakedefine WITH_ASF 1 #cmakedefine WITH_MP4 1 diff --git a/taglib/asf/asfattribute.h b/taglib/asf/asfattribute.h index 93e8c2e1..6bc9a847 100644 --- a/taglib/asf/asfattribute.h +++ b/taglib/asf/asfattribute.h @@ -205,7 +205,7 @@ namespace TagLib ByteVector render(const String &name, int kind = 0) const; class AttributePrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; } diff --git a/taglib/asf/asfpicture.h b/taglib/asf/asfpicture.h index e2279462..e493428a 100644 --- a/taglib/asf/asfpicture.h +++ b/taglib/asf/asfpicture.h @@ -231,7 +231,7 @@ namespace TagLib #endif private: class PicturePrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; } } diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 78164e32..2d215bce 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -66,7 +66,7 @@ class FileRef::FileRefPrivate public: FileRefPrivate(File *f) : file(f) {} - RefCountPtr file; + TAGLIB_SHARED_PTR file; static List fileTypeResolvers; }; diff --git a/taglib/fileref.h b/taglib/fileref.h index c359ef22..01e2875c 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -278,7 +278,7 @@ namespace TagLib { private: class FileRefPrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; } // namespace TagLib diff --git a/taglib/mp4/mp4coverart.h b/taglib/mp4/mp4coverart.h index a34e715e..3b78d747 100644 --- a/taglib/mp4/mp4coverart.h +++ b/taglib/mp4/mp4coverart.h @@ -66,7 +66,7 @@ namespace TagLib { private: class CoverArtPrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; typedef List CoverArtList; diff --git a/taglib/mp4/mp4item.h b/taglib/mp4/mp4item.h index 44fae301..e78acee5 100644 --- a/taglib/mp4/mp4item.h +++ b/taglib/mp4/mp4item.h @@ -97,7 +97,7 @@ namespace TagLib { private: class ItemPrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; } diff --git a/taglib/mpeg/mpegheader.h b/taglib/mpeg/mpegheader.h index cdc8669d..330746ce 100644 --- a/taglib/mpeg/mpegheader.h +++ b/taglib/mpeg/mpegheader.h @@ -181,7 +181,7 @@ namespace TagLib { void parse(const ByteVector &data); class HeaderPrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; } } diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 38cb97ef..a94bc07c 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -272,7 +272,7 @@ public: { } - ByteVectorPrivate(RefCountPtr d, size_t o, size_t l) + ByteVectorPrivate(TAGLIB_SHARED_PTR d, size_t o, size_t l) : data(d->data) , offset(d->offset + o) , length(l) @@ -320,7 +320,7 @@ public: return *this; } - RefCountPtr data; + TAGLIB_SHARED_PTR data; size_t offset; size_t length; }; diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index ec8e7c3f..cea615d9 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -478,7 +478,7 @@ namespace TagLib { private: class ByteVectorPrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; /*! diff --git a/taglib/toolkit/tlist.h b/taglib/toolkit/tlist.h index 0948ee70..48a1d356 100644 --- a/taglib/toolkit/tlist.h +++ b/taglib/toolkit/tlist.h @@ -305,7 +305,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class ListPrivate; - RefCountPtr > d; + TAGLIB_SHARED_PTR > d; #endif }; diff --git a/taglib/toolkit/tmap.h b/taglib/toolkit/tmap.h index 38a23896..b9d4a8fd 100644 --- a/taglib/toolkit/tmap.h +++ b/taglib/toolkit/tmap.h @@ -219,7 +219,7 @@ namespace TagLib { private: #ifndef DO_NOT_DOCUMENT template class MapPrivate; - RefCountPtr > d; + TAGLIB_SHARED_PTR > d; #endif }; diff --git a/taglib/toolkit/trefcountptr.h b/taglib/toolkit/trefcountptr.h index 535d0efd..54ecf307 100644 --- a/taglib/toolkit/trefcountptr.h +++ b/taglib/toolkit/trefcountptr.h @@ -37,19 +37,33 @@ #elif defined(HAVE_BOOST_SHARED_PTR) # include #else -# ifdef __APPLE__ -# include -# define TAGLIB_ATOMIC_MAC -# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define TAGLIB_ATOMIC_WIN -# elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ - && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ - defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ - && !defined(__INTEL_COMPILER) -# define TAGLIB_ATOMIC_GCC -# elif defined(__ia64) && defined(__INTEL_COMPILER) -# include -# define TAGLIB_ATOMIC_GCC +# include +# if defined(HAVE_GCC_ATOMIC) +# define TAGLIB_ATOMIC_INT int +# define TAGLIB_ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) +# define TAGLIB_ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) +# elif defined(HAVE_WIN_ATOMIC) +# if !defined(NOMINMAX) +# define NOMINMAX +# endif +# include +# define TAGLIB_ATOMIC_INT long +# define TAGLIB_ATOMIC_INC(x) InterlockedIncrement(&x) +# define TAGLIB_ATOMIC_DEC(x) InterlockedDecrement(&x) +# elif defined(HAVE_MAC_ATOMIC) +# include +# define TAGLIB_ATOMIC_INT int32_t +# define TAGLIB_ATOMIC_INC(x) OSAtomicIncrement32Barrier(&x) +# define TAGLIB_ATOMIC_DEC(x) OSAtomicDecrement32Barrier(&x) +# elif defined(HAVE_IA64_ATOMIC) +# include +# define TAGLIB_ATOMIC_INT int +# define TAGLIB_ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) +# define TAGLIB_ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) +# else +# define TAGLIB_ATOMIC_INT int +# define TAGLIB_ATOMIC_INC(x) (++x) +# define TAGLIB_ATOMIC_DEC(x) (--x) # endif #endif @@ -63,55 +77,18 @@ namespace TagLib { -#if defined(HAVE_STD_SHARED_PTR) || defined(HAVE_TR1_SHARED_PTR) || defined(HAVE_BOOST_SHARED_PTR) +#if defined(HAVE_STD_SHARED_PTR) || defined(HAVE_TR1_SHARED_PTR) + +#define TAGLIB_SHARED_PTR std::tr1::shared_ptr -# if defined(SUPPORT_TEMPLATE_ALIAS) +#elif defined(HAVE_BOOST_SHARED_PTR) - // Defines RefCountPtr as an alias of shared_ptr - // if shared_ptr and the template alias are both available. - -# if defined(HAVE_STD_SHARED_PTR) || defined(HAVE_TR1_SHARED_PTR) - - template - using RefCountPtr = std::tr1::shared_ptr; - -# else - - template - using RefCountPtr = boost::shared_ptr; - -# endif - -# else - - // Defines RefCountPtr as a derived class of shared_ptr. - // if shared_ptr is available but the template alias is not. - -# if defined(HAVE_STD_SHARED_PTR) || defined(HAVE_TR1_SHARED_PTR) - - template - class RefCountPtr : public std::tr1::shared_ptr - { - public: - explicit RefCountPtr(T *p) : std::tr1::shared_ptr(p) {} - }; - -# else - - template - class RefCountPtr : public boost::shared_ptr - { - public: - explicit RefCountPtr(T *p) : boost::shared_ptr(p) {} - }; - -# endif - -# endif +#define TAGLIB_SHARED_PTR boost::shared_ptr #else // HAVE_*_SHARED_PTR - // Implements RefCountPtr if shared_ptr is not available. + // Self-implements RefCountPtr if shared_ptr is not available. + // I STRONGLY RECOMMEND using standard shared_ptr rather than this class. template class RefCountPtr @@ -134,12 +111,12 @@ namespace TagLib { void addref() { - increment(&count); + TAGLIB_ATOMIC_INC(count); } void release() { - if(decrement(&count) == 0) { + if(TAGLIB_ATOMIC_DEC(count) == 0) { dispose(); delete this; } @@ -153,33 +130,7 @@ namespace TagLib { virtual void dispose() = 0; private: -# if defined(TAGLIB_ATOMIC_MAC) - typedef volatile int32_t counter_t; - - inline static void increment(counter_t *c) { OSAtomicIncrement32Barrier(c); } - inline static counter_t decrement(counter_t *c) { return OSAtomicDecrement32Barrier(c); } - -# elif defined(TAGLIB_ATOMIC_WIN) - typedef volatile long counter_t; - - inline static void increment(counter_t *c) { InterlockedIncrement(c); } - inline static counter_t decrement(counter_t *c) { return InterlockedDecrement(c); } - -# elif defined(TAGLIB_ATOMIC_GCC) - typedef volatile int counter_t; - - inline static void increment(counter_t *c) { __sync_add_and_fetch(c, 1); } - inline static counter_t decrement(counter_t *c) { return __sync_sub_and_fetch(c, 1); } - -# else - typedef uint counter_t; - - inline static void increment(counter_t *c) { ++(*c) } - inline static counter_t decrement(counter_t *c) { return --(*c); } - -# endif - - counter_t count; + volatile TAGLIB_ATOMIC_INT count; }; // Counter impl class. Provides a dynamic deleter. @@ -208,31 +159,52 @@ namespace TagLib { }; public: + explicit RefCountPtr() + : counter(0) + { + } + template explicit RefCountPtr(U *p) : counter(new CounterImpl(p)) { } - RefCountPtr(const RefCountPtr &x) + RefCountPtr(const RefCountPtr &x) + : counter(x.counter) { - counter = x.counter; - counter->addref(); + if(counter) + counter->addref(); + } + + template + RefCountPtr(const RefCountPtr &x) + : counter(reinterpret_cast(x.counter)) + { + if(counter) + counter->addref(); } ~RefCountPtr() { - counter->release(); + if(counter) + counter->release(); } T *get() const { - return static_cast*>(counter)->get(); + if(counter) + return static_cast*>(counter)->get(); + else + return 0; } long use_count() const { - return counter->use_count(); + if(counter) + return counter->use_count(); + else + return 0; } bool unique() const @@ -244,20 +216,44 @@ namespace TagLib { void reset(U *p) { if(get() != p) - { - counter->release(); - counter = new CounterImpl(p); - } + RefCountPtr(p).swap(*this); + } + + void reset() + { + RefCountPtr().swap(*this); + } + + void swap(RefCountPtr &x) + { + std::swap(counter, x.counter); } RefCountPtr &operator=(const RefCountPtr &x) { - if(get() != x.get()) - { - counter->release(); + if(get() != x.get()) { + if(counter) + counter->release(); counter = x.counter; - counter->addref(); + + if(counter) + counter->addref(); + } + return *this; + } + + template + RefCountPtr &operator=(const RefCountPtr &x) + { + if(get() != x.get()) { + if(counter) + counter->release(); + + counter = reinterpret_cast(x.counter); + + if(counter) + counter->addref(); } return *this; } @@ -288,9 +284,19 @@ namespace TagLib { } private: - CounterBase *counter; + mutable CounterBase *counter; + + template friend class RefCountPtr; }; +# define TAGLIB_SHARED_PTR TagLib::RefCountPtr + + template + void swap(RefCountPtr &a, RefCountPtr &b) + { + a.swap(b); + } + #endif // HAVE_*_SHARED_PTR } #endif // DO_NOT_DOCUMENT diff --git a/taglib/toolkit/tstring.h b/taglib/toolkit/tstring.h index dfde414d..bfa35459 100644 --- a/taglib/toolkit/tstring.h +++ b/taglib/toolkit/tstring.h @@ -523,7 +523,7 @@ namespace TagLib { static const Type WCharByteOrder; class StringPrivate; - RefCountPtr d; + TAGLIB_SHARED_PTR d; }; /*! diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4e428af8..a369b5a1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,6 +30,7 @@ SET(test_runner_SRCS main.cpp test_list.cpp test_map.cpp + test_smartptr.cpp test_mpeg.cpp test_synchdata.cpp test_trueaudio.cpp diff --git a/tests/test_smartptr.cpp b/tests/test_smartptr.cpp new file mode 100644 index 00000000..4fd9b3bf --- /dev/null +++ b/tests/test_smartptr.cpp @@ -0,0 +1,200 @@ +#include +#include +#include "utils.h" + +using namespace std; +using namespace TagLib; + +bool baseDestructorCalled; +bool derivedDestructorCalled; +bool incompleteDestructorCalled; + +class TestSmartptr : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(TestSmartptr); + CPPUNIT_TEST(testSharedptrBasic); + CPPUNIT_TEST(testDerivedClass); + CPPUNIT_TEST(testIncompleteClass); + CPPUNIT_TEST_SUITE_END(); + +private: + template + void ck( const T* v1, T v2 ) { CPPUNIT_ASSERT( *v1 == v2 ); } + +public: + void testSharedptrBasic() + { + int * ip = new int; + TAGLIB_SHARED_PTR cp ( ip ); + CPPUNIT_ASSERT( ip == cp.get() ); + CPPUNIT_ASSERT( cp.use_count() == 1 ); + + *cp = 54321; + CPPUNIT_ASSERT( *cp == 54321 ); + CPPUNIT_ASSERT( *ip == 54321 ); + ck( static_cast(cp.get()), 54321 ); + ck( static_cast(ip), *cp ); + + TAGLIB_SHARED_PTR cp2 ( cp ); + CPPUNIT_ASSERT( ip == cp2.get() ); + CPPUNIT_ASSERT( cp.use_count() == 2 ); + CPPUNIT_ASSERT( cp2.use_count() == 2 ); + + CPPUNIT_ASSERT( *cp == 54321 ); + CPPUNIT_ASSERT( *cp2 == 54321 ); + ck( static_cast(cp2.get()), 54321 ); + ck( static_cast(ip), *cp2 ); + + TAGLIB_SHARED_PTR cp3 ( cp ); + CPPUNIT_ASSERT( cp.use_count() == 3 ); + CPPUNIT_ASSERT( cp2.use_count() == 3 ); + CPPUNIT_ASSERT( cp3.use_count() == 3 ); + cp.reset(); + CPPUNIT_ASSERT( cp2.use_count() == 2 ); + CPPUNIT_ASSERT( cp3.use_count() == 2 ); + cp.reset( new int ); + *cp = 98765; + CPPUNIT_ASSERT( *cp == 98765 ); + *cp3 = 87654; + CPPUNIT_ASSERT( *cp3 == 87654 ); + CPPUNIT_ASSERT( *cp2 == 87654 ); + cp.swap( cp3 ); + CPPUNIT_ASSERT( *cp == 87654 ); + CPPUNIT_ASSERT( *cp2 == 87654 ); + CPPUNIT_ASSERT( *cp3 == 98765 ); + cp.swap( cp3 ); + CPPUNIT_ASSERT( *cp == 98765 ); + CPPUNIT_ASSERT( *cp2 == 87654 ); + CPPUNIT_ASSERT( *cp3 == 87654 ); + cp2 = cp2; + CPPUNIT_ASSERT( cp2.use_count() == 2 ); + CPPUNIT_ASSERT( *cp2 == 87654 ); + cp = cp2; + CPPUNIT_ASSERT( cp2.use_count() == 3 ); + CPPUNIT_ASSERT( *cp2 == 87654 ); + CPPUNIT_ASSERT( cp.use_count() == 3 ); + CPPUNIT_ASSERT( *cp == 87654 ); + + TAGLIB_SHARED_PTR cp4; + swap( cp2, cp4 ); + CPPUNIT_ASSERT( cp4.use_count() == 3 ); + CPPUNIT_ASSERT( *cp4 == 87654 ); + CPPUNIT_ASSERT( cp2.get() == 0 ); + + std::set< TAGLIB_SHARED_PTR > scp; + scp.insert(cp4); + CPPUNIT_ASSERT( scp.find(cp4) != scp.end() ); + CPPUNIT_ASSERT( scp.find(cp4) == scp.find( TAGLIB_SHARED_PTR(cp4) ) ); + } + +private: + class DummyBase + { + public: + DummyBase(int x) : value(x) + { + } + + virtual ~DummyBase() + { + baseDestructorCalled = true; + } + + int getValue() const + { + return value; + } + + private: + int value; + }; + + class DummyDerived : public DummyBase + { + public: + DummyDerived(int x) : DummyBase(x) + { + } + + virtual ~DummyDerived() + { + derivedDestructorCalled = true; + } + }; + +public: + void testDerivedClass() + { + baseDestructorCalled = false; + derivedDestructorCalled = false; + + { + TAGLIB_SHARED_PTR p1(new DummyDerived(100)); + CPPUNIT_ASSERT(p1->getValue() == 100); + } + + CPPUNIT_ASSERT(baseDestructorCalled); + CPPUNIT_ASSERT(derivedDestructorCalled); + + baseDestructorCalled = false; + derivedDestructorCalled = false; + + { + TAGLIB_SHARED_PTR p1(new DummyDerived(100)); + TAGLIB_SHARED_PTR p2 = p1; + + CPPUNIT_ASSERT(p1->getValue() == 100); + CPPUNIT_ASSERT(p2->getValue() == 100); + } + + CPPUNIT_ASSERT(baseDestructorCalled); + CPPUNIT_ASSERT(derivedDestructorCalled); + + baseDestructorCalled = false; + derivedDestructorCalled = false; + + { + TAGLIB_SHARED_PTR p1; + TAGLIB_SHARED_PTR p2; + + p1.reset(new DummyDerived(100)); + p2 = p1; + + CPPUNIT_ASSERT(p1->getValue() == 100); + CPPUNIT_ASSERT(p2->getValue() == 100); + } + + CPPUNIT_ASSERT(baseDestructorCalled); + CPPUNIT_ASSERT(derivedDestructorCalled); + } + +private: + class DummyIncomplete; + TAGLIB_SHARED_PTR pincomplete; + + class DummyIncomplete + { + public: + ~DummyIncomplete() + { + incompleteDestructorCalled = true; + } + + int getValue() const { return 100; } + }; + +public: + void testIncompleteClass() + { + incompleteDestructorCalled = false; + + pincomplete.reset(new DummyIncomplete()); + CPPUNIT_ASSERT(pincomplete->getValue() == 100); + + pincomplete.reset(); + CPPUNIT_ASSERT(incompleteDestructorCalled); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestSmartptr);