// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_UTIL_H_
#define V8_UTIL_H_

#include "v8.h"  // NOLINT(build/include)
#include <assert.h>
#include <map>
#include <vector>

/**
 * Support for Persistent containers.
 *
 * C++11 embedders can use STL containers with Global values,
 * but pre-C++11 does not support the required move semantic and hence
 * may want these container classes.
 */
namespace v8 {

typedef uintptr_t PersistentContainerValue;
static const uintptr_t kPersistentContainerNotFound = 0;
enum PersistentContainerCallbackType {
  kNotWeak,
  // These correspond to v8::WeakCallbackType
  kWeakWithParameter,
  kWeakWithInternalFields
};

/**
 * A default trait implementation for PersistentValueMap which uses std::map
 * as a backing map.
 *
 * Users will have to implement their own weak callbacks & dispose traits.
 */
template<typename K, typename V>
class StdMapTraits {
 public:
  // STL map & related:
  typedef std::map<K, PersistentContainerValue> Impl;
  typedef typename Impl::iterator Iterator;

  static bool Empty(Impl* impl) { return impl->empty(); }
  static size_t Size(Impl* impl) { return impl->size(); }
  static void Swap(Impl& a, Impl& b) { std::swap(a, b); }  // NOLINT
  static Iterator Begin(Impl* impl) { return impl->begin(); }
  static Iterator End(Impl* impl) { return impl->end(); }
  static K Key(Iterator it) { return it->first; }
  static PersistentContainerValue Value(Iterator it) { return it->second; }
  static PersistentContainerValue Set(Impl* impl, K key,
      PersistentContainerValue value) {
    std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
    PersistentContainerValue old_value = kPersistentContainerNotFound;
    if (!res.second) {
      old_value = res.first->second;
      res.first->second = value;
    }
    return old_value;
  }
  static PersistentContainerValue Get(Impl* impl, K key) {
    Iterator it = impl->find(key);
    if (it == impl->end()) return kPersistentContainerNotFound;
    return it->second;
  }
  static PersistentContainerValue Remove(Impl* impl, K key) {
    Iterator it = impl->find(key);
    if (it == impl->end()) return kPersistentContainerNotFound;
    PersistentContainerValue value = it->second;
    impl->erase(it);
    return value;
  }
};


/**
 * A default trait implementation for PersistentValueMap, which inherits
 * a std:map backing map from StdMapTraits and holds non-weak persistent
 * objects and has no special Dispose handling.
 *
 * You should not derive from this class, since MapType depends on the
 * surrounding class, and hence a subclass cannot simply inherit the methods.
 */
template<typename K, typename V>
class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
 public:
  // Weak callback & friends:
  static const PersistentContainerCallbackType kCallbackType = kNotWeak;
  typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
      MapType;
  typedef void WeakCallbackDataType;

  static WeakCallbackDataType* WeakCallbackParameter(
      MapType* map, const K& key, Local<V> value) {
    return nullptr;
  }
  static MapType* MapFromWeakCallbackInfo(
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
    return nullptr;
  }
  static K KeyFromWeakCallbackInfo(
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
    return K();
  }
  static void DisposeCallbackData(WeakCallbackDataType* data) { }
  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
};


template <typename K, typename V>
class DefaultGlobalMapTraits : public StdMapTraits<K, V> {
 private:
  template <typename T>
  struct RemovePointer;

 public:
  // Weak callback & friends:
  static const PersistentContainerCallbackType kCallbackType = kNotWeak;
  typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
  typedef void WeakCallbackDataType;

  static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
                                                     Local<V> value) {
    return nullptr;
  }
  static MapType* MapFromWeakCallbackInfo(
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
    return nullptr;
  }
  static K KeyFromWeakCallbackInfo(
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
    return K();
  }
  static void DisposeCallbackData(WeakCallbackDataType* data) {}
  static void OnWeakCallback(
      const WeakCallbackInfo<WeakCallbackDataType>& data) {}
  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
  // This is a second pass callback, so SetSecondPassCallback cannot be called.
  static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}

 private:
  template <typename T>
  struct RemovePointer<T*> {
    typedef T Type;
  };
};


/**
 * A map wrapper that allows using Global as a mapped value.
 * C++11 embedders don't need this class, as they can use Global
 * directly in std containers.
 *
 * The map relies on a backing map, whose type and accessors are described
 * by the Traits class. The backing map will handle values of type
 * PersistentContainerValue, with all conversion into and out of V8
 * handles being transparently handled by this class.
 */
