logo.png
mORMot2 API Reference

mormot.core.data.pas unit

Purpose: Framework Core Low-Level Data Processing Functions
- this unit is a part of the Open Source Synopse mORMot framework 2, licensed under a MPL/GPL/LGPL three license - see LICENSE.md

1.1. Units used in the mormot.core.data unit

Unit NameDescription
mormot.core.baseFramework Core Shared Types and RTL-like Functions
mormot.core.buffersFramework Core Low-Level Memory Buffer Process
mormot.core.datetimeFramework Core Low-Level Date and Time Support
mormot.core.osFramework Core Low-Level Wrappers to the Operating-System API
mormot.core.rttiFramework Core Low-Level Cross-Compiler RTTI Definitions
mormot.core.textFramework Core Low-Level Text Processing
mormot.core.unicodeFramework Core Low-Level Unicode UTF-8 UTF-16 Ansi Conversion

1.2. mormot.core.data class hierarchy

TPersistentTPersistentWithCustomCreateTSynPersistentRWLockTSynPersistentStoreTRawUtf8ListTRawUtf8ListLockedTRawUtf8ListHashedTRawUtf8ListHashedLockedTSynPersistentTSynPersistentRWLightLockTSynPersistentLockTRawUtf8InterningAbstractTSynPersistentLockedTRawUtf8InterningTObjectWithCustomCreateTSynObjectListLockedTSynObjectListSortedTSynObjectListTSynObjectListLightLockedTSynListTObjectTSynInterfacedObjectTRawUtf8InterningSlotTRawUtf8HashedTRadixTreeNodeTRadixTreeTDynArrayHasherTDynArrayTRadixTreeNodeParamsTRadixTreeParamsTDynArrayHashedTInterfacedObjectWithCustomCreateTInterfacedObjectRWLockedTInterfacedObjectLockedTAutoLockerTInterfacedObjectTAutoFreeTCollectionTInterfacedCollectionIInterfaceIAutoLockerIAutoFreeESynExceptionERadixTreeEDynArray
mormot.core.data class hierarchy

1.3. Objects implemented in the mormot.core.data unit

ObjectsDescription
EDynArrayThe kind of exceptions raised during TDynArray/TDynArrayHashed process
IAutoFreeInterface for TAutoFree to register another TObject instance to an existing IAutoFree local variable
IAutoLockerAn interface used by TAutoLocker to protect multi-thread execution
TAutoFreeSimple reference-counted storage for local objects
TAutoLockerReference-counted block code critical section
TDynArrayA wrapper around a dynamic array with one dimension
TDynArrayHashedUsed to access any dynamic arrray items using fast hash
TDynArrayHasherImplements O(1) lookup to any dynamic array content
TDynArrayLockedJust a wrapper record to join a TDynArray, its Count and a TRWLightLock
TInterfacedCollectionAny TCollection used between client and server shall inherit from this class
TInterfacedObjectLockedAdding locking methods to a TInterfacedObject with virtual constructor
TInterfacedObjectRWLockedAdding light locking methods to a TInterfacedObject with virtual constructor
TInterfacedObjectWithCustomCreateAbstract parent class with threadsafe implementation of IInterface and a virtual constructor
TPersistentWithCustomCreateAbstract parent class with a virtual constructor, ready to be overridden to initialize the instance
TRadixTreeImplement an abstract Radix Tree over UTF-8 case-insensitive text
TRadixTreeNodeImplement an abstract Radix Tree node
TRadixTreeNodeParamsImplement an abstract Radix Tree static or <param> node
TRadixTreeParamsImplement an abstract Radix Tree with static or <param> nodes
TRawUtf8HashedStore a TRawUtf8DynArray with its efficient hash table
TRawUtf8InterningAllow to store only one copy of distinct RawUtf8 values
TRawUtf8InterningAbstractDefined here as forward definition of the TRawUtf8Interning final class
TRawUtf8InterningSlotUsed to store one list of hashed RawUtf8 in TRawUtf8Interning pool
TRawUtf8ListThread-safe TStringList-class optimized for our native UTF-8 string type
TRawUtf8ListLockedSome declarations used for backward compatibility only
TSynInterfacedObjectAn abstract ancestor, for implementing a custom TInterfacedObject like class
TSynListSimple and efficient TList, without any notification
TSynObjectListSimple and efficient TObjectList, without any notification
TSynObjectListLightLockedAdd TRWLightLock non-upgradable methods to a TSynObjectList
TSynObjectListLockedAdd TRWLock upgradable methods to a TSynObjectList
TSynObjectListSortedAn ordered thread-safe TSynObjectList
TSynPersistentOur own empowered TPersistent-like parent class
TSynPersistentLockAdding locking methods to a TSynPersistent with virtual constructor
TSynPersistentLockedUsed for backward compatibility only with existing code
TSynPersistentRWLightLockAdding light non-upgradable multiple Read / exclusive Write locking methods to a TSynPersistent with virtual constructor
TSynPersistentRWLockAdding light upgradable multiple Read / exclusive Write locking methods to a TSynPersistent with virtual constructor
TSynPersistentStoreAbstract high-level handling of (SynLZ-)compressed persisted storage

1.3.1. TPersistentWithCustomCreate

TPersistentWithCustomCreate = class(TPersistent)

Abstract parent class with a virtual constructor, ready to be overridden to initialize the instance
- you can specify such a class if you need an object including published properties (like TPersistent) with a virtual constructor (e.g. to initialize some nested class properties)


constructor Create; virtual;

This virtual constructor will be called at instance creation
- this constructor does nothing, but is declared as virtual so that inherited classes may safely override this default void implementation


1.3.2. TInterfacedObjectWithCustomCreate

TInterfacedObjectWithCustomCreate = class(TInterfacedObject)

Abstract parent class with threadsafe implementation of IInterface and a virtual constructor
- you can specify e.g. such a class to TRestServer.ServiceRegister() if you need an interfaced object with a virtual constructor, ready to be overridden to initialize the instance


constructor Create; virtual;

This virtual constructor will be called at instance creation
- this constructor does nothing, but is declared as virtual so that inherited classes may safely override this default void implementation


procedure RefCountUpdate(Release: boolean); virtual;

Used to mimic TInterfacedObject reference counting
- Release=true will call TInterfacedObject._Release
- Release=false will call TInterfacedObject._AddRef
- could be used to emulate proper reference counting of the instance via interfaces variables, but still storing plain class instances (e.g. in a global list of instances) - warning: use with extreme caution!


1.3.3. TSynInterfacedObject

TSynInterfacedObject = class(TObject)

An abstract ancestor, for implementing a custom TInterfacedObject like class
- by default, will do nothing: no instance would be retrieved by QueryInterface unless the VirtualQueryInterface protected method is overriden, and _AddRef/_Release methods would call VirtualAddRef and VirtualRelease pure abstract methods
- using this class will leverage the signature difference between Delphi and FPC, among all supported platforms
- the class includes a RefCount integer field


constructor Create; virtual;

This virtual constructor will be called at instance creation
- this constructor does nothing, but is declared as virtual so that inherited classes may safely override this default void implementation


property RefCount: integer read fRefCount write fRefCount;

The associated reference count


1.3.4. TInterfacedCollection

TInterfacedCollection = class(TCollection)

Any TCollection used between client and server shall inherit from this class
- you should override the GetClass virtual method to provide the expected collection item class to be used on server side
- another possibility is to register a TCollection/TCollectionItem pair via a call to Rtti.RegisterCollection()


constructor Create; reintroduce; virtual;

This constructor will call GetClass to initialize the collection


class function GetClass: TCollectionItemClass; virtual; abstract;

You shall override this abstract method


1.3.5. IAutoFree

IAutoFree = interface(IInterface)

Interface for TAutoFree to register another TObject instance to an existing IAutoFree local variable
- WARNING: both FPC and Delphi 10.4+ don't keep the IAutoFree instance up to the end-of-method -> you should not use TAutoFree for new projects :(


procedure ForMethod;

Do-nothing method to circumvent the Delphi 10.4 IAutoFree early release


1.3.6. TAutoFree

TAutoFree = class(TInterfacedObject)

Simple reference-counted storage for local objects
- WARNING: both FPC and Delphi 10.4+ don't keep the IAutoFree instance up to the end-of-method -> you should not use TAutoFree for new projects :(
- be aware that it won't implement a full ARC memory model, but may be just used to avoid writing some try ... finally blocks on local variables
- use with caution, only on well defined local scope


constructor Create(const varObjPairs: array of pointer); reintroduce; overload;

Initialize the TAutoFree class for several local variables
- do not call this constructor, but class function Several() instead


constructor Create(var localVariable; obj: TObject); reintroduce; overload;

Initialize the TAutoFree class for one local variable
- do not call this constructor, but class function One() instead


destructor Destroy; override;

Will finalize the associated TObject instances
- note that releasing the TObject instances won't be protected, so any exception here may induce a memory leak: use only with "safe" simple objects, e.g. mORMot's TOrm


class function One(var localVariable; obj: TObject): IAutoFree;

Protect one local TObject variable instance life time
- for instance, instead of writing:

var
  myVar: TMyClass;
begin
  myVar := TMyClass.Create;
  try
    ... use myVar
  finally
    myVar.Free;
  end;
end;

- you may write:

var
  myVar: TMyClass;
begin
  TAutoFree.One(myVar,TMyClass.Create);
  ... use myVar
end; // here myVar will be released

- warning: under FPC, you should assign the result of this method to a local IAutoFree variable - see bug http://bugs.freepascal.org/view.php?id=26602
- Delphi 10.4 also did change it and release the IAutoFree before the end of the current method, so we inlined a void method call trying to circumvent this problem - https://quality.embarcadero.com/browse/RSP-30050
- for both Delphi 10.4+ and FPC, you may use with TAutoFree.One() do


class function Several(const varObjPairs: array of pointer): IAutoFree;

Protect several local TObject variable instances life time
- specified as localVariable/objectInstance pairs
- you may write:

var
  var1, var2: TMyClass;
begin
  TAutoFree.Several([
    @var1,TMyClass.Create,
    @var2,TMyClass.Create]);
  ... use var1 and var2
end; // here var1 and var2 will be released

- warning: under FPC, you should assign the result of this method to a local IAutoFree variable - see bug http://bugs.freepascal.org/view.php?id=26602
- Delphi 10.4 also did change it and release the IAutoFree before the end of the current method, and an "array of pointer" cannot be inlined by the Delphi compiler, so you should explicitly call ForMethod:

  TAutoFree.Several([
    @var1,TMyClass.Create,
    @var2,TMyClass.Create]).ForMethod;

procedure Another(var localVariable; obj: TObject);

Protect another TObject variable to an existing IAutoFree instance life time
- you may write:

var
  var1, var2: TMyClass;
  auto: IAutoFree;
begin
  auto := TAutoFree.One(var1,TMyClass.Create);,
  .... do something
  auto.Another(var2,TMyClass.Create);
  ... use var1 and var2
end; // here var1 and var2 will be released

1.3.7. IAutoLocker

IAutoLocker = interface(IInterface)

An interface used by TAutoLocker to protect multi-thread execution


function ProtectMethod: IUnknown;

Will enter the mutex until the IUnknown reference is released
- using an IUnknown interface to let the compiler auto-generate a try..finally block statement to release the lock for the code block
- could be used as such under Delphi:

begin
  ... // unsafe code
  fSharedAutoLocker.ProtectMethod;
  ... // thread-safe code
end; // local hidden IUnknown will release the lock for the method

- warning: under FPC, you should assign its result to a local variable - see bug http://bugs.freepascal.org/view.php?id=26602

var
  LockFPC: IUnknown;
begin
  ... // unsafe code
  LockFPC := fSharedAutoLocker.ProtectMethod;
  ... // thread-safe code
end; // LockFPC will release the lock for the method

or

begin
  ... // unsafe code
  with fSharedAutoLocker.ProtectMethod do
  begin
    ... // thread-safe code
  end; // local hidden IUnknown will release the lock for the method
end;

function Safe: PSynLocker;

Gives an access to the internal low-level TSynLocker instance used


procedure Enter;

Enter the mutex
- any call to Enter should be ended with a call to Leave, and protected by a try..finally block, as such:

begin
  ... // unsafe code
  fSharedAutoLocker.Enter;
  try
    ... // thread-safe code
  finally
    fSharedAutoLocker.Leave;
  end;
end;

procedure Leave;

Leave the mutex
- any call to Leave should be preceded with a call to Enter


1.3.8. TAutoLocker

TAutoLocker = class(TInterfacedObjectWithCustomCreate)

Reference-counted block code critical section
- you can use one instance of this to protect multi-threaded execution
- the main class may initialize a IAutoLocker property in Create, then call IAutoLocker.ProtectMethod in any method to make its execution thread safe
- this class inherits from TInterfacedObjectWithCustomCreate so you could define one published property of a mormot.core.interface.pas TInjectableObject as IAutoLocker so that this class may be automatically injected
- consider inherit from high-level TSynPersistentLock or call low-level fSafe := NewSynLocker / fSafe^.DoneAndFreemem instead


constructor Create; override;

Initialize the mutex


destructor Destroy; override;

Finalize the mutex


function ProtectMethod: IUnknown;

Will enter the mutex until the IUnknown reference is released
- as expected by IAutoLocker interface
- could be used as such under Delphi:

begin
  ... // unsafe code
  fSharedAutoLocker.ProtectMethod;
  ... // thread-safe code
end; // local hidden IUnknown will release the lock for the method

- warning: under FPC, you should assign its result to a local variable - see bug http://bugs.freepascal.org/view.php?id=26602

var
  LockFPC: IUnknown;
begin
  ... // unsafe code
  LockFPC := fSharedAutoLocker.ProtectMethod;
  ... // thread-safe code
end; // LockFPC will release the lock for the method

or

begin
  ... // unsafe code
  with fSharedAutoLocker.ProtectMethod do
  begin
    ... // thread-safe code
  end; // local hidden IUnknown will release the lock for the method
end;

function Safe: PSynLocker;

Access to the locking methods of this instance
- as expected by IAutoLocker interface


procedure Enter; virtual;

Enter the mutex
- as expected by IAutoLocker interface
- any call to Enter should be ended with a call to Leave, and protected by a try..finally block, as such:

begin
  ... // unsafe code
  fSharedAutoLocker.Enter;
  try
    ... // thread-safe code
  finally
    fSharedAutoLocker.Leave;
  end;
end;

procedure Leave; virtual;

Leave the mutex
- as expected by IAutoLocker interface


property Locker: TSynLocker read fSafe;

Direct access to the locking methods of this instance
- faster than IAutoLocker.Safe function


1.3.9. TSynPersistent

TSynPersistent = class(TObjectWithCustomCreate)

