// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// unique_ptr-style pointer that stores values that may be from an arena. Takes
// up the same storage as the platform's native pointer type. Takes ownership
// of the value it's constructed with; if holding a value in an arena, and the
// type has a non-trivial destructor, the arena must outlive the
// QuicArenaScopedPtr. Does not support array overloads.

#ifndef QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_
#define QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_

#include <cstdint>  // for uintptr_t

#include "quic/platform/api/quic_export.h"
#include "quic/platform/api/quic_logging.h"

namespace quic {

template <typename T>
class QUIC_NO_EXPORT QuicArenaScopedPtr {
  static_assert(alignof(T*) > 1,
                "QuicArenaScopedPtr can only store objects that are aligned to "
                "greater than 1 byte.");

 public:
  // Constructs an empty QuicArenaScopedPtr.
  QuicArenaScopedPtr();

  // Constructs a QuicArenaScopedPtr referencing the heap-allocated memory
  // provided.
  explicit QuicArenaScopedPtr(T* value);

  template <typename U>
  QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other);  // NOLINT
  template <typename U>
  QuicArenaScopedPtr& operator=(QuicArenaScopedPtr<U>&& other);
  ~QuicArenaScopedPtr();

  // Returns a pointer to the value.
  T* get() const;

  // Returns a reference to the value.
  T& operator*() const;

  // Returns a pointer to the value.
  T* operator->() const;

  // Swaps the value of this pointer with |other|.
  void swap(QuicArenaScopedPtr& other);

  // Resets the held value to |value|.
  void reset(T* value = nullptr);

  // Returns true if |this| came from an arena. Primarily exposed for testing
  // and assertions.
  bool is_from_arena();

 private:
  // Friends with other derived types of QuicArenaScopedPtr, to support the
  // derived-types case.
  template <typename U>
  friend class QuicArenaScopedPtr;
  // Also befriend all known arenas, only to prevent misuse.
  template <uint32_t ArenaSize>
  friend class QuicOneBlockArena;

  // Tag to denote that a QuicArenaScopedPtr is being explicitly created by an
  // arena.
  enum class ConstructFrom { kHeap, kArena };

  // Constructs a QuicArenaScopedPtr with the given representation.
  QuicArenaScopedPtr(void* value, ConstructFrom from);
  QuicArenaScopedPtr(const QuicArenaScopedPtr&) = delete;
  QuicArenaScopedPtr& operator=(const QuicArenaScopedPtr&) = delete;

  // Low-order bits of value_ that determine if the pointer came from an arena.
  static const uintptr_t kFromArenaMask = 0x1;

  // Every platform we care about has at least 4B aligned integers, so store the
  // is_from_arena bit in the least significant bit.
  void* value_;
};

template <typename T>
bool operator==(const QuicArenaScopedPtr<T>& left,
                const QuicArenaScopedPtr<T>& right) {
  return left.get() == right.get();
}

template <typename T>
bool operator!=(const QuicArenaScopedPtr<T>& left,
                const QuicArenaScopedPtr<T>& right) {
  return left.get() != right.get();
}

template <typename T>
bool operator==(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
  return nullptr == right.get();
}

template <typename T>
bool operator!=(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
  return nullptr != right.get();
}

template <typename T>
bool operator==(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
  return left.get() == nullptr;
}

template <typename T>
bool operator!=(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
  return left.get() != nullptr;
}

template <typename T>
QuicArenaScopedPtr<T>::QuicArenaScopedPtr() : value_(nullptr) {}

template <typename T>
QuicArenaScopedPtr<T>::QuicArenaScopedPtr(T* value)
    : QuicArenaScopedPtr(value, ConstructFrom::kHeap) {}

template <typename T>
template <typename U>
QuicArenaScopedPtr<T>::QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other)
    : value_(other.value_) {
  static_assert(
      std::is_base_of<T, U>::value || std::is_same<T, U>::value,
      "Cannot construct QuicArenaScopedPtr; type is not derived or same.");
  other.value_ = nullptr;
}

template <typename T>
template <typename U>
QuicArenaScopedPtr<T>& QuicArenaScopedPtr<T>::operator=(
    QuicArenaScopedPtr<U>&& other) {
  static_assert(
      std::is_base_of<T, U>::value || std::is_same<T, U>::value,
      "Cannot assign QuicArenaScopedPtr; type is not derived or same.");
  swap(other);
  return *this;
}

template <typename T>
QuicArenaScopedPtr<T>::~QuicArenaScopedPtr() {
  reset();
}

template <typename T>
T* QuicArenaScopedPtr<T>::get() const {
  return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(value_) &
                              ~kFromArenaMask);
}

template <typename T>
T& QuicArenaScopedPtr<T>::operator*() const {
  return *get();
}

template <typename T>
T* QuicArenaScopedPtr<T>::operator->() const {
  return get();
}

template <typename T>
void QuicArenaScopedPtr<T>::swap(QuicArenaScopedPtr& other) {
  using std::swap;
  swap(value_, other.value_);
}

template <typename T>
bool QuicArenaScopedPtr<T>::is_from_arena() {
  return (reinterpret_cast<uintptr_t>(value_) & kFromArenaMask) != 0;
}

template <typename T>
void QuicArenaScopedPtr<T>::reset(T* value) {
  if (value_ != nullptr) {
    if (is_from_arena()) {
      // Manually invoke the destructor.
      get()->~T();
    } else {
      delete get();
    }
  }
  QUICHE_DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value) & kFromArenaMask);
  value_ = value;
}

template <typename T>
QuicArenaScopedPtr<T>::QuicArenaScopedPtr(void* value, ConstructFrom from_arena)
    : value_(value) {
  QUICHE_DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value_) & kFromArenaMask);
  switch (from_arena) {
    case ConstructFrom::kHeap:
      break;
    case ConstructFrom::kArena:
      value_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(value_) |
                                       QuicArenaScopedPtr<T>::kFromArenaMask);
      break;
  }
}

}  // namespace quic

#endif  // QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_
