diff --git a/source/mijin/container/vector_map.hpp b/source/mijin/container/vector_map.hpp new file mode 100644 index 0000000..af99853 --- /dev/null +++ b/source/mijin/container/vector_map.hpp @@ -0,0 +1,257 @@ + +#pragma once + +#if !defined(MIJIN_CONTAINER_VECTOR_MAP_HPP_INCLUDED) +#define MIJIN_CONTAINER_VECTOR_MAP_HPP_INCLUDED 1 + +#include +#include "./boxed_object.hpp" +#include "./optional.hpp" + +#include "../internal/common.hpp" + +namespace mijin +{ +template +struct VectorMapIterator +{ +public: + using difference_type = std::ptrdiff_t; +private: + Optional> 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 operator*() const MIJIN_NOEXCEPT + { + return *ref_; + } + const std::pair* 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 TValueAllocator = std::allocator> +class VectorMap +{ +public: + using key_type = TKey; + using mapped_type = TValue; + using value_type = std::pair; + 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; + using const_iterator = VectorMapIterator; +private: + std::vector keys_; + std::vector values_; +public: + 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 + std::pair emplace(TArgs&&... args) + { + std::pair asPair(std::forward(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