#pragma once
#include <cstddef>
#include <unordered_map>
#include <vector>
namespace ddwaf {
template <typename Key, typename T> class indexed_multivector {
public:
indexed_multivector() = default;
void emplace(Key key, std::vector<T> element)
{
total_size_ += element.size();
data_.emplace(std::move(key), std::move(element));
}
void erase(const Key &key)
{
auto it = data_.find(key);
if (it != data_.end()) {
total_size_ -= it->second.size();
data_.erase(it);
}
}
[[nodiscard]] bool empty() const { return data_.empty(); }
[[nodiscard]] std::size_t size() const { return total_size_; }
class const_iterator {
public:
using index_iterator_type =
typename std::unordered_map<Key, std::vector<T>>::const_iterator;
using item_iterator_type = typename std::vector<T>::const_iterator;
const_iterator(
index_iterator_type index_it, index_iterator_type end_index_it,
item_iterator_type item_it)
: index_it_(index_it), end_index_it_(end_index_it), item_it_(item_it)
{}
const_iterator &operator++()
{
++item_it_;
if (item_it_ == index_it_->second.end()) {
++index_it_;
if (index_it_ != end_index_it_) {
item_it_ = index_it_->second.begin();
} else {
item_it_ = {};
}
}
return *this;
}
bool operator==(const_iterator other) const
{
return index_it_ == other.index_it_ && item_it_ == other.item_it_;
}
bool operator!=(const_iterator other) const { return !(*this == other); }
const T &operator*() const { return *item_it_; }
protected:
index_iterator_type index_it_;
index_iterator_type end_index_it_;
item_iterator_type item_it_;
};
const_iterator begin() const
{
if (data_.empty()) {
return end();
}
auto index_it = data_.begin();
auto item_it = index_it->second.begin();
return {index_it, data_.end(), item_it};
}
const_iterator end() const { return {data_.end(), data_.end(), {}}; }
protected:
std::unordered_map<Key, std::vector<T>> data_;
std::size_t total_size_{0};
};
}