text: /*
   * Copyright (c) 2015-present, Facebook, Inc.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   */
  
  #pragma once
  
  #include <cassert>
  #include <new>
  #include <atomic>
  
  namespace facebook {
  namespace jni {
  
  /// @cond INTERNAL
  namespace internal {
  
  // Statistics mostly provided for test (only updated if FBJNI_DEBUG_REFS is defined)
  struct ReferenceStats {
    std::atomic_uint locals_created, globals_created, weaks_created,
                     locals_deleted, globals_deleted, weaks_deleted;
  
    void reset() noexcept;
  };
  
  extern ReferenceStats g_reference_stats;
  }
  /// @endcond
  
  
  // LocalReferenceAllocator /////////////////////////////////////////////////////////////////////////
  
  inline jobject LocalReferenceAllocator::newReference(jobject original) const {
    internal::dbglog("Local new: %p", original);
    #ifdef FBJNI_DEBUG_REFS
      ++internal::g_reference_stats.locals_created;
    #endif
    auto ref = internal::getEnv()->NewLocalRef(original);
    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
    return ref;
  }
  
  inline void LocalReferenceAllocator::deleteReference(jobject reference) const noexcept {
    internal::dbglog("Local release: %p", reference);
  
    if (reference) {
      #ifdef FBJNI_DEBUG_REFS
        ++internal::g_reference_stats.locals_deleted;
      #endif
      assert(verifyReference(reference));
      internal::getEnv()->DeleteLocalRef(reference);
    }
  }
  
  inline bool LocalReferenceAllocator::verifyReference(jobject reference) const noexcept {
    if (!reference || !internal::doesGetObjectRefTypeWork()) {
      return true;
    }
    return internal::getEnv()->GetObjectRefType(reference) == JNILocalRefType;
  }
  
  
  // GlobalReferenceAllocator ////////////////////////////////////////////////////////////////////////
  
  inline jobject GlobalReferenceAllocator::newReference(jobject original) const {
    internal::dbglog("Global new: %p", original);
    #ifdef FBJNI_DEBUG_REFS
      ++internal::g_reference_stats.globals_created;
    #endif
    auto ref = internal::getEnv()->NewGlobalRef(original);
    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
    return ref;
  }
  
  inline void GlobalReferenceAllocator::deleteReference(jobject reference) const noexcept {
    internal::dbglog("Global release: %p", reference);
  
    if (reference) {
      #ifdef FBJNI_DEBUG_REFS
        ++internal::g_reference_stats.globals_deleted;
      #endif
      assert(verifyReference(reference));
      internal::getEnv()->DeleteGlobalRef(reference);
    }
  }
  
  inline bool GlobalReferenceAllocator::verifyReference(jobject reference) const noexcept {
    if (!reference || !internal::doesGetObjectRefTypeWork()) {
      return true;
    }
    return internal::getEnv()->GetObjectRefType(reference) == JNIGlobalRefType;
  }
  
  
  // WeakGlobalReferenceAllocator ////////////////////////////////////////////////////////////////////
  
  inline jobject WeakGlobalReferenceAllocator::newReference(jobject original) const {
    internal::dbglog("Weak global new: %p", original);
    #ifdef FBJNI_DEBUG_REFS
      ++internal::g_reference_stats.weaks_created;
    #endif
    auto ref = internal::getEnv()->NewWeakGlobalRef(original);
    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
    return ref;
  }
  
  inline void WeakGlobalReferenceAllocator::deleteReference(jobject reference) const noexcept {
    internal::dbglog("Weak Global release: %p", reference);
  
    if (reference) {
      #ifdef FBJNI_DEBUG_REFS
        ++internal::g_reference_stats.weaks_deleted;
      #endif
      assert(verifyReference(reference));
      internal::getEnv()->DeleteWeakGlobalRef(reference);
    }
  }
  
  inline bool WeakGlobalReferenceAllocator::verifyReference(jobject reference) const noexcept {
    if (!reference || !internal::doesGetObjectRefTypeWork()) {
      return true;
    }
    return internal::getEnv()->GetObjectRefType(reference) == JNIWeakGlobalRefType;
  }
  
  }}
  