Aby zadeklarowanie funkcji było możliwe dla tablicy itemów typu TRec
, powinieneś mieć zadeklarowany typ takie macierzy i użyć go w nagłówku funkcji:
type
TRec = record
X: Integer;
Y: Integer;
S: String;
end;
type
TRecArr = array of TRec;
Potem możesz sobie zadeklarować funkcję:
function RecArrAppend(var AArr: TRecArr; const ARec: TRec): Integer; inline;
var
Size: Integer;
begin
Size := Length(AArr);
SetLength(AArr, Size + 1);
AArr[Size] := ARec;
Result := Size;
end;
Ewentualnie możesz też skorzystać z macierzy otwartych, bez deklaracji typu macierzowego:
function RecArrAppend(var AArr: array of TRec; const ARec: TRec): Integer; inline;
Jeśli potrzebujesz czegoś takiego dla dowolnych macierzy i itemów, spróbuj wykorzystać generyki. Mimo wszystko coś takiego nie jest dobrym rozwiązaniem, bo każdorazowe dodanie itemka do tablicy bardzo często spowoduje relokację bloku pamięci, a więc wydajność będzie niska.
To jest jeden z przykładów, dla których nie używam macierzy o dynamicznym rozmiarze, a także wudowanych generyków, bo tylko komplikują składnię, a w rzeczywistości i tak mają ograniczenia co do typów danych.
Obecnie pracuję nad projektem gry, pisanym czysto proceduralnie, w którym dane trzymane są w prostych strukturach. Zamiast macierzy używam instancji własnoręcznie zaimplementowanej listy (oraz kolejki i stosu). Daje mi to znacznie więcej możliwości, w porównaniu do macierzy dynamicznych:
- mogę przechowywać w listach dane dowolnych typów (dane proste i całe struktury), a więc pełna generyczność,
- ograniczam ilość operacji na pamięci, bo:
- listę tworzę z jednoczesną alokacją pamięci dla kilku itemów,
- pamięć zawsze alokuję z zapasem dla kolejnych itemów (wykładniczo), dzięki czemu dodanie itema rzadko kiedy wymaga relokacji bloku listy,
- usuwanie itemów nie powoduje relokacji całego bloku danych itemów,
- dodatkowo są funkcje do szybkiego wstawiania i usuwania itemów, nie wymagające w ogóle relokacji pamięci ani przesuwania całych (dużych) bloków pamięci itemów (wzamian zmienia się kolejność itemów w liście),
- jeśli potrzebuję iterować po całej liście, odkrywam wskaźniki na pierwszy i ostatni element w buforze listy i na ich podstawie poruszam się po liscie, co jest szybsze niż iterowanie po tablicach za pomocą indeksów.
- jeśli potrzebuję odczytać jakieś dane konkretnego itema, zwracam jego wskaźnik, zamiast kopiować paczkę jego danych.
- wydajność jest bardzo wysoka, ze względu na rzadkość alokacji/relokacji pamięci listy.
- w dowolnym momencie mogę zmienić zachowanie listy, tak aby wyciągnąć jak najwyższą wydajność lub rozszerzyć jej funkcjonalność.
To jest nieco inne podejście, daje naprawdę sporo korzyści i zapewnia wysoką wydajność, jednak kosztem nastukania ~200 linijek kodu i wyższej trudności obsługi takiego kontenerka. Troszkę ograniczeń też jest, ale to i tak nic w porównaniu do ilości zalet.