// Copyright 2020 The Fuchsia 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 SRC_LIB_VMO_STORE_GROWABLE_SLAB_H_
#define SRC_LIB_VMO_STORE_GROWABLE_SLAB_H_

#include <lib/stdcompat/optional.h>
#include <zircon/status.h>

#include <limits>

#include <fbl/vector.h>

namespace vmo_store {

// A slab data structure to store items of type `T` keyed by `KeyType`.
//
// `KeyType` must be an integer type, it is used to index an underlying vector storage of `T`.
//
// `GrowableSlab` is always created with zero capacity and can grow in capacity up to the maximum
// namespace of `std::numeric_limits<KeyType>::max()-1`.
//
// `GrowableSlab` acts as a container for `T` with O(1) guarantee on `Push`, `Insert`, `Get`, and
// `Erase` operations, and O(capacity) on `Grow`.
//
// This structure is not thread-safe.
template <typename T, typename KeyType = size_t>
class GrowableSlab {
 public:
  static_assert(!std::numeric_limits<KeyType>::is_signed);
  static_assert(std::numeric_limits<KeyType>::is_integer);

  class Iterator;

  GrowableSlab() = default;

  // Returns the currently allocated capacity of the slab.
  KeyType capacity() const { return static_cast<KeyType>(slots_.size()); }
  // Returns the number of items held by the slab.
  KeyType count() const { return used_; }
  // Returns the number of free slots available on the slab.
  KeyType free() const { return capacity() - count(); }

  bool is_empty() const { return used_ == 0; }

  // Grows the slab by a fixed factor if there are no more free slots.
  //
  // Note that the worst-case complexity for `Grow` is O(new_capacity).
  void Grow() {
    if (free() == 0) {
      GrowTo(capacity() == 0 ? 1 : capacity() * 2);
    }
  }

  void GrowTo(KeyType capacity) {
    slots_.reserve(capacity);
    while (slots_.size() != slots_.capacity()) {
      auto key = static_cast<KeyType>(slots_.size());
      slots_.push_back(Slot());
      ListInsert(&free_list_, key);
    }
  }

  // Inserts `value` on the slab, using a key from the available pool.
  // Returns a valid `KeyType` if there was an available slot to put `value` in.
  [[nodiscard]] cpp17::optional<KeyType> Push(T&& value) {
    KeyType key = free_list_.head;
    if (Insert(key, std::move(value)) != ZX_OK) {
      return cpp17::optional<KeyType>();
    }
    return key;
  }

  // Attempts to insert `value` at slot `key` in the slab.
  // Returns `ZX_ERR_OUT_OF_RANGE` if `key` is not in the valid namespace.
  // Returns `ZX_ERR_ALREADY_EXISTS` if `key` is already occupied by another value.
  [[nodiscard]] zx_status_t Insert(KeyType key, T&& value) {
    if (key >= static_cast<KeyType>(slots_.size())) {
      return ZX_ERR_OUT_OF_RANGE;
    }
    auto* slot = &slots_[key];
    if (slot->value.has_value()) {
      return ZX_ERR_ALREADY_EXISTS;
    }

    slot->value.emplace(std::move(value));
    ListRemove(&free_list_, key);
    ListInsert(&used_list_, key);

    used_++;
    return ZX_OK;
  }

  // Gets the value `T` stored at `key`.
  // Returns `nullptr` if `key` is invalid or the slot is not occupied.
  T* Get(KeyType key) {
    auto* slot = GetOccupiedSlot(key);
    if (!slot) {
      return nullptr;
    }
    return &slot->value.value();
  }

  // Erases the value at `key`, freeing the slot and returning the stored value.
  // `Erase` returns a valid `T` if `key` pointed to an occupied slot.
  cpp17::optional<T> Erase(KeyType key) {
    auto* slot = GetOccupiedSlot(key);
    if (!slot) {
      return cpp17::optional<T>();
    }
    cpp17::optional<T> ret(std::move(slot->value.value()));
    slot->value.reset();

    ListRemove(&used_list_, key);
    ListInsert(&free_list_, key);

    used_--;
    return ret;
  }

  // Removes all currently stored values from the slab, returning all slots to the free-list.
  void Clear() {
    while (used_ != 0) {
      Erase(used_list_.head);
    }
  }

  // TODO(https://fxbug.dev/42078992): Create a separate ConstIterator class for const
  // begin() and end() iterators.
  Iterator begin() { return Iterator(this); }

  Iterator end() { return Iterator(); }

  struct Slot {
    Slot() : next(kSentinel), prev(kSentinel) {}

    Slot(Slot&& other) noexcept = default;
    Slot(const Slot& other) = delete;
    KeyType next;
    KeyType prev;
    cpp17::optional<T> value;
  };

  class Iterator {
   public:
    Iterator() = default;

    explicit Iterator(GrowableSlab* parent) : parent_(parent), index_(parent->used_list_.head) {}

    Iterator(const Iterator& other) : parent_(other.parent_), index_(other.index_) {}

    Iterator& operator=(const Iterator& other) {
      parent_ = other.parent_;
      index_ = other.index_;
      return *this;
    }

    bool IsValid() const { return parent_ != nullptr && index_ != kSentinel; }

    bool operator==(const Iterator& other) const { return index_ == other.index_; }

    bool operator!=(const Iterator& other) const { return index_ != other.index_; }

    // Prefix
    Iterator& operator++() {
      if (IsValid()) {
        index_ = parent_->slots_[index_].next;
      }

      return *this;
    }

    // Postfix
    Iterator operator++(int) {
      Iterator ret(*this);
      ++(*this);
      return ret;
    }

    T& operator*() {
      ZX_DEBUG_ASSERT(IsValid());
      return parent_->slots_[index_].value.value();
    }

    T* operator->() {
      ZX_DEBUG_ASSERT(IsValid());
      return &parent_->slots_[index_].value.value();
    }

    KeyType key() const { return index_; }

   private:
    Iterator(GrowableSlab* parent, size_t index) : parent_(parent), index_(index) {}

    // Pointer to parent slab, not owned.
    GrowableSlab<T, KeyType>* const parent_ = nullptr;
    KeyType index_ = kSentinel;
  };

  DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(GrowableSlab);

 private:
  static constexpr KeyType kSentinel = std::numeric_limits<KeyType>::max();
  // We keep two `List`s in `GrowableSlab`: a list of free slots in the vector, and a list of used
  // slots which contains valid stored `T`s.
  // The list itself is defined by head and tail indices, and each node contains the next and
  // previous node indices (see `Slot`). This index-based implementation is used instead of the fbl
  // DLL implementation so we can `Grow` the underlying fbl::Vector without having to update any
  // pointers - the fbl DLL is based on pointers and growing the fbl::Vector may cause things to
  // move around in memory.
  struct List {
    KeyType head;
    KeyType tail;
  };

  inline void ListRemove(List* list, KeyType key) {
    auto* slot = &slots_[key];
    if (slot->prev != kSentinel) {
      slots_[slot->prev].next = slot->next;
    }
    if (slot->next != kSentinel) {
      slots_[slot->next].prev = slot->prev;
    }
    if (list->head == key) {
      list->head = slot->next;
    }
    if (list->tail == key) {
      list->tail = slot->prev;
    }
    slot->next = kSentinel;
    slot->prev = kSentinel;
  }

  inline void ListInsert(List* list, KeyType key) {
    auto* slot = &slots_[key];
    ZX_DEBUG_ASSERT(slot->prev == kSentinel);
    ZX_DEBUG_ASSERT(slot->next == kSentinel);
    if (list->tail != kSentinel) {
      slots_[list->tail].next = key;
    }
    slot->prev = list->tail;
    list->tail = key;
    if (slot->prev == kSentinel) {
      list->head = key;
    }
  }

  Slot* GetOccupiedSlot(KeyType key) {
    if (key >= slots_.size()) {
      return nullptr;
    }
    auto* slot = &slots_[key];
    if (!slot->value.has_value()) {
      return nullptr;
    }
    return slot;
  }

  List used_list_ = {kSentinel, kSentinel};
  List free_list_ = {kSentinel, kSentinel};
  KeyType used_ = 0;
  fbl::Vector<Slot> slots_;
};

}  // namespace vmo_store

#endif  // SRC_LIB_VMO_STORE_GROWABLE_SLAB_H_