Our own empowered TPersistent-like parent class
- TPersistent has an unexpected speed overhead due a giant lock introduced to manage property name fixup resolution (which we won't use outside the UI)
- this class has a virtual constructor, so is a preferred alternative to both TPersistent and TPersistentWithCustomCreate classes
- features some protected methods to customize its JSON serialization
- for best performance, any type inheriting from this class will bypass some regular steps: do not implement interfaces or use TMonitor with them!


procedure Assign(Source: TSynPersistent); virtual;

Allows to implement a TPersistent-like assignement mechanism
- inherited class should override AssignTo() protected method to implement the proper assignment


1.3.10. TSynList

TSynList = class(TObject)

Simple and efficient TList, without any notification
- regular TList has an internal notification mechanism which slows down basic process, and can't be easily inherited
- stateless methods (like Add/Clear/Exists/Remove) are defined as virtual since can be overriden e.g. by TSynObjectListLocked to add a TSynLocker


constructor Create; virtual;

Virtual constructor called at instance creation


function Add(item: pointer): PtrInt; virtual;

Add one item to the list


function Exists(item: pointer): boolean; virtual;

Fast check if one item exists in the list


function IndexOf(item: pointer): PtrInt; virtual;

Fast retrieve one item in the list


function Insert(item: pointer; index: PtrInt): PtrInt;

Insert one item to the list at a given position


function Remove(item: pointer): PtrInt; virtual;

Fast delete one item in the list


procedure Clear; virtual;

Delete all items of the list


procedure Delete(index: integer; dontfree: boolean = false); virtual;

Delete one item from the list


property Count: integer read fCount;

How many items are stored in this TList instance


property Items[index: integer]: pointer read Get;

Low-level array-like access to the items stored in this TList instance
- warning: if index is out of range, will return nil and won't raise any exception


property List: TPointerDynArray read fList;

Low-level access to the items stored in this TList instance


1.3.11. TSynObjectList

TSynObjectList = class(TSynList)

Simple and efficient TObjectList, without any notification


constructor Create(aOwnObjects: boolean = true; aItemClass: TClass = nil); reintroduce; virtual;

Initialize the object list
- can optionally specify an item class for efficient JSON serialization


destructor Destroy; override;

Finalize the store items


function NewItem: pointer;

Create a new ItemClass instance, Add() it and return it


procedure Clear; override;

Delete all objects of the list


procedure ClearFromLast; virtual;

Delete all objects of the list in reverse order
- for some kind of processes, owned objects should be removed from the last added to the first
- will use slower but safer FreeAndNilSafe() instead of plain Free


procedure Delete(index: integer; dontfree: boolean = false); override;

Delete one object from the list
- will also Free the item if OwnObjects was set, and dontfree is false


property ItemClass: TClass read fItemClass write fItemClass;

Optional class of the stored items
- used e.g. by _JL_TSynObjectList() when unserializing from JSON


property OwnObjects: boolean read fOwnObjects write fOwnObjects;

Flag set if this list will Free its items on Delete/Clear/Destroy


1.3.12. TSynPersistentLock

TSynPersistentLock = class(TSynPersistent)

Adding locking methods to a TSynPersistent with virtual constructor
- you may use this class instead of the RTL TCriticalSection, since it would use a TSynLocker which does not suffer from CPU cache line conflit, and is cross-compiler whereas TMonitor is Delphi-specific and buggy (at least before XE5)
- if you don't need TSynPersistent overhead, consider plain TSynLocked class


constructor Create; override;

Initialize the instance, and its associated lock


destructor Destroy; override;

Finalize the instance, and its associated lock


procedure Lock;

Could be used as a short-cut to Safe.Lock


procedure Unlock;

Could be used as a short-cut to Safe.UnLock


property Safe: PSynLocker read fSafe;

Access to the associated instance critical section
- call Safe.Lock/UnLock to protect multi-thread access on this storage


1.3.13. TSynPersistentRWLightLock

TSynPersistentRWLightLock = class(TSynPersistent)

Adding light non-upgradable multiple Read / exclusive Write locking methods to a TSynPersistent with virtual constructor


property Safe: TRWLightLock read fSafe;

Access to the associated non-upgradable TRWLightLock instance
- call Safe methods to protect multi-thread access on this storage


1.3.14. TSynPersistentRWLock

TSynPersistentRWLock = class(TSynPersistent)

Adding light upgradable multiple Read / exclusive Write locking methods to a TSynPersistent with virtual constructor


property Safe: TRWLock read fSafe;

Access to the associated upgradable TRWLock instance
- call Safe methods to protect multi-thread access on this storage


1.3.15. TSynPersistentLocked

TSynPersistentLocked = class(TSynPersistentLock)

Used for backward compatibility only with existing code


1.3.16. TInterfacedObjectLocked

TInterfacedObjectLocked = class(TInterfacedObjectWithCustomCreate)

Adding locking methods to a TInterfacedObject with virtual constructor


constructor Create; override;

TSynLocker would increase inherited fields offset initialize the object instance, and its associated lock


destructor Destroy; override;

Release the instance (including the locking resource)


property Safe: PSynLocker read fSafe;

Access to the locking methods of this instance
- use Safe.Lock/TryLock with a try ... finally Safe.Unlock block


1.3.17. TInterfacedObjectRWLocked

TInterfacedObjectRWLocked = class(TInterfacedObjectWithCustomCreate)

Adding light locking methods to a TInterfacedObject with virtual constructor


property Safe: TRWLock read fSafe;

Access to the multiple Read / exclusive Write locking methods of this instance


1.3.18. TSynObjectListLightLocked

TSynObjectListLightLocked = class(TSynObjectList)

Add TRWLightLock non-upgradable methods to a TSynObjectList
- this class expands the regular TSynObjectList to include a TRWLightLock
- you need to call the Safe locking methods by hand to protect the execution of all methods, since even Add/Clear/ClearFromLast/Remove/Exists have not been overriden because TRWLighLock.WriteLock is not reentrant


property Safe: TRWLightLock read fSafe;

The light single Read / exclusive Write LightLock associated to this list
- could be used to protect shared resources within the internal process, for index-oriented methods like Delete/Items/Count...
- use Safe LightLock methods with a try ... finally bLightLock


1.3.19. TSynObjectListLocked

TSynObjectListLocked = class(TSynObjectList)

Add TRWLock upgradable methods to a TSynObjectList
- this class expands the regular TSynObjectList to include a TRWLock
- you need to call the Safe locking methods by hand to protect the execution of index-oriented methods (like Delete/Items/Count...): the list content may change in the background, so using indexes is thread-safe
- on the other hand, Add/Clear/ClearFromLast/Remove stateless methods have been overriden in this class to call Safe lock methods, and therefore are thread-safe and protected to any background change


function Add(item: pointer): PtrInt; override;

Add one item to the list using Safe.WriteLock


function Exists(item: pointer): boolean; override;

Check an item using Safe.ReadOnlyLock


function Remove(item: pointer): PtrInt; override;

Fast delete one item in the list, using Safe.WriteLock


procedure Clear; override;

Delete all items of the list using Safe.WriteLock


procedure ClearFromLast; override;

Delete all items of the list in reverse order, using Safe.WriteLock


property Safe: TRWLock read fSafe;

The light single Read / exclusive Write lock associated to this list
- could be used to protect shared resources within the internal process, for index-oriented methods like Delete/Items/Count...
- use Safe lock methods within a try ... finally block


1.3.20. TSynObjectListSorted

TSynObjectListSorted = class(TSynObjectListLocked)

An ordered thread-safe TSynObjectList
- items will be stored in order, for O(log(n)) fast search


constructor Create(const aCompare: TOnObjectCompare; aOwnsObjects: boolean = true); reintroduce;

Initialize the object list to be sorted with the supplied function


function Add(item: pointer): PtrInt; override;

Add in-order one item to the list using Safe.WriteLock
- returns the sorted index when item was inserted
- returns < 0 if item was found, as -(existingindex + 1)


function Find(item: TObject): TObject;

Fast retrieve one item in the list using O(log(n)) binary search
- supplied item should have enough information for fCompare to work


function IndexOf(item: pointer): PtrInt; override;

Fast retrieve one item in the list using O(log(n)) binary search
- this overriden version won't search for the item pointer itself, but will use the Compare() function until it is 0


property Compare: TOnObjectCompare read fCompare write fCompare;

How two stored objects are stored


1.3.21. TSynPersistentStore

TSynPersistentStore = class(TSynPersistentRWLock)

Abstract high-level handling of (SynLZ-)compressed persisted storage
- LoadFromReader/SaveToWriter abstract methods should be overriden with proper binary persistence implementation


constructor Create(const aName: RawUtf8); reintroduce; overload; virtual;

Initialize a void storage with the supplied name


constructor CreateFrom(const aBuffer: RawByteString; aLoad: TAlgoCompressLoad = aclNormal);

Initialize a storage from a SaveTo persisted buffer
- raise a EFastReader exception on decoding error


constructor CreateFromBuffer(aBuffer: pointer; aBufferLen: integer; aLoad: TAlgoCompressLoad = aclNormal);

Initialize a storage from a SaveTo persisted buffer
- raise a EFastReader exception on decoding error


constructor CreateFromFile(const aFileName: TFileName; aLoad: TAlgoCompressLoad = aclNormal);

Initialize a storage from a SaveTo persisted buffer
- raise a EFastReader exception on decoding error


function LoadFromFile(const aFileName: TFileName; aLoad: TAlgoCompressLoad = aclNormal): boolean;

Initialize the storage from a SaveToFile content
- actually call the LoadFromReader() virtual method for persistence
- returns false if the file is not found, true if the file was loaded without any problem, or raise a EFastReader exception on decoding error


function SaveTo(nocompression: boolean = false; BufLen: integer = 65536; ForcedAlgo: TAlgoCompress = nil; BufferOffset: integer = 0): RawByteString; overload;

Persist the content as a SynLZ-compressed binary blob
- just an overloaded wrapper


function SaveToFile(const aFileName: TFileName; nocompression: boolean = false; BufLen: integer = 65536; ForcedAlgo: TAlgoCompress = nil): PtrUInt;

Persist the content as a SynLZ-compressed binary file
- to be retrieved later on via LoadFromFile method
- returns the number of bytes of the resulting file
- actually call the SaveTo method for persistence


procedure LoadFrom(const aBuffer: RawByteString; aLoad: TAlgoCompressLoad = aclNormal); overload;

Fill the storage from a SaveTo persisted buffer
- actually call the LoadFromReader() virtual method for persistence
- raise a EFastReader exception on decoding error


procedure LoadFrom(aBuffer: pointer; aBufferLen: integer; aLoad: TAlgoCompressLoad = aclNormal); overload; virtual;

Initialize the storage from a SaveTo persisted buffer
- actually call the LoadFromReader() virtual method for persistence
- raise a EFastReader exception on decoding error


procedure SaveTo(out aBuffer: RawByteString; nocompression: boolean = false; BufLen: integer = 65536; ForcedAlgo: TAlgoCompress = nil; BufferOffset: integer = 0); overload; virtual;

Persist the content as a SynLZ-compressed binary blob
- to be retrieved later on via LoadFrom method
- actually call the SaveToWriter() protected virtual method for persistence
- you can specify ForcedAlgo if you want to override the default AlgoSynLZ
- BufferOffset could be set to reserve some bytes before the compressed buffer


property LoadFromLastUncompressed: integer read fLoadFromLastUncompressed;

After a LoadFrom(), contains the uncompressed data size read


property Name: RawUtf8 read fName;

One optional text associated with this storage
- you can define this field as published to serialize its value in log/JSON


property SaveToLastUncompressed: integer read fSaveToLastUncompressed;

After a SaveTo(), contains the uncompressed data size written


1.3.22. TRawUtf8InterningAbstract

TRawUtf8InterningAbstract = class(TSynPersistent)

Defined here as forward definition of the TRawUtf8Interning final class


1.3.23. EDynArray

EDynArray = class(ESynException)

The kind of exceptions raised during TDynArray/TDynArrayHashed process


1.3.24. TDynArray

TDynArray = object(TObject)

A wrapper around a dynamic array with one dimension
- provide TList-like methods using fast RTTI information
- can be used to fast save/retrieve all memory content to a TStream
- note that the "const Item" is not checked at compile time nor runtime: you must ensure that Item matchs the element type of the dynamic array; all Item*() methods will use pointers for safety
- can use external Count storage to make Add() and Delete() much faster (avoid most reallocation of the memory buffer)
- Note that TDynArray is just a wrapper around an existing dynamic array: methods can modify the content of the associated variable but the TDynArray doesn't contain any data by itself. It is therefore aimed to initialize a TDynArray wrapper on need, to access any existing dynamic array.
- is defined as an object or as a record, due to a bug in Delphi 2009/2010 compiler (at least): this structure is not initialized if defined as an object on the stack, but will be as a record :(


function Add(const Item): PtrInt;

Add an element to the dynamic array
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write Add(i+10) e.g.)
- returns the index of the added element in the dynamic array
- note that because of dynamic array internal memory managment, adding may reallocate the list every time a record is added, unless an external count variable has been specified in Init(...,@Count) method


function AddArray(const DynArrayVar; aStartIndex: integer = 0; aCount: integer = -1): integer;

Add items from a given dynamic array variable
- the supplied source DynArray MUST be of the same exact type as the current used for this TDynArray - warning: pass here a reference to a "array of ..." variable, not another TDynArray instance; if you want to add another TDynArray, use AddDynArray() method
- you can specify the start index and the number of items to take from the source dynamic array (leave as -1 to add till the end)
- returns the number of items added to the array


function ClearSafe: boolean;

Delete the whole dynamic array content, ignoring exceptions
- returns true if no exception occurred when calling Clear, false otherwise
- you should better not call this method, which will catch and ignore all exceptions - but it may somewhat make sense in a destructor
- this method will recognize T*ObjArray types and free all instances


function Compares(B: PDynArray; IgnoreCompare: boolean = false; CaseSensitive: boolean = true): integer;

Compare the content of the two arrays
- use any supplied Compare property (unless ignorecompare=true), or following the RTTI element description on all array items
- T*ObjArray kind of arrays will properly compare their properties


function Delete(aIndex: PtrInt): boolean;

Delete one item inside the dynamic array
- the deleted element is finalized if necessary
- this method will recognize T*ObjArray types and free all instances


function Equals(B: PDynArray; IgnoreCompare: boolean = false; CaseSensitive: boolean = true): boolean;

Compare the content of the two arrays, returning TRUE if both match
- use any supplied Compare property (unless ignorecompare=true), or following the RTTI element description on all array items
- T*ObjArray kind of arrays will properly compare their properties


function FastLocateOrAddSorted(const Item; wasAdded: PBoolean = nil): integer;

Search and add an element value inside a sorted dynamic array
- this method will use the Compare property function for the search
- will be faster than a manual FindAndAddIfNotExisting+Sort process
- returns the index of the existing Item and wasAdded^=false
- returns the sorted index of the inserted Item and wasAdded^=true
- if the array is not sorted, returns -1 and wasAdded^=false
- is just a wrapper around FastLocateSorted+FastAddSorted


function FastLocateSorted(const Item; out Index: integer): boolean;

Search for an element value inside a sorted dynamic array
- this method will use the Compare property function for the search
- will be faster than a manual FindAndAddIfNotExisting+Sort process
- returns TRUE and the index of existing Item, or FALSE and the index where the Item is to be inserted so that the array remains sorted
- you should then call FastAddSorted() later with the returned Index
- if the array is not sorted, returns FALSE and Index=-1
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (no FastLocateSorted(i+10) e.g.)
- warning: Index out parameter should be integer, not PtrInt


function Find(const Item; const aIndex: TIntegerDynArray; aCompare: TDynArraySortCompare): PtrInt; overload;

Search for an element value inside the dynamic array, from an external aIndex[] lookup table - e.g. created by CreateOrderedIndex()
- return the index found (0..Count-1), or -1 if Item was not found
- if an indexed lookup is supplied, it must already be sorted: this function will then use fast O(log(n)) binary search over aCompare
- if the indexed lookup is not correct (e.g. aIndex=nil), iterate O(n) using aCompare - it won't fallback to IndexOf() RTTI search
- warning: the lookup aIndex[] should be synchronized if array content is modified (in case of addition or deletion)


function Find(const Item; aCompare: TDynArraySortCompare = nil): PtrInt; overload;

Search for an element inside the dynamic array using the Compare function
- this method will use the Compare property function, or the supplied aCompare for the search; if none of them are set, it will fallback to IndexOf() to perform a default case-sensitive RTTI search
- return the index found (0..Count-1), or -1 if Item was not found
- if the array is sorted, it will use fast O(log(n)) binary search
- if the array is not sorted, it will use slower O(n) iterating search
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write Find(i+10) e.g.)


function FindAllSorted(const Item; out FindCount: integer): pointer; overload;

Search the item pointers which match a given value in a sorted dynamic array
- this method will use the Compare property function for the search
- return nil and FindCount = 0 if no matching item was found
- return the a pointer to the first matching item, and FindCount >=1
- warning: FindCount out parameter should be integer, not PtrInt


function FindAllSorted(const Item; out FirstIndex, LastIndex: integer): boolean; overload;

Search the items range which match a given value in a sorted dynamic array
- this method will use the Compare property function for the search
- returns TRUE and the matching indexes, or FALSE if none found
- if the array is not sorted, returns FALSE
- warning: FirstIndex/LastIndex parameters should be integer, not PtrInt


function FindAndAddIfNotExisting(const Item; aIndex: PIntegerDynArray = nil; aCompare: TDynArraySortCompare = nil): integer;

Search for an element value, then add it if none matched
- this method will use the Compare property function for the search, or the supplied indexed lookup table and its associated compare function, and fallback to case-sensitive RTTI search if none is defined
- if no Item content matches, the item will added to the array
- can be used e.g. as a simple dictionary: if Compare will match e.g. the first string field (i.e. set to SortDynArrayString), you can fill the first string field with the searched value (if returned index is >= 0)
- return the index found (0..Count-1), or -1 if Item was not found and the supplied element has been successfully added
- if the array is sorted, it will use fast O(log(n)) binary search
- if the array is not sorted, it will use slower O(n) iterating search
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write Find(i+10) e.g.)


function FindAndDelete(const Item; aIndex: PIntegerDynArray = nil; aCompare: TDynArraySortCompare = nil): integer;

Search for an element value, then delete it if match
- this method will use the Compare property function for the search, or the supplied indexed lookup table and its associated compare function, and fallback to case-sensitive RTTI search if none is defined
- if Item content matches, this item will be deleted from the array
- can be used e.g. as a simple dictionary: if Compare will match e.g. the first string field (i.e. set to SortDynArrayString), you can fill the first string field with the searched value (if returned index is >= 0)
- return the index deleted (0..Count-1), or -1 if Item was not found
- if the array is sorted, it will use fast O(log(n)) binary search
- if the array is not sorted, it will use slower O(n) iterating search
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write Find(i+10) e.g.)


function FindAndFill(var Item; aIndex: PIntegerDynArray = nil; aCompare: TDynArraySortCompare = nil): integer;

Search for an element value, then fill all properties if match
- this method will use the Compare property function for the search, or the supplied indexed lookup table and its associated compare function, and fallback to case-sensitive RTTI search if none is defined
- if Item content matches, all Item fields will be filled with the record
- can be used e.g. as a simple dictionary: if Compare will match e.g. the first string field (i.e. set to SortDynArrayString), you can fill the first string field with the searched value (if returned index is >= 0)
- return the index found (0..Count-1), or -1 if Item was not found
- if the array is sorted, it will use fast O(log(n)) binary search
- if the array is not sorted, it will use slower O(n) iterating search
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write Find(i+10) e.g.)


function FindAndUpdate(const Item; aIndex: PIntegerDynArray = nil; aCompare: TDynArraySortCompare = nil): integer;

Search for an element value, then update the item if match
- this method will use the Compare property function for the search, or the supplied indexed lookup table and its associated compare function, and fallback to case-sensitive RTTI search if none is defined
- if Item content matches, this item will be updated with the supplied value
- can be used e.g. as a simple dictionary: if Compare will match e.g. the first string field (i.e. set to SortDynArrayString), you can fill the first string field with the searched value (if returned index is >= 0)
- return the index found (0..Count-1), or -1 if Item was not found
- if the array is sorted, it will use fast O(log(n)) binary search
- if the array is not sorted, it will use slower O(n) iterating search
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write Find(i+10) e.g.)


function IndexOf(const Item; CaseInSensitive: boolean = true): PtrInt;

Search for an element inside the dynamic array using RTTI
- return the index found (0..Count-1), or -1 if Item was not found
- will search for all properties content of Item: TList.IndexOf() searches by address, this method searches by content using the RTTI element description (and not the Compare property function)
- use the Find() method if you want the search via the Compare property function, or e.g. to search only with some part of the element content
- will work with simple types: binaries (byte, word, integer, Int64, Currency, array[0..255] of byte, packed records with no reference-counted type within...), string types (e.g. array of string), and packed records with binary and string types within (like TFileVersion)
- won't work with not packed types (like a shorstring, or a record with byte or word fields with {$A+}): in this case, the padding data (i.e. the bytes between the aligned fields) can be filled as random, and there is no way with standard RTTI to identify randomness from values
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write IndexOf(i+10) e.g.)


