262 lines
7.7 KiB
C++
262 lines
7.7 KiB
C++
|
|
#pragma once
|
|
|
|
#if !defined(MIJIN_CONTAINER_VECTOR_MAP_HPP_INCLUDED)
|
|
#define MIJIN_CONTAINER_VECTOR_MAP_HPP_INCLUDED 1
|
|
|
|
#include <vector>
|
|
#include "./boxed_object.hpp"
|
|
#include "./optional.hpp"
|
|
|
|
#include "../internal/common.hpp"
|
|
|
|
namespace mijin
|
|
{
|
|
template<typename TKey, typename TValue>
|
|
struct VectorMapIterator
|
|
{
|
|
public:
|
|
using difference_type = std::ptrdiff_t;
|
|
private:
|
|
Optional<std::pair<TKey&, TValue&>> ref_;
|
|
public:
|
|
VectorMapIterator(TKey* key, TValue* value)
|
|
{
|
|
ref_.emplace(std::tie(*key, *value));
|
|
}
|
|
VectorMapIterator(const VectorMapIterator& other) MIJIN_NOEXCEPT : VectorMapIterator(&other.ref_->first, &other.ref_->second) {}
|
|
~VectorMapIterator() noexcept
|
|
{
|
|
ref_.reset();
|
|
}
|
|
|
|
VectorMapIterator& operator=(const VectorMapIterator& other) MIJIN_NOEXCEPT
|
|
{
|
|
if (this != &other)
|
|
{
|
|
ref_.reset();
|
|
ref_.emplace(std::tie(other.ref_->first, other.ref_->second));
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const VectorMapIterator& other) const MIJIN_NOEXCEPT { return &ref_->first == &other.ref_->first; }
|
|
bool operator!=(const VectorMapIterator& other) const MIJIN_NOEXCEPT { return &ref_->first != &other.ref_->first; }
|
|
|
|
std::pair<TKey&, TValue&> operator*() const MIJIN_NOEXCEPT
|
|
{
|
|
return *ref_;
|
|
}
|
|
const std::pair<TKey&, TValue&>* operator->() const MIJIN_NOEXCEPT
|
|
{
|
|
return &*ref_;
|
|
}
|
|
|
|
VectorMapIterator& operator++() MIJIN_NOEXCEPT
|
|
{
|
|
TKey* oldKey = &ref_->first;
|
|
TValue* oldValue = &ref_->second;
|
|
ref_.reset();
|
|
ref_.emplace(std::tie(*(++oldKey), *(++oldValue)));
|
|
return *this;
|
|
}
|
|
|
|
VectorMapIterator operator++(int) const MIJIN_NOEXCEPT
|
|
{
|
|
VectorMapIterator copy(*this);
|
|
++(*this);
|
|
return copy;
|
|
}
|
|
|
|
VectorMapIterator& operator--() MIJIN_NOEXCEPT
|
|
{
|
|
TKey* oldKey = &ref_->first;
|
|
TValue* oldValue = &ref_->second;
|
|
ref_.reset();
|
|
ref_.emplace(std::tie(*(--oldKey), *(--oldValue)));
|
|
return *this;
|
|
}
|
|
|
|
VectorMapIterator operator--(int) const MIJIN_NOEXCEPT
|
|
{
|
|
VectorMapIterator copy(*this);
|
|
--(*this);
|
|
return copy;
|
|
}
|
|
|
|
VectorMapIterator operator+(difference_type diff) const MIJIN_NOEXCEPT
|
|
{
|
|
return VectorMapIterator(&ref_->first + diff, &ref_->second + diff);
|
|
}
|
|
|
|
VectorMapIterator operator-(difference_type diff) const MIJIN_NOEXCEPT
|
|
{
|
|
return VectorMapIterator(&ref_->first - diff, &ref_->second - diff);
|
|
}
|
|
|
|
difference_type operator-(const VectorMapIterator& other) const MIJIN_NOEXCEPT
|
|
{
|
|
return &ref_->first - &other.ref_->first;
|
|
}
|
|
};
|
|
|
|
template<typename TKey, typename TValue, typename TKeyAllocator = std::allocator<TKey>, typename TValueAllocator = std::allocator<TValue>>
|
|
class VectorMap
|
|
{
|
|
public:
|
|
using key_type = TKey;
|
|
using mapped_type = TValue;
|
|
using value_type = std::pair<const TKey, TValue>;
|
|
using size_type = std::size_t;
|
|
using difference_type = std::ptrdiff_t;
|
|
using reference = value_type&;
|
|
using const_reference = const value_type&;
|
|
using iterator = VectorMapIterator<const TKey, TValue>;
|
|
using const_iterator = VectorMapIterator<const TKey, const TValue>;
|
|
private:
|
|
std::vector<TKey, TKeyAllocator> keys_;
|
|
std::vector<TValue, TValueAllocator> values_;
|
|
public:
|
|
VectorMap() noexcept = default;
|
|
VectorMap(const VectorMap&) = default;
|
|
VectorMap(VectorMap&&) MIJIN_NOEXCEPT = default;
|
|
|
|
VectorMap& operator=(const VectorMap&) = default;
|
|
VectorMap& operator=(VectorMap&&) MIJIN_NOEXCEPT = default;
|
|
auto operator<=>(const VectorMap& other) const noexcept = default;
|
|
|
|
TValue& operator[](const TKey& key)
|
|
{
|
|
auto it = find(key);
|
|
if (it != end())
|
|
{
|
|
return it->second;
|
|
}
|
|
return emplace(key, TValue()).first->second;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
iterator begin() MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
|
[[nodiscard]]
|
|
const_iterator begin() const MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
|
[[nodiscard]]
|
|
const_iterator cbegin() const MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
|
[[nodiscard]]
|
|
iterator end() MIJIN_NOEXCEPT { return {keys_.data() + keys_.size(), values_.data() + values_.size()}; }
|
|
[[nodiscard]]
|
|
const_iterator end() const MIJIN_NOEXCEPT { return {keys_.data() + keys_.size(), values_.data() + values_.size()}; }
|
|
[[nodiscard]]
|
|
const_iterator cend() const MIJIN_NOEXCEPT { return {keys_.data() + keys_.size(), values_.data() + values_.size()}; }
|
|
|
|
[[nodiscard]]
|
|
TValue& at(const TKey& key)
|
|
{
|
|
auto it = find(key);
|
|
if (it == end())
|
|
{
|
|
throw std::out_of_range("key not found in map");
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
const TValue& at(const TKey& key) const
|
|
{
|
|
auto it = find(key);
|
|
if (it == end())
|
|
{
|
|
throw std::out_of_range("key not found in map");
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool empty() const MIJIN_NOEXCEPT { return keys_.empty(); }
|
|
[[nodiscard]]
|
|
size_type size() const MIJIN_NOEXCEPT { return keys_.size(); }
|
|
[[nodiscard]]
|
|
size_type max_size() const MIJIN_NOEXCEPT { return std::min(keys_.max_size(), values_.max_size()); }
|
|
|
|
void clear()
|
|
{
|
|
keys_.clear();
|
|
values_.clear();
|
|
}
|
|
|
|
template<typename... TArgs>
|
|
std::pair<iterator, bool> emplace(TArgs&&... args)
|
|
{
|
|
std::pair<TKey, TValue> asPair(std::forward<TArgs>(args)...);
|
|
auto it = find(asPair.first);
|
|
if (it != end())
|
|
{
|
|
return std::make_pair(std::move(it), false);
|
|
}
|
|
keys_.push_back(std::move(asPair.first));
|
|
values_.push_back(std::move(asPair.second));
|
|
return std::make_pair(iterator(&keys_.back(), &values_.back()), true);
|
|
}
|
|
|
|
iterator erase(iterator pos) MIJIN_NOEXCEPT
|
|
{
|
|
const std::ptrdiff_t idx = &pos->first - &keys_[0];
|
|
return eraseImpl(idx);
|
|
}
|
|
|
|
iterator erase(const_iterator pos) MIJIN_NOEXCEPT
|
|
{
|
|
const std::ptrdiff_t idx = &pos->first - &keys_[0];
|
|
return eraseImpl(idx);
|
|
}
|
|
|
|
iterator erase(iterator first, iterator last) MIJIN_NOEXCEPT
|
|
{
|
|
const std::ptrdiff_t idx = &first->first - &keys_[0];
|
|
const std::ptrdiff_t count = last - first;
|
|
return eraseImpl(idx, count);
|
|
}
|
|
|
|
iterator erase(const_iterator first, const_iterator last) MIJIN_NOEXCEPT
|
|
{
|
|
const std::ptrdiff_t idx = &first->first - &keys_[0];
|
|
const std::ptrdiff_t count = last - first;
|
|
return eraseImpl(idx, count);
|
|
}
|
|
|
|
iterator find(const TKey& key) MIJIN_NOEXCEPT
|
|
{
|
|
for (std::size_t idx = 0; idx < keys_.size(); ++idx)
|
|
{
|
|
if (keys_[idx] == key)
|
|
{
|
|
return iterator(&keys_[idx], &values_[idx]);
|
|
}
|
|
}
|
|
return end();
|
|
}
|
|
|
|
const_iterator find(const TKey& key) const MIJIN_NOEXCEPT
|
|
{
|
|
for (std::size_t idx = 0; idx < keys_.size(); ++idx)
|
|
{
|
|
if (keys_[idx] == key)
|
|
{
|
|
return iterator(&keys_[idx], &values_[idx]);
|
|
}
|
|
}
|
|
return end();
|
|
}
|
|
private:
|
|
iterator eraseImpl(std::ptrdiff_t idx, std::ptrdiff_t count = 1) MIJIN_NOEXCEPT
|
|
{
|
|
auto itKey = keys_.begin() + idx;
|
|
auto itValue = values_.begin() + idx;
|
|
itKey = keys_.erase(itKey, itKey + count);
|
|
itValue = values_.erase(itValue, itValue + count);
|
|
return itKey == keys_.end() ? end() : iterator(&*itKey, &*itValue); // cannot dereference the iterators if the last element was removed
|
|
}
|
|
};
|
|
} // namespace mijin
|
|
|
|
#endif // MIJIN_CONTAINER_VECTOR_MAP_HPP_INCLUDED
|