Spec-Zone.ru › D

std.container

В этом модуле определены обобщенные контейнеры.

Создание
Для реализации различных контейнеров были использованы подходы, основанные как на структурах, так и на классах. std.container.util.make позволяет создавать контейнеры единообразно с использованием любого из этих подходов.
import std.container;
// Construct a red-black tree and an array both containing the values 1, 2, 3.
// RedBlackTree should typically be allocated using `new`
RedBlackTree!int rbTree = new RedBlackTree!int(1, 2, 3);
// But `new` should not be used with Array
Array!int array = Array!int(1, 2, 3);
// `make` hides the differences
RedBlackTree!int rbTree2 = make!(RedBlackTree!int)(1, 2, 3);
Array!int array2 = make!(Array!int)(1, 2, 3);
Обратите внимание, что make может вывести тип элемента из заданных аргументов.
import std.container;
auto rbTree = make!RedBlackTree(1, 2, 3); // RedBlackTree!int
auto array = make!Array("1", "2", "3"); // Array!string
Семантика ссылок
Все контейнеры имеют семантику ссылок, что означает, что после присваивания обе переменные ссылаются на одни и те же данные.
Для создания копии контейнера используйте примитив контейнера c.dup.
import std.container, std.range;
Array!int originalArray = make!(Array!int)(1, 2, 3);
Array!int secondArray = originalArray;
assert(equal(originalArray[], secondArray[]));

// changing one instance changes the other one as well!
originalArray[0] = 12;
assert(secondArray[0] == 12);

// secondArray now refers to an independent copy of originalArray
secondArray = originalArray.dup;
secondArray[0] = 1;
// assert that originalArray has not been affected
assert(originalArray[0] == 12);
Внимание: Если контейнер реализован как класс, использование неинициализированного экземпляра может привести к сбою из-за обращения к нулевому указателю.
import std.container;

RedBlackTree!int rbTree;
rbTree.insert(5); // null pointer dereference
Использование неинициализированного контейнера, основанного на структуре, будет работать, поскольку структура инициализируется при использовании; однако, до этого момента контейнер не будет иметь идентичности, а присвоение не создаст две ссылки на одни и те же данные.
import std.container;

// create an uninitialized array
Array!int array1;
// array2 does _not_ refer to array1
Array!int array2 = array1;
array2.insertBack(42);
// thus array1 will not be affected
assert(array1.empty);

// after initialization reference semantics work as expected
array1 = array2;
// now affects array2 as well
array1.removeBack();
assert(array2.empty);
Поэтому рекомендуется всегда создавать контейнеры с помощью std.container.util.make. Это, в действительности, необходимо для размещения контейнеров в другом контейнере. Например, чтобы создать Array из десяти пустых Array, используйте следующее, которое вызывает make десять раз.
import std.container, std.range;

auto arrOfArrs = make!Array(generate!(() => make!(Array!int)).take(10));
Подмодули
Этот модуль состоит из следующих подмодулей:
  • Модуль std.container.array предоставляет тип массива с детерминированным управлением памятью, не зависящий от сборщика мусора, в отличие от встроенных массивов.
  • Модуль std.container.binaryheap предоставляет реализацию бинарной кучи, которую можно применять к любому предоставленному пользователем диапазону с произвольным доступом.
  • Модуль std.container.dlist предоставляет реализацию двусвязного списка.
  • Модуль std.container.rbtree реализует красно-черные деревья.
  • Модуль std.container.slist реализует односвязные списки.
  • Модуль std.container.util содержит некоторые общие инструменты, обычно используемые реализациями контейнеров.