function InitSpecific(aTypeInfo: PRttiInfo; var aValue; aKind: TRttiParserType; aCountPointer: PInteger = nil; aCaseInsensitive: boolean = false): TRttiParserType;

Initialize the wrapper with a one-dimension dynamic array
- also set the Compare() function from a supplied TRttiParserType
- aKind=ptNone will guess the type from Info.ArrayRtti/ArrayFirstField
- will raise an exception if there is not enough RTTI available
- no RTTI check is made over the corresponding array layout: you shall ensure that the aKind parameter matches at least the first field of the dynamic array item definition
- aCaseInsensitive will be used for ptStringTypes


function IsSorted(aCompare: TDynArraySortCompare = nil): boolean;

Will check all items against aCompare


function IsVoid: boolean;

Check if the wrapper points to a dynamic array
- i.e. if Void has been called before


function ItemCompare(A, B: pointer; CaseInSensitive: boolean = false): integer;

Compare the content of two items, returning -1, 0 or +1s
- use the Compare() property function (if set) or using Info.Cache.ItemInfoManaged if available - and fallbacks to binary comparison


function ItemCopyAt(index: PtrInt; Dest: pointer): boolean;

Will copy one element content from its index into another variable
- do nothing and return false if index is out of range or Dest is nil


function ItemCopyFirstField(Source, Dest: pointer): boolean;

Will copy the first field value of an array element
- will use the array KnownType to guess the copy routine to use
- returns false if the type information is not enough for a safe copy


function ItemEquals(A, B: pointer; CaseInSensitive: boolean = false): boolean;

Compare the content of two items, returning TRUE if both values equal
- use the Compare() property function (if set) or using Info.Cache.ItemInfoManaged if available - and fallbacks to binary comparison


function ItemLoadFind(Source, SourceMax: PAnsiChar): integer;

Search for an array element as saved by the ItemSave method
- same as ItemLoad() + Find()/IndexOf() + ItemLoadClear()
- will call Find() method if Compare property is set
- will call generic IndexOf() method if no Compare property is set


function ItemLoadMem(Source, SourceMax: PAnsiChar): RawByteString;

Load an array element as saved by the ItemSave method
- this overloaded method will retrieve the element as a memory buffer, which should be cleared by ItemLoadMemClear() before release


function ItemMoveTo(index: PtrInt; Dest: pointer): boolean;

Will move one element content from its index into another variable
- will erase the internal item after copy
- do nothing and return false if index is out of range or Dest is nil


function ItemPtr(index: PtrInt): pointer;

Returns a pointer to an element of the array
- returns nil if aIndex is out of range
- since TDynArray is just a wrapper around an existing array, you should better use direct access to its wrapped variable, and not this (slightly) slower and more error prone method (such pointer access lacks of strong typing abilities), which is designed for TDynArray abstract/internal use


function ItemSave(Item: pointer): RawByteString;

Save an array element into a serialized binary content
- use the same layout as TDynArray.SaveTo, but for a single item
- you can use ItemLoad method later to retrieve its content
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write ItemSave(i+10) e.g.)


function ItemSize: PtrUInt;

Just a convenient wrapper of Info.Cache.ItemSize


function LoadFrom(Source: PAnsiChar; SourceMax: PAnsiChar = nil): PAnsiChar;

Unserialize dynamic array content from binary written by TDynArray.SaveTo
- return nil if the Source buffer is incorrect: invalid type, wrong checksum, or SourceMax overflow
- return a non nil pointer just after the Source content on success
- this method will raise an ESynException for T*ObjArray types


function LoadFromBinary(const Buffer: RawByteString): boolean;

Unserialize the dynamic array content from a TDynArray.SaveTo binary string
- same as LoadFrom, and will check for any buffer overflow since we know the actual end of input buffer
- will read mORMot 1.18 binary content, but will ignore the Hash32 stored checksum which is not needed any more


function LoadFromJson(P: PUtf8Char; EndOfObject: PUtf8Char = nil; CustomVariantOptions: PDocVariantOptions = nil; Tolerant: boolean = false; Interning: TRawUtf8InterningAbstract = nil): PUtf8Char; overload;

Load the dynamic array content from an UTF-8 encoded JSON buffer
- expect the format as saved by TTextWriter.AddDynArrayJson method, i.e. handling TbooleanDynArray, TIntegerDynArray, TInt64DynArray, TCardinalDynArray, TDoubleDynArray, TCurrencyDynArray, TWordDynArray, TByteDynArray, TRawUtf8DynArray, TWinAnsiDynArray, TRawByteStringDynArray, TStringDynArray, TWideStringDynArray, TSynUnicodeDynArray, TTimeLogDynArray and TDateTimeDynArray as JSON array - or any customized Rtti.RegisterFromText/TRttiJson.RegisterCustomSerializer format
- or any other kind of array as Base64 encoded binary stream precessed via JSON_BASE64_MAGIC_C (UTF-8 encoded \uFFF0 special code)
- typical handled content could be

 '[1,2,3,4]' or '["\uFFF0base64encodedbinary"]'

- return a pointer at the end of the data read from P, nil in case of an invalid input buffer
- this method will recognize T*ObjArray types, and will first free any existing instance before unserializing, to avoid memory leak
- set e.g. @JSON_[mFast] as CustomVariantOptions parameter to handle complex JSON object or arrays as TDocVariant into variant fields
- can use an associated TRawUtf8Interning instance for RawUtf8 values
- warning: the content of P^ will be modified during parsing: make a local copy if it will be needed later (using e.g. the overloaded method)


function LoadFromJson(const Json: RawUtf8; CustomVariantOptions: PDocVariantOptions = nil; Tolerant: boolean = false; Interning: TRawUtf8InterningAbstract = nil): boolean; overload;

Load the dynamic array content from an UTF-8 encoded JSON buffer
- this method will make a private copy of the JSON for in-place parsing
- returns false in case of invalid input buffer, true on success


function New: PtrInt;

Add an element to the dynamic array, returning its index
- note: if you use this method to add a new item with a reference to the dynamic array, be aware that the following trigger a GPF on FPC:

    with Values[DynArray.New] do // otherwise Values is nil -> GPF
    begin
      Field1 := 1;
      ...

- so you should either use a local variable:

    i := DynArray.New;
    with Values[i] do // otherwise Values is nil -> GPF
    begin

- or even better, don't use the dubious "with Values[...] do" but NewPtr


function NewPtr: pointer;

Add an element to the dynamic array, returning its pointer
- a slightly faster alternative to ItemPtr(New)


function Peek(var Dest): boolean;

Get the last element stored in the dynamic array
- Add + Pop/Peek will implement a LIFO (Last-In-First-Out) stack
- warning: Dest must be of the same exact type than the dynamic array
- returns true if the item was successfully copied into Dest
- use Pop() if you also want to remove the item


function PeekHead(var Dest): boolean;

Get the first element stored in the dynamic array
- Add + PopHead/PeekHead will implement a FIFO (First-In-First-Out) stack
- warning: Dest must be of the same exact type than the dynamic array
- returns true if the item was successfully copied and removed
- use PopHead() if you also want to remove the item


function Pop(var Dest): boolean;

Get and remove the last element stored in the dynamic array
- Add + Pop/Peek will implement a LIFO (Last-In-First-Out) stack
- warning: Dest must be of the same exact type than the dynamic array
- returns true if the item was successfully copied and removed
- use Peek() if you don't want to remove the item, but just get its value


function PopHead(var Dest): boolean;

Get and remove the first element stored in the dynamic array
- Add + PopHead/PeekHead will implement a FIFO (First-In-First-Out) stack
- removing from head will move all items so TSynQueue is faster
- warning: Dest must be of the same exact type than the dynamic array
- returns true if the item was successfully copied and removed
- use PeekHead() if you don't want to remove the item, but get its value
- first slot will be deleted and all content moved, so may take some time


function SaveTo: RawByteString; overload;

Save the dynamic array content into a RawByteString
- will use a proprietary binary format, with some variable-length encoding of the string length - note that if you change the type definition, any previously-serialized content will fail, maybe triggering unexpected GPF: use SaveToTypeInfoHash if you share this binary data accross executables
- this method will raise an ESynException for T*ObjArray types
- use TDynArray.LoadFrom to decode the saved buffer
- warning: legacy Hash32 checksum will be stored as 0, so may be refused by mORMot TDynArray.LoadFrom before 1.18.5966


function SaveToJson(EnumSetsAsText: boolean = false; reformat: TTextWriterJsonFormat = jsonCompact): RawUtf8; overload;

Serialize the dynamic array content as JSON


function SetParserType(aKind: TRttiParserType; aCaseInsensitive: boolean): TRttiParserType;

Set a specific TRttiParserType for this dynamic array
- could be called after InitRtti() to set the Compare() function
- as used by InitSpecific() after InitRtti(Rtti.RegisterType(aTypeInfo))


procedure AddDynArray(aSource: PDynArray; aStartIndex: integer = 0; aCount: integer = -1);

Add items from a given TDynArray
- the supplied source TDynArray MUST be of the same exact type as the current used for this TDynArray, otherwise it won't do anything
- you can specify the start index and the number of items to take from the source dynamic array (leave as -1 to add till the end)


procedure Clear;

Delete the whole dynamic array content
- this method will recognize T*ObjArray types and free all instances


procedure Copy(Source: PDynArray; ObjArrayByRef: boolean = false);

Set all content of one dynamic array to the current array
- both must be of the same exact type
- T*ObjArray will be reallocated and copied by content (using a temporary JSON serialization), unless ObjArrayByRef is true and pointers are copied


procedure CopyFrom(const Source; MaxItem: integer; ObjArrayByRef: boolean = false);

Set all content of one dynamic array to the current array
- both must be of the same exact type
- T*ObjArray will be reallocated and copied by content (using a temporary JSON serialization), unless ObjArrayByRef is true and pointers are copied


procedure CopyTo(out Dest; ObjArrayByRef: boolean = false);

Set all content of the current dynamic array to another array variable
- both must be of the same exact type
- resulting length(Dest) will match the exact items count, even if an external Count integer variable is used by this instance
- T*ObjArray will be reallocated and copied by content (using a temporary JSON serialization), unless ObjArrayByRef is true and pointers are copied


procedure CreateOrderedIndex(var aIndex: TIntegerDynArray; aCompare: TDynArraySortCompare); overload;

Sort the dynamic array items using a lookup array of indexes
- in comparison to the Sort method, this CreateOrderedIndex won't change the dynamic array content, but only create (or update) the supplied integer lookup array, using the specified comparison function
- if aCompare is not supplied, the method will use fCompare (if defined)
- you should provide either a void either a valid lookup table, that is a table with one to one lookup (e.g. created with FillIncreasing)
- if the lookup table has less items than the main dynamic array, its content will be recreated


procedure CreateOrderedIndex(out aIndex: TSynTempBuffer; aCompare: TDynArraySortCompare); overload;

Sort the dynamic array items using a lookup array of indexes
- this overloaded method will use the supplied TSynTempBuffer for index storage, so use PIntegerArray(aIndex.buf) to access the values
- caller should always make aIndex.Done once done


procedure CreateOrderedIndexAfterAdd(var aIndex: TIntegerDynArray; aCompare: TDynArraySortCompare);

Sort using a lookup array of indexes, after a Add()
- will resize aIndex if necessary, and set aIndex[Count-1] := Count-1


procedure EnsureSorted(aCompare: TDynArraySortCompare = nil);

Will check all items against aCompare, calling Sort() if needed
- faster than plain Sort() if the array is likely to be already sorted


procedure FastAddSorted(Index: PtrInt; const Item);

Insert a sorted element value at the proper place
- the index should have been computed by FastLocateSorted(): false
- you may consider using FastLocateOrAddSorted() instead


procedure FastDeleteSorted(Index: PtrInt);

Delete a sorted element value at the proper place
- plain Delete(Index) would reset the fSorted flag to FALSE, so use this method with a FastLocateSorted/FastAddSorted array


procedure FillZero;

Will call FillZero() on all items, mainly binaries and strings
- could be used on a dynamic array to avoid memory forensic after release


procedure Init(aTypeInfo: PRttiInfo; var aValue; aCountPointer: PInteger = nil);

Initialize the wrapper with a one-dimension dynamic array
- the dynamic array must have been defined with its own type (e.g. TIntegerDynArray = array of integer)
- if aCountPointer is set, it will be used instead of length() to store the dynamic array items count - it will be much faster when adding items to the array, because the dynamic array won't need to be resized each time - but in this case, you should use the Count property instead of length(array) or high(array) when accessing the data: in fact length(array) will store the memory size reserved, not the items count
- if aCountPointer is set, its content will be set to 0, whatever the array length is, or the current aCountPointer^ value is - to bypass this behavior and keep an existing Count, call UseExternalCount() after Init()
- a sample usage may be:

var
  DA: TDynArray;
  A: TIntegerDynArray;
begin
  DA.Init(TypeInfo(TIntegerDynArray), A);
 (...)

- a sample usage may be (using a count variable):

var
  DA: TDynArray;
  A: TIntegerDynArray;
  ACount: integer;
  i: integer;
begin
  DA.Init(TypeInfo(TIntegerDynArray), A, @ACount);
  for i := 1 to 100000 do
    DA.Add(i); // MUCH faster using the ACount variable
 (...)   // now you should use DA.Count or Count instead of length(A)

procedure InitFrom(aAnother: PDynArray; var aValue);

Fast initialize a wrapper for an existing dynamic array of the same type
- is slightly faster than

 InitRtti(aAnother.Info, aValue, nil);

procedure InitRtti(aInfo: TRttiCustom; var aValue; aCountPointer: PInteger); overload;

Initialize the wrapper with a one-dimension dynamic array
- low-level method, as called by Init() and InitSpecific()
- can be called directly for a very fast TDynArray initialization
- warning: caller should check that aInfo.Kind=rkDynArray


procedure InitRtti(aInfo: TRttiCustom; var aValue); overload;

Initialize the wrapper with a one-dimension dynamic array
- low-level method, as called by Init() and InitSpecific()
- can be called directly for a very fast TDynArray initialization
- warning: caller should check that aInfo.Kind=rkDynArray


procedure Insert(Index: PtrInt; const Item);

