Change nonstd::unique_ptr to take a custom deleter.
authorLei Zhang <thestig@chromium.org>
Wed, 23 Sep 2015 02:15:49 +0000 (19:15 -0700)
committerLei Zhang <thestig@chromium.org>
Wed, 23 Sep 2015 02:15:49 +0000 (19:15 -0700)
Code is mostly stolen from Chromium's scoped_ptr.

- Add unit tests.
- Use this to fix a leak.

BUG=chromium:531408
R=jyasskin@chromium.org, tsepez@chromium.org

Review URL: https://codereview.chromium.org/1351383004 .

BUILD.gn
core/include/fxcrt/fx_basic.h
core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
third_party/base/nonstd_unique_ptr.h
third_party/base/nonstd_unique_ptr_unittest.cpp
third_party/base/template_util.h

index bba4818..ec28f17 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -740,6 +740,7 @@ test("pdfium_unittests") {
     "core/src/fxcrt/fx_system_unittest.cpp",
     "testing/fx_string_testhelpers.cpp",
     "testing/fx_string_testhelpers.h",
+    "third_party/base/nonstd_unique_ptr_unittest.cpp",
   ]
   deps = [
     "//testing/gtest",
index bc3d812..3e556f5 100644 (file)
@@ -947,6 +947,13 @@ class CFX_AutoRestorer {
   T m_OldValue;
 };
 
+// Used with nonstd::unique_ptr to Release() objects that can't be deleted.
+template <class T>
+struct ReleaseDeleter {
+  inline void operator()(T* ptr) const { ptr->Release(); }
+};
+
+// TODO(thestig) Remove in favor of nonstd::unique_ptr.
 template <class T>
 class CFX_SmartPointer {
  public:
@@ -959,6 +966,7 @@ class CFX_SmartPointer {
  protected:
   T* m_pObj;
 };
+
 #define FX_DATALIST_LENGTH 1024
 template <size_t unit>
 class CFX_SortListArray {
index ff14a98..7482f0b 100644 (file)
@@ -2376,8 +2376,9 @@ CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(
         continue;
       }
       key = PDF_NameDecode(key);
-      CPDF_Object* pObj = GetObject(pObjList, objnum, gennum);
-      if (pObj == NULL) {
+      nonstd::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>> obj(
+          GetObject(pObjList, objnum, gennum));
+      if (!obj) {
         if (pDict) {
           pDict->Release();
         }
@@ -2394,7 +2395,7 @@ CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict(
       }
       if (key.GetLength() > 1) {
         pDict->AddValue(CFX_ByteStringC(key.c_str() + 1, key.GetLength() - 1),
-                        pObj);
+                        obj.release());
       }
     }
     if (pContext) {
index d666e1e..f519b34 100644 (file)
 #include <stddef.h>
 #include <stdlib.h>
 
+#include <ostream>
+
+#include "template_util.h"
+
 namespace nonstd {
 
 // Replacement for move, but doesn't allow things that are already
@@ -82,47 +86,114 @@ T&& move(T& t) {
   return static_cast<T&&>(t);
 }
 
+// Function object which deletes its parameter, which must be a pointer.
+// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
+// invokes 'delete'. The default deleter for unique_ptr<T>.
+template <class T>
+struct DefaultDeleter {
+  DefaultDeleter() {}
+  template <typename U>
+  DefaultDeleter(const DefaultDeleter<U>& other) {
+    // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
+    // if U* is implicitly convertible to T* and U is not an array type.
+    //
+    // Correct implementation should use SFINAE to disable this
+    // constructor. However, since there are no other 1-argument constructors,
+    // using a static_assert() based on is_convertible<> and requiring
+    // complete types is simpler and will cause compile failures for equivalent
+    // misuses.
+    //
+    // Note, the is_convertible<U*, T*> check also ensures that U is not an
+    // array. T is guaranteed to be a non-array, so any U* where U is an array
+    // cannot convert to T*.
+    enum { T_must_be_complete = sizeof(T) };
+    enum { U_must_be_complete = sizeof(U) };
+    static_assert((pdfium::base::is_convertible<U*, T*>::value),
+                  "U_ptr_must_implicitly_convert_to_T_ptr");
+  }
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
+    delete ptr;
+  }
+};
+
+// Specialization of DefaultDeleter for array types.
+template <class T>
+struct DefaultDeleter<T[]> {
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
+    delete[] ptr;
+  }
+
+ private:
+  // Disable this operator for any U != T because it is undefined to execute
+  // an array delete when the static type of the array mismatches the dynamic
+  // type.
+  //
+  // References:
+  //   C++98 [expr.delete]p3
+  //   http://cplusplus.github.com/LWG/lwg-defects.html#938
+  template <typename U>
+  void operator()(U* array) const;
+};
+
+template <class T, int n>
+struct DefaultDeleter<T[n]> {
+  // Never allow someone to declare something like unique_ptr<int[10]>.
+  static_assert(sizeof(T) == -1, "do_not_use_array_with_size_as_type");
+};
+
+namespace internal {
+
 // Common implementation for both pointers to elements and pointers to
 // arrays. These are differentiated below based on the need to invoke
 // delete vs. delete[] as appropriate.
-template <class C>
+template <class C, class D>
 class unique_ptr_base {
  public:
-
   // The element type
   typedef C element_type;
 
-  explicit unique_ptr_base(C* p) : ptr_(p) { }
+  explicit unique_ptr_base(C* p) : data_(p) {}
+
+  // Initializer for deleters that have data parameters.
+  unique_ptr_base(C* p, const D& d) : data_(p, d) {}
 
   // Move constructor.
-  unique_ptr_base(unique_ptr_base<C>&& that) {
-    ptr_ = that.ptr_;
-    that.ptr_ = nullptr;
-  }
+  unique_ptr_base(unique_ptr_base<C, D>&& that)
+      : data_(that.release(), that.get_deleter()) {}
 
-  // Accessors to get the owned object.
-  // operator* and operator-> will assert() if there is no current object.
-  C& operator*() const {
-    assert(ptr_ != NULL);
-    return *ptr_;
+  ~unique_ptr_base() {
+    enum { type_must_be_complete = sizeof(C) };
+    if (data_.ptr != nullptr) {
+      // Not using get_deleter() saves one function call in non-optimized
+      // builds.
+      static_cast<D&>(data_)(data_.ptr);
+    }
   }
-  C* operator->() const  {
-    assert(ptr_ != NULL);
-    return ptr_;
+
+  void reset(C* p = nullptr) {
+    C* old = data_.ptr;
+    data_.ptr = p;
+    if (old != nullptr)
+      static_cast<D&>(data_)(old);
   }
-  C* get() const { return ptr_; }
+
+  C* get() const { return data_.ptr; }
+  D& get_deleter() { return data_; }
+  const D& get_deleter() const { return data_; }
 
   // Comparison operators.
   // These return whether two unique_ptr refer to the same object, not just to
   // two different but equal objects.
-  bool operator==(C* p) const { return ptr_ == p; }
-  bool operator!=(C* p) const { return ptr_ != p; }
+  bool operator==(C* p) const { return data_.ptr == p; }
+  bool operator!=(C* p) const { return data_.ptr != p; }
 
-  // Swap two scoped pointers.
+  // Swap two unique pointers.
   void swap(unique_ptr_base& p2) {
-    C* tmp = ptr_;
-    ptr_ = p2.ptr_;
-    p2.ptr_ = tmp;
+    Data tmp = data_;
+    data_ = p2.data_;
+    p2.data_ = tmp;
   }
 
   // Release a pointer.
@@ -131,125 +202,180 @@ class unique_ptr_base {
   // After this operation, this object will hold a NULL pointer,
   // and will not own the object any more.
   C* release() {
-    C* retVal = ptr_;
-    ptr_ = NULL;
-    return retVal;
+    C* ptr = data_.ptr;
+    data_.ptr = nullptr;
+    return ptr;
   }
 
   // Allow promotion to bool for conditional statements.
-  explicit operator bool() const { return ptr_ != NULL; }
+  explicit operator bool() const { return data_.ptr != nullptr; }
 
  protected:
-  C* ptr_;
+  // Use the empty base class optimization to allow us to have a D
+  // member, while avoiding any space overhead for it when D is an
+  // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
+  // discussion of this technique.
+  struct Data : public D {
+    explicit Data(C* ptr_in) : ptr(ptr_in) {}
+    Data(C* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
+    C* ptr;
+  };
+
+  Data data_;
 };
 
+}  // namespace internal
+
 // Implementation for ordinary pointers using delete.
-template <class C>
-class unique_ptr : public unique_ptr_base<C> {
+template <class C, class D = DefaultDeleter<C>>
+class unique_ptr : public internal::unique_ptr_base<C, D> {
  public:
-  using unique_ptr_base<C>::ptr_;
+  // Constructor.  Defaults to initializing with nullptr.
+  unique_ptr() : internal::unique_ptr_base<C, D>(nullptr) {}
 
-  // Constructor. Defaults to initializing with NULL. There is no way
-  // to create an uninitialized unique_ptr. The input parameter must be
-  // allocated with new (not new[] - see below).
-  explicit unique_ptr(C* p = NULL) : unique_ptr_base<C>(p) { }
+  // Constructor.  Takes ownership of p.
+  explicit unique_ptr(C* p) : internal::unique_ptr_base<C, D>(p) {}
 
-  // Move constructor.
-  unique_ptr(unique_ptr<C>&& that) : unique_ptr_base<C>(nonstd::move(that)) {}
+  // Constructor.  Allows initialization of a stateful deleter.
+  unique_ptr(C* p, const D& d) : internal::unique_ptr_base<C, D>(p, d) {}
 
-  // Destructor.  If there is a C object, delete it.
-  // We don't need to test ptr_ == NULL because C++ does that for us.
-  ~unique_ptr() {
-    enum { type_must_be_complete = sizeof(C) };
-    delete ptr_;
-  }
+  // Constructor.  Allows construction from a nullptr.
+  unique_ptr(decltype(nullptr)) : internal::unique_ptr_base<C, D>(nullptr) {}
 
-  // Reset.  Deletes the current owned object, if any.
-  // Then takes ownership of a new object, if given.
-  // this->reset(this->get()) works.
-  void reset(C* p = NULL) {
-    if (p != ptr_) {
-      enum { type_must_be_complete = sizeof(C) };
-      C* old_ptr = ptr_;
-      ptr_ = p;
-      delete old_ptr;
-    }
+  // Move constructor.
+  unique_ptr(unique_ptr&& that)
+      : internal::unique_ptr_base<C, D>(nonstd::move(that)) {}
+
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // object, if any.
+  unique_ptr& operator=(decltype(nullptr)) {
+    this->reset();
+    return *this;
   }
 
   // Move assignment.
   unique_ptr<C>& operator=(unique_ptr<C>&& that) {
-    if (that.ptr_ != ptr_)
-      reset(that.release());
+    this->reset(that.release());
     return *this;
   }
 
-private:
-  // Forbid comparison of unique_ptr types.  If C2 != C, it totally doesn't
-  // make sense, and if C2 == C, it still doesn't make sense because you should
-  // never have the same object owned by two different unique_ptrs.
-  template <class C2> bool operator==(unique_ptr<C2> const& p2) const;
-  template <class C2> bool operator!=(unique_ptr<C2> const& p2) const;
+  // Accessors to get the owned object.
+  // operator* and operator-> will assert() if there is no current object.
+  C& operator*() const {
+    assert(this->data_.ptr != nullptr);
+    return *this->data_.ptr;
+  }
+  C* operator->() const {
+    assert(this->data_.ptr != nullptr);
+    return this->data_.ptr;
+  }
+
+  // Comparison operators.
+  // These return whether two unique_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(const C* p) const { return this->get() == p; }
+  bool operator!=(const C* p) const { return this->get() != p; }
 
+ private:
   // Disallow evil constructors. It doesn't make sense to make a copy of
   // something that's allegedly unique.
   unique_ptr(const unique_ptr&) = delete;
   void operator=(const unique_ptr&) = delete;
+
+  // Forbid comparison of unique_ptr types.  If U != C, it totally
+  // doesn't make sense, and if U == C, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // unique_ptrs.
+  template <class U>
+  bool operator==(unique_ptr<U> const& p2) const;
+  template <class U>
+  bool operator!=(unique_ptr<U> const& p2) const;
 };
 
 // Specialization for arrays using delete[].
-template <class C>
-class unique_ptr<C[]> : public unique_ptr_base<C> {
+template <class C, class D>
+class unique_ptr<C[], D> : public internal::unique_ptr_base<C, D> {
  public:
-  using unique_ptr_base<C>::ptr_;
-
-  // Constructor. Defaults to initializing with NULL. There is no way
-  // to create an uninitialized unique_ptr. The input parameter must be
-  // allocated with new[] (not new - see above).
-  explicit unique_ptr(C* p = NULL) : unique_ptr_base<C>(p) { }
+  // Constructor.  Defaults to initializing with nullptr.
+  unique_ptr() : internal::unique_ptr_base<C, D>(nullptr) {}
+
+  // Constructor. Stores the given array. Note that the argument's type
+  // must exactly match T*. In particular:
+  // - it cannot be a pointer to a type derived from T, because it is
+  //   inherently unsafe in the general case to access an array through a
+  //   pointer whose dynamic type does not match its static type (eg., if
+  //   T and the derived types had different sizes access would be
+  //   incorrectly calculated). Deletion is also always undefined
+  //   (C++98 [expr.delete]p3). If you're doing this, fix your code.
+  // - it cannot be const-qualified differently from T per unique_ptr spec
+  //   (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
+  //   to work around this may use const_cast<const T*>().
+  explicit unique_ptr(C* p) : internal::unique_ptr_base<C, D>(p) {}
+
+  // Constructor.  Allows construction from a nullptr.
+  unique_ptr(decltype(nullptr)) : internal::unique_ptr_base<C, D>(nullptr) {}
 
   // Move constructor.
-  unique_ptr(unique_ptr<C>&& that) : unique_ptr_base<C>(nonstd::move(that)) {}
+  unique_ptr(unique_ptr&& that)
+      : internal::unique_ptr_base<C, D>(nonstd::move(that)) {}
 
-  // Destructor.  If there is a C object, delete it.
-  // We don't need to test ptr_ == NULL because C++ does that for us.
-  ~unique_ptr() {
-    enum { type_must_be_complete = sizeof(C) };
-    delete[] ptr_;
-  }
-
-  // Reset.  Deletes the current owned object, if any.
-  // Then takes ownership of a new object, if given.
-  // this->reset(this->get()) works.
-  void reset(C* p = NULL) {
-    if (p != ptr_) {
-      enum { type_must_be_complete = sizeof(C) };
-      C* old_ptr = ptr_;
-      ptr_ = p;
-      delete[] old_ptr;
-    }
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // array, if any.
+  unique_ptr& operator=(decltype(nullptr)) {
+    this->reset();
+    return *this;
   }
 
   // Move assignment.
   unique_ptr<C>& operator=(unique_ptr<C>&& that) {
-    if (that.ptr_ != ptr_)
-      reset(that.release());
+    this->reset(that.release());
     return *this;
   }
 
+  // Reset.  Deletes the currently owned array, if any.
+  // Then takes ownership of a new object, if given.
+  void reset(C* array = nullptr) {
+    static_cast<internal::unique_ptr_base<C, D>*>(this)->reset(array);
+  }
+
   // Support indexing since it is holding array.
-  C& operator[] (size_t i) { return ptr_[i]; }
+  C& operator[](size_t i) { return this->data_.ptr[i]; }
 
-private:
-  // Forbid comparison of unique_ptr types.  If C2 != C, it totally doesn't
-  // make sense, and if C2 == C, it still doesn't make sense because you should
-  // never have the same object owned by two different unique_ptrs.
-  template <class C2> bool operator==(unique_ptr<C2> const& p2) const;
-  template <class C2> bool operator!=(unique_ptr<C2> const& p2) const;
+  // Comparison operators.
+  // These return whether two unique_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(C* array) const { return this->get() == array; }
+  bool operator!=(C* array) const { return this->get() != array; }
+
+ private:
+  // Disable initialization from any type other than element_type*, by
+  // providing a constructor that matches such an initialization, but is
+  // private and has no definition. This is disabled because it is not safe to
+  // call delete[] on an array whose static type does not match its dynamic
+  // type.
+  template <typename U>
+  explicit unique_ptr(U* array);
+  explicit unique_ptr(int disallow_construction_from_null);
+
+  // Disable reset() from any type other than element_type*, for the same
+  // reasons as the constructor above.
+  template <typename U>
+  void reset(U* array);
+  void reset(int disallow_reset_from_null);
 
   // Disallow evil constructors.  It doesn't make sense to make a copy of
   // something that's allegedly unique.
   unique_ptr(const unique_ptr&) = delete;
   void operator=(const unique_ptr&) = delete;
+
+  // Forbid comparison of unique_ptr types.  If U != C, it totally
+  // doesn't make sense, and if U == C, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // unique_ptrs.
+  template <class U>
+  bool operator==(unique_ptr<U> const& p2) const;
+  template <class U>
+  bool operator!=(unique_ptr<U> const& p2) const;
 };
 
 // Free functions
@@ -268,6 +394,11 @@ bool operator!=(C* p1, const unique_ptr<C>& p2) {
   return p1 != p2.get();
 }
 
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const unique_ptr<T>& p) {
+  return out << p.get();
+}
+
 }  // namespace nonstd
 
 #endif  // NONSTD_UNIQUE_PTR_H_
index 49cc901..2b12058 100644 (file)
@@ -85,3 +85,306 @@ TEST(UniquePtrTest, MoveTest) {
   }
   EXPECT_EQ(0, constructed);
 }
+
+TEST(UniquePtrTest, UniquePtr) {
+  int constructed = 0;
+
+  // Ensure size of unique_ptr<> doesn't increase unexpectedly.
+  static_assert(sizeof(int*) >= sizeof(unique_ptr<int>),
+                "unique_ptr_larger_than_raw_ptr");
+
+  {
+    unique_ptr<CtorDtorLogger> scoper(new CtorDtorLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    EXPECT_EQ(10, scoper->SomeMeth(10));
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    unique_ptr<CtorDtorLogger> scoper(new CtorDtorLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset(new CtorDtorLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new CtorDtorLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    CtorDtorLogger* take = scoper.release();
+    EXPECT_EQ(1, constructed);
+    EXPECT_FALSE(scoper.get());
+    delete take;
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new CtorDtorLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), == and !=
+  {
+    unique_ptr<CtorDtorLogger> scoper1;
+    unique_ptr<CtorDtorLogger> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    CtorDtorLogger* logger = new CtorDtorLogger(&constructed);
+    scoper1.reset(logger);
+    EXPECT_EQ(logger, scoper1.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(logger, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(UniquePtrTest, UniquePtrWithArray) {
+  static const int kNumLoggers = 12;
+
+  int constructed = 0;
+
+  {
+    unique_ptr<CtorDtorLogger[]> scoper(new CtorDtorLogger[kNumLoggers]);
+    EXPECT_TRUE(scoper);
+    EXPECT_EQ(&scoper[0], scoper.get());
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, scoper[2].SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    unique_ptr<CtorDtorLogger[]> scoper;
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper.release());
+    EXPECT_FALSE(scoper.get());
+    scoper.reset();
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new CtorDtorLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new CtorDtorLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    CtorDtorLogger* ptr = scoper.release();
+    EXPECT_EQ(12, constructed);
+    delete[] ptr;
+    EXPECT_EQ(0, constructed);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), ==, !=, and type-safe Boolean.
+  {
+    unique_ptr<CtorDtorLogger[]> scoper1;
+    unique_ptr<CtorDtorLogger[]> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    CtorDtorLogger* loggers = new CtorDtorLogger[kNumLoggers];
+    for (int i = 0; i < kNumLoggers; ++i) {
+      loggers[i].SetPtr(&constructed);
+    }
+    scoper1.reset(loggers);
+    EXPECT_TRUE(scoper1);
+    EXPECT_EQ(loggers, scoper1.get());
+    EXPECT_FALSE(scoper2);
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(loggers, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(UniquePtrTest, ReturnTypeBehavior) {
+  int constructed = 0;
+
+  // Test that we can return a unique_ptr.
+  {
+    CtorDtorLogger* logger = new CtorDtorLogger(&constructed);
+    unique_ptr<CtorDtorLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test uncaught return type not leak.
+  {
+    CtorDtorLogger* logger = new CtorDtorLogger(&constructed);
+    unique_ptr<CtorDtorLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Call TestReturnOfType() so the compiler doesn't warn for an unused
+  // function.
+  { TestReturnOfType(&constructed); }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(UniquePtrTest, CustomDeleter) {
+  double dummy_value;  // Custom deleter never touches this value.
+  int deletes = 0;
+  int alternate_deletes = 0;
+
+  // Normal delete support.
+  {
+    deletes = 0;
+    unique_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    EXPECT_EQ(0, deletes);
+    EXPECT_TRUE(scoper.get());
+  }
+  EXPECT_EQ(1, deletes);
+
+  // Test reset() and release().
+  deletes = 0;
+  {
+    unique_ptr<double, CountingDeleter> scoper(nullptr,
+                                               CountingDeleter(&deletes));
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper.release());
+    EXPECT_FALSE(scoper.get());
+    scoper.reset();
+    EXPECT_FALSE(scoper.get());
+    EXPECT_EQ(0, deletes);
+
+    scoper.reset(&dummy_value);
+    scoper.reset();
+    EXPECT_EQ(1, deletes);
+
+    scoper.reset(&dummy_value);
+    EXPECT_EQ(&dummy_value, scoper.release());
+  }
+  EXPECT_EQ(1, deletes);
+
+  // Test get_deleter().
+  deletes = 0;
+  alternate_deletes = 0;
+  {
+    unique_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    // Call deleter manually.
+    EXPECT_EQ(0, deletes);
+    scoper.get_deleter()(&dummy_value);
+    EXPECT_EQ(1, deletes);
+
+    // Deleter is still there after reset.
+    scoper.reset();
+    EXPECT_EQ(2, deletes);
+    scoper.get_deleter()(&dummy_value);
+    EXPECT_EQ(3, deletes);
+
+    // Deleter can be assigned into (matches C++11 unique_ptr<> spec).
+    scoper.get_deleter() = CountingDeleter(&alternate_deletes);
+    scoper.reset(&dummy_value);
+    EXPECT_EQ(0, alternate_deletes);
+  }
+  EXPECT_EQ(3, deletes);
+  EXPECT_EQ(1, alternate_deletes);
+
+  // Test swap(), ==, !=, and type-safe Boolean.
+  {
+    unique_ptr<double, CountingDeleter> scoper1(nullptr,
+                                                CountingDeleter(&deletes));
+    unique_ptr<double, CountingDeleter> scoper2(nullptr,
+                                                CountingDeleter(&deletes));
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    scoper1.reset(&dummy_value);
+    EXPECT_TRUE(scoper1);
+    EXPECT_EQ(&dummy_value, scoper1.get());
+    EXPECT_FALSE(scoper2);
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(&dummy_value, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+}
+
+unique_ptr<int> NullIntReturn() {
+  return nullptr;
+}
+
+TEST(UniquePtrTest, Nullptr) {
+  unique_ptr<int> scoper1(nullptr);
+  unique_ptr<int> scoper2(new int);
+  scoper2 = nullptr;
+  unique_ptr<int> scoper3(NullIntReturn());
+  unique_ptr<int> scoper4 = NullIntReturn();
+  EXPECT_EQ(nullptr, scoper1.get());
+  EXPECT_EQ(nullptr, scoper2.get());
+  EXPECT_EQ(nullptr, scoper3.get());
+  EXPECT_EQ(nullptr, scoper4.get());
+}
+
+unique_ptr<int[]> NullIntArrayReturn() {
+  return nullptr;
+}
+
+TEST(UniquePtrTest, NullptrArray) {
+  unique_ptr<int[]> scoper1(nullptr);
+  unique_ptr<int[]> scoper2(new int[3]);
+  scoper2 = nullptr;
+  unique_ptr<int[]> scoper3(NullIntArrayReturn());
+  unique_ptr<int[]> scoper4 = NullIntArrayReturn();
+  EXPECT_EQ(nullptr, scoper1.get());
+  EXPECT_EQ(nullptr, scoper2.get());
+  EXPECT_EQ(nullptr, scoper3.get());
+  EXPECT_EQ(nullptr, scoper4.get());
+}
+
+// Logging a unique_ptr<T> to an ostream shouldn't convert it to a boolean
+// value first.
+TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
+  unique_ptr<int> x(new int);
+  std::stringstream s1;
+  s1 << x;
+
+  std::stringstream s2;
+  s2 << x.get();
+
+  EXPECT_EQ(s2.str(), s1.str());
+}
index ab66094..719f3f1 100644 (file)
@@ -21,7 +21,8 @@ typedef integral_constant<bool, true> true_type;
 typedef integral_constant<bool, false> false_type;
 
 template <class T, class U> struct is_same : public false_type {};
-template <class T> struct is_same<T,T> : true_type {};
+template <class T>
+struct is_same<T, T> : true_type {};
 
 template<bool B, class T = void>
 struct enable_if {};
@@ -29,6 +30,49 @@ struct enable_if {};
 template<class T>
 struct enable_if<true, T> { typedef T type; };
 
+namespace internal {
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+  YesType dummy[2];
+};
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From.  See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+struct ConvertHelper {
+  template <typename To>
+  static YesType Test(To);
+
+  template <typename To>
+  static NoType Test(...);
+
+  template <typename From>
+  static From& Create();
+};
+
+}  // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+//
+// Note that if the type is convertible, this will be a true_type REGARDLESS
+// of whether or not the conversion would emit a warning.
+template <typename From, typename To>
+struct is_convertible
+    : integral_constant<bool,
+                        sizeof(internal::ConvertHelper::Test<To>(
+                            internal::ConvertHelper::Create<From>())) ==
+                            sizeof(internal::YesType)> {};
+
 }  // namespace base
 }  // namespace pdfium