summaryrefslogtreecommitdiffstats
path: root/base/mac
diff options
context:
space:
mode:
authorthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-20 22:42:11 +0000
committerthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-20 22:42:11 +0000
commit974282583d003c569aca7a22b72cc2ca94264af1 (patch)
tree768c0ba11cce6835e54ce39b567a9e0f98c94ff5 /base/mac
parent1a5f6eacc2e704970d566b236c196645eab7d2aa (diff)
downloadchromium_src-974282583d003c569aca7a22b72cc2ca94264af1.zip
chromium_src-974282583d003c569aca7a22b72cc2ca94264af1.tar.gz
chromium_src-974282583d003c569aca7a22b72cc2ca94264af1.tar.bz2
Move scoped_nsobject from base/memory to base/mac.
So it's next to scoped_cftyperef.h. Also move both scoped_nsobject and ScopedCFTypeRef to namespace base. BUG=251957 R=mark@chromium.org Review URL: https://codereview.chromium.org/17500005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207616 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/mac')
-rw-r--r--base/mac/scoped_cftyperef.h6
-rw-r--r--base/mac/scoped_nsobject.h156
-rw-r--r--base/mac/scoped_nsobject_unittest.mm86
3 files changed, 247 insertions, 1 deletions
diff --git a/base/mac/scoped_cftyperef.h b/base/mac/scoped_cftyperef.h
index c6ca46a..f09fcbf 100644
--- a/base/mac/scoped_cftyperef.h
+++ b/base/mac/scoped_cftyperef.h
@@ -12,7 +12,6 @@
#include "base/memory/scoped_policy.h"
namespace base {
-namespace mac {
// ScopedCFTypeRef<> is patterned after scoped_ptr<>, but maintains ownership
// of a CoreFoundation object: any object that can be represented as a
@@ -102,7 +101,12 @@ class ScopedCFTypeRef {
CFT object_;
};
+// TODO(thakis): Remove this once all clients use base::ScopedCFTypeRef
+// directly.
+namespace mac {
+using base::ScopedCFTypeRef;
} // namespace mac
+
} // namespace base
#endif // BASE_MAC_SCOPED_CFTYPEREF_H_
diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h
new file mode 100644
index 0000000..8d7bd4a
--- /dev/null
+++ b/base/mac/scoped_nsobject.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_NSOBJECT_H_
+#define BASE_MAC_SCOPED_NSOBJECT_H_
+
+#import <Foundation/Foundation.h>
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
+// of an NSObject subclass object. Style deviations here are solely for
+// compatibility with scoped_ptr<>'s interface, with which everyone is already
+// familiar.
+//
+// scoped_nsobject<> takes ownership of an object (in the constructor or in
+// reset()) by taking over the caller's existing ownership claim. The caller
+// must own the object it gives to scoped_nsobject<>, and relinquishes an
+// ownership claim to that object. scoped_nsobject<> does not call -retain,
+// callers have to call this manually if appropriate.
+//
+// scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used
+// with protocols.
+//
+// scoped_nsobject<> is not to be used for NSAutoreleasePools. For
+// NSAutoreleasePools use ScopedNSAutoreleasePool from
+// scoped_nsautorelease_pool.h instead.
+// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
+// time with a template specialization (see below).
+
+template<typename NST>
+class scoped_nsprotocol {
+ public:
+ explicit scoped_nsprotocol(NST object = nil) : object_(object) {}
+
+ scoped_nsprotocol(const scoped_nsprotocol<NST>& that)
+ : object_([that.object_ retain]) {
+ }
+
+ ~scoped_nsprotocol() {
+ [object_ release];
+ }
+
+ scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) {
+ reset([that.get() retain]);
+ return *this;
+ }
+
+ void reset(NST object = nil) {
+ // We intentionally do not check that object != object_ as the caller must
+ // either already have an ownership claim over whatever it passes to this
+ // method, or call it with the |RETAIN| policy which will have ensured that
+ // the object is retained once more when reaching this point.
+ [object_ release];
+ object_ = object;
+ }
+
+ bool operator==(NST that) const { return object_ == that; }
+ bool operator!=(NST that) const { return object_ != that; }
+
+ operator NST() const {
+ return object_;
+ }
+
+ NST get() const {
+ return object_;
+ }
+
+ void swap(scoped_nsprotocol& that) {
+ NST temp = that.object_;
+ that.object_ = object_;
+ object_ = temp;
+ }
+
+ // scoped_nsprotocol<>::release() is like scoped_ptr<>::release. It is NOT a
+ // wrapper for [object_ release]. To force a scoped_nsprotocol<> to call
+ // [object_ release], use scoped_nsprotocol<>::reset().
+ NST release() WARN_UNUSED_RESULT {
+ NST temp = object_;
+ object_ = nil;
+ return temp;
+ }
+
+ // Shift reference to the autorelease pool to be released later.
+ NST autorelease() {
+ return [release() autorelease];
+ }
+
+ private:
+ NST object_;
+};
+
+// Free functions
+template <class C>
+void swap(scoped_nsprotocol<C>& p1, scoped_nsprotocol<C>& p2) {
+ p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C p1, const scoped_nsprotocol<C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
+ return p1 != p2.get();
+}
+
+template<typename NST>
+class scoped_nsobject : public scoped_nsprotocol<NST*> {
+ public:
+ explicit scoped_nsobject(NST* object = nil)
+ : scoped_nsprotocol<NST*>(object) {}
+
+ scoped_nsobject(const scoped_nsobject<NST>& that)
+ : scoped_nsprotocol<NST*>(that) {
+ }
+
+ scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
+ scoped_nsprotocol<NST*>::operator=(that);
+ return *this;
+ }
+};
+
+// Specialization to make scoped_nsobject<id> work.
+template<>
+class scoped_nsobject<id> : public scoped_nsprotocol<id> {
+ public:
+ explicit scoped_nsobject(id object = nil) : scoped_nsprotocol<id>(object) {}
+
+ scoped_nsobject(const scoped_nsobject<id>& that)
+ : scoped_nsprotocol<id>(that) {
+ }
+
+ scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
+ scoped_nsprotocol<id>::operator=(that);
+ return *this;
+ }
+};
+
+// Do not use scoped_nsobject for NSAutoreleasePools, use
+// ScopedNSAutoreleasePool instead. This is a compile time check. See details
+// at top of header.
+template<>
+class scoped_nsobject<NSAutoreleasePool> {
+ private:
+ explicit scoped_nsobject(NSAutoreleasePool* object = nil);
+ DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
+};
+
+} // namespace base
+
+#endif // BASE_MAC_SCOPED_NSOBJECT_H_
diff --git a/base/mac/scoped_nsobject_unittest.mm b/base/mac/scoped_nsobject_unittest.mm
new file mode 100644
index 0000000..f290c3a
--- /dev/null
+++ b/base/mac/scoped_nsobject_unittest.mm
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(ScopedNSObjectTest, ScopedNSObject) {
+ base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+ ASSERT_TRUE(p1.get());
+ ASSERT_EQ(1u, [p1 retainCount]);
+ base::scoped_nsobject<NSObject> p2(p1);
+ ASSERT_EQ(p1.get(), p2.get());
+ ASSERT_EQ(2u, [p1 retainCount]);
+ p2.reset();
+ ASSERT_EQ(nil, p2.get());
+ ASSERT_EQ(1u, [p1 retainCount]);
+ {
+ base::scoped_nsobject<NSObject> p3 = p1;
+ ASSERT_EQ(p1.get(), p3.get());
+ ASSERT_EQ(2u, [p1 retainCount]);
+ p3 = p1;
+ ASSERT_EQ(p1.get(), p3.get());
+ ASSERT_EQ(2u, [p1 retainCount]);
+ }
+ ASSERT_EQ(1u, [p1 retainCount]);
+ base::scoped_nsobject<NSObject> p4([p1.get() retain]);
+ ASSERT_EQ(2u, [p1 retainCount]);
+ ASSERT_TRUE(p1 == p1.get());
+ ASSERT_TRUE(p1 == p1);
+ ASSERT_FALSE(p1 != p1);
+ ASSERT_FALSE(p1 != p1.get());
+ base::scoped_nsobject<NSObject> p5([[NSObject alloc] init]);
+ ASSERT_TRUE(p1 != p5);
+ ASSERT_TRUE(p1 != p5.get());
+ ASSERT_FALSE(p1 == p5);
+ ASSERT_FALSE(p1 == p5.get());
+
+ base::scoped_nsobject<NSObject> p6 = p1;
+ ASSERT_EQ(3u, [p6 retainCount]);
+ {
+ base::mac::ScopedNSAutoreleasePool pool;
+ p6.autorelease();
+ ASSERT_EQ(nil, p6.get());
+ ASSERT_EQ(3u, [p1 retainCount]);
+ }
+ ASSERT_EQ(2u, [p1 retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectInContainer) {
+ base::scoped_nsobject<id> p([[NSObject alloc] init]);
+ ASSERT_TRUE(p.get());
+ ASSERT_EQ(1u, [p retainCount]);
+ {
+ std::vector<base::scoped_nsobject<id>> objects;
+ objects.push_back(p);
+ ASSERT_EQ(2u, [p retainCount]);
+ ASSERT_EQ(p.get(), objects[0].get());
+ objects.push_back(base::scoped_nsobject<id>([[NSObject alloc] init]));
+ ASSERT_TRUE(objects[1].get());
+ ASSERT_EQ(1u, [objects[1] retainCount]);
+ }
+ ASSERT_EQ(1u, [p retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectFreeFunctions) {
+ base::scoped_nsobject<id> p1([[NSObject alloc] init]);
+ id o1 = p1.get();
+ ASSERT_TRUE(o1 == p1);
+ ASSERT_FALSE(o1 != p1);
+ base::scoped_nsobject<id> p2([[NSObject alloc] init]);
+ ASSERT_TRUE(o1 != p2);
+ ASSERT_FALSE(o1 == p2);
+ id o2 = p2.get();
+ swap(p1, p2);
+ ASSERT_EQ(o2, p1.get());
+ ASSERT_EQ(o1, p2.get());
+}
+
+} // namespace