Add an element to the dynamic array at the position specified by Index
- warning: Item must be of the same exact type than the dynamic array, and must be a reference to a variable (you can't write Insert(10,i+10) e.g.)


procedure ItemClear(Item: pointer);

Will reset the element content
- i.e. release any managed type memory, and fill Item with zeros


procedure ItemCopy(Source, Dest: pointer);

Will copy one element content


procedure ItemCopyFrom(Source: pointer; index: PtrInt; ClearBeforeCopy: boolean = false);

Will copy one variable content into an indexed element
- do nothing if index is out of range
- ClearBeforeCopy will call ItemClear() before the copy, which may be safer if the source item is a copy of Values[index] with some dynamic arrays


procedure ItemLoad(Source, SourceMax: PAnsiChar; Item: pointer);

Load an array element as saved by the ItemSave method into Item variable
- warning: Item must be of the same exact type than the dynamic array


procedure ItemLoadMemClear(var ItemTemp: RawByteString);

Finalize a temporary buffer used to store an element via ItemLoadMem()
- will release any managed type referenced inside the RawByteString, then void the variable
- is just a wrapper around ItemClear(pointer(ItemTemp)) + ItemTemp := ''


procedure ItemRandom(Item: pointer);

Will fill the element with some random content
- this method is thread-safe using Rtti.DoLock/DoUnLock


procedure LoadFromReader(var Read: TFastReader);

Unserialize dynamic array content from binary written by TDynArray.SaveTo


procedure LoadFromStream(Stream: TCustomMemoryStream);

Load the dynamic array content from a (memory) stream
- stream content must have been created using SaveToStream method
- will handle array of binaries values (byte, word, integer...), array of strings or array of packed records, with binaries and string properties
- will use a proprietary binary format, with some variable-length encoding of the string length - note that if you change the type definition, any previously-serialized content will fail, maybe triggering unexpected GPF: use SaveToTypeInfoHash if you share this binary data accross executables


procedure Reverse;

Will reverse all array items, in place


procedure SaveTo(W: TBufferWriter); overload;

Save the dynamic array content using our binary serialization
- will use a proprietary binary format, with some variable-length encoding of the string length - note that if you change the type definition, any previously-serialized content will fail, maybe triggering unexpected GPF
- this method will raise an ESynException for T*ObjArray types
- use TDynArray.LoadFrom to decode the saved buffer
- warning: legacy Hash32 checksum will be stored as 0, so may be refused by mORMot TDynArray.LoadFrom before 1.18.5966


procedure SaveToJson(W: TTextWriter; ObjectOptions: TTextWriterWriteObjectOptions = []); overload;

Serialize the dynamic array content as JSON
- is just a wrapper around TTextDateWTTextWriterriter.AddTypedJson()
- this method will therefore recognize T*ObjArray types


procedure SaveToJson(out result: RawUtf8; Options: TTextWriterOptions; ObjectOptions: TTextWriterWriteObjectOptions = []; reformat: TTextWriterJsonFormat = jsonCompact); overload;

Serialize the dynamic array content as JSON
- is just a wrapper around TTextWriter.AddTypedJson()
- this method will therefore recognize T*ObjArray types


procedure SaveToJson(out result: RawUtf8; EnumSetsAsText: boolean = false; reformat: TTextWriterJsonFormat = jsonCompact); overload;

Serialize the dynamic array content as JSON


procedure SaveToStream(Stream: TStream);

Save the dynamic array content into a (memory) stream
- will handle array of binaries values (byte, word, integer...), array of strings or array of packed records, with binaries and string properties
- will use a proprietary binary format, with some variable-length encoding of the string length - note that if you change the type definition, any previously-serialized content will fail, maybe triggering unexpected GPF: use SaveToTypeInfoHash if you share this binary data accross executables
- Stream position will be set just after the added data
- is optimized for memory streams, but will work with any kind of TStream


procedure Slice(var Dest; Limit: cardinal; Offset: cardinal = 0);

Select a sub-section (slice) of a dynamic array content


procedure SliceAsDynArray(Dest: PPointer; Offset: integer = 0; Limit: integer = 0);

Assign the current dynamic array content into a variable
- by default (Offset=Limit=0), the whole array is set with no memory (re)allocation, just finalize the Dest slot, then make Inc(RefCnt) and force the internal length/Capacity to equal Count
- Offset/Limit could be used to create a new dynamic array with some part of the existing content (Offset<0 meaning from the end):

 SliceAsDynArray(DA);         // items 0..Count-1 (assign with refcount)
 SliceAsDynArray(DA, 10);     // items 10..Count-1
 SliceAsDynArray(DA, 0, 10);  // first 0..9 items
 SliceAsDynArray(DA, 10, 20); // items 10..29 - truncated if Count < 20
 SliceAsDynArray(DA, -10);    // last Count-10..Count-1 items

procedure Sort(aCompare: TDynArraySortCompare = nil); overload;

Sort the dynamic array items, using the Compare property function
- it will change the dynamic array content, and exchange all items in order to be sorted in increasing order according to Compare function


procedure Sort(const aCompare: TOnDynArraySortCompare; aReverse: boolean = false); overload;

Sort the dynamic array items, using a Compare method (not function)
- it will change the dynamic array content, and exchange all items in order to be sorted in increasing order according to Compare function, unless aReverse is true
- it won't mark the array as Sorted, since the comparer is local


procedure SortRange(aStart, aStop: integer; aCompare: TDynArraySortCompare = nil);

Sort some dynamic array items, using the Compare property function
- this method allows to sort only some part of the items
- it will change the dynamic array content, and exchange all items in order to be sorted in increasing order according to Compare function


procedure UseExternalCount(aCountPointer: PInteger);

Define the reference to an external count integer variable
- Init and InitSpecific methods will reset the aCountPointer to 0: you can use this method to set the external count variable without overriding the current value


procedure Void;

Initialize the wrapper to point to no dynamic array
- it won't clear the wrapped array, just reset the fValue internal pointer
- in practice, will disable the other methods


property Capacity: PtrInt read GetCapacity write SetCapacity;

The internal buffer capacity
- if no external Count pointer was set with Init, is the same as Count
- if an external Count pointer is set, you can set a value to this property before a massive use of the Add() method e.g.
- if no external Count pointer is set, set a value to this property will affect the Count value, i.e. Add() will append after this count
- this property will recognize T*ObjArray types, so will free any stored instance if the array is sized down


property Compare: TDynArraySortCompare read fCompare write SetCompare;

The compare function to be used for Sort and Find methods
- by default, no comparison function is set
- common functions exist for base types: e.g. SortDynArrayByte, SortDynArrayBoolean, SortDynArrayWord, SortDynArrayInteger, SortDynArrayCardinal, SortDynArraySingle, SortDynArrayInt64, SortDynArrayDouble, SortDynArrayAnsiString, SortDynArrayAnsiStringI, SortDynArrayString, SortDynArrayStringI, SortDynArrayUnicodeString, SortDynArrayUnicodeStringI


property Count: PtrInt read GetCount write SetCount;

Retrieve or set the number of items of the dynamic array
- same as length(DynArray) or SetLength(DynArray)
- this property will recognize T*ObjArray types, so will free any stored instance if the array is sized down


property CountExternal: PInteger read fCountP;

Low-level direct access to the external count (if defined at Init)
- use UseExternalCount() after Init to avoid resetting the count to 0


property Info: TRttiCustom read fInfo;

Low-level extended RTTI access
- use e.g. Info.ArrayRtti to access the item RTTI, or Info.Cache.ItemInfoManaged to get the managed item TypeInfo()


property NoFinalize: boolean read fNoFinalize write fNoFinalize;

Can be set to TRUE to avoid any item finalization
- e.g. with T*ObjArray - handle with care to avoid memory leaks


property Sorted: boolean read fSorted write fSorted;

Must be TRUE if the array is currently in sorted order according to the compare function
- Add/Delete/Insert/Load* methods will reset this property to false
- Sort method will set this property to true
- you MUST set this property to false if you modify the dynamic array content in your code, so that Find() won't try to wrongly use binary search in an unsorted array, and miss its purpose


property Value: PPointer read fValue;

Low-level direct access to the storage variable


1.3.25. TDynArrayLocked

TDynArrayLocked = record

Just a wrapper record to join a TDynArray, its Count and a TRWLightLock


Count: integer;

Will store the length of the TDynArray


DynArray: TDynArray;

The wrapper to a dynamic array


Safe: TRWLightLock;

Lightweight multiple Reads / exclusive Write non-upgradable lock


1.3.26. TDynArrayHasher

TDynArrayHasher = object(TObject)

Implements O(1) lookup to any dynamic array content
- this won't handle the storage process (like add/update), just efficiently maintain a hash table over an existing dynamic array: several TDynArrayHasher could be applied to a single TDynArray wrapper
- TDynArrayHashed will use a TDynArrayHasher on its own storage


function Equals(Item: pointer; ndx: PtrInt): boolean;

Compare one given item from its index with a value
- using either EventCompare() or Compare() functions


function Find(Item: pointer; aHashCode: cardinal): PtrInt; overload;

Search for a hashed element value inside the dynamic array with hashing


function Find(aHashCode: cardinal; aForAdd: boolean): PtrInt; overload;

Search for a hash position inside the dynamic array with hashing


function Find(Item: pointer): PtrInt; overload;

Search for an element value inside the dynamic array with hashing


function FindBeforeAdd(Item: pointer; out wasAdded: boolean; aHashCode: cardinal): PtrInt;

Search an hashed element value for adding, updating the internal hash table
- trigger hashing if Count reaches CountTrigger


function FindBeforeDelete(Item: pointer): PtrInt;

Search and delete an element value, updating the internal hash table


function FindOrNew(aHashCode: cardinal; Item: pointer; aHashTableIndex: PPtrInt): PtrInt;

Returns position in array, or next void index in HashTable[] as -(index+1)


function FindOrNewComp(aHashCode: cardinal; Item: pointer; Comp: TDynArraySortCompare = nil): PtrInt;

Returns position in array, or -1 if not found with a custom comparer


function GetHashFromIndex(aIndex: PtrInt): cardinal;

Retrieve the low-level hash of a given item


function HashOne(Item: pointer): cardinal;

Compute the hash of a given item


function Scan(Item: pointer): PtrInt;

Search for an element value inside the dynamic array without hashing


procedure ForceReHash(duplicates: PInteger = nil);

Full computation of the internal hash table
- to be called after items have been manually updated - e.g. after Clear
- can return the number of duplicated values found (likely to be 0)


procedure Init(aDynArray: PDynArray; aHashItem: TDynArrayHashOne; const aEventHash: TOnDynArrayHashOne; aHasher: THasher; aCompare: TDynArraySortCompare; const aEventCompare: TOnDynArraySortCompare; aCaseInsensitive: boolean);

Initialize the hash table for a given dynamic array storage
- you can call this method several times, e.g. if aCaseInsensitive changed


procedure InitSpecific(aDynArray: PDynArray; aKind: TRttiParserType; aCaseInsensitive: boolean; aHasher: THasher);

Initialize a known hash table for a given dynamic array storage
- you can call this method several times, e.g. if aCaseInsensitive changed


property Compare: TDynArraySortCompare read fCompare;

Associated item comparison - may differ from DynArray^.Compare


property EventCompare: TOnDynArraySortCompare read fEventCompare write SetEventCompare;

Custom method-based comparison function
- should be set just after Init, when no item has been stored


property EventHash: TOnDynArrayHashOne read fEventHash write SetEventHash;

Custom method-based hashing function
- should be set just after Init, when no item has been stored


property Hasher: THasher read fHasher;

Associated item hasher


1.3.27. TDynArrayHashed

TDynArrayHashed = object(TDynArray)

Used to access any dynamic arrray items using fast hash
- by default, binary sort could be used for searching items for TDynArray: using a hash is faster on huge arrays for implementing a dictionary
- in this current implementation, modification (update or delete) of an element is not handled yet: you should rehash all content - only TDynArrayHashed.FindHashedForAdding / FindHashedAndUpdate / FindHashedAndDelete will refresh the internal hash
- this object extends the TDynArray type, since presence of Hashs[] dynamic array will increase code size if using TDynArrayHashed instead of TDynArray
- in order to have the better performance, you should use an external Count variable, AND set the Capacity property to the expected maximum count (this will avoid most re-hashing for FindHashedForAdding+FindHashedAndUpdate)
- consider using TSynDictionary from mormot.core.json for a thread-safe stand-alone storage of key/value pairs


function AddAndMakeUniqueName(aName: RawUtf8): pointer;

Search for a given element name, make it unique, and add it to the array
- expected element layout is to have a RawUtf8 field at first position
- the aName is searched (using hashing) to be unique, and if not the case, some suffix is added to make it unique, counting from _1 to _999
- use internally FindHashedForAdding method
- this version will set the field content with the unique value
- returns a pointer to the newly added element (to set other fields)


function AddUniqueName(const aName: RawUtf8; const ExceptionMsg: RawUtf8; const ExceptionArgs: array of const; aNewIndex: PPtrInt = nil): pointer; overload;

Ensure a given element name is unique, then add it to the array
- expected element layout is to have a RawUtf8 field at first position
- the aName is searched (using hashing) to be unique, and if not the case, an ESynException.CreateUtf8() is raised with the supplied arguments
- use internally FindHashedForAdding method
- this version will set the field content with the unique value
- returns a pointer to the newly added element (to set other fields)


function AddUniqueName(const aName: RawUtf8; aNewIndex: PPtrInt = nil): pointer; overload;

Ensure a given element name is unique, then add it to the array
- just a wrapper to AddUniqueName(aName,'',[],aNewIndex)


function FindFromHash(const Item; aHashCode: cardinal): PtrInt;

Search for an element value inside the dynamic array using its hash
- returns -1 if not found, or the index in the dynamic array if found
- aHashCode parameter constains an already hashed value of the item, to be used e.g. after a call to HashFind()


function FindHashed(const Item): PtrInt;

Search for an element value inside the dynamic array using hashing
- Item should be of the type expected by both the hash function and Compare/EventCompare methods: e.g. if the searched/hashed field contains a string as first field, you can safely use a string variable as Item
- Item must refer to a variable: e.g. you can't write FindHashed(i+10)
- will call fHashItem(Item,fHasher) to compute the needed hash
- returns -1 if not found, or the index in the dynamic array if found


function FindHashedAndDelete(const Item; FillDeleted: pointer = nil; noDeleteEntry: boolean = false): PtrInt;

Search for an element value inside the dynamic array using hashing, and delete it if matchs
- return the index deleted (0..Count-1), or -1 if Item was not found
- can optionally copy the deleted item to FillDeleted^ before erased
- Item should be of the type expected by Compare/EventCompare (no need to supply a full array item), and by design must refer to a variable: e.g. you can't write FindHashedAndDelete(i+10)
- it won't call slow ForceReHash but refresh the hash table as needed


function FindHashedAndFill(var ItemToFill): PtrInt;

Search for an element value inside the dynamic array using hashing, and fill ItemToFill with the found content
- return the index found (0..Count-1), or -1 if Item was not found
- ItemToFill should be of the type expected by the dynamic array, since all its fields will be set on match


function FindHashedAndUpdate(const Item; AddIfNotExisting: boolean): PtrInt;

Search for an element value inside the dynamic array using hashing, then update any matching item, or add the item if none matched
- by design, hashed field shouldn't have been modified by this update, otherwise the method won't be able to find and update the old hash: in this case, you should first call FindHashedAndDelete(OldItem) then FindHashedForAdding(NewItem) to properly handle the internal hash table
- if AddIfNotExisting is FALSE, returns the index found (0..Count-1), or -1 if Item was not found - Update will force slow rehash all content
- if AddIfNotExisting is TRUE, returns the index found (0..Count-1), or the index newly created/added is the Item value was not matching - add won't rehash all content - for even faster process (avoid rehash), please set the Capacity property
- Item should be of the type expected by the dynamic array, since its content will be copied into the dynamic array, and by design it must refer to a variable: e.g. you can't write FindHashedAndUpdate(i+10)


function FindHashedForAdding(const Item; out wasAdded: boolean; aHashCode: cardinal; noAddEntry: boolean = false): PtrInt; overload;

Search for an element value inside the dynamic array using hashing, and add a void entry to the array if was not found (unless noAddEntry is set)
- overloaded method accepting an already hashed value of the item, to be used e.g. after a call to HashFind()


function FindHashedForAdding(const Item; out wasAdded: boolean; noAddEntry: boolean = false): PtrInt; overload;

Search for an element value inside the dynamic array using hashing, and add a void entry to the array if was not found (unless noAddEntry is set)
- this method will use hashing for fast retrieval
- Item should be of the type expected by both the hash function and Compare/EventCompare methods: e.g. if the searched/hashed field contains a string as first field, you can safely use a string variable as Item
- returns either the index in the dynamic array if found (and set wasAdded to false), either the newly created index in the dynamic array (and set wasAdded to true)
- for faster process (avoid rehash), please set the Capacity property
- warning: in contrast to the Add() method, if an entry is added to the array (wasAdded=true), the entry is left VOID: you must set the field content to expecting value - in short, Item is used only for searching, not copied to the newly created entry in the array - check FindHashedAndUpdate() for a method actually copying Item fields


function Scan(const Item): PtrInt;

Search for an element value inside the dynamic array without hashing
- is preferred to Find(), since EventCompare would be used if defined
- Item should be of the type expected by Compare/EventCompare (no need to supply a full array item), and by design must refer to a variable: e.g. you can't write Scan(i+10)
- returns -1 if not found, or the index in the dynamic array if found


procedure ForceReHash;

Will recompute all hash from the current items of the dynamic array
- can be called on purpose, when modifications have been performed on the dynamic array content (e.g. in case of element deletion or update, or after calling LoadFrom/Clear method) - this is not necessary after FindHashedForAdding / FindHashedAndUpdate / FindHashedAndDelete methods
- returns the number of duplicated items found - which should be 0


procedure Init(aTypeInfo: PRttiInfo; var aValue; aHashItem: TDynArrayHashOne = nil; aCompare: TDynArraySortCompare = nil; aHasher: THasher = nil; aCountPointer: PInteger = nil; aCaseInsensitive: boolean = false);

Initialize the wrapper with a one-dimension dynamic array
- this version accepts some hash-dedicated parameters: aHashItem to set how to hash each element, aCompare to handle hash collision
- if no aHashItem is supplied, it will hash according to the RTTI, i.e. strings or binary types, and the first field for records (strings included)
- if no aCompare is supplied, it will use default Equals() method
- if no THasher function is supplied, it will use the one supplied in DefaultHasher global variable, set to crc32c() by default - using SSE4.2 instruction if available
- if CaseInsensitive is set to TRUE, it will ignore difference in 7-bit alphabetic characters (e.g. compare 'a' and 'A' as equal)


procedure InitRtti(aRtti: TRttiCustom; var aValue; aHashItem: TDynArrayHashOne = nil; aCompare: TDynArraySortCompare = nil; aHasher: THasher = nil; aCountPointer: PInteger = nil; aCaseInsensitive: boolean = false);

Initialize the wrapper with a one-dimension dynamic array from our RTTI


procedure InitSpecific(aTypeInfo: PRttiInfo; var aValue; aKind: TRttiParserType; aCountPointer: PInteger = nil; aCaseInsensitive: boolean = false; aHasher: THasher = nil);

Initialize the wrapper with a one-dimension dynamic array
- this version accepts to specify how both hashing and comparison should occur, setting the TRttiParserType kind of first/hashed field
- djNone and djCustom are too vague, and will raise an exception
- no RTTI check is made over the corresponding array layout: you shall ensure that aKind matches the dynamic array element definition
- aCaseInsensitive will be used for djRawUtf8..djHash512 text comparison


property EventCompare: TOnDynArraySortCompare read fHash.fEventCompare write SetEventCompare;

Alternative event-oriented Compare function to be used for Sort and Find
- will be used instead of Compare, to allow object-oriented callbacks
- should be set just after Init, when not item has been stored


property EventHash: TOnDynArrayHashOne read fHash.fEventHash write SetEventHash;

Alternative event-oriented Hash function
- this object-oriented callback will be used instead of HashItem() on each dynamic array entries - HashItem will still be used on const Item values, since they may be just a sub part of the stored entry
- should be set just after Init, when not item has been stored


property Hash[aIndex: PtrInt]: cardinal read GetHashFromIndex;

Retrieve the hash value of a given item, from its index


property Hasher: TDynArrayHasher read fHash;

Access to the internal hash table
- you can call e.g. Hasher.Clear to invalidate the whole hash table


property HashItem: TDynArrayHashOne read fHash.fHashItem;

Custom hash function used for hashing of a dynamic array element


1.3.28. TRawUtf8Hashed

TRawUtf8Hashed = object(TObject)

Store a TRawUtf8DynArray with its efficient hash table


procedure Init;

Initialize the RawUtf8 dynamic array and hasher


1.3.29. TRawUtf8InterningSlot

TRawUtf8InterningSlot = object(TObject)

Used to store one list of hashed RawUtf8 in TRawUtf8Interning pool
- Delphi "object" is buggy on stack -> also defined as record with methods
- each slot has its own TRWLightLock for efficient concurrent reads


function Clean(aMaxRefCount: TStrCnt): integer;

Reclaim any unique RawUtf8 values
- any string with an usage count <= aMaxRefCount will be removed


function Existing(const aText: RawUtf8; aTextHash: cardinal): pointer;

Return the interned value, if any


procedure Clear;

Delete all stored RawUtf8 values


procedure Init;

Initialize the RawUtf8 slot (and its Safe mutex)


procedure Unique(var aResult: RawUtf8; const aText: RawUtf8; aTextHash: cardinal);

Returns the interned RawUtf8 value


procedure UniqueFromBuffer(var aResult: RawUtf8; aText: PUtf8Char; aTextLen: PtrInt; aTextHash: cardinal); overload;

Returns the interned RawUtf8 value
- only allocates new aResult string if needed


procedure UniqueFromBuffer(var aResult: RawUtf8; aText: PUtf8Char; aTextLen: PtrInt); overload;

Returns the interned RawUtf8 value with no pre-computed hash


procedure UniqueText(var aText: RawUtf8; aTextHash: cardinal);

Ensure the supplied RawUtf8 value is interned


property Count: integer read fHash.Count;

How many items are currently stored in Value[]


1.3.30. TRawUtf8Interning

TRawUtf8Interning = class(TRawUtf8InterningAbstract)

Allow to store only one copy of distinct RawUtf8 values
- thanks to the Copy-On-Write feature of string variables, this may reduce a lot the memory overhead of duplicated text content
- this class is thread-safe and optimized for performance


constructor Create(aHashTables: integer = 4); reintroduce;

Initialize the storage and its internal hash pools
- aHashTables is the pool size, and should be a power of two <= 512 (1, 2, 4, 8, 16, 32, 64, 128, 256, 512)


function Clean(aMaxRefCount: TStrCnt = 1): integer;

Reclaim any unique RawUtf8 values
- i.e. run a garbage collection process of all values with RefCount=1 by default, i.e. all string which are not used any more; you may set aMaxRefCount to a higher value, depending on your expecations, i.e. 2 to delete all string which are referenced only once outside of the pool
- returns the number of unique RawUtf8 cleaned from the internal pool
- to be executed on a regular basis - but not too often, since the process can be time consumming, and void the benefit of interning


function Count: integer;

How many items are currently stored in this instance


function Existing(const aText: RawUtf8): pointer;

Check if a RawUtf8 value is already stored within this class
- if not existing, returns nil and don't add it to the pool
- if existing, returns pointer(fValue[i]) of the unique stored RawUtf8
- use e.g. for very fast per-pointer lookup of interned property names


function Unique(const aText: RawUtf8): RawUtf8; overload;

Return a RawUtf8 variable stored within this class
- if aText occurs for the first time, add it to the internal string pool
- if aText does exist in the internal string pool, return the shared instance (with its reference counter increased), to reduce memory usage


function Unique(aText: PUtf8Char; aTextLen: PtrInt): RawUtf8; overload;

Return a RawUtf8 variable stored within this class from a text buffer
- if aText occurs for the first time, add it to the internal string pool
- if aText does exist in the internal string pool, return the shared instance (with its reference counter increased), to reduce memory usage


procedure Clear;

Delete any previous storage pool


procedure Unique(var aResult: RawUtf8; const aText: RawUtf8); overload;

Return a RawUtf8 variable stored within this class
- if aText occurs for the first time, add it to the internal string pool
- if aText does exist in the internal string pool, return the shared instance (with its reference counter increased), to reduce memory usage


procedure Unique(var aResult: RawUtf8; aText: PUtf8Char; aTextLen: PtrInt); overload;

Return a RawUtf8 variable stored within this class from a text buffer
- if aText occurs for the first time, add it to the internal string pool
- if aText does exist in the internal string pool, return the shared instance (with its reference counter increased), to reduce memory usage
- this method won't allocate any memory if aText is already interned


procedure UniqueText(var aText: RawUtf8);

Ensure a RawUtf8 variable is stored within this class
- if aText occurs for the first time, add it to the internal string pool
- if aText does exist in the internal string pool, set the shared instance (with its reference counter increased), to reduce memory usage


procedure UniqueVariant(var aResult: variant; const aText: RawUtf8); overload;

Return a variant containing a RawUtf8 stored within this class
- similar to RawUtf8ToVariant(), but with string interning
- see also UniqueVariant() from mormot.core.variants if you want to intern only non-numerical values


procedure UniqueVariant(var aResult: variant); overload;

Ensure a variant contains only RawUtf8 stored within this class
- supplied variant should be a varString containing a RawUtf8 value


procedure UniqueVariantString(var aResult: variant; const aText: string);

Return a variant containing a RawUtf8 stored within this class
- similar to RawUtf8ToVariant(StringToUtf8()), but with string interning
- this method expects the text to be supplied as a RTL string, which will be converted into a variant containing a RawUtf8 varString instance


1.3.31. TRawUtf8List

TRawUtf8List = class(TSynPersistentRWLock)

Thread-safe TStringList-class optimized for our native UTF-8 string type
- can optionally store associated some TObject instances
- high-level methods of this class are thread-safe
- if fNoDuplicate flag is defined, an internal hash table will be maintained to perform IndexOf() lookups in O(1) linear way
- not thread-safe by default, unless fThreadSafe is set to use the TRWLock


constructor Create(aOwnObjects: boolean; aNoDuplicate: boolean = false; aCaseSensitive: boolean = true); reintroduce; overload;

Backward compatiliby overloaded constructor
- please rather use the overloaded CreateEx(TRawUtf8ListFlags)
- for instance, Create(true) is CreateEx([fObjectsOwned, fCaseSensitive]);


constructor Create; overload; override;

Initialize the RawUtf8/Objects storage with [fCaseSensitive] flags


constructor CreateEx(aFlags: TRawUtf8ListFlags);

Initialize the RawUtf8/Objects storage with extended flags
- by default, any associated Objects[] are just weak references; you may supply fOwnObjects flag to force object instance management
- if you want the stored text items to be unique, set fNoDuplicate and then an internal hash table will be maintained for fast IndexOf()
- you can set fCaseSensitive to let the UTF-8 lookup be case-sensitive
- not thread-safe by default, unless fThreadSafe is set to use a R/W lock
- is defined as CreateEx instead of overload Create to avoid weird Delphi compilation issues, especially within packages


destructor Destroy; override;

Finalize the internal objects stored
- if instance was created with fOwnObjects flag


function Add(const aText: RawUtf8; aRaiseExceptionIfExisting: boolean = false): PtrInt;

Store a new RawUtf8 item
- without the fNoDuplicate flag, it will always add the supplied value
- if fNoDuplicate was set and aText already exists (using the internal hash table), it will return -1 unless aRaiseExceptionIfExisting is forced
- thread-safe method


function AddObject(const aText: RawUtf8; aObject: TObject; aRaiseExceptionIfExisting: boolean = false; aFreeAndReturnExistingObject: PPointer = nil; aReplaceExistingObject: boolean = false): PtrInt;

Store a new RawUtf8 item, and its associated TObject
- without the fNoDuplicate flag, it will always add the supplied value
- if fNoDuplicate was set and aText already exists (using the internal hash table), it will return -1 unless aRaiseExceptionIfExisting is forced; optionally freeing the supplied aObject if aFreeAndReturnExistingObject is set, in which pointer the existing Objects[] is copied (see AddObjectUnique as a convenient wrapper around this behavior); if aFreeAndReturnExistingObject is nil, and aReplaceExistingObject is true, the existing object is freed and replaced by aObject
- thread-safe method


function AddOrReplaceObject(const aText: RawUtf8; aObject: TObject): PtrInt;

Force the storage of a RawUtf8 item, and its associated TObject
- without the fNoDuplicate flag, it will always add the supplied value
- if fNoDuplicate was set and aText already exists (using the internal hash table), it will free any existing Objects[] and put aObject in its place
- thread-safe method, using an internal Hash Table to speedup IndexOf()


function Contains(const aText: RawUtf8; aFirstIndex: integer = 0): PtrInt;

Search for any RawUtf8 item containing some text
- uses PosEx() on the stored lines
- this method is not thread-safe since the internal list may change and the returned index may not be accurate any more
- by design, aText lookup can't use the internal Hash Table


function Delete(const aText: RawUtf8): PtrInt; overload;

Delete a stored RawUtf8 item, and its associated TObject
- will search for the value using IndexOf(aText), and returns its index
- returns -1 if no entry was found and deleted
- thread-safe method, using the internal Hash Table if fNoDuplicate is set


function DeleteFromName(const Name: RawUtf8): PtrInt; virtual;

Delete a stored RawUtf8 item, and its associated TObject, from a given Name when stored as 'Name=Value' pairs
- raise no exception in case of out of range supplied index
- thread-safe method, but not using the internal Hash Table
- consider using TSynNameValue if you expect efficient name/value process


function EqualValueAt(Index: PtrInt; const aText: RawUtf8): boolean;

Compare a Value with some RawUtf8 text
- this method is not thread-safe


function Exists(const aText: RawUtf8): boolean;

Find a RawUtf8 item in the stored Strings[] list
- search is case sensitive if fCaseSensitive flag was set (default)
- this method is thread-safe
- uses the internal Hash Table if fNoDuplicate was set


function GetObjectFrom(const aText: RawUtf8): pointer;

Get a stored Object item by its associated UTF-8 text
- returns nil and raise no exception if aText doesn't exist
- thread-safe method, unless returned TObject is deleted in the background


function GetText(const Delimiter: RawUtf8 = #13#10): RawUtf8;

Retrieve the all lines, separated by the supplied delimiter
- this method is thread-safe


function GetValueAt(Index: PtrInt): RawUtf8;

Access to the Value of a given 'Name=Value' pair at a given position
- this method is not thread-safe
- consider using TSynNameValue if you expect efficient name/value process


function IndexOf(const aText: RawUtf8): PtrInt;

Find a RawUtf8 item in the stored Strings[] list
- this search is case sensitive if fCaseSensitive flag was set (which is the default)
- this method is not thread-safe since the internal list may change and the returned index may not be accurate any more
- see also Exists() and GetObjectFrom() method
- uses the internal Hash Table if fNoDuplicate was set


function IndexOfName(const Name: RawUtf8): PtrInt;

Find the index of a given Name when stored as 'Name=Value' pairs
- search on Name is case-insensitive with 'Name=Value' pairs
- this method is not thread-safe, and won't use the internal Hash Table
- consider using TSynNameValue if you expect efficient name/value process


function IndexOfObject(aObject: TObject): PtrInt;

Find a TObject item index in the stored Objects[] list
- this method is not thread-safe since the internal list may change and the returned index may not be accurate any more
- aObject lookup won't use the internal Hash Table


function PopFirst(out aText: RawUtf8; aObject: PObject = nil): boolean;

Retrieve and delete the first RawUtf8 item in the list
- could be used as a FIFO, calling Add() as a "push" method
- thread-safe method


function PopLast(out aText: RawUtf8; aObject: PObject = nil): boolean;

Retrieve and delete the last RawUtf8 item in the list
- could be used as a FILO, calling Add() as a "push" method
- thread-safe method


function UpdateValue(const Name: RawUtf8; var Value: RawUtf8; ThenDelete: boolean): boolean;

Retrieve Value from an existing Name=Value, then optinally delete the entry
- if Name is found, will fill Value with the stored content and return true
- if Name is not found, Value is not modified, and false is returned
- thread-safe method, but not using the internal Hash Table
- consider using TSynNameValue if you expect efficient name/value process


procedure AddObjectUnique(const aText: RawUtf8; aObjectToAddOrFree: PPointer);

Try to store a new RawUtf8 item and its associated TObject
- fNoDuplicate should have been specified in the list flags
- if aText doesn't exist, will add the values
- if aText exist, will call aObjectToAddOrFree.Free and set the value already stored in Objects[] into aObjectToAddOrFree - allowing dual commit thread-safe update of the list, e.g. after a previous unsuccessful call to GetObjectFrom(aText)
- thread-safe method, using an internal Hash Table to speedup IndexOf()
- in fact, this method is just a wrapper around

 AddObject(aText,aObjectToAddOrFree^,false,@aObjectToAddOrFree);

procedure AddRawUtf8List(List: TRawUtf8List);

Append a specified list to the current content
- thread-safe method


procedure BeginUpdate;

The OnChange event will be raised only when EndUpdate will be called
- this method will also call Safe.Lock for thread-safety


procedure Clear; virtual;

Erase all stored RawUtf8 items
- and corresponding objects (if aOwnObjects was true at constructor)
- thread-safe method, also clearing the internal Hash Table


procedure Delete(Index: PtrInt); overload;

Delete a stored RawUtf8 item, and its associated TObject
- raise no exception in case of out of range supplied index
- this method is not thread-safe: use Safe.Lock/UnLock if needed


procedure EndUpdate;

Call the OnChange event if changes occurred
- this method will also call Safe.UnLock for thread-safety


procedure LoadFromFile(const FileName: TFileName);

Set all lines from a text file
- will assume text file with no BOM is already UTF-8 encoded
- this method is thread-safe


procedure SaveToFile(const FileName: TFileName; const Delimiter: RawUtf8 = #13#10);

Write all lines into a new UTF-8 file
- this method is thread-safe


procedure SaveToStream(Dest: TStream; const Delimiter: RawUtf8 = #13#10);

Write all lines into the supplied stream
- this method is thread-safe


procedure SetFrom(const aText: TRawUtf8DynArray; const aObject: TObjectDynArray);

Set low-level text and objects from existing arrays


procedure SetText(const aText: RawUtf8; const Delimiter: RawUtf8 = #13#10);

Set all lines, separated by the supplied delimiter
- this method is thread-safe


property Capacity: PtrInt read GetCapacity write SetCapacity;

Set or retrieve the current memory capacity of the RawUtf8 list
- reading this property is not thread-safe, since size may change


property CaseSensitive: boolean read GetCaseSensitive write SetCaseSensitive;

Set if IndexOf() shall be case sensitive or not
- default is TRUE
- matches fCaseSensitive in Flags


property Count: PtrInt read GetCount;

Return the count of stored RawUtf8
- reading this property is not thread-safe, since size may change


property Flags: TRawUtf8ListFlags read fFlags write fFlags;

Access to the low-level flags of this list


property Names[Index: PtrInt]: RawUtf8 read GetName;

Retrieve the corresponding Name when stored as 'Name=Value' pairs
- reading this property is not thread-safe, since content may change
- consider TSynNameValue if you expect more efficient name/value process


property NameValueSep: AnsiChar read fNameValueSep write fNameValueSep;

The char separator between 'Name=Value' pairs
- equals '=' by default
- consider TSynNameValue if you expect more efficient name/value process


property NoDuplicate: boolean read GetNoDuplicate;

Set if the list doesn't allow duplicated UTF-8 text
- if true, an internal hash table is maintained for faster IndexOf()
- matches fNoDuplicate in Flags


property ObjectPtr: PPointerArray read GetObjectPtr;

Direct access to the memory of the TObjectDynArray items
- reading this property is not thread-safe, since content may change


property Objects[Index: PtrInt]: pointer read GetObject write PutObject;

Get or set a Object item
- returns nil and raise no exception in case of out of range supplied index
- reading this property is not thread-safe, since content may change


property OnChange: TNotifyEvent read fOnChange write fOnChange;

Event triggered when an entry is modified


property Str[Index: PtrInt]: string read GetS write PutS;

Get or set an item as RTL string, ready to be used with the UI
- returns '' and raise no exception in case of out of range supplied index
- wrap Strings[] with Utf8ToString/StringToUtf8 functions
- reading this property is not thread-safe, since content may change


property Strings[Index: PtrInt]: RawUtf8 read Get write Put;

Get or set a RawUtf8 item
- returns '' and raise no exception in case of out of range supplied index
- if you want to use it with the UI, use Utf8ToString() function
- reading this property is not thread-safe, since content may change


property Text: RawUtf8 read GetTextCRLF write SetTextCRLF;

Set or retrieve all items as text lines
- lines are separated by #13#10 (CRLF) by default; use GetText and SetText methods if you want to use another line delimiter (even a comma)
- this property is thread-safe


property TextPtr: PPUtf8CharArray read GetTextPtr;

Direct access to the memory of the TRawUtf8DynArray items
- reading this property is not thread-safe, since content may change


property ValuePtr: TRawUtf8DynArray read fValue;

Direct access to the TRawUtf8DynArray instance
- reading this property is not thread-safe, since content may change


property Values[const Name: RawUtf8]: RawUtf8 read GetValue write SetValue;

Access to the corresponding 'Name=Value' pairs
- search on Name is case-insensitive with 'Name=Value' pairs
- reading this property is thread-safe, but won't use the hash table
- consider TSynNameValue if you expect more efficient name/value process


property ValuesArray: TDynArrayHashed read fValues;

Direct access to the TRawUtf8DynArray items dynamic array wrapper
- using this property is not thread-safe, since content may change


1.3.32. TRawUtf8ListLocked

TRawUtf8ListLocked = class(TRawUtf8List)

Some declarations used for backward compatibility only


1.3.33. TRadixTreeNode

TRadixTreeNode = class(TObject)

Implement an abstract Radix Tree node


Chars: RawUtf8;

The characters to be compared at this level


Child: array of TRadixTreeNode;

The nested nodes


Depth: integer;

How many branches are within this node - used to sort by priority


Flags: TRadixTreeNodeFlags;

Describe the content of this node


FullText: RawUtf8;

The whole text up to this level


Owner: TRadixTree;

The main Tree holding this node


constructor Create(aOwner: TRadixTree); reintroduce;

Initialize this node instance


destructor Destroy; override;

Finalize this Radix Tree node


function Find(P: PUtf8Char): TRadixTreeNode;

Search for the node corresponding to a given text


function Split(const Text: RawUtf8): TRadixTreeNode; virtual;

Instantiate a new node with the same class and properties


procedure ToText(var Result: RawUtf8; Level: integer);

Internal debugging/testing method


1.3.34. TRadixTree

TRadixTree = class(TObject)

Implement an abstract Radix Tree over UTF-8 case-insensitive text
- as such, this class is not very useful if you just need to lookup for a text value: a TDynArrayHasher/TDictionary is faster and uses less RAM
- but, once extended e.g. as TUriTree, it can very efficiently parse some text with variants parts (e.g. parameters)


constructor Create(aNodeClass: TRadixTreeNodeClass; aOptions: TRadixTreeOptions = []); reintroduce;

For efficient rtoCaseInsensitiveUri initialize the Radix Tree


destructor Destroy; override;

Finalize this Radix Tree


function Find(const Text: RawUtf8): TRadixTreeNode;

Search for the node corresponding to a given text
- more than 6 million lookups per second, with 1000 items stored


function Insert(Text: RawUtf8; Node: TRadixTreeNode = nil; NodeClass: TRadixTreeNodeClass = nil): TRadixTreeNode;

Low-level insertion of a given Text entry as a given child
- may return an existing node instance, if Text was already inserted


function ToText: RawUtf8;

Internal debugging/testing method


procedure AfterInsert;

To be called after Insert() to consolidate the internal tree state
- nodes will be sorted by search priority, i.e. the longest depths first
- as called e.g. by TUriTree.Setup()


procedure Clear;

Finalize this Radix Tree node


property Options: TRadixTreeOptions read fOptions;

Define how TRadixTreeNode.Lookup() will process this node
- as set with this class constructor


property Root: TRadixTreeNode read fRoot;

Low-level access to the root node of the Radix Tree


1.3.35. TRadixTreeNodeParams

TRadixTreeNodeParams = class(TRadixTreeNode)

Implement an abstract Radix Tree static or <param> node


Names: TRawUtf8DynArray;

All the <param1> <param2> names, in order, up to this parameter
- equals nil for static nodes
- is referenced as pointer into THttpServerRequestAbstract.fRouteName


function Lookup(P: PUtf8Char; Ctxt: TObject): TRadixTreeNodeParams;

Main search method, recognizing static or <param> patterns


function Split(const Text: RawUtf8): TRadixTreeNode; override;

Overriden to support the additional Names fields


1.3.36. TRadixTreeParams

TRadixTreeParams = class(TRadixTree)

Implement an abstract Radix Tree with static or <param> nodes


function Setup(const aFromUri: RawUtf8; out aNames: TRawUtf8DynArray): TRadixTreeNodeParams;

Low-level registration of a new URI path, with <param> support
- returns the node matching the given URI
- called e.g. from TUriRouter.Rewrite/Run methods
- will recognize <param> alphanumerical and <int:id> integer parameters


1.4. Types implemented in the mormot.core.data unit

1.4.1. PDocVariantOptions

PDocVariantOptions = ^TDocVariantOptions;

Pointer to a set of options for a TDocVariant storage
- defined in this unit to avoid circular reference with mormot.core.variants
- use e.g. @JSON_[mFast], @JSON_[mDefault], or any other TDocVariantModel


1.4.2. PDynArray

PDynArray = ^TDynArray;

A pointer to a TDynArray Wrapper instance


1.4.3. PDynArrayHasher

PDynArrayHasher = ^TDynArrayHasher;

Pointer to a TDynArrayHasher instance


1.4.4. TDocVariantOption

TDocVariantOption = ( dvoIsArray, dvoIsObject, dvoNameCaseSensitive, dvoCheckForDuplicatedNames, dvoReturnNullForUnknownProperty, dvoValueCopiedByReference, dvoJsonParseDoNotTryCustomVariants, dvoJsonParseDoNotGuessCount, dvoJsonObjectParseWithinString, dvoSerializeAsExtendedJson, dvoAllowDoubleValue, dvoInternNames, dvoInternValues );

Possible options for a TDocVariant JSON/BSON document storage
- defined in this unit to avoid circular reference with mormot.core.variants
- dvoIsArray and dvoIsObject will store the "Kind: TDocVariantKind" state - you should never have to define these two options directly
- dvoNameCaseSensitive will be used for every name lookup - here case-insensitivity is restricted to a-z A-Z 0-9 and _ characters
- dvoCheckForDuplicatedNames will be used for method TDocVariantData.AddValue(), but not when setting properties at variant level: for consistency, "aVariant.AB := aValue" will replace any previous value for the name "AB"
- dvoReturnNullForUnknownProperty will be used when retrieving any value from its name (for dvObject kind of instance), or index (for dvArray or dvObject kind of instance)
- by default, internal values will be copied by-value from one variant instance to another, to ensure proper safety - but it may be too slow: if you set dvoValueCopiedByReference, the internal TDocVariantData.VValue/VName instances will be copied by-reference, to avoid memory allocations, BUT it may break internal process if you change some values in place (since VValue/VName and VCount won't match) - as such, if you set this option, ensure that you use the content as read-only
- any registered custom types may have an extended JSON syntax (e.g. TBsonVariant does for MongoDB types), and will be searched during JSON parsing, unless dvoJsonParseDoNotTryCustomVariants is set (slightly faster)
- the parser will try to guess the array or object size by pre-fetching some content: you can set dvoJsonParseDoNotGuessCount if your input has a lot of nested documents, and manual resize is preferred - this option will be forced by InitJson if a huge nest of objects is detected
- by default, it will only handle direct JSON [array] of {object}: but if you define dvoJsonObjectParseWithinString, it will also try to un-escape a JSON string first, i.e. handle "[array]" or "{object}" content (may be used e.g. when JSON has been retrieved from a database TEXT column) - is used for instance by VariantLoadJson()
- JSON serialization will follow the standard layout, unless dvoSerializeAsExtendedJson is set so that the property names would not be escaped with double quotes, writing '{name:"John",age:123}' instead of '{"name":"John","age":123}': this extended json layout is compatible with http://docs.mongodb.org/manual/reference/mongodb-extended-json and with TDocVariant JSON unserialization, also our SynCrossPlatformJSON unit, but NOT recognized by most JSON clients, like AJAX/JavaScript or C#/Java
- by default, only integer/Int64/currency number values are allowed, unless dvoAllowDoubleValue is set and 32-bit floating-point conversion is tried, with potential loss of precision during the conversion
- dvoInternNames and dvoInternValues will use shared TRawUtf8Interning instances to maintain a list of RawUtf8 names/values for all TDocVariant, so that redundant text content will be allocated only once on heap
- see JSON_[TDocVariantModel] and all JSON_* constants as useful sets, and TDocVariantData.IsObject/IsArray/IsCaseSensitive/Has wrapper methods


1.4.5. TDocVariantOptions

TDocVariantOptions = set of TDocVariantOption;

Set of options for a TDocVariant storage
- defined in this unit to avoid circular reference with mormot.core.variants
- see JSON_[TDocVariantModel] and all JSON_* constants (e.g. JSON_FAST or JSON_FAST_FLOAT) as potential values
- when specifying the options, you should not include dvoIsArray nor dvoIsObject directly in the set, but explicitly define TDocVariantDataKind
- see TDocVariantData.IsObject/IsArray/IsCaseSensitive/Has wrapper methods which are faster than 16-bit "if dvo* in VOptions" on Intel


1.4.6. TDocVariantOptionsBool

TDocVariantOptionsBool = array[boolean] of TDocVariantOptions;

A boolean array of TDocVariant storage options


1.4.7. TDynArrayHashOne

TDynArrayHashOne = function(const Item; Hasher: THasher): cardinal;

Function prototype to be used for hashing of a dynamic array element
- this function must use the supplied hasher on the Item data


1.4.8. TDynArrayKind

TDynArrayKind = TRttiParserType;

Internal enumeration used to specify some standard arrays
- mORMot 1.18 did have two serialization engines - we unified it
- defined only for backward compatible code; use TRttiParserType instead


1.4.9. TDynArraySortCompare

TDynArraySortCompare = function(const A, B): integer;

Function prototype to be used for TDynArray Sort and Find method
- common functions exist for base types: see e.g. SortDynArrayBoolean, SortDynArrayByte, SortDynArrayWord, SortDynArrayInteger, SortDynArrayCardinal, SortDynArrayInt64, SortDynArrayQWord, SordDynArraySingle, SortDynArrayDouble, SortDynArrayAnsiString, SortDynArrayAnsiStringI, SortDynArrayUnicodeString, SortDynArrayUnicodeStringI, SortDynArrayString, SortDynArrayStringI
- any custom type (even records) can be compared then sort by defining such a custom function
- must return 0 if A=B, -1 if A<B, 1 if A>B


1.4.10. TInterfacedCollectionClass

TInterfacedCollectionClass = class of TInterfacedCollection;

Class-reference type (metaclass) of a TInterfacedCollection kind


1.4.11. TInterfacedObjectWithCustomCreateClass

TInterfacedObjectWithCustomCreateClass = class of TInterfacedObjectWithCustomCreate;

Used to determine the exact class type of a TInterfacedObjectWithCustomCreate
- could be used to create instances using its virtual constructor


1.4.12. TOnDynArrayHashOne

TOnDynArrayHashOne = function(const Item): cardinal of object;

Event handler to be used for hashing of a dynamic array element
- can be set as an alternative to TDynArrayHashOne


1.4.13. TOnDynArraySortCompare

TOnDynArraySortCompare = function(const A, B): integer of object;

Event oriented version of TDynArraySortCompare


1.4.14. TOnNotifySortedIntegerChange

TOnNotifySortedIntegerChange = procedure(const Sender; Value: integer) of object;

Event handler called by NotifySortedIntegerChanges()
- Sender is an opaque const value, maybe a TObject or any pointer


1.4.15. TOnObjectCompare

TOnObjectCompare = function(A, B: TObject): integer;

Event used by TSynObjectListSorted to compare its instances


1.4.16. TOnValueGreater

TOnValueGreater = function(IndexA, IndexB: PtrInt): boolean of object;

Comparison function as expected by MedianQuickSelect()
- should return TRUE if Values[IndexA]>Values[IndexB]


1.4.17. TPersistentWithCustomCreateClass

TPersistentWithCustomCreateClass = class of TPersistentWithCustomCreate;

Used to determine the exact class type of a TPersistentWithCustomCreateClass
- could be used to create instances using its virtual constructor


1.4.18. TRadixTreeNodeClass

TRadixTreeNodeClass = class of TRadixTreeNode;

Our TRadixTree works on dynamic/custom types of node classes


1.4.19. TRadixTreeNodeFlags

TRadixTreeNodeFlags = set of ( rtfParam, rtfParamInteger, rtfParamPath);

Refine the TRadixTreeNode content
- rtfParam is <param> node, i.e. a TRadixTreeNodeParams with Names <> nil
- rtfParamInteger is for a rtfParam which value should be only an integer, either from rtoIntegerParams global flag, or individually as <int:###>
- rtfParamPath is for a rtfParam which value should be the whole path, until the end of the URI or the beginning of the parameters (i.e. at '?'), set individually as <path:###> parameter - * being synonymous to <path:path>


1.4.20. TRadixTreeOptions

TRadixTreeOptions = set of ( rtoCaseInsensitiveUri, rtoIntegerParams);

Allow to customize TRadixTree process
- e.g. if static text matching should be case-insensitive (but <params> are always case-sensitive, because they are user-specific runtime variables)
- if <param> values should be only plain integers, never alphabetical text - you may also specify int:xxx for a single parameter, e.g. as <int:id>


1.4.21. TRawUtf8ListFlags

TRawUtf8ListFlags = set of ( fObjectsOwned, fCaseSensitive, fNoDuplicate, fOnChangeTrigerred, fThreadSafe);

Possible values used by TRawUtf8List.Flags


1.4.22. TRttiBinaryLoad

TRttiBinaryLoad = function(Data: pointer; var Source: TFastReader; Info: PRttiInfo): PtrInt;

Internal function handler for binary persistence of any RTTI type value
- i.e. the kind of functions called via RTTI_BINARYLOAD[] lookup table
- work with managed and unmanaged types
- fill Data^ from Source, returning the size in Data^ as bytes


1.4.23. TRttiBinaryLoads

TRttiBinaryLoads = array[TRttiKind] of TRttiBinaryLoad;

The type of RTTI_BINARYLOAD[] efficient lookup table


1.4.24. TRttiBinarySave

TRttiBinarySave = function(Data: pointer; Dest: TBufferWriter; Info: PRttiInfo): PtrInt;

Internal function handler for binary persistence of any RTTI type value
- i.e. the kind of functions called via RTTI_BINARYSAVE[] lookup table
- work with managed and unmanaged types
- persist Data^ into Dest, returning the size in Data^ as bytes


1.4.25. TRttiBinarySaves

TRttiBinarySaves = array[TRttiKind] of TRttiBinarySave;

The type of RTTI_BINARYSAVE[] efficient lookup table


1.4.26. TRttiCompare

TRttiCompare = function(Data1, Data2: pointer; Info: PRttiInfo; out Compared: integer): PtrInt;

Internal function handler for fast comparison of any RTTI type value
- i.e. the kind of functions called via RTTI_COMPARE[] lookup table
- work with managed and unmanaged types
- returns the size in Data1/Data2^ as bytes, and the result in Compared


1.4.27. TRttiCompares

TRttiCompares = array[TRttiKind] of TRttiCompare;

The type of RTTI_COMPARE[] efficient lookup table


1.4.28. TSynObjectListClass

TSynObjectListClass = class of TSynObjectList;

Meta-class of TSynObjectList type


1.4.29. TSynPersistentClass

TSynPersistentClass = class of TSynPersistent;

Used to determine the exact class type of a TSynPersistent


1.5. Constants implemented in the mormot.core.data unit

1.5.1. djNone

djNone = ptNone;

Deprecated TDynArrayKind enumerate mapping
- defined only for backward compatible code; use TRttiParserType instead


1.5.2. HASH_PO2

HASH_PO2 = 1 shl 18;

- and Delphi Win32 is not efficient at 64-bit multiplication, anyway use 16-bit Hash table when indexes fit in a word (array Capacity < 65535)
- to reduce memory consumption and slightly enhance CPU cache efficiency
- e.g. arrays of size 1..127 use only 256*2=512 bytes for their hash table defined for inlining bitwise division in TDynArrayHasher.HashTableIndex
- HashTableSize<=HASH_PO2 is expected to be a power of two (fast binary op); limit is set to 262,144 hash table slots (=512KB), for Capacity=131,072 items
- above this limit, a set of increasing primes is used; using a prime as hashtable modulo enhances its distribution, especially for a weak hash function
- 64-bit CPU and FPC can efficiently compute a prime reduction using Lemire algorithm, but power of two sizes still have a better practical performance for lower (and most common) content until it consumes too much memory


1.5.3. SORT_LSTRING

SORT_LSTRING: array[boolean] of TDynArraySortCompare = ( SortDynArrayAnsiString, SortDynArrayAnsiStringI);

Redirect to the proper SortDynArrayAnsiString/SortDynArrayAnsiStringI


1.6. Functions or procedures implemented in the mormot.core.data unit

Functions or proceduresDescription
AnyScanExistsFast search of a binary value position in a fixed-size array
AnyScanIndexFast search of a binary value position in a fixed-size array
BinaryCompareComparison of two arrays of values by content, using RTTI
BinaryCompareComparison of two values by content, using RTTI
BinaryEqualsCheck equality of two values by content, using RTTI
BinaryLoadUnserialize any value from BinarySave() memory buffer, using RTTI
BinaryLoadUnserialize any value from BinarySave() RawByteString, using RTTI
BinaryLoadBase64Unserialize any value from BinarySaveBase64() encoding, using RTTI
BinarySaveBinary persistence of any value using RTTI, into a TBufferWriter stream
BinarySaveBinary persistence of any value using RTTI, into a RawByteString buffer
BinarySaveBinary persistence of any value using RTTI, into a memory buffer
BinarySaveBinary persistence of any value using RTTI, into a TSynTempBuffer buffer
BinarySaveBase64Binary persistence of any value using RTTI, into a Base64-encoded text
BinarySaveBytesBinary persistence of any value using RTTI, into a TBytes buffer
BinarySaveLengthHow many bytes a BinarySave() may return
CopyAndSortInt64Copy an integer array, then sort it, low values first
CopyAndSortIntegerCopy an integer array, then sort it, low values first
CopyInt64Create a new 64-bit integer dynamic array with the values from another one
CopyIntegerCreate a new 32-bit integer dynamic array with the values from another one
DeduplicateInt64Sort and remove any 64-bit duplicated integer from Values[]
DeduplicateInt64Sort and remove any 64-bit duplicated integer from Values[]
DeduplicateInt64SortedLow-level function called by DeduplicateInt64()
DeduplicateIntegerSort and remove any 32-bit duplicated integer from Values[]
DeduplicateIntegerSort and remove any 32-bit duplicated integer from Values[]
DeduplicateIntegerSortedLow-level function called by DeduplicateInteger()
DeleteSectionDelete a whole [Section]
DeleteSectionDelete a whole [Section]
DynArrayInitialize the structure with a one-dimension dynamic array
DynArrayAddWrapper around TDynArray.Add
DynArrayCompareRaw comparison of two dynamic arrays
DynArrayDeleteWrapper around TDynArray.Delete
DynArrayEqualsCompare two dynamic arrays by calling TDynArray.Equals
DynArrayHashOneGet the hash function corresponding to a given standard array type
DynArrayLoadFill a dynamic array content from a binary serialization as saved by DynArraySave() / TDynArray.Save()
DynArrayLoadHeaderLow-level binary unserialization as saved by DynArraySave/TDynArray.Save
DynArraySaveSerialize a dynamic array content as binary, ready to be loaded by DynArrayLoad() / TDynArray.Load()
DynArraySaveRaw binary serialization of a dynamic array
DynArraySortIndexedSort any dynamic array, generating an external array of indexes
DynArraySortIndexedSort any dynamic array, via a supplied array of indexes
DynArraySortOneGet the comparison function corresponding to a given standard array type
ExcludeInt64Remove some 64-bit integer from Values[]
ExcludeIntegerRemove some 32-bit integer from Values[]
ExistsIniNameReturn TRUE if Value of UpperName does exist in P, till end of current section
ExistsIniNameValueReturn TRUE if one of the Value of UpperName exists in P, till end of current section
FindIniEntryFind a Name= Value in a [Section] of a INI RawUtf8 Content
FindIniEntryFileFind a Name= Value in a [Section] of a .INI file
FindIniEntryIntegerFind a Name= numeric Value in a [Section] of a INI RawUtf8 Content and return it as an integer, or 0 if not found
FindIniNameValueFind the Value of UpperName in P, till end of current section
FindIniNameValueIntegerFind the integer Value of UpperName in P, till end of current section
FindSectionFirstLineFind the position of the [SEARCH] section in source
FindSectionFirstLineWFind the position of the [SEARCH] section in source
FindWinAnsiIniEntryFind a Name= Value in a [Section] of a INI WinAnsi Content
GetSectionContentRetrieve the whole content of a section as a string
GetSectionContentRetrieve the whole content of a section as a string
IncludeInt64Ensure some 64-bit integer from Values[] will only contain Included[]
IncludeIntegerEnsure some 32-bit integer from Values[] will only contain Included[]
IniToObjectFill a class Instance properties from an .ini content
Int64ToUInt32Copy some Int64 values into an unsigned integer array
IsHtmlContentTypeTextualReturns TRUE if the supplied HTML Headers contains 'Content-Type: text/...', 'Content-Type: application/json' or 'Content-Type: application/xml'
IsWebSocketUpgradeSearch if the WebSocketUpgrade() header is present
MaxInt64Find the maximum 64-bit integer in Values[]
MaxIntegerFind the maximum 32-bit integer in Values[]
MedianQuickSelectCompute the median of a serie of values, using "Quickselect"
MedianQuickSelectIntegerCompute the median of an integer serie of values, using "Quickselect"
NotifySortedIntegerChangesCompares two 32-bit signed sorted integer arrays, and call event handlers to notify the corresponding modifications in an O(n) time
ObjArraySortSort any TObjArray with a given comparison function
ObjectCompareComparison of two TObject published properties, using RTTI
ObjectCompareComparison of published properties of several TObject instances, using RTTI
ObjectEqualsCase-sensitive comparison of two TObject published properties, using RTTI
ObjectEqualsICase-insensitive comparison of two TObject published properties, using RTTI
ObjectToIniSerialize a class Instance properties into an .ini content
QuickSortIndexedPUtf8CharDeprecated TRawUtf8MethodList should be replaced by a TSynDictionary sort a dynamic array of PUtf8Char items, via an external array of indexes
RecordEqualsCheck equality of two records by content
RecordLoadFill a record content from a memory buffer as saved by RecordSave()
RecordLoadFill a record content from a memory buffer as saved by RecordSave()
RecordLoadBase64Read a record content from a Base64 encoded content
RecordSaveSave a record content into a RawByteString
RecordSaveSave a record content into a destination memory buffer
RecordSaveSave a record content into a destination memory buffer
RecordSaveSave a record content into a destination memory buffer
RecordSaveBase64Save a record content into a Base64 encoded UTF-8 text content
RecordSaveBytesSave a record content into a TBytes dynamic array
RecordSaveLengthCompute the number of bytes needed to save a record content using the RecordSave() function
ReplaceSectionReplace a whole [Section] content by a new content
ReplaceSectionReplace a whole [Section] content by a new content
ReverseFill already allocated Reversed[] so that Reversed[Values[i]]=i
SumIntegerSum all 32-bit integers in Values[]
UpdateIniEntryUpdate a Name= Value in a [Section] of a INI RawUtf8 Content
UpdateIniEntryFileUpdate a Name= Value in a [Section] of a .INI file
UpdateIniNameValueReplace a value from a given set of name=value lines
VariantHashCrc32c-based hash of a variant value
_BC_SQWordSome low-level comparison methods used by mormot.core.json

1.6.1. AnyScanExists

function AnyScanExists(P, V: pointer; Count, VSize: PtrInt): boolean;

Fast search of a binary value position in a fixed-size array
- Count is the number of entries in P^[]


1.6.2. AnyScanIndex

function AnyScanIndex(P, V: pointer; Count, VSize: PtrInt): PtrInt;

Fast search of a binary value position in a fixed-size array
- Count is the number of entries in P^[]
- return index of P^[index]=V^, comparing VSize bytes
- return -1 if Value was not found


1.6.3. BinaryCompare

function BinaryCompare(A, B: pointer; Info: PRttiInfo; CaseInSensitive: boolean): integer; overload;

Comparison of two values by content, using RTTI


1.6.4. BinaryCompare

function BinaryCompare(A, B: pointer; Info: PRttiInfo; Count: PtrInt; CaseInSensitive: boolean): integer; overload;

Comparison of two arrays of values by content, using RTTI


1.6.5. BinaryEquals

function BinaryEquals(A, B: pointer; Info: PRttiInfo; PSize: PInteger; Kinds: TRttiKinds; CaseInSensitive: boolean): boolean;

Check equality of two values by content, using RTTI
- optionally returns the known in-memory PSize of the value


1.6.6. BinaryLoad

function BinaryLoad(Data: pointer; const Source: RawByteString; Info: PRttiInfo; Kinds: TRttiKinds; TryCustomVariants: PDocVariantOptions = nil): boolean; overload;

Unserialize any value from BinarySave() RawByteString, using RTTI


1.6.7. BinaryLoad

function BinaryLoad(Data: pointer; Source: PAnsiChar; Info: PRttiInfo; Len: PInteger; SourceMax: PAnsiChar; Kinds: TRttiKinds; TryCustomVariants: PDocVariantOptions = nil): PAnsiChar; overload;

Unserialize any value from BinarySave() memory buffer, using RTTI


1.6.8. BinaryLoadBase64

function BinaryLoadBase64(Source: PAnsiChar; Len: PtrInt; Data: pointer; Info: PRttiInfo; UriCompatible: boolean; Kinds: TRttiKinds; WithCrc: boolean = true; TryCustomVariants: PDocVariantOptions = nil): boolean;

Unserialize any value from BinarySaveBase64() encoding, using RTTI
- optionally contains a trailing crc32c hash before the actual data


1.6.9. BinarySave

function BinarySave(Data: pointer; Dest: PAnsiChar; Info: PRttiInfo; out Len: integer; Kinds: TRttiKinds): PAnsiChar; overload; deprecated;

Binary persistence of any value using RTTI, into a memory buffer
- deprecated function - use overloaded BinarySave() functions instead


1.6.10. BinarySave

procedure BinarySave(Data: pointer; var Dest: TSynTempBuffer; Info: PRttiInfo; Kinds: TRttiKinds; WithCrc: boolean = false); overload;

Binary persistence of any value using RTTI, into a TSynTempBuffer buffer


1.6.11. BinarySave

procedure BinarySave(Data: pointer; Info: PRttiInfo; Dest: TBufferWriter); overload;

Binary persistence of any value using RTTI, into a TBufferWriter stream


1.6.12. BinarySave

function BinarySave(Data: pointer; Info: PRttiInfo; Kinds: TRttiKinds; WithCrc: boolean = false): RawByteString; overload;

Binary persistence of any value using RTTI, into a RawByteString buffer


1.6.13. BinarySaveBase64

function BinarySaveBase64(Data: pointer; Info: PRttiInfo; UriCompatible: boolean; Kinds: TRttiKinds; WithCrc: boolean = true): RawUtf8;

Binary persistence of any value using RTTI, into a Base64-encoded text
- contains a trailing crc32c hash before the actual data


1.6.14. BinarySaveBytes

function BinarySaveBytes(Data: pointer; Info: PRttiInfo; Kinds: TRttiKinds): TBytes;

Binary persistence of any value using RTTI, into a TBytes buffer


1.6.15. BinarySaveLength

function BinarySaveLength(Data: pointer; Info: PRttiInfo; Len: PInteger; Kinds: TRttiKinds): integer; deprecated;

How many bytes a BinarySave() may return
- deprecated function - use overloaded BinarySave() functions instead


1.6.16. CopyAndSortInt64

procedure CopyAndSortInt64(Values: PInt64Array; ValuesCount: integer; var Dest: TInt64DynArray);

Copy an integer array, then sort it, low values first


1.6.17. CopyAndSortInteger

procedure CopyAndSortInteger(Values: PIntegerArray; ValuesCount: integer; var Dest: TIntegerDynArray);

Copy an integer array, then sort it, low values first


1.6.18. CopyInt64

procedure CopyInt64(const Source: TInt64DynArray; out Dest: TInt64DynArray);

Create a new 64-bit integer dynamic array with the values from another one


1.6.19. CopyInteger

procedure CopyInteger(const Source: TIntegerDynArray; out Dest: TIntegerDynArray);

Create a new 32-bit integer dynamic array with the values from another one


1.6.20. DeduplicateInt64

function DeduplicateInt64(var Values: TInt64DynArray; Count: PtrInt): PtrInt; overload;

Sort and remove any 64-bit duplicated integer from Values[]
- returns the new Values[] length


1.6.21. DeduplicateInt64

procedure DeduplicateInt64(var Values: TInt64DynArray); overload;

Sort and remove any 64-bit duplicated integer from Values[]


1.6.22. DeduplicateInt64Sorted

function DeduplicateInt64Sorted(val: PInt64Array; last: PtrInt): PtrInt;

Low-level function called by DeduplicateInt64()
- warning: caller should ensure that last>0


1.6.23. DeduplicateInteger

function DeduplicateInteger(var Values: TIntegerDynArray; Count: PtrInt): PtrInt; overload;

Sort and remove any 32-bit duplicated integer from Values[]
- returns the new Values[] length


1.6.24. DeduplicateInteger

procedure DeduplicateInteger(var Values: TIntegerDynArray); overload;

Sort and remove any 32-bit duplicated integer from Values[]


1.6.25. DeduplicateIntegerSorted

function DeduplicateIntegerSorted(val: PIntegerArray; last: PtrInt): PtrInt;

Low-level function called by DeduplicateInteger()


1.6.26. DeleteSection

function DeleteSection(SectionFirstLine: PUtf8Char; var Content: RawUtf8; EraseSectionHeader: boolean = true): boolean; overload;

Delete a whole [Section]
- if EraseSectionHeader is TRUE (default), then the [Section] line is also deleted together with its content lines
- return TRUE if something was changed in Content
- return FALSE if [Section] doesn't exist or is already void
- SectionFirstLine may have been obtained by FindSectionFirstLine() function above


1.6.27. DeleteSection

function DeleteSection(var Content: RawUtf8; const SectionName: RawUtf8; EraseSectionHeader: boolean = true): boolean; overload;

Delete a whole [Section]
- if EraseSectionHeader is TRUE (default), then the [Section] line is also deleted together with its content lines
- return TRUE if something was changed in Content
- return FALSE if [Section] doesn't exist or is already void


1.6.28. DynArray

function DynArray(aTypeInfo: PRttiInfo; var aValue; aCountPointer: PInteger = nil): TDynArray;

Initialize the structure with a one-dimension dynamic array
- the dynamic array must have been defined with its own type (e.g. TIntegerDynArray = array of integer)
- if aCountPointer is set, it will be used instead of length() to store the dynamic array items count - it will be much faster when adding elements to the array, because the dynamic array won't need to be resized each time - but in this case, you should use the Count property instead of length(array) or high(array) when accessing the data: in fact length(array) will store the memory size reserved, not the items count
- if aCountPointer is set, its content will be set to 0, whatever the array length is, or the current aCountPointer^ value is
- a typical usage could be:

var
  IntArray: TIntegerDynArray;
begin
  with DynArray(TypeInfo(TIntegerDynArray), IntArray) do
  begin
    (...)
  end;
 (...)
 bin := DynArray(TypeInfo(TIntegerDynArray), IntArray).SaveTo;

1.6.29. DynArrayAdd

function DynArrayAdd(TypeInfo: PRttiInfo; var DynArray; const Item): integer; overload;

Wrapper around TDynArray.Add
- warning: the Item type is not checked at runtime, so should be as expected
- not very fast, but could be useful for simple code


1.6.30. DynArrayCompare

function DynArrayCompare(A, B: PAnsiChar; ExternalCountA, ExternalCountB: PInteger; Info: PRttiInfo; CaseInSensitive: boolean): integer; overload;

Raw comparison of two dynamic arrays
- as called e.g. by TDynArray.Equals, using ExternalCountA/B optional parameter
- RTTI_COMPARE[true/false,rkDynArray] are wrappers to this, with ExternalCount=nil
- if Info=TypeInfo(TObjectDynArray) then will compare any T*ObjArray


1.6.31. DynArrayDelete

function DynArrayDelete(TypeInfo: PRttiInfo; var DynArray; Index: PtrInt): boolean; overload;

Wrapper around TDynArray.Delete
- not very fast, but could be useful for simple code


1.6.32. DynArrayEquals

function DynArrayEquals(TypeInfo: PRttiInfo; var Array1, Array2; Array1Count: PInteger = nil; Array2Count: PInteger = nil; CaseInsensitive: boolean = false): boolean;

Compare two dynamic arrays by calling TDynArray.Equals
- if Info=TypeInfo(TObjectDynArray) then will compare any T*ObjArray


1.6.33. DynArrayHashOne

function DynArrayHashOne(Kind: TRttiParserType; CaseInsensitive: boolean = false): TDynArrayHashOne;

Get the hash function corresponding to a given standard array type
- as used internally by TDynArrayHasher.Init and exported here for testing


1.6.34. DynArrayLoad

function DynArrayLoad(var Value; Source: PAnsiChar; TypeInfo: PRttiInfo; TryCustomVariants: PDocVariantOptions = nil; SourceMax: PAnsiChar = nil): PAnsiChar;

Fill a dynamic array content from a binary serialization as saved by DynArraySave() / TDynArray.Save()
- Value shall be set to the target dynamic array field
- is a wrapper around BinaryLoad(rkDynArray)


1.6.35. DynArrayLoadHeader

function DynArrayLoadHeader(var Source: TFastReader; ArrayInfo, ItemInfo: PRttiInfo): integer;

Low-level binary unserialization as saved by DynArraySave/TDynArray.Save
- as used by DynArrayLoad() and TDynArrayLoadFrom
- returns the stored length() of the dynamic array, and Source points to the stored binary data itself


1.6.36. DynArraySave

procedure DynArraySave(Data: PAnsiChar; ExternalCount: PInteger; Dest: TBufferWriter; Info: PRttiInfo); overload;

Raw binary serialization of a dynamic array
- as called e.g. by TDynArray.SaveTo, using ExternalCount optional parameter
- RTTI_BINARYSAVE[rkDynArray] is a wrapper to this function, with ExternalCount=nil


1.6.37. DynArraySave

function DynArraySave(var Value; TypeInfo: PRttiInfo): RawByteString; overload;

Serialize a dynamic array content as binary, ready to be loaded by DynArrayLoad() / TDynArray.Load()
- Value shall be set to the source dynamic arry field
- is a wrapper around BinarySave(rkDynArray)


1.6.38. DynArraySortIndexed

procedure DynArraySortIndexed(Values: pointer; ItemSize, Count: integer; Indexes: PCardinalArray; Compare: TDynArraySortCompare); overload;

Sort any dynamic array, via a supplied array of indexes
- this function expects Indexes[] to be already allocated and filled


1.6.39. DynArraySortIndexed

procedure DynArraySortIndexed(Values: pointer; ItemSize, Count: integer; out Indexes: TSynTempBuffer; Compare: TDynArraySortCompare); overload;

Sort any dynamic array, generating an external array of indexes
- this function will use the supplied TSynTempBuffer for index storage, so use PIntegerArray(Indexes.buf) to access the values
- caller should always make Indexes.Done once finshed


1.6.40. DynArraySortOne

function DynArraySortOne(Kind: TRttiParserType; CaseInsensitive: boolean): TDynArraySortCompare;

Get the comparison function corresponding to a given standard array type
- as used e.g. internally by TDynArray


1.6.41. ExcludeInt64

procedure ExcludeInt64(var Values, Excluded: TInt64DynArray; ExcludedSortSize: integer = 32);

Remove some 64-bit integer from Values[]
- Excluded is declared as var, since it will be sorted in-place during process if it contains more than ExcludedSortSize items (i.e. if the sort is worth it)


1.6.42. ExcludeInteger

procedure ExcludeInteger(var Values, Excluded: TIntegerDynArray; ExcludedSortSize: integer = 32);

Remove some 32-bit integer from Values[]
- Excluded is declared as var, since it will be sorted in-place during process if it contains more than ExcludedSortSize items (i.e. if the sort is worth it)


1.6.43. ExistsIniName

function ExistsIniName(P: PUtf8Char; UpperName: PAnsiChar): boolean;

Return TRUE if Value of UpperName does exist in P, till end of current section
- expect UpperName as 'NAME='


1.6.44. ExistsIniNameValue

function ExistsIniNameValue(P: PUtf8Char; const UpperName: RawUtf8; UpperValues: PPAnsiChar): boolean;

Return TRUE if one of the Value of UpperName exists in P, till end of current section
- expect UpperName e.g. as 'CONTENT-TYPE: '
- expect UpperValues to be an array of upper values with left side matching, and ending with nil - as expected by IdemPPChar(), i.e. with at least 2 chars


1.6.45. FindIniEntry

function FindIniEntry(const Content, Section, Name: RawUtf8; const DefaultValue: RawUtf8 = ''): RawUtf8;

Find a Name= Value in a [Section] of a INI RawUtf8 Content
- this function scans the Content memory buffer, and is therefore very fast (no temporary TMemIniFile is created)
- if Section equals '', find the Name= value before any [Section]


1.6.46. FindIniEntryFile

function FindIniEntryFile(const FileName: TFileName; const Section, Name: RawUtf8; const DefaultValue: RawUtf8 = ''): RawUtf8;

Find a Name= Value in a [Section] of a .INI file
- if Section equals '', find the Name= value before any [Section]
- use internally fast FindIniEntry() function above


1.6.47. FindIniEntryInteger

function FindIniEntryInteger(const Content, Section, Name: RawUtf8): integer;

Find a Name= numeric Value in a [Section] of a INI RawUtf8 Content and return it as an integer, or 0 if not found
- this function scans the Content memory buffer, and is therefore very fast (no temporary TMemIniFile is created)
- if Section equals '', find the Name= value before any [Section]


1.6.48. FindIniNameValue

function FindIniNameValue(P: PUtf8Char; UpperName: PAnsiChar; const DefaultValue: RawUtf8 = ''): RawUtf8;

Find the Value of UpperName in P, till end of current section
- expect UpperName as 'NAME='


1.6.49. FindIniNameValueInteger

function FindIniNameValueInteger(P: PUtf8Char; const UpperName: RawUtf8): PtrInt;

Find the integer Value of UpperName in P, till end of current section
- expect UpperName as 'NAME='
- return 0 if no NAME= entry was found


1.6.50. FindSectionFirstLine

function FindSectionFirstLine(var source: PUtf8Char; search: PAnsiChar): boolean;

Find the position of the [SEARCH] section in source
- return true if [SEARCH] was found, and store pointer to the line after it in source


1.6.51. FindSectionFirstLineW

function FindSectionFirstLineW(var source: PWideChar; search: PUtf8Char): boolean;

Find the position of the [SEARCH] section in source
- return true if [SEARCH] was found, and store pointer to the line after it in source
- this version expects source^ to point to an Unicode char array


1.6.52. FindWinAnsiIniEntry

function FindWinAnsiIniEntry(const Content, Section, Name: RawUtf8): RawUtf8;

Find a Name= Value in a [Section] of a INI WinAnsi Content
- same as FindIniEntry(), but the value is converted from WinAnsi into UTF-8


1.6.53. GetSectionContent

function GetSectionContent(SectionFirstLine: PUtf8Char): RawUtf8; overload;

Retrieve the whole content of a section as a string
- SectionFirstLine may have been obtained by FindSectionFirstLine() function above


1.6.54. GetSectionContent

function GetSectionContent(const Content, SectionName: RawUtf8): RawUtf8; overload;

Retrieve the whole content of a section as a string
- use SectionFirstLine() then previous GetSectionContent()


1.6.55. IncludeInt64

procedure IncludeInt64(var Values, Included: TInt64DynArray; IncludedSortSize: integer = 32);

Ensure some 64-bit integer from Values[] will only contain Included[]
- Included is declared as var, since it will be sorted in-place during process if it contains more than IncludedSortSize items (i.e. if the sort is worth it)


1.6.56. IncludeInteger

procedure IncludeInteger(var Values, Included: TIntegerDynArray; IncludedSortSize: integer = 32);

Ensure some 32-bit integer from Values[] will only contain Included[]
- Included is declared as var, since it will be sorted in-place during process if it contains more than IncludedSortSize items (i.e. if the sort is worth it)


1.6.57. IniToObject

function IniToObject(const Ini: RawUtf8; Instance: TObject; const SectionName: RawUtf8 = 'Main'; DocVariantOptions: PDocVariantOptions = nil; Level: integer = 0): boolean;

Fill a class Instance properties from an .ini content
- the class property fields are searched in the supplied main SectionName
- nested objects and multi-line text values are searched in their own section, named from their section level and property (e.g. [mainprop.nested1.nested2])
- returns true if at least one property has been identified


1.6.58. Int64ToUInt32

procedure Int64ToUInt32(Values64: PInt64Array; Values32: PCardinalArray; Count: PtrInt);

Copy some Int64 values into an unsigned integer array


1.6.59. IsHtmlContentTypeTextual

function IsHtmlContentTypeTextual(Headers: PUtf8Char): boolean;

Returns TRUE if the supplied HTML Headers contains 'Content-Type: text/...', 'Content-Type: application/json' or 'Content-Type: application/xml'


1.6.60. IsWebSocketUpgrade

function IsWebSocketUpgrade(headers: PUtf8Char): boolean;

Search if the WebSocketUpgrade() header is present
- consider checking the hsrConnectionUpgrade flag instead


1.6.61. MaxInt64

function MaxInt64(const Values: TInt64DynArray; ValuesCount: PtrInt; MaxStart: Int64 = -1): Int64;

Find the maximum 64-bit integer in Values[]


1.6.62. MaxInteger

function MaxInteger(const Values: TIntegerDynArray; ValuesCount: PtrInt; MaxStart: integer = -1): integer;

Find the maximum 32-bit integer in Values[]


1.6.63. MedianQuickSelect

function MedianQuickSelect(const OnCompare: TOnValueGreater; n: integer; var TempBuffer: TSynTempBuffer): integer;

Compute the median of a serie of values, using "Quickselect"
- based on the algorithm described in "Numerical recipes in C", Second Edition
- expect the values information to be available from a comparison callback
- this version will use a temporary index list to exchange items order (supplied as a TSynTempBuffer), so won't change the supplied values themself
- see also function MedianQuickSelectInteger() for PIntegerArray values
- returns the index of the median Value


1.6.64. MedianQuickSelectInteger

function MedianQuickSelectInteger(Values: PIntegerArray; n: integer): integer;

Compute the median of an integer serie of values, using "Quickselect"
- based on the algorithm described in "Numerical recipes in C", Second Edition, translated from Nicolas Devillard's C code: http://ndevilla.free.fr/median/median
- warning: the supplied integer array is modified in-place during the process, and won't be fully sorted on output (this is no QuickSort alternative)


1.6.65. NotifySortedIntegerChanges

procedure NotifySortedIntegerChanges(old, new: PIntegerArray; oldn, newn: PtrInt; const added, deleted: TOnNotifySortedIntegerChange; const sender);

Compares two 32-bit signed sorted integer arrays, and call event handlers to notify the corresponding modifications in an O(n) time
- items in both old[] and new[] arrays are required to be sorted


1.6.66. ObjArraySort

procedure ObjArraySort(var aValue; Compare: TDynArraySortCompare; CountPointer: PInteger = nil);

Sort any TObjArray with a given comparison function


1.6.67. ObjectCompare

function ObjectCompare(A, B: PObject; Count: PtrInt; CaseInsensitive: boolean = false): integer; overload;

Comparison of published properties of several TObject instances, using RTTI


1.6.68. ObjectCompare

function ObjectCompare(A, B: TObject; CaseInSensitive: boolean): integer; overload;

Comparison of two TObject published properties, using RTTI


1.6.69. ObjectEquals

function ObjectEquals(A, B: TObject): boolean;

Case-sensitive comparison of two TObject published properties, using RTTI


1.6.70. ObjectEqualsI

function ObjectEqualsI(A, B: TObject): boolean;

Case-insensitive comparison of two TObject published properties, using RTTI


1.6.71. ObjectToIni

function ObjectToIni(const Instance: TObject; const SectionName: RawUtf8 = 'Main'; Options: TTextWriterWriteObjectOptions = [woEnumSetsAsText, woRawBlobAsBase64, woHumanReadableEnumSetAsComment]; Level: integer = 0): RawUtf8;

Serialize a class Instance properties into an .ini content
- the class property fields are written in the supplied main SectionName
- nested objects and multi-line text values are written in their own section, named from their section level and property (e.g. [mainprop.nested1.nested2])


1.6.72. QuickSortIndexedPUtf8Char

procedure QuickSortIndexedPUtf8Char(Values: PPUtf8CharArray; Count: integer; var SortedIndexes: TCardinalDynArray; CaseSensitive: boolean = false);

Deprecated TRawUtf8MethodList should be replaced by a TSynDictionary sort a dynamic array of PUtf8Char items, via an external array of indexes
- you can use FastFindIndexedPUtf8Char() for fast O(log(n)) binary search


1.6.73. RecordEquals

function RecordEquals(const RecA, RecB; TypeInfo: PRttiInfo; PRecSize: PInteger = nil; CaseInSensitive: boolean = false): boolean;

Check equality of two records by content
- will handle packed records, with binaries (byte, word, integer...) and string types properties
- will use binary-level comparison: it could fail to match two floating-point values because of rounding issues (Currency won't have this problem)
- is a wrapper around BinaryEquals(rkRecordTypes)


1.6.74. RecordLoad

function RecordLoad(var Rec; Source: PAnsiChar; TypeInfo: PRttiInfo; Len: PInteger = nil; SourceMax: PAnsiChar = nil; TryCustomVariants: PDocVariantOptions = nil): PAnsiChar; overload;

Fill a record content from a memory buffer as saved by RecordSave()
- return nil if the Source buffer is incorrect
- in case of success, return the memory buffer pointer just after the read content, and set the Rec size, in bytes, into Len reference variable
- will use a proprietary binary format, with some variable-length encoding of the string length - note that if you change the type definition, any previously-serialized content will fail, maybe triggering unexpected GPF: you may use TypeInfoToHash() if you share this binary data accross executables
- you should provide in SourceMax the first byte after the Source memory buffer, which will be used to avoid any unexpected buffer overflow - clearly mandatory when decoding the content from any external process (e.g. a maybe-forged client) - with no performance penalty
- is a wrapper around BinaryLoad(rkRecordTypes)


1.6.75. RecordLoad

function RecordLoad(var Rec; const Source: RawByteString; TypeInfo: PRttiInfo; TryCustomVariants: PDocVariantOptions = nil): boolean; overload;

Fill a record content from a memory buffer as saved by RecordSave()
- will use the Source length to detect and avoid any buffer overlow
- returns false if the Source buffer was incorrect, true on success
- is a wrapper around BinaryLoad(rkRecordTypes)


1.6.76. RecordLoadBase64

function RecordLoadBase64(Source: PAnsiChar; Len: PtrInt; var Rec; TypeInfo: PRttiInfo; UriCompatible: boolean = false; TryCustomVariants: PDocVariantOptions = nil): boolean;

Read a record content from a Base64 encoded content
- expects RecordSaveBase64() format, with a left-sided binary CRC32C
- is a wrapper around BinaryLoadBase64(rkRecordTypes)


1.6.77. RecordSave

procedure RecordSave(const Rec; var Dest: TSynTempBuffer; TypeInfo: PRttiInfo); overload;

Save a record content into a destination memory buffer
- caller should make Dest.Done once finished with Dest.buf/Dest.len buffer
- is a wrapper around BinarySave(rkRecordTypes)


1.6.78. RecordSave

function RecordSave(const Rec; Dest: PAnsiChar; TypeInfo: PRttiInfo; out Len: integer): PAnsiChar; overload; deprecated;

Save a record content into a destination memory buffer
- Dest must be at least RecordSaveLength() bytes long
- deprecated function - use overloaded BinarySave() functions instead


1.6.79. RecordSave

function RecordSave(const Rec; TypeInfo: PRttiInfo): RawByteString; overload;

Save a record content into a RawByteString
- will handle packed records, with binaries (byte, word, integer...) and string types properties (but not with internal raw pointers, of course)
- will use a proprietary binary format, with some variable-length encoding of the string length - note that if you change the type definition, any previously-serialized content will fail, maybe triggering unexpected GPF: you may use TypeInfoToHash() if you share this binary data accross executables
- warning: will encode RTL string fields as AnsiString (one byte per char) prior to Delphi 2009, and as UnicodeString (two bytes per char) since Delphi 2009: if you want to use this function between UNICODE and NOT UNICODE versions of Delphi, you should use some explicit types like RawUtf8, WinAnsiString, SynUnicode or even RawUnicode/WideString
- is a wrapper around BinarySave(rkRecordTypes)


1.6.80. RecordSave

function RecordSave(const Rec; Dest: PAnsiChar; TypeInfo: PRttiInfo): PAnsiChar; overload; deprecated;

Save a record content into a destination memory buffer
- Dest must be at least RecordSaveLength() bytes long
- deprecated function - use overloaded BinarySave() functions instead


1.6.81. RecordSaveBase64

function RecordSaveBase64(const Rec; TypeInfo: PRttiInfo; UriCompatible: boolean = false): RawUtf8;

Save a record content into a Base64 encoded UTF-8 text content
- will use RecordSave() format, with a left-sided binary CRC
- is a wrapper around BinarySaveBase64(rkRecordTypes)


1.6.82. RecordSaveBytes

function RecordSaveBytes(const Rec; TypeInfo: PRttiInfo): TBytes;

Save a record content into a TBytes dynamic array
- could be used as an alternative to RawByteString's RecordSave()
- is a wrapper around BinarySaveBytes(rkRecordTypes)


1.6.83. RecordSaveLength

function RecordSaveLength(const Rec; TypeInfo: PRttiInfo; Len: PInteger = nil): integer; deprecated;

Compute the number of bytes needed to save a record content using the RecordSave() function
- deprecated function - use overloaded BinarySave() functions instead


1.6.84. ReplaceSection

procedure ReplaceSection(SectionFirstLine: PUtf8Char; var Content: RawUtf8; const NewSectionContent: RawUtf8); overload;

Replace a whole [Section] content by a new content
- create a new [Section] if none was existing
- SectionFirstLine may have been obtained by FindSectionFirstLine() function above


1.6.85. ReplaceSection

procedure ReplaceSection(var Content: RawUtf8; const SectionName, NewSectionContent: RawUtf8); overload;

Replace a whole [Section] content by a new content
- create a new [Section] if none was existing


1.6.86. Reverse

procedure Reverse(const Values: TIntegerDynArray; ValuesCount: PtrInt; Reversed: PIntegerArray);

Fill already allocated Reversed[] so that Reversed[Values[i]]=i


1.6.87. SumInteger

function SumInteger(const Values: TIntegerDynArray; ValuesCount: PtrInt): integer;

Sum all 32-bit integers in Values[]


1.6.88. UpdateIniEntry

procedure UpdateIniEntry(var Content: RawUtf8; const Section, Name, Value: RawUtf8);

Update a Name= Value in a [Section] of a INI RawUtf8 Content
- this function scans and update the Content memory buffer, and is therefore very fast (no temporary TMemIniFile is created)
- if Section equals '', update the Name= value before any [Section]


1.6.89. UpdateIniEntryFile

procedure UpdateIniEntryFile(const FileName: TFileName; const Section, Name, Value: RawUtf8);

Update a Name= Value in a [Section] of a .INI file
- if Section equals '', update the Name= value before any [Section]
- use internally fast UpdateIniEntry() function above


1.6.90. UpdateIniNameValue

function UpdateIniNameValue(var Content: RawUtf8; const Name, UpperName, NewValue: RawUtf8): boolean;

Replace a value from a given set of name=value lines
- expect UpperName as 'UPPERNAME=', otherwise returns false
- if no UPPERNAME= entry was found, then Name+NewValue is added to Content
- a typical use may be:

 UpdateIniNameValue(headers,HEADER_CONTENT_TYPE,HEADER_CONTENT_TYPE_UPPER,contenttype);

1.6.91. VariantHash

function VariantHash(const value: variant; CaseInsensitive: boolean; Hasher: THasher = nil): cardinal;

Crc32c-based hash of a variant value
- complex string types will make up to 255 uppercase characters conversion if CaseInsensitive is true
- you can specify your own hashing function if crc32c is not what you expect


1.6.92. _BC_SQWord

function _BC_SQWord(A, B: PInt64; Info: PRttiInfo; out Compared: integer): PtrInt;

Some low-level comparison methods used by mormot.core.json


1.7. Variables implemented in the mormot.core.data unit

1.7.1. GetDataFromJson

GetDataFromJson: procedure(Data: pointer; var Json: PUtf8Char; EndOfObject: PUtf8Char; Rtti: TRttiCustom; CustomVariantOptions: PDocVariantOptions; Tolerant: boolean; Interning: TRawUtf8InterningAbstract);

Low-level JSON unserialization function
- defined in this unit to avoid circular reference with mormot.core.json, but to publish the TDynArray.LoadFromJson overloaded methods
- this unit will just set a wrapper raising an ERttiException
- link mormot.core.json.pas to have a working implementation
- rather call LoadJson() from mormot.core.json than this low-level function


1.7.2. RTTI_BINARYLOAD

RTTI_BINARYLOAD: TRttiBinaryLoads;

Lookup table for binary persistence of any RTTI type value
- for efficient retrieval from binary of managed and unmanaged types


1.7.3. RTTI_BINARYSAVE

RTTI_BINARYSAVE: TRttiBinarySaves;

Lookup table for binary persistence of any RTTI type value
- for efficient persistence into binary of managed and unmanaged types


1.7.4. RTTI_COMPARE

RTTI_COMPARE: TRttiComparers;

Lookup table for comparison of any RTTI type value
- for efficient search or sorting of managed and unmanaged types
- RTTI_COMPARE[false] for case-sensitive comparison
- RTTI_COMPARE[true] for case-insensitive comparison


1.7.5. RTTI_FLOAT_COMPARE

RTTI_FLOAT_COMPARE: array[TRttiFloat] of TRttiCompare;

Lookup table for comparison of floating-point RTTI type values
- slightly faster alternative to RTTI_COMPARE[rkFloat]


1.7.6. RTTI_ORD_COMPARE

RTTI_ORD_COMPARE: array[TRttiOrd] of TRttiCompare;

Lookup table for comparison of ordinal RTTI type values
- slightly faster alternative to RTTI_COMPARE[rkOrdinalTypes]