Главная страницаОбратная связьКарта сайта

Быстрые списки

Автор: Vitaly Sergienko
WEB-сайт: http://delphibase.endimus.com

{ **** UBPFD *********** by delphibase.endimus.com ****
>> Быстрые списки.

Цепочка - односвязный список записей (record) фиксированной длины.
Пул цепочек позволяет быстро манипулировать с множеством цепочек.
Общая для всех цепочек конкретного пула память выделяется по мере
необходимости страницами через VirtualAlloc, т.е. без обращения к
менеджеру памяти (GetMem/FreeMem). Соответственно, освобождается
память сразу всего пула. Удобно использовать цепочки в качестве
рабочей памяти, когда нужно раскидать множество элементов по кучкам,
а также при реализации графов ( списки соседей узла ), деревьев
(списки детей узла). Большинство методов и функций написано на basm.

Зависимости: System
Автор:       Alex Konshin, akonshin@earthlink.net, Boston, USA
Copyright:   http://home.earthlink.net/~akonshin/index.htm
Дата:        30 декабря 2002 г.
***************************************************** }

// (c) Alex Konshin mailto:alexk@mtgroup.ru 08 Feb 1999

// 21 jun 2000 - bugfix PutValue
// all "uses" are removed

unit ChainPools;

interface

//uses

type

  PChainLink = ^TChainLink;
  PPChainLink = ^PChainLink;
  TChainLink = packed record
    FNext: PChainLink;
    FValue: LongInt;
  end;

  PPoolBuffer = ^TPoolBuffer;
  PPPoolBuffer = ^PPoolBuffer;
  TPoolBuffer = record
    FNextBuf: PPoolBuffer;
  end;

  TChainLinkCallBack = function(const Value: LongInt; const ALink: PChainLink;
    AParm: Pointer): Boolean;
  TScanChainCallBack = function(ALink: PChainLink; AParm: Pointer): Boolean of
    object;

  TChainPool = class
  protected
    FFirstBuffer: PPoolBuffer;
    FPLastBuffer: PPPoolBuffer;
    FRest: LongWord;
    FTop: PChar;
    FItemSize: Integer;
    function Allocate(const ASize: LongWord): Pointer;
  public
    FFreeChain: PChainLink;
    constructor Create(AItemSize: Integer = SizeOf(TChainLink));
    destructor Destroy; override;
    procedure FreeBuffers;
    // извлекаем из цепочки первый элемент (освобождается)
    function GetValue(var AAnchor: PChainLink): LongInt; virtual;
    // извлекаем из цепочки первый элемент (отсоединяется от цепочки)
    function GetFirstLink(var AAnchor: PChainLink): PChainLink; virtual;
    // извлекаем из цепочки последний элемент (освобождается)
    function GetLastValue(var AAnchor: PChainLink): LongInt; virtual;
    // извлекаем из цепочки последний элемент (отсоединяется от цепочки)
    function GetLastLink(var AAnchor: PChainLink): PChainLink; virtual;
    // вставка в начало без проверки на уникальность
    procedure PutValue(const Value: LongInt; var AAnchor: PChainLink); virtual;
    // вставка в конец с проверкой, False - значение уже существует
    function AddValue(const Value: LongInt; var AAnchor: PChainLink): Boolean;
      virtual;
    // вставка перед звеном, на которое ACallBackFunc выдаст True
    function InsertValue(const Value: LongInt; var AAnchor: PChainLink;
      ACallBackFunc: TChainLinkCallBack; AParm: Pointer = nil): PChainLink;
      virtual;
    // вставка в цепочку в порядке возврастания Value
    function InsertSorted(const Value: LongInt; var AAnchor: PChainLink):
      PChainLink; virtual;
    // удаление указанного значения //
    function RemoveValue(const Value: LongInt; var AAnchor: PChainLink): Boolean;
      virtual;
    // удаление указанного звена
    function RemoveLink(const ALink: PChainLink; var AAnchor: PChainLink):
      Boolean; virtual;
    // создает новый элемент, непривязанный к какой-либо цепочке
    function NewLink: PChainLink; // virtual;
    // освобождение элемента - перенос в список FFreeChain (элемент не должен принадлежать какой-либо цепочке)
    procedure FreeLink(const ALink: PChainLink); virtual;
    // освобождение цепочки
    procedure FreeChain(var AAnchor: PChainLink); virtual;
  end; { TChainPool }

  // вставка элемента в начало цепочки(элемент не должен принадлежать какой-либо цепочке)
