# Архитектура ## Представления `AdaptiveSequence` хранит `variant, TieredStorage>`. Векторный режим предназначен для random/sequential read и append. Tiered-режим состоит из независимо выделенных циклических leaf-блоков (`RingBlock`) и многоуровневого каталога весов. Каталог строит только необходимое число уровней до заданного максимума; поиск спускается по уровням, а отдельный Fenwick index восстанавливает логическую позицию stable ID. Текущий `TieredStorage` — сегментированный исследовательский вариант, а не полная реализация implicit tiered vector с offsets на каждом внутреннем узле. Offsets реально используются внутри leaf, но split/merge меняет массив дескрипторов leaf и перестраивает каталог. Это важное ограничение: некоторые uniform-edit результаты отражают O(number_of_leaves) обслуживание split, а не теоретическую границу полноценного tiered vector. ## Адаптивное решение Storage и policy разделены. Контейнер передаёт `OperationSample`, policy возвращает: ```cpp struct AdaptationDecision { StorageMode target; TieredConfig tiered_config; double expected_saving; }; ``` Для каждого окна оцениваются vector и все tiered-кандидаты. Главная форма модели edit-cost: ```text vector: fixed + move_unit * sizeof(T) * (N - position) tiered: fixed + move_unit * sizeof(T) * distance_inside_leaf + directory_unit * locality_multiplier * N / leaf + lookup(levels) ``` Первая переменная часть tiered растёт с leaf, вторая — с `N/leaf`. Поэтому минимум сдвигается к большим блокам при росте N. Для близких последовательных edit-позиций directory multiplier уменьшается: горячая область не создаёт split во множестве разных leaf, и policy выбирает меньший блок. Для каждого leaf вычисляется минимально достаточная глубина при текущих `N` и fanout. Сравниваются три альтернативы: остаться, перейти в другое представление, либо перестроить tiered с другой геометрией. Решение требует: ```text (current_cost - candidate_cost) * forecast > rebuild_cost * safety_factor ``` Для `vector→tiered`, `tiered→vector` и `tiered→tiered` используются разные safety factor. Дополнительно действуют minimum residency, минимальное улучшение shape, EWMA и два подтверждающих окна. После перехода статистическое окно начинается заново. Все коэффициенты находятся в `AdaptationConfig` и могут заменяться другой policy. ## Почему чтение по умолчанию не перестраивает storage `ReadAdaptationMode::deferred` лишь записывает статистику. Pending-решение выполняется на следующей мутации или при явном `adapt_now()`. Это сохраняет важный контракт: обычное чтение не инвалидирует уже выданную ссылку. `eager_nonconst` оставлен только как benchmark-эксперимент. Он может выполнить переход вокруг non-const `operator[]`, добавляет проверку в горячий read path и имеет более слабую семантику. Первые измерения не оправдали его как default. Для read-only фазы, после которой мутаций нет, вызывающий код может поставить явную maintenance point: ```cpp values.adapt_now(); ``` ## Инвалидация - const-чтение и сбор статистики в deferred mode ничего не инвалидируют; - `set()` не меняет логические позиции, но ссылка на заменённое значение не должна использоваться как ссылка на старый объект; - любая структурная операция в auto mode может также выполнить rebuild, поэтому инвалидирует все references, pointers и iterators; - conversion, shape rebuild, `force_*`, `reserve`, `clear` и `make_contiguous()` инвалидируют всё позиционное; - stable ID переживает shifts, split и смену представления; он перестаёт быть живым только после удаления элемента или `clear()`. Debug-проверка iterator хранит structural generation и бросает `logic_error` после инвалидирования. ## Hash index `AdaptiveSequence` использует open-addressed flat table `value -> {head_id,count}`. Дубликаты связаны через компактные intrusive links в ID metadata. `find_one` означает любой экземпляр. `find_all` возвращает логически отсортированные позиции и потому может стоить O(k log k), тогда как `find_all_ids` возвращает unordered stable IDs за O(k).