/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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 ART_LIBARTBASE_BASE_DEBUG_STACK_H_
#define ART_LIBARTBASE_BASE_DEBUG_STACK_H_

#include <android-base/logging.h>
#include <android-base/macros.h>

#include "globals.h"

namespace art {

// Helper classes for reference counting to enforce construction/destruction order and
// usage of the top element of a stack in debug mode with no overhead in release mode.

// Reference counter. No references allowed in destructor or in explicitly called CheckNoRefs().
template <bool kIsDebug>
class DebugStackRefCounterImpl;
// Reference. Allows an explicit check that it's the top reference.
template <bool kIsDebug>
class DebugStackReferenceImpl;
// Indirect top reference. Checks that the reference is the top reference when used.
template <bool kIsDebug>
class DebugStackIndirectTopRefImpl;

using DebugStackRefCounter = DebugStackRefCounterImpl<kIsDebugBuild>;
using DebugStackReference = DebugStackReferenceImpl<kIsDebugBuild>;
using DebugStackIndirectTopRef = DebugStackIndirectTopRefImpl<kIsDebugBuild>;

// Non-debug mode specializations. This should be optimized away.

template <>
class DebugStackRefCounterImpl<false> {
 public:
  size_t IncrementRefCount() { return 0u; }
  void DecrementRefCount() { }
  size_t GetRefCount() const { return 0u; }
  void CheckNoRefs() const { }
};

template <>
class DebugStackReferenceImpl<false> {
 public:
  explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<false>* counter ATTRIBUTE_UNUSED) {}
  DebugStackReferenceImpl(const DebugStackReferenceImpl& other) = default;
  DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) = default;
  void CheckTop() { }
};

template <>
class DebugStackIndirectTopRefImpl<false> {
 public:
  explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<false>* ref ATTRIBUTE_UNUSED) {}
  DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other) = default;
  DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) = default;
  void CheckTop() { }
};

// Debug mode versions.

template <bool kIsDebug>
class DebugStackRefCounterImpl {
 public:
  DebugStackRefCounterImpl() : ref_count_(0u) { }
  ~DebugStackRefCounterImpl() { CheckNoRefs(); }
  size_t IncrementRefCount() { return ++ref_count_; }
  void DecrementRefCount() { --ref_count_; }
  size_t GetRefCount() const { return ref_count_; }
  void CheckNoRefs() const { CHECK_EQ(ref_count_, 0u); }

 private:
  size_t ref_count_;
};

template <bool kIsDebug>
class DebugStackReferenceImpl {
 public:
  explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<kIsDebug>* counter)
    : counter_(counter), ref_count_(counter->IncrementRefCount()) {
  }
  DebugStackReferenceImpl(const DebugStackReferenceImpl& other)
    : counter_(other.counter_), ref_count_(counter_->IncrementRefCount()) {
  }
  DebugStackReferenceImpl(DebugStackReferenceImpl&& other) noexcept
    : counter_(other.counter_), ref_count_(other.ref_count_) {
    other.counter_ = nullptr;
  }
  DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) {
    CHECK(counter_ == other.counter_);
    return *this;
  }
  ~DebugStackReferenceImpl() {
    if (counter_ != nullptr) {
      counter_->DecrementRefCount();
    }
  }
  void CheckTop() { CHECK_EQ(counter_->GetRefCount(), ref_count_); }

 private:
  DebugStackRefCounterImpl<true>* counter_;
  size_t ref_count_;
};

template <bool kIsDebug>
class DebugStackIndirectTopRefImpl {
 public:
  explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<kIsDebug>* ref)
      : ref_(ref) {
    CheckTop();
  }
  DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other)
      : ref_(other.ref_) {
    CheckTop();
  }
  DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) {
    CHECK(ref_ == other.ref_);
    CheckTop();
    return *this;
  }
  ~DebugStackIndirectTopRefImpl() {
    CheckTop();
  }
  void CheckTop() {
    ref_->CheckTop();
  }

 private:
  DebugStackReferenceImpl<kIsDebug>* ref_;
};

}  // namespace art

#endif  // ART_LIBARTBASE_BASE_DEBUG_STACK_H_