procedure LinkTo(const ALink: PChainLink; var AAnchor: PChainLink);
// вставка элемента в конец цепочки(элемент не должен принадлежать какой-либо цепочке)
procedure Append(const ALink: PChainLink; var AAnchor: PChainLink);
function MoveFirstToChain(var AFrom, ATo: PChainLink): PChainLink;
function MoveChainLink(const Value: LongInt; var AAnchor, ATo: PChainLink):
  Boolean;
function AppendChainLink(const Value: LongInt; var AFromChain, AToChain:
  PChainLink): Boolean;
function LastChainLink(const AAnchor: PChainLink): PChainLink;
// проверяем наличие указанного значения в цепочке
function IsValueInChain(const Value: LongInt; AAnchor: PChainLink): Boolean;
// ищем элемент (остается в цепочке)
function FindValue(const Value: LongInt; AAnchor: PChainLink): PChainLink;
function FindAndUnlink(var AAnchor: PChainLink; ACallBackFunc:
  TScanChainCallBack; AParm: Pointer = nil): PChainLink;
function IndexOfValue(const Value: LongInt; AAnchor: PChainLink): LongInt;
// ищем ChainLink, на который AScanChainFunc выдаст True
function ScanChain(const AAnchor: PChainLink; AScanChainFunc:
  TScanChainCallBack; AParm: Pointer): PChainLink;
function ChainLinkByIndex(AAnchor: PChainLink; AIndex: Integer): PChainLink;
function ChainLinkCount(AAnchor: PChainLink): Integer;
// сравнение цепочек, результат =0, <0, >0, abs(result) = индекс несовпавшего элемента
function CompareChains(AFromChain, AToChain: PChainLink): LongInt;

//=============================================================
implementation

const
  MEM_COMMIT = $1000;
  MEM_DECOMMIT = $4000;
  MEM_RELEASE = $8000;
  PAGE_READWRITE = 4;

  kernel = "kernel32.dll";

type
  DWORD = LongInt;
  BOOL = LongBool;

function VirtualAlloc(lpAddress: Pointer; dwSize, flAllocationType, flProtect:
  DWORD): Pointer; stdcall; external kernel name "VirtualAlloc";

function VirtualFree(lpAddress: Pointer; dwSize, dwFreeType: DWORD): BOOL;
  stdcall; external kernel name "VirtualFree";

//-------------------------------------------------------------
// вставка элемента (элемент не должен принадлежать какой-либо цепочке)

procedure LinkTo(const ALink: PChainLink; var AAnchor: PChainLink);
begin
  ALink^.FNext := AAnchor;
  AAnchor := ALink;
end;
//-------------------------------------------------------------
// вставка элемента в конец (элемент не должен принадлежать какой-либо цепочке)

procedure Append(const ALink: PChainLink; var AAnchor: PChainLink); assembler;
asm
@@FindLast:
  mov ecx,edx
  mov edx,[edx]
  test edx,edx
  jnz @@FindLast
  mov [eax],edx
  mov [ecx],eax
end;
//-------------------------------------------------------------
// перенос первого элемента в другую цепочку

