home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / h / hugecoll.zip / HUGECOLL.PAS next >
Pascal/Delphi Source File  |  1992-07-25  |  18KB  |  748 lines

  1. L{File name :HUGECOLL.PAS; Revision Date 23/5/1992 Size :556 Lines }
  2. unit hugecoll; {implement huge collection in TurboPascal for Windows}
  3.  
  4. interface
  5.  
  6. {----------Huge Collection and Huge SortedCollection Object----------}
  7. {      May 1992                                                      }
  8. {      Ver 0.1       (c) Nicholas Waltham, Oxford, United Kingdom    }
  9. {                        <SPEEDY%UK.AC.OX.VAX@UKACRL>                }
  10. {                        <100013.3330@COM.COMPUSERVE>                }
  11. {                                                                    }
  12. {                    Thanks to Jeroen Pluimers and other members of  }
  13. {                    the Usenet community for memory handling advice }
  14. {--------------------------------------------------------------------}
  15.  
  16. { NB                                                                    }
  17. {                                                                       }
  18. { o Programs compiled with the only386 option defined will not run in   }
  19. {   real mode - but who runs a 386 in real mode anyway!                 }
  20.  
  21. { o If anyone makes any significant alterations or has any bright ideas }
  22. {   then please forward them to me so I can keep one up to date copy    }
  23.  
  24. { o This is supplied as is - there is no warrenty expressed or implied  }
  25.  
  26. { o This code is released to the public domain and may be freely copied }
  27. {   No money must be charged for this code                              }
  28.  
  29.  
  30. uses
  31.  Wintypes,WinProcs,WObjects,Strings;
  32.  
  33. {$I p:\shared\objid.inc}
  34.  { This is a Pascal '.INC' file containing contants for all my object ids I have ever written
  35.    and prevents me from assigning the same id twice. You will need to define oidHugeCollection
  36.    and oidHugeSortedCollection constants for this unit}
  37.  
  38. {
  39. {$DEFINE Only386}
  40.  
  41.  {Define this flag is the subsequent code is only going to run on a 386base computer
  42.   or above - includes pointer calculation optimisation}
  43.  
  44.  
  45. type
  46.   LongType = record
  47.     case Word of
  48.       0: (Ptr: Pointer);
  49.       1: (Long: Longint);
  50.       2: (Lo: Word;
  51.       Hi: Word);
  52.   end;
  53.  
  54.  ppointer = ^pointer;
  55.  
  56.  
  57.  pHugeCollection = ^tHugeCollection;
  58.  tHugeCollection = Object (tObject)
  59.  
  60.  
  61.                    Items  : tHandle; {Handle to Global Memory}
  62.                    Count  : longint; {Current Number of Items}
  63.                    Limit  : longint; {Current Allocated size}
  64.                    Delta  : longint; {Number of items by which the collection grows when full}
  65.  
  66.  
  67.                    base   : longtype;  {global pointer to memory when locked}
  68.  
  69.  
  70.                    constructor init(aLimit, aDelta : Longint);
  71.  
  72.                    constructor Load(Var S : tStream);
  73.  
  74.  
  75.                    destructor  done; virtual;
  76.  
  77.                    function    At            (Index : Longint) : Pointer;
  78.                    procedure   AtDelete      (Index : Longint);
  79.                    procedure   AtInsert      (Index : Longint; Item : Pointer);
  80.                    procedure   AtPut         (Index : Longint; Item : Pointer);
  81.                    procedure   Delete        (Item : Pointer);
  82.                    procedure   DeleteAll;
  83.                    procedure   Error         (Code,Info : Integer); virtual;
  84.                    function    FirstThat     (Test : Pointer) : Pointer;
  85.                    procedure   ForEach       (Action : Pointer);
  86.                    procedure   Free          (Item : Pointer);
  87.                    procedure   FreeAll;
  88.                    procedure   FreeItem      (Item : Pointer); virtual;
  89.                    function    GetItem       (Var S : tStream) : Pointer; virtual;
  90.                    function    IndexOf       (Item : Pointer) : longint; virtual;
  91.                    procedure   Insert        (Item : Pointer); virtual;
  92.                    function    LastThat      (Test : Pointer) : Pointer;
  93.                    procedure   Pack;
  94.                    procedure   PutItem       (Var S : tStream; Item : Pointer); virtual;
  95.                    procedure   SetLimit      (aLimit : Longint);virtual;
  96.  
  97.                    procedure   Store         (Var S : tStream);
  98.  
  99.                    procedure   AtZero        (Index : Longint);
  100.  
  101.                    procedure   Lock;
  102.                    procedure   UnLock;
  103.  
  104.                    end;
  105.  
  106.  
  107.  
  108.  pHugeSortedCollection = ^tHugeSortedCollection;
  109.  
  110.  tHugeSortedCollection = Object(tHugeCollection)
  111.  
  112.  
  113.                          function       Compare (Key1,Key2 : Pointer): Integer; virtual;
  114.                          function       IndexOf (Item : Pointer): Longint; virtual;
  115.                          procedure      Insert  (Item : Pointer); virtual;
  116.                          function       KeyOf   (Item : Pointer): Pointer; virtual;
  117.                          function       Search  (key : Pointer; Var Index : Longint) : Boolean; virtual;
  118.  
  119.  
  120.                          end;
  121.  
  122.  
  123.  
  124. pCharHugeCollection        = ^tCharHugeCollection;
  125. tCharHugeCollection        = Object(tHugeCollection)
  126.  
  127.                              procedure   FreeItem      (Item : Pointer); virtual;
  128.  
  129.                              end;
  130.  
  131. pStrHugeCollection         = ^tStrHugeCollection;
  132. tStrHugeCollection         = Object(tHugeSortedCollection)
  133.  
  134.  
  135.                               function       Compare       (Key1,Key2 : Pointer): Integer; virtual;
  136.                               procedure      FreeItem      (Item : Pointer); virtual;
  137.  
  138.                               end;
  139.  
  140.  
  141.  
  142. const
  143.  RHugeCollection : tStreamRec =
  144.   (ObjType : oidHugeCollection;
  145.    VmtLink : Ofs(Typeof(tHugeCollection)^);
  146.    Load    : @tHugeCollection.load;
  147.    Store   : @tHugeCollection.Store);
  148.  
  149.  RHugeSortedCollection : tStreamRec =
  150.  
  151.   (ObjType : oidHugeSortedCollection;
  152.    VmtLink : Ofs(Typeof(tHugeSortedCollection)^);
  153.    Load    : @tHugeSortedCollection.load;
  154.    Store   : @tHugeSortedCollection.Store);
  155.  
  156.  
  157.  
  158. implementation
  159.  
  160.  
  161. Procedure _AHShift;  External 'KERNEL' Index 113;
  162. procedure _AHIncr;far; external 'Kernel' index 114; {The MAGINC! function}
  163.  
  164. const
  165.  cAHShift = {Ofs(_AHShift)}3 ;{This won't work in real mode!}
  166.   AHShift : word = cAHShift;
  167.  cAHIncr  = {Ofs(_AHShift)}8 ;{This won't work in real mode!}
  168.   AHIncr  : word = cAHIncr;
  169.  
  170.  
  171. {$IFDEF Only386}
  172.  
  173.  function Compute(base : Pointer;aIndex : Longint) : Pointer;
  174.  inline(
  175.  $66/$5B                      {Pop EBX                  ; Load EBX with Index}
  176.  /$58                         {Pop AX                   ; Load AX  with Offset(base)
  177.                                                          (Sensible since pointers are returned as DX:AX}
  178.  /$5A                         {Pop DX                   ; Load DX  with Segment(base) }
  179.  /$66/$C1/$E3/$02             {SHL EBX,2                ; Multiply EBX by 4           }
  180.  /$03/$C3                     {ADD AX,BX                ; Add Lower half of pointer to AX}
  181.  /$33/$DB                     {XOR BX,BX                ; Zero bottom 16bits of EBX      }
  182.  /$66/$C1/$EB/<($10-cAHShift) {SHR EBX,16 - AHShift     ; Shift Top of EBX into BX compensating for AHShift}
  183.                                                          {This won't work in real mode}
  184.  /$03/$D3                     {ADD DX,BX                ; Add to BX}
  185.  );
  186.  
  187. {$ELSE}
  188.  function Compute(base : Pointer;aIndex : Longint) : Pointer;
  189.  INLINE(
  190. $5B                     { POP BX                             }
  191. /$5A                    { POP DX                             }
  192. /$58                    { POP AX                             }
  193. /$D1/$E3                { SHL BX,1                           }
  194. /$D1/$D2                { RCL DX,1                           }
  195. /$D1/$E3                { SHL BX,1                           }
  196. /$D1/$D2                { RCL DX,1                           }
  197. /$03/$C3                { ADD AX,BX                          }
  198. /$8B/$DA                { MOV BX,DX                          }
  199. /$5A                    { POP DX                             }
  200. /$8B/$0E/>AHShift       { MOV CX,word([AHSHIFT])             }
  201. /$D3/$E3                { SHL BX,CL                          }
  202. /$03/$D3                { ADD DX,BX                          }
  203. );
  204. {$ENDIF}
  205.  
  206. const
  207.  sp = Sizeof(pointer);
  208.  
  209. constructor tHugeCollection.Init;
  210.  
  211. begin
  212.  tObject.Init;
  213.  Limit:=aLimit;
  214.  Delta:=aDelta;
  215.  Count:=0;
  216.  Items:=GlobalAlloc(gmem_moveable or gmem_nodiscard or gmem_zeroinit,Limit*sp);
  217.  If Items=0 then
  218.   begin
  219.   Error(-1,0);
  220.   exit;
  221.   end;
  222. end;
  223.  
  224. constructor tHugeCollection.Load;
  225.  
  226. var
  227.  i      : integer;
  228.  aCount : Longint;
  229.  
  230. begin
  231.  tObject.Init;
  232.  S.Read(Limit,Sizeof(Limit));
  233.  S.Read(Delta,Sizeof(Delta));
  234.  S.Read(aCount,Sizeof(aCount));
  235.  Count:=0;
  236.  Items:=GlobalAlloc(gmem_moveable or gmem_nodiscard or gmem_zeroinit,Limit*sp);
  237.  If Items=0 then
  238.   begin
  239.   Error(-1,0);
  240.   exit;
  241.   end;
  242.  For i:=0 to aCount-1 do
  243.   begin
  244.   AtInsert(I,GetItem(S));
  245.   end;
  246. end;
  247.  
  248.  
  249. destructor tHugeCollection.Done;
  250.  
  251. begin
  252. tObject.Done;
  253. FreeAll;
  254. Limit:=0;
  255. Items:=GlobalFree(Items);
  256. If Items<>0 then
  257.  begin
  258.  Error(-2,0);
  259.  exit;
  260.  end;
  261. end;
  262.  
  263. function tHugeCollection.At;
  264.  
  265.  
  266. begin
  267. If Index>Count-1 then
  268.  begin
  269.  Error(coIndexError,0);
  270.  At:=nil;
  271.  exit;
  272.  end;
  273. Lock;
  274.  At:=ppointer(Compute(base.ptr,Index))^;
  275. UnLock;
  276. end;
  277.  
  278. procedure tHugeCollection.Lock;
  279.  
  280. begin
  281.  Base.ptr:=GlobalLock(Items);
  282.  If Base.ptr=nil then
  283.   begin
  284.   Error(-3,0);
  285.   exit;
  286.   end;
  287. end;
  288.  
  289. procedure tHugeCollection.UnLock;
  290.  
  291. begin
  292.  GlobalUnLock(Items);
  293. end;
  294.  
  295.  
  296. {
  297. function tHugeCollection.Compute(base.ptr,aIndex : Longint) : pointer;
  298.  
  299. var
  300.  Result : LongType;
  301.  Posn   : LongType;
  302.  
  303.  
  304. begin
  305.  Posn.Long:=aIndex*sp;
  306.  Result.Lo:=Base.Lo+Posn.Lo;
  307.  Result.Hi:=Base.Hi+(Posn.Hi*Ofs(AHIncr));
  308.  Compute:=Result.ptr;
  309. end;
  310. }
  311.  
  312.  
  313. procedure tHugeCollection.AtDelete;
  314.  
  315. var
  316.  i : Longint;
  317.  
  318. begin
  319. If (Index<0) or (Index>=Count) then
  320.  begin
  321.  Error(coIndexError,0);
  322.  exit;
  323.  end;
  324. Lock;
  325.  If Index<Count-1 then
  326.  begin
  327.  for i:=Index to Count-2 do
  328.   begin
  329.    Move(Compute(base.ptr,i+1)^,Compute(base.ptr,i)^,sp);
  330.   end;
  331.  end;
  332. Dec(Count);
  333. UnLock;
  334. end;
  335.  
  336. procedure tHugeCollection.AtInsert;
  337.  
  338. var
  339.  i : Longint;
  340.  
  341. begin
  342. If (Index<0) or (Index>Count) then
  343.  begin
  344.  Error(coIndexError,0);
  345.  exit;
  346.  end;
  347. If Limit=Count then
  348.  begin
  349.  If Delta=0 then
  350.   begin
  351.   Error(coOverFlow,0);
  352.   exit;
  353.   end;
  354.  Inc(Limit,Delta);
  355.  Items:=GlobalReAlloc(Items,Limit*sp,gmem_moveable or gmem_nodiscard or gmem_zeroinit);
  356.  If Items=0 then
  357.   begin
  358.   Error(coOverFlow,0);
  359.   exit;
  360.   end;
  361.  end;
  362. Lock;
  363. If Index<>Count then
  364.  begin {Do a shuffle first}
  365.  i:=Count-1;
  366.  While i>=Index do
  367.   begin
  368.   Move(Compute(base.ptr,i)^,Compute(base.ptr,i+1)^,sp);
  369.   Dec(i);
  370.   end;
  371.  end;
  372. Move(Item,Compute(base.ptr,index)^,sp);
  373. UnLock;
  374. Inc(Count);
  375. end;
  376.  
  377. procedure tHugeCollection.AtPut;
  378.  
  379. begin
  380.  If (Index<0) or (Index>=Count) then
  381.   begin
  382.    Error(coIndexError,0);
  383.    exit;
  384.   end;
  385.  Lock;
  386.  Move(Item,Compute(base.ptr,index)^,sp);
  387.  UnLock;
  388. end;
  389.  
  390. procedure tHugeCollection.AtZero;
  391.  
  392.  
  393. begin
  394. Lock;
  395.  If (Index<Count) and (Index>=0) then LongType(Compute(base.ptr,index)^).long:=0;
  396. UnLock;
  397. end;
  398.  
  399. procedure tHugeCollection.Delete;
  400.  
  401. begin
  402.  AtDelete(Indexof(Item));
  403. end;
  404.  
  405. procedure tHugeCollection.DeleteAll;
  406.  
  407. begin
  408.  Count:=0;
  409. end;
  410.  
  411. procedure tHugeCollection.Error;
  412.  
  413. begin
  414. MessageBox(0,'There has been a HugeCollection error','tHuge Collection',mb_ok);
  415. Halt(1);
  416. end;
  417.  
  418. function tHugeCollection.FirstThat;
  419.  
  420. type
  421.  tTestFunc = function(i : pointer;bp : word) : Boolean;
  422.  
  423. var
  424.  i       : integer;
  425.  tbp     : word;
  426.  
  427. begin
  428.  i:=0;
  429.  asm
  430.   mov ax,[bp]
  431.   and al,$FE
  432.   mov tbp,ax
  433.  end;
  434.  While (i<Count) and Not (tTestFunc(Test)(At(i),tbp)) do Inc(i);
  435.  If i<Count then FirstThat:=At(i) else FirstThat:=nil;
  436. end;
  437.  
  438. procedure tHugeCollection.ForEach;
  439.  
  440. type
  441.  tActionProc = procedure(i : pointer;bp : word);
  442.  
  443. var
  444.  i     : longint;
  445.  tbp   : word;
  446.  
  447. begin
  448.  asm
  449.   mov ax,[bp]
  450.   and al,$FE
  451.   mov tbp,ax
  452.  end;
  453.  For i:=0 to Count-1 do
  454.   begin
  455.    tActionProc(Action)(At(i),tbp);
  456.   end;
  457. end;
  458.  
  459. procedure tHugeCollection.Free;
  460.  
  461. begin
  462.  Delete(Item);
  463.  FreeItem(Item);
  464. end;
  465.  
  466. procedure tHugeCollection.FreeAll;
  467.  
  468. var
  469.  i : integer;
  470.  
  471. begin
  472. for i:=0 to Count-1 do
  473.  begin
  474.  FreeItem(At(i));
  475.  end;
  476. Count:=0;
  477. end;
  478.  
  479. procedure tHugeCollection.FreeItem;
  480.  
  481. begin
  482.  If Item<>nil then Dispose(pObject(Item),Done);
  483. end;
  484.  
  485. function tHugeCollection.GetItem;
  486.  
  487. begin
  488. GetItem:=S.Get;
  489. end;
  490.  
  491. function tHugeCollection.IndexOf;
  492.  
  493. var
  494.  i : integer;
  495.  
  496. begin
  497. Lock;
  498.  i:=0;
  499.  while (i<count) and (ppointer(Compute(base.ptr,i))^<>item) do
  500.   begin
  501.   inc(i);
  502.   end;
  503. If i=count then IndexOf:=-1 else Indexof:=i;
  504. UnLock;
  505. end;
  506.  
  507.  
  508. procedure tHugeCollection.Insert;
  509.  
  510. begin
  511.  AtInsert(Count,Item);
  512. end;
  513.  
  514. function tHugeCollection.LastThat;
  515.  
  516. type
  517.  tTestFunc = function(i : pointer;bp : word) : Boolean;
  518.  
  519. var
  520.  i       : integer;
  521.  tbp     : word;
  522.  
  523. begin
  524.  i:=Count-1;
  525.  asm
  526.   mov ax,[bp]
  527.   and al,$FE
  528.   mov tbp,ax
  529.  end;
  530.  While (i>=0) and Not (tTestFunc(Test)(At(i),tbp)) do Dec(i);
  531.  If i>=0 then LastThat:=At(i) else LastThat:=nil;
  532. end;
  533.  
  534.  
  535. {$IFDEF only386}
  536.  
  537. procedure lodsd; inline ($66/$AD);
  538. procedure stosd; inline ($66/$AB);
  539. procedure or_eax_eax; inline ($66/$0B/$C0);
  540.  
  541. {$ELSE}
  542.  
  543. procedure lodsd; inline($AD/            {LODSW}
  544.                         $8B/$C8/        {MOV CX,AX}
  545.                         $AD             {LODSW}
  546.                         );
  547.  
  548. procedure stosd; inline($50/            {PUSH AX}
  549.                         $8B/$C1/        {MOV  AX,CX}
  550.                         $AB/            {STOSW}
  551.                         $58/            {POP  AX}
  552.                         $AB             {STOSW}
  553.                        );
  554.  
  555. procedure or_eax_eax; inline($0B/$C9/   {OR CX,CX}
  556.                              $75/$02/   {JNZ past the next compare}
  557.                              $0B/$C0    {OR AX,AX}
  558.                       );
  559.  
  560. {$ENDIF}
  561.  
  562. procedure tHugeCollection.Pack;
  563.  
  564. Label lp1,lp2,lp3;
  565.  
  566. var
  567.  sCount : Longint;
  568.  sBase  : Pointer;
  569.  sShift : Word;
  570.  sIncr  : Word;
  571.  
  572. begin
  573.  Lock;
  574.  sCount:=Count*Sizeof(pointer);
  575.  sBase:=Base.ptr;
  576.  sShift:=Ofs(_AHShift);
  577.  sIncr:=Ofs(_AHIncr);     { Move variables onto stack so still }
  578.  asm                      { available when DS has changed.     }
  579.   push ds;                { Store DS}
  580.   CLD                     { Clear Direction flag so that copy goes in right direction}
  581.   LDS  SI,sBase;          { Load DS:SI and ES:DI with array base}
  582.   LES  DI,sBase;
  583.   MOV  DX,DS              { Load DX:BX with array base }
  584.   MOV  BX,SI
  585.   ADD  BX,Word(sCount);
  586.   MOV  AX,Word(sCount)+2;
  587.   MOV  CX,[sShift];
  588.   SHL  AX,CL;
  589.   ADD  DX,AX;             { Set DX:BX to point to last element in array+1 }
  590. lp1:
  591.  end;
  592.   lodsd;                  { Load EAX with dword pointed to by DS:SI ; INC SI,4 }
  593.   or_eax_eax;             { Compare EAX with Zero If zero then don't copy it }
  594.  asm
  595.   JZ   lp2
  596.  end;
  597.   stosd;                  { Store EAX at ES:DI; INC DI,4 }
  598.  asm
  599.   OR   di,di
  600.   JNZ  lp2
  601.   MOV  AX,ES
  602.   ADD  AX,[sIncr]
  603.   MOV  ES,AX              { Increment ES selector by right amount when neccessary}
  604. lp2:
  605.   MOV  AX,DS
  606.   OR   SI,SI
  607.   JNZ  lp3
  608.   ADD  AX,[sIncr]
  609.   MOV  DS,AX              { Increment DS selector by right amount when neccessary}
  610. lp3:
  611.   CMP  AX,DX
  612.   JNE  lp1
  613.   CMP  SI,BX
  614.   JNE  lp1                  { Continue loop until DS=DX and SI=BX }
  615.   MOV  AX,DI
  616.   SUB  AX,word(sBase)
  617.   MOV  word(sCount),AX
  618.   MOV  AX,ES
  619.   SUB  AX,word(sBase)+2
  620.   MOV  CX,[sShift]
  621.   SHR  AX,CL
  622.   MOV  word(sCount)+2,AX
  623.   pop  ds;
  624.   end;
  625.  Count:=sCount DIV Sizeof(pointer);
  626.  UnLock;
  627. end;
  628.  
  629. Procedure tHugeCollection.PutItem;
  630.  
  631. begin
  632.  S.Put(Item);
  633. end;
  634.  
  635. procedure tHugeCollection.SetLimit;
  636.  
  637. begin
  638. Limit:=aLimit;
  639. Items:=GlobalReAlloc(Items,Limit*sp,gmem_moveable or gmem_nodiscard or gmem_zeroinit);
  640. If Items=0 then
  641.  begin
  642.  Error(-3,0);
  643.  exit;
  644.  end;
  645. end;
  646.  
  647. procedure tHugeCollection.Store;
  648.  
  649. var
  650.  i : integer;
  651.  
  652. begin
  653.  S.Write(Limit,Sizeof(Limit));
  654.  S.Write(Delta,Sizeof(Delta));
  655.  S.Write(Count,Sizeof(Count));
  656. For i:=0 to Count-1 do
  657.   begin
  658.   PutItem(S,At(i));
  659.   end;
  660. end;
  661.  
  662. function tHugeSortedCollection.Compare;
  663.  
  664. begin
  665.  Abstract;
  666. end;
  667.  
  668. function tHugeSortedCollection.IndexOf;
  669.  
  670. var
  671.  I : longint;
  672.  
  673. begin
  674.  if Search(KeyOf(Item),I) then IndexOf:=I else Indexof:=-1;
  675. end;
  676.  
  677. procedure tHugeSortedCollection.Insert;
  678.  
  679. var
  680.  I : longint;
  681.  
  682. begin
  683.  If Count=0 then AtInsert(0,Item) else
  684.  If not Search(Keyof(Item),I) then AtInsert(I,Item);
  685. end;
  686.  
  687. function tHugeSortedCollection.KeyOf;
  688.  
  689. begin
  690.  KeyOf:=Item;
  691. end;
  692.  
  693. function tHugeSortedCollection.Search;
  694.  
  695. var
  696.  First,Last,Middle : Longint;
  697.  result            : integer;
  698.  
  699. begin
  700.  First:=0;
  701.  Last:=Count-1;
  702.   repeat
  703.    middle:=(first+last) div 2;
  704.    result:=Compare(At(middle),Key);
  705.    if result>0 then
  706.     last:=middle-1
  707.    else
  708.     first:=middle+1
  709.   until (result=0) or (first>last);
  710.  if result=0 then
  711.   begin
  712.    Search:=True;
  713.    Index:=Middle
  714.   end else
  715.   begin
  716.    Search:=False;
  717.    Index:=first;
  718.   end;
  719. end;
  720.  
  721. {----------------------tCharHugeCollection--------------------------}
  722.  
  723. procedure tCharHugeCollection.FreeItem;
  724.  
  725. begin
  726.  If Item<>nil then StrDispose(pChar(Item));
  727. end;
  728.  
  729. {----------------------tStrHugeCollection--------------------------}
  730.  
  731. procedure tStrHugeCollection.FreeItem;
  732.  
  733. begin
  734.  If Item<>nil then StrDispose(pChar(Item));
  735. end;
  736.  
  737. function tStrHugeCollection.Compare;
  738.  
  739. begin
  740.  Compare:=StrComp(pChar(key1),pChar(key2));
  741. end;
  742.  
  743.  
  744. begin
  745.  AhIncr := Ofs(_AhIncr);
  746.  AHShift:= Ofs(_AhShift);
  747. end.
  748.