Явный рост Vec · 0.0.21
Реализовано в 0.0.21. Вектор может явно увеличить вместимость, сохраняя происхождение хранилища и возвращая владельца даже при отказе.
vec.reserve увеличивает вместимость существующего вектора в его исходном
регионе. push сохраняет прежний контракт: сам не растёт и возвращает Full,
если места нет. Изменения синтаксиса языка не требуются.
currentимеет типvec.Vec<T>, где T копируем.region— доступная именованная привязка исходного региона; передаётся безmove.capacity: u32— желаемая полная вместимость, а не число дополнительных элементов.nextбезусловно получает владельца вектора.statusимеет типResult<vec.Done, MemoryError>.- Вызов требует эффекта
alloc.
Поведение
| Условие | Результат |
|---|---|
capacity <= current.capacity |
Ok, вектор и размещение не меняются; выделений и копирования нет |
| Запрошен рост и места достаточно | Ok, вместимость становится ровно запрошенной; длина и значения сохраняются |
| Места недостаточно | Err(MemoryError.Exhausted), вектор и использованная вместимость региона не меняются |
| Размер размещения непредставим | Err(MemoryError.SizeOverflow), состояние не меняется |
Регион уже создан: reserve не обращается к системному heap и сам не порождает
OutOfMemory. Используется общий тип MemoryError, поэтому match над ним
по-прежнему должен учитывать все варианты.
Все аргументы вычисляются слева направо до вызова, даже если запрос окажется
no-op или завершится отказом. Эффекты и traps аргументов сохраняются.
При trap cleanup не гарантируется, как и для остальных операций языка.
Если новая вместимость вычисляется из vec.capacity(current), вычислите её
до вызова: после первого аргумента move current прежнее имя уже недоступно.
Хранилище и стоимость
При росте выделяется новое размещение на capacity элементов и копируется
только инициализированный префикс [0,len). Неиспользуемая часть новой
вместимости не инициализируется значениями T. Проверки размеров, выравнивания
и доступного места выполняются до изменения состояния региона.
Предыдущее размещение остаётся занятым до memory.close: регион не поддерживает
индивидуальное освобождение. release нового вектора также не возвращает
вместимость. Последовательность частых небольших увеличений может расходовать
значительно больше памяти, чем последнее размещение. Стратегию роста выбирает
программа; скрытого удвоения вместимости нет.
Рост имеет стоимость копирования len × sizeof(T) байтов, с учётом размера
и представления T. Запрос без роста не копирует содержимое. После роста
push/pop/get/set сохраняют прежние контракты без выделения хранилища.
Владение и заимствования
Компилятор проверяет совпадение происхождения региона и вектора. Два разных региона одного типа не взаимозаменяемы. Проверка действует даже для no-op: семантика вызова не зависит от догадки о значении аргумента вместимости.
Живой readonly view запрещает reserve, включая no-op, поскольку вызов
потребляет владельца. После завершения области заимствования можно увеличить
вместимость и создать новый view. Ранее извлечённые независимые значения
get/pop остаются корректными.
Происхождение next совпадает с происхождением current, но физическое
размещение может измениться. Нераспакованный результат reserve продолжает
удерживать зависимость от региона. Передача результата через generic-функции
и объединения CFG не снимают эту зависимость.
Общие ограничения анализа происхождения сохраняются. Пользовательских
заимствуемых параметров Region эта версия не добавляет: вызов выполняется
там, где доступны и владелец вектора, и исходный регион.
Границы версии
Нет автоматического роста, уменьшения вместимости, переноса в другой регион, индивидуального освобождения старых размещений, mutable views или ресурсных элементов. Модель владения и линейного результата из 0.0.20 остаётся прежней.
Пример: от одного элемента к четырём местам
Сначала вектор заполнен одним числом 42. reserve запрашивает четыре места
и сохраняет это число. При отказе ветка Err завершает возвращённого владельца;
при успехе добавляется 7 и создаётся новый view. Регион закрывается после
завершения владельца на обоих путях. Успешное выполнение возвращает 0.
Проверенная стоимость
Для вместимостей 64, 4096 и 16384 и runtime-входов при O0/O2 проверено:
успешный рост вектора из одного u64 копирует ровно 8 байтов независимо
от старой вместимости. No-op не копирует данные и не расходует регион.
В каждом сценарии остаётся одно выделение системной памяти — создание региона.
Отдельно проверяются нетронутый хвост нового размещения, рост пустого вектора, выравнивание, переполнение размера и успешный повторный запрос после отказа. Это проверка конкретных трактов, а не обещание постоянного времени любого роста: объём копирования увеличивается вместе с длиной и размером элемента.
Где применять монотонный регион
Монотонный регион не является универсальной заменой heap-allocator.
Он подходит для временных буферов, пакетов и вычислений с ограниченным
временем жизни данных. Повторный рост долгоживущей коллекции накапливает
занятые размещения: вместимости 4 → 8 → 16 → 32 для u64 требуют суммарно
480 байтов без учёта выравнивания, хотя последнее размещение занимает 256.
Индивидуальный возврат блоков потребует отдельного контракта хранения;
release и reserve его не вводят.