/*
 * Copyright (C) 2016 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 LIBMEMUNREACHABLE_ALLOCATOR_H_
#define LIBMEMUNREACHABLE_ALLOCATOR_H_

#include <atomic>
#include <cstddef>
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
extern std::atomic<int> heap_count;

class HeapImpl;

template<typename T>
class Allocator;


// Non-templated class that implements wraps HeapImpl to keep
// implementation out of the header file
class Heap {
public:
  Heap();
  ~Heap();

  // Copy constructor that does not take ownership of impl_
  Heap(const Heap& other) : impl_(other.impl_), owns_impl_(false) {}

  // Assignment disabled
  Heap& operator=(const Heap&) = delete;

  // Allocate size bytes
  void* allocate(size_t size);

  // Deallocate allocation returned by allocate
  void deallocate(void*);

  bool empty();

  static void deallocate(HeapImpl* impl, void* ptr);

  // Allocate a class of type T
  template<class T>
  T* allocate() {
    return reinterpret_cast<T*>(allocate(sizeof(T)));
  }

  // Comparators, copied objects will be equal
  bool operator ==(const Heap& other) const {
    return impl_ == other.impl_;
  }
  bool operator !=(const Heap& other) const {
    return !(*this == other);
  }

  // std::unique_ptr wrapper that allocates using allocate and deletes using
  // deallocate
  template<class T>
  using unique_ptr = std::unique_ptr<T, std::function<void(void*)>>;

  template<class T, class... Args>
  unique_ptr<T> make_unique(Args&&... args) {
    HeapImpl* impl = impl_;
    return unique_ptr<T>(new (allocate<T>()) T(std::forward<Args>(args)...),
        [impl](void* ptr) {
          reinterpret_cast<T*>(ptr)->~T();
          deallocate(impl, ptr);
        });
  }

  // std::unique_ptr wrapper that allocates using allocate and deletes using
  // deallocate
  template<class T>
  using shared_ptr = std::shared_ptr<T>;

  template<class T, class... Args>
  shared_ptr<T> make_shared(Args&&... args);

protected:
  HeapImpl* impl_;
  bool owns_impl_;
};

// STLAllocator implements the std allocator interface on top of a Heap
template<typename T>
class STLAllocator {
public:
  using value_type = T;
  ~STLAllocator() {
  }

  // Construct an STLAllocator on top of a Heap
  STLAllocator(const Heap& heap) :  // NOLINT, implicit
      heap_(heap) {
  }

  // Rebind an STLAllocator from an another STLAllocator
  template<typename U>
  STLAllocator(const STLAllocator<U>& other) :  // NOLINT, implicit
      heap_(other.heap_) {
  }

  STLAllocator(const STLAllocator&) = default;
  STLAllocator<T>& operator=(const STLAllocator<T>&) = default;

  T* allocate(std::size_t n) {
    return reinterpret_cast<T*>(heap_.allocate(n * sizeof(T)));
  }

  void deallocate(T* ptr, std::size_t) {
    heap_.deallocate(ptr);
  }

  template<typename U>
  bool operator ==(const STLAllocator<U>& other) const {
    return heap_ == other.heap_;
  }
  template<typename U>
  inline bool operator !=(const STLAllocator<U>& other) const {
    return !(this == other);
  }

  template<typename U>
  friend class STLAllocator;

protected:
  Heap heap_;
};


// Allocator extends STLAllocator with some convenience methods for allocating
// a single object and for constructing unique_ptr and shared_ptr objects with
// appropriate deleters.
template<class T>
class Allocator : public STLAllocator<T> {
 public:
  ~Allocator() {}

  Allocator(const Heap& other) : // NOLINT, implicit
      STLAllocator<T>(other) {
  }

  template<typename U>
  Allocator(const STLAllocator<U>& other) :  // NOLINT, implicit
      STLAllocator<T>(other) {
  }

  Allocator(const Allocator&) = default;
  Allocator<T>& operator=(const Allocator<T>&) = default;

  using STLAllocator<T>::allocate;
  using STLAllocator<T>::deallocate;
  using STLAllocator<T>::heap_;

  T* allocate() {
    return STLAllocator<T>::allocate(1);
  }
  void deallocate(void* ptr) {
    heap_.deallocate(ptr);
  }

  using shared_ptr = Heap::shared_ptr<T>;

  template<class... Args>
  shared_ptr make_shared(Args&& ...args) {
    return heap_.template make_shared<T>(std::forward<Args>(args)...);
  }

  using unique_ptr = Heap::unique_ptr<T>;

  template<class... Args>
  unique_ptr make_unique(Args&& ...args) {
    return heap_.template make_unique<T>(std::forward<Args>(args)...);
  }
};

// std::unique_ptr wrapper that allocates using allocate and deletes using
// deallocate.  Implemented outside class definition in order to pass
// Allocator<T> to shared_ptr.
template<class T, class... Args>
inline Heap::shared_ptr<T> Heap::make_shared(Args&&... args) {
  return std::allocate_shared<T, Allocator<T>, Args...>(Allocator<T>(*this),
      std::forward<Args>(args)...);
}

namespace allocator {

template<class T>
using vector = std::vector<T, Allocator<T>>;

template<class T>
using list = std::list<T, Allocator<T>>;

template<class Key, class T, class Compare = std::less<Key>>
using map = std::map<Key, T, Compare, Allocator<std::pair<const Key, T>>>;

template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
using unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, Allocator<std::pair<const Key, T>>>;

template<class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
using unordered_set = std::unordered_set<Key, Hash, KeyEqual, Allocator<Key>>;

template<class Key, class Compare = std::less<Key>>
using set = std::set<Key, Compare, Allocator<Key>>;

using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
}

#endif