function MoveFirstToChain(var AFrom, ATo: PChainLink): PChainLink; assembler;
asm
  mov ecx,[eax]
  test ecx,ecx
  jz @@Exit
  push edx
  mov edx,[ecx]
  mov [eax],edx
  pop edx
  mov eax,[edx]
  mov [ecx],eax
  mov [edx],ecx
@@Exit:
  mov eax,ecx
end;
//-------------------------------------------------------------

function MoveChainLink(const Value: LongInt; var AAnchor, ATo: PChainLink):
  Boolean; assembler;
asm
  push edi
  mov edi,eax
  jmp @@Start
@@Next:
  mov edx,eax
@@Start:
  mov eax,[edx]
  test eax,eax
  jz @@Done
  cmp edi,[eax].TChainLink.FValue
  jne @@Next
  mov edi,[eax]
  mov [edx],edi
  mov edi,[ecx]
  mov [eax],edi
  mov [ecx],eax
  mov eax,1
@@Done:
  pop edi
@@Exit:
end;
//-------------------------------------------------------------

function AppendChainLink(const Value: LongInt; var AFromChain, AToChain:
  PChainLink): Boolean; assembler;
asm
  push edi
  mov edi,eax
  jmp @@Start
@@Next:
  mov edx,eax
@@Start:
  mov eax,[edx]
  test eax,eax
  jz @@Done
  cmp edi,[eax].TChainLink.FValue
  jne @@Next
  mov edi,[eax]
  mov [edx],edi

@@FindLast:
  mov edx,ecx
  mov ecx,[ecx]
  test ecx,ecx
  jnz @@FindLast

  mov edi,[edx]
  mov [eax],edi
  mov [edx],eax
  mov eax,1
@@Done:
  pop edi
@@Exit:
end;
//-------------------------------------------------------------

function LastChainLink(const AAnchor: PChainLink): PChainLink; assembler;
asm
  mov edx,eax
  jmp @@Start
@@Next:
  mov eax,edx
  mov edx,[edx]
@@Start:
  test edx,edx
  jnz @@Next
@@Exit:
end;
//-------------------------------------------------------------

function ScanChain(const AAnchor: PChainLink; AScanChainFunc:
  TScanChainCallBack; AParm: Pointer): PChainLink;
var
  pNext: PChainLink;
begin
  pNext := AAnchor;
  while pNext <> nil do
  begin
    Result := pNext;
    pNext := pNext^.FNext;
    if AScanChainFunc(Result, AParm) then
      Exit;
  end;
  Result := nil;
end;
//-------------------------------------------------------------
// сравнение цепочек, результат =0, <0, >0, abs(result) = индекс несовпавшего элемента

function CompareChains(AFromChain, AToChain: PChainLink): LongInt; assembler;
asm
    mov ecx,1
    push esi
    mov esi,eax
@@loop:
    inc ecx
    test esi,esi
    jz @@1
    test edx,edx
    jz @@gt
    mov eax,[esi]
    sub eax,[edx]
    jz @@loop
    jc @@lt
    jmp @@gt

@@1:
    test edx,edx
    jz @@exit
@@lt:
    neg ecx
@@gt:
    mov eax,ecx
@@exit:
    pop esi
end;
//-------------------------------------------------------------

function IsValueInChain(const Value: LongInt; AAnchor: PChainLink): Boolean;
  assembler; // проверяем наличие указанного значения в цепочке
{
  while AAnchor<>nil do
  begin
    if AAnchor^.FValue=Value then
    begin
      Result := True;
      Exit;
    end;
    AAnchor := AAnchor^.FNext;
  end;
  Result := False;
}
asm
  test edx,edx
  jz @False
@loop:
  cmp eax,TChainLink[edx].FValue
  je @True
  mov edx,[edx]
  test edx,edx
  jnz @loop
@False:
  mov eax,0
  jmp @Exit
@True:
  mov eax,1
@Exit:
end;
//-------------------------------------------------------------