template <typename K, typename V, typename Traits>
class PersistentValueMapBase {
 public:
  Isolate* GetIsolate() { return isolate_; }

  /**
   * Return size of the map.
   */
  size_t Size() { return Traits::Size(&impl_); }

  /**
   * Return whether the map holds weak persistents.
   */
  bool IsWeak() { return Traits::kCallbackType != kNotWeak; }

  /**
   * Get value stored in map.
   */
  Local<V> Get(const K& key) {
    return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
  }

  /**
   * Check whether a value is contained in the map.
   */
  bool Contains(const K& key) {
    return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
  }

  /**
   * Get value stored in map and set it in returnValue.
   * Return true if a value was found.
   */
  bool SetReturnValue(const K& key,
      ReturnValue<Value> returnValue) {
    return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
  }

  /**
   * Return value for key and remove it from the map.
   */
  Global<V> Remove(const K& key) {
    return Release(Traits::Remove(&impl_, key)).Pass();
  }

  /**
  * Traverses the map repeatedly,
  * in case side effects of disposal cause insertions.
  **/
  void Clear() {
    typedef typename Traits::Iterator It;
    HandleScope handle_scope(isolate_);
    // TODO(dcarney): figure out if this swap and loop is necessary.
    while (!Traits::Empty(&impl_)) {
      typename Traits::Impl impl;
      Traits::Swap(impl_, impl);
      for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
        Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
                        Traits::Key(i));
      }
    }
  }

  /**
   * Helper class for GetReference/SetWithReference. Do not use outside
   * that context.
   */
  class PersistentValueReference {
   public:
    PersistentValueReference() : value_(kPersistentContainerNotFound) { }
    PersistentValueReference(const PersistentValueReference& other)
        : value_(other.value_) { }

    Local<V> NewLocal(Isolate* isolate) const {
      return Local<V>::New(isolate, FromVal(value_));
    }
    bool IsEmpty() const {
      return value_ == kPersistentContainerNotFound;
    }
    template<typename T>
    bool SetReturnValue(ReturnValue<T> returnValue) {
      return SetReturnValueFromVal(&returnValue, value_);
    }
    void Reset() {
      value_ = kPersistentContainerNotFound;
    }
    void operator=(const PersistentValueReference& other) {
      value_ = other.value_;
    }

   private:
    friend class PersistentValueMapBase;
    friend class PersistentValueMap<K, V, Traits>;
    friend class GlobalValueMap<K, V, Traits>;

    explicit PersistentValueReference(PersistentContainerValue value)
        : value_(value) { }

    void operator=(PersistentContainerValue value) {
      value_ = value;
    }

    PersistentContainerValue value_;
  };

  /**
   * Get a reference to a map value. This enables fast, repeated access
   * to a value stored in the map while the map remains unchanged.
   *
   * Careful: This is potentially unsafe, so please use with care.
   * The value will become invalid if the value for this key changes
   * in the underlying map, as a result of Set or Remove for the same
   * key; as a result of the weak callback for the same key; or as a
   * result of calling Clear() or destruction of the map.
   */
  PersistentValueReference GetReference(const K& key) {
    return PersistentValueReference(Traits::Get(&impl_, key));
  }

 protected:
  explicit PersistentValueMapBase(Isolate* isolate)
      : isolate_(isolate), label_(nullptr) {}
  PersistentValueMapBase(Isolate* isolate, const char* label)
      : isolate_(isolate), label_(label) {}

  ~PersistentValueMapBase() { Clear(); }

  Isolate* isolate() { return isolate_; }
  typename Traits::Impl* impl() { return &impl_; }

  static V* FromVal(PersistentContainerValue v) {
    return reinterpret_cast<V*>(v);
  }

  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
    V* v = persistent->val_;
    persistent->val_ = nullptr;
    return reinterpret_cast<PersistentContainerValue>(v);
  }

  static PersistentContainerValue Leak(Global<V>* persistent) {
    return reinterpret_cast<PersistentContainerValue>(persistent->val_);
  }

  /**
   * Return a container value as Global and make sure the weak
   * callback is properly disposed of. All remove functionality should go
   * through this.
   */
  static Global<V> Release(PersistentContainerValue v) {
    Global<V> p;
    p.val_ = FromVal(v);
    if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
      Traits::DisposeCallbackData(
          p.template ClearWeak<typename Traits::WeakCallbackDataType>());
    }
    return p.Pass();
  }

  void RemoveWeak(const K& key) {
    Global<V> p;
    p.val_ = FromVal(Traits::Remove(&impl_, key));
    p.Reset();
  }

  void AnnotateStrongRetainer(Global<V>* persistent) {
    persistent->AnnotateStrongRetainer(label_);
  }

 private:
  PersistentValueMapBase(PersistentValueMapBase&);
  void operator=(PersistentValueMapBase&);

  static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
                                    PersistentContainerValue value) {
    bool hasValue = value != kPersistentContainerNotFound;
    if (hasValue) {
      returnValue->SetInternal(
          *reinterpret_cast<internal::Address*>(FromVal(value)));
    }
    return hasValue;
  }

  Isolate* isolate_;
  typename Traits::Impl impl_;
  const char* label_;
};

