Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / src / core / lib / gprpp / ref_counted.h
diff --git a/legacy-libs/grpc/deps/grpc/src/core/lib/gprpp/ref_counted.h b/legacy-libs/grpc/deps/grpc/src/core/lib/gprpp/ref_counted.h
new file mode 100644 (file)
index 0000000..5c7a5cf
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ *
+ * Copyright 2017 gRPC 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 GRPC_CORE_LIB_GPRPP_REF_COUNTED_H
+#define GRPC_CORE_LIB_GPRPP_REF_COUNTED_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include <atomic>
+#include <cassert>
+#include <cinttypes>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/atomic.h"
+#include "src/core/lib/gprpp/debug_location.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+
+namespace grpc_core {
+
+// PolymorphicRefCount enforces polymorphic destruction of RefCounted.
+class PolymorphicRefCount {
+ public:
+  GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+
+  virtual ~PolymorphicRefCount() = default;
+};
+
+// NonPolymorphicRefCount does not enforce polymorphic destruction of
+// RefCounted. Please refer to grpc_core::RefCounted for more details, and
+// when in doubt use PolymorphicRefCount.
+class NonPolymorphicRefCount {
+ public:
+  GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+
+  ~NonPolymorphicRefCount() = default;
+};
+
+// RefCount is a simple atomic ref-count.
+//
+// This is a C++ implementation of gpr_refcount, with inline functions. Due to
+// inline functions, this class is significantly more efficient than
+// gpr_refcount and should be preferred over gpr_refcount whenever possible.
+//
+// TODO(soheil): Remove gpr_refcount after submitting the GRFC and the paragraph
+//               above.
+class RefCount {
+ public:
+  using Value = intptr_t;
+
+  // `init` is the initial refcount stored in this object.
+  //
+  // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
+  // Note: RefCount tracing is only enabled on debug builds, even when a
+  //       TraceFlag is used.
+  template <typename TraceFlagT = TraceFlag>
+  constexpr explicit RefCount(Value init = 1, TraceFlagT* trace_flag = nullptr)
+      :
+#ifndef NDEBUG
+        trace_flag_(trace_flag),
+#endif
+        value_(init) {
+  }
+
+  // Increases the ref-count by `n`.
+  void Ref(Value n = 1) {
+#ifndef NDEBUG
+    const Value prior = value_.FetchAdd(n, MemoryOrder::RELAXED);
+    if (trace_flag_ != nullptr && trace_flag_->enabled()) {
+      gpr_log(GPR_INFO, "%s:%p ref %" PRIdPTR " -> %" PRIdPTR,
+              trace_flag_->name(), this, prior, prior + n);
+    }
+#else
+    value_.FetchAdd(n, MemoryOrder::RELAXED);
+#endif
+  }
+  void Ref(const DebugLocation& location, const char* reason, Value n = 1) {
+#ifndef NDEBUG
+    const Value prior = value_.FetchAdd(n, MemoryOrder::RELAXED);
+    if (trace_flag_ != nullptr && trace_flag_->enabled()) {
+      gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
+              trace_flag_->name(), this, location.file(), location.line(),
+              prior, prior + n, reason);
+    }
+#else
+    value_.FetchAdd(n, MemoryOrder::RELAXED);
+#endif
+  }
+
+  // Similar to Ref() with an assert on the ref-count being non-zero.
+  void RefNonZero() {
+#ifndef NDEBUG
+    const Value prior = value_.FetchAdd(1, MemoryOrder::RELAXED);
+    if (trace_flag_ != nullptr && trace_flag_->enabled()) {
+      gpr_log(GPR_INFO, "%s:%p ref %" PRIdPTR " -> %" PRIdPTR,
+              trace_flag_->name(), this, prior, prior + 1);
+    }
+    assert(prior > 0);
+#else
+    value_.FetchAdd(1, MemoryOrder::RELAXED);
+#endif
+  }
+  void RefNonZero(const DebugLocation& location, const char* reason) {
+#ifndef NDEBUG
+    const Value prior = value_.FetchAdd(1, MemoryOrder::RELAXED);
+    if (trace_flag_ != nullptr && trace_flag_->enabled()) {
+      gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
+              trace_flag_->name(), this, location.file(), location.line(),
+              prior, prior + 1, reason);
+    }
+    assert(prior > 0);
+#else
+    RefNonZero();
+#endif
+  }
+
+  bool RefIfNonZero() {
+#ifndef NDEBUG
+    if (trace_flag_ != nullptr && trace_flag_->enabled()) {
+      const Value prior = get();
+      gpr_log(GPR_INFO, "%s:%p ref_if_non_zero %" PRIdPTR " -> %" PRIdPTR,
+              trace_flag_->name(), this, prior, prior + 1);
+    }
+#endif
+    return value_.IncrementIfNonzero();
+  }
+  bool RefIfNonZero(const DebugLocation& location, const char* reason) {
+#ifndef NDEBUG
+    if (trace_flag_ != nullptr && trace_flag_->enabled()) {
+      const Value prior = get();
+      gpr_log(GPR_INFO,
+              "%s:%p %s:%d ref_if_non_zero "
+              "%" PRIdPTR " -> %" PRIdPTR " %s",
+              trace_flag_->name(), this, location.file(), location.line(),
+              prior, prior + 1, reason);
+    }
+#endif
+    return value_.IncrementIfNonzero();
+  }
+
+  // Decrements the ref-count and returns true if the ref-count reaches 0.
+  bool Unref() {
+#ifndef NDEBUG
+    // Grab a copy of the trace flag before the atomic change, since we
+    // can't safely access it afterwards if we're going to be freed.
+    auto* trace_flag = trace_flag_;
+#endif
+    const Value prior = value_.FetchSub(1, MemoryOrder::ACQ_REL);
+#ifndef NDEBUG
+    if (trace_flag != nullptr && trace_flag->enabled()) {
+      gpr_log(GPR_INFO, "%s:%p unref %" PRIdPTR " -> %" PRIdPTR,
+              trace_flag->name(), this, prior, prior - 1);
+    }
+    GPR_DEBUG_ASSERT(prior > 0);
+#endif
+    return prior == 1;
+  }
+  bool Unref(const DebugLocation& location, const char* reason) {
+#ifndef NDEBUG
+    // Grab a copy of the trace flag before the atomic change, since we
+    // can't safely access it afterwards if we're going to be freed.
+    auto* trace_flag = trace_flag_;
+#endif
+    const Value prior = value_.FetchSub(1, MemoryOrder::ACQ_REL);
+#ifndef NDEBUG
+    if (trace_flag != nullptr && trace_flag->enabled()) {
+      gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
+              trace_flag->name(), this, location.file(), location.line(), prior,
+              prior - 1, reason);
+    }
+    GPR_DEBUG_ASSERT(prior > 0);
+#endif
+    return prior == 1;
+  }
+
+ private:
+  Value get() const { return value_.Load(MemoryOrder::RELAXED); }
+
+#ifndef NDEBUG
+  TraceFlag* trace_flag_;
+#endif
+  Atomic<Value> value_;
+};
+
+// A base class for reference-counted objects.
+// New objects should be created via New() and start with a refcount of 1.
+// When the refcount reaches 0, the object will be deleted via Delete().
+//
+// This will commonly be used by CRTP (curiously-recurring template pattern)
+// e.g., class MyClass : public RefCounted<MyClass>
+//
+// Use PolymorphicRefCount and NonPolymorphicRefCount to select between
+// different implementations of RefCounted.
+//
+// Note that NonPolymorphicRefCount does not support polymorphic destruction.
+// So, use NonPolymorphicRefCount only when both of the following conditions
+// are guaranteed to hold:
+// (a) Child is a concrete leaf class in RefCounted<Child>, and
+// (b) you are guaranteed to call Unref only on concrete leaf classes and not
+//     their parents.
+//
+// The following example is illegal, because calling Unref() will not call
+// the dtor of Child.
+//
+//    class Parent : public RefCounted<Parent, NonPolymorphicRefCount> {}
+//    class Child : public Parent {}
+//
+//    Child* ch;
+//    ch->Unref();
+//
+template <typename Child, typename Impl = PolymorphicRefCount>
+class RefCounted : public Impl {
+ public:
+  RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
+    IncrementRefCount();
+    return RefCountedPtr<Child>(static_cast<Child*>(this));
+  }
+
+  RefCountedPtr<Child> Ref(const DebugLocation& location,
+                           const char* reason) GRPC_MUST_USE_RESULT {
+    IncrementRefCount(location, reason);
+    return RefCountedPtr<Child>(static_cast<Child*>(this));
+  }
+
+  // TODO(roth): Once all of our code is converted to C++ and can use
+  // RefCountedPtr<> instead of manual ref-counting, make this method
+  // private, since it will only be used by RefCountedPtr<>, which is a
+  // friend of this class.
+  void Unref() {
+    if (GPR_UNLIKELY(refs_.Unref())) {
+      Delete(static_cast<Child*>(this));
+    }
+  }
+  void Unref(const DebugLocation& location, const char* reason) {
+    if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
+      Delete(static_cast<Child*>(this));
+    }
+  }
+
+  bool RefIfNonZero() { return refs_.RefIfNonZero(); }
+  bool RefIfNonZero(const DebugLocation& location, const char* reason) {
+    return refs_.RefIfNonZero(location, reason);
+  }
+
+  // Not copyable nor movable.
+  RefCounted(const RefCounted&) = delete;
+  RefCounted& operator=(const RefCounted&) = delete;
+
+  GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+  GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
+
+  // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
+  // Note: RefCount tracing is only enabled on debug builds, even when a
+  //       TraceFlag is used.
+  template <typename TraceFlagT = TraceFlag>
+  explicit RefCounted(TraceFlagT* trace_flag = nullptr,
+                      intptr_t initial_refcount = 1)
+      : refs_(initial_refcount, trace_flag) {}
+
+  // Note: Depending on the Impl used, this dtor can be implicitly virtual.
+  ~RefCounted() = default;
+
+ private:
+  // Allow RefCountedPtr<> to access IncrementRefCount().
+  template <typename T>
+  friend class RefCountedPtr;
+
+  void IncrementRefCount() { refs_.Ref(); }
+  void IncrementRefCount(const DebugLocation& location, const char* reason) {
+    refs_.Ref(location, reason);
+  }
+
+  RefCount refs_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_GPRPP_REF_COUNTED_H */