[K/N] Constructor of ObjectPtr with retain ^KT-63423
This commit is contained in:
committed by
Space Team
parent
c4992f1912
commit
e5269daa74
@@ -20,12 +20,16 @@ OBJC_FORWARD_DECLARE(NSObject);
|
||||
|
||||
namespace kotlin::objc_support {
|
||||
|
||||
struct object_ptr_retain_t{};
|
||||
inline constexpr object_ptr_retain_t object_ptr_retain{};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class ObjectPtrImpl {
|
||||
public:
|
||||
ObjectPtrImpl() noexcept;
|
||||
explicit ObjectPtrImpl(NSObject* object) noexcept;
|
||||
ObjectPtrImpl(object_ptr_retain_t, NSObject* object) noexcept;
|
||||
|
||||
ObjectPtrImpl(const ObjectPtrImpl& rhs) noexcept;
|
||||
ObjectPtrImpl(ObjectPtrImpl&& rhs) noexcept;
|
||||
@@ -51,6 +55,7 @@ public:
|
||||
|
||||
void reset() noexcept;
|
||||
void reset(NSObject* object) noexcept;
|
||||
void reset(object_ptr_retain_t, NSObject* object) noexcept;
|
||||
|
||||
bool operator==(const ObjectPtrImpl& rhs) const noexcept;
|
||||
bool operator<(const ObjectPtrImpl& rhs) const noexcept;
|
||||
@@ -65,8 +70,10 @@ private:
|
||||
|
||||
// `std::shared_ptr`-like smart pointer for ObjC objects.
|
||||
//
|
||||
// IMPORTANT: Must be constructed from a retained ObjC object.
|
||||
// IMPORTANT: By default constructed from a retained ObjC object.
|
||||
// This optimizes for the common case of constructing directly from `[[T alloc] init...]`.
|
||||
// To construct and additionally retain the object, use `object_ptr_retain` as the first argument
|
||||
// to the constructor.
|
||||
//
|
||||
// Unlike a regular C++ smart pointer `operator*` does not return a reference but return a pointer
|
||||
// for convenient syntax of calling ObjC methods: `[*smartPtr methodName]`.
|
||||
@@ -88,6 +95,9 @@ public:
|
||||
// IMPORTANT: this does not `retain` `ptr`.
|
||||
explicit object_ptr(T* ptr) noexcept : impl_(ptr) {}
|
||||
|
||||
// Construct from ObjC object, additionally retaining `ptr`.
|
||||
object_ptr(object_ptr_retain_t, T* ptr) noexcept : impl_(object_ptr_retain, ptr) {}
|
||||
|
||||
void swap(object_ptr<T>& rhs) noexcept { impl_.swap(rhs.impl_); }
|
||||
|
||||
T* get() const noexcept { return (T*)impl_.get(); }
|
||||
@@ -104,6 +114,9 @@ public:
|
||||
// IMPORTANT: this does not `retain` `ptr`.
|
||||
void reset(T* ptr) noexcept { impl_.reset(ptr); }
|
||||
|
||||
// Release stored pointer and store `ptr` instead, additionally retaining `ptr`.
|
||||
void reset(object_ptr_retain_t, T* ptr) noexcept { impl_.reset(object_ptr_retain, ptr); }
|
||||
|
||||
template <typename U>
|
||||
bool operator==(const object_ptr<U>& rhs) const noexcept {
|
||||
return impl_ == rhs.impl_;
|
||||
|
||||
@@ -15,6 +15,8 @@ objc_support::internal::ObjectPtrImpl::ObjectPtrImpl() noexcept : object_(nil) {
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(NSObject* object) noexcept : object_(object) {}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(object_ptr_retain_t, NSObject* object) noexcept : object_([object retain]) {}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(const ObjectPtrImpl& rhs) noexcept : object_([rhs.object_ retain]) {}
|
||||
|
||||
objc_support::internal::ObjectPtrImpl::ObjectPtrImpl(ObjectPtrImpl&& rhs) noexcept : object_(rhs.object_) {
|
||||
@@ -51,6 +53,10 @@ void objc_support::internal::ObjectPtrImpl::reset(NSObject* object) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void objc_support::internal::ObjectPtrImpl::reset(object_ptr_retain_t, NSObject* object) noexcept {
|
||||
reset([object retain]);
|
||||
}
|
||||
|
||||
std::size_t objc_support::internal::ObjectPtrImpl::computeHash() const noexcept {
|
||||
return object_.hash;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,21 @@ TEST(ObjectPtrTest, ObjectCtor) {
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ObjectCtorWithRetain) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(objc_support::object_ptr_retain, ptr);
|
||||
EXPECT_CONTAINS(obj, ptr);
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
[ptr release];
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, CopyCtor) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
@@ -304,6 +319,24 @@ TEST(ObjectPtrTest, ResetObjectFromEmpty) {
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetObjectFromEmptyWithRetain) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj;
|
||||
|
||||
obj.reset(objc_support::object_ptr_retain, ptr);
|
||||
EXPECT_CONTAINS(obj, ptr);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl)).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr.impl));
|
||||
[ptr release];
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetObjectFromSet) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
@@ -319,6 +352,27 @@ TEST(ObjectPtrTest, ResetObjectFromSet) {
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
}
|
||||
|
||||
TEST(ObjectPtrTest, ResetObjectFromSetWithRetain) {
|
||||
testing::StrictMock<testing::MockFunction<DestructorHook>> destructorHook;
|
||||
|
||||
auto* ptr1 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
auto* ptr2 = [[WithDestructorHookObjC alloc] initWithDestructorHook:destructorHook.AsStdFunction()];
|
||||
{
|
||||
objc_support::object_ptr<WithDestructorHookObjC> obj(ptr1);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr1.impl));
|
||||
obj.reset(objc_support::object_ptr_retain, ptr2);
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
EXPECT_CONTAINS(obj, ptr2);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl)).Times(0);
|
||||
}
|
||||
testing::Mock::VerifyAndClearExpectations(&destructorHook);
|
||||
|
||||
EXPECT_CALL(destructorHook, Call(ptr2.impl));
|
||||
[ptr2 release];
|
||||
}
|
||||
|
||||
#define EXPECT_EQUAL(expr1, expr2) \
|
||||
do { \
|
||||
EXPECT_TRUE((expr1) == (expr2)); \
|
||||
|
||||
Reference in New Issue
Block a user