/**************************************************************************/1/* inflection_map.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#include "core/templates/hash_map.h"33#include "core/templates/local_vector.h"3435/// An unordered map that splits elements between a fast-access vector of LinearCount consecutively36/// indexed elements, and a slower-access map holding sparse indexes larger than LinearCount.37///38/// \tparam KeyType is used to lookup values, and must be a type that is convertible to an unsigned integer.39/// \tparam ValueType must have an empty constructor (default or otherwise).40/// \tparam LinearCount41/// \tparam IndexType must be a type that is convertible to an unsigned integer (eg. uint8_t...uint64_t), and which is large enough to represent the number of values in this map.42template <typename KeyType, typename ValueType, size_t LinearCount, typename IndexType = uint16_t>43class InflectionMap {44public:45using value_type = ValueType;46class Iterator {47InflectionMap *map;48IndexType index;4950public:51using iterator_category = std::forward_iterator_tag;52using value_type = ValueType;53using pointer = value_type *;54using reference = value_type &;5556Iterator() :57map(nullptr), index(0) {}58Iterator(InflectionMap &p_m, const IndexType p_i) :59map(&p_m), index(p_i) {}6061Iterator &operator=(const Iterator &p_it) {62map = p_it.map;63index = p_it.index;64return *this;65}6667ValueType *operator->() { return &map->_values[index]; }68ValueType &operator*() { return map->_values[index]; }69operator ValueType *() { return &map->_values[index]; }7071bool operator==(const Iterator &p_it) const { return map == p_it.map && index == p_it.index; }72bool operator!=(const Iterator &p_it) const { return map != p_it.map || index != p_it.index; }7374Iterator &operator++() {75index++;76return *this;77}78Iterator operator++(int) {79Iterator t = *this;80index++;81return t;82}8384bool is_valid() const { return index < map->_values.size(); }85};8687const ValueType &operator[](const KeyType p_idx) const { return get_value(p_idx); }88ValueType &operator[](const KeyType p_idx) { return get_value(p_idx); }8990Iterator begin() { return Iterator(*this, 0); }91Iterator end() { return Iterator(*this, _values.size()); }9293bool is_empty() { return _values.is_empty(); }94size_t size() { return _values.size(); }95void reserve(size_t p_new_cap) { _values.reserve(p_new_cap); }9697protected:98static constexpr IndexType INVALID = std::numeric_limits<IndexType>::max();99typedef struct IndexValue {100IndexType value = INVALID;101} IndexValue;102103// Returns a reference to the value at the index.104// If the index has not been initialized, add an empty element at105// the end of the values array, and set the index to its position.106ValueType &get_value(KeyType p_idx) {107IndexValue *val_idx = p_idx < LinearCount ? &_linear_indexes[p_idx] : _inflection_indexes.getptr(p_idx);108if (val_idx == nullptr || val_idx->value == INVALID) {109_values.push_back({});110if (val_idx == nullptr) {111val_idx = &_inflection_indexes.insert(p_idx, {})->value;112}113val_idx->value = _values.size() - 1;114}115return _values[val_idx->value];116}117118TightLocalVector<ValueType> _values;119HashMap<KeyType, IndexValue> _inflection_indexes;120IndexValue _linear_indexes[LinearCount];121};122123124