function FindValue(const Value: LongInt; AAnchor: PChainLink): PChainLink;
  assembler;
{ Result := AAnchor;
  while (Result<>nil)and(Result^.FValue<>Value) do Result := Result^.FNext;
}
asm
  xchg eax,edx
  test eax,eax
  jz @Exit
@loop:
  cmp edx,TChainLink[eax].FValue
  je @Exit
  mov eax,[eax]
  test eax,eax
  jnz @loop
@Exit:
end;
//-------------------------------------------------------------

function IndexOfValue(const Value: LongInt; AAnchor: PChainLink): LongInt;
asm
  test edx,edx
  jz @NotFound
  mov ecx,eax
  xor eax,eax
@loop:
  cmp ecx,TChainLink[edx].FValue
  je @Exit
  inc eax
  mov edx,[edx]
  test edx,edx
  jnz @loop
@NotFound:
  mov eax,-1
@Exit:
end;
//-------------------------------------------------------------
// Извлечение первого звена, для которого ACallBackFunc выдаст True
// Внимание! Найденный элемент отсоединяется от цепочки. Для присоединения к другой цепочке используйте LinkTo, для освобождения памяти - TChainPool.FreeLink

function FindAndUnlink(var AAnchor: PChainLink; ACallBackFunc:
  TScanChainCallBack; AParm: Pointer = nil): PChainLink; assembler;
var
  pParm: Pointer;
asm
  push edi
  push esi
  mov esi,eax // esi <= AAnchor
  mov eax,AParm
  mov pParm,eax
  mov edi,edx // edi <= ACallBackFunc
@NextLink:
  mov eax,[esi]
  mov edx,pParm
  call edi
  test eax,eax
  jnz @Unlink
  mov esi,[esi]
  test esi,esi
  jnz @NextLink
  xor eax,eax // для всех получили отказ
  jmp @Exit

@Unlink:
  mov eax,[esi]
  mov edx,[eax]
  mov [esi],edx
  mov dword ptr [eax],0
@Exit:
  pop esi
  pop edi
end;
//-------------------------------------------------------------

function ChainLinkByIndex(AAnchor: PChainLink; AIndex: Integer): PChainLink;
  assembler;
asm
  test eax,eax
  jz @Exit
  test edx,edx
  jz @Exit
@Next:
  mov eax,[eax]
  test eax,eax
  jz @Exit
  dec edx
  jnz @Next
@Exit:
end;
//-------------------------------------------------------------

function ChainLinkCount(AAnchor: PChainLink): Integer;
asm
  test eax,eax
  jz @Exit
  xor edx,edx
@Next:
  mov eax,[eax]
  inc edx
  test eax,eax
  jnz @Next
  mov eax,edx
@Exit:
end;

//==TChainPool===========================================================

constructor TChainPool.Create(AItemSize: Integer = SizeOf(TChainLink));
begin
  inherited Create;
  FPLastBuffer := @FFirstBuffer;
  FItemSize := AItemSize;
end;
//-------------------------------------------------------------

destructor TChainPool.Destroy;
begin
  FreeBuffers;
  inherited Destroy;
end;
//-------------------------------------------------------------

procedure TChainPool.FreeBuffers;
var
  pBuf: PPoolBuffer;
begin
  while FFirstBuffer <> nil do
  begin
    pBuf := FFirstBuffer;
    FFirstBuffer := FFirstBuffer^.FNextBuf;
    VirtualFree(pBuf, 0, MEM_RELEASE);
  end;
  FPLastBuffer := @FFirstBuffer;
  FFreeChain := nil;
  FRest := 0;
  FTop := nil;
end;
//-------------------------------------------------------------

function TChainPool.Allocate(const ASize: LongWord): Pointer;
var
  nSize: LongInt;
  pBuf: PPoolBuffer;
