Provides list classes implemented using generics.

lazlistclasses.pas contains list classes implemented using generics. The lists are provided as "object" and "class" versions. Each list can be specialized to hold either items of a given type (specialized to type at compile-time) or untyped data with the size specified as a run-time argument to the constructor.

The current implementations for these list classes are not suitable for managed types, such as String.

TLazShiftBufferList

This list is designed for shift/unshift/pop/push operations. The first list element is not forced to the start of the allocated memory. Instead it allows a gap (some of the over-allocated memory / List.Capacity) in front of the first element. Therefore elements can be added/removed at either the begin or end of the list, without any need to move the other elements in the list.

TLazRoundBufferList

The first element of the list can be anywhere within the allocated memory (capacity). If the elements of the list reach the end of the memory, the list will wrap around and continues in the available memory at the start of the allocation. This list can be used for a first-in, first-out queue. If the list does never exceed the size set by its capacity, then elements can be pushed/shifted from/to the list without any need to reallocate or move entries to new locations.

TLazPagedListMem

This list organize its data into pages of fixed size. If the list grows or shrinks it can allocate extra pages or free existing pages. It does not need to reallocate its entire memory. This means that growing needs less extra memory than conventional lists. The page size is specified in the call to the constructor. The size has to be a power of 2. The constructor takes the exponent as argument. (e.g. an argument of "10" will give a size of 1024). The list also acts like a TLazShiftBufferList.

Variants of the above lists

Noted about the "object" variants:

"object"s are stored on the stack, as such the memory of the object itself is freed when the variable goes out of scope. The objects do however allocate additional memory on the heap.

  • So it is necessary to call Destroy.
  • It is also necessary to call Create. (Unless you can guarantee that the memory for the object has been zero filled).

The samples below show the available variants of the above list. The constructor for each sample is included.

Helpers for specializing the variants

Either of the following can be specified to generics that take a "TSizeT"

type generic TLazListClassesItemSize<T> = object

Used for specializing lists with a fixed item size. The size will be: sizeof(T).

type TLazListClassesVarItemSize = object

Used for specializing list with a configurable item size. The size must be set in the constructor and can not be changed after this. When using this, you need to add a constructor setting:

fItemSize.ItemSize := ASize; // "ASize" is your size

Variants for TLazShiftBufferList

generic TLazShiftBufferListObjBase<TPItemT, TSizeT> = object procedure Create;

This is the base for all other variants. Usually you do not use this directly, but use one of the other variants below.

  • TSizeT: See above.
  • TPItemT: The type of the item. Can be "Pointer" or any type. Must match TSizeT.
TLazShiftBufferListObj = object procedure Create(AnItemSize: Integer);
  • The list as an "object".
  • Use the "ItemPointer" method to get a pointer to the item-data. The pointer is only valid while there are no insert/delete/capacity operations.
generic TLazShiftBufferListObjGen<T> = object procedure Create;
  • The list as a generic for a typed "object".
  • This list an "Items" method to access the list entries.
TLazShiftBufferList = class procedure Create(AnItemSize: Integer);

The pointer-list as an "class".

generic TLazShiftBufferListGen<T> = class procedure Create;

The typed-list as an "class".

Variants for TLazRoundBufferList

generic TLazRoundBufferListObjBase<TPItemT, TSizeT> = object procedure Create; ... TLazRoundBufferListObj = object procedure Create(AnItemSize: Integer); ... generic TLazRoundBufferListObjGen<T> = object procedure Create; ...

Variants for TLazPagedListObj

generic TLazPagedListObjBase<TPItemT, TSizeT> = object procedure Create(APageSizeExp: Integer); // pagesize := 2 ^^ APageSizeExp ... TLazPagedListObj = object procedure Create(APageSizeExp: Integer; AnItemSize: Integer); ...

Notes

MoveRows(From, To, Cnt)
  • Can handle overlaps in the "From" and "To" ranges.
  • The data in the "From" block will be undefined afterwards (except for any overlaps with "To").

This file is part of the LazUtils package.

Initial revision: May 2015 Helper to specialize lists for a give type. Helper to specialize lists at run-time to a specified size. AList := TList.Create(ASize); Helper object used internally. The address for the first byte of data. This is a dummy field.

Lists can use either FirstItemPointer or FirstItemIndex. Only RoundBuffer uses FirstItemIndex.

Lists can use either FirstItemPointer or FirstItemIndex. Only RoundBuffer uses FirstItemIndex.

May be 0 (zero). Can be re-introduced to change GrowProc. Can be re-introduced to change ShrinkProc. Can be re-introduced to change GrowProc. Can be re-introduced to change ShrinkProc. May be 0 (zero). Can be re-introduced to change GrowProc. Can be re-introduced to change ShrinkProc.

The first element of the list can be anywhere within the allocated memory (capacity). If the elements of the list reach the end of the memory, the list will wrap around and continues in the available memory at the start of the allocation.

This list can be used for a first-in, first-out queue. If the list does never exceed the size set by its capacity, then elements can be pushed/shifted from/to the list without any need to reallocate or move entries to new locations.

Can be re-introduced to change GrowProc. Can be re-introduced to change ShrinkProc. Bitmask for Capacity. Bitmask for Capacity. For bubbling. Shifts the buffer.

This list is designed for shift/unshift/pop/push operations.

The first list element is not forced to the start of the allocated memory. Instead it allows a gap (some of the over-allocated memory / List.Capacity) in front of the first element.

Therefore elements can be added/removed at either the begin or end of the list, without any need to move the other elements in the list.