Основной диапазон контейнера
Хотя некоторые контейнеры предлагают прямой доступ к своим элементам, например, через opIndex, c.front или c.back, доступ к содержимому контейнера и его модификация обычно осуществляется через его основной тип диапазона, который алиасируется как C.Range. Например, основной тип диапазона Array!int — Array!int.Range.
Если в документации к членской функции контейнера используется параметр типа Range, то это относится к основному типу диапазона этого контейнера. Часто используется Take!Range, в этом случае диапазон относится к отрезку элементов в контейнере. Аргументы этих параметров должны быть получены от того же экземпляра контейнера, с которым выполняется работа. Важно отметить, что многие обобщенные алгоритмы диапазонов возвращают тот же тип диапазона, что и их входной диапазон.
import std.algorithm.comparison : equal;
import std.algorithm.iteration : find;
import std.container;
import std.range : take;

auto array = make!Array(1, 2, 3);

// `find` returns an Array!int.Range advanced to the element "2"
array.linearRemove(array[].find(2));

assert(array[].equal([1]));

array = make!Array(1, 2, 3);

// the range given to `linearRemove` is a Take!(Array!int.Range)
// spanning just the element "2"
array.linearRemove(array[].find(2).take(1));

assert(array[].equal([1, 3]));
Когда любой диапазон может быть передан в качестве аргумента в членскую функцию, в документации тип параметра обычно обозначается как Stuff.
import std.algorithm.comparison : equal;
import std.container;
import std.range : iota;

auto array = make!Array(1, 2);

// the range type returned by `iota` is completely unrelated to Array,
// which is fine for Array.insertBack:
array.insertBack(iota(3, 10));

assert(array[].equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
Примитивы контейнера
Контейнеры не образуют иерархии классов, вместо этого они реализуют общий набор примитивов (см. таблицу ниже). Каждый из этих примитивов гарантирует определенную сложность в худшем случае, что позволяет писать обобщенный код независимо от реализации контейнера.
Например, примитивы c.remove(r) и c.linearRemove(r) оба удаляют последовательность элементов в диапазоне r из контейнера c. Примитив c.remove(r) гарантирует сложность Ο(nr log nc) в худшем случае, а c.linearRemove(r) ослабляет это ограничение до Ο(nc). Поскольку последовательность элементов может быть удалена из двусвязного списка в постоянное время, DList предоставляет примитив c.remove(r) и c.linearRemove(r). С другой стороны, массив предлагает только c.linearRemove(r). В таблице ниже описывается общий набор примитивов, которые реализуют контейнеры. Контейнер необязательно должен реализовывать все примитивы, но если примитив реализован, он должен поддерживать синтаксис, описанный в столбце синтаксис, с семантикой, описанной в столбце описание, и он не должен иметь сложность в худшем случае хуже, чем обозначено в нотации "большое О" в столбце Ο(·). Ниже, C означает тип контейнера, c — значение типа контейнера, nx представляет собой эффективную длину значения x, которое может быть одним элементом (в этом случае nx равно 1), контейнером или диапазоном.
Основные контейнерные примитивы
Синтаксис Ο(·) Описание
C(x) nx Создаёт контейнер типа C из другого контейнера или диапазона. Созданный контейнер не должен быть нулевым даже если x пустой.
c.dup nc Возвращает копию контейнера.
c ~ x nc + nx Возвращает конкатенацию c и r. x может быть отдельным элементом или диапазоном ввода.
x ~ c nc + nx Возвращает конкатенацию x и c. x может быть отдельным элементом или диапазоном ввода.
Итерация
c.Range Основной тип диапазона, связанный с контейнером.
c[] log nc Возвращает диапазон, итерирующий по всему контейнеру в определённом контейнером порядке.
c[a .. b] log nc Извлекает часть контейнера с ключом a до ключа b.
Емкость
c.empty 1 Возвращает true, если контейнер пустой, false в противном случае.
c.length log nc Возвращает количество элементов в контейнере.
c.length = n nc + n Принудительно устанавливает количество элементов в контейнере на n. Если контейнер увеличивается, добавленные элементы инициализируются способом, зависящим от контейнера (обычно с использованием T.init).
c.capacity log nc Возвращает максимальное количество элементов, которое может храниться в контейнере без вызова перераспределения.
c.reserve(x) nc Принудительно устанавливает capacity как минимум на x без уменьшения.
Доступ
c.front log nc Возвращает первый элемент контейнера в определённом контейнером порядке.
c.moveFront log nc Деструктивно считывает и возвращает первый элемент контейнера. Ячейка не удаляется из контейнера; она инициализируется значением T.init. Эта процедура может не быть определена, если front возвращает ref.
c.front = v log nc Присваивает v первому элементу контейнера.
c.back log nc Возвращает последний элемент контейнера в определённом контейнером порядке.
c.moveBack log nc Деструктивно считывает и возвращает последний элемент контейнера. Ячейка не удаляется из контейнера; она инициализируется значением T.init. Эта процедура может не быть определена, если front возвращает ref.
c.back = v log nc Присваивает v последнему элементу контейнера.
c[x] log nc Обеспечивает индексированный доступ к контейнеру. Тип индекса определяется контейнером. Контейнер может определять несколько типов индексов (и, следовательно, перегружать индексирование).
c.moveAt(x) log nc Деструктивно считывает и возвращает значение в позиции x. Ячейка не удаляется из контейнера; она инициализируется значением T.init.
c[x] = v log nc Устанавливает элемент в контейнер по указанному индексу.
c[x] op= v log nc Выполняет операцию чтения-модификации-записи в контейнере по указанному индексу.
Операции
e in c log nc Возвращает ненулевое значение, если e найдено в c.
c.lowerBound(v) log nc Возвращает диапазон всех элементов, строго меньших v.
c.upperBound(v) log nc Возвращает диапазон всех элементов, строго больших v.
c.equalRange(v) log nc Возвращает диапазон всех элементов в c, равных v.
Измененные значения
c ~= x nc + nx Добавляет x в c. x может быть отдельным элементом или диапазоном ввода.
c.clear() nc Удаляет все элементы в c.
c.insert(x) nx * log nc Вставляет x в c в позиции(и), выбранной c.
c.stableInsert(x) nx * log nc То же, что и c.insert(x), но гарантирует, что никакие диапазоны не будут повреждены.
c.linearInsert(v) nc То же, что и c.insert(v), но сложность снижена до линейной.
c.stableLinearInsert(v) nc То же, что и c.stableInsert(v), но сложность снижена до линейной.
c.removeAny() log nc Удаляет некоторый элемент из c и возвращает его.
c.stableRemoveAny() log nc То же, что и c.removeAny(), но гарантирует, что никакие итераторы не будут повреждены.
c.insertFront(v) log nc Вставляет v в начало c.
c.stableInsertFront(v) log nc То же, что и c.insertFront(v), но гарантирует, что никакие диапазоны не будут повреждены.
c.insertBack(v) log nc Вставляет v в конец c.
c.stableInsertBack(v) log nc То же, что и c.insertBack(v), но гарантирует, что никакие диапазоны не будут повреждены.
c.removeFront() log nc Удаляет элемент в начале c.
c.stableRemoveFront() log nc То же, что и c.removeFront(), но гарантирует, что никакие диапазоны не будут повреждены.
c.removeBack() log nc Удаляет значение в конце c.
c.stableRemoveBack() log nc То же, что и c.removeBack(), но гарантирует, что никакие диапазоны не будут повреждены.
c.remove(r) nr * log nc Удаляет диапазон r из c.
c.stableRemove(r) nr * log nc То же, что и c.remove(r), но гарантирует, что итераторы не будут повреждены.
c.linearRemove(r) nc Удаляет диапазон r из c.
c.stableLinearRemove(r) nc То же, что и c.linearRemove(r), но гарантирует, что итераторы не будут повреждены.
c.removeKey(k) log nc Удаляет элемент из c по ключу k. Тип ключа определяется контейнером.
Источник
std/container/package.d
Лицензия:
Распространяется по лицензии Boost Software License, версия 1.0. (См. прилагаемый файл LICENSE_1_0.txt или копию по адресу boost.org/LICENSE_1_0.txt).
Авторы:
Steven Schveighoffer, Andrei Alexandrescu

© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_container.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API