mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-12 22:56:09 +00:00
Metal: Wrap NS classes and protocols in NSRef.
This makes refcounting of these objects more automatic to try and prevent leaks or use-after-frees in the future. Also removes operator* from RefBase (and Ref) because it is never used and cannot work in a normal way for ObjectiveC protocols that cannot be dereferenced. Bug: dawn:89 Change-Id: I2e3fbfd638e2ba76d8c563f30bc489a384152552 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/32161 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
1805e46a15
commit
0055d95fa7
@@ -167,6 +167,7 @@ if (is_win || is_linux || is_chromeos || is_mac || is_fuchsia || is_android) {
|
||||
"Log.h",
|
||||
"Math.cpp",
|
||||
"Math.h",
|
||||
"NSRef.h",
|
||||
"PlacementAllocated.h",
|
||||
"Platform.h",
|
||||
"RefBase.h",
|
||||
|
||||
@@ -29,6 +29,7 @@ target_sources(dawn_common PRIVATE
|
||||
"Log.h"
|
||||
"Math.cpp"
|
||||
"Math.h"
|
||||
"NSRef.h"
|
||||
"PlacementAllocated.h"
|
||||
"Platform.h"
|
||||
"RefBase.h"
|
||||
|
||||
123
src/common/NSRef.h
Normal file
123
src/common/NSRef.h
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef COMMON_NSREF_H_
|
||||
#define COMMON_NSREF_H_
|
||||
|
||||
#include "common/RefBase.h"
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#if !defined(__OBJC__)
|
||||
# error "NSRef can only be used in Objective C/C++ code."
|
||||
#endif
|
||||
|
||||
// This file contains smart pointers that automatically reference and release Objective C objects
|
||||
// and prototocals in a manner very similar to Ref<>. Note that NSRef<> and NSPRef's constructor add
|
||||
// a reference to the object by default, so the pattern to get a reference for a newly created
|
||||
// NSObject is the following:
|
||||
//
|
||||
// NSRef<NSFoo> foo = AcquireNSRef([NSFoo alloc]);
|
||||
//
|
||||
// NSRef overloads -> and * but these operators don't work extremely well with Objective C's
|
||||
// features. For example automatic dereferencing when doing the following doesn't work:
|
||||
//
|
||||
// NSFoo* foo;
|
||||
// foo.member = 1;
|
||||
// someVar = foo.member;
|
||||
//
|
||||
// Instead use the message passing syntax:
|
||||
//
|
||||
// NSRef<NSFoo> foo;
|
||||
// [*foo setMember: 1];
|
||||
// someVar = [*foo member];
|
||||
//
|
||||
// Also did you notive the extra '*' in the example above? That's because Objective C's message
|
||||
// passing doesn't automatically call a C++ operator to dereference smart pointers (like -> does) so
|
||||
// we have to dereference manually using '*'. In some cases the extra * or message passing syntax
|
||||
// can get a bit annoying so instead a local "naked" pointer can be borrowed from the NSRef. This
|
||||
// would change the syntax overload in the following:
|
||||
//
|
||||
// NSRef<NSFoo> foo;
|
||||
// [*foo setA:1];
|
||||
// [*foo setB:2];
|
||||
// [*foo setC:3];
|
||||
//
|
||||
// Into (note access to members of ObjC classes referenced via pointer is done with . and not ->):
|
||||
//
|
||||
// NSRef<NSFoo> fooRef;
|
||||
// NSFoo* foo = fooRef.Get();
|
||||
// foo.a = 1;
|
||||
// foo.b = 2;
|
||||
// boo.c = 3;
|
||||
//
|
||||
// Which can be subjectively easier to read.
|
||||
|
||||
template <typename T>
|
||||
struct NSRefTraits {
|
||||
static constexpr T kNullValue = nullptr;
|
||||
static void Reference(T value) {
|
||||
[value retain];
|
||||
}
|
||||
static void Release(T value) {
|
||||
[value release];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class NSRef : public RefBase<T*, NSRefTraits<T*>> {
|
||||
public:
|
||||
using RefBase<T*, NSRefTraits<T*>>::RefBase;
|
||||
|
||||
const T* operator*() const {
|
||||
return this->Get();
|
||||
}
|
||||
|
||||
T* operator*() {
|
||||
return this->Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
NSRef<T> AcquireNSRef(T* pointee) {
|
||||
NSRef<T> ref;
|
||||
ref.Acquire(pointee);
|
||||
return ref;
|
||||
}
|
||||
|
||||
// This is a RefBase<> for an Objective C protocol (hence the P). Objective C protocols must always
|
||||
// be referenced with id<ProtocolName> and not just ProtocolName* so they cannot use NSRef<>
|
||||
// itself. That's what the P in NSPRef stands for: Protocol.
|
||||
template <typename T>
|
||||
class NSPRef : public RefBase<T, NSRefTraits<T>> {
|
||||
public:
|
||||
using RefBase<T, NSRefTraits<T>>::RefBase;
|
||||
|
||||
const T operator*() const {
|
||||
return this->Get();
|
||||
}
|
||||
|
||||
T operator*() {
|
||||
return this->Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
NSPRef<T> AcquireNSPRef(T pointee) {
|
||||
NSPRef<T> ref;
|
||||
ref.Acquire(pointee);
|
||||
return ref;
|
||||
}
|
||||
|
||||
#endif // COMMON_NSREF_H_
|
||||
@@ -137,14 +137,6 @@ class RefBase {
|
||||
return mValue != kNullValue;
|
||||
}
|
||||
|
||||
// Operator * and -> to act like a pointer.
|
||||
const typename Traits::PointedType& operator*() const {
|
||||
return *mValue;
|
||||
}
|
||||
typename Traits::PointedType& operator*() {
|
||||
return *mValue;
|
||||
}
|
||||
|
||||
const T operator->() const {
|
||||
return mValue;
|
||||
}
|
||||
@@ -166,6 +158,11 @@ class RefBase {
|
||||
return value;
|
||||
}
|
||||
|
||||
void Acquire(T value) {
|
||||
Release();
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
private:
|
||||
// Friend is needed so that instances of RefBase<U> can call Reference and Release on
|
||||
// RefBase<T>.
|
||||
|
||||
@@ -42,7 +42,6 @@ class RefCounted {
|
||||
|
||||
template <typename T>
|
||||
struct RefCountedTraits {
|
||||
using PointedType = T;
|
||||
static constexpr T* kNullValue = nullptr;
|
||||
static void Reference(T* value) {
|
||||
value->Reference();
|
||||
@@ -60,8 +59,8 @@ class Ref : public RefBase<T*, RefCountedTraits<T>> {
|
||||
|
||||
template <typename T>
|
||||
Ref<T> AcquireRef(T* pointee) {
|
||||
Ref<T> ref(pointee);
|
||||
ref->Release();
|
||||
Ref<T> ref;
|
||||
ref.Acquire(pointee);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user