/*
 * 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 _STLPORT_CPP11_EXTENSION_MEMORY_
#define _STLPORT_CPP11_EXTENSION_MEMORY_

// This file extends stlport's <memory> implementation to provide support for:
//  - std::shared_ptr (C++11)
//  - std::unique_ptr (C++11)

// Cloned from master branch vendor/google/native/cmds/sysproxy/shared_ptr.h
// Upstream commit ff64c352c35c46a14f15503778781889a816eea4
// Upstream Change-Id: I481ec53b08beecde2bf6dc38e5933342235da3d9

#include <stlport/memory>

namespace std {

template <typename T>
class shared_ptr {
 public:
  shared_ptr();
  explicit shared_ptr(T *value);
  shared_ptr(const shared_ptr &rhs);
  shared_ptr &operator=(const shared_ptr &rhs);
  template <typename U>
  shared_ptr(const shared_ptr<U> &rhs);
  template <typename U>
  shared_ptr &operator=(const shared_ptr<U> &rhs);
  ~shared_ptr();

  T *get() const;
  T *operator->() const;
  T &operator*() const;

  template <typename U>
  bool operator==(const shared_ptr<U> &rhs) const;
  template <typename U>
  bool operator!=(const shared_ptr<U> &rhs) const;
  template <typename U>
  bool operator<(const shared_ptr<U> &rhs) const;
  template <typename U>
  bool operator<=(const shared_ptr<U> &rhs) const;
  template <typename U>
  bool operator>(const shared_ptr<U> &rhs) const;
  template <typename U>
  bool operator>=(const shared_ptr<U> &rhs) const;

  void reset(T *value = NULL);

  // TODO(haining) Work with Deleter

 private:
  template <typename U>
  friend class shared_ptr;

  struct Node {
    T *value;
    int *count;
  };
  // Thread safe decrement, deletes node_ if holding last remaining reference.
  // Any use of node_ after calling this function is unsafe unless node_ is
  // reassigned.
  void DecNode();

  // Thread safe increment.
  void IncNode();

  // Creates a Node referring to NULL.
  static Node NewNullNode();

  // Creates a Node referring to value.
  static Node NewNodeFor(T *value);

  Node node_;
};

template <typename T>
typename shared_ptr<T>::Node shared_ptr<T>::NewNodeFor(T *value) {
  Node n = {value, new int(1)};
  return n;
}

template <typename T>
typename shared_ptr<T>::Node shared_ptr<T>::NewNullNode() {
  return NewNodeFor(NULL);
}

template <typename T>
void shared_ptr<T>::reset(T *value) {
  DecNode();
  node_ = NewNodeFor(value);
}

template <typename T>
shared_ptr<T>::shared_ptr() : node_(NewNullNode()) {}

template <typename T>
void shared_ptr<T>::DecNode() {
  bool should_delete = __atomic_fetch_sub(node_.count, 1, __ATOMIC_SEQ_CST) == 0;
  // The only accesses to node_ that should be made after this line is the
  // deletion conditional on should_delete. Anything else is unsafe since
  // because another thread could have deleted node_
  if (should_delete) {
    delete node_.value;
    delete node_.count;
    node_.value = NULL;
    node_.count = NULL;
  }
}

template <typename T>
void shared_ptr<T>::IncNode() {
  __atomic_fetch_add(node_.count, 1, __ATOMIC_SEQ_CST);
}

template <typename T>
shared_ptr<T>::shared_ptr(T *value) {
  node_ = NewNodeFor(value);
}

template <typename T>
shared_ptr<T>::shared_ptr(const shared_ptr &rhs) : node_(rhs.node_) {
  IncNode();
}

template <typename T>
template <typename U>
shared_ptr<T>::shared_ptr(const shared_ptr<U> &rhs) {
  node_.value = rhs.node_.value;
  node_.count = rhs.node_.count;
  node_.m = rhs.node_.m;
  IncNode();
}

template <typename T>
shared_ptr<T> &shared_ptr<T>::operator=(const shared_ptr &rhs) {
  if (node_.value == rhs.node_.value) {
    return *this;
  }

  DecNode();
  node_ = rhs.node_;
  IncNode();
  return *this;
}

template <typename T>
template <typename U>
shared_ptr<T> &shared_ptr<T>::operator=(const shared_ptr<U> &rhs) {
  if (node_.value == rhs.node_.value) {
    return *this;
  }

  DecNode();
  node_.value = rhs.node_.value;
  node_.count = rhs.node_.count;
  node_.m = rhs.node_.m;
  IncNode();
  return *this;
}

template <typename T>
shared_ptr<T>::~shared_ptr() {
  DecNode();
}

template <typename T>
T *shared_ptr<T>::get() const {
  return node_.value;
}

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

template <typename T>
T &shared_ptr<T>::operator*() const {
  return *node_.value;
}

template <typename T>
template <typename U>
bool shared_ptr<T>::operator==(const shared_ptr<U> &rhs) const {
  return node_.value == rhs.node_.value;
}

template <typename T>
template <typename U>
bool shared_ptr<T>::operator!=(const shared_ptr<U> &rhs) const {
  return node_.value != rhs.node_.value;
}

template <typename T>
template <typename U>
bool shared_ptr<T>::operator<(const shared_ptr<U> &rhs) const {
  return node_.value < rhs.node_.value;
}

template <typename T>
template <typename U>
bool shared_ptr<T>::operator<=(const shared_ptr<U> &rhs) const {
  return node_.value <= rhs.node_.value;
}

template <typename T>
template <typename U>
bool shared_ptr<T>::operator>(const shared_ptr<U> &rhs) const {
  return node_.value > rhs.node_.value;
}

template <typename T>
template <typename U>
bool shared_ptr<T>::operator>=(const shared_ptr<U> &rhs) const {
  return node_.value >= rhs.node_.value;
}

#if !defined(DISALLOW_COPY_AND_ASSIGN)
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&);               \
  void operator=(const TypeName&);
#endif

#include <cstddef>

// Default deleter for pointer types.
template <typename T>
struct DefaultDelete {
  void operator()(T* p) const { delete p; }
};

// Default deleter for array types.
template <typename T>
struct DefaultDelete<T[]> {
  void operator()(T* p) const { delete[] p; }
};

// A smart pointer that deletes the given pointer on destruction.
// Equivalent to C++11's std::unique_ptr
// Named to be in keeping with Android style but also to avoid
// collision with any other implementation, until we can switch over
// to unique_ptr.
// Use thus:
//   unique_ptr<C> c(new C);

namespace workaround_internal {
template <typename T, typename Deleter>
class UniquePtrBase {
 public:
  // Construct a new UniquePtrBase, taking ownership of the given raw pointer.
  explicit UniquePtrBase(T* ptr = 0) : mPtr(ptr), mDeleter() {}
  explicit UniquePtrBase(T* ptr, Deleter d) : mPtr(ptr), mDeleter(d) {}

  ~UniquePtrBase() { reset(); }

  // Accessors.
  T* get() const { return mPtr; }

  // Returns the raw pointer and hands over ownership to the caller.
  // The pointer will not be deleted by UniquePtrBase.
  T* release() {
    T* result = mPtr;
    mPtr = 0;
    return result;
  }

  // Takes ownership of the given raw pointer.
  // If this smart pointer previously owned a different raw pointer, that
  // raw pointer will be freed.
  void reset(T* ptr = 0) {
    T* old_ptr = mPtr;
    mPtr = ptr;
    if (old_ptr != NULL && mPtr != old_ptr) {
      get_deleter()(old_ptr);
    }
  }

  Deleter& get_deleter() { return mDeleter; }
  const Deleter& get_deleter() const { return mDeleter; }

 private:
  // This is so users can compare against null. Callers should be able
  // to invoke operator== and operator!= above with NULL pointers but not
  // with any other pointer.
  struct RawDummy {};

 public:
  bool operator==(const RawDummy*) const { return get() == NULL; }
  friend bool operator==(const RawDummy*, const UniquePtrBase& self) {
    return self == NULL;
  }

  bool operator!=(const RawDummy*) const { return !(*this == NULL); }
  friend bool operator!=(const RawDummy*, const UniquePtrBase& self) {
    return self != NULL;
  }

 private:
  // The raw pointer.
  T* mPtr;
  Deleter mDeleter;

  DISALLOW_COPY_AND_ASSIGN(UniquePtrBase);
};
}  // namespace workaround_internal

template <typename T, typename Deleter = DefaultDelete<T> >
class unique_ptr : public workaround_internal::UniquePtrBase<T, Deleter> {
  typedef workaround_internal::UniquePtrBase<T, Deleter> Base;
 public:
  // Construct a new unique_ptr, taking ownership of the given raw pointer.
  explicit unique_ptr(T* ptr = 0) : Base(ptr) { }
  explicit unique_ptr(T* ptr, Deleter d) : Base(ptr, d) { }

  T& operator*() const { return *this->get(); }
  T* operator->() const { return this->get(); }
};

// Partial specialization for array types. Like std::unique_ptr, this removes
// operator* and operator-> but adds operator[].
template <typename T, typename Deleter>
class unique_ptr<T[], Deleter> : public workaround_internal::UniquePtrBase<T, Deleter> {
  typedef workaround_internal::UniquePtrBase<T, Deleter> Base;
 public:
  explicit unique_ptr(T* ptr = 0) : Base(ptr) { }
  explicit unique_ptr(T* ptr, Deleter d) : Base(ptr, d) { }

  T& operator[](std::ptrdiff_t i) const { return this->get()[i]; }
};

template <typename T>
shared_ptr<T> make_shared() {
  return shared_ptr<T>(new T);
}

}  // namespace std

#endif  // _STLPORT_CPP11_EXTENSION_MEMORY_