template <typename K, typename V, typename Traits>
class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
 public:
  explicit PersistentValueMap(Isolate* isolate)
      : PersistentValueMapBase<K, V, Traits>(isolate) {}
  PersistentValueMap(Isolate* isolate, const char* label)
      : PersistentValueMapBase<K, V, Traits>(isolate, label) {}

  typedef
      typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
          PersistentValueReference;

  /**
   * Put value into map. Depending on Traits::kIsWeak, the value will be held
   * by the map strongly or weakly.
   * Returns old value as Global.
   */
  Global<V> Set(const K& key, Local<V> value) {
    Global<V> persistent(this->isolate(), value);
    return SetUnique(key, &persistent);
  }

  /**
   * Put value into map, like Set(const K&, Local<V>).
   */
  Global<V> Set(const K& key, Global<V> value) {
    return SetUnique(key, &value);
  }

  /**
   * Put the value into the map, and set the 'weak' callback when demanded
   * by the Traits class.
   */
  Global<V> SetUnique(const K& key, Global<V>* persistent) {
    if (Traits::kCallbackType == kNotWeak) {
      this->AnnotateStrongRetainer(persistent);
    } else {
      WeakCallbackType callback_type =
          Traits::kCallbackType == kWeakWithInternalFields
              ? WeakCallbackType::kInternalFields
              : WeakCallbackType::kParameter;
      Local<V> value(Local<V>::New(this->isolate(), *persistent));
      persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
          Traits::WeakCallbackParameter(this, key, value), WeakCallback,
          callback_type);
    }
    PersistentContainerValue old_value =
        Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    return this->Release(old_value).Pass();
  }

  /**
   * Put a value into the map and update the reference.
   * Restrictions of GetReference apply here as well.
   */
  Global<V> Set(const K& key, Global<V> value,
                PersistentValueReference* reference) {
    *reference = this->Leak(&value);
    return SetUnique(key, &value);
  }

 private:
  static void WeakCallback(
      const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    if (Traits::kCallbackType != kNotWeak) {
      PersistentValueMap<K, V, Traits>* persistentValueMap =
          Traits::MapFromWeakCallbackInfo(data);
      K key = Traits::KeyFromWeakCallbackInfo(data);
      Traits::Dispose(data.GetIsolate(),
                      persistentValueMap->Remove(key).Pass(), key);
      Traits::DisposeCallbackData(data.GetParameter());
    }
  }
};


template <typename K, typename V, typename Traits>
class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
 public:
  explicit GlobalValueMap(Isolate* isolate)
      : PersistentValueMapBase<K, V, Traits>(isolate) {}
  GlobalValueMap(Isolate* isolate, const char* label)
      : PersistentValueMapBase<K, V, Traits>(isolate, label) {}

  typedef
      typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
          PersistentValueReference;

  /**
   * Put value into map. Depending on Traits::kIsWeak, the value will be held
   * by the map strongly or weakly.
   * Returns old value as Global.
   */
  Global<V> Set(const K& key, Local<V> value) {
    Global<V> persistent(this->isolate(), value);
    return SetUnique(key, &persistent);
  }

  /**
   * Put value into map, like Set(const K&, Local<V>).
   */
  Global<V> Set(const K& key, Global<V> value) {
    return SetUnique(key, &value);
  }

  /**
   * Put the value into the map, and set the 'weak' callback when demanded
   * by the Traits class.
   */
  Global<V> SetUnique(const K& key, Global<V>* persistent) {
    if (Traits::kCallbackType == kNotWeak) {
      this->AnnotateStrongRetainer(persistent);
    } else {
      WeakCallbackType callback_type =
          Traits::kCallbackType == kWeakWithInternalFields
              ? WeakCallbackType::kInternalFields
              : WeakCallbackType::kParameter;
      Local<V> value(Local<V>::New(this->isolate(), *persistent));
      persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
          Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
          callback_type);
    }
    PersistentContainerValue old_value =
        Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    return this->Release(old_value).Pass();
  }

  /**
   * Put a value into the map and update the reference.
   * Restrictions of GetReference apply here as well.
   */
  Global<V> Set(const K& key, Global<V> value,
                PersistentValueReference* reference) {
    *reference = this->Leak(&value);
    return SetUnique(key, &value);
  }

 private:
  static void OnWeakCallback(
      const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    if (Traits::kCallbackType != kNotWeak) {
      auto map = Traits::MapFromWeakCallbackInfo(data);
      K key = Traits::KeyFromWeakCallbackInfo(data);
      map->RemoveWeak(key);
      Traits::OnWeakCallback(data);
      data.SetSecondPassCallback(SecondWeakCallback);
    }
  }

  static void SecondWeakCallback(
      const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    Traits::DisposeWeak(data);
  }
};


