trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bc...@apache.org
Subject [trafficserver] 02/03: tsconfig/IntrusivePtr refresh - updated for eleventy and better conformance with std::shared_ptr.
Date Wed, 06 Jun 2018 20:22:11 GMT
This is an automated email from the ASF dual-hosted git repository.

bcall pushed a commit to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 71440695e0ab638389afeed48c125521e513232e
Author: Alan M. Carroll <amc@apache.org>
AuthorDate: Wed May 30 12:52:50 2018 -0500

    tsconfig/IntrusivePtr refresh - updated for eleventy and better conformance with std::shared_ptr.
    
    (cherry picked from commit 40f01aa0c4fb2ab72459dcc16d63989f40bb8b9b)
---
 CMakeLists.txt                         |   1 +
 lib/ts/Makefile.am                     |   1 +
 lib/ts/unit-tests/test_IntrusivePtr.cc | 134 ++++++++++
 lib/tsconfig/Errata.cc                 |  15 +-
 lib/tsconfig/IntrusivePtr.h            | 464 +++++++++++++++------------------
 lib/tsconfig/TsValue.cc                |  12 +-
 lib/tsconfig/TsValue.h                 |   4 +-
 lib/wccp/WccpEndPoint.cc               |   4 +-
 8 files changed, 364 insertions(+), 271 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1191842..edcf8d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1309,6 +1309,7 @@ add_executable(test_tslib
 	lib/ts/unit-tests/test_BufferWriter.cc
 	lib/ts/unit-tests/test_BufferWriterFormat.cc
 	lib/ts/unit-tests/test_ink_inet.cc
+	lib/ts/unit-tests/test_IntrusivePtr.cc
 	lib/ts/unit-tests/test_IpMap.cc
 	lib/ts/unit-tests/test_layout.cc
 	lib/ts/unit-tests/test_MemArena.cc
diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am
index fead563..f87b7b1 100644
--- a/lib/ts/Makefile.am
+++ b/lib/ts/Makefile.am
@@ -267,6 +267,7 @@ test_tslib_SOURCES = \
 	unit-tests/test_BufferWriter.cc \
 	unit-tests/test_BufferWriterFormat.cc \
 	unit-tests/test_ink_inet.cc \
+	unit-tests/test_IntrusivePtr.cc \
 	unit-tests/test_IpMap.cc \
 	unit-tests/test_layout.cc \
 	unit-tests/test_MemSpan.cc \
diff --git a/lib/ts/unit-tests/test_IntrusivePtr.cc b/lib/ts/unit-tests/test_IntrusivePtr.cc
new file mode 100644
index 0000000..79c9350
--- /dev/null
+++ b/lib/ts/unit-tests/test_IntrusivePtr.cc
@@ -0,0 +1,134 @@
+/** @file
+
+    IntrusivePtr tests.
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+*/
+
+#include <string>
+#include <sstream>
+#include <tsconfig/IntrusivePtr.h>
+#include <catch.hpp>
+
+struct Thing : public ts::IntrusivePtrCounter {
+  Thing() { ++_count; }
+  ~Thing() { --_count; }
+  std::string _name;
+  static int _count; // instance count.
+};
+
+struct Stuff : public Thing {
+  int _value{0};
+};
+
+struct Obscure : private ts::IntrusivePtrCounter {
+  std::string _text;
+
+  friend class ts::IntrusivePtr<Obscure>;
+};
+
+struct Atomic : ts::IntrusivePtrAtomicCounter {
+  int _q{0};
+};
+
+int Thing::_count{0};
+
+TEST_CASE("IntrusivePtr", "[libts][IntrusivePtr]")
+{
+  using Ptr = ts::IntrusivePtr<Thing>;
+
+  Ptr p1{new Thing};
+  REQUIRE(p1.use_count() == 1);
+  REQUIRE(Thing::_count == 1);
+  p1.reset(nullptr);
+  REQUIRE(Thing::_count == 0);
+
+  p1.reset(new Thing);
+  Ptr p2 = p1;
+  REQUIRE(Thing::_count == 1);
+  REQUIRE(p1.use_count() == p2.use_count());
+  REQUIRE(p2.use_count() == 2);
+
+  Ptr p3{new Thing};
+  REQUIRE(Thing::_count == 2);
+  p1 = p3;
+  p2 = p3;
+  REQUIRE(Thing::_count == 1);
+
+  Ptr p4;
+
+  REQUIRE(static_cast<bool>(p4) == false);
+  REQUIRE(!p4 == true);
+
+  REQUIRE(static_cast<bool>(p3) == true);
+  REQUIRE(!p3 == false);
+
+  // This is a compile check to make sure IntrusivePtr can be used with private inheritance
+  // of ts::InstrusivePtrCounter if IntrusivePtr is declared a friend.
+  ts::IntrusivePtr<Obscure> op{new Obscure};
+  op->_text.assign("Text");
+}
+
+// Cross type tests.
+TEST_CASE("IntrusivePtr CrossType", "[libts][IntrusivePtr]")
+{
+  using ThingPtr = ts::IntrusivePtr<Thing>;
+  using StuffPtr = ts::IntrusivePtr<Stuff>;
+
+  ThingPtr tp1{new Stuff};
+  StuffPtr sp1{new Stuff};
+
+  ThingPtr tp2{sp1};
+  REQUIRE(tp2.get() == sp1.get());
+  REQUIRE(Thing::_count == 2);
+  REQUIRE(tp2.use_count() == 2);
+  tp2 = sp1; // should be a no-op, verify it compiles.
+  REQUIRE(tp2.get() == sp1.get());
+  REQUIRE(Thing::_count == 2);
+  REQUIRE(sp1.use_count() == 2);
+  sp1 = ts::ptr_cast<Stuff>(tp1); // move assign
+  REQUIRE(sp1.get() == tp1.get());
+  REQUIRE(sp1.use_count() == 2);
+  REQUIRE(tp2.use_count() == 1);
+  tp1 = ts::ptr_cast<Stuff>(tp2); // cross type move assign
+  REQUIRE(sp1.use_count() == 1);
+  REQUIRE(tp1.get() == tp2.get());
+  REQUIRE(tp1.use_count() == 2);
+  sp1 = ts::ptr_cast<Stuff>(tp1);
+  REQUIRE(Thing::_count == 1);
+  REQUIRE(sp1.use_count() == 3);
+  tp1 = tp2; // same object assign check.
+  {
+    StuffPtr sp2{sp1};
+    REQUIRE(sp1.use_count() == 4);
+  }
+  sp1.reset();
+  tp1 = std::move(tp2); // should clear tp2
+  tp1.reset();
+  REQUIRE(Thing::_count == 0);
+}
+
+TEST_CASE("IntrusiveAtomicPtr", "[libts][IntrusivePtr]")
+{
+  using Ptr = ts::IntrusivePtr<Atomic>;
+
+  Ptr p1{new Atomic};
+  REQUIRE(p1.use_count() == 1);
+  p1.reset(nullptr);
+}
diff --git a/lib/tsconfig/Errata.cc b/lib/tsconfig/Errata.cc
index 14ab513..f91ca7f 100644
--- a/lib/tsconfig/Errata.cc
+++ b/lib/tsconfig/Errata.cc
@@ -69,9 +69,8 @@ inline Errata::Errata(ImpPtr const& ptr)
 
 Errata::Data::~Data() {
   if (m_log_on_delete) {
-    Errata tmp(this); // because client API requires a wrapper.
-    for ( auto& f : Sink_List ) { (*f)(tmp);
-}
+    Errata tmp(ImpPtr(this)); // because client API requires a wrapper.
+    for ( auto& f : Sink_List ) { (*f)(tmp); }
     tmp.m_data.release(); // don't delete this again.
   }
 }
@@ -102,11 +101,11 @@ Errata::~Errata() {
 Errata::Data*
 Errata::pre_write() {
   if (m_data) {
-    if (m_data.useCount() > 1) {
-      m_data = new Data(*m_data); // clone current data
+    if (m_data.use_count() > 1) {
+      m_data.reset(new Data(*m_data)); // clone current data
     }
   } else { // create new data
-    m_data = new Data;
+    m_data.reset(new Data);
   }
   return m_data.get();
 }
@@ -114,7 +113,7 @@ Errata::pre_write() {
 // Just create an instance if needed.
 Errata::Data const*
 Errata::instance() {
-  if (!m_data) { m_data = new Data;
+  if (!m_data) { m_data.reset(new Data);
 }
   return m_data.get();
 }
@@ -140,7 +139,7 @@ Errata::operator=(self const& that) {
 Errata&
 Errata::operator = (Message const& msg) {
   // Avoid copy on write in the case where we discard.
-  if (!m_data || m_data.useCount() > 1) {
+  if (!m_data || m_data.use_count() > 1) {
     this->clear();
     this->push(msg);
   } else {
diff --git a/lib/tsconfig/IntrusivePtr.h b/lib/tsconfig/IntrusivePtr.h
index 1db5054..93be87b 100644
--- a/lib/tsconfig/IntrusivePtr.h
+++ b/lib/tsconfig/IntrusivePtr.h
@@ -1,193 +1,184 @@
-#if !defined(TS_INTRUSIVE_PTR_HEADER)
-#define TS_INTRUSIVE_PTR_HEADER
-
 /** @file
 
-    This is a simple shared pointer class for restricted use. It is not a
-    completely general class. The most significant missing feature is the
-    lack of thread safety. For its intended use, this is acceptable and
-    provides a performance improvement. However, it does restrict how the
-    class may be used.
+    This is an intrusive shared pointer class designed for internal use in various containers
inside
+    Traffic Server. It is not dependent on TS and could be used elsewhere. The design tries
to
+    follow that of @c std::shared_ptr as it performs a similar function. The key difference
is
+    this shared pointer requires the reference count to be in the target class. This is done
by
+    inheriting a class containing the counter. This has the benefits
+
+    - improved locality for instances of the class and the reference count
+    - the ability to reliably construct shared pointers from raw pointers.
+    - lower overhead (a single reference counter).
 
-    This style of shared pointer also requires explicit support from the
-    target class, which must provide an internal reference counter.
+    The requirement of modifying the target class limits the generality of this class but
it is
+    still quite useful in specific cases (particularly containers and their internal node
classes).
 
     @section license License
 
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you 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
+    Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+    agreements.  See the NOTICE file distributed with this work for additional information
regarding
+    copyright ownership.  The ASF licenses this file to you 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
+    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.
  */
 
+#pragma once
+
 #include <sys/types.h>
+#include <type_traits>
 #include <cassert>
 #include <functional>
+#include <atomic>
 
 namespace ts
 {
-class IntrusivePtrCounter;
-
-/** This class exists solely to be declared a friend of @c IntrusivePtrCounter.
 
-    @internal This is done because we can't declare the template a
-    friend, so rather than burden the client with the declaration we
-    do it here. It provides a single method that allows the smart pointer
-    to get access to the protected reference count.
-
- */
-class IntrusivePtrBase
-{
-public:
-  /// Type used for reference counter.
-  typedef long Counter;
+template < typename T > class IntrusivePtr; // forward declare
 
-protected:
-  Counter *getCounter(IntrusivePtrCounter *c ///< Cast object with reference counter.
-                      ) const;
-};
-/* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 /** Reference counter mixin.
 
-    To add support for @c IntrusivePtr to class @a T, it
-    should inherit from @c IntrusivePtrCounter<T> in order to
-
-    - provide a reference count member
-    - force the reference count to initialize to zero
-    - define the add and release global functions required by @c IntrusivePtr
-
-    In general this class should be inherited publicly. This will
-    provide methods which mimic the @c Boost.shared_ptr interface ( @c
-    unique() , @c use_count() ).
-
-    If this class is not inherited publically or the destructor is
-    non-public then the host class (@a T) must declare this class ( @c
-    reference_counter<T> ) as a friend.
+    To add support for @c IntrusivePtr to class @a T, it must publicly inherit
+    @c IntrusivePtrCounter. Doing so
 
-    @internal Due to changes in the C++ standard and design decisions
-    in gcc, it is no longer possible to declare a template parameter
-    as a friend class.  (Basically, you can't use a typedef in a
-    friend declaration and gcc treats template parameters as
-    typedefs).
+    - provides a reference count member
+    - forces the reference count to initialize to zero
+    - prevents reference count copying on copy construction or assignment
+    - provides access to the reference counter from the shared pointer
+    - provides the `use_count` method to check the reference count.
 
-    @note You can use this with insulated (by name only) classes. The
-    important thing is to make sure that any such class that uses @c
-    IntrusivePtr has all of its constructors and destructors declared
-    in the header and defined in the implementation translation
-    unit. If the compiler generates any of those, it will not compile
-    due to missing functions or methods
+    @note You can use this with insulated (by name only) classes. The important thing is
to make
+    sure that any such class that uses @c IntrusivePtr has all of its constructors and destructors
+    declared in the header and defined in the implementation translation unit. If the compiler
+    generates any of those, it will not compile due to missing functions or methods
 
   */
 class IntrusivePtrCounter
 {
-  friend class IntrusivePtrBase;
+  template < typename T > friend class IntrusivePtr;
 
+  using self_type = IntrusivePtrCounter;
 public:
   /** Copy constructor.
 
-      @internal We have to define this to explicitly _not_ copy the
-      reference count. Otherwise any client that uses a default copy
-      constructor will _copy the ref count into the new object_. That
-      way lies madness.
+      @internal We have to define this to explicitly _not_ copy the reference count. Otherwise
any
+      client that uses a default copy constructor will _copy the ref count into the new object_.
+      That way lies madness.
   */
-
-  IntrusivePtrCounter(IntrusivePtrCounter const & ///< Source object.
-                      );
+  IntrusivePtrCounter(self_type const & that);
+  /// No move constructor - that won't work for an object that is the target of a shared
pointer.
+  IntrusivePtrCounter(self_type && that) = delete;
 
   /** Assignment operator.
 
-      @internal We need this for the same reason as the copy
-      constructor. The reference counter must not participate in
-      assignment.
+      @internal We need this for the same reason as the copy constructor. The reference count
must
+      not be copied.
    */
-  IntrusivePtrCounter &operator=(IntrusivePtrCounter const &);
+  self_type &operator=(self_type const &that);
+  /// No move assignment - that won't work for an object that is the target of a shared pointer.
+  self_type &operator=(self_type &&that) = delete;
 
 protected:
-  IntrusivePtrBase::Counter m_intrusive_pointer_reference_count;
+  /// The reference counter type is signed because detecting underflow is more important
than having
+  /// more than 2G references.
+  using intrusive_ptr_reference_counter_type = long int;
+  /// The reference counter.
+  intrusive_ptr_reference_counter_type m_intrusive_pointer_reference_count{0};
   /// Default constructor (0 init counter).
   /// @internal Only subclasses can access this.
   IntrusivePtrCounter();
 };
+
+/** Atomic reference counting mixin.
+ */
+class IntrusivePtrAtomicCounter
+{
+  template < typename T > friend class IntrusivePtr;
+
+  using self_type = IntrusivePtrAtomicCounter;
+
+public:
+  IntrusivePtrAtomicCounter(self_type const & that);
+  /// No move constructor - that won't work for an object that is the target of a shared
pointer.
+  IntrusivePtrAtomicCounter(self_type && that) = delete;
+
+  self_type &operator=(self_type const &that);
+  /// No move assignment - that won't work for an object that is the target of a shared pointer.
+  self_type &operator=(self_type &&that) = delete;
+
+protected:
+  /// The reference counter type is signed because detecting underflow is more important
than having
+  /// more than 2G references.
+  using intrusive_ptr_reference_counter_type = std::atomic<long int>;
+  /// The reference counter.
+  intrusive_ptr_reference_counter_type m_intrusive_pointer_reference_count{0};
+  /// Default constructor (0 init counter).
+  /// @internal Only subclasses can access this.
+  IntrusivePtrAtomicCounter();
+};
+
 /* ----------------------------------------------------------------------- */
-/* ----------------------------------------------------------------------- */
-/** Shared pointer.
+/** Intrusive shared pointer.
 
-    This is a reference counted smart pointer. A single object is jointly
-    ownded by a set of pointers. When the last of the pointers is destructed
-    the target object is also destructed.
+    This is a reference counted smart pointer. A single object is jointly ownded by a set
of
+    pointers. When the last of the pointers is destructed the target object is also destructed.
 
-    The smart pointer actions can be changed through class specific policy
-    by specializing the @c IntrusivePtrPolicy template class.
+    The smart pointer actions can be changed through class specific policy by specializing
the @c
+    IntrusivePtrPolicy template class.
 */
-template <typename T> class IntrusivePtr : private IntrusivePtrBase
+template <typename T> class IntrusivePtr
 {
 private:                          /* don't pollute client with these typedefs */
-  typedef IntrusivePtrBase super; ///< Parent type.
-  typedef IntrusivePtr self;      ///< Self reference type.
-
+  using self_type = IntrusivePtr;      ///< Self reference type.
+  template < typename U > friend class IntrusivePtr; /// Make friends wih our clones.
 public:
-  /// Promote type for reference counter.
-  typedef super::Counter Counter;
+  /// The underlying (integral) type of the reference counter.
+  using count_type = long int;
 
-  /// Default constructor (0 initialized).
+  /// Default constructor (nullptr initialized).
   IntrusivePtr();
   /// Construct from instance.
   /// The instance becomes referenced and owned by the pointer.
-  IntrusivePtr(T *obj);
+  explicit IntrusivePtr(T *obj);
   /// Destructor.
   ~IntrusivePtr();
 
-  /// Copy constructor.
-  IntrusivePtr(const self &src);
-  /// Self assignement.
-  self &operator=(const self &src);
-  /** Assign from instance.
-      The instance becomes referenced and owned by the pointer.
-      The reference to the current object is dropped.
-  */
-  self &operator=(T *obj ///< Target instance.
-                  );
+  /// Copy constructor
+  IntrusivePtr(self_type const& that);
+  /// Move constructor.
+  IntrusivePtr(self_type && that);
+  /// Self assignment.
+  self_type& operator=(self_type const& that);
+  /// Move assignment.
+  self_type& operator=(self_type && that);
 
   /** Assign from instance.
       The instance becomes referenced and owned by the pointer.
       The reference to the current object is dropped.
-      @note A synonym for @c operator= for compatibility.
   */
-  self &assign(T *obj ///< Target instance.
-               );
+  void reset(T *obj = nullptr);
 
-  /** Assign from instance.
-      The instance becomes referenced and owned by the pointer.
-      The reference to the current object is dropped.
-  */
-  void reset(T *obj);
   /** Clear reference without cleanup.
 
-      This unsets this smart pointer and decrements the reference
-      count, but does @b not perform any finalization on the
-      target object. This can easily lead to memory leaks and
-      in some sense vitiates the point of this class, but it is
-      occasionally the right thing to do. Use with caution.
+      This unsets this smart pointer and decrements the reference count, but does @b not
perform any
+      finalization on the target object. This can easily lead to memory leaks and in some
sense
+      vitiates the point of this class, but it is occasionally the right thing to do. Use
with
+      caution.
 
       @return @c true if there are no references upon return,
       @c false if the reference count is not zero.
    */
-  bool release();
+  T* release();
 
-  /// Test if the pointer is zero (@c NULL).
-  bool isNull() const;
+  /// Test for not @c nullptr
+  explicit operator bool() const;
 
   /// Member dereference.
   T *operator->() const;
@@ -198,53 +189,41 @@ public:
 
   /** User conversion to raw pointer.
 
-      @internal allow implicit conversion to the underlying
-      pointer. This allows for the form "if (handle)" and is not
-      particularly dangerous (as it would be for a scope_ptr or
-      std::shared_ptr) because the counter is carried with the object and
-      so can't get lost or duplicated.
+      @internal allow implicit conversion to the underlying pointer which is one of the advantages
+      of intrusive pointers because the reference count doesn't get lost.
 
   */
   operator T *() const;
 
   /** Cross type construction.
-      This succeeds if an @a X* can be implicitly converted to a @a T*.
+      This succeeds if an @a U* can be implicitly converted to a @a T*.
   */
-  template <typename X ///< Foreign pointer type.
-            >
-  IntrusivePtr(IntrusivePtr<X> const &that ///< Foreign pointer.
-               );
+  template <typename U>
+  IntrusivePtr(IntrusivePtr<U> const &that);
+
+  template <typename U>
+  IntrusivePtr(IntrusivePtr<U> && that);
 
   /** Cross type assignment.
-      This succeeds if an @a X* can be implicitily converted to a @a T*.
+      This succeeds if an @a U* can be implicitily converted to a @a T*.
   */
-  template <typename X ///< Foreign pointer type.
-            >
-  self &operator=(IntrusivePtr<X> const &that ///< Foreign pointer.
-                  );
-
-  /// Check for multiple references.
-  /// @return @c true if more than one smart pointer references the object,
-  /// @c false otherwise.
-  bool isShared() const;
-  /// Check for a single reference (@c std::shared_ptr compatibility)
-  /// @return @c true if this object is not shared.
-  bool unique() const;
+  template <typename U>
+  self_type &operator=(IntrusivePtr<U> const &that);
+
+  template <typename U>
+  self_type &operator=(IntrusivePtr<U> && that);
+
   /// Reference count.
   /// @return Number of references.
-  Counter useCount() const;
+  count_type use_count() const;
 
 private:
-  T *m_obj; ///< Pointer to object.
+  T *m_obj{nullptr}; ///< Pointer to object.
 
   /// Reference @a obj.
-  void set(T *obj ///< Target object.
-           );
+  void set(T *obj);
   /// Drop the current reference.
   void unset();
-
-  /// Get a pointer to the reference counter of the target object.
-  Counter *getCounter() const;
 };
 
 /** Pointer dynamic cast.
@@ -260,11 +239,9 @@ private:
     the_b = dynamic_ptr_cast<B>(really_b);
     @endcode
 */
-template <typename T, ///< Target type.
-          typename X  ///< Source type.
-          >
+template <typename T, typename U>
 IntrusivePtr<T>
-dynamic_ptr_cast(IntrusivePtr<X> const &src ///< Source pointer.
+dynamic_ptr_cast(IntrusivePtr<U> const &src ///< Source pointer.
                  )
 {
   return IntrusivePtr<T>(dynamic_cast<T *>(src.get()));
@@ -285,10 +262,10 @@ dynamic_ptr_cast(IntrusivePtr<X> const &src ///< Source
pointer.
     @endcode
 */
 template <typename T, ///< Target type.
-          typename X  ///< Source type.
+          typename U  ///< Source type.
           >
 IntrusivePtr<T>
-ptr_cast(IntrusivePtr<X> const &src ///< Source pointer.
+ptr_cast(IntrusivePtr<U> const &src ///< Source pointer.
          )
 {
   return IntrusivePtr<T>(static_cast<T *>(src.get()));
@@ -357,27 +334,29 @@ typedef IntrusivePtrPolicy<IntrusivePtrDefaultPolicyTag> IntrusivePtrDefaultPoli
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
 /* Inline Methods */
-inline IntrusivePtrCounter::IntrusivePtrCounter() : m_intrusive_pointer_reference_count(0)
-{
-}
+inline IntrusivePtrCounter::IntrusivePtrCounter() {}
 
-inline IntrusivePtrCounter::IntrusivePtrCounter(IntrusivePtrCounter const &) : m_intrusive_pointer_reference_count(0)
-{
-}
+inline IntrusivePtrCounter::IntrusivePtrCounter(self_type const &) {}
 
 inline IntrusivePtrCounter &
-IntrusivePtrCounter::operator=(IntrusivePtrCounter const &)
+IntrusivePtrCounter::operator=(self_type const &)
 {
   return *this;
 }
 
-inline IntrusivePtrBase::Counter *
-IntrusivePtrBase::getCounter(IntrusivePtrCounter *c) const
+inline IntrusivePtrAtomicCounter::IntrusivePtrAtomicCounter() {}
+
+inline IntrusivePtrAtomicCounter::IntrusivePtrAtomicCounter(self_type const &) {}
+
+inline IntrusivePtrAtomicCounter &
+IntrusivePtrAtomicCounter::operator=(self_type const &)
 {
-  return &(c->m_intrusive_pointer_reference_count);
+  return *this;
 }
+
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
+
 template <typename T>
 void
 IntrusivePtrPolicy<T>::dereferenceCheck(T *)
@@ -399,9 +378,7 @@ IntrusivePtrPolicy<T>::Order::operator()(IntrusivePtr<T> const
&lhs, IntrusivePt
 }
 /* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
-template <typename T> IntrusivePtr<T>::IntrusivePtr() : m_obj(nullptr)
-{
-}
+template <typename T> IntrusivePtr<T>::IntrusivePtr() {}
 
 template <typename T> IntrusivePtr<T>::IntrusivePtr(T *obj)
 {
@@ -413,50 +390,81 @@ template <typename T> IntrusivePtr<T>::~IntrusivePtr()
   this->unset();
 }
 
-template <typename T> IntrusivePtr<T>::IntrusivePtr(const self &that)
+template < typename T >
+IntrusivePtr<T>::IntrusivePtr(self_type const &that)
 {
   this->set(that.m_obj);
 }
 
 template <typename T>
-template <typename X>
-IntrusivePtr<T>::IntrusivePtr(IntrusivePtr<X> const &that ///< Foreign
pointer.
-                              )
-  : super(that.get())
+template <typename U>
+IntrusivePtr<T>::IntrusivePtr(IntrusivePtr<U> const &that)
 {
+  static_assert(std::is_convertible<U*, T*>::value, "The argument type is not implicitly
convertible to the return type.");
+  this->set(that.m_obj);
+}
+
+template < typename T >
+IntrusivePtr<T>::IntrusivePtr(self_type && that)
+{
+  std::swap<T*>(m_obj, that.m_obj);
 }
 
 template <typename T>
+template <typename U>
+IntrusivePtr<T>::IntrusivePtr(IntrusivePtr<U> && that)
+{
+  static_assert(std::is_convertible<U*, T*>::value, "The argument type is not implicitly
convertible to the return type.");
+  std::swap<T*>(m_obj, that.get());
+}
+
+template < typename T >
 IntrusivePtr<T> &
-IntrusivePtr<T>::operator=(const self &that)
+IntrusivePtr<T>::operator=(self_type const& that)
 {
-  this->reset(that.m_obj);
+  this->reset(that.get());
   return *this;
 }
 
+
 template <typename T>
-template <typename X>
+template <typename U>
 IntrusivePtr<T> &
-IntrusivePtr<T>::operator=(IntrusivePtr<X> const &that ///< Foreign pointer.
-                           )
+IntrusivePtr<T>::operator=(IntrusivePtr<U> const& that)
 {
+  static_assert(std::is_convertible<U*, T*>::value, "The argument type is not implicitly
convertible to the return type.");
   this->reset(that.get());
   return *this;
 }
 
-template <typename T>
+template < typename T >
 IntrusivePtr<T> &
-IntrusivePtr<T>::operator=(T *obj)
+IntrusivePtr<T>::operator=(self_type && that)
 {
-  this->reset(obj);
+  if (m_obj != that.m_obj) {
+    this->unset();
+    m_obj = that.m_obj;
+    that.m_obj = nullptr;
+  } else {
+    that.unset();
+  }
   return *this;
 }
 
 template <typename T>
+template <typename U>
 IntrusivePtr<T> &
-IntrusivePtr<T>::assign(T *obj)
+IntrusivePtr<T>::operator=(IntrusivePtr<U> && that)
 {
-  return *this = obj;
+  static_assert(std::is_convertible<U*, T*>::value, "The argument type is not implicitly
convertible to the return type.");
+  if (m_obj != that.m_obj) {
+    this->unset();
+    m_obj = that.m_obj;
+    that.m_obj = nullptr;
+  } else {
+    that.unset();
+  }
+  return *this;
 }
 
 template <typename T> T *IntrusivePtr<T>::operator->() const
@@ -479,21 +487,14 @@ IntrusivePtr<T>::get() const
   return m_obj;
 }
 
-template <typename T>
-typename IntrusivePtr<T>::Counter *
-IntrusivePtr<T>::getCounter() const
-{
-  return super::getCounter(static_cast<IntrusivePtrCounter *>(m_obj));
-}
-
 /* The Set/Unset methods are the basic implementation of our
  * reference counting. The Reset method is the standard way
  * of invoking the pair, although splitting them allows some
  * additional efficiency in certain situations.
  */
 
-/* set and unset are two half operations that don't do checks.
-   It is the callers responsibility to do that.
+/* @c set and @c unset are two half operations that don't do checks.
+   It is the caller's responsibility to do that.
 */
 
 template <typename T>
@@ -506,16 +507,16 @@ IntrusivePtr<T>::unset()
      * super class. We call the super class method to get a raw pointer
      * to the counter variable.
      */
-    Counter *cp = this->getCounter();
+    auto &cp = m_obj->m_intrusive_pointer_reference_count;
 
     /* If you hit this assert you've got a cycle of objects that
        reference each other. A delete in the cycle will eventually
        result in one of the objects getting deleted twice, which is
        what this assert indicates.
     */
-    assert(*cp);
+    assert(cp);
 
-    if (0 == --*cp) {
+    if (0 == --cp) {
       IntrusivePtrPolicy<T>::finalize(m_obj);
     }
     m_obj = nullptr;
@@ -528,7 +529,7 @@ IntrusivePtr<T>::set(T *obj)
 {
   m_obj = obj;    /* update to new object */
   if (nullptr != m_obj) /* if a real object, bump the ref count */
-    ++(*(this->getCounter()));
+    ++(m_obj->m_intrusive_pointer_reference_count);
 }
 
 template <typename T>
@@ -542,28 +543,25 @@ IntrusivePtr<T>::reset(T *obj)
 }
 
 template <typename T>
-bool
+T*
 IntrusivePtr<T>::release()
 {
-  bool zret = true;
+  T* zret = m_obj;
   if (m_obj) {
-    Counter *cp = this->getCounter();
-    zret        = *cp <= 1;
+    auto &cp = m_obj->m_intrusive_pointer_reference_count;
     // If the client is using this method, they're doing something funky
     // so be extra careful with the reference count.
-    if (*cp > 0)
-      --*cp;
+    if (cp > 0)
+      --cp;
     m_obj = nullptr;
   }
   return zret;
 }
 
-/* Simple method to check for invalid pointer */
 template <typename T>
-bool
-IntrusivePtr<T>::isNull() const
+IntrusivePtr<T>::operator bool() const
 {
-  return 0 == m_obj;
+  return m_obj != nullptr;
 }
 
 /* Pointer comparison */
@@ -588,63 +586,17 @@ operator<(IntrusivePtr<T> const &lhs, IntrusivePtr<T>
const &rhs)
   return lhs.get() < rhs.get();
 }
 
-template <typename T>
-bool
-operator==(IntrusivePtr<T> const &lhs, int rhs)
-{
-  assert(0 == rhs);
-  return lhs.get() == 0;
-}
-
-template <typename T>
-bool
-operator==(int lhs, IntrusivePtr<T> const &rhs)
-{
-  assert(0 == lhs);
-  return rhs.get() == nullptr;
-}
-
-template <typename T>
-bool
-operator!=(int lhs, IntrusivePtr<T> const &rhs)
-{
-  return !(lhs == rhs);
-}
-
-template <typename T>
-bool
-operator!=(IntrusivePtr<T> const &lhs, int rhs)
-{
-  return !(lhs == rhs);
-}
-
 template <typename T> IntrusivePtr<T>::operator T *() const
 {
   return m_obj;
 }
 
 template <typename T>
-bool
-IntrusivePtr<T>::isShared() const
+typename IntrusivePtr<T>::count_type
+IntrusivePtr<T>::use_count() const
 {
-  return m_obj && *(this->getCounter()) > 1;
+  return m_obj ? count_type{m_obj->m_intrusive_pointer_reference_count} : count_type{0};
 }
-
-template <typename T>
-bool
-IntrusivePtr<T>::unique() const
-{
-  return 0 == m_obj || *(this->getCounter()) <= 1;
-}
-
-template <typename T>
-typename IntrusivePtr<T>::Counter
-IntrusivePtr<T>::useCount() const
-{
-  return m_obj ? *(this->getCounter()) : 0;
-}
-/* ----------------------------------------------------------------------- */
 /* ----------------------------------------------------------------------- */
-} // namespace ats
 /* ----------------------------------------------------------------------- */
-#endif // TS_INTRUSIVE_PTR_HEADER
+} // namespace ts
diff --git a/lib/tsconfig/TsValue.cc b/lib/tsconfig/TsValue.cc
index 0aea522..de0298f 100644
--- a/lib/tsconfig/TsValue.cc
+++ b/lib/tsconfig/TsValue.cc
@@ -62,8 +62,13 @@ detail::ValueTableImpl::~ValueTableImpl() {
 // ---------------------------------------------------------------------------
 detail::ValueTable::ImplType*
 detail::ValueTable::instance() {
-  if (! _ptr) { _ptr.reset(new ImplType);
-}
+  // Stupid workaround for clang analyzer false positive. The new instance isn't leaked because
+  // it's stored in a shared ptr type.
+#if !defined(__clang_analyzer__)
+  if (! _ptr) { _ptr.reset(new ImplType); }
+#else
+  assert(_ptr.get() != nullptr);
+#endif
   return _ptr.get();
 }
 
@@ -229,7 +234,8 @@ Value::makePath(Path const& path, ConstBuffer const& name) {
 Path& Path::reset() {
   if (_ptr) {
     // If we're sharing the instance, make a new one for us.
-    if (_ptr.isShared()) { _ptr = new ImplType;
+    if (_ptr.use_count() > 1) {
+      _ptr.reset(new ImplType);
     } else { // clear out the existing instance.
       _ptr->_elements.clear();
     }
diff --git a/lib/tsconfig/TsValue.h b/lib/tsconfig/TsValue.h
index db8fc3f..f8fc4e1 100644
--- a/lib/tsconfig/TsValue.h
+++ b/lib/tsconfig/TsValue.h
@@ -642,7 +642,7 @@ namespace detail {
   inline size_t ValueTable::size() const { return _ptr ? _ptr->_values.size() : 0; }
   inline Generation ValueTable::generation() const { return _ptr ? _ptr->_generation :
Generation(0); }
   inline ValueItem const& ValueTable::operator [] (ValueIndex idx) const { return const_cast<self*>(this)->operator
[] (idx); }
-  inline ValueTable& ValueTable::reset() { _ptr = nullptr; return *this; }
+  inline ValueTable& ValueTable::reset() { _ptr.reset(); return *this; }
 
   inline ValueItem::ValueItem() : _type(VoidValue), _local_index(0), _srcLine(0), _srcColumn(0)
{}
   inline ValueItem::ValueItem(ValueType type) : _type(type), _local_index(0), _srcLine(0),
_srcColumn(0) {}
@@ -716,7 +716,7 @@ inline Value& Value::setSource(int line, int col) {
 inline Path::ImplType::ImplType() { }
 
 inline Path::Path() { }
-inline Path::ImplType* Path::instance() { if (!_ptr) _ptr = new ImplType; return _ptr.get();
}
+inline Path::ImplType* Path::instance() { if (!_ptr) _ptr.reset(new ImplType); return _ptr.get();
}
 inline Path& Path::append(ConstBuffer const& tag) { this->instance()->_elements.push_back(tag);
return *this; }
 inline Path& Path::append(size_t index) { this->instance()->_elements.push_back(ConstBuffer(nullptr,
index)); return *this; }
 inline size_t Path::count() const { return _ptr ? _ptr->_elements.size() : 0; }
diff --git a/lib/wccp/WccpEndPoint.cc b/lib/wccp/WccpEndPoint.cc
index 2815875..b69c5bc 100644
--- a/lib/wccp/WccpEndPoint.cc
+++ b/lib/wccp/WccpEndPoint.cc
@@ -1165,7 +1165,7 @@ Cache::~Cache() {}
 EndPoint::ImplType *
 Cache::make()
 {
-  m_ptr.assign(new ImplType);
+  m_ptr.reset(new ImplType);
   return m_ptr.get();
 }
 
@@ -1219,7 +1219,7 @@ Router::~Router() {}
 EndPoint::ImplType *
 Router::make()
 {
-  m_ptr.assign(new ImplType);
+  m_ptr.reset(new ImplType);
   return m_ptr.get();
 }
 

-- 
To stop receiving notification emails like this one, please contact
bcall@apache.org.

Mime
View raw message