{
    StringPools содержит класс для создания множества уникальных текстовых строк
    с учётом регистра. Используется для разработки статических рекомпиляторов.

    Copyright © 2016–2017, 2019–2022 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
}

unit StringPools;

{$MODE DELPHI}

interface

uses
    Lang;

{%region public }
type
    StringPool = class(_Object)
    strict private
        count: int;
        pool: AnsiString_Array1d;
    public
        constructor create();
        procedure clear();
        procedure delete(index: int);
        procedure setString(index: int; const str: AnsiString);
        function acquireStringIndex(const str: AnsiString): int;
        function indexOfString(const str: AnsiString): int;
        function getString(index: int): AnsiString;
        function getLength(): int;
    end;
{%endregion}

implementation

{%region StringPool }
    constructor StringPool.create();
    begin
        inherited create();
    end;

    procedure StringPool.clear();
    begin
        count := 0;
        pool := nil;
    end;

    procedure StringPool.delete(index: int);
    var
        c: int;
    begin
        if (index < 0) or (index >= count) then begin
            raise ArrayIndexOutOfBoundsException.create(index);
        end;
        c := count - index - 1;
        if c > 0 then begin
            arraycopy(pool, index + 1, pool, index, c);
        end;
        dec(count);
        pool[count] := '';
    end;

    procedure StringPool.setString(index: int; const str: AnsiString);
    begin
        if (index < 0) or (index >= count) then begin
            raise ArrayIndexOutOfBoundsException.create(index);
        end;
        pool[index] := str;
    end;

    function StringPool.acquireStringIndex(const str: AnsiString): int;
    var
        p: AnsiString_Array1d;
    begin
        result := indexOfString(str);
        if result >= 0 then begin
            exit;
        end;
        result := count;
        if result = length(pool) then begin
            p := String_Array1d_create(result * 2 + 1);
            arraycopy(pool, 0, p, 0, result);
            pool := p;
        end;
        pool[result] := str;
        count := result + 1;
    end;

    function StringPool.indexOfString(const str: AnsiString): int;
    var
        i: int;
        p: AnsiString_Array1d;
    begin
        p := pool;
        for i := count - 1 downto 0 do begin
            if p[i] = str then begin
                result := i;
                exit;
            end;
        end;
        result := -1;
    end;

    function StringPool.getString(index: int): AnsiString;
    begin
        if (index < 0) or (index >= count) then begin
            raise ArrayIndexOutOfBoundsException.create(index);
        end;
        result := pool[index];
    end;

    function StringPool.getLength(): int;
    begin
        result := count;
    end;
{%endregion}

end.

