mirror of https://github.com/axmolengine/axmol.git
Merge pull request #6365 from dumganhar/pull/6012
Merge PR #6012: Add cocos2d::RefPtr<T>
This commit is contained in:
commit
cc7ded036f
|
@ -1 +1 @@
|
||||||
feee3c038221d15aa270c3c33e2187ed35630b45
|
1f2c191d1027ab72afff7e81d1fb31fce82ce4b1
|
|
@ -1 +1 @@
|
||||||
20d3130f1f163df349f4503d05a21797039f1b40
|
e569f7828939a72dd90b17fea3e60f6b9fe3da16
|
|
@ -0,0 +1,309 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2014 PlayFirst Inc.
|
||||||
|
Copyright (c) 2014 Chukong Technologies Inc.
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __CC_REF_PTR_H__
|
||||||
|
#define __CC_REF_PTR_H__
|
||||||
|
|
||||||
|
#include "CCRef.h"
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
NS_CC_BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility/support macros. Defined to enable RefPtr<T> to contain types like 'const T' because we do not
|
||||||
|
* regard retain()/release() as affecting mutability of state.
|
||||||
|
*/
|
||||||
|
#define CC_REF_PTR_SAFE_RETAIN(ptr)\
|
||||||
|
\
|
||||||
|
do\
|
||||||
|
{\
|
||||||
|
if (ptr)\
|
||||||
|
{\
|
||||||
|
const_cast<Ref*>(static_cast<const Ref*>(ptr))->retain();\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define CC_REF_PTR_SAFE_RELEASE(ptr)\
|
||||||
|
\
|
||||||
|
do\
|
||||||
|
{\
|
||||||
|
if (ptr)\
|
||||||
|
{\
|
||||||
|
const_cast<Ref*>(static_cast<const Ref*>(ptr))->release();\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define CC_REF_PTR_SAFE_RELEASE_NULL(ptr)\
|
||||||
|
\
|
||||||
|
do\
|
||||||
|
{\
|
||||||
|
if (ptr)\
|
||||||
|
{\
|
||||||
|
const_cast<Ref*>(static_cast<const Ref*>(ptr))->release();\
|
||||||
|
ptr = nullptr;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class which maintains a strong reference to a cocos2dx cocos2d::Ref* type object.
|
||||||
|
* Similar in concept to a boost smart pointer.
|
||||||
|
*
|
||||||
|
* Enables the use of the RAII idiom with Cocos2dx objects and helps automate some of the more
|
||||||
|
* mundane tasks of pointer initialization and cleanup.
|
||||||
|
*
|
||||||
|
* The class itself is modelled on C++ 11 std::shared_ptr, and trys to keep some of the methods
|
||||||
|
* and functionality consistent with std::shared_ptr.
|
||||||
|
*/
|
||||||
|
template <typename T> class RefPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline RefPtr()
|
||||||
|
:
|
||||||
|
_ptr(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr(RefPtr<T> && other)
|
||||||
|
{
|
||||||
|
_ptr = other._ptr;
|
||||||
|
other._ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr(T * ptr)
|
||||||
|
:
|
||||||
|
_ptr(const_cast<typename std::remove_const<T>::type*>(ptr)) // Const cast allows RefPtr<T> to reference objects marked const too.
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RETAIN(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr(std::nullptr_t ptr)
|
||||||
|
:
|
||||||
|
_ptr(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr(const RefPtr<T> & other)
|
||||||
|
:
|
||||||
|
_ptr(other._ptr)
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RETAIN(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~RefPtr()
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr<T> & operator = (const RefPtr<T> & other)
|
||||||
|
{
|
||||||
|
if (other._ptr != _ptr)
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RETAIN(other._ptr);
|
||||||
|
CC_REF_PTR_SAFE_RELEASE(_ptr);
|
||||||
|
_ptr = other._ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr<T> & operator = (RefPtr<T> && other)
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RELEASE(_ptr);
|
||||||
|
_ptr = other._ptr;
|
||||||
|
other._ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr<T> & operator = (T * other)
|
||||||
|
{
|
||||||
|
if (other != _ptr)
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RETAIN(other);
|
||||||
|
CC_REF_PTR_SAFE_RELEASE(_ptr);
|
||||||
|
_ptr = const_cast<typename std::remove_const<T>::type*>(other); // Const cast allows RefPtr<T> to reference objects marked const too.
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RefPtr<T> & operator = (std::nullptr_t other)
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: using reinterpret_cast<> instead of static_cast<> here because it doesn't require type info.
|
||||||
|
// Since we verify the correct type cast at compile time on construction/assign we don't need to know the type info
|
||||||
|
// here. Not needing the type info here enables us to use these operations in inline functions in header files when
|
||||||
|
// the type pointed to by this class is only forward referenced.
|
||||||
|
|
||||||
|
inline operator T * () const { return reinterpret_cast<T*>(_ptr); }
|
||||||
|
|
||||||
|
inline T & operator * () const
|
||||||
|
{
|
||||||
|
CCASSERT(_ptr, "Attempt to dereference a null pointer!");
|
||||||
|
return reinterpret_cast<T&>(*_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T * operator->() const
|
||||||
|
{
|
||||||
|
CCASSERT(_ptr, "Attempt to dereference a null pointer!");
|
||||||
|
return reinterpret_cast<T*>(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T * get() const { return reinterpret_cast<T*>(_ptr); }
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator == (const RefPtr<T> & other) const { return _ptr == other._ptr; }
|
||||||
|
|
||||||
|
inline bool operator == (const T * other) const { return _ptr == other; }
|
||||||
|
|
||||||
|
inline bool operator == (typename std::remove_const<T>::type * other) const { return _ptr == other; }
|
||||||
|
|
||||||
|
inline bool operator == (const std::nullptr_t other) const { return _ptr == other; }
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator != (const RefPtr<T> & other) const { return _ptr != other._ptr; }
|
||||||
|
|
||||||
|
inline bool operator != (const T * other) const { return _ptr != other; }
|
||||||
|
|
||||||
|
inline bool operator != (typename std::remove_const<T>::type * other) const { return _ptr != other; }
|
||||||
|
|
||||||
|
inline bool operator != (const std::nullptr_t other) const { return _ptr != other; }
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator > (const RefPtr<T> & other) const { return _ptr > other._ptr; }
|
||||||
|
|
||||||
|
inline bool operator > (const T * other) const { return _ptr > other; }
|
||||||
|
|
||||||
|
inline bool operator > (typename std::remove_const<T>::type * other) const { return _ptr > other; }
|
||||||
|
|
||||||
|
inline bool operator > (const std::nullptr_t other) const { return _ptr > other; }
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator < (const RefPtr<T> & other) const { return _ptr < other._ptr; }
|
||||||
|
|
||||||
|
inline bool operator < (const T * other) const { return _ptr < other; }
|
||||||
|
|
||||||
|
inline bool operator < (typename std::remove_const<T>::type * other) const { return _ptr < other; }
|
||||||
|
|
||||||
|
inline bool operator < (const std::nullptr_t other) const { return _ptr < other; }
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator >= (const RefPtr<T> & other) const { return _ptr >= other._ptr; }
|
||||||
|
|
||||||
|
inline bool operator >= (const T * other) const { return _ptr >= other; }
|
||||||
|
|
||||||
|
inline bool operator >= (typename std::remove_const<T>::type * other) const { return _ptr >= other; }
|
||||||
|
|
||||||
|
inline bool operator >= (const std::nullptr_t other) const { return _ptr >= other; }
|
||||||
|
|
||||||
|
|
||||||
|
inline bool operator <= (const RefPtr<T> & other) const { return _ptr <= other._ptr; }
|
||||||
|
|
||||||
|
inline bool operator <= (const T * other) const { return _ptr <= other; }
|
||||||
|
|
||||||
|
inline bool operator <= (typename std::remove_const<T>::type * other) const { return _ptr <= other; }
|
||||||
|
|
||||||
|
inline bool operator <= (const std::nullptr_t other) const { return _ptr <= other; }
|
||||||
|
|
||||||
|
|
||||||
|
inline operator bool() const { return _ptr != nullptr; }
|
||||||
|
|
||||||
|
inline void reset()
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void swap(RefPtr<T> & other)
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
Ref * tmp = _ptr;
|
||||||
|
_ptr = other._ptr;
|
||||||
|
other._ptr = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function assigns to this RefPtr<T> but does not increase the reference count of the object pointed to.
|
||||||
|
* Useful for assigning an object created through the 'new' operator to a RefPtr<T>. Basically used in scenarios
|
||||||
|
* where the RefPtr<T> has the initial ownership of the object.
|
||||||
|
*
|
||||||
|
* E.G:
|
||||||
|
* RefPtr<cocos2d::Image> image;
|
||||||
|
* image.weakAssign(new cocos2d::Image());
|
||||||
|
*
|
||||||
|
* Instead of:
|
||||||
|
* RefPtr<cocos2d::Image> image;
|
||||||
|
* image = new cocos2d::Image();
|
||||||
|
* image->release(); // Required because new'd object already has a reference count of '1'.
|
||||||
|
*/
|
||||||
|
inline void weakAssign(const RefPtr<T> & other)
|
||||||
|
{
|
||||||
|
CC_REF_PTR_SAFE_RELEASE(_ptr);
|
||||||
|
_ptr = other._ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ref * _ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast between RefPtr types statically.
|
||||||
|
*/
|
||||||
|
template<class T, class U> RefPtr<T> static_pointer_cast(const RefPtr<U> & r)
|
||||||
|
{
|
||||||
|
return RefPtr<T>(static_cast<T*>(r.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast between RefPtr types dynamically.
|
||||||
|
*/
|
||||||
|
template<class T, class U> RefPtr<T> dynamic_pointer_cast(const RefPtr<U> & r)
|
||||||
|
{
|
||||||
|
return RefPtr<T>(dynamic_cast<T*>(r.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Done with these macros.
|
||||||
|
*/
|
||||||
|
#undef CC_REF_PTR_SAFE_RETAIN
|
||||||
|
#undef CC_REF_PTR_SAFE_RELEASE
|
||||||
|
#undef CC_REF_PTR_SAFE_RELEASE_NULL
|
||||||
|
|
||||||
|
NS_CC_END
|
||||||
|
|
||||||
|
#endif // __CC_REF_PTR_H__
|
|
@ -171,6 +171,7 @@ Classes/TouchesTest/Ball.cpp \
|
||||||
Classes/TouchesTest/Paddle.cpp \
|
Classes/TouchesTest/Paddle.cpp \
|
||||||
Classes/TouchesTest/TouchesTest.cpp \
|
Classes/TouchesTest/TouchesTest.cpp \
|
||||||
Classes/TransitionsTest/TransitionsTest.cpp \
|
Classes/TransitionsTest/TransitionsTest.cpp \
|
||||||
|
Classes/UnitTest/RefPtrTest.cpp \
|
||||||
Classes/UnitTest/UnitTest.cpp \
|
Classes/UnitTest/UnitTest.cpp \
|
||||||
Classes/UserDefaultTest/UserDefaultTest.cpp \
|
Classes/UserDefaultTest/UserDefaultTest.cpp \
|
||||||
Classes/ZwoptexTest/ZwoptexTest.cpp
|
Classes/ZwoptexTest/ZwoptexTest.cpp
|
||||||
|
|
|
@ -172,6 +172,7 @@ set(SAMPLE_SRC
|
||||||
Classes/DataVisitorTest/DataVisitorTest.cpp
|
Classes/DataVisitorTest/DataVisitorTest.cpp
|
||||||
Classes/ConfigurationTest/ConfigurationTest.cpp
|
Classes/ConfigurationTest/ConfigurationTest.cpp
|
||||||
Classes/ConsoleTest/ConsoleTest.cpp
|
Classes/ConsoleTest/ConsoleTest.cpp
|
||||||
|
Classes/UnitTest/RefPtrTest.cpp
|
||||||
Classes/UnitTest/UnitTest.cpp
|
Classes/UnitTest/UnitTest.cpp
|
||||||
Classes/controller.cpp
|
Classes/controller.cpp
|
||||||
Classes/testBasic.cpp
|
Classes/testBasic.cpp
|
||||||
|
|
|
@ -0,0 +1,322 @@
|
||||||
|
#include "RefPtrTest.h"
|
||||||
|
#include "CCRefPtr.h"
|
||||||
|
|
||||||
|
void RefPtrTest::onEnter()
|
||||||
|
{
|
||||||
|
UnitTestDemo::onEnter();
|
||||||
|
|
||||||
|
// TEST(constructors)
|
||||||
|
{
|
||||||
|
// Default constructor
|
||||||
|
RefPtr<Ref> ref1;
|
||||||
|
CC_ASSERT(nullptr == ref1.get());
|
||||||
|
|
||||||
|
// Parameter constructor
|
||||||
|
RefPtr<__String> ref2(cocos2d::String::create("Hello"));
|
||||||
|
CC_ASSERT(strcmp("Hello", ref2->getCString()) == 0);
|
||||||
|
CC_ASSERT(2 == ref2->getReferenceCount());
|
||||||
|
|
||||||
|
// Parameter constructor with nullptr
|
||||||
|
RefPtr<__String> ref3(nullptr);
|
||||||
|
CC_ASSERT((__String*) nullptr == ref3.get());
|
||||||
|
|
||||||
|
// Copy constructor
|
||||||
|
RefPtr<__String> ref4(ref2);
|
||||||
|
CC_ASSERT(strcmp("Hello", ref4->getCString()) == 0);
|
||||||
|
CC_ASSERT(3 == ref2->getReferenceCount());
|
||||||
|
CC_ASSERT(3 == ref4->getReferenceCount());
|
||||||
|
|
||||||
|
// Copy constructor with nullptr reference
|
||||||
|
RefPtr<Ref> ref5(ref1);
|
||||||
|
CC_ASSERT((Ref*) nullptr == ref5.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(destructor)
|
||||||
|
{
|
||||||
|
__String * hello = __String::create("Hello");
|
||||||
|
CC_ASSERT(1 == hello->getReferenceCount());
|
||||||
|
|
||||||
|
{
|
||||||
|
RefPtr<Ref> ref(hello);
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
CC_ASSERT(1 == hello->getReferenceCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(assignmentOperator)
|
||||||
|
{
|
||||||
|
// Test basic assignment with pointer
|
||||||
|
RefPtr<__String> ref1;
|
||||||
|
CC_ASSERT((Ref*) nullptr == ref1.get());
|
||||||
|
|
||||||
|
ref1 = __String::create("World");
|
||||||
|
CC_ASSERT(strcmp("World", ref1->getCString()) == 0);
|
||||||
|
CC_ASSERT(2 == ref1->getReferenceCount());
|
||||||
|
|
||||||
|
// Assigment back to nullptr
|
||||||
|
__String * world = ref1;
|
||||||
|
CC_ASSERT(2 == world->getReferenceCount());
|
||||||
|
|
||||||
|
ref1 = nullptr;
|
||||||
|
CC_ASSERT(1 == world->getReferenceCount());
|
||||||
|
|
||||||
|
// Assignment swapping
|
||||||
|
ref1 = __String::create("Hello");
|
||||||
|
CC_ASSERT(strcmp("Hello", ref1->getCString()) == 0);
|
||||||
|
CC_ASSERT(2 == ref1->getReferenceCount());
|
||||||
|
|
||||||
|
__String * hello = (__String*) ref1;
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
|
||||||
|
ref1 = world;
|
||||||
|
CC_ASSERT(1 == hello->getReferenceCount());
|
||||||
|
CC_ASSERT(2 == world->getReferenceCount());
|
||||||
|
|
||||||
|
// Test assignment with another reference
|
||||||
|
RefPtr<__String> ref2 = __String::create("blah");
|
||||||
|
__String * blah = ref2;
|
||||||
|
CC_ASSERT(2 == blah->getReferenceCount());
|
||||||
|
|
||||||
|
ref2 = ref1;
|
||||||
|
CC_ASSERT(1 == blah->getReferenceCount());
|
||||||
|
CC_ASSERT(3 == world->getReferenceCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(castBackToPointerOperator)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1 = __String::create("Hello");
|
||||||
|
__String * helloPtr = ref1;
|
||||||
|
Ref * objectPtr = ref1;
|
||||||
|
|
||||||
|
CC_ASSERT(helloPtr == objectPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(dereferenceOperators)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1 = __String::create("Hello");
|
||||||
|
CC_ASSERT(strcmp("Hello", ref1->getCString()) == 0);
|
||||||
|
CC_ASSERT(strcmp("Hello", (*ref1).getCString()) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(convertToBooleanOperator)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1 = __String::create("Hello");
|
||||||
|
CC_ASSERT(true == (bool) ref1);
|
||||||
|
|
||||||
|
ref1 = nullptr;
|
||||||
|
CC_ASSERT(false == (bool) ref1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(get)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1 = __String::create("Hello");
|
||||||
|
CC_ASSERT(strcmp("Hello", ref1.get()->getCString()) == 0);
|
||||||
|
|
||||||
|
ref1.reset();
|
||||||
|
CC_ASSERT((__String*) nullptr == ref1.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(reset)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1;
|
||||||
|
CC_ASSERT((__String*) nullptr == ref1.get());
|
||||||
|
|
||||||
|
ref1.reset();
|
||||||
|
CC_ASSERT((__String*) nullptr == ref1.get());
|
||||||
|
|
||||||
|
ref1 = __String::create("Hello");
|
||||||
|
CC_ASSERT(strcmp("Hello", ref1.get()->getCString()) == 0);
|
||||||
|
|
||||||
|
__String * hello = ref1.get();
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
|
||||||
|
ref1.reset();
|
||||||
|
CC_ASSERT((__String*) nullptr == ref1.get());
|
||||||
|
CC_ASSERT(1 == hello->getReferenceCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(swap)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1;
|
||||||
|
RefPtr<__String> ref2;
|
||||||
|
|
||||||
|
CC_ASSERT((__String*) nullptr == ref1.get());
|
||||||
|
CC_ASSERT((__String*) nullptr == ref2.get());
|
||||||
|
|
||||||
|
ref1.swap(ref2);
|
||||||
|
|
||||||
|
CC_ASSERT((__String*) nullptr == ref1.get());
|
||||||
|
CC_ASSERT((__String*) nullptr == ref2.get());
|
||||||
|
|
||||||
|
__String * hello = __String::create("Hello");
|
||||||
|
CC_ASSERT(1 == hello->getReferenceCount());
|
||||||
|
|
||||||
|
ref1 = hello;
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
|
||||||
|
ref1.swap(ref2);
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
CC_ASSERT((__String*) nullptr == ref1.get());
|
||||||
|
CC_ASSERT(strcmp("Hello", ref2->getCString()) == 0);
|
||||||
|
|
||||||
|
ref1.swap(ref2);
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
CC_ASSERT(strcmp("Hello", ref1->getCString()) == 0);
|
||||||
|
CC_ASSERT((__String*) nullptr == ref2.get());
|
||||||
|
|
||||||
|
__String * world = __String::create("World");
|
||||||
|
CC_ASSERT(1 == world->getReferenceCount());
|
||||||
|
|
||||||
|
ref2 = world;
|
||||||
|
CC_ASSERT(2 == world->getReferenceCount());
|
||||||
|
|
||||||
|
ref2.swap(ref1);
|
||||||
|
CC_ASSERT(strcmp("World", ref1->getCString()) == 0);
|
||||||
|
CC_ASSERT(strcmp("Hello", ref2->getCString()) == 0);
|
||||||
|
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
CC_ASSERT(2 == world->getReferenceCount());
|
||||||
|
|
||||||
|
ref1.swap(ref2);
|
||||||
|
|
||||||
|
CC_ASSERT(strcmp("Hello", ref1->getCString()) == 0);
|
||||||
|
CC_ASSERT(strcmp("World", ref2->getCString()) == 0);
|
||||||
|
|
||||||
|
CC_ASSERT(2 == hello->getReferenceCount());
|
||||||
|
CC_ASSERT(2 == world->getReferenceCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(staticPointerCast)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1 = __String::create("Hello");
|
||||||
|
CC_ASSERT(2 == ref1->getReferenceCount());
|
||||||
|
|
||||||
|
RefPtr<Ref> ref2 = static_pointer_cast<Ref>(ref1);
|
||||||
|
CC_ASSERT(strcmp("Hello", ((__String*) ref2.get())->getCString()) == 0);
|
||||||
|
CC_ASSERT(3 == ref1->getReferenceCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(dynamicPointerCast)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1 = cocos2d::String::create("Hello");
|
||||||
|
CC_ASSERT(2 == ref1->getReferenceCount());
|
||||||
|
|
||||||
|
RefPtr<Ref> ref2 = dynamic_pointer_cast<Ref>(ref1);
|
||||||
|
CC_ASSERT(strcmp("Hello", ((__String*) ref2.get())->getCString()) == 0);
|
||||||
|
CC_ASSERT(3 == ref1->getReferenceCount());
|
||||||
|
|
||||||
|
RefPtr<__String> ref3 = dynamic_pointer_cast<__String>(ref2);
|
||||||
|
CC_ASSERT(strcmp("Hello", ref3->getCString()) == 0);
|
||||||
|
CC_ASSERT(4 == ref1->getReferenceCount());
|
||||||
|
|
||||||
|
RefPtr<cocos2d::Node> ref4 = dynamic_pointer_cast<cocos2d::Node>(ref2);
|
||||||
|
CC_ASSERT((Ref*) nullptr == ref4.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(weakAssign)
|
||||||
|
{
|
||||||
|
RefPtr<__String> ref1;
|
||||||
|
|
||||||
|
__String * string1 = new __String("Hello");
|
||||||
|
ref1.weakAssign(string1);
|
||||||
|
CC_ASSERT(1 == string1->getReferenceCount());
|
||||||
|
|
||||||
|
RefPtr<__String> ref2 = ref1;
|
||||||
|
CC_ASSERT(2 == string1->getReferenceCount());
|
||||||
|
|
||||||
|
__String * string2 = new __String("World");
|
||||||
|
ref1.weakAssign(string2);
|
||||||
|
|
||||||
|
CC_ASSERT(1 == string1->getReferenceCount());
|
||||||
|
CC_ASSERT(1 == ref2->getReferenceCount());
|
||||||
|
|
||||||
|
__String * string3 = new __String("Blah");
|
||||||
|
RefPtr<__String> ref3;
|
||||||
|
ref3.weakAssign(string3);
|
||||||
|
CC_ASSERT(1 == string3->getReferenceCount());
|
||||||
|
|
||||||
|
string3->retain();
|
||||||
|
CC_ASSERT(2 == string3->getReferenceCount());
|
||||||
|
|
||||||
|
ref3.weakAssign(nullptr);
|
||||||
|
CC_ASSERT(1 == string3->getReferenceCount());
|
||||||
|
CC_SAFE_RELEASE_NULL(string3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(comparisonOperators)
|
||||||
|
{
|
||||||
|
RefPtr<Ref> ref1;
|
||||||
|
RefPtr<Ref> ref2;
|
||||||
|
|
||||||
|
CC_ASSERT(true == (ref1 == ref2));
|
||||||
|
CC_ASSERT(false == (ref1 != ref2));
|
||||||
|
CC_ASSERT(false == (ref1 < ref2));
|
||||||
|
CC_ASSERT(false == (ref1 > ref2));
|
||||||
|
CC_ASSERT(true == (ref1 <= ref2));
|
||||||
|
CC_ASSERT(true == (ref1 >= ref2));
|
||||||
|
|
||||||
|
CC_ASSERT(true == (ref1 == nullptr));
|
||||||
|
CC_ASSERT(false == (ref1 != nullptr));
|
||||||
|
CC_ASSERT(false == (ref1 < nullptr));
|
||||||
|
CC_ASSERT(false == (ref1 > nullptr));
|
||||||
|
CC_ASSERT(true == (ref1 <= nullptr));
|
||||||
|
CC_ASSERT(true == (ref1 >= nullptr));
|
||||||
|
|
||||||
|
CC_ASSERT(false == (ref1 == __String::create("Hello")));
|
||||||
|
CC_ASSERT(true == (ref1 != __String::create("Hello")));
|
||||||
|
CC_ASSERT(true == (ref1 < __String::create("Hello")));
|
||||||
|
CC_ASSERT(false == (ref1 > __String::create("Hello")));
|
||||||
|
CC_ASSERT(true == (ref1 <= __String::create("Hello")));
|
||||||
|
CC_ASSERT(false == (ref1 >= __String::create("Hello")));
|
||||||
|
|
||||||
|
ref1 = __String::create("Hello");
|
||||||
|
|
||||||
|
CC_ASSERT(false == (ref1 == ref2));
|
||||||
|
CC_ASSERT(true == (ref1 != ref2));
|
||||||
|
CC_ASSERT(false == (ref1 < ref2));
|
||||||
|
CC_ASSERT(true == (ref1 > ref2));
|
||||||
|
CC_ASSERT(false == (ref1 <= ref2));
|
||||||
|
CC_ASSERT(true == (ref1 >= ref2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(moveConstructor)
|
||||||
|
{
|
||||||
|
auto someFunc = []() -> RefPtr<__String>
|
||||||
|
{
|
||||||
|
return __String::create("Hello world!");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note: std::move will turn the rvalue into an rvalue reference and thus cause the move constructor to be invoked.
|
||||||
|
// Have to use this because the compiler will try and optimize how we handle the return value otherwise and skip the move constructor.
|
||||||
|
RefPtr<__String> theString(std::move(someFunc()));
|
||||||
|
CC_ASSERT(theString->getReferenceCount() == 2);
|
||||||
|
CC_ASSERT(theString->compare("Hello world!") == 0);
|
||||||
|
|
||||||
|
__String * theStringPtr = theString;
|
||||||
|
theString.reset();
|
||||||
|
CC_ASSERT(theStringPtr->getReferenceCount() == 1);
|
||||||
|
CC_ASSERT(theStringPtr->compare("Hello world!") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST(moveAssignmentOperator)
|
||||||
|
{
|
||||||
|
auto someFunc = []() -> RefPtr<__String>
|
||||||
|
{
|
||||||
|
return __String::create("Hello world!");
|
||||||
|
};
|
||||||
|
|
||||||
|
RefPtr<__String> theString(someFunc());
|
||||||
|
CC_ASSERT(theString->getReferenceCount() == 2);
|
||||||
|
CC_ASSERT(theString->compare("Hello world!") == 0);
|
||||||
|
|
||||||
|
theString = someFunc(); // No need to use std::move here, compiler should figure out that move semantics are appropriate for this statement.
|
||||||
|
CC_ASSERT(theString->getReferenceCount() == 2);
|
||||||
|
CC_ASSERT(theString->compare("Hello world!") == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RefPtrTest::subtitle() const
|
||||||
|
{
|
||||||
|
return "RefPtrTest, should not crash!";
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef __REF_PTR_TEST_H__
|
||||||
|
#define __REF_PTR_TEST_H__
|
||||||
|
|
||||||
|
#include "UnitTest.h"
|
||||||
|
|
||||||
|
class RefPtrTest : public UnitTestDemo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CREATE_FUNC(RefPtrTest);
|
||||||
|
|
||||||
|
virtual void onEnter() override;
|
||||||
|
|
||||||
|
virtual std::string subtitle() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __REF_PTR_TEST_H__ */
|
|
@ -1,11 +1,13 @@
|
||||||
#include "UnitTest.h"
|
#include "UnitTest.h"
|
||||||
|
#include "RefPtrTest.h"
|
||||||
|
|
||||||
// For ' < o > ' multiply test scene.
|
// For ' < o > ' multiply test scene.
|
||||||
|
|
||||||
static std::function<Layer*()> createFunctions[] = {
|
static std::function<Layer*()> createFunctions[] = {
|
||||||
CL(TemplateVectorTest),
|
CL(TemplateVectorTest),
|
||||||
CL(TemplateMapTest),
|
CL(TemplateMapTest),
|
||||||
CL(ValueTest)
|
CL(ValueTest),
|
||||||
|
CL(RefPtrTest)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sceneIdx = -1;
|
static int sceneIdx = -1;
|
||||||
|
|
|
@ -224,6 +224,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\external\websockets\prebuilt\win32\*.*" "$(Ou
|
||||||
<ClCompile Include="..\Classes\ShaderTest\ShaderTest2.cpp" />
|
<ClCompile Include="..\Classes\ShaderTest\ShaderTest2.cpp" />
|
||||||
<ClCompile Include="..\Classes\SpineTest\SpineTest.cpp" />
|
<ClCompile Include="..\Classes\SpineTest\SpineTest.cpp" />
|
||||||
<ClCompile Include="..\Classes\TexturePackerEncryptionTest\TextureAtlasEncryptionTest.cpp" />
|
<ClCompile Include="..\Classes\TexturePackerEncryptionTest\TextureAtlasEncryptionTest.cpp" />
|
||||||
|
<ClCompile Include="..\Classes\UnitTest\RefPtrTest.cpp" />
|
||||||
<ClCompile Include="..\Classes\UnitTest\UnitTest.cpp" />
|
<ClCompile Include="..\Classes\UnitTest\UnitTest.cpp" />
|
||||||
<ClCompile Include="..\Classes\VisibleRect.cpp" />
|
<ClCompile Include="..\Classes\VisibleRect.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
|
@ -402,6 +403,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\external\websockets\prebuilt\win32\*.*" "$(Ou
|
||||||
<ClInclude Include="..\Classes\ShaderTest\ShaderTest2.h" />
|
<ClInclude Include="..\Classes\ShaderTest\ShaderTest2.h" />
|
||||||
<ClInclude Include="..\Classes\SpineTest\SpineTest.h" />
|
<ClInclude Include="..\Classes\SpineTest\SpineTest.h" />
|
||||||
<ClInclude Include="..\Classes\TexturePackerEncryptionTest\TextureAtlasEncryptionTest.h" />
|
<ClInclude Include="..\Classes\TexturePackerEncryptionTest\TextureAtlasEncryptionTest.h" />
|
||||||
|
<ClInclude Include="..\Classes\UnitTest\RefPtrTest.h" />
|
||||||
<ClInclude Include="..\Classes\UnitTest\UnitTest.h" />
|
<ClInclude Include="..\Classes\UnitTest\UnitTest.h" />
|
||||||
<ClInclude Include="..\Classes\VisibleRect.h" />
|
<ClInclude Include="..\Classes\VisibleRect.h" />
|
||||||
<ClInclude Include="main.h" />
|
<ClInclude Include="main.h" />
|
||||||
|
|
|
@ -831,6 +831,9 @@
|
||||||
<ClCompile Include="..\Classes\ShaderTest\ShaderTest2.cpp">
|
<ClCompile Include="..\Classes\ShaderTest\ShaderTest2.cpp">
|
||||||
<Filter>Classes\ShaderTest</Filter>
|
<Filter>Classes\ShaderTest</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Classes\UnitTest\RefPtrTest.cpp">
|
||||||
|
<Filter>Classes\UnitTest</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="main.h">
|
<ClInclude Include="main.h">
|
||||||
|
@ -1535,5 +1538,8 @@
|
||||||
<ClInclude Include="..\Classes\ShaderTest\ShaderTest2.h">
|
<ClInclude Include="..\Classes\ShaderTest\ShaderTest2.h">
|
||||||
<Filter>Classes\ShaderTest</Filter>
|
<Filter>Classes\ShaderTest</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Classes\UnitTest\RefPtrTest.h">
|
||||||
|
<Filter>Classes\UnitTest</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in New Issue