begin
  if FRest < ASize then
  begin
    nSize := (4095 + ASize + SizeOf(TPoolBuffer)) and (-4096);
    pBuf := PPoolBuffer(VirtualAlloc(nil, nSize, MEM_COMMIT, PAGE_READWRITE));
    if pBuf = nil then
      GetMem(pBuf, not 0);
        // raise Exception.Create("ChainPools: Out of memory"); - SysUtils required
    FPLastBuffer^ := pBuf;
    FPLastBuffer := @(pBuf^.FNextBuf);
    FTop := PChar(pBuf) + SizeOf(TPoolBuffer);
    FRest := nSize - SizeOf(TPoolBuffer);
  end;
  Dec(FRest, ASize);
  Result := FTop;
  Inc(FTop, ASize);
end;
//-------------------------------------------------------------

function TChainPool.AddValue(const Value: LongInt; var AAnchor: PChainLink):
  Boolean; assembler;
asm
  push edi
  push esi
  xor esi,esi
  mov edi,eax
  mov eax,[ecx]
  test eax,eax
  jz @@New
@@Compare:
  cmp edx,[eax].TChainLink.FValue
  je @@Done
  mov ecx,eax
  mov eax,[ecx]
  test eax,eax
  jnz @@Compare
@@New:
  inc esi
  push edx
  mov eax,edi
  mov edi,ecx
  call TChainPool.NewLink
  mov ecx,edi
@@Link:
  pop edx
  mov [eax].TChainLink.FValue,edx
  mov dword ptr [eax],0
  mov [ecx],eax
@@Done:
  mov eax,esi
  pop esi
  pop edi
end; {TChainPool.AddValue}
//-------------------------------------------------------------

procedure TChainPool.PutValue(const Value: LongInt; var AAnchor: PChainLink);
  assembler;
asm
  push edi
  mov edi,eax
  push edx
  push ecx
  call TChainPool.NewLink
  pop ecx
  pop edx
  mov TChainLink[eax].FValue,edx
  mov edx,[ecx]
  mov [eax],edx
  mov [ecx],eax
@@Done:
  pop edi
end; {TChainPool.PutValue}
//-------------------------------------------------------------
// Вставка перед звеном, на которое ACallBackFunc выдаст True
// Будет предложено также вставить в конец - будет вызов ACallBackFunc с ALink=nil
// TChainLinkCallBack = function ( const Value : LongInt; const ALink : PChainLink; AParm : Pointer ) : Boolean;

function TChainPool.InsertValue(const Value: LongInt; var AAnchor: PChainLink;
  ACallBackFunc: TChainLinkCallBack; AParm: Pointer = nil): PChainLink; assembler;
var
  pSelf: LongInt;
asm
  push edi
  push esi
  mov pSelf,eax
  mov edi,edx // edi <= Value
  mov esi,ecx // esi <= AAnchor
@NextLink:
  mov eax,edi // AValue
  mov edx,[esi]
  mov ecx,AParm
  call [ACallBackFunc]
  test eax,eax
  jnz @Insert
  mov esi,[esi]
  test esi,esi
  jnz @NextLink
  xor eax,eax // для всех получили отказ
  jmp @Exit

@Insert:
  mov eax,pSelf
  call TChainPool.NewLink
  mov TChainLink[eax].FValue,edi
  mov edx,[esi]
  mov [eax],edx
  mov [esi],eax
@Exit:
  pop esi
  pop edi
end; {TChainPool.InsertValue}
//-------------------------------------------------------------
// CallBack для InsertSorted

function ChainLinkAscending(const Value: LongInt; const ALink: PChainLink;
  AParm: Pointer): Boolean;
begin
  Result := (Value < ALink.FValue);
end;
// вставка в цепочку в порядке возврастания Value

function TChainPool.InsertSorted(const Value: LongInt; var AAnchor: PChainLink):
  PChainLink;
begin
  Result := InsertValue(Value, AAnchor, ChainLinkAscending);
end;
//-------------------------------------------------------------
// освобождение элемента - перенос в список FFreeChain (элемент не должен принадлежать какой-либо цепочке)

