source: Generics/NativeGenerics/Generic/GenericMatrix.pas

Last change on this file was 496, checked in by chronos, 6 years ago
  • Modified: New native generics classes working under FPC 3.0 transformed from TemplateGenerics package.
File size: 14.8 KB
Line 
1unit GenericMatrix;
2
3{$mode delphi}
4
5interface
6
7type
8 TGMatrix<T> = class
9 public
10 type
11 TSortCompare = function(const Item1, Item2: T): Integer of object;
12 TToStringConverter = function(Item: T): string;
13 TFromStringConverter = function(Text: string): T;
14 TRow = array of T;
15 TMerge = function(Item1, Item2: T): T of object;
16
17 TIndex = record
18 X: Integer;
19 Y: Integer;
20 end;
21 private
22 FItems: array of array of T;
23 FCount: TIndex;
24 function GetItemXY(X: Integer; Y: Integer): T;
25 function GetItem(Index: TIndex): T;
26 function GetCapacity: TIndex;
27 function GetLast: T;
28 function GetFirst: T;
29 procedure SetCapacity(const AValue: TIndex);
30 procedure SetLast(AValue: T);
31 procedure SetFirst(AValue: T);
32 procedure PutItemXY(X: Integer; Y: Integer; const AValue: T); virtual;
33 procedure PutItem(Index: TIndex; const AValue: T); virtual;
34 procedure SetCount(const AValue: TIndex);
35 procedure RaiseIndexError(X, Y: Integer);
36 public
37 function Add(Item: T): TIndex;
38 procedure AddMatrix(Values: array of TRow);
39 procedure AddList(List: TGMatrix<T>);
40 procedure Assign(Source: TGMatrix<T>);
41 procedure Clear; virtual;
42 procedure Contract;
43 function CreateIndex(X: Integer; Y: Integer): TIndex;
44 procedure Delete(Index: TIndex); virtual;
45 procedure DeleteItems(Index, Count: TIndex);
46 function EqualTo(List: TGMatrix<T>): Boolean;
47 procedure Expand;
48 function Extract(Item: T): T;
49 procedure Exchange(Index1, Index2: TIndex);
50 property First: T read GetFirst write SetFirst;
51 procedure FillAll(Value: T);
52 procedure Fill(Start, Count: TIndex; Value: T);
53 function Implode(RowSeparator, ColSeparator: string; Converter: TToStringConverter): string;
54 procedure Explode(Text, Separator: string; Converter: TFromStringConverter; SlicesCount: Integer = -1);
55 function IndexOf(Item: T; Start: TIndex): TIndex;
56 function IndexOfList(List: TGMatrix<T>; Start: TIndex): TIndex;
57 procedure Insert(Index: TIndex; Item: T);
58 procedure InsertList(Index: TIndex; List: TGMatrix<T>);
59 procedure InsertArray(Index: TIndex; Values: array of T);
60 procedure Move(CurIndex, NewIndex: TIndex);
61 procedure MoveItems(CurIndex, NewIndex, Count: TIndex);
62 procedure Merge(Index: TIndex; Source: TGMatrix<T>; Proc: TMerge);
63 procedure Replace(Index: TIndex; Source: TGMatrix<T>);
64 function Remove(Item: T): TIndex;
65 procedure Reverse;
66 procedure ReverseHorizontal;
67 procedure ReverseVertical;
68 procedure Sort(Compare: TSortCompare);
69 procedure SetArray(Values: array of T);
70 property Count: TIndex read FCount write SetCount;
71 property Capacity: TIndex read GetCapacity write SetCapacity;
72 property ItemsXY[X: Integer; Y: Integer]: T
73 read GetItemXY write PutItemXY; default;
74 property Items[Index: TIndex]: T
75 read GetItem write PutItem;
76 property Last: T read GetLast write SetLast;
77 end;
78
79
80implementation
81
82uses
83 RtlConsts, Classes, SysUtils;
84
85resourcestring
86 SMatrixIndexError = 'Matrix index error [X: %d, Y: %d]';
87
88
89{ TGMatrix }
90
91procedure TGMatrix<T>.RaiseIndexError(X, Y: Integer);
92begin
93 raise EListError.CreateFmt('Matrix index error [X: %d, Y: %d]', [X, Y]);
94end;
95
96procedure TGMatrix<T>.Replace(Index: TIndex; Source: TGMatrix<T>);
97var
98 X: Integer;
99 Y: Integer;
100begin
101 Y := 0;
102 while Y < Source.Count.Y do begin
103 X := 0;
104 while X < Source.Count.X do begin
105 ItemsXY[Index.X + X, Index.Y + Y] := Source.ItemsXY[X, Y];
106 X := X + 1;
107 end;
108 Y := Y + 1;
109 end;
110end;
111
112procedure TGMatrix<T>.Merge(Index: TIndex; Source: TGMatrix<T>; Proc: TMerge);
113var
114 X: Integer;
115 Y: Integer;
116begin
117 Y := 0;
118 while Y < Source.Count.Y do begin
119 X := 0;
120 while X < Source.Count.X do begin
121 ItemsXY[Index.X + X, Index.Y + Y] := Proc(ItemsXY[Index.X + X, Index.Y + Y], Source.ItemsXY[X, Y]);
122 X := X + 1;
123 end;
124 Y := Y + 1;
125 end;
126end;
127
128function TGMatrix<T>.CreateIndex(X: Integer; Y: Integer): TIndex;
129begin
130 Result.X := X;
131 Result.Y := Y;
132end;
133
134function TGMatrix<T>.GetCapacity: TIndex;
135begin
136 Result.Y := Length(FItems);
137 if Result.Y > 0 then Result.X := Length(FItems[0]) else Result.X := 0;
138end;
139
140procedure TGMatrix<T>.SetCapacity(const AValue: TIndex);
141var
142 Y: Integer;
143begin
144 if (Capacity.X <> AValue.X) and (Capacity.Y <> AValue.Y) then begin
145(* SetLength(FItems, AValue.Y);
146 Y := 0;
147 while Y < Length(FItems) do begin
148 SetLength(FItems[Y], AValue.X);
149 Y := Y + 1;
150 end;
151 end;
152 *)
153 SetLength(FItems, AValue.Y, AValue.X);
154 end;
155end;
156
157function TGMatrix<T>.GetItemXY(X, Y: Integer): T;
158begin
159 if (X < 0) or (X >= Count.X) or
160 (Y < 0) or (Y >= Count.Y) then
161 RaiseIndexError(X, Y);
162 Result := FItems[Y, X];
163end;
164
165function TGMatrix<T>.GetItem(Index: TIndex): T;
166begin
167 if (Index.X < 0) or (Index.X >= Count.X) or
168 (Index.Y < 0) or (Index.Y >= Count.Y) then
169 RaiseIndexError(Index.X, Index.Y);
170 Result := FItems[Index.Y, Index.X];
171end;
172
173procedure TGMatrix<T>.PutItemXY(X: Integer; Y: Integer; const AValue: T);
174begin
175 if (X < 0) or (X >= Count.X) or
176 (Y < 0) or (Y >= Count.Y) then
177 RaiseIndexError(X, Y);
178 FItems[Y, X] := AValue;
179end;
180
181procedure TGMatrix<T>.PutItem(Index: TIndex; const AValue: T);
182begin
183 if (Index.X < 0) or (Index.X >= Count.X) or
184 (Index.Y < 0) or (Index.Y >= Count.Y) then
185 RaiseIndexError(Index.X, Index.Y);
186 FItems[Index.Y, Index.X] := AValue;
187end;
188
189procedure TGMatrix<T>.SetCount(const AValue: TIndex);
190begin
191 Capacity := AValue;
192 FCount := AValue;
193end;
194
195procedure TGMatrix<T>.Assign(Source: TGMatrix<T>);
196var
197 Index: TIndex;
198begin
199 Count := Source.Count;
200 Index.Y := 0;
201 while Index.Y < Count.Y do begin
202 Index.X := 0;
203 while Index.X < Count.X do begin
204 Items[Index] := Source.Items[Index];
205 Index.X := Index.X + 1;
206 end;
207 Index.Y := Index.Y + 1;
208 end;
209end;
210
211procedure TGMatrix<T>.Expand;
212var
213 IncSize: TIndex;
214 NewCapacity: TIndex;
215begin
216 if (FCount.X = Capacity.X) then begin
217 IncSize.X := 4;
218 if Capacity.X > 3 then IncSize.X := IncSize.X + 4;
219 if Capacity.X > 8 then IncSize.X := IncSize.X + 8;
220 if Capacity.X > 63 then IncSize.X := IncSize.X + Capacity.X shr 2;
221 NewCapacity.X := Capacity.X + IncSize.X;
222 end;
223 if (FCount.Y = Capacity.Y) then begin
224 IncSize.Y := 4;
225 if Capacity.Y > 3 then IncSize.Y := IncSize.Y + 4;
226 if Capacity.Y > 8 then IncSize.Y := IncSize.Y + 8;
227 if Capacity.Y > 63 then IncSize.Y := IncSize.Y + Capacity.Y shr 2;
228 NewCapacity.Y := Capacity.Y + IncSize.Y;
229 end;
230 Capacity := NewCapacity;
231end;
232
233procedure TGMatrix<T>.Contract;
234var
235 NewCapacity: TIndex;
236begin
237 if (Capacity.X > 256) and (FCount.X < Capacity.X shr 2) then
238 begin
239 NewCapacity.X := Capacity.X shr 1;
240 end;
241 if (Capacity.Y > 256) and (FCount.Y < Capacity.Y shr 2) then
242 begin
243 NewCapacity.Y := Capacity.Y shr 1;
244 end;
245 Capacity := NewCapacity;
246end;
247
248function TGMatrix<T>.Extract(Item: T): T;
249var
250 I: TIndex;
251begin
252(* I := IndexOf(Item);
253 if I >= 0 then begin
254 Result := Item;
255 Delete(I);
256 end else
257 raise EListError.CreateFmt(SListIndexError, [0]);
258 *)
259end;
260
261function TGMatrix<T>.IndexOf(Item: T; Start: TIndex): TIndex;
262begin
263(* Result := Start;
264 while (Result < FCount) and
265 not CompareMem(Addr(FItems[Result]), Addr(Item), SizeOf(T)) do
266 Result := Result + 1;
267 if Result = FCount then Result := -1;
268 *)
269end;
270
271procedure TGMatrix<T>.Insert(Index: TIndex; Item: T);
272begin
273(* if (Index < 0) or (Index > FCount ) then
274 raise EListError.CreateFmt(SListIndexError, [Index]);
275 if FCount = Capacity then Expand;
276 if Index < FCount then
277 System.Move(FItems[Index], FItems[Index + 1], (FCount - Index) * SizeOf(T));
278 FItems[Index] := Item;
279 FCount := FCount + 1;
280 *)
281end;
282
283procedure TGMatrix<T>.InsertList(Index: TIndex; List: TGMatrix<T>);
284var
285 I: TIndex;
286begin
287(* I := 0;
288 while (I < List.Count) do begin
289 Insert(Index + I, List[I]);
290 I := I + 1;
291 end;
292 *)
293end;
294
295function TGMatrix<T>.IndexOfList(List: TGMatrix<T>; Start: TIndex): TIndex;
296var
297 I: TIndex;
298begin
299(* if List.Count > 0 then begin
300 Result := IndexOf(List[0], Start);
301 if Result <> -1 then begin
302 I := 1;
303 while I < List.Count do begin
304 if not CompareMem(Addr(FItems[Result + I]), Addr(List.FItems[I]), SizeOf(T)) then begin
305 Result := -1;
306 Break;
307 end;
308 I := I + 1;
309 end;
310 end;
311 end else Result := -1;
312 *)
313end;
314
315function TGMatrix<T>.GetLast: T;
316begin
317(* if FCount = 0 then
318 raise EListError.CreateFmt(SListIndexError, [0])
319 else
320 Result := Items[FCount - 1];
321 *)
322end;
323
324procedure TGMatrix<T>.SetLast(AValue: T);
325begin
326(* if FCount = 0 then
327 raise EListError.CreateFmt(SListIndexError, [0])
328 else
329 Items[FCount - 1] := AValue;
330 *)
331end;
332
333function TGMatrix<T>.GetFirst: T;
334begin
335(* if FCount = 0 then
336 raise EListError.CreateFmt(SListIndexError, [0])
337 else
338 Result := Items[0];
339 *)
340end;
341
342procedure TGMatrix<T>.SetFirst(AValue: T);
343begin
344(* if FCount = 0 then
345 raise EListError.CreateFmt(SListIndexError, [0])
346 else
347 Items[0] := AValue;
348 *)
349end;
350
351procedure TGMatrix<T>.Move(CurIndex, NewIndex: TIndex);
352var
353 Temp: T;
354begin
355(* if ((CurIndex < 0) or (CurIndex > Count - 1)) then
356 raise EListError.CreateFmt(SListIndexError, [CurIndex]);
357 if ((NewIndex < 0) or (NewIndex > Count -1)) then
358 raise EListError.CreateFmt(SlistIndexError, [NewIndex]);
359 Temp := FItems[CurIndex];
360 if NewIndex > CurIndex then begin
361 System.Move(FItems[CurIndex + 1], FItems[CurIndex], (NewIndex - CurIndex) * SizeOf(T));
362 end else
363 if NewIndex < CurIndex then begin
364 System.Move(FItems[NewIndex], FItems[NewIndex + 1], (CurIndex - NewIndex) * SizeOf(T));
365 end;
366 FItems[NewIndex] := Temp;
367 //Delete(CurIndex);
368 //Insert(NewIndex, Temp);*)
369end;
370
371procedure TGMatrix<T>.MoveItems(CurIndex, NewIndex, Count: TIndex);
372var
373 S: Integer;
374 D: Integer;
375begin
376(* if CurIndex < NewIndex then begin
377 S := CurIndex + Count - 1;
378 D := NewIndex + Count - 1;
379 while S >= CurIndex do begin
380 Move(S, D);
381 S := S - 1;
382 D := D - 1;
383 end;
384 end else
385 if CurIndex > NewIndex then begin
386 S := CurIndex;
387 D := NewIndex;
388 while S < (CurIndex + Count) do begin
389 Move(S, D);
390 S := S + 1;
391 D := D + 1;
392 end;
393 end;*)
394end;
395
396function TGMatrix<T>.Remove(Item: T): TIndex;
397begin
398(* Result := IndexOf(Item);
399 if Result <> -1 then
400 Delete(Result); *)
401end;
402
403function TGMatrix<T>.EqualTo(List: TGMatrix<T>): Boolean;
404var
405 I: TIndex;
406begin
407(* Result := Count = List.Count;
408 if Result then begin
409 I := 0;
410 while I < Count do begin
411 if not CompareMem(Addr(FItems[I]), Addr(List.FItems[I]), SizeOf(T)) then begin
412 Result := False;
413 Break;
414 end;
415 I := I + 1;
416 end;
417 end; *)
418end;
419
420procedure TGMatrix<T>.Reverse;
421var
422 X: Integer;
423 Y: Integer;
424begin
425 Y := 0;
426 while Y < (Count.Y - 1) do begin
427 X := 1 + Y;
428 while X < Count.X do begin
429 Exchange(CreateIndex(X, Y), CreateIndex(Y, X));
430 X := X + 1;
431 end;
432 Y := Y + 1;
433 end;
434end;
435
436procedure TGMatrix<T>.ReverseHorizontal;
437var
438 X: Integer;
439 Y: Integer;
440begin
441 Y := 0;
442 while Y < Count.Y do begin
443 X := 0;
444 while X < (Count.X div 2) do begin
445 Exchange(CreateIndex(X, Y), CreateIndex(Count.X - 1 - X, Y));
446 X := X + 1;
447 end;
448 Y := Y + 1;
449 end;
450end;
451
452procedure TGMatrix<T>.ReverseVertical;
453var
454 X: Integer;
455 Y: Integer;
456begin
457 X := 0;
458 while X < Count.X do begin
459 Y := 0;
460 while Y < (Count.Y div 2) do begin
461 Exchange(CreateIndex(X, Y), CreateIndex(X, Count.Y - 1 - Y));
462 Y := Y + 1;
463 end;
464 X := X + 1;
465 end;
466end;
467
468procedure TGMatrix<T>.Sort(Compare: TSortCompare);
469begin
470(* if FCount > 1 then
471 QuickSort(0, FCount - 1, Compare); *)
472end;
473
474procedure TGMatrix<T>.AddMatrix(Values: array of TRow);
475var
476 I: TIndex;
477begin
478(* I := 0;
479 while I <= High(Values) do begin
480 Add(Values[I]);
481 I := I + 1;
482 end; *)
483end;
484
485procedure TGMatrix<T>.SetArray(Values: array of T);
486var
487 I: TIndex;
488begin
489(* Clear;
490 I := 0;
491 while I <= High(Values) do begin
492 Add(Values[I]);
493 I := I + 1;
494 end; *)
495end;
496
497procedure TGMatrix<T>.InsertArray(Index: TIndex; Values: array of T);
498var
499 I: TIndex;
500begin
501(* I := 0;
502 while I <= High(Values) do begin
503 Insert(Index + I, Values[I]);
504 I := I + 1;
505 end; *)
506end;
507
508function TGMatrix<T>.Implode(RowSeparator, ColSeparator: string; Converter: TToStringConverter): string;
509var
510 Y: Integer;
511 X: Integer;
512begin
513 Result := '';
514 Y := 0;
515 while Y < Count.Y do begin
516 X := 0;
517 while X < Count.X do begin
518 Result := Result + Converter(ItemsXY[X, Y]);
519 if X < (Count.X - 1) then
520 Result := Result + ColSeparator;
521 X := X + 1;
522 end;
523 if Y < (Count.Y - 1) then
524 Result := Result + RowSeparator;
525 Y := Y + 1;
526 end;
527end;
528
529procedure TGMatrix<T>.Explode(Text, Separator: string; Converter: TFromStringConverter; SlicesCount: Integer = -1);
530begin
531(* Clear;
532 while (Pos(Separator, Text) > 0) and
533 ((Count < (SlicesCount - 1)) or (SlicesCount = -1)) do begin
534 Add(Converter(Copy(Text, 1, Pos(Separator, Text) - 1)));
535 System.Delete(Text, 1, Pos(Separator, Text) + Length(Separator) - 1);
536 end;
537 Add(Converter(Text)); *)
538end;
539
540function TGMatrix<T>.Add(Item: T): TIndex;
541begin
542(* if FCount = Capacity then
543 Self.Expand;
544 FItems[FCount] := Item;
545 Result := FCount;
546 FCount := FCount + 1; *)
547end;
548
549procedure TGMatrix<T>.AddList(List: TGMatrix<T>);
550var
551 I: TIndex;
552begin
553(* I := 0;
554 while I < List.Count do begin
555 Add(List[I]);
556 I := I + 1;
557 end; *)
558end;
559
560procedure TGMatrix<T>.Clear;
561begin
562 Count := CreateIndex(0, 0);
563 Capacity := CreateIndex(0, 0);
564end;
565
566procedure TGMatrix<T>.Delete(Index: TIndex);
567begin
568(* if (Index < 0) or (Index >= FCount) then
569 raise EListError.CreateFmt(SListIndexError, [Index]);
570 FCount := FCount - 1;
571 System.Move(FItems[Index + 1], FItems[Index], (FCount - Index) * SizeOf(T));
572 Contract;
573 *)
574end;
575
576procedure TGMatrix<T>.DeleteItems(Index, Count: TIndex);
577var
578 I: TIndex;
579begin
580(* I := Index;
581 while I < (Index + Count) do begin
582 Delete(Index);
583 I := I + 1;
584 end;
585 *)
586end;
587
588procedure TGMatrix<T>.Fill(Start, Count: TIndex; Value: T);
589var
590 X: Integer;
591 Y: Integer;
592begin
593 Y := Start.Y;
594 while Y < Count.Y do begin
595 X := Start.X;
596 while X < Count.X do begin
597 ItemsXY[X, Y] := Value;
598 X := X + 1;
599 end;
600 Y := Y + 1;
601 end;
602end;
603
604procedure TGMatrix<T>.FillAll(Value: T);
605begin
606 Fill(CreateIndex(0, 0), CreateIndex(Count.X - 1, Count.Y - 1), Value);
607end;
608
609procedure TGMatrix<T>.Exchange(Index1, Index2: TIndex);
610var
611 Temp: T;
612begin
613 if (Index1.X < 0) or (Index1.X >= Count.X) or
614 (Index1.Y < 0) or (Index1.Y >= Count.Y) then
615 RaiseIndexError(Index1.X, Index1.Y);
616 if (Index2.X < 0) or (Index2.X >= Count.X) or
617 (Index2.Y < 0) or (Index2.Y >= Count.Y) then
618 RaiseIndexError(Index2.X, Index2.Y);
619 Temp := FItems[Index1.Y, Index1.X];
620 FItems[Index1.Y, Index1.X] := FItems[Index2.Y, Index2.X];
621 FItems[Index2.Y, Index2.X] := Temp;
622end;
623
624end.
Note: See TracBrowser for help on using the repository browser.