LEM: C++ библиотека поисковой машины - контейнеры

Базовый шаблон - BaseCollect<T,C>.

Объявления - в containers.h.

Заданием политики копирования элементов C (для POD и прочих) образуются две частичных специализации - MCollect (для POD-элементов, допускающих побитовое копирование и инициализируемых нулями), Collect (универсальный шаблон).

Изменением интерфейса образуются ряд других контейнеров:

Stack (в файле stack.h) и MStack (lem_mstk.h) для обычных стеков;

CyclicStack (файл lem_cycs.h) - стек с ограниченной глубиной, как только число элементов достигает заданного значения, помещение нового элемента выталкивает один элемент из головы стека;

Queue (lem_queu.h) и MQueue (lem_mque.h)- обычные очереди.

Все это простые (в сравнении с std::vector) контейнеры. Для них нет аллокаторов. В целом они поддерживают интерфейс класса std::vector в том, что касается доступа к элементам, изменения размера контейнера, итерирования по элементам. Есть несколько дополнительных методов, отсутствующих в std::vector, но принципиального значения они не имеют.

Хочется отметить одну важную особенность контейнеров BaseCollect - они умеют работать с потоками ввода-вывода, а именно - сохранятся в потоке и восстанавливать себя из него. Этим занимаются два метода SaveBin и LoadBin. При этом элементы контейнера также должны иметь такие методы.

BaseArray - контейнер для решения математических задач (у него есть специализация RArray - одномерный вектор действительных чисел). Объявлен в lem_qarr.h. Главная его фича - возможность задавать начальный индекс, например при переносе Fortran'овских процедур можно объявлять вектора с индексацией от 1. Так как этот контейнер произведен от BaseCollect<...>, то можно использовать многие возможности последнего - итераторы и т.д.

BaseMatrix - контейнер для двухмерных массивов (матриц). Объявлен в lem_qmat.h. Это контейнер сам по себе - он не произведен от других, не поддерживает изменение своих размеров. Размерность матрицы задается как аргументы конструктора - поэтому можно присвоить одну матрицу другой даже если их размерности не совпадают. Специализация RMatrix - матрицы действительных чисел. Позволяет задавать значение начального индекса - например 1 для переноса фортрановского кода.

BasePolynome - контейнер для хранения многочленов. Объявлен в lem_poly.h. Производный от BaseArray. В нем введены некоторые специфические операции: нормализация полинома (приведение первого коэффициента к 1), интегрирование, дифференцирование, перемножение и деление многочленов.

BaseVector - контейнер для математических векторов. Объявлен в lem_vect.h. Не допускает динамического добавления элементов (это бессмысленная для математических векторов операция). Поддерживает такие операции, как вычисление длины вектора, сложение векторов.

Не можем не отметить важную особенность lem-контейнеров: они при определенном макросе LEM_DEBUGGING=1 всегда проверяют индексы на невыход за допустимый диапазон. Как показывает практика, при интенсивном использовании сложно организованных контейнеров в большой программе проверка индексации спасает многие часы и дни отладки. При определении макроса LEM_DEBUGGING=0 все проверки (за исключением метода at(...)) отключаются. Таким образом, lem-контейнеры в целом более удобны для отладки.

Семантика контейнеров в версии 0.81 (до рефакторинга)

В версии 0.82 был проведен рефакторинг некоторых базовых классов библиотеки LEM, благодаря чему в качестве контейнеров стали использоваться стандартные шаблоны STL (в частности, vector<>). Прежние версии контейнеров, написанные полностью "с нуля", были проще в плане предоставляемой функциональности, и кроме того имели несколько специфическую семантику конструктора, от которой в версии 0.82 было решено отказаться. Строка:

MCollect<int> a(0,15)

означает, что создается вектор, в котором изначально содержится 0 элементов, но зарезервировано место под 15 элементов. Это в корне отличается от семантики похожего синтаксически конструктора std::vector. А так как с точки зрения компилятора оба этих конструктора правильны, то никаких сообщений в случае изменения кода не будет получено - с самыми печальными последствиями в виде множества веселых ошибок.

В библиотеке было еще два контейнера для специальных нужд.

Контейнер BaseFixCollect<...> не имеет аналога в STL. Размер его (число хранимых элементов) задается параметром шаблона, поэтому динамическое изменение размера невозможно. С этой стороны данный контейнер является аналогом обычных одномерных C-массивов. С другой стороны, этот контейнер дает интерфейс, аналогичных stl::vector и lem::BaseCollect. Кроме этого, данный контейнер проверяет правильность задания индексов (при задании макроса LEM_DEBUGGING=1). Как и для BaseCollect, существуют две специализации: FxMCollect и FxCollect для POD-элементов и прочих соответственно.

Контейнер BaseExCollect<...> отличается от BaseCollect тем, что память для элементов не выделяется динамически, а объявлена как массив в теле класса. Размер этого массива, а значит максимальное число хранимых элементов задается параметром шаблона. Элементы можно добавлять, удалять - как и для BaseCollect. Благодаря отсутствию операций с динамической памятью контейнер в некоторых ситуациях будет работать быстрее чем BaseCollect. Объявлены две специализации: ExMCollect и ExCollect для POD-элементов и прочих соответственно.

изменено 14.11.2005

  © Mental Computing 2010