/**
 * A map that uses Global as value and std::map as the backing
 * implementation. Persistents are held non-weak.
 *
 * C++11 embedders don't need this class, as they can use
 * Global directly in std containers.
 */
template<typename K, typename V,
    typename Traits = DefaultPersistentValueMapTraits<K, V> >
class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
 public:
  explicit StdPersistentValueMap(Isolate* isolate)
      : PersistentValueMap<K, V, Traits>(isolate) {}
};


/**
 * A map that uses Global as value and std::map as the backing
 * implementation. Globals are held non-weak.
 *
 * C++11 embedders don't need this class, as they can use
 * Global directly in std containers.
 */
template <typename K, typename V,
          typename Traits = DefaultGlobalMapTraits<K, V> >
class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
 public:
  explicit StdGlobalValueMap(Isolate* isolate)
      : GlobalValueMap<K, V, Traits>(isolate) {}
};


class DefaultPersistentValueVectorTraits {
 public:
  typedef std::vector<PersistentContainerValue> Impl;

  static void Append(Impl* impl, PersistentContainerValue value) {
    impl->push_back(value);
  }
  static bool IsEmpty(const Impl* impl) {
    return impl->empty();
  }
  static size_t Size(const Impl* impl) {
    return impl->size();
  }
  static PersistentContainerValue Get(const Impl* impl, size_t i) {
    return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
  }
  static void ReserveCapacity(Impl* impl, size_t capacity) {
    impl->reserve(capacity);
  }
  static void Clear(Impl* impl) {
    impl->clear();
  }
};


/**
 * A vector wrapper that safely stores Global values.
 * C++11 embedders don't need this class, as they can use Global
 * directly in std containers.
 *
 * This class relies on a backing vector implementation, whose type and methods
 * are described by the Traits class. The backing map will handle values of type
 * PersistentContainerValue, with all conversion into and out of V8
 * handles being transparently handled by this class.
 */
template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
class PersistentValueVector {
 public:
  explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }

  ~PersistentValueVector() {
    Clear();
  }

  /**
   * Append a value to the vector.
   */
  void Append(Local<V> value) {
    Global<V> persistent(isolate_, value);
    Traits::Append(&impl_, ClearAndLeak(&persistent));
  }

  /**
   * Append a persistent's value to the vector.
   */
  void Append(Global<V> persistent) {
    Traits::Append(&impl_, ClearAndLeak(&persistent));
  }

  /**
   * Are there any values in the vector?
   */
  bool IsEmpty() const {
    return Traits::IsEmpty(&impl_);
  }

  /**
   * How many elements are in the vector?
   */
  size_t Size() const {
    return Traits::Size(&impl_);
  }

  /**
   * Retrieve the i-th value in the vector.
   */
  Local<V> Get(size_t index) const {
    return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
  }

  /**
   * Remove all elements from the vector.
   */
  void Clear() {
    size_t length = Traits::Size(&impl_);
    for (size_t i = 0; i < length; i++) {
      Global<V> p;
      p.val_ = FromVal(Traits::Get(&impl_, i));
    }
    Traits::Clear(&impl_);
  }

  /**
   * Reserve capacity in the vector.
   * (Efficiency gains depend on the backing implementation.)
   */
  void ReserveCapacity(size_t capacity) {
    Traits::ReserveCapacity(&impl_, capacity);
  }

 private:
  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
    V* v = persistent->val_;
    persistent->val_ = nullptr;
    return reinterpret_cast<PersistentContainerValue>(v);
  }

  static V* FromVal(PersistentContainerValue v) {
    return reinterpret_cast<V*>(v);
  }

  Isolate* isolate_;
  typename Traits::Impl impl_;
};

}  // namespace v8

#endif  // V8_UTIL_H
