diff options
author | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-20 22:42:11 +0000 |
---|---|---|
committer | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-20 22:42:11 +0000 |
commit | 974282583d003c569aca7a22b72cc2ca94264af1 (patch) | |
tree | 768c0ba11cce6835e54ce39b567a9e0f98c94ff5 /base/mac | |
parent | 1a5f6eacc2e704970d566b236c196645eab7d2aa (diff) | |
download | chromium_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.h | 6 | ||||
-rw-r--r-- | base/mac/scoped_nsobject.h | 156 | ||||
-rw-r--r-- | base/mac/scoped_nsobject_unittest.mm | 86 |
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 |