Made VectorMap constexpr.
This commit is contained in:
@@ -5,12 +5,10 @@
|
||||
#define MIJIN_CONTAINER_VECTOR_MAP_HPP_INCLUDED 1
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "./boxed_object.hpp"
|
||||
#include "./optional.hpp"
|
||||
|
||||
#include "../internal/common.hpp"
|
||||
|
||||
namespace mijin
|
||||
@@ -19,87 +17,85 @@ template<typename TKey, typename TValue>
|
||||
struct VectorMapIterator
|
||||
{
|
||||
public:
|
||||
using key_t = TKey;
|
||||
using value_t = TValue;
|
||||
using pair_t = std::pair<const key_t&, value_t&>;
|
||||
struct Pointer
|
||||
{
|
||||
pair_t pair;
|
||||
|
||||
constexpr pair_t* operator->() { return &pair; }
|
||||
};
|
||||
|
||||
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = std::pair<key_t&, value_t&>;
|
||||
using pointer = Pointer;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
private:
|
||||
Optional<std::pair<TKey&, TValue&>> ref_;
|
||||
const key_t* key_;
|
||||
value_t* value_;
|
||||
public:
|
||||
VectorMapIterator(TKey* key, TValue* value)
|
||||
constexpr VectorMapIterator(const key_t* key, value_t* value) MIJIN_NOEXCEPT : key_(key), value_(value)
|
||||
{
|
||||
ref_.emplace(std::tie(*key, *value));
|
||||
}
|
||||
VectorMapIterator(const VectorMapIterator& other) MIJIN_NOEXCEPT : VectorMapIterator(&other.ref_->first, &other.ref_->second) {}
|
||||
~VectorMapIterator() noexcept
|
||||
constexpr VectorMapIterator(const VectorMapIterator& other) noexcept = default;
|
||||
constexpr VectorMapIterator& operator=(const VectorMapIterator& other) MIJIN_NOEXCEPT = default;
|
||||
|
||||
constexpr bool operator==(const VectorMapIterator& other) const MIJIN_NOEXCEPT { return key_ == other.key_; }
|
||||
constexpr bool operator!=(const VectorMapIterator& other) const MIJIN_NOEXCEPT { return key_ != other.key_; }
|
||||
|
||||
constexpr reference operator*() const MIJIN_NOEXCEPT
|
||||
{
|
||||
ref_.reset();
|
||||
return std::tie(*key_, *value_);
|
||||
}
|
||||
constexpr pointer operator->() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return {std::tie(*key_, *value_)};
|
||||
}
|
||||
|
||||
VectorMapIterator& operator=(const VectorMapIterator& other) MIJIN_NOEXCEPT
|
||||
constexpr VectorMapIterator& operator++() 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)));
|
||||
++key_;
|
||||
++value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VectorMapIterator operator++(int) const MIJIN_NOEXCEPT
|
||||
constexpr VectorMapIterator operator++(int) const MIJIN_NOEXCEPT
|
||||
{
|
||||
VectorMapIterator copy(*this);
|
||||
++(*this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
VectorMapIterator& operator--() MIJIN_NOEXCEPT
|
||||
constexpr VectorMapIterator& operator--() MIJIN_NOEXCEPT
|
||||
{
|
||||
TKey* oldKey = &ref_->first;
|
||||
TValue* oldValue = &ref_->second;
|
||||
ref_.reset();
|
||||
ref_.emplace(std::tie(*(--oldKey), *(--oldValue)));
|
||||
--key_;
|
||||
--value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VectorMapIterator operator--(int) const MIJIN_NOEXCEPT
|
||||
constexpr VectorMapIterator operator--(int) const MIJIN_NOEXCEPT
|
||||
{
|
||||
VectorMapIterator copy(*this);
|
||||
--(*this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
VectorMapIterator operator+(difference_type diff) const MIJIN_NOEXCEPT
|
||||
constexpr VectorMapIterator operator+(difference_type diff) const MIJIN_NOEXCEPT
|
||||
{
|
||||
return VectorMapIterator(&ref_->first + diff, &ref_->second + diff);
|
||||
return VectorMapIterator(key_ + diff, value_ + diff);
|
||||
}
|
||||
|
||||
VectorMapIterator operator-(difference_type diff) const MIJIN_NOEXCEPT
|
||||
constexpr VectorMapIterator operator-(difference_type diff) const MIJIN_NOEXCEPT
|
||||
{
|
||||
return VectorMapIterator(&ref_->first - diff, &ref_->second - diff);
|
||||
return VectorMapIterator(key_ - diff, value_ - diff);
|
||||
}
|
||||
|
||||
difference_type operator-(const VectorMapIterator& other) const MIJIN_NOEXCEPT
|
||||
constexpr difference_type operator-(const VectorMapIterator& other) const MIJIN_NOEXCEPT
|
||||
{
|
||||
return &ref_->first - &other.ref_->first;
|
||||
return key_ - other.key_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -120,61 +116,61 @@ private:
|
||||
std::vector<TKey, TKeyAllocator> keys_;
|
||||
std::vector<TValue, TValueAllocator> values_;
|
||||
public:
|
||||
explicit VectorMap(TKeyAllocator keyAllocator = {})
|
||||
explicit constexpr VectorMap(TKeyAllocator keyAllocator = {})
|
||||
MIJIN_NOEXCEPT_IF((std::is_nothrow_move_constructible_v<TKeyAllocator> && std::is_nothrow_constructible_v<TValueAllocator, const TKeyAllocator&>))
|
||||
: keys_(std::move(keyAllocator)), values_(TValueAllocator(keys_.get_allocator())) {}
|
||||
VectorMap(TKeyAllocator keyAllocator, TValueAllocator valueAllocator)
|
||||
constexpr VectorMap(TKeyAllocator keyAllocator, TValueAllocator valueAllocator)
|
||||
MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<TKeyAllocator> && std::is_nothrow_move_constructible_v<TValueAllocator>)
|
||||
: keys_(std::move(keyAllocator)), values_(std::move(valueAllocator)) {}
|
||||
VectorMap(const VectorMap&) = default;
|
||||
VectorMap(VectorMap&&) = default;
|
||||
constexpr VectorMap(const VectorMap&) = default;
|
||||
constexpr VectorMap(VectorMap&&) = default;
|
||||
|
||||
VectorMap& operator=(const VectorMap&) = default;
|
||||
VectorMap& operator=(VectorMap&&) = default;
|
||||
auto operator<=>(const VectorMap& other) const noexcept = default;
|
||||
constexpr VectorMap& operator=(const VectorMap&) = default;
|
||||
constexpr VectorMap& operator=(VectorMap&&) = default;
|
||||
constexpr auto operator<=>(const VectorMap& other) const noexcept = default;
|
||||
|
||||
template<typename TIndex>
|
||||
TValue& operator[](const TIndex& key)
|
||||
constexpr mapped_type& operator[](const TIndex& key)
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it != end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return emplace(key, TValue()).first->second;
|
||||
return emplace(key, mapped_type()).first->second;
|
||||
}
|
||||
|
||||
template<typename TIndex>
|
||||
const TValue& operator[](const TIndex& key) const
|
||||
constexpr const mapped_type& operator[](const TIndex& key) const
|
||||
{
|
||||
return at(key);
|
||||
}
|
||||
|
||||
TValue& operator[](TKey&& key)
|
||||
constexpr mapped_type& operator[](key_type&& key)
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it != end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return emplace(std::move(key), TValue()).first->second;
|
||||
return emplace(std::move(key), mapped_type()).first->second;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
iterator begin() MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
||||
constexpr iterator begin() MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
||||
[[nodiscard]]
|
||||
const_iterator begin() const MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
||||
constexpr const_iterator begin() const MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
||||
[[nodiscard]]
|
||||
const_iterator cbegin() const MIJIN_NOEXCEPT { return {keys_.data(), values_.data()}; }
|
||||
constexpr 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()}; }
|
||||
constexpr 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()}; }
|
||||
constexpr 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()}; }
|
||||
constexpr const_iterator cend() const MIJIN_NOEXCEPT { return {keys_.data() + keys_.size(), values_.data() + values_.size()}; }
|
||||
|
||||
[[nodiscard]]
|
||||
TValue& at(const TKey& key)
|
||||
constexpr mapped_type& at(const key_type& key)
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
@@ -185,7 +181,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const TValue& at(const TKey& key) const
|
||||
constexpr const mapped_type& at(const key_type& key) const
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it == end())
|
||||
@@ -196,27 +192,29 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool empty() const MIJIN_NOEXCEPT { return keys_.empty(); }
|
||||
constexpr bool empty() const MIJIN_NOEXCEPT { return keys_.empty(); }
|
||||
[[nodiscard]]
|
||||
size_type size() const MIJIN_NOEXCEPT { return keys_.size(); }
|
||||
constexpr 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 reserve(std::size_t size)
|
||||
constexpr size_type max_size() const MIJIN_NOEXCEPT { return std::min(keys_.max_size(), values_.max_size()); }
|
||||
constexpr void reserve(std::size_t size)
|
||||
{
|
||||
keys_.reserve(size);
|
||||
values_.reserve(size);
|
||||
}
|
||||
|
||||
void clear()
|
||||
constexpr void clear()
|
||||
{
|
||||
keys_.clear();
|
||||
values_.clear();
|
||||
}
|
||||
|
||||
template<typename... TArgs>
|
||||
std::pair<iterator, bool> emplace(TArgs&&... args)
|
||||
constexpr std::pair<iterator, bool> emplace(TArgs&&... args)
|
||||
MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<std::pair<key_type, mapped_type>, TArgs&&...>
|
||||
&& std::is_nothrow_move_constructible_v<key_type> && std::is_nothrow_move_constructible_v<mapped_type>))
|
||||
{
|
||||
std::pair<TKey, TValue> asPair(std::forward<TArgs>(args)...);
|
||||
std::pair<key_type, mapped_type> asPair(std::forward<TArgs>(args)...);
|
||||
auto it = find(asPair.first);
|
||||
if (it != end())
|
||||
{
|
||||
@@ -227,40 +225,40 @@ public:
|
||||
return std::make_pair(iterator(&keys_.back(), &values_.back()), true);
|
||||
}
|
||||
|
||||
iterator erase(iterator pos) MIJIN_NOEXCEPT
|
||||
constexpr 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
|
||||
constexpr 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
|
||||
constexpr 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
|
||||
constexpr 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 eraseAt(std::size_t idx, std::size_t count = 1) MIJIN_NOEXCEPT
|
||||
constexpr iterator eraseAt(std::size_t idx, std::size_t count = 1) MIJIN_NOEXCEPT
|
||||
{
|
||||
return eraseImpl(static_cast<std::ptrdiff_t>(idx), static_cast<std::ptrdiff_t>(count));
|
||||
}
|
||||
|
||||
template<typename TSearch>
|
||||
[[nodiscard]]
|
||||
iterator find(const TSearch& key) MIJIN_NOEXCEPT
|
||||
constexpr iterator find(const TSearch& key) MIJIN_NOEXCEPT
|
||||
{
|
||||
for (std::size_t idx = 0; idx < keys_.size(); ++idx)
|
||||
{
|
||||
@@ -272,39 +270,38 @@ public:
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename TSearch>
|
||||
template<typename TSearch, typename TProj = std::identity>
|
||||
[[nodiscard]]
|
||||
const_iterator find(const TSearch& key) const MIJIN_NOEXCEPT
|
||||
constexpr const_iterator find(const TSearch& key, TProj proj = {}) const MIJIN_NOEXCEPT
|
||||
{
|
||||
for (std::size_t idx = 0; idx < keys_.size(); ++idx)
|
||||
{
|
||||
if (keys_[idx] == key)
|
||||
{
|
||||
return const_iterator(&keys_[idx], &values_[idx]);
|
||||
}
|
||||
auto itKey = std::ranges::find(keys_, key, std::move(proj));
|
||||
if (itKey == keys_.end()) {
|
||||
return end();
|
||||
}
|
||||
return end();
|
||||
const std::ptrdiff_t idx = std::distance(keys_.begin(), itKey);
|
||||
return const_iterator(&*itKey, &values_[idx]);
|
||||
}
|
||||
|
||||
template<typename TSearch, typename TProj = std::identity>
|
||||
[[nodiscard]]
|
||||
bool contains(const TKey& key) const MIJIN_NOEXCEPT
|
||||
constexpr bool contains(const TSearch& key, TProj proj = {}) const MIJIN_NOEXCEPT
|
||||
{
|
||||
return std::ranges::contains(keys_, key);
|
||||
return std::ranges::contains(keys_, key, std::move(proj));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::pair<const TKey&, TValue&> entry(std::size_t idx) MIJIN_NOEXCEPT
|
||||
constexpr std::pair<const key_type&, mapped_type&> entry(std::size_t idx) MIJIN_NOEXCEPT
|
||||
{
|
||||
return std::tie(keys_.at(idx), values_.at(idx));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::pair<const TKey&, const TValue&> entry(std::size_t idx) const MIJIN_NOEXCEPT
|
||||
constexpr std::pair<const key_type&, const mapped_type&> entry(std::size_t idx) const MIJIN_NOEXCEPT
|
||||
{
|
||||
return std::tie(keys_.at(idx), values_.at(idx));
|
||||
}
|
||||
private:
|
||||
iterator eraseImpl(std::ptrdiff_t idx, std::ptrdiff_t count = 1) MIJIN_NOEXCEPT
|
||||
constexpr iterator eraseImpl(std::ptrdiff_t idx, std::ptrdiff_t count = 1) MIJIN_NOEXCEPT
|
||||
{
|
||||
auto itKey = keys_.begin() + idx;
|
||||
auto itValue = values_.begin() + idx;
|
||||
@@ -313,6 +310,16 @@ private:
|
||||
return itKey == keys_.end() ? end() : iterator(&*itKey, &*itValue); // cannot dereference the iterators if the last element was removed
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
consteval VectorMap<int, int> testMap() {
|
||||
VectorMap<int, int> result;
|
||||
result.emplace(5, 17);
|
||||
result[0] = -10;
|
||||
return result;
|
||||
};
|
||||
static_assert(testMap().at(0) == -10);
|
||||
#endif
|
||||
} // namespace mijin
|
||||
|
||||
#endif // MIJIN_CONTAINER_VECTOR_MAP_HPP_INCLUDED
|
||||
|
||||
Reference in New Issue
Block a user