/* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once /** \file * \ingroup bli * * A `blender::MultiValueMap` is an unordered associative container that stores * key-value pairs. It is different from `blender::Map` in that it can store multiple values for * the same key. The list of values that corresponds to a specific key can contain duplicates * and their order is maintained. * * This data structure is different from a `std::multi_map`, because multi_map can store the same * key more than once and MultiValueMap can't. * * Currently, this class exists mainly for convenience. There are no performance benefits over * using Map>. In the future, a better implementation for this data structure * can be developed. */ #include "BLI_map.hh" #include "BLI_vector.hh" namespace blender { template class MultiValueMap { public: using size_type = int64_t; private: using MapType = Map>; MapType map_; public: /** * Add a new value for the given key. If the map contains the key already, the value will be * appended to the list of corresponding values. */ void add(const Key &key, const Value &value) { this->add_as(key, value); } void add(const Key &key, Value &&value) { this->add_as(key, std::move(value)); } void add(Key &&key, const Value &value) { this->add_as(std::move(key), value); } void add(Key &&key, Value &&value) { this->add_as(std::move(key), std::move(value)); } template void add_as(ForwardKey &&key, ForwardValue &&value) { Vector &vector = map_.lookup_or_add_default_as(std::forward(key)); vector.append(std::forward(value)); } void add_non_duplicates(const Key &key, const Value &value) { Vector &vector = map_.lookup_or_add_default_as(key); vector.append_non_duplicates(value); } /** * Add all given values to the key. */ void add_multiple(const Key &key, Span values) { this->add_multiple_as(key, values); } void add_multiple(Key &&key, Span values) { this->add_multiple_as(std::move(key), values); } template void add_multiple_as(ForwardKey &&key, Span values) { Vector &vector = map_.lookup_or_add_default_as(std::forward(key)); vector.extend(values); } /** * Get a span to all the values that are stored for the given key. */ Span lookup(const Key &key) const { return this->lookup_as(key); } template Span lookup_as(const ForwardKey &key) const { const Vector *vector = map_.lookup_ptr_as(key); if (vector != nullptr) { return vector->as_span(); } return {}; } /** * Get a mutable span to all the values that are stored for the given key. */ MutableSpan lookup(const Key &key) { return this->lookup_as(key); } template MutableSpan lookup_as(const ForwardKey &key) { Vector *vector = map_.lookup_ptr_as(key); if (vector != nullptr) { return vector->as_mutable_span(); } return {}; } /** * Get the number of keys. */ int64_t size() const { return map_.size(); } /** * NOTE: This signature will change when the implementation changes. */ typename MapType::ItemIterator items() const { return map_.items(); } /** * NOTE: This signature will change when the implementation changes. */ typename MapType::KeyIterator keys() const { return map_.keys(); } /** * NOTE: This signature will change when the implementation changes. */ typename MapType::ValueIterator values() const { return map_.values(); } void clear() { map_.clear(); } }; } // namespace blender