procedure TChainPool.FreeLink(const ALink: PChainLink);
begin
  ALink^.FNext := FFreeChain;
  FFreeChain := ALink;
end;
//-------------------------------------------------------------
// создает новый элемент, непривязанный к какой-либо цепочке

function TChainPool.NewLink: PChainLink;
asm
  mov ecx,TChainPool[eax].FFreeChain
  test ecx,ecx
  jz @Allocate
  mov edx,[ecx]
  mov TChainPool[eax].FFreeChain,edx
  push ecx
  mov edx,TChainPool[eax].FItemSize
  mov eax,ecx
  mov ecx,0
  call System.@FillChar
  pop eax
  jmp @Exit
@Allocate:
  mov edx,TChainPool[eax].FItemSize
  call TChainPool.Allocate
@Exit:
end;
//-------------------------------------------------------------

function TChainPool.GetValue(var AAnchor: PChainLink): LongInt; assembler;
asm
  mov ecx,[edx]
  test ecx,ecx
  jnz @@1
  xor eax,eax
  jmp @@Exit

@@1:
  push edi
  mov edi,[ecx]
  mov [edx],edi
  mov edi,[eax].TChainPool.FFreeChain
  mov [ecx],edi
  mov [eax].TChainPool.FFreeChain,ecx
  pop edi
  mov eax,[ecx].TChainLink.FValue
@@Exit:
end;
//-------------------------------------------------------------

function TChainPool.GetFirstLink(var AAnchor: PChainLink): PChainLink;
  assembler;
asm
  mov eax,[edx]
  test eax,eax
  jz @Empty
  mov ecx,[eax]
  mov [edx],ecx
  mov dword ptr[eax],0
@Empty:
end;
//-------------------------------------------------------------

function TChainPool.RemoveValue(const Value: LongInt; var AAnchor: PChainLink):
  Boolean; assembler;
asm
  test eax,eax
  jz @@Exit
  push edi
  mov edi,eax
  jmp @@Start
@@Next:
  mov ecx,eax
@@Start:
  mov eax,[ecx]
  test eax,eax
  jz @@Done
  cmp edx,TChainLink[eax].FValue
  jne @@Next
  mov edx,[eax] // FNext
  mov [ecx],edx
  mov edx,TChainPool[edi].FFreeChain
  mov [eax],edx
  mov TChainPool[edi].FFreeChain,eax
  mov eax,1
@@Done:
  pop edi
@@Exit:
end;
//-------------------------------------------------------------

function TChainPool.RemoveLink(const ALink: PChainLink; var AAnchor:
  PChainLink): Boolean; assembler;
asm
  test eax,eax
  jz @@Exit
  push edi
  mov edi,eax
  test edx,edx
  jz @@False
  test ecx,ecx
  jnz @@Start
@@False:
  xor eax,eax
  jmp @@Done

@@Next:
  mov ecx,eax
@@Start:
  mov eax,[ecx]
  test eax,eax
  jz @@Done
  cmp edx,eax
  jne @@Next
  mov eax,[edx]
  mov [ecx],eax
  mov eax,[edi].TChainPool.FFreeChain
  mov [edx],eax
  mov [edi].TChainPool.FFreeChain,edx
  mov eax,1
@@Done:
  pop edi
@@Exit:
end;
//-------------------------------------------------------------

function TChainPool.GetLastValue(var AAnchor: PChainLink): LongInt; assembler;
asm
  mov ecx,[edx]
  test ecx,ecx
  jnz @@Start
  xor eax,eax
  jmp @@Exit

@@Next:
  mov edx,ecx
  mov ecx,[edx]
@@Start:
  cmp dword ptr [ecx],0
  jnz @@Next
  mov dword ptr [edx],0
  mov edx,[eax].TChainPool.FFreeChain
  mov [ecx],edx
  mov [eax].TChainPool.FFreeChain,ecx
  mov eax,[ecx].TChainLink.FValue
