home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / lxlt121s.zip / lxLite_src / common / Collect.pas < prev    next >
Pascal/Delphi Source File  |  1997-01-23  |  11KB  |  499 lines

  1. {$A-,B-,D+,E-,F-,G-,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y+}
  2. {════════════════════════════════════════════════════════════════════════════}
  3. { Collections (dynamic arrays)                                               }
  4. { Portable source code (tested on DOS and OS/2)                              }
  5. { Original copyright (c) Borland International :-)                           }
  6. { Major modifications by Andrew Zabolotny, FRIENDS software                  }
  7. {════════════════════════════════════════════════════════════════════════════}
  8. Unit Collect;
  9.  
  10. Interface uses use32, miscUtil, Strings, Streams;
  11.  
  12. const
  13. {$ifDef use32}
  14.  MaxCollectionSize = (512*1024) div sizeOf(Pointer);
  15. {$else}
  16.  MaxCollectionSize = (64*1024-8) div sizeOf(Pointer);
  17. {$endIf}
  18. type
  19.  pCollection = ^tCollection;
  20.  tCollection = object(tObject)
  21.   Items       : pPointerArray;
  22.   Count       : Integer;
  23.   Limit       : Integer;
  24.   Delta       : Integer;
  25.   constructor Create(ALimit, ADelta : Integer);
  26.   constructor Load(var S : tStream);
  27.   constructor Clone(C : pCollection);
  28.   destructor  Destroy; virtual;
  29.   function    At(Index : Integer): Pointer;
  30.   procedure   AtDelete(Index : Integer);
  31.   procedure   AtFree(Index : Integer);
  32.   function    AtInsert(Index : Integer; Item : Pointer) : boolean;
  33.   procedure   AtReplace(Index : Integer; Item : Pointer);
  34.   procedure   Delete(Item : Pointer);
  35.   procedure   DeleteAll;
  36.   function    FirstThat(Test : Pointer) : Pointer;
  37.   procedure   ForEach(Action : Pointer);
  38.   procedure   FreeAll; virtual;
  39.   procedure   FreeItem(Item : Pointer); virtual;
  40.   function    GetItem(var S : tStream) : Pointer; virtual;
  41.   function    IndexOf(Item : Pointer) : Integer; virtual;
  42.   function    Insert(Item : Pointer) : Integer; virtual;
  43.   function    LastThat(Test : Pointer) : Pointer;
  44.   procedure   PutItem(var S : tStream; Item : Pointer); virtual;
  45.   procedure   SetLimit(ALimit : Integer); virtual;
  46.   procedure   Store(var S : tStream);
  47.  end;
  48.  
  49.  pSortedCollection = ^tSortedCollection;
  50.  tSortedCollection = object(tCollection)
  51.   Duplicates  : Boolean;
  52.   constructor Create(ALimit, ADelta : Integer);
  53.   constructor Load(var S : tStream);
  54.   function    Compare(Key1, Key2 : Pointer) : Integer; virtual;
  55.   function    IndexOf(Item : Pointer) : Integer; virtual;
  56.   function    Insert(Item : Pointer) : Integer; virtual;
  57.   function    KeyOf(Item : Pointer) : Pointer; virtual;
  58.   function    Search(Key : Pointer; var Index : Integer) : Boolean; virtual;
  59.   procedure   Store(var S : tStream);
  60.  end;
  61.  
  62.  pStringCollection = ^tStringCollection;
  63.  tStringCollection = object(tSortedCollection)
  64.   function    Compare(Key1, Key2 : Pointer) : Integer; virtual;
  65.   procedure   FreeItem(Item : Pointer); virtual;
  66.   function    GetItem(var S : tStream) : Pointer; virtual;
  67.   procedure   PutItem(var S : tStream; Item : Pointer); virtual;
  68.  end;
  69.  
  70.  pZTstrCollection = ^tZTstrCollection;
  71.  tZTstrCollection = object(tSortedCollection)
  72.   function    Compare(Key1, Key2 : Pointer) : Integer; virtual;
  73.   procedure   FreeItem(Item : Pointer); virtual;
  74.   function    GetItem(var S : tStream) : Pointer; virtual;
  75.   procedure   PutItem(var S : tStream; Item : Pointer); virtual;
  76.  end;
  77.  
  78.  pValueCollection = ^tValueCollection;
  79.  tValueCollection = object(tCollection)
  80.   procedure   FreeItem(Item : Pointer); virtual;
  81.  end;
  82.  
  83. Implementation
  84.  
  85. type
  86. {fake stream object for cloning collections}
  87.  pFakeStream = ^tFakeStream;
  88.  tFakeStream = object(tStream)
  89.   DataStorage : pByteArray;
  90.   DataPtr,
  91.   DataSize    : word;
  92.   function    Put(var Data; bytes : word) : word; virtual;
  93.   function    Get(var Data; bytes : word) : word; virtual;
  94.   destructor  Destroy; virtual;
  95.  end;
  96.  
  97. function tFakeStream.Put;
  98. var
  99.  nP : pByteArray;
  100. begin
  101.  GetMem(nP, DataSize + bytes);
  102.  Move(DataStorage^, nP^, DataSize);
  103.  Move(Data, nP^[DataSize], bytes);
  104.  FreeMem(DataStorage, DataSize);
  105.  Inc(DataSize, bytes);
  106.  DataStorage := nP;
  107.  DataPtr := 0;
  108.  Put := bytes;
  109. end;
  110.  
  111. function tFakeStream.Get;
  112. var
  113.  I : word;
  114. begin
  115.  I := minI(DataSize - DataPtr, bytes);
  116.  Move(DataStorage^[DataPtr], Data, I);
  117.  Inc(DataPtr, I);
  118.  if DataPtr >= DataSize
  119.   then begin
  120.         FreeMem(DataStorage, DataSize);
  121.         DataSize := 0;
  122.         DataPtr := 0;
  123.        end;
  124.  Get := I;
  125. end;
  126.  
  127. destructor tFakeStream.Destroy;
  128. begin
  129.  if DataSize > 0
  130.   then FreeMem(DataStorage, DataSize);
  131.  inherited Destroy;
  132. end;
  133.  
  134. constructor tCollection.Create;
  135. begin
  136.  inherited Create;
  137.  Items := nil;
  138.  Count := 0;
  139.  Limit := 0;
  140.  Delta := ADelta;
  141.  SetLimit(ALimit);
  142. end;
  143.  
  144. constructor tCollection.Load;
  145. var
  146.  C,I : Integer;
  147. begin
  148.  S.Get(Count, SizeOf(Integer) * 3);
  149.  Items := nil;
  150.  C := Count;
  151.  I := Limit;
  152.  Count := 0;
  153.  Limit := 0;
  154.  SetLimit(I);
  155.  Count := C;
  156.  for I := 0 to C - 1 do AtReplace(I, GetItem(S));
  157. end;
  158.  
  159. constructor tCollection.Clone;
  160. var
  161.  I : Integer;
  162.  S : pFakeStream;
  163. begin
  164.  inherited Create;
  165.  New(S, Create);
  166.  if S = nil then Fail;
  167.  Delta := C^.Delta;
  168.  SetLimit(C^.Limit);
  169.  For I := 0 to pred(C^.Count) do
  170.   begin
  171.    C^.PutItem(S^, C^.At(I));
  172.    AtInsert(I, GetItem(S^));
  173.   end;
  174.  Dispose(S, Destroy);
  175. end;
  176.  
  177. destructor tCollection.Destroy;
  178. begin
  179.  FreeAll;
  180.  inherited Destroy;
  181. end;
  182.  
  183. function tCollection.At;
  184. begin
  185.  if (Index < Count)
  186.   then At := Items^[Index]
  187.   else At := nil;
  188. end;
  189.  
  190. procedure tCollection.AtDelete;
  191. begin
  192.  if (Index < Count)
  193.   then begin
  194.         Move(Items^[succ(Index)], Items^[Index], sizeOf(Pointer) * (Count - succ(Index)));
  195.         Dec(Count);
  196.        end;
  197. end;
  198.  
  199. function tCollection.AtInsert;
  200. begin
  201.  AtInsert := FALSE;
  202.  if Index <= Count
  203.   then begin
  204.         if Count >= Limit
  205.          then SetLimit(Limit + Delta);
  206.         if Count < Limit
  207.          then begin
  208.                Move(Items^[Index], Items^[succ(Index)], sizeOf(Pointer) * (Count - Index));
  209.                Items^[Index] := Item;
  210.                Inc(Count);
  211.                AtInsert := TRUE;
  212.               end;
  213.        end;
  214. end;
  215.  
  216. procedure tCollection.AtReplace;
  217. begin
  218.  if (Index < Count)
  219.   then Items^[Index] := Item;
  220. end;
  221.  
  222. function tCollection.FirstThat;
  223. label
  224.  Found;
  225. var
  226.  I : Integer;
  227.  P : Pointer;
  228. begin
  229.  For I := 0 to pred(Count) do
  230.   begin
  231.    P := At(I);
  232.    if level2call(Test, P)
  233.     then Goto Found;
  234.   end;
  235.  P := nil;
  236. Found:
  237.  FirstThat := P;
  238. end;
  239.  
  240. function tCollection.LastThat;
  241. label
  242.  Found;
  243. var
  244.  I : Integer;
  245.  P : Pointer;
  246. begin
  247.  For I := pred(Count) downto 0 do
  248.   begin
  249.    P := At(I);
  250.    if level2call(Test, P)
  251.     then Goto Found;
  252.   end;
  253.  P := nil;
  254. Found:
  255.  LastThat := P;
  256. end;
  257.  
  258. procedure tCollection.ForEach;
  259. var
  260.  I : Integer;
  261. begin
  262.  For I := pred(Count) downto 0 do
  263.   level2call(Action, At(I));
  264. end;
  265.  
  266. function tCollection.IndexOf;
  267. var
  268.  I : Integer;
  269. begin
  270.  For I := 0 to pred(Count) do
  271.   if Item = At(I)
  272.    then begin
  273.          IndexOf := I;
  274.          exit;
  275.         end;
  276.  IndexOf := -1;
  277. end;
  278.  
  279. procedure tCollection.AtFree;
  280. var
  281.  Item : Pointer;
  282. begin
  283.  Item := At(Index);
  284.  AtDelete(Index);
  285.  FreeItem(Item);
  286. end;
  287.  
  288. procedure tCollection.Delete;
  289. begin
  290.  AtDelete(IndexOf(Item));
  291. end;
  292.  
  293. procedure tCollection.DeleteAll;
  294. begin
  295.  Count := 0;
  296. end;
  297.  
  298. procedure tCollection.FreeAll;
  299. var
  300.  I : Integer;
  301. begin
  302.  for I := 0 to pred(Count) do FreeItem(At(I));
  303.  DeleteAll; SetLimit(0);
  304. end;
  305.  
  306. procedure tCollection.FreeItem;
  307. begin
  308.  Dispose(pObject(Item), Destroy);
  309. end;
  310.  
  311. function tCollection.GetItem;
  312. var P : Pointer;
  313. begin
  314.  if S.Get(P, sizeOf(P)) = sizeOf(P)
  315.   then GetItem := P
  316.   else GetItem := nil;
  317. end;
  318.  
  319. procedure tCollection.PutItem;
  320. begin
  321.  S.Put(Item, sizeOf(Item));
  322. end;
  323.  
  324. function tCollection.Insert;
  325. begin
  326.  Insert := Count;
  327.  if not AtInsert(Count, Item)
  328.   then Insert := -1;
  329. end;
  330.  
  331. procedure tCollection.SetLimit;
  332. var
  333.  AItems : pPointerArray;
  334. begin
  335.  if ALimit < Count then ALimit := Count;
  336.  if ALimit > MaxCollectionSize then ALimit := MaxCollectionSize;
  337.  if ALimit <> Limit
  338.   then begin
  339.         if ALimit = 0
  340.          then AItems := nil
  341.          else begin
  342.                GetMem(AItems, ALimit * SizeOf(Pointer));
  343.                if AItems = nil then Exit;
  344.                if (Count <> 0) and (Items <> nil)
  345.                 then Move(Items^, AItems^, Count * SizeOf(Pointer));
  346.               end;
  347.         if Limit <> 0 then FreeMem(Items, Limit * SizeOf(Pointer));
  348.         Items := AItems;
  349.         Limit := ALimit;
  350.        end;
  351. end;
  352.  
  353. procedure tCollection.Store;
  354.  
  355. procedure DoPutItem(P : Pointer); far;
  356. begin
  357.  PutItem(S, P);
  358. end;
  359.  
  360. begin
  361.  S.Put(Count, SizeOf(Integer) * 3);
  362.  ForEach(@DoPutItem);
  363. end;
  364.  
  365. constructor tSortedCollection.Create;
  366. begin
  367.  inherited Create(ALimit, ADelta);
  368.  Duplicates := False;
  369. end;
  370.  
  371. constructor tSortedCollection.Load;
  372. begin
  373.  inherited Load(S);
  374.  S.Get(Duplicates, SizeOf(Duplicates));
  375. end;
  376.  
  377. function tSortedCollection.Compare;
  378. begin
  379.  Compare := Integer(Key1 = Key2);
  380. end;
  381.  
  382. function tSortedCollection.IndexOf(Item: Pointer): Integer;
  383. var
  384.  I : Integer;
  385. begin
  386.  IndexOf := -1;
  387.  if Search(KeyOf(Item), I)
  388.   then begin
  389.         if Duplicates
  390.          then while (I < Count) and (Item <> Items^[I]) do Inc(I);
  391.         if I < Count then IndexOf := I;
  392.        end;
  393. end;
  394.  
  395. function tSortedCollection.Insert;
  396. var
  397.  I : Integer;
  398. begin
  399.  if (not Search(KeyOf(Item), I)) or Duplicates
  400.   then if AtInsert(I, Item)
  401.         then Insert := I
  402.         else Insert := -1
  403.   else Insert := -1;
  404. end;
  405.  
  406. function tSortedCollection.KeyOf;
  407. begin
  408.  KeyOf := Item;
  409. end;
  410.  
  411. function tSortedCollection.Search;
  412. var
  413.  L,H,I,C : Integer;
  414. begin
  415.  Search := False;
  416.  L := 0;
  417.  H := Count - 1;
  418.  while L <= H do
  419.   begin
  420.    I := (L + H) shr 1;
  421.    C := Compare(KeyOf(Items^[I]), Key);
  422.    if C < 0
  423.     then L := I + 1
  424.     else begin
  425.           H := I - 1;
  426.           if C = 0
  427.            then begin
  428.                  Search := True;
  429.                  if not Duplicates then L := I;
  430.                 end;
  431.          end;
  432.   end;
  433.  Index := L;
  434. end;
  435.  
  436. procedure tSortedCollection.Store;
  437. begin
  438.  inherited Store(S);
  439.  S.Put(Duplicates, SizeOf(Duplicates));
  440. end;
  441.  
  442. function tStringCollection.Compare;
  443. var
  444.  Res : Integer;
  445. begin
  446.  Res := MemCmp(pString(Key1)^[1], pString(Key2)^[1],
  447.          MinI(length(pString(Key1)^), length(pString(Key2)^)));
  448.  if Res = 0
  449.   then if length(pString(Key1)^) < length(pString(Key2)^)
  450.         then Res := -1
  451.         else
  452.        if length(pString(Key1)^) > length(pString(Key2)^)
  453.         then Res := +1
  454.         else Res := 0;
  455.  Compare := Res;
  456. end;
  457.  
  458. procedure tStringCollection.FreeItem;
  459. begin
  460.  DisposeStr(Item);
  461. end;
  462.  
  463. function tStringCollection.GetItem;
  464. begin
  465.  GetItem := NewStr(S.GetStr);
  466. end;
  467.  
  468. procedure tStringCollection.PutItem;
  469. begin
  470.  S.PutStr(pString(Item)^);
  471. end;
  472.  
  473. function tZTstrCollection.Compare;
  474. begin
  475.  Compare := StrComp(Key1, Key2);
  476. end;
  477.  
  478. procedure tZTstrCollection.FreeItem;
  479. begin
  480.  StrDispose(Item);
  481. end;
  482.  
  483. function tZTstrCollection.GetItem;
  484. begin
  485.  GetItem := S.GetZTstr;
  486. end;
  487.  
  488. procedure tZTstrCollection.PutItem;
  489. begin
  490.  S.PutZTstr(Item);
  491. end;
  492.  
  493. procedure tValueCollection.FreeItem;
  494. begin
  495. end;
  496.  
  497. end.
  498.  
  499.