Program Listing for File VectorMap.hpp

Return to documentation for file (include/uitsl/datastructs/VectorMap.hpp)

#pragma once
#ifndef UITSL_DATASTRUCTS_VECTORMAP_HPP_INCLUDE
#define UITSL_DATASTRUCTS_VECTORMAP_HPP_INCLUDE

#include <functional>
#include <memory>
#include <utility>

#include "../../../third-party/Empirical/source/base/optional.h"
#include "../../../third-party/Empirical/source/base/vector.h"

namespace uitsl {

namespace internal {

template<typename Key, typename T>
class VectorMapIterator
: public emp::vector<std::reference_wrapper<
  std::pair<const Key, T>
>>::iterator {

public:
  using value_type = std::pair<const Key, T>;

private:
  using parent_t = typename emp::vector<std::reference_wrapper<
    value_type
  >>::iterator;

public:

  VectorMapIterator() = default;
  VectorMapIterator(const parent_t& val) : parent_t(val) { ; }

  value_type& operator*() { return parent_t::operator*().get(); }

  const value_type& operator*() const { return parent_t::operator*().get(); }

  value_type* operator->() { return &operator*(); }

  const value_type* operator->() const { return &operator*(); }


};

template<typename Key, typename T>
class VectorMapConstIterator
: public emp::vector<std::reference_wrapper<
  const std::pair<const Key, T>
>>::const_iterator {

public:
  using value_type = std::pair<const Key, T>;

private:
  using parent_t = typename emp::vector<std::reference_wrapper<
    const value_type
  >>::const_iterator;

public:

  VectorMapConstIterator() = default;
  VectorMapConstIterator(const parent_t& val) : parent_t(val) { ; }

  const value_type& operator*() const { return parent_t::operator*().get(); }

  const value_type* operator->() const { return &operator*(); }

};

} // namespace internal

template<typename Key, typename T>
class VectorMap {

public:
  using key_type = Key;
  using mapped_type = T;
  using value_type = std::pair<const Key, T>;
private:
  using container_t = emp::vector< emp::optional< value_type > >;
public:
  using difference_type = typename container_t::difference_type;
  using size_type = typename container_t::size_type;
  using reference = value_type&;
  using const_reference = const value_type&;
  using allocator_type = typename container_t::allocator_type;
  using pointer = typename std::allocator_traits<allocator_type>::pointer;
  using const_pointer = typename std::allocator_traits<
    allocator_type
  >::const_pointer;
  using iterator = internal::VectorMapIterator<Key, T>;
  using const_iterator = internal::VectorMapConstIterator<Key, T>;

private:

  container_t data;

  size_t num_items{};

  emp::optional<emp::vector<std::reference_wrapper<
    value_type
  >>> view;
  mutable emp::optional<emp::vector<std::reference_wrapper<
    const value_type
  >>> const_view;

  void PrepareView() {
    if (!view.has_value()) {
      view.emplace();
      for (auto& item : data) {
        if ( item.has_value() ) view->emplace_back( *item );
      }
    }
  }

  void PrepareConstView() const {
    if (!const_view.has_value()) {
      const_view.emplace();
      for (const auto& item : data) {
        if ( item.has_value() ) const_view->emplace_back( *item );
      }
    }
  }

  void InvalidateViews() { view.reset(); const_view.reset(); }

public:

  T& operator[](const Key i) {
    emp_assert( i >= 0 );

    // if needed, make space
    if (static_cast<size_t>(i) >= data.size()) data.resize(i + 1);

    // if needed, set up new value
    if ( !data[i].has_value() ) {
      data[i].emplace(
        std::piecewise_construct,
        std::forward_as_tuple(i),
        std::forward_as_tuple()
      );
      ++num_items;
    }

    // clear cached views
    InvalidateViews();

    return at(i);
  }

  T& at(const Key i) { return data[i]->second; }

  const T& at(const Key i) const { return data[i]->second; }

  iterator begin() {
    PrepareView();
    return iterator( std::begin( *view ) );
  }

  iterator end() {
    PrepareView();
    return iterator( std::end( *view ) );
  }

  const_iterator begin() const {
    PrepareConstView();
    return const_iterator( std::cbegin( *const_view ) );
  }

  const_iterator end() const {
    PrepareConstView();
    return const_iterator( std::cend( *const_view ) );
  }

  const_iterator cbegin() const {
    PrepareConstView();
    return const_iterator( std::cbegin( *const_view ) );
  }

  const_iterator cend() const {
    PrepareConstView();
    return const_iterator( std::cend( *const_view ) );
  }

  size_t size() const { return num_items; }

  size_t empty() const { return !size(); }

  void erase(const Key i) { data[i].reset(); --num_items; InvalidateViews(); }

  void clear() { data.clear(); num_items = 0; InvalidateViews(); }

  size_t count(const Key i) const {
    return i < data.size() && data[i].has_value();
  }

  bool contains(const Key i) const { return count(i); }

};

} // namespace uitsl

#endif // #ifndef UITSL_DATASTRUCTS_VECTORMAP_HPP_INCLUDE