@@Exit:
end;
//-------------------------------------------------------------

function TChainPool.GetLastLink(var AAnchor: PChainLink): PChainLink; assembler;
asm
  mov eax,[edx]
  test eax,eax
  jz @Empty
  mov ecx,[eax]
  test ecx,ecx
  jz @Finish
@@Next:
  mov edx,eax
  mov eax,ecx
  mov ecx,[eax]
  test ecx,ecx
  jnz @@Next
@Finish:
  mov dword ptr [edx],0
@Empty:
end;
//-------------------------------------------------------------

procedure TChainPool.FreeChain(var AAnchor: PChainLink); assembler;
asm
  test eax,eax
  jz @@Exit
  test edx,edx
  jz @@Exit
  add eax,offset(TChainPool.FFreeChain)
  mov ecx,[edx]
  xchg ecx,[eax]
  mov eax,[edx]
  mov dword ptr[edx],0
  test eax,eax
  jz @@Done
@@Next:
  mov edx,eax
  mov eax,[edx]
  test eax,eax
  jnz @@Next
@@Done:
  mov [edx],ecx
@@Exit:
end;

end.

Пример использования:

program Test;

{$APPTYPE CONSOLE}
uses
  ChainPools;

type
  PItem = ^TItem;
  TItem = packed record
    FNext: PItem;
    FValue: LongInt;
    FValue2: LongInt;
  end;

  // It is just a holder of method.
  // In real life use forms or other objects.
  TSomeClass = class
    function FindValue2(ALink: PChainLink; AParm: Pointer): Boolean;
  end;

function TSomeClass.FindValue2(ALink: PChainLink; AParm: Pointer): Boolean;
begin
  Result := PLongInt(AParm)^ = PItem(ALink)^.FValue2;
end;

var
  oChainPool: TChainPool;
  pFirst1: PItem; // pointer to the first item in chain 1
  pFirst2: PItem; // pointer to the first item in chain 2
  ptr: PItem;
  nValue: LongInt;
  i: Integer;
  oSomeObject: TSomeClass;
begin

  oSomeObject := TSomeClass.Create;

  pFirst1 := nil;
  pFirst2 := nil;
  oChainPool := TChainPool.Create(SizeOf(TItem));

  // Put some values in chain 1
  for i := 0 to 99 do
    oChainPool.AddValue(i, PChainLink(pFirst1));

  // Put some values in chain 2
  for i := 0 to 99 do
  begin
    ptr := PItem(oChainPool.NewLink);
    with ptr^ do
    begin
      // put here the code that fills in new item"s fields.
      FValue := i;
      FValue2 := 100 - i;
    end;
    ChainPools.LinkTo(PChainLink(ptr), PChainLink(pFirst2));
  end;

  // Example for scanning chain.
  nValue := 30;
  ptr := PItem(ChainPools.ScanChain(PChainLink(pFirst2), oSomeObject.FindValue2,
    @nValue));
  if ptr = nil then
    WriteLn("Item is not found")
  else
    WriteLn("FValue = ", ptr^.FValue);

  // Scan chain
  ptr := pFirst2;
  while ptr <> nil do
  begin
    if ptr^.FValue2 = 30 then
    begin
      WriteLn("FValue = ", ptr^.FValue);
      Break;
    end;
    ptr := ptr^.FNext;
  end;

  // Destroy pool
  oChainPool.Free;

end.

Обсудить статью на форуме


Если Вас заинтересовала или понравилась информация по разработке на Delph - "Быстрые списки", Вы можете поставить закладку в социальной сети или в своём блоге на данную страницу:

Так же Вы можете задать вопрос по работе этого модуля или примера через форму обратной связи, в сообщение обязательно указывайте название или ссылку на статью!
   


Copyright © 2008 - 2024 Дискета.info