Библиотека Vectors: краткое описание

Copyright (C) Alexey A.Chernobaev, 1996-2000 (http://attend.to/alexch; e-mail: alexch@caravan.ru).

Версия 000216.

В статье описывается библиотека классов, в которой реализованы векторы (массивы переменной длины) на базе различных типов Object Pascal, в том числе векторы над целыми и вещественными числами, логическими переменными, указателями и строками. В классах библиотеки реализован широкий набор операций, которые зависят от типа элементов вектора: сортировка по возрастанию и убыванию, различные варианты поиска элементов (начиная с некоторого элемента, вверх или вниз), для числовых векторов - векторные арифметические операции, для булевских векторов - логические операции и т.д. Кроме того, библиотека предлагает ряд производных и дополнительных классов: разреженные векторы, матрицы, очереди, стеки, словари, потоки. Существующая версия библиотеки совместима с Delphi 1, 3-5 и последними версиями компилятора Free Pascal (v.0.99.15 и выше).

Введение

Создание больших программных систем в настоящее время практически невозможно без использования вспомогательных программных компонент, реализующих базовые структуры данных (такие, как динамические массивы, списки, стеки, деревья поиска) и алгоритмы. Примером такой компоненты для C++ является стандартная библиотека шаблонов (С++ STL - Standard Template Library). В настоящее время для языка Object Pascal не существует стандартных библиотек, подобных C++ STL (библиотека визуальных компонент Delphi VCL ориентирована на решение других задач). Основной причиной такого положения является, вероятно, отсутствие в Object Pascal аналогов ряда важных языковых возможностей C++, в первую очередь - шаблонов (templates). В то же время, Object Pascal является развитым объектно-ориентированным языком программирования, сочетающим большие возможности со значительно большей, по сравнению с C++, простотой использования. Создание библиотеки Vectors является попыткой предложить программистам на Object Pascal набор удобных, надежных и эффективных классов, реализующих базовые структуры данных. В отличие от некоторых других разработок, Vectors не требует использования внешнего макропроцессора. Вместо этого при создании библиотеки Vectors был применен механизм псевдошаблонов (см. ниже), основанный исключительно на средствах Object Pascal.

Базовые классы

Типы данных Vectors

Для простого и независимого от версии компилятора именования типов Object Pascal в состав библиотеки Vectors входит модуль ExtType, где определены синонимы для стандартных числовых типов Object Pascal. В таблице приведено соответствие между типами ExtType и типами Delphi версий 1 и 3.

Модуль ExtType Delphi 1 Delphi 3
UInt8 Byte Byte
Int8 ShortInt ShortInt
Int16 Integer SmallInt
UInt16 Word Word
Int32 LongInt Integer, LongInt
UInt32 0..MaxLongInt Cardinal
Float32 Single Single
Float64 Double Double
Float80 Extended Extended

В ExtType опредены также некоторые другие типы-синонимы:

Модуль ExtType Delphi
Bool Boolean
DWord UInt32
UInt 0..MaxInt
Float В зависимости от условий компиляции (файл VCheck.inc):
FLOAT_EQ_FLOAT32 => Float32;
FLOAT_EQ_FLOAT64 => Float64;
FLOAT_EQ_FLOAT80 => Float80.

Общие свойства и методы классов векторов

Все классы-векторы являются потомками базового класса TVector (модуль Vectors), в котором реализованы базовые операции над векторами, не зависящие от типа элементов.

Свойства класса TVector

property Count: Integer; количество элементов вектора (R/W);
property Capacity: Integer; количество элементов, для которых выделена память (Capacity >= Count) (R/W);
property ElemSize: TElemSize; размер элемента вектора (RO);

Свойство Count позволяет изменять размер вектора. При увеличении Count происходит расширение выделенного для хранения элементов блока памяти, а вновь выделенная часть блока заполняется нулями (многие потомки класса TVector позволяют задавать значение вектора по умолчанию, которое используется при изменении размера векторов). Поскольку менеджер памяти Delphi выделяет память блоками (в случае Delphi 3 размер кванта памяти равен 4 байтам), фактический размер вектора изменяется ступенчато. Для того, чтобы минимизировать количество обращений к менеджеру памяти, в текущей версии библиотеки память распределяется еще более крупными блоками: не менее чем по 4*ElemSize байт.

Свойство Capacity возвращает объем блока памяти (в элементах), который выделен для хранения элементов вектора. Этому свойству можно присвоить любое значение, большее либо равное Count. При этом будет выделен блок памяти, достаточный для хранения Capacity элементов. Это позволит методам класса TVector не производить дополнительных обращений к менеджеру памяти, когда размер вектора будет увеличиваться в пределах Capacity. Для того, чтобы освободить неиспользуемую память, следует вызвать метод Pack или выполнить присваивание Capacity:=Count.

Методы класса TVector

procedure WriteToStream(VStream: TVStream); записывает вектор в поток (см. ниже);
procedure ReadFromStream(VStream: TVStream); чтение из потока;
procedure Assign(Source: TVector); присваивает вектору значение другого вектора;
function EqualTo(V: TVector): Bool; сравнивает векторы;
procedure Delete(I: Integer); удаляет I-ый элемент из вектора;
procedure DeleteRange(I, ACount: Integer); если ACount > 0, то исключает ACount элементов, начиная с I (предусловие: I + ACount <= Count);
procedure Clear; очищает вектор (Count:=0);
procedure Pack; освобождает неиспользуемую память;
procedure Grow(Delta: Integer); Count:=Count + Delta;

Векторы, поддерживающие сортировку значений

Прямым потомком класса TVector является абстрактный класс TSortableVector. В данном классе реализованы различные варианты сортировки векторов (по возрастанию или убыванию, всего вектора или избранного отрезка элементов вектора). Реализованные в TSortableVector методы сортировки не зависят от типа элементов вектора: это достигается за счет использования абстрактных методов Compare, Exchange и GetUntyped, которые переопределяются векторами-потомками.

Методы класса TSortableVector

function Compare(I: Integer; const V): Int32; abstract; возвращает значение больше нуля, если I-й элемент больше V, нуль, если они равны, и значение меньше нуля, если I-й элемент меньше V;
procedure Exchange(I, J: Integer); abstract; меняет местами элементы с индексами I и J;
procedure GetUntyped(I: Integer; var Result); abstract; возвращает I-ый элемент (размер Result должен быть не меньше ElemSize);
procedure SortRange(L, R: Integer); сортирует элементы с L по R по возрастанию (L, R = 0..Count - 1);
procedure SortRangeDesc(L, R: Integer); сортирует элементы с L по R по убыванию (L, R = 0..Count - 1);
procedure Sort; сортирует вектор по возрастанию;
procedure SortDesc; сортирует вектор по убыванию;
procedure SortWith(AVector: TSortableVector); сортирует вектор по возрастанию, сохраняя соответствие между элементами данного вектора и вектора AVector; AVector должен иметь размер, не меньший, чем размер данного вектора;
procedure SortDescWith(AVector: TSortableVector); сортирует вектор по убыванию, сохраняя соответствие между элементами данного вектора и вектора AVector; AVector должен иметь размер, не меньший, чем размер данного вектора;
procedure Invert; инвертирует вектор (последний элемент становится первым, предпоследний - вторым, и т.д.);

Числовые векторы

Простой пример

Начнем с примера использования классов векторов библиотеки. Следующая программа иллюстрирует создание вектора, присваивание значений его элементам, изменение размера, вставку и удаление элементов. В программе создается вектор элементов типа Int32 (класс TInt32Vector) нулевой длины со значением по умолчанию, равным 1. Определение данного класса находится в модуле Int32v.

uses
  ExtType, Int32v;
var
  I: Integer;
  Min: Int32;
  V: TInt32Vector;
begin
  V:=TInt32Vector.Create(0, 1);
  try
    V.SetItems([1, 2, 3, 4, 5]); { V = (1, 2, 3, 4, 5) }
    V.DebugWrite;
    V.Delete(0); { V = (2, 3, 4, 5) }
    V.DebugWrite;
    V.Count:=6; { V = (2, 3, 4, 5, 1, 1) }
    V.DebugWrite;
    Min:=V.Min; { Min = 1 }
    writeln(Min);
    V.Remove(Min); { V = (2, 3, 4, 5, 1) }
    V.DebugWrite;
    V.Delete(V.IndexOf(Min)); { V = (2, 3, 4, 5) }
    V.DebugWrite;
    for I:=0 to V.Count - 1 do
      V[I]:=V[I] + Min + I; { эффективнее: V.IncItem(I, Min + I) }
    V.DebugWrite; { V = (3, 5, 7, 9) }
    V.SubScalar(2); { V = (1, 3, 5, 7) }
    V.DebugWrite;
  finally
    V.Free;
  end;
end.
Имена классов числовых векторов образованы по принципу TXXXXVector, где XXXX - имя типа элементов вектора из модуля ExtType. Имена большинства модулей, в которых определены классы векторов, образованы по тому же принципу: имя типа элемента плюс суффикс 'v', например UInt16v. Исключение сделано для вещественных векторов: соответствующие модули называются F32v, F64v и F80v.

Реализация

Иерархия классов

Все числовые векторы реализованы единообразно и образуют следующую иерархию:

TVector
+------   TSortableVector
  +------   TBaseXXVector
    +------   TGenericNumberVector
      +------   TNumberVector
      +------   TSparseNumberVector

Здесь Number - имя базового типа (Int8, Int16...), TBaseXXVector - один из классов TBase8Vector, TBase16Vector, TBase32Vector, TBase64Vector и TBase80Vector. Таким образом, определены три семейства классов:

  1. TGenericInt8Vector, TGenericUInt8Vector, TGenericInt16Vector, TGenericUInt16Vector, TGenericInt32Vector, TGenericUInt32Vector, TGenericFloat32Vector, TGenericFloat64Vector и TGenericFloat80Vector;
  2. TInt8Vector, TUInt8Vector, TInt16Vector, TUInt16Vector, TInt32Vector, TUInt32Vector, TFloat32Vector, TFloat64Vector и TFloat80Vector;
  3. TSparseInt8Vector, TSparseUInt8Vector, TSparseInt16Vector, TSparseUInt16Vector, TSparseInt32Vector, TSparseUInt32Vector, TSparseFloat32Vector, TSparseFloat64Vector и TSparseFloat80Vector.
Создание экземпляров классов, начиная с TVector и кончая TGenericNumberVector, не имеет смысла, т.к. эти классы являются абстрактными. Приложения должны создавать экземпляры классов TNumberVector и TSparseNumberVector.

В модуле Aliasv определены некоторые синонимы для перечисленных типов векторов: TByteVector = TUInt8Vector, TSmallIntVector = TInt8Vector, TIntegerVector = TInt16Vector (Delphi 1.0) или TInt32Vector (32-разрядные версии Object Pascal) и т.д.

Свойства и методы числовых векторов описаны в комментариях к описанию класса TGenericNumberVector - см. файл VGeneric.def.

Механизм псевдошаблонов

Для реализации семейств классов, отличающихся лишь типом элементов, в библиотеке был применен механизм псевдошаблонов, основанный на использованнии директивы $INCLUDE и конструкции переопределения типов (type T1 = T2). Для примера рассмотрим модуль Int16g, в котором определен класс TGenericInt16Vector (модуль приведен в сокращенном виде):

unit Int16g;

interface

uses
  ExtType, Vectors, Base16v;

type
  NumberType = Int16;

  TGenericNumberVector = class(TBase16Vector)
  {$I VGeneric.def}
  end;

  TGenericInt16Vector = TGenericNumberVector;

implementation

{$I VGeneric.imp}

end.
Из приведенного текста видно, что вся "неформальная" часть модуля вынесена в файл VGeneric.def, содержащий интерфейсную часть "абстрактного числового вектора" TGenericNumberVector, и VGeneric.imp, содержащий его реализацию. Фактически в файлах VGeneric.def и VGeneric.imp определен абстрактный тип данных (АТД) "абстрактный числовой вектор". Тип NumberType, который определяется в модуле перед включением в него файла VGeneric.def, является параметром этого АТД. Программный код, находящийся в файлах VGeneric.def и VGeneric.imp, ничем не отличается от "нормального" кода, за исключением того, что вместо конкретного типа элементов используется тип NumberType, например:
function TGenericNumberVector.Add(Value: NumberType): Integer;
begin
  Result:=Count;
  Insert(Result, Value);
end;

Аналогичным образом реализованы классы "эффективных числовых векторов" TNumberVector (псевдошаблон определен в файлах VFast.def и VFast.imp) и "разреженных числовых векторов" TSparseNumberVector (псевдошаблон определен в файлах SprsVect.def и SprsVect.imp), матрицы и т.д. При использовании псевдошаблонов иногда возникают технические проблемы, связанные со спецификой базового типа (например, из-за различия операторов целочисленного деления "div" и вещественного деления "/" в Object Pascal), но все эти проблемы преодолеваются с помощью директив условной компиляции.

Производные классы

Разреженные векторы

Разреженные векторы (векторы семейства TSparseNumberVector) могут применяться для работы с векторами большой размерности (т.е. такого размера, что хранение их в памяти в обычном виде невозможно или нежелательно), при условии, что большинство элементов вектора равны одному и тому же значению. В разреженных векторах хранятся только элементы, значения которых отличны от значений по умолчанию (фактически хранятся сами значения и их индексы). Операции над разреженными векторами осуществляются, как правило, намного медленнее, чем над обычными векторами, однако их использование может быть единственным способом решения некоторых задач. Разреженные векторы полностью совместимы с "обычными" векторами, что позволяет, в зависимости от объема доступной памяти, создавать объекты классов TNumberVector либо TSparseNumberVector.

Пример:

uses
  Int16g, Int16v, Int16sv;
var
  IV1, IV2: TGenericInt16Vector;
  I: Int16;
begin
  IV1:=TInt16Vector.Create(5, 0); { IV1 = (0, 0, 0, 0, 0) }
  IV2:=TSparseInt16Vector.Create(3, 1); { IV2 = (1, 1, 1) }
  try
    IV1[0]:=2;
    IV1[4]:=-1; { IV1 = (2, 0, 0, 0, -1) }
    IV2[2]:=4;
    IV2.Count:=7; { IV2 = (1, 1, 4, 1, 1, 1, 1) }
    IV1.Sort;
    IV1.Insert(3, 5); { IV1 = (-1, 0, 0, 5, 0, 2) }
    IV2[6]:=-5;
    IV2.Delete(5); { IV2 = (1, 1, 4, 1, 1, -5) }
    IV1.AddVector(IV2);
    IV1.MulScalar(2); { IV1 = (0, 2, 8, 12, 2, -6) }
    I:=IV1.LastIndexOf(2); { I = 4 }
    I:=IV2.DotProduct(IV1); { I = 78 }
  finally
    IV1.Free;
    IV2.Free;
  end;
end;

Числовые матрицы

На базе числовых векторов различных типов в библиотеке реализованы матрицы.

TNumberMatrix      
+----------    TSquareMatrix    
  +----------    TSimMatrix  
    +----------    TSparseSimMatrix
+----------    TSparseMatrix    

Свойства и методы матриц описаны в комментариях к описанию класса TNumberMatrix и его потомков (файл NumMatrix.def).

Следующий пример демонстрирует перемножение матриц:

uses
  ExtType, Int16m;
var
  A, B, C: TInt16Matrix;
begin
  A:=TInt16Matrix.Create(3, 2, 0);
  B:=TInt16Matrix.Create(2, 4, 0);
  C:=nil;
  try
    A.SetItems([
      3, 2,
      6, -4,
      2, 7
    ]);
    B.SetItems([
      7, 0, 2, 1,
      2, -2, 3, 6
    ]);
    C:=TInt16Matrix.CreateMatrixProduct(A, B);
    C.DebugWrite;
  finally
    A.Free;
    B.Free;
    C.Free;
  end;
end.

Логические векторы и матрицы

В библиотеке реализованы различные варианты логических векторов и матриц.

Логические векторы:

TVector    
+------------    TBoolVector  
  +------------    TPackedBoolVector

Логические матрицы:

TBoolMatrix      
+---------    TSquareBoolMatrix    
  +---------    TSimBoolMatrix  
    +---------    TSparseSimMatrix (=TPackedSimMatrix)
+---------    TSparseBoolMatrix (=TPackedBoolMatrix)    

В текущей версии библиотеки не реализованы разреженные булевские векторы либо матрицы. Вместо этого реализованы упакованные (Packed) булевские вектора и матрицы, в которых каждый элемент занимает один бит.

Векторы указателей

Класс TPointerVector (синоним - TClassList) является аналогом класса TList, реализованного в Delphi VCL. Основные отличия TPointerVector от TList состоят в следующем:

  1. размер объекта класса TPointerVector может быть изменен с помощью свойства Count (при увеличении размера новые элементы получают значение nil);
  2. добавлен метод FreeItems, который интерпретирует все элементы как TObject и уничтожает их вызовом метода Free.
Класс TPointerVector реализован в модуле Pointerv.

Векторы строк

Класс TStrLst - потомок класса TPointerVector (TClassList). Он является упрощенным аналогом класса TStringList Delphi VCL. По сравнению с последним, в классе TStrLst не определены свойства Objects и Sorted, а также связанные с ними методы. В то же время, TStrLst позволяет изменять размер с помощью свойства Count и поддерживает расширенные возможности сортировки и поиска.

Класс TStrLst определен в модуле StrLst. В том же модуле реализованы его потомки: список, учитывающий регистр при сравнении строк (TCaseSensStrLst), сортированный список (TSortedStrLst) и вариант сортированного списка, учитывающий регистр строк (TCaseSensSortedStrLst).

--- TStrLst    
+------------    TCaseSensStrLst  
+------------    TSortedStrLst  
  +------------    TCaseSensSortedStrLst

Словари

Словарь - это структура данных для хранения пар вида (ключ, значение), которая позволяет эффективно добавлять и удалять такие пары, а также искать значения по ключу. Словари в библиотеки реализованы на основе красно-черных деревьев поиска (Read-Black Trees). Псевдошаблон красно-черных деревьев определен в файлах RBTree.def и RBTree.imp, псевдошаблон словарей - в файлах Dic.def и Dic.imp. На основе этих псевдошаблонов построены словари типа String-String (SSDic.pas), String-Integer (SIDic.pas), String-Pointer (SPDic.pas). При необходимости пользователи могут определить свои классы словарей.

Методы классов словарей

function Add(const AKey: TDicKey; const AData: TDicData): Bool; если значения с ключом AKey не было в словаре, то добавляет пару (AKey, AData) в словарь и возвращает True, иначе изменяет поле Data значения с ключом AKey на AData и возвращает False
function Find(const AKey: TDicKey): Bool; возвращает True, если в словаре есть значение с ключом AKey, и False иначе
procedure Delete(const AKey: TDicKey); если в словаре есть значение с ключом AKey, то удаляет его, иначе возбуждает исключение
function Data(const AKey: TDicKey): TDicData; если в словаре есть значение с ключом AKey, то возращает поле Data этого значения, иначе возбуждает исключение
function PData(const AKey: TDicKey): PDicData; если в словаре есть значение с ключом AKey, то возращает указатель на поле Data этого значения, иначе возвращает nil

Потоки

В модулях VStream и FVStream библиотеки реализованы простые варианты потоков: абстрактный базовый поток (TVStream), поток, хранящий значения в памяти (TVMemStream) и файловый поток (TVFileStream). Все векторы и матрицы могут быть записаны и считаны из потока с помощью своих методов WriteToStream и ReadFromStream. Кроме того, реализованы потоки с CRC-контролем (TVCRCFileStream) и буферизованные файловые потоки (TVBufFileStream).

Методы класса TStream

function EOF: Bool; возвращает True, если текущая позиция находится в конце потока, иначе False;
procedure WriteProc(const Buffer; Count: Int32); abstract; записывает Count байт из буфера в поток;
function ReadFunc(var Buffer; Count: Int32): Int32; abstract; читает максимум Count байт из потока в буфер (может быть прочитано меньше, чем Count байт, если достигнут конец потока); возвращает количество реально прочитанных байт;
procedure ReadProc(var Buffer; Count: Int32); читает ровно Count байт из потока в буфер; если до конца потока осталось менее Count байт или произошла ошибка, то возбуждает исключение;
procedure CopyTo(DestinStream: TVStream); копирует данные в поток DestinStream; текущая позиция (Position) при этом в общем случае изменяется;
procedure WriteString(const S: String); записывает в поток строку;
procedure WriteInt8(I: Int8); записывает в поток целое 8-разрядное число;
procedure WriteInt16(I: Int16); записывает в поток целое 16-разрядное число;
procedure WriteInt32(I: Int32); записывает в поток целое 32-разрядное число;
function ReadString: String; читает из потока строку;
function ReadInt8: Int8; читает из потока целое 8-разрядное число;
function ReadInt16: Int16; читает из потока целое 16-разрядное число;
function ReadInt32: Int32; читает из потока целое 32-разрядное число;

Свойства класса TStream

property Position: Int32; текущая позиция в потоке (R/W);
property Size: Int32; размер потока (R/W);

Следующий пример демонстрирует запись матрицы в поток (TVMemStream) и чтение ее из потока:

uses
  F64m, VStream;
var
  S: TVMemStream;
  A, B: TFloat64Matrix;
begin
  A:=TFloat64Matrix.Create(3, 2, 0);
  B:=TFloat64Matrix.Create(0, 0, 0);
  S:=TVMemStream.Create;
  try
    A.SetItems([
      3.5, 2.7,
      -0.2, 4.5,
      3.6, 7,2
    ]);
    writeln('A:');
    A.DebugWrite;
    A.WriteToStream(S);
    S.Seek(0); { то же: S.Position:=0 }
    B.ReadFromStream(S);
    writeln('B:');
    B.DebugWrite;
  finally
    A.Free;
    B.Free;
    S.Free;
  end;
end.

В моделе TxtStrm реализован класс текстовых потоков TTextStream. Данный класс поддерживает запись и чтение строк, целых и вещественных чисел. Кроме того, поддерживается операция "отката" (RollBack), позволяющая вернуться к предыдущей прочитанной строке.

Методы и свойства класса TTextStream

function EOF: Bool; возвращает True, если текущая позиция находится в конце потока, иначе False;
function CreateBookmark: TTextStreamBookmark; создать "закладку" на текущей позиции;
procedure GotoBookmark(ABookmark: TTextStreamBookmark); переходит на "закладку";
procedure PassEmpty; пропускает пустые или состоящие целиком из символов с кодами <= ' ' строки;
function ReadString: String; читает очередную строку;
function ReadTrimmed: String; читает очередную строку и возвращает результат, в котором "обрезаны" и конечные символы с кодами <= ' ';
function ReadInteger: Integer; читает целое значение (оно должно занимать отдельную строку);
procedure WriteString(const S: String); записывает строку и символы перевода строки в поток;
procedure WriteInteger(I: Integer); записывает целое значение и символы перевода строки в поток;
procedure WriteSection(const SectionName: String); записывает в поток строку вида "[SectionName]";
procedure WriteStringKey(const Key, Value: String); записывает в поток строку вида "Key=Value";
procedure WriteIntegerKey(const Key: String; Value: Integer); записывает в поток строку вида "Key=Value";
procedure RollBack; выполняет "откат" на предыдущую строку (при следующем вызове ReadXXXX будет возвращено то же значение); откат невозможен, если был выполнен метод Flush или после открытия потока / вызова метода PassEmpty не была прочитана ни одна строка - тогда возбуждается исключительная ситуация;
procedure Flush; записывает на диск системный файловый буфер, связанный с потоком;
property LineNumber: Int32; номер последней прочитанной или записанной строки (RO);

В качестве примера рассмотрим программу, которая копирует входной файл в выходной, пропуская повторяющиеся строки:

program deldup;
uses
  TxtStrm;

procedure Main;
var
  InStream, OutStream: TTextStream;
  LastString, T: String;
begin
  InStream:=TTextStream.Create(ParamStr(1), tsRead);
  OutStream:=nil;
  try
    OutStream:=TTextStream.Create(ParamStr(2), tsRewrite);
    LastString:='';
    while not InStream.EOF do begin
      T:=InStream.ReadTrimmed;
      if T <> LastString then begin
        OutStream.WriteString(T);
        LastString:=T;
      end;
    end;
  finally
    InStream.Free;
    OutStream.Free;
  end;
end;

begin
  if ParamCount > 1 then
    Main
  else
    writeln('Usage: deldup <from_file> <to_file>');
end.

Надежность и эффективность

При написании библиотеки учитывались соображения эффективности, надежности и переносимости. Многие векторные операции реализованы на встроенном ассемблере Delphi 3, в то же время для всех методов существуют варианты, полностью написанные на Object Pascal. Ассемблерные процедуры оптимизированы (если они оптимизированы) для выполнения на процессорах класса Pentium (см. модуль VectProc). Если процессор поддерживает MMX-расширения, то для выполнения некоторых операций над 8- и 16-битными целочисленными векторами используются MMX-команды. Компиляция модулей библиотеки управляется директивами условной компиляции, которые находятся в файле VCheck.inc. При отладке следует включить условия, отвечающие за различные run-time проверки (условие VDEBUG включает все возможные проверки, реализованных в классах библиотеки; условия CHECK_VECTORS, CHECK_MATRIXES и CHECK_OBJECTS_FREE служат для включения отдельных видов проверок). Следует также включить опции компилятора, отвечающие за run-time проверки ($R+, $Q+), и запретить использование ассемблерных фрагментов, так как в них не реализованы проверки на выход значение из диапазона или переполнение. Для получения максимально эффективного рабочего варианта программы следует отключить все проверки и разрешить использование ассемблера (USE_ASM).