Przeglądaj źródła

Fix for Mantis #27206. *Finally* add Maciej Izak's contribution of the Delphi compatible generic collections.
Two small changes were done:
* Generics.Defaults.pas does not require the Contnrs unit (it wasn't used anyway and thus the units can be added as rtl-generics instead of fcl-generics)
* the example files were changed to lowercase filenames

git-svn-id: trunk@34229 -

svenbarth 9 lat temu
rodzic
commit
3596809ab4
32 zmienionych plików z 12634 dodań i 0 usunięć
  1. 29 0
      .gitattributes
  2. 1 0
      packages/fpmake_add.inc
  3. 2 0
      packages/fpmake_proc.inc
  4. 2486 0
      packages/rtl-generics/Makefile
  5. 102 0
      packages/rtl-generics/Makefile.fpc
  6. 66 0
      packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpi
  7. 91 0
      packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpr
  8. 71 0
      packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpi
  9. 111 0
      packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpr
  10. 66 0
      packages/rtl-generics/examples/tcomparer/tcomparerproject.lpi
  11. 124 0
      packages/rtl-generics/examples/tcomparer/tcomparerproject.lpr
  12. 71 0
      packages/rtl-generics/examples/thashmap/thashmapproject.lpi
  13. 218 0
      packages/rtl-generics/examples/thashmap/thashmapproject.lpr
  14. 66 0
      packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpi
  15. 55 0
      packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpr
  16. 66 0
      packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpi
  17. 108 0
      packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpr
  18. 66 0
      packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpi
  19. 194 0
      packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpr
  20. 66 0
      packages/rtl-generics/examples/tqueue/tqueueproject.lpi
  21. 89 0
      packages/rtl-generics/examples/tqueue/tqueueproject.lpr
  22. 66 0
      packages/rtl-generics/examples/tstack/tstackproject.lpi
  23. 86 0
      packages/rtl-generics/examples/tstack/tstackproject.lpr
  24. 78 0
      packages/rtl-generics/fpmake.pp
  25. 1265 0
      packages/rtl-generics/src/generics.collections.pas
  26. 3270 0
      packages/rtl-generics/src/generics.defaults.pas
  27. 915 0
      packages/rtl-generics/src/generics.hashes.pas
  28. 144 0
      packages/rtl-generics/src/generics.helpers.pas
  29. 236 0
      packages/rtl-generics/src/generics.memoryexpanders.pas
  30. 34 0
      packages/rtl-generics/src/generics.strings.pas
  31. 1859 0
      packages/rtl-generics/src/inc/generics.dictionaries.inc
  32. 533 0
      packages/rtl-generics/src/inc/generics.dictionariesh.inc

+ 29 - 0
.gitattributes

@@ -7091,6 +7091,35 @@ packages/rtl-extra/src/win/winsock.pp svneol=native#text/plain
 packages/rtl-extra/src/win/winsock2.pp svneol=native#text/plain
 packages/rtl-extra/src/wince/winsock.pp svneol=native#text/plain
 packages/rtl-extra/src/wince/winsock2.pp svneol=native#text/plain
+packages/rtl-generics/Makefile svneol=native#text/plain
+packages/rtl-generics/Makefile.fpc svneol=native#text/plain
+packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpi svneol=native#text/xml
+packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpi svneol=native#text/xml
+packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/tcomparer/tcomparerproject.lpi svneol=native#text/xml
+packages/rtl-generics/examples/tcomparer/tcomparerproject.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/thashmap/thashmapproject.lpi svneol=native#text/xml
+packages/rtl-generics/examples/thashmap/thashmapproject.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpi svneol=native#text/xml
+packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpi svneol=native#text/xml
+packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpi svneol=native#text/xml
+packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/tqueue/tqueueproject.lpi svneol=native#text/xml
+packages/rtl-generics/examples/tqueue/tqueueproject.lpr svneol=native#text/pascal
+packages/rtl-generics/examples/tstack/tstackproject.lpi svneol=native#text/xml
+packages/rtl-generics/examples/tstack/tstackproject.lpr svneol=native#text/pascal
+packages/rtl-generics/fpmake.pp svneol=native#text/pascal
+packages/rtl-generics/src/generics.collections.pas svneol=native#text/pascal
+packages/rtl-generics/src/generics.defaults.pas svneol=native#text/pascal
+packages/rtl-generics/src/generics.hashes.pas svneol=native#text/pascal
+packages/rtl-generics/src/generics.helpers.pas svneol=native#text/pascal
+packages/rtl-generics/src/generics.memoryexpanders.pas svneol=native#text/pascal
+packages/rtl-generics/src/generics.strings.pas svneol=native#text/pascal
+packages/rtl-generics/src/inc/generics.dictionaries.inc svneol=native#text/pascal
+packages/rtl-generics/src/inc/generics.dictionariesh.inc svneol=native#text/pascal
 packages/rtl-objpas/Makefile svneol=native#text/plain
 packages/rtl-objpas/Makefile.fpc svneol=native#text/plain
 packages/rtl-objpas/Makefile.fpc.fpcmake svneol=native#text/plain

+ 1 - 0
packages/fpmake_add.inc

@@ -104,6 +104,7 @@
   add_rexx(ADirectory+IncludeTrailingPathDelimiter('rexx'));
   add_rtl_console(ADirectory+IncludeTrailingPathDelimiter('rtl-console'));
   add_rtl_extra(ADirectory+IncludeTrailingPathDelimiter('rtl-extra'));
+  add_rtl_generics(ADirectory+IncludeTrailingPathDelimiter('rtl-generics'));
   add_rtl_objpas(ADirectory+IncludeTrailingPathDelimiter('rtl-objpas'));
   add_rtl_unicode(ADirectory+IncludeTrailingPathDelimiter('rtl-unicode'));
   add_sdl(ADirectory+IncludeTrailingPathDelimiter('sdl'));

+ 2 - 0
packages/fpmake_proc.inc

@@ -605,6 +605,8 @@ end;
 
 {$include rtl-extra/fpmake.pp}
 
+{$include rtl-generics/fpmake.pp}
+
 {$include rtl-objpas/fpmake.pp}
 
 {$include rtl-unicode/fpmake.pp}

+ 2486 - 0
packages/rtl-generics/Makefile

@@ -0,0 +1,2486 @@
+#
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2016-06-18 rev 34006]
+#
+default: all
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin
+BSDs = freebsd netbsd openbsd darwin dragonfly
+UNIXs = linux $(BSDs) solaris qnx haiku aix
+LIMIT83fs = go32v2 os2 emx watcom msdos win16
+OSNeedsComspecToRunBatch = go32v2 watcom
+FORCE:
+.PHONY: FORCE
+override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH)))
+ifneq ($(findstring darwin,$(OSTYPE)),)
+inUnix=1 #darwin
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+ifeq ($(findstring ;,$(PATH)),)
+inUnix=1
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+SEARCHPATH:=$(subst ;, ,$(PATH))
+endif
+endif
+SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE))))
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH))))
+ifeq ($(PWD),)
+$(error You need the GNU utils package to use this Makefile)
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=
+endif
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=.exe
+endif
+ifndef inUnix
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+else
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+else
+ifneq ($(findstring cygdrive,$(PATH)),)
+inCygWin=1
+endif
+endif
+ifdef inUnix
+SRCBATCHEXT=.sh
+else
+ifdef inOS2
+SRCBATCHEXT=.cmd
+else
+SRCBATCHEXT=.bat
+endif
+endif
+ifdef COMSPEC
+ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),)
+ifndef RUNBATCH
+RUNBATCH=$(COMSPEC) /C
+endif
+endif
+endif
+ifdef inUnix
+PATHSEP=/
+else
+PATHSEP:=$(subst /,\,/)
+ifdef inCygWin
+PATHSEP=/
+endif
+endif
+ifdef PWD
+BASEDIR:=$(subst \,/,$(shell $(PWD)))
+ifdef inCygWin
+ifneq ($(findstring /cygdrive/,$(BASEDIR)),)
+BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR))
+BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR)))
+BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR))
+endif
+endif
+else
+BASEDIR=.
+endif
+ifdef inOS2
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO=echo
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+endif
+override DEFAULT_FPCDIR=../..
+ifndef FPC
+ifdef PP
+FPC=$(PP)
+endif
+endif
+ifndef FPC
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+ifneq ($(CPU_TARGET),)
+FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB)
+else
+FPC:=$(shell $(FPCPROG) -PB)
+endif
+ifneq ($(findstring Error,$(FPC)),)
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+else
+ifeq ($(strip $(wildcard $(FPC))),)
+FPC:=$(firstword $(FPCPROG))
+endif
+endif
+else
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+FOUNDFPC:=$(strip $(wildcard $(FPC)))
+ifeq ($(FOUNDFPC),)
+FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))
+ifeq ($(FOUNDFPC),)
+$(error Compiler $(FPC) not found)
+endif
+endif
+ifndef FPC_COMPILERINFO
+FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+endif
+ifndef FPC_VERSION
+FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO))
+endif
+export FPC FPC_VERSION FPC_COMPILERINFO
+unexport CHECKDEPEND ALLDEPENDENCIES
+ifndef CPU_TARGET
+ifdef CPU_TARGET_DEFAULT
+CPU_TARGET=$(CPU_TARGET_DEFAULT)
+endif
+endif
+ifndef OS_TARGET
+ifdef OS_TARGET_DEFAULT
+OS_TARGET=$(OS_TARGET_DEFAULT)
+endif
+endif
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 5,$(FPC_COMPILERINFO))
+endif
+FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifeq ($(CPU_TARGET),armeb)
+ARCH=arm
+override FPCOPT+=-Cb
+else
+ifeq ($(CPU_TARGET),armel)
+ARCH=arm
+override FPCOPT+=-CaEABI
+else
+ARCH=$(CPU_TARGET)
+endif
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for arm-embedded, a sub-architecture (e.g. SUBARCH=armv4t or SUBARCH=armv7m) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for avr-embedded, a sub-architecture (e.g. SUBARCH=avr25 or SUBARCH=avr35) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),mipsel-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for mipsel-embedded, a sub-architecture (e.g. SUBARCH=pic32mx) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+SOURCESUFFIX=$(OS_SOURCE)
+else
+ifneq ($(findstring $(OS_TARGET),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+else
+TARGETSUFFIX=$(FULL_TARGET)
+endif
+SOURCESUFFIX=$(FULL_SOURCE)
+endif
+ifneq ($(FULL_TARGET),$(FULL_SOURCE))
+CROSSCOMPILE=1
+endif
+ifeq ($(findstring makefile,$(MAKECMDGOALS)),)
+ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),)
+$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first)
+endif
+endif
+ifneq ($(findstring $(OS_TARGET),$(BSDs)),)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),linux)
+linuxHier=1
+endif
+ifndef CROSSCOMPILE
+BUILDFULLNATIVE=1
+export BUILDFULLNATIVE
+endif
+ifdef BUILDFULLNATIVE
+BUILDNATIVE=1
+export BUILDNATIVE
+endif
+export OS_TARGET OS_SOURCE ARCH CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX CROSSCOMPILE
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+else
+override FPCDIR=wrong
+endif
+ifdef DEFAULT_FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+endif
+endif
+ifeq ($(FPCDIR),wrong)
+ifdef inUnix
+override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=/usr/lib/fpc/$(FPC_VERSION)
+endif
+else
+override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))))
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(BASEDIR)
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX))
+endif
+ifneq ($(findstring $(OS_TARGET),darwin iphonesim),)
+ifeq ($(OS_SOURCE),darwin)
+DARWIN2DARWIN=1
+endif
+endif
+ifndef BINUTILSPREFIX
+ifndef CROSSBINDIR
+ifdef CROSSCOMPILE
+ifneq ($(OS_TARGET),msdos)
+ifndef DARWIN2DARWIN
+ifneq ($(CPU_TARGET),jvm)
+BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)-
+ifeq ($(OS_TARGET),android)
+ifeq ($(CPU_TARGET),arm)
+BINUTILSPREFIX=arm-linux-androideabi-
+else
+ifeq ($(CPU_TARGET),i386)
+BINUTILSPREFIX=i686-linux-android-
+else
+ifeq ($(CPU_TARGET),mipsel)
+BINUTILSPREFIX=mipsel-linux-android-
+endif
+endif
+endif
+endif
+endif
+endif
+else
+BINUTILSPREFIX=$(OS_TARGET)-
+endif
+endif
+endif
+endif
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
+ifeq ($(UNITSDIR),)
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+ifndef FPCFPMAKE
+ifdef CROSSCOMPILE
+ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),)
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+FPCFPMAKE:=$(shell $(FPCPROG) -PB)
+ifeq ($(strip $(wildcard $(FPCFPMAKE))),)
+FPCFPMAKE:=$(firstword $(FPCPROG))
+endif
+else
+override FPCFPMAKE=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+else
+FPCFPMAKE=$(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR))))
+FPMAKE_SKIP_CONFIG=-n
+export FPCFPMAKE
+export FPMAKE_SKIP_CONFIG
+endif
+else
+FPMAKE_SKIP_CONFIG=-n
+FPCFPMAKE=$(FPC)
+endif
+endif
+override PACKAGE_NAME=googleapi
+override PACKAGE_VERSION=3.1.1
+FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT))
+ifdef OS_TARGET
+FPC_TARGETOPT+=--os=$(OS_TARGET)
+endif
+ifdef CPU_TARGET
+FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
+endif
+LOCALFPMAKE=./fpmake$(SRCEXEEXT)
+override INSTALL_FPCPACKAGE=y
+ifdef REQUIRE_UNITSDIR
+override UNITSDIR+=$(REQUIRE_UNITSDIR)
+endif
+ifdef REQUIRE_PACKAGESDIR
+override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR)
+endif
+ifdef ZIPINSTALL
+ifneq ($(findstring $(OS_TARGET),$(UNIXs)),)
+UNIXHier=1
+endif
+else
+ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),)
+UNIXHier=1
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef PREFIX
+INSTALL_PREFIX=$(PREFIX)
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef UNIXHier
+INSTALL_PREFIX=/usr/local
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=/pp
+else
+INSTALL_BASEDIR:=/$(PACKAGE_NAME)
+endif
+endif
+endif
+export INSTALL_PREFIX
+ifdef INSTALL_FPCSUBDIR
+export INSTALL_FPCSUBDIR
+endif
+ifndef DIST_DESTDIR
+DIST_DESTDIR:=$(BASEDIR)
+endif
+export DIST_DESTDIR
+ifndef COMPILER_UNITTARGETDIR
+ifdef PACKAGEDIR_MAIN
+COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX)
+else
+COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX)
+endif
+endif
+ifndef COMPILER_TARGETDIR
+COMPILER_TARGETDIR=.
+endif
+ifndef INSTALL_BASEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION)
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME)
+endif
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)
+endif
+endif
+ifndef INSTALL_BINDIR
+ifdef UNIXHier
+INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin
+else
+INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin
+ifdef INSTALL_FPCPACKAGE
+ifdef CROSSCOMPILE
+ifdef CROSSINSTALL
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX)
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+endif
+endif
+endif
+ifndef INSTALL_UNITDIR
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX)
+ifdef INSTALL_FPCPACKAGE
+ifdef PACKAGE_NAME
+INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME)
+endif
+endif
+endif
+ifndef INSTALL_LIBDIR
+ifdef UNIXHier
+INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib
+else
+INSTALL_LIBDIR:=$(INSTALL_UNITDIR)
+endif
+endif
+ifndef INSTALL_SOURCEDIR
+ifdef UNIXHier
+ifdef BSDhier
+SRCPREFIXDIR=share/src
+else
+ifdef linuxHier
+SRCPREFIXDIR=share/src
+else
+SRCPREFIXDIR=src
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source
+endif
+endif
+endif
+ifndef INSTALL_DOCDIR
+ifdef UNIXHier
+ifdef BSDhier
+DOCPREFIXDIR=share/doc
+else
+ifdef linuxHier
+DOCPREFIXDIR=share/doc
+else
+DOCPREFIXDIR=doc
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc
+endif
+endif
+endif
+ifndef INSTALL_EXAMPLEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME)
+endif
+endif
+else
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+endif
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples
+endif
+endif
+endif
+ifndef INSTALL_DATADIR
+INSTALL_DATADIR=$(INSTALL_BASEDIR)
+endif
+ifndef INSTALL_SHAREDDIR
+INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib
+endif
+ifdef CROSSCOMPILE
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX))
+ifeq ($(CROSSBINDIR),)
+CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE))
+endif
+endif
+else
+CROSSBINDIR=
+endif
+BATCHEXT=.bat
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+SHAREDLIBPREFIX=libfp
+STATICLIBPREFIX=libp
+IMPORTLIBPREFIX=libimp
+RSTEXT=.rst
+EXEDBGEXT=.dbg
+ifeq ($(OS_TARGET),go32v1)
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+OEXT=.obj
+ASMEXT=.asm
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=wat
+IMPORTLIBPREFIX=
+endif
+ifneq ($(CPU_TARGET),jvm)
+ifeq ($(OS_TARGET),android)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),dragonfly)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=df
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),emx)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=emx
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),aros)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=aros
+endif
+ifeq ($(OS_TARGET),morphos)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=mos
+endif
+ifeq ($(OS_TARGET),atari)
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),haiku)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=hai
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nw
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),netwlibc)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nwl
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+IMPORTLIBPREFIX=imp
+endif
+ifneq ($(findstring $(OS_TARGET),darwin iphonesim),)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=dwn
+EXEDBGEXT=.dSYM
+endif
+ifeq ($(OS_TARGET),gba)
+EXEEXT=.gba
+SHAREDLIBEXT=.so
+SHORTSUFFIX=gba
+endif
+ifeq ($(OS_TARGET),symbian)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=symbian
+endif
+ifeq ($(OS_TARGET),NativeNT)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=nativent
+endif
+ifeq ($(OS_TARGET),wii)
+EXEEXT=.dol
+SHAREDLIBEXT=.so
+SHORTSUFFIX=wii
+endif
+ifeq ($(OS_TARGET),aix)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=aix
+endif
+ifeq ($(OS_TARGET),java)
+OEXT=.class
+ASMEXT=.j
+SHAREDLIBEXT=.jar
+SHORTSUFFIX=java
+endif
+ifeq ($(CPU_TARGET),jvm)
+ifeq ($(OS_TARGET),android)
+OEXT=.class
+ASMEXT=.j
+SHAREDLIBEXT=.jar
+SHORTSUFFIX=android
+endif
+endif
+ifeq ($(OS_TARGET),msdos)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+SHORTSUFFIX=d16
+endif
+ifeq ($(OS_TARGET),embedded)
+ifeq ($(CPU_TARGET),i8086)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+else
+EXEEXT=.bin
+endif
+SHORTSUFFIX=emb
+endif
+ifeq ($(OS_TARGET),win16)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w16
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+FPCMADE=fpcmade.$(SHORTSUFFIX)
+ZIPSUFFIX=$(SHORTSUFFIX)
+ZIPCROSSPREFIX=
+ZIPSOURCESUFFIX=src
+ZIPEXAMPLESUFFIX=exm
+else
+FPCMADE=fpcmade.$(TARGETSUFFIX)
+ZIPSOURCESUFFIX=.source
+ZIPEXAMPLESUFFIX=.examples
+ifdef CROSSCOMPILE
+ZIPSUFFIX=.$(SOURCESUFFIX)
+ZIPCROSSPREFIX=$(TARGETSUFFIX)-
+else
+ZIPSUFFIX=.$(TARGETSUFFIX)
+ZIPCROSSPREFIX=
+endif
+endif
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO= __missing_command_ECHO
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+ifndef DATE
+DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE= __missing_command_DATE
+else
+DATE:=$(firstword $(DATE))
+endif
+else
+DATE:=$(firstword $(DATE))
+endif
+endif
+export DATE
+ifndef GINSTALL
+GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL= __missing_command_GINSTALL
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+endif
+export GINSTALL
+ifndef CPPROG
+CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(CPPROG),)
+CPPROG= __missing_command_CPPROG
+else
+CPPROG:=$(firstword $(CPPROG))
+endif
+endif
+export CPPROG
+ifndef RMPROG
+RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(RMPROG),)
+RMPROG= __missing_command_RMPROG
+else
+RMPROG:=$(firstword $(RMPROG))
+endif
+endif
+export RMPROG
+ifndef MVPROG
+MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MVPROG),)
+MVPROG= __missing_command_MVPROG
+else
+MVPROG:=$(firstword $(MVPROG))
+endif
+endif
+export MVPROG
+ifndef MKDIRPROG
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG= __missing_command_MKDIRPROG
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+endif
+export MKDIRPROG
+ifndef ECHOREDIR
+ifndef inUnix
+ECHOREDIR=echo
+else
+ECHOREDIR=$(ECHO)
+endif
+endif
+ifndef COPY
+COPY:=$(CPPROG) -fp
+endif
+ifndef COPYTREE
+COPYTREE:=$(CPPROG) -Rfp
+endif
+ifndef MKDIRTREE
+MKDIRTREE:=$(MKDIRPROG) -p
+endif
+ifndef MOVE
+MOVE:=$(MVPROG) -f
+endif
+ifndef DEL
+DEL:=$(RMPROG) -f
+endif
+ifndef DELTREE
+DELTREE:=$(RMPROG) -rf
+endif
+ifndef INSTALL
+ifdef inUnix
+INSTALL:=$(GINSTALL) -c -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+ifndef INSTALLEXE
+ifdef inUnix
+INSTALLEXE:=$(GINSTALL) -c -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+ifndef MKDIR
+MKDIR:=$(GINSTALL) -m 755 -d
+endif
+export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE= __missing_command_PPUMOVE
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+ifndef FPCMAKE
+FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(FPCMAKE),)
+FPCMAKE= __missing_command_FPCMAKE
+else
+FPCMAKE:=$(firstword $(FPCMAKE))
+endif
+endif
+export FPCMAKE
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG= __missing_command_ZIPPROG
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG= __missing_command_TARPROG
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+ASNAME=$(BINUTILSPREFIX)as
+LDNAME=$(BINUTILSPREFIX)ld
+ARNAME=$(BINUTILSPREFIX)ar
+RCNAME=$(BINUTILSPREFIX)rc
+NASMNAME=$(BINUTILSPREFIX)nasm
+ifndef ASPROG
+ifdef CROSSBINDIR
+ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT)
+else
+ASPROG=$(ASNAME)
+endif
+endif
+ifndef LDPROG
+ifdef CROSSBINDIR
+LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT)
+else
+LDPROG=$(LDNAME)
+endif
+endif
+ifndef RCPROG
+ifdef CROSSBINDIR
+RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT)
+else
+RCPROG=$(RCNAME)
+endif
+endif
+ifndef ARPROG
+ifdef CROSSBINDIR
+ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT)
+else
+ARPROG=$(ARNAME)
+endif
+endif
+ifndef NASMPROG
+ifdef CROSSBINDIR
+NASMPROG=$(CROSSBINDIR)/$(NASMNAME)$(SRCEXEEXT)
+else
+NASMPROG=$(NASMNAME)
+endif
+endif
+AS=$(ASPROG)
+LD=$(LDPROG)
+RC=$(RCPROG)
+AR=$(ARPROG)
+NASM=$(NASMPROG)
+ifdef inUnix
+PPAS=./ppas$(SRCBATCHEXT)
+else
+PPAS=ppas$(SRCBATCHEXT)
+endif
+ifdef inUnix
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+ifdef DATE
+DATESTR:=$(shell $(DATE) +%Y%m%d)
+else
+DATESTR=
+endif
+ZIPOPT=-9
+ZIPEXT=.zip
+ifeq ($(USETAR),bz2)
+TAROPT=vj
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+override REQUIRE_PACKAGES=rtl fpmkunit
+ifeq ($(FULL_TARGET),i386-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-nativent)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-iphonesim)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i386-aros)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-wii)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc-aix)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-iphonesim)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-aros)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),x86_64-dragonfly)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),arm-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-aix)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),mips-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),mipsel-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),mipsel-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),mipsel-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),jvm-java)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),jvm-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i8086-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i8086-msdos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),i8086-win16)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),aarch64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),aarch64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifdef REQUIRE_PACKAGES_RTL
+PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_RTL),)
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),)
+UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)
+else
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_RTL)/$(OS_TARGET) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_RTL=
+UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_RTL),)
+UNITDIR_RTL:=$(firstword $(UNITDIR_RTL))
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override COMPILER_UNITDIR+=$(UNITDIR_RTL)
+endif
+ifdef UNITDIR_FPMAKE_RTL
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_RTL)
+endif
+endif
+ifdef REQUIRE_PACKAGES_PASZLIB
+PACKAGEDIR_PASZLIB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_PASZLIB),)
+ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX)),)
+UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX)
+else
+UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_PASZLIB)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_PASZLIB) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_PASZLIB)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_PASZLIB=
+UNITDIR_PASZLIB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_PASZLIB),)
+UNITDIR_PASZLIB:=$(firstword $(UNITDIR_PASZLIB))
+else
+UNITDIR_PASZLIB=
+endif
+endif
+ifdef UNITDIR_PASZLIB
+override COMPILER_UNITDIR+=$(UNITDIR_PASZLIB)
+endif
+ifdef UNITDIR_FPMAKE_PASZLIB
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_PASZLIB)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL-PROCESS
+PACKAGEDIR_FCL-PROCESS:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-PROCESS),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-PROCESS) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-PROCESS=
+UNITDIR_FCL-PROCESS:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-PROCESS),)
+UNITDIR_FCL-PROCESS:=$(firstword $(UNITDIR_FCL-PROCESS))
+else
+UNITDIR_FCL-PROCESS=
+endif
+endif
+ifdef UNITDIR_FCL-PROCESS
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-PROCESS)
+endif
+ifdef UNITDIR_FPMAKE_FCL-PROCESS
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-PROCESS)
+endif
+endif
+ifdef REQUIRE_PACKAGES_HASH
+PACKAGEDIR_HASH:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /hash/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_HASH),)
+ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX)),)
+UNITDIR_HASH=$(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX)
+else
+UNITDIR_HASH=$(PACKAGEDIR_HASH)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_HASH)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_HASH) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_HASH)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_HASH=
+UNITDIR_HASH:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /hash/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_HASH),)
+UNITDIR_HASH:=$(firstword $(UNITDIR_HASH))
+else
+UNITDIR_HASH=
+endif
+endif
+ifdef UNITDIR_HASH
+override COMPILER_UNITDIR+=$(UNITDIR_HASH)
+endif
+ifdef UNITDIR_FPMAKE_HASH
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_HASH)
+endif
+endif
+ifdef REQUIRE_PACKAGES_LIBTAR
+PACKAGEDIR_LIBTAR:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /libtar/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_LIBTAR),)
+ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX)),)
+UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX)
+else
+UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_LIBTAR)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_LIBTAR) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_LIBTAR)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_LIBTAR=
+UNITDIR_LIBTAR:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /libtar/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_LIBTAR),)
+UNITDIR_LIBTAR:=$(firstword $(UNITDIR_LIBTAR))
+else
+UNITDIR_LIBTAR=
+endif
+endif
+ifdef UNITDIR_LIBTAR
+override COMPILER_UNITDIR+=$(UNITDIR_LIBTAR)
+endif
+ifdef UNITDIR_FPMAKE_LIBTAR
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_LIBTAR)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FPMKUNIT
+PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FPMKUNIT),)
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX)),)
+UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FPMKUNIT=
+UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FPMKUNIT),)
+UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT))
+else
+UNITDIR_FPMKUNIT=
+endif
+endif
+ifdef UNITDIR_FPMKUNIT
+override COMPILER_UNITDIR+=$(UNITDIR_FPMKUNIT)
+endif
+ifdef UNITDIR_FPMAKE_FPMKUNIT
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT)
+endif
+endif
+ifndef NOCPUDEF
+override FPCOPTDEF=$(ARCH)
+endif
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+ifneq ($(CPU_TARGET),$(CPU_SOURCE))
+override FPCOPT+=-P$(ARCH)
+endif
+ifeq ($(OS_SOURCE),openbsd)
+override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
+override FPCMAKEOPT+=-FD$(NEW_BINUTILS_PATH)
+override FPMAKE_BUILD_OPT+=-FD$(NEW_BINUTILS_PATH)
+endif
+ifndef CROSSBOOTSTRAP
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-XP$(BINUTILSPREFIX)
+endif
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-Xr$(RLINKPATH)
+endif
+endif
+ifndef CROSSCOMPILE
+ifneq ($(BINUTILSPREFIX),)
+override FPCMAKEOPT+=-XP$(BINUTILSPREFIX)
+override FPMAKE_BUILD_OPT+=-XP$(BINUTILSPREFIX)
+endif
+endif
+ifdef UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(UNITDIR))
+endif
+ifdef LIBDIR
+override FPCOPT+=$(addprefix -Fl,$(LIBDIR))
+endif
+ifdef OBJDIR
+override FPCOPT+=$(addprefix -Fo,$(OBJDIR))
+endif
+ifdef INCDIR
+override FPCOPT+=$(addprefix -Fi,$(INCDIR))
+endif
+ifdef LINKSMART
+override FPCOPT+=-XX
+endif
+ifdef CREATESMART
+override FPCOPT+=-CX
+endif
+ifdef DEBUG
+override FPCOPT+=-gl
+override FPCOPTDEF+=DEBUG
+endif
+ifdef RELEASE
+ifneq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(CPU_TARGET),i386)
+FPCCPUOPT:=-OG2p3
+endif
+ifeq ($(CPU_TARGET),powerpc)
+FPCCPUOPT:=-O1r
+endif
+else
+FPCCPUOPT:=-O2
+endif
+override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n
+override FPCOPTDEF+=RELEASE
+endif
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+ifdef OPTIMIZE
+override FPCOPT+=-O2
+endif
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+ifdef COMPILER_OPTIONS
+override FPCOPT+=$(COMPILER_OPTIONS)
+endif
+ifdef COMPILER_UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR))
+endif
+ifdef COMPILER_LIBRARYDIR
+override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR))
+endif
+ifdef COMPILER_OBJECTDIR
+override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR))
+endif
+ifdef COMPILER_INCLUDEDIR
+override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR))
+endif
+ifdef CROSSBINDIR
+override FPCOPT+=-FD$(CROSSBINDIR)
+endif
+ifdef COMPILER_TARGETDIR
+override FPCOPT+=-FE$(COMPILER_TARGETDIR)
+ifeq ($(COMPILER_TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/
+endif
+endif
+ifdef COMPILER_UNITTARGETDIR
+override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR)
+ifeq ($(COMPILER_UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/
+endif
+else
+ifdef COMPILER_TARGETDIR
+override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+ifdef CREATESHARED
+override FPCOPT+=-Cg
+endif
+ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+override FPCOPT+=-Cg
+endif
+endif
+ifdef LINKSHARED
+endif
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+ifdef FPMAKEBUILDOPT
+override FPMAKE_BUILD_OPT+=$(FPMAKEBUILDOPT)
+endif
+ifdef FPCOPTDEF
+override FPCOPT+=$(addprefix -d,$(FPCOPTDEF))
+endif
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+ifdef USEENV
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+override AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(AFULL_TARGET),$(AFULL_SOURCE))
+override ACROSSCOMPILE=1
+endif
+ifdef ACROSSCOMPILE
+override FPCOPT+=$(CROSSOPT)
+endif
+override COMPILER:=$(strip $(FPC) $(FPCOPT))
+ifneq (,$(findstring -sh ,$(COMPILER)))
+UseEXECPPAS=1
+endif
+ifneq (,$(findstring -s ,$(COMPILER)))
+ifeq ($(FULL_SOURCE),$(FULL_TARGET))
+UseEXECPPAS=1
+endif
+endif
+ifneq ($(UseEXECPPAS),1)
+EXECPPAS=
+else
+ifdef RUNBATCH
+EXECPPAS:=@$(RUNBATCH) $(PPAS)
+else
+EXECPPAS:=@$(PPAS)
+endif
+endif
+ifdef TARGET_RSTS
+override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
+override CLEANRSTFILES+=$(RSTFILES)
+endif
+.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall
+ifdef INSTALL_UNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS))
+endif
+ifdef INSTALL_BUILDUNIT
+override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES))
+endif
+ifdef INSTALLPPUFILES
+override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+ifneq ($(UNITTARGETDIRPREFIX),)
+override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPUFILES)))
+override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPULINKFILES))))
+endif
+override INSTALL_CREATEPACKAGEFPC=1
+endif
+ifdef INSTALLEXEFILES
+ifneq ($(TARGETDIRPREFIX),)
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES)))
+endif
+endif
+fpc_install: all $(INSTALLTARGET)
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(INSTALL_BINDIR)
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR)
+endif
+ifdef INSTALL_CREATEPACKAGEFPC
+ifdef FPCMAKE
+ifdef PACKAGE_VERSION
+ifneq ($(wildcard Makefile.fpc),)
+	$(FPCMAKE) -p -T$(CPU_TARGET)-$(OS_TARGET) Makefile.fpc
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) Package.fpc $(INSTALL_UNITDIR)
+endif
+endif
+endif
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR)
+endif
+ifneq ($(wildcard $(LIB_FULLNAME)),)
+	$(MKDIR) $(INSTALL_LIBDIR)
+	$(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR)
+ifdef inUnix
+	ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME)
+endif
+endif
+endif
+ifdef INSTALL_FILES
+	$(MKDIR) $(INSTALL_DATADIR)
+	$(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR)
+endif
+fpc_sourceinstall: distclean
+	$(MKDIR) $(INSTALL_SOURCEDIR)
+	$(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR)
+fpc_exampleinstall: $(EXAMPLEINSTALLTARGET) $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS))
+ifdef HASEXAMPLES
+	$(MKDIR) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef EXAMPLESOURCEFILES
+	$(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR)
+endif
+.PHONY: fpc_distinstall
+fpc_distinstall: install exampleinstall
+.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall
+ifndef PACKDIR
+ifndef inUnix
+PACKDIR=$(BASEDIR)/../fpc-pack
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+ifndef ZIPNAME
+ifdef DIST_ZIPNAME
+ZIPNAME=$(DIST_ZIPNAME)
+else
+ZIPNAME=$(PACKAGE_NAME)
+endif
+endif
+ifndef FULLZIPNAME
+FULLZIPNAME=$(ZIPCROSSPREFIX)$(ZIPPREFIX)$(ZIPNAME)$(ZIPSUFFIX)
+endif
+ifndef ZIPTARGET
+ifdef DIST_ZIPTARGET
+ZIPTARGET=DIST_ZIPTARGET
+else
+ZIPTARGET=install
+endif
+endif
+ifndef USEZIP
+ifdef inUnix
+USETAR=1
+endif
+endif
+ifndef inUnix
+USEZIPWRAPPER=1
+endif
+ifdef USEZIPWRAPPER
+ZIPPATHSEP=$(PATHSEP)
+ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(SRCBATCHEXT))
+else
+ZIPPATHSEP=/
+endif
+ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR))
+ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR))
+ifdef USETAR
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(TAREXT)
+ZIPCMD_ZIP:=$(TARPROG) c$(TAROPT)f $(ZIPDESTFILE) *
+else
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(ZIPEXT)
+ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) *
+endif
+fpc_zipinstall:
+	$(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1
+	$(MKDIR) $(DIST_DESTDIR)
+	$(DEL) $(ZIPDESTFILE)
+ifdef USEZIPWRAPPER
+ifneq ($(ECHOREDIR),echo)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER)
+else
+	echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER)
+	echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER)
+	echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER)
+endif
+ifdef inUnix
+	/bin/sh $(ZIPWRAPPER)
+else
+ifdef RUNBATCH
+	$(RUNBATCH) $(ZIPWRAPPER)
+else
+	$(ZIPWRAPPER)
+endif
+endif
+	$(DEL) $(ZIPWRAPPER)
+else
+	$(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE)
+endif
+	$(DELTREE) $(PACKDIR)
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=$(ZIPSOURCESUFFIX)
+fpc_zipexampleinstall:
+ifdef HASEXAMPLES
+	$(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=$(ZIPEXAMPLESUFFIX)
+endif
+fpc_zipdistinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=distinstall
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+ifdef EXEFILES
+override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES))
+override CLEANEXEDBGFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEDBGFILES))
+endif
+ifdef CLEAN_PROGRAMS
+override CLEANEXEFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEEXT), $(CLEAN_PROGRAMS)))
+override CLEANEXEDBGFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEDBGEXT), $(CLEAN_PROGRAMS)))
+endif
+ifdef CLEAN_UNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS))
+endif
+ifdef CLEANPPUFILES
+override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES)))
+ifdef DEBUGSYMEXT
+override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES))
+endif
+override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES))
+override CLEANPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILES)))
+endif
+fpc_clean: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef CLEANEXEDBGFILES
+	-$(DELTREE) $(CLEANEXEDBGFILES)
+endif
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+ifdef LIB_NAME
+	-$(DEL) $(LIB_NAME) $(LIB_FULLNAME)
+endif
+	-$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *$(ASMEXT) *_ppas$(BATCHEXT)
+fpc_cleanall: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef COMPILER_UNITTARGETDIR
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+	-$(DELTREE) units
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+ifneq ($(PPUEXT),.ppu)
+	-$(DEL) *.o *.ppu *.a
+endif
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) fpcmade.* Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *_ppas$(BATCHEXT)
+ifdef AOUTEXT
+	-$(DEL) *$(AOUTEXT)
+endif
+ifdef DEBUGSYMEXT
+	-$(DEL) *$(DEBUGSYMEXT)
+endif
+ifdef LOCALFPMAKEBIN
+	-$(DEL) $(LOCALFPMAKEBIN)
+	-$(DEL) $(FPMAKEBINOBJ)
+endif
+fpc_distclean: cleanall
+.PHONY: fpc_baseinfo
+override INFORULES+=fpc_baseinfo
+fpc_baseinfo:
+	@$(ECHO)
+	@$(ECHO)  == Package info ==
+	@$(ECHO)  Package Name..... $(PACKAGE_NAME)
+	@$(ECHO)  Package Version.. $(PACKAGE_VERSION)
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC.......... $(FPC)
+	@$(ECHO)  FPC Version.. $(FPC_VERSION)
+	@$(ECHO)  Source CPU... $(CPU_SOURCE)
+	@$(ECHO)  Target CPU... $(CPU_TARGET)
+	@$(ECHO)  Source OS.... $(OS_SOURCE)
+	@$(ECHO)  Target OS.... $(OS_TARGET)
+	@$(ECHO)  Full Source.. $(FULL_SOURCE)
+	@$(ECHO)  Full Target.. $(FULL_TARGET)
+	@$(ECHO)  SourceSuffix. $(SOURCESUFFIX)
+	@$(ECHO)  TargetSuffix. $(TARGETSUFFIX)
+	@$(ECHO)  FPC fpmake... $(FPCFPMAKE)
+	@$(ECHO)
+	@$(ECHO)  == Directory info ==
+	@$(ECHO)
+	@$(ECHO)  Required pkgs... $(REQUIRE_PACKAGES)
+	@$(ECHO)
+	@$(ECHO)  Basedir......... $(BASEDIR)
+	@$(ECHO)  FPCDir.......... $(FPCDIR)
+	@$(ECHO)  CrossBinDir..... $(CROSSBINDIR)
+	@$(ECHO)  UnitsDir........ $(UNITSDIR)
+	@$(ECHO)  PackagesDir..... $(PACKAGESDIR)
+	@$(ECHO)
+	@$(ECHO)  GCC library..... $(GCCLIBDIR)
+	@$(ECHO)  Other library... $(OTHERLIBDIR)
+	@$(ECHO)
+	@$(ECHO)  == Tools info ==
+	@$(ECHO)
+	@$(ECHO)  As........ $(AS)
+	@$(ECHO)  Ld........ $(LD)
+	@$(ECHO)  Ar........ $(AR)
+	@$(ECHO)  Rc........ $(RC)
+	@$(ECHO)
+	@$(ECHO)  Mv........ $(MVPROG)
+	@$(ECHO)  Cp........ $(CPPROG)
+	@$(ECHO)  Rm........ $(RMPROG)
+	@$(ECHO)  GInstall.. $(GINSTALL)
+	@$(ECHO)  Echo...... $(ECHO)
+	@$(ECHO)  Shell..... $(SHELL)
+	@$(ECHO)  Date...... $(DATE)
+	@$(ECHO)  FPCMake... $(FPCMAKE)
+	@$(ECHO)  PPUMove... $(PPUMOVE)
+	@$(ECHO)  Zip....... $(ZIPPROG)
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  Target Loaders........ $(TARGET_LOADERS)
+	@$(ECHO)  Target Units.......... $(TARGET_UNITS)
+	@$(ECHO)  Target Implicit Units. $(TARGET_IMPLICITUNITS)
+	@$(ECHO)  Target Programs....... $(TARGET_PROGRAMS)
+	@$(ECHO)  Target Dirs........... $(TARGET_DIRS)
+	@$(ECHO)  Target Examples....... $(TARGET_EXAMPLES)
+	@$(ECHO)  Target ExampleDirs.... $(TARGET_EXAMPLEDIRS)
+	@$(ECHO)
+	@$(ECHO)  Clean Units......... $(CLEAN_UNITS)
+	@$(ECHO)  Clean Files......... $(CLEAN_FILES)
+	@$(ECHO)
+	@$(ECHO)  Install Units....... $(INSTALL_UNITS)
+	@$(ECHO)  Install Files....... $(INSTALL_FILES)
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+	@$(ECHO)  DateStr.............. $(DATESTR)
+	@$(ECHO)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)  ZipPrefix............ $(ZIPPREFIX)
+	@$(ECHO)  ZipCrossPrefix....... $(ZIPCROSSPREFIX)
+	@$(ECHO)  ZipSuffix............ $(ZIPSUFFIX)
+	@$(ECHO)  FullZipName.......... $(FULLZIPNAME)
+	@$(ECHO)  Install FPC Package.. $(INSTALL_FPCPACKAGE)
+	@$(ECHO)
+	@$(ECHO)  Install base dir..... $(INSTALL_BASEDIR)
+	@$(ECHO)  Install binary dir... $(INSTALL_BINDIR)
+	@$(ECHO)  Install library dir.. $(INSTALL_LIBDIR)
+	@$(ECHO)  Install units dir.... $(INSTALL_UNITDIR)
+	@$(ECHO)  Install source dir... $(INSTALL_SOURCEDIR)
+	@$(ECHO)  Install doc dir...... $(INSTALL_DOCDIR)
+	@$(ECHO)  Install example dir.. $(INSTALL_EXAMPLEDIR)
+	@$(ECHO)  Install data dir..... $(INSTALL_DATADIR)
+	@$(ECHO)
+	@$(ECHO)  Dist destination dir. $(DIST_DESTDIR)
+	@$(ECHO)  Dist zip name........ $(DIST_ZIPNAME)
+	@$(ECHO)
+.PHONY: fpc_info
+fpc_info: $(INFORULES)
+.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \
+	fpc_makefile_dirs
+fpc_makefile:
+	$(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc
+fpc_makefile_sub1:
+ifdef TARGET_DIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS))
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS))
+endif
+fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS))
+fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2
+fpc_makefiles: fpc_makefile fpc_makefile_dirs
+units:
+examples:
+shared:
+sourceinstall: fpc_sourceinstall
+exampleinstall: fpc_exampleinstall
+zipexampleinstall: fpc_zipexampleinstall
+info: fpc_info
+makefiles: fpc_makefiles
+.PHONY: units examples shared sourceinstall exampleinstall zipexampleinstall info makefiles
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+override FPCOPT:=$(filter-out -FU%,$(FPCOPT))
+override FPCOPT:=$(filter-out -FE%,$(FPCOPT))
+override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters
+ifdef FPMAKEOPT
+FPMAKE_OPT+=$(FPMAKEOPT)
+endif
+FPMAKE_OPT+=--localunitdir=../..
+FPMAKE_OPT+=--globalunitdir=..
+FPMAKE_OPT+=$(FPC_TARGETOPT)
+FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT))
+FPMAKE_OPT+=--compiler=$(FPC)
+FPMAKE_OPT+=-bu
+.NOTPARALLEL:
+fpmake$(SRCEXEEXT): fpmake.pp
+	$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT)
+all:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT)
+smart:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX
+release:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE
+debug:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG
+ifeq ($(FPMAKE_BIN_CLEAN),)
+clean:
+else
+clean:
+	$(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT)
+endif
+ifeq ($(FPMAKE_BIN_CLEAN),)
+distclean:	$(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
+else
+distclean:
+ifdef inUnix
+	{ $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi;  }
+else
+	$(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT)
+endif
+	-$(DEL) $(LOCALFPMAKE)
+endif
+cleanall: distclean
+install:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
+endif
+distinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+endif
+zipinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX)
+zipdistinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0
+zipsourceinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\)
+else
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\)
+endif

+ 102 - 0
packages/rtl-generics/Makefile.fpc

@@ -0,0 +1,102 @@
+#
+#   Makefile.fpc for running fpmake
+#
+
+[package]
+name=googleapi
+version=3.1.1
+
+[require]
+packages=rtl fpmkunit
+
+[install]
+fpcpackage=y
+
+[default]
+fpcdir=../..
+
+[prerules]
+FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT))
+ifdef OS_TARGET
+FPC_TARGETOPT+=--os=$(OS_TARGET)
+endif
+ifdef CPU_TARGET
+FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
+endif
+LOCALFPMAKE=./fpmake$(SRCEXEEXT)
+
+[rules]
+# Do not pass the Makefile's unit and binary target locations. Fpmake uses it's own.
+override FPCOPT:=$(filter-out -FU%,$(FPCOPT))
+override FPCOPT:=$(filter-out -FE%,$(FPCOPT))
+# Do not pass the package-unitdirectories. Fpmake adds those and this way they don't apear in the .fpm
+override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters
+# Compose general fpmake-parameters
+ifdef FPMAKEOPT
+FPMAKE_OPT+=$(FPMAKEOPT)
+endif
+FPMAKE_OPT+=--localunitdir=../..
+FPMAKE_OPT+=--globalunitdir=..
+FPMAKE_OPT+=$(FPC_TARGETOPT)
+FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT))
+FPMAKE_OPT+=--compiler=$(FPC)
+FPMAKE_OPT+=-bu
+.NOTPARALLEL:
+
+fpmake$(SRCEXEEXT): fpmake.pp
+	$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT)
+all:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT)
+smart:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX
+release:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE
+debug:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG
+# If no fpmake exists and (dist)clean is called, do not try to build fpmake, it will
+# most often fail because the dependencies are cleared.
+# In case of a clean, simply do nothing
+ifeq ($(FPMAKE_BIN_CLEAN),)
+clean:
+else
+clean:
+	$(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT)
+endif
+# In case of a distclean, perform an 'old'-style distclean. This to avoid problems
+# when the package is compiled using fpcmake prior to running this clean using fpmake
+ifeq ($(FPMAKE_BIN_CLEAN),)
+distclean:	$(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
+else
+distclean:
+ifdef inUnix
+        { $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi;  }
+else
+        $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT)
+endif
+	-$(DEL) $(LOCALFPMAKE)
+endif
+cleanall: distclean
+install:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
+endif
+# distinstall also installs the example-sources and omits the location of the source-
+# files from the fpunits.cfg files.
+distinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+endif
+zipinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX)
+zipdistinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0
+zipsourceinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\)
+else
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\)
+endif

+ 66 - 0
packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="TArrayProjectDouble"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="tarrayprojectdouble.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="tarrayprojectdouble"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 91 - 0
packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpr

@@ -0,0 +1,91 @@
+// Generic types for FreeSparta.com and FreePascal!
+// Original version by keeper89.blogspot.com, 2011
+// FPC version by Maciej Izak (hnb), 2014
+
+program TArrayProjectDouble;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, Math, Types, Generics.Collections, Generics.Defaults;
+
+type
+  TDoubleIntegerArray = array of TIntegerDynArray;
+
+procedure PrintMatrix(A: TDoubleIntegerArray);
+var
+  i, j: Integer;
+begin
+  for i := Low(A) to High(A) do
+  begin
+    for j := Low(A[0]) to High(A[0]) do
+      Write(A[i, j]: 3, ' ');
+    Writeln;
+  end;
+  Writeln; Writeln;
+end;
+
+function CustomCompare_1(constref Left, Right: TIntegerDynArray): Integer;
+begin
+  Result := TCompare.Integer(Right[0], Left[0]);
+end;
+
+function CustomCompare_2(constref Left, Right: TIntegerDynArray): Integer;
+var
+  i: Integer;
+begin
+  i := 0;
+  repeat
+    Result := TCompare.Integer(Right[i], Left[i]);
+    Inc(i);
+  until ((Result <> 0) or (i = Length(Left)));
+end;
+
+var
+  A: TDoubleIntegerArray;
+  FoundIndex: Integer;
+  i, j: Integer;
+
+begin
+  WriteLn('Working with TArray - a two-dimensional integer array');
+  WriteLn;
+
+  // Fill integer array with random numbers [1 .. 50]
+  SetLength(A, 4, 7);
+  Randomize;
+  for i := Low(A) to High(A) do
+    for j := Low(A[0]) to High(A[0]) do
+      A[i, j] := Math.RandomRange(1, 50);
+
+  // Equate some of the elements for further "cascade" sorting
+  A[1, 0] := A[0, 0];
+  A[2, 0] := A[0, 0];
+  A[1, 1] := A[0, 1];
+
+  // Print out what happened
+  Writeln('The original array:');
+  PrintMatrix(A);
+
+  // ! FPC don't support anonymous methods yet
+  //TArray.Sort<TIntegerDynArray>(A, TComparer<TIntegerDynArray>.Construct(
+  //  function (const Left, Right: TIntegerDynArray): Integer
+  //  begin
+  //    Result := Right[0] - Left[0];
+  //  end));
+  // Sort descending 1st column, with cutom comparer_1
+  TArrayHelper<TIntegerDynArray>.Sort(A, TComparer<TIntegerDynArray>.Construct(
+    CustomCompare_1));
+  Writeln('Descending in column 1:');
+  PrintMatrix(A);
+
+  // Sort descending 1st column "cascade" -
+  // If the line items are equal, compare neighboring
+  TArrayHelper<TIntegerDynArray>.Sort(A, TComparer<TIntegerDynArray>.Construct(
+    CustomCompare_2));
+  Writeln('Cascade sorting, starting from the 1st column:');
+  PrintMatrix(A);
+
+  Readln;
+end.
+

+ 71 - 0
packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpi

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="TArrayProjectSingle"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="tarrayprojectsingle.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="tarrayprojectsingle"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <SyntaxMode Value="Delphi"/>
+      </SyntaxOptions>
+    </Parsing>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 111 - 0
packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpr

@@ -0,0 +1,111 @@
+// Generic types for FreeSparta.com and FreePascal!
+// Original version by keeper89.blogspot.com, 2011
+// FPC version by Maciej Izak (hnb), 2014
+
+program TArrayProjectSingle;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, Math, Types, Generics.Collections, Generics.Defaults;
+
+function CompareIntReverse(constref Left, Right: Integer): Integer;
+begin
+  Result := TCompare.Integer(Right, Left);
+end;
+
+type
+  TForCompare = class
+  public
+    function CompareIntReverseMethod(constref Left, Right: Integer): Integer;
+  end;
+
+function TForCompare.CompareIntReverseMethod(constref Left, Right: Integer): Integer;
+begin
+  Result := TCompare.Integer(Right, Left);
+end;
+
+procedure PrintMatrix(A: TIntegerDynArray);
+var
+  item: Integer;
+begin
+  for item in A do
+    Write(item, ' ');
+  Writeln; Writeln;
+end;
+
+var
+  A: TIntegerDynArray;
+  FoundIndex: PtrInt;
+  ForCompareObj: TForCompare;
+begin
+  WriteLn('Working with TArray - one-dimensional integer array');
+  WriteLn;
+
+  // Fill a one-dimensional array of integers by random numbers [1 .. 10]
+  A := TIntegerDynArray.Create(1, 6, 3, 2, 9);
+
+  // Print out what happened
+  Writeln('The original array:');
+  PrintMatrix(A);
+
+  // Sort ascending without comparator
+  TArrayHelper<Integer>.Sort(A);
+  Writeln('Ascending Sort without parameters:');
+  PrintMatrix(A);
+
+  // ! FPC don't support anonymous methods yet
+  // Sort descending, the comparator is constructed
+  // using an anonymous method
+  //TArray.Sort<Integer>(A, TComparer<Integer>.Construct(
+  //  function (const Left, Right: Integer): Integer
+  //  begin
+  //    Result := Math.CompareValue(Right, Left)
+  //  end));
+
+  // Sort descending, the comparator is constructed
+  // using an method
+  TArrayHelper<Integer>.Sort(A, TComparer<Integer>.Construct(
+    ForCompareObj.CompareIntReverseMethod));
+  Writeln('Descending by TComparer<Integer>.Construct(ForCompareObj.Method):');
+  PrintMatrix(A);
+
+  // Again sort ascending by using defaul
+  TArrayHelper<Integer>.Sort(A, TComparer<Integer>.Default);
+  Writeln('Ascending by TComparer<Integer>.Default:');
+  PrintMatrix(A);
+
+  // Again descending using own comparator function
+  TArrayHelper<Integer>.Sort(A, TComparer<Integer>.Construct(CompareIntReverse));
+  Writeln('Descending by TComparer<Integer>.Construct(CompareIntReverse):');
+  PrintMatrix(A);
+
+  // Searches for a nonexistent element
+  Writeln('BinarySearch nonexistent element');
+  if TArrayHelper<Integer>.BinarySearch(A, 5, FoundIndex) then
+    Writeln('5 is found, its index ', FoundIndex)
+  else
+    Writeln('5 not found!');
+  Writeln;
+
+  // Search for an existing item with default comparer
+  Writeln('BinarySearch for an existing item ');
+  if TArrayHelper<Integer>.BinarySearch(A, 6, FoundIndex) then
+    Writeln('6 is found, its index ', FoundIndex)
+  else
+    Writeln('6 not found!');
+  Writeln;
+
+  // Search for an existing item with custom comparer
+  Writeln('BinarySearch for an existing item with custom comparer');
+  if TArrayHelper<Integer>.BinarySearch(A, 6, FoundIndex,
+    TComparer<Integer>.Construct(CompareIntReverse)) then
+    Writeln('6 is found, its index ', FoundIndex)
+  else
+    Writeln('6 not found!');
+  Writeln;
+
+  Readln;
+end.
+

+ 66 - 0
packages/rtl-generics/examples/tcomparer/tcomparerproject.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="TComparerProject"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="tcomparerproject.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="tcomparerproject"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 124 - 0
packages/rtl-generics/examples/tcomparer/tcomparerproject.lpr

@@ -0,0 +1,124 @@
+// Generic types for FreeSparta.com and FreePascal!
+// by Maciej Izak (hnb), 2014
+
+program TComparerProject;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, Generics.Collections, Generics.Defaults;
+
+type
+
+  { TCustomer }
+
+  TCustomer = record
+  private
+    FName: string;
+    FMoney: Currency;
+  public
+    constructor Create(const Name: string; Money: Currency);
+    property Name: string read FName write FName;
+    property Money: Currency read FMoney write FMoney;
+    function ToString: string;
+  end;
+
+  TCustomerComparer = class(TComparer<TCustomer>)
+    function Compare(constref Left, Right: TCustomer): Integer; override;
+  end;
+
+{ TCustomer }
+
+constructor TCustomer.Create(const Name: string; Money: Currency);
+begin
+  FName := Name;
+  FMoney := Money;
+end;
+
+function TCustomer.ToString: string;
+begin
+  Result := Format('Name: %s >>> Money: %m', [Name, Money]);
+end;
+
+// Ascending
+function TCustomerComparer.Compare(constref Left, Right: TCustomer): Integer;
+begin
+  Result := TCompare.&String(Left.Name, Right.Name);
+  if Result = 0 then
+    Result := TCompare.Currency(Left.Money, Right.Money);
+end;
+
+// Descending
+function CustomerCompare(constref Left, Right: TCustomer): Integer;
+begin
+  Result := TCompare.&String(Right.Name, Left.Name);
+  if Result = 0 then
+    Result := TCompare.Currency(Right.Money, Left.Money);
+end;
+
+var
+  CustomersArray: TArray<TCustomer>;
+  CustomersList: TList<TCustomer>;
+  Comparer: TCustomerComparer;
+  Customer: TCustomer;
+begin
+  CustomersArray := TArray<TCustomer>.Create(
+    TCustomer.Create('Derp', 2000),
+    TCustomer.Create('Sheikh', 2000000000),
+    TCustomer.Create('Derp', 1000),
+    TCustomer.Create('Bill Gates', 1000000000));
+
+  Comparer := TCustomerComparer.Create;
+  Comparer._AddRef;
+
+  // create TList with custom comparer
+  CustomersList := TList<TCustomer>.Create(Comparer);
+  CustomersList.AddRange(CustomersArray);
+
+  WriteLn('CustomersList before sort:');
+  for Customer in CustomersList do
+    WriteLn(Customer.ToString);
+  WriteLn;
+
+  // default sort
+  CustomersList.Sort; // will use TCustomerComparer (passed in the constructor)
+  WriteLn('CustomersList after ascending sort (default with interface from constructor):');
+  for Customer in CustomersList do
+    WriteLn(Customer.ToString);
+  WriteLn;
+
+  // construct with simple function
+  CustomersList.Sort(TComparer<TCustomer>.Construct(CustomerCompare));
+  WriteLn('CustomersList after descending sort (by using construct with function)');
+  WriteLn('CustomersList.Sort(TComparer<TCustomer>.Construct(CustomerCompare)):');
+  for Customer in CustomersList do
+    WriteLn(Customer.ToString);
+  WriteLn;
+
+  // construct with method
+  CustomersList.Sort(TComparer<TCustomer>.Construct(Comparer.Compare));
+  WriteLn('CustomersList after ascending sort (by using construct with method)');
+  WriteLn('CustomersList.Sort(TComparer<TCustomer>.Construct(Comparer.Compare)):');
+  for Customer in CustomersList do
+    WriteLn(Customer.ToString);
+  WriteLn;
+
+  WriteLn('CustomersArray before sort:');
+  for Customer in CustomersArray do
+    WriteLn(Customer.ToString);
+  WriteLn;
+
+  // sort with interface
+  TArrayHelper<TCustomer>.Sort(CustomersArray, TCustomerComparer.Create);
+  WriteLn('CustomersArray after ascending sort (by using interfese - no construct)');
+  WriteLn('TArrayHelper<TCustomer>.Sort(CustomersArray, TCustomerComparer.Create):');
+  for Customer in CustomersArray do
+    WriteLn(Customer.ToString);
+  WriteLn;
+
+  CustomersList.Free;
+  Comparer._Release;
+  ReadLn;
+end.
+

+ 71 - 0
packages/rtl-generics/examples/thashmap/thashmapproject.lpi

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="THashMapProject"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="thashmapproject.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="thashmapproject"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <SyntaxMode Value="Delphi"/>
+      </SyntaxOptions>
+    </Parsing>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 218 - 0
packages/rtl-generics/examples/thashmap/thashmapproject.lpr

@@ -0,0 +1,218 @@
+// Generic types for FreeSparta.com and FreePascal!
+// Original version by keeper89.blogspot.com, 2011
+// FPC version by Maciej Izak (hnb), 2014
+
+program THashMapProject;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, Generics.Collections, Generics.Defaults;
+
+type
+  TSubscriberInfo = record
+    Name, SName: string;
+    class function Create(const Name, SName: string): TSubscriberInfo; static;
+    function ToString: string;
+  end;
+
+  // Class containing handlers add / remove items in the dictionary
+  THashMapEventsHandler = class
+  public
+    class procedure OnKeyNotify(Sender: TObject; constref Item: string;
+      Action: TCollectionNotification);
+    class procedure OnValueNotify(Sender: TObject; constref Item: TSubscriberInfo;
+      Action: TCollectionNotification);
+  end;
+
+class function TSubscriberInfo.Create(const Name,
+  SName: string): TSubscriberInfo;
+begin
+  Result.Name := Name;
+  Result.SName := SName;
+end;
+
+function TSubscriberInfo.ToString: string;
+begin
+  Result := Format('%s %s', [Name, SName]);
+end;
+
+// Function to generate the dictionary contents into a string
+function PrintTelephoneDirectory(
+  TelephoneDirectory: THashMap<string, TSubscriberInfo>): string;
+var
+  PhoneNumber: string;
+begin
+  Result := Format('Content directory (%d):', [TelephoneDirectory.Count]);
+
+  for PhoneNumber in TelephoneDirectory.Keys do
+    Result := Result + Format(LineEnding + '%s: %s',
+      [PhoneNumber, TelephoneDirectory[PhoneNumber].ToString]);
+end;
+
+// Handlers add / remove items dictionary
+class procedure THashMapEventsHandler.OnKeyNotify(Sender: TObject;
+  constref Item: string; Action: TCollectionNotification);
+begin
+  case Action of
+    cnAdded:
+      Writeln(Format('OnKeyNotify! Phone %s added!', [Item]));
+    cnRemoved:
+      Writeln(Format('OnKeyNotify! Number %s deleted!', [Item]));
+  end;
+end;
+
+class procedure THashMapEventsHandler.OnValueNotify(Sender: TObject;
+  constref Item: TSubscriberInfo; Action: TCollectionNotification);
+begin
+  case Action of
+    cnAdded:
+      Writeln(Format('OnValueNotify! Subscriber %s added!', [Item.ToString]));
+    cnRemoved:
+      Writeln(Format('OnValueNotify! Subscriber %s deleted!', [Item.ToString]));
+  end;
+end;
+
+function CustomCompare(constref Left, Right: TPair<string, TSubscriberInfo>): Integer;
+begin
+  // Comparable full first names, and then phones if necessary
+  Result := TCompare.&String(Left.Value.ToString, Right.Value.ToString);
+  if Result = 0 then
+    Result := TCompare.&String(Left.Key, Right.Key);
+end;
+
+var
+  // Declare the "dictionary"
+  // key is the telephone number which will be possible
+  // to determine information about the owner
+  TelephoneDirectory: THashMap<string, TSubscriberInfo>;
+  TTelephoneArray: array of TPair<string, TSubscriberInfo>;
+  TTelephoneArrayItem: TPair<string, TSubscriberInfo>;
+  PhoneNumber: string;
+  Subscriber: TSubscriberInfo;
+begin
+  WriteLn('Working with THashMap - phonebook');
+  WriteLn;
+
+  // create a directory
+  // Constructor has several overloaded options which will
+  // enable the capacity of the container, a comparator for values
+  // or the initial data - we use the easiest option
+  TelephoneDirectory := THashMap<string, TSubscriberInfo>.Create;
+
+  // ---------------------------------------------------
+  // 1) Adding items to dictionary
+
+  // Add new users to the phonebook
+  TelephoneDirectory.Add('9201111111', TSubscriberInfo.Create('Arnold', 'Schwarzenegger'));
+  TelephoneDirectory.Add('9202222222', TSubscriberInfo.Create('Jessica', 'Alba'));
+  TelephoneDirectory.Add('9203333333', TSubscriberInfo.Create('Brad', 'Pitt'));
+  TelephoneDirectory.Add('9204444444', TSubscriberInfo.Create('Brad', 'Pitt'));
+  TelephoneDirectory.Add('9205555555', TSubscriberInfo.Create('Sandra', 'Bullock'));
+  // Adding a new subscriber if number already exist
+  TelephoneDirectory.AddOrSetValue('9204444444',
+                                   TSubscriberInfo.Create('Angelina', 'Jolie'));
+  // Print list
+  Writeln(PrintTelephoneDirectory(TelephoneDirectory));
+
+  // ---------------------------------------------------
+  // 2) Working with the elements
+
+  // Set the "capacity" of the dictionary according to the current number of elements
+  TelephoneDirectory.TrimExcess;
+  // Is there a key? - ContainsKey
+  if TelephoneDirectory.ContainsKey('9205555555') then
+    Writeln('Phone 9205555555 registered!');
+  // Is there a subscriber? - ContainsValue
+  Subscriber := TSubscriberInfo.Create('Sandra', 'Bullock');
+  if TelephoneDirectory.ContainsValue(Subscriber) then
+    Writeln(Format('%s is in the directory!', [Subscriber.ToString]));
+  // Try to get information via telephone. TryGetValue
+  if TelephoneDirectory.TryGetValue('9204444444', Subscriber) then
+    Writeln(Format('Number 9204444444 belongs to %s', [Subscriber.ToString]));
+  // Directly access by phone number
+  Writeln(Format('Phone 9201111111 subscribers: %s', [TelephoneDirectory['9201111111'].ToString]));
+  // Number of people in the directory
+  Writeln(Format('Total subscribers in the directory: %d', [TelephoneDirectory.Count]));
+
+  // ---------------------------------------------------
+  // 3) Delete items
+
+  // Schwarzenegger now will not be listed
+  TelephoneDirectory.Remove('9201111111');
+  // Completely clear the list
+  TelephoneDirectory.Clear;
+
+  // ---------------------------------------------------
+  //   4) Events add / remove values
+  //
+  // Events OnKeyNotify OnValueNotify are designed for "tracking"
+  // for adding / removing keys and values ​​respectively
+  TelephoneDirectory.OnKeyNotify := THashMapEventsHandler.OnKeyNotify;
+  TelephoneDirectory.OnValueNotify := THashMapEventsHandler.OnValueNotify;
+
+  Writeln;
+  // Try events
+  TelephoneDirectory.Add('9201111111', TSubscriberInfo.Create('Arnold', 'Schwarzenegger'));
+  TelephoneDirectory.Add('9202222222', TSubscriberInfo.Create('Jessica', 'Alba'));
+  TelephoneDirectory['9202222222'] := TSubscriberInfo.Create('Monica', 'Bellucci');
+  TelephoneDirectory.Clear;
+  WriteLn;
+
+  TelephoneDirectory.Add('9201111111', TSubscriberInfo.Create('Monica', 'Bellucci'));
+  TelephoneDirectory.Add('9202222222', TSubscriberInfo.Create('Sylvester', 'Stallone'));
+  TelephoneDirectory.Add('9203333333', TSubscriberInfo.Create('Bruce', 'Willis'));
+  WriteLn;
+
+  // Show keys (phones)
+  Writeln('Keys (phones):');
+  for PhoneNumber in TelephoneDirectory.Keys do
+    Writeln(PhoneNumber);
+  Writeln;
+
+  // Show values ​​(subscribers)
+  Writeln('Values (subscribers):');
+  for Subscriber in TelephoneDirectory.Values do
+    Writeln(Subscriber.ToString);
+  Writeln;
+
+  // All together now
+  Writeln('Subscribers list with phones:');
+  for PhoneNumber in TelephoneDirectory.Keys do
+    Writeln(Format('%s: %s',
+      [PhoneNumber, TelephoneDirectory[PhoneNumber].ToString]));
+  Writeln;
+
+  // In addition, we can "export" from the dictionary
+  // to TArray
+  // Sort the resulting array and display
+  TTelephoneArray := TelephoneDirectory.ToArray;
+
+  // partial specializations not allowed
+  // same for anonymous methods
+  //TArray.Sort<TPair<string, TSubscriberInfo>>(
+  //  TTelephoneArray, TComparer<TPair<string, TSubscriberInfo>>.Construct(
+  //    function (const Left, Right: TPair<string, TSubscriberInfo>): Integer
+  //    begin
+  //      // Comparable full first names, and then phones if necessary
+  //      Result := CompareStr(Left.Value.ToString, Right.Value.ToString);
+  //      if Result = 0 then
+  //        Result := CompareStr(Left.Key, Right.Key);
+  //    end));
+
+  TArrayHelper<TelephoneDirectory.TDictionaryPair>.Sort(
+    TTelephoneArray, TComparer<TelephoneDirectory.TDictionaryPair>.Construct(
+      CustomCompare));
+  // Print
+  Writeln('Sorted list of subscribers into TArray (by name, and eventually by phone):');
+  for TTelephoneArrayItem in TTelephoneArray do
+    Writeln(Format('%s: %s',
+      [TTelephoneArrayItem.Value.ToString, TTelephoneArrayItem.Key]));
+
+  Writeln;
+  FreeAndNil(TelephoneDirectory);
+
+  Readln;
+end.
+

+ 66 - 0
packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="THashMapCaseInsensitive"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="thashmapcaseinsensitive.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="thashmapcaseinsensitive"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 55 - 0
packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpr

@@ -0,0 +1,55 @@
+// Generic types for FreeSparta.com and FreePascal!
+// by Maciej Izak (hnb), 2014
+
+program THashMapCaseInsensitive;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  Generics.Collections, Generics.Defaults;
+
+var
+  StringMap: THashMap<String, TEmptyRecord>;
+  AnsiStringMap: THashMap<AnsiString, TEmptyRecord>;
+  UnicodeStringMap: THashMap<UnicodeString, TEmptyRecord>;
+  AdvancedHashMapWithBigLoadFactor: TCuckooD6<RawByteString, TEmptyRecord>;
+  k: String;
+begin
+  WriteLn('Working with case insensitive THashMap');
+  WriteLn;
+  // example constructors for different string types
+  StringMap := THashMap<String, TEmptyRecord>.Create(TIStringComparer.Ordinal);
+  StringMap.Free;
+  AnsiStringMap := THashMap<AnsiString, TEmptyRecord>.Create(TIAnsiStringComparer.Ordinal);
+  AnsiStringMap.Free;
+  UnicodeStringMap := THashMap<UnicodeString, TEmptyRecord>.Create(TIUnicodeStringComparer.Ordinal);
+  UnicodeStringMap.Free;
+
+  // standard TI*Comparer is dedicated for MAX_HASHLIST_COUNT = 4 and lower. For example DArrayCuckoo where D = 6
+  // we need to create extra specialized TGIStringComparer type
+  AdvancedHashMapWithBigLoadFactor := TCuckooD6<RawByteString, TEmptyRecord>.Create(
+    TGIStringComparer<RawByteString, TDelphiSixfoldHashFactory>.Ordinal);
+  AdvancedHashMapWithBigLoadFactor.Free;
+
+  // ok lets start
+  // another way to create case insensitive hash map
+  StringMap := THashMap<String, TEmptyRecord>.Create(TGIStringComparer<String>.Ordinal);
+
+  WriteLn('Add Cat and Dog');
+  StringMap.Add('Cat', EmptyRecord);
+  StringMap.Add('Dog', EmptyRecord);
+
+  //
+  WriteLn('Contains CAT = ', StringMap.ContainsKey('CAT'));
+  WriteLn('Contains dOG = ', StringMap.ContainsKey('dOG'));
+  WriteLn('Contains Fox = ', StringMap.ContainsKey('Fox'));
+
+  WriteLn('Enumerate all keys :');
+  for k in StringMap.Keys do
+    WriteLn(' > ', k);
+
+  ReadLn;
+  StringMap.Free;
+end.
+

+ 66 - 0
packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="THashMapExtendedEqualityComparer"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="thashmapextendedequalitycomparer.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="thashmapextendedequalitycomparer"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 108 - 0
packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpr

@@ -0,0 +1,108 @@
+// Generic types for FreeSparta.com and FreePascal!
+// by Maciej Izak (hnb), 2014
+
+program THashMapExtendedEqualityComparer;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, Generics.Collections, Generics.Defaults;
+
+type
+
+  { TTaxPayer }
+
+  TTaxPayer = record
+    TaxID: Integer;
+    Name: string;
+
+    constructor Create(ATaxID: Integer; const AName: string);
+    function ToString: string;
+  end;
+
+constructor TTaxPayer.Create(ATaxID: Integer; const AName: string);
+begin
+  TaxID := ATaxID;
+  Name := AName;
+end;
+
+function TTaxPayer.ToString: string;
+begin
+  Result := Format('TaxID = %-10d Name = %-17s', [TaxID, Name]);
+end;
+
+function EqualityComparison(constref ALeft, ARight: TTaxPayer): Boolean;
+begin
+  Result := ALeft.TaxID = ARight.TaxID;
+end;
+
+procedure ExtendedHasher(constref AValue: TTaxPayer; AHashList: PUInt32);
+begin
+  // don't work with TCuckooD6 map because default TCuckooD6 needs TDelphiSixfoldHashFactory
+  // and TDefaultHashFactory = TDelphiQuadrupleHashFactory
+  // (TDelphiQuadrupleHashFactory is compatible with TDelphiDoubleHashFactory and TDelphiHashFactory)
+  TDefaultHashFactory.GetHashList(@AValue.TaxID, SizeOf(Integer), AHashList);
+end;
+
+var
+  map: THashMap<TTaxPayer, string>; // THashMap = TCuckooD4
+  LTaxPayer: TTaxPayer;
+  LSansa: TTaxPayer;
+  LPair: TPair<TTaxPayer, string>;
+begin
+  WriteLn('program of tax office - ExtendedEqualityComparer for THashMap');
+  WriteLn;
+
+  // to identify the taxpayer need only nip
+  map := THashMap<TTaxPayer, string>.Create(
+    TExtendedEqualityComparer<TTaxPayer>.Construct(EqualityComparison, ExtendedHasher));
+
+  map.Add(TTaxPayer.Create(1234567890, 'Joffrey Baratheon'), 'guilty');
+  map.Add(TTaxPayer.Create(90, 'Little Finger'), 'swindler');
+  map.Add(TTaxPayer.Create(667, 'John Snow'), 'delinquent tax');
+
+  // useless in this place but we can convert Keys to TArray<TKey> :)
+  WriteLn(Format('All taxpayers (count = %d)', [Length(map.Keys.ToArray)]));
+  for LTaxPayer in map.Keys do
+    WriteLn(' > ', LTaxPayer.ToString);
+
+  LSansa := TTaxPayer.Create(667, 'Sansa Stark');
+
+  // exist because custom EqualityComparison and ExtendedHasher
+  WriteLn;
+  WriteLn(LSansa.Name, ' exist in map = ',  map.ContainsKey(LSansa));
+  WriteLn;
+
+  //
+  WriteLn('All taxpayers');
+  for LPair in map do
+    WriteLn(' > ', LPair.Key.ToString, ' is ', LPair.Value);
+
+  // Add or set sansa? :)
+  WriteLn;
+  WriteLn(Format('AddOrSet(%s, ''innocent'')', [LSansa.ToString]));
+  map.AddOrSetValue(LSansa, 'innocent');
+  WriteLn;
+
+  //
+  WriteLn('All taxpayers');
+  for LPair in map do
+    WriteLn(' > ', LPair.Key.ToString, ' is ', LPair.Value);
+
+  // Add or set sansa? :)
+  WriteLn;
+  LSansa.TaxID := 668;
+  WriteLn(Format('AddOrSet(%s, ''innocent'')', [LSansa.ToString]));
+  map.AddOrSetValue(LSansa, 'innocent');
+  WriteLn;
+
+  //
+  WriteLn('All taxpayers');
+  for LPair in map do
+    WriteLn(' > ', LPair.Key.ToString, ' is ', LPair.Value);
+
+  ReadLn;
+  map.Free;
+end.
+

+ 66 - 0
packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="TObjectListProject"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="tobjectlistproject.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="tobjectlistproject"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 194 - 0
packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpr

@@ -0,0 +1,194 @@
+// Generic types for FreeSparta.com and FreePascal!
+// Original version by keeper89.blogspot.com, 2011
+// FPC version by Maciej Izak (hnb), 2014
+
+program TObjectListProject;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, Generics.Collections, Generics.Defaults, DateUtils;
+
+type
+  TPlayer = class
+  public
+    Name, Team: string;
+    BirthDay: TDateTime;
+    NTeamGoals: Byte; // Number of goals for the national team
+    constructor Create(const Name: string; BirthDay: TDateTime;
+      const Team: string; NTeamGoals: Byte = 0);
+    function ToString: string;
+  end;
+
+  // Class containing handlers add / remove list items
+  TListEventsHandler = class
+  public
+    class procedure OnListChanged(Sender: TObject; constref Item: TPlayer;
+      Action: TCollectionNotification);
+  end;
+
+
+constructor TPlayer.Create(const Name: string; BirthDay: TDateTime;
+  const Team: string; NTeamGoals: Byte);
+begin
+  Self.Name := Name;
+  Self.BirthDay := BirthDay;
+  Self.Team := Team;
+  Self.NTeamGoals := NTeamGoals;
+end;
+
+function TPlayer.ToString: string;
+begin
+  Result := Format('%s - Age: %d Team: %s Goals: %d',
+                   [Name,
+                    DateUtils.YearsBetween(Date, BirthDay),
+                    Team, NTeamGoals])
+end;
+
+// Function sort descending goals for the national team
+function ComparePlayersByGoalsDecs(constref Player1, Player2: TPlayer): Integer;
+begin
+  Result := TCompare.UInt8(Player2.NTeamGoals, Player1.NTeamGoals);
+end;
+
+class procedure TListEventsHandler.OnListChanged(Sender: TObject; constref Item: TPlayer;
+  Action: TCollectionNotification);
+var
+  Mes: string;
+begin
+  // Unlike TDictionary we added Action = cnExtracted
+  case Action of
+    cnAdded:
+      Mes := 'added to the list!';
+    cnRemoved:
+      Mes := 'removed from the list!';
+    cnExtracted:
+      Mes := 'extracted from the list!';
+  end;
+  Writeln(Format('Football player %s %s ', [Item.ToString, Mes]));
+end;
+
+var
+  // Declare TObjectList as storage for TPlayer
+  PlayersList: TObjectList<TPlayer>;
+  Player: TPlayer;
+  FoundIndex: PtrInt;
+begin
+  WriteLn('Working with TObjectList - football manager');
+  WriteLn;
+
+  PlayersList := TObjectList<TPlayer>.Create;
+
+  // ---------------------------------------------------
+  // 1) Adding items
+
+  PlayersList.Add(
+    TPlayer.Create('Zinedine Zidane', EncodeDate(1972, 06, 23), 'France', 31));
+  PlayersList.Add(
+    TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44));
+  PlayersList.Add(
+    TPlayer.Create('Ronaldo', EncodeDate(1976, 09, 22), 'Brazil', 62));
+   // Adding the specified position
+  PlayersList.Insert(0,
+    TPlayer.Create('Luis Figo', EncodeDate(1972, 11, 4), 'Portugal', 33));
+  // Add a few players through InsertRange (AddRange works similarly)
+  PlayersList.InsertRange(0,
+    [TPlayer.Create('David Beckham', EncodeDate(1975, 05, 2), 'England', 17),
+     TPlayer.Create('Alessandro Del Piero', EncodeDate(1974, 11, 9), 'Italy ', 27),
+     TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44)]);
+  Player := TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44);
+  PlayersList.Add(Player);
+
+
+  // ---------------------------------------------------
+  // 2) Access and check the items
+
+  // Is there a player in the list - Contains
+  if PlayersList.Contains(Player) then
+    Writeln('Raul is in the list!');
+  // Player index and count of items in the list
+  Writeln(Format('Raul is %d-th on the list of %d players.',
+                 [PlayersList.IndexOf(Player) + 1, PlayersList.Count]));
+  // Index access
+  Writeln(Format('1st in the list: %s', [PlayersList[0].ToString]));
+  // The first player
+  Writeln(Format('1st in the list: %s', [PlayersList.First.ToString]));
+  // The last player
+  Writeln(Format('Last in the list: %s', [PlayersList.Last.ToString]));
+  // "Reverse" elements
+  PlayersList.Reverse;
+  Writeln('List items have been "reversed"');
+  Writeln;
+
+
+  // ---------------------------------------------------
+  // 3) Moving and removing items
+
+  // Changing places players in the list
+  PlayersList.Exchange(0, 1);
+  // Move back 1 player
+  PlayersList.Move(1, 0);
+
+  // Removes the element at index
+  PlayersList.Delete(5);
+  // Or a number of elements starting at index
+  PlayersList.DeleteRange(5, 2);
+  // Remove the item from the list, if the item
+  // exists returns its index in the list
+  Writeln(Format('Removed %d-st player', [PlayersList.Remove(Player) + 1]));
+
+  // Extract and return the item, if there is no Player in the list then
+  // Extract will return = nil, (anyway Raul is already removed via Remove)
+  Player := PlayersList.Extract(Player);
+  if Assigned(Player) then
+    Writeln(Format('Extracted: %s', [Player.ToString]));
+
+  // Clear the list completely
+  PlayersList.Clear;
+  Writeln;
+
+  // ---------------------------------------------------
+  // 4) Event OnNotify, sorting and searching
+
+  PlayersList.OnNotify := TListEventsHandler.OnListChanged;
+
+  PlayersList.Add(
+    TPlayer.Create('Zinedine Zidane', EncodeDate(1972, 06, 23), 'France', 31));
+  PlayersList.Add(
+    TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44));
+  PlayersList.Add(
+    TPlayer.Create('Ronaldo', EncodeDate(1976, 09, 22), 'Brazil', 62));
+  PlayersList.AddRange(
+    [TPlayer.Create('David Beckham', EncodeDate(1975, 05, 2), 'England', 17),
+     TPlayer.Create('Alessandro Del Piero', EncodeDate(1974, 11, 9), 'Italy ', 27),
+     TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44)]);
+
+  PlayersList.Remove(PlayersList.Last);
+  Player := PlayersList.Extract(PlayersList[0]);
+
+  PlayersList.Sort(TComparer<TPlayer>.Construct(ComparePlayersByGoalsDecs));
+  Writeln;
+  Writeln('Sorted list of players:');
+  for Player in PlayersList do
+    Writeln(Player.ToString);
+  Writeln;
+
+  // Find Ronaldo!
+  // TArray BinarySearch requires sorted list
+  // IndexOf does not require sorted list
+  // but BinarySearch is usually faster
+  Player := PlayersList[0];
+  if PlayersList.BinarySearch(Player, FoundIndex,
+    TComparer<TPlayer>.Construct(ComparePlayersByGoalsDecs)) then
+    Writeln(Format('Ronaldo is in the sorted list at position %d', [FoundIndex + 1]));
+
+  Writeln;
+
+  // With the destruction of the list remove all elements
+  // OnNotify show it
+  FreeAndNil(PlayersList);
+
+  Readln;
+end.
+

+ 66 - 0
packages/rtl-generics/examples/tqueue/tqueueproject.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="TQueueProject"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="tqueueproject.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="tqueueproject"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 89 - 0
packages/rtl-generics/examples/tqueue/tqueueproject.lpr

@@ -0,0 +1,89 @@
+// Generic types for FreeSparta.com and FreePascal!
+// Original version by keeper89.blogspot.com, 2011
+// FPC version by Maciej Izak (hnb), 2014
+
+program TQueueProject;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, Generics.Collections;
+
+type
+  // This is FreeSpaaarta! versions =)
+  TSpartaVersion = (svFreeSparta, svBasic, svStarter, svProfessional);
+
+  TCustomer = record
+    strict private
+      const
+        SV_NAMES: array [TSpartaVersion] of string =
+          ('FreeSparta', 'Basic', 'Starter', 'Professional');
+    public
+      var
+        SpartaVersion: TSpartaVersion;
+    class function Create(SpartaVersion: TSpartaVersion): TCustomer; static;
+    function ToString: string;
+  end;
+
+class function TCustomer.Create(SpartaVersion: TSpartaVersion): TCustomer;
+begin
+  Result.SpartaVersion := SpartaVersion;
+end;
+
+function TCustomer.ToString: string;
+begin
+  Result := Format('Sparta %s', [SV_NAMES[SpartaVersion]])
+end;
+
+var
+  CustomerQueue: TQueue<TCustomer>;
+  Customer: TCustomer;
+begin
+  WriteLn('Working with TQueue - buy FreeSparta.com');
+  WriteLn;
+
+  // "Create" turn in sales
+  CustomerQueue := TQueue<TCustomer>.Create;
+
+  // Add a few people in the queue
+  // Enqueue - puts the item in the queue
+  CustomerQueue.Enqueue(TCustomer.Create(svFreeSparta));
+  CustomerQueue.Enqueue(TCustomer.Create(svBasic));
+  CustomerQueue.Enqueue(TCustomer.Create(svBasic));
+  CustomerQueue.Enqueue(TCustomer.Create(svBasic));
+  CustomerQueue.Enqueue(TCustomer.Create(svStarter));
+  CustomerQueue.Enqueue(TCustomer.Create(svStarter));
+  CustomerQueue.Enqueue(TCustomer.Create(svProfessional));
+  CustomerQueue.Enqueue(TCustomer.Create(svProfessional));
+
+  // Part of customers served
+  // Dequeue - remove an element from the queue
+  // btw if TQueue is TObjectQueue also call Free for object
+  Customer := CustomerQueue.Dequeue;
+  Writeln(Format('Sold (Dequeue): %s', [Customer.ToString]));
+  // Extract - similar to Dequeue, but causes in OnNotify
+  // Action = cnExtracted instead cnRemoved
+  Customer := CustomerQueue.Extract;
+  Writeln(Format('Sold (Extract): %s', [Customer.ToString]));
+
+  // For what came next buyer?
+  // Peek - returns the first element, but does not remove it from the queue
+  Writeln(Format('Serves customers come for %s',
+                 [CustomerQueue.Peek.ToString]));
+
+  // The remaining buyers
+  Writeln;
+  Writeln(Format('Buyers left: %d', [CustomerQueue.Count]));
+  for Customer in CustomerQueue do
+    Writeln(Customer.ToString);
+
+  // We serve all
+  // Clear - clears the queue
+  CustomerQueue.Clear;
+
+  FreeAndNil(CustomerQueue);
+
+  Readln;
+end.
+

+ 66 - 0
packages/rtl-generics/examples/tstack/tstackproject.lpi

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="TStackProject"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="tstackproject.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="tstackproject"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..\..\src"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 86 - 0
packages/rtl-generics/examples/tstack/tstackproject.lpr

@@ -0,0 +1,86 @@
+// Generic types for FreeSparta.com and FreePascal!
+// Original version by keeper89.blogspot.com, 2011
+// FPC version by Maciej Izak (hnb), 2014
+program TStackProject;
+
+{$MODE DELPHI}
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils,
+  Windows,
+  Generics.Collections;
+
+type
+  // We will cook pancakes, put them on a plate and take the last
+  TPancakeType = (ptMeat, ptCherry, ptCurds);
+
+  TPancake = record
+    strict private
+      const
+        PANCAKE_TYPE_NAMES: array [TPancakeType] of string =
+          ('meat', 'cherry', 'curds');
+    public
+      var
+        PancakeType: TPancakeType;
+    class function Create(PancakeType: TPancakeType): TPancake; static;
+    function ToString: string;
+  end;
+
+class function TPancake.Create(PancakeType: TPancakeType): TPancake;
+begin
+  Result.PancakeType := PancakeType;
+end;
+
+function TPancake.ToString: string;
+begin
+  Result := Format('Pancake with %s', [PANCAKE_TYPE_NAMES[PancakeType]])
+end;
+
+var
+  PancakesPlate: TStack<TPancake>;
+  Pancake: TPancake;
+
+begin
+  WriteLn('Working with TStack - pancakes');
+  WriteLn;
+
+  // "Create" a plate of pancakes
+  PancakesPlate := TStack<TPancake>.Create;
+
+  // Bake some pancakes
+  // Push - puts items on the stack
+  PancakesPlate.Push(TPancake.Create(ptMeat));
+  PancakesPlate.Push(TPancake.Create(ptCherry));
+  PancakesPlate.Push(TPancake.Create(ptCherry));
+  PancakesPlate.Push(TPancake.Create(ptCurds));
+  PancakesPlate.Push(TPancake.Create(ptMeat));
+
+  // Eating some pancakes
+  // Pop - removes an item from the stack
+  Pancake := PancakesPlate.Pop;
+  Writeln(Format('Ate a pancake (Pop): %s', [Pancake.ToString]));
+  // Extract - similar to Pop, but causes in OnNotify
+  // Action = cnExtracted instead of cnRemoved
+  Pancake := PancakesPlate.Extract;
+  Writeln(Format('Ate a pancake (Extract): %s', [Pancake.ToString]));
+
+  // What is the last pancake?
+  // Peek - returns the last item, but does not remove it from the stack
+  Writeln(Format('Last pancake: %s', [PancakesPlate.Peek.ToString]));
+
+  // Show the remaining pancakes
+  Writeln;
+  Writeln(Format('Total pancakes: %d', [PancakesPlate.Count]));
+  for Pancake in PancakesPlate do
+    Writeln(Pancake.ToString);
+
+  // Eat up all
+  // Clear - clears the stack
+  PancakesPlate.Clear;
+
+  FreeAndNil(PancakesPlate);
+
+  Readln;
+end.
+

+ 78 - 0
packages/rtl-generics/fpmake.pp

@@ -0,0 +1,78 @@
+{$ifndef ALLPACKAGES}
+program fpmake;
+
+{$mode objfpc}{$h+}
+
+uses fpmkunit;
+{$endif}
+
+Procedure add_rtl_generics(ADirectory : string);
+
+Var
+  P : TPackage;
+  T : TTarget;
+
+begin
+  With Installer do
+    begin
+    P:=AddPackage('rtl-generics');
+    P.ShortName:='rtlgen';
+    P.Author := 'Maciej Izak';
+    P.License := 'LGPL with modification, ';
+    P.HomepageURL := 'www.freepascal.org';
+    P.Email := '';
+    P.Description := 'Generic collection library.';
+    P.NeedLibC:= false;
+    P.OSes := AllOSes;
+    P.Directory:=ADirectory;
+    P.Version:='3.1.1';
+    P.Dependencies.Add('rtl-objpas');
+    P.SourcePath.Add('src');
+    P.IncludePath.Add('src/inc');
+    T:=P.Targets.AddUnit('generics.collections.pas');
+    with T.Dependencies do
+      begin
+        AddUnit('generics.memoryexpanders');
+        AddUnit('generics.defaults');
+        AddUnit('generics.helpers');
+        AddUnit('generics.strings');
+      end;
+    T:=P.Targets.AddUnit('generics.defaults.pas');
+    with T.Dependencies do
+      begin
+        AddUnit('generics.hashes');
+        AddUnit('generics.strings');
+        AddUnit('generics.helpers');
+      end;
+    T:=P.Targets.AddUnit('generics.hashes.pas');
+    T:=P.Targets.AddUnit('generics.helpers.pas');
+    T:=P.Targets.AddUnit('generics.memoryexpanders.pas');
+    T:=P.Targets.AddUnit('generics.strings.pas');
+    // Examples
+    P.ExamplePath.Add('examples/tarraydouble');
+    T:=P.Targets.AddExampleProgram('tarrayprojectdouble.lpr');
+    P.ExamplePath.Add('examples/tarraysingle');
+    T:=P.Targets.AddExampleProgram('tarrayprojectsingle.lpr');
+    P.ExamplePath.Add('examples/tcomparer');
+    T:=P.Targets.AddExampleProgram('tcomparerproject.lpr');
+    P.ExamplePath.Add('examples/thashmap');
+    T:=P.Targets.AddExampleProgram('thashmapproject.lpr');
+    P.ExamplePath.Add('examples/thashmapcaseinsensitive');
+    T:=P.Targets.AddExampleProgram('thashmapcaseinsensitive.lpr');
+    P.ExamplePath.Add('examples/thashmapextendedequalitycomparer');
+    T:=P.Targets.AddExampleProgram('thashmapextendedequalitycomparer.lpr');
+    P.ExamplePath.Add('examples/tobjectlist');
+    T:=P.Targets.AddExampleProgram('tobjectlistproject.lpr');
+    P.ExamplePath.Add('examples/tqueue');
+    T:=P.Targets.AddExampleProgram('tqueueproject.lpr');
+    P.ExamplePath.Add('examples/tstack');
+    T:=P.Targets.AddExampleProgram('tstackproject.lpr');
+    end;
+end;
+
+{$ifndef ALLPACKAGES}
+begin
+  add_rtl_generics('');
+  Installer.Run;
+end.
+{$endif ALLPACKAGES}

+ 1265 - 0
packages/rtl-generics/src/generics.collections.pas

@@ -0,0 +1,1265 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit Generics.Collections;
+
+{$MODE DELPHI}{$H+}
+{$MACRO ON}
+{$COPERATORS ON}
+{$DEFINE CUSTOM_DICTIONARY_CONSTRAINTS := TKey, TValue, THashFactory}
+{$DEFINE OPEN_ADDRESSING_CONSTRAINTS := TKey, TValue, THashFactory, TProbeSequence}
+{$DEFINE CUCKOO_CONSTRAINTS := TKey, TValue, THashFactory, TCuckooCfg}
+{$WARNINGS OFF}
+{$HINTS OFF}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+
+interface
+
+uses
+    Classes, SysUtils, Generics.MemoryExpanders, Generics.Defaults, 
+    Generics.Helpers, Generics.Strings;
+
+{ FPC BUGS related to Generics.* (54 bugs, 19 fixed)
+  REGRESSION: 26483, 26481
+  FIXED REGRESSION: 26480, 26482
+
+  CRITICAL: 24848(!!!), 24872(!), 25607(!), 26030, 25917, 25918, 25620, 24283, 24254, 24287 (Related to? 24872)
+  IMPORTANT: 23862(!), 24097, 24285, 24286 (Similar to? 24285), 24098, 24609 (RTL inconsistency), 24534, 
+             25606, 25614, 26177, 26195
+  OTHER: 26484, 24073, 24463, 25593, 25596, 25597, 25602, 26181 (or MYBAD?)
+  CLOSED BUT IMO STILL TO FIX: 25601(!), 25594
+  FIXED: 25610(!), 24064, 24071, 24282, 24458, 24867, 24871, 25604, 25600, 25605, 25598, 25603, 25929, 26176, 26180,
+         26193, 24072
+  MYBAD: 24963, 25599
+}
+
+{ LAZARUS BUGS related to Generics.* (7 bugs, 0 fixed)
+  CRITICAL: 25613
+  OTHER: 25595, 25612, 25615, 25617, 25618, 25619
+}
+
+type
+  TArray<T> = array of T; // for name TArray<T> conflict with TArray record implementation (bug #26030)
+
+  // bug #24254 workaround
+  // should be TArray = record class procedure Sort<T>(...) etc.
+  TCustomArrayHelper<T> = class abstract
+  private
+    type
+      // bug #24282
+      TComparerBugHack = TComparer<T>;
+  protected
+    // modified QuickSort from classes\lists.inc
+    class procedure QuickSort(var AValues: array of T; ALeft, ARight: SizeInt; const AComparer: IComparer<T>);
+      virtual; abstract;
+  public
+    class procedure Sort(var AValues: array of T); overload;
+    class procedure Sort(var AValues: array of T;
+      const AComparer: IComparer<T>);   overload;
+    class procedure Sort(var AValues: array of T;
+      const AComparer: IComparer<T>; AIndex, ACount: SizeInt); overload;
+
+    class function BinarySearch(constref AValues: array of T; constref AItem: T;
+      out AFoundIndex: SizeInt; const AComparer: IComparer<T>;
+      AIndex, ACount: SizeInt): Boolean; virtual; abstract; overload;
+    class function BinarySearch(constref AValues: array of T; constref AItem: T;
+      out AFoundIndex: SizeInt; const AComparer: IComparer<T>): Boolean; overload;
+    class function BinarySearch(constref AValues: array of T; constref AItem: T;
+      out AFoundIndex: SizeInt): Boolean; overload;
+  end experimental; // will be renamed to TCustomArray (bug #24254)
+
+  TArrayHelper<T> = class(TCustomArrayHelper<T>)
+  protected
+    // modified QuickSort from classes\lists.inc
+    class procedure QuickSort(var AValues: array of T; ALeft, ARight: SizeInt; const AComparer: IComparer<T>); override;
+  public
+    class function BinarySearch(constref AValues: array of T; constref AItem: T;
+      out AFoundIndex: SizeInt; const AComparer: IComparer<T>;
+      AIndex, ACount: SizeInt): Boolean; override; overload;
+  end experimental; // will be renamed to TArray (bug #24254)
+
+  TCollectionNotification = (cnAdded, cnRemoved, cnExtracted);
+  TCollectionNotifyEvent<T> = procedure(ASender: TObject; constref AItem: T; AAction: TCollectionNotification)
+    of object;
+
+  { TEnumerator }
+
+  TEnumerator<T> = class abstract
+  protected
+    function DoGetCurrent: T; virtual; abstract;
+    function DoMoveNext: boolean; virtual; abstract;
+  public
+    property Current: T read DoGetCurrent;
+    function MoveNext: boolean;
+  end;
+
+  { TEnumerable }
+
+  TEnumerable<T> = class abstract
+  protected
+    function ToArrayImpl(ACount: SizeInt): TArray<T>; overload; // used by descendants
+  protected
+    function DoGetEnumerator: TEnumerator<T>; virtual; abstract;
+  public
+    function GetEnumerator: TEnumerator<T>; inline;
+    function ToArray: TArray<T>; virtual; overload;
+  end;
+
+  // More info: http://stackoverflow.com/questions/5232198/about-vectors-growth
+  // TODO: custom memory managers (as constraints)
+  {$DEFINE CUSTOM_LIST_CAPACITY_INC := Result + Result div 2} // ~approximation to golden ratio: n = n * 1.5 }
+  // {$DEFINE CUSTOM_LIST_CAPACITY_INC := Result * 2} // standard inc
+  TCustomList<T> = class abstract(TEnumerable<T>)
+  protected
+    type // bug #24282
+      TArrayHelperBugHack = TArrayHelper<T>;
+  private
+    FOnNotify: TCollectionNotifyEvent<T>;
+    function GetCapacity: SizeInt; inline;
+  protected
+    FItemsLength: SizeInt;
+    FItems: array of T;
+
+    function PrepareAddingItem: SizeInt; virtual;
+    function PrepareAddingRange(ACount: SizeInt): SizeInt; virtual;
+    procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); virtual;
+    function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; virtual;
+    procedure SetCapacity(AValue: SizeInt); virtual; abstract;
+    function GetCount: SizeInt; virtual;
+  public
+    function ToArray: TArray<T>; override; final;
+
+    property Count: SizeInt read GetCount;
+    property Capacity: SizeInt read GetCapacity write SetCapacity;
+    property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
+  end;
+
+  TCustomListEnumerator<T> = class abstract(TEnumerator< T >)
+  private
+    FList: TCustomList<T>;
+    FIndex: SizeInt;
+  protected
+    function DoMoveNext: boolean; override;
+    function DoGetCurrent: T; override;
+    function GetCurrent: T; virtual;
+  public
+    constructor Create(AList: TCustomList<T>);
+  end;
+
+  TList<T> = class(TCustomList<T>)
+  private var
+    FComparer: IComparer<T>;
+  protected
+    // bug #24287 - workaround for generics type name conflict (Identifier not found)
+    // next bug workaround - for another error related to previous workaround
+    // change order (method must be declared before TEnumerator declaration)
+    function DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; override;
+  public
+    // with this type declaration i found #24285, #24285
+    type
+      // bug workaround
+      TEnumerator = class(TCustomListEnumerator<T>);
+
+    function GetEnumerator: TEnumerator; reintroduce;
+  protected
+    procedure SetCapacity(AValue: SizeInt); override;
+    procedure SetCount(AValue: SizeInt);
+  private
+    function GetItem(AIndex: SizeInt): T;
+    procedure SetItem(AIndex: SizeInt; const AValue: T);
+  public
+    constructor Create; overload;
+    constructor Create(const AComparer: IComparer<T>); overload;
+    constructor Create(ACollection: TEnumerable<T>); overload;
+    destructor Destroy; override;
+
+    function Add(constref AValue: T): SizeInt;
+    procedure AddRange(constref AValues: array of T); overload;
+    procedure AddRange(const AEnumerable: IEnumerable<T>); overload;
+    procedure AddRange(AEnumerable: TEnumerable<T>); overload;
+
+    procedure Insert(AIndex: SizeInt; constref AValue: T);
+    procedure InsertRange(AIndex: SizeInt; constref AValues: array of T); overload;
+    procedure InsertRange(AIndex: SizeInt; const AEnumerable: IEnumerable<T>); overload;
+    procedure InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerable<T>); overload;
+
+    function Remove(constref AValue: T): SizeInt;
+    procedure Delete(AIndex: SizeInt); inline;
+    procedure DeleteRange(AIndex, ACount: SizeInt);
+    function ExtractIndex(const AIndex: SizeInt): T; overload;
+    function Extract(constref AValue: T): T; overload;
+
+    procedure Exchange(AIndex1, AIndex2: SizeInt);
+    procedure Move(AIndex, ANewIndex: SizeInt);
+
+    function First: T; inline;
+    function Last: T; inline;
+
+    procedure Clear;
+
+    function Contains(constref AValue: T): Boolean; inline;
+    function IndexOf(constref AValue: T): SizeInt; virtual;
+    function LastIndexOf(constref AValue: T): SizeInt; virtual;
+
+    procedure Reverse;
+
+    procedure TrimExcess;
+
+    procedure Sort; overload;
+    procedure Sort(const AComparer: IComparer<T>); overload;
+    function BinarySearch(constref AItem: T; out AIndex: SizeInt): Boolean; overload;
+    function BinarySearch(constref AItem: T; out AIndex: SizeInt; const AComparer: IComparer<T>): Boolean; overload;
+
+    property Count: SizeInt read FItemsLength write SetCount;
+    property Items[Index: SizeInt]: T read GetItem write SetItem; default;
+  end;
+
+  TQueue<T> = class(TCustomList<T>)
+  protected
+    // bug #24287 - workaround for generics type name conflict (Identifier not found)
+    // next bug workaround - for another error related to previous workaround
+    // change order (function must be declared before TEnumerator declaration}
+    function DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; override;
+  public
+    type
+      TEnumerator = class(TCustomListEnumerator<T>)
+      public
+        constructor Create(AQueue: TQueue<T>);
+      end;
+
+    function GetEnumerator: TEnumerator; reintroduce;
+  private
+    FLow: SizeInt;
+  protected
+    procedure SetCapacity(AValue: SizeInt); override;
+    function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override;
+    function GetCount: SizeInt; override;
+  public
+    constructor Create(ACollection: TEnumerable<T>); overload;
+    destructor Destroy; override;
+    procedure Enqueue(constref AValue: T);
+    function Dequeue: T;
+    function Extract: T;
+    function Peek: T;
+    procedure Clear;
+    procedure TrimExcess;
+  end;
+
+  TStack<T> = class(TCustomList<T>)
+  protected
+  // bug #24287 - workaround for generics type name conflict (Identifier not found)
+  // next bug workaround - for another error related to previous workaround
+  // change order (function must be declared before TEnumerator declaration}
+    function DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; override;
+  public
+    type
+      TEnumerator = class(TCustomListEnumerator<T>);
+
+    function GetEnumerator: TEnumerator; reintroduce;
+  protected
+    function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override;
+    procedure SetCapacity(AValue: SizeInt); override;
+  public
+    constructor Create(ACollection: TEnumerable<T>); overload;
+    destructor Destroy; override;
+    procedure Clear;
+    procedure Push(constref AValue: T);
+    function Pop: T; inline;
+    function Peek: T;
+    function Extract: T; inline;
+    procedure TrimExcess;
+  end;
+
+  TObjectList<T: class> = class(TList<T>)
+  private
+    FObjectsOwner: Boolean;
+  protected
+    procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); override;
+  public
+    constructor Create(AOwnsObjects: Boolean = True); overload;
+    constructor Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean = True); overload;
+    constructor Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
+    property OwnsObjects: Boolean read FObjectsOwner write FObjectsOwner;
+  end;
+
+  TObjectQueue<T: class> = class(TQueue<T>)
+  private
+    FObjectsOwner: Boolean;
+  protected
+    procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); override;
+  public
+    constructor Create(AOwnsObjects: Boolean = True); overload;
+    constructor Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
+    procedure Dequeue;
+    property OwnsObjects: Boolean read FObjectsOwner write FObjectsOwner;
+  end;
+
+  TObjectStack<T: class> = class(TStack<T>)
+  private
+    FObjectsOwner: Boolean;
+  protected
+    procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); override;
+  public
+    constructor Create(AOwnsObjects: Boolean = True); overload;
+    constructor Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
+    function Pop: T;
+    property OwnsObjects: Boolean read FObjectsOwner write FObjectsOwner;
+  end;
+
+  PObject = ^TObject;
+
+{$I inc\generics.dictionariesh.inc}
+
+function InCircularRange(ABottom, AItem, ATop: SizeInt): Boolean;
+
+implementation
+
+function InCircularRange(ABottom, AItem, ATop: SizeInt): Boolean;
+begin
+  Result :=
+       (ABottom < AItem) and (AItem <= ATop )
+    or (ATop < ABottom) and (AItem > ABottom)
+    or (ATop < ABottom ) and (AItem <= ATop );
+end;
+
+{ TCustomArrayHelper<T> }
+
+class function TCustomArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T;
+  out AFoundIndex: SizeInt; const AComparer: IComparer<T>): Boolean;
+begin
+  Result := BinarySearch(AValues, AItem, AFoundIndex, AComparer, Low(AValues), Length(AValues));
+end;
+
+class function TCustomArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T;
+  out AFoundIndex: SizeInt): Boolean;
+begin
+  Result := BinarySearch(AValues, AItem, AFoundIndex, TComparerBugHack.Default, Low(AValues), Length(AValues));
+end;
+
+class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T);
+begin
+  QuickSort(AValues, Low(AValues), High(AValues), TComparerBugHack.Default);
+end;
+
+class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T;
+  const AComparer: IComparer<T>);
+begin
+  QuickSort(AValues, Low(AValues), High(AValues), AComparer);
+end;
+
+class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T;
+  const AComparer: IComparer<T>; AIndex, ACount: SizeInt);
+begin
+  if ACount <= 1 then
+    Exit;
+  QuickSort(AValues, AIndex, Pred(AIndex + ACount), AComparer);
+end;
+
+{ TArrayHelper<T> }
+
+class procedure TArrayHelper<T>.QuickSort(var AValues: array of T; ALeft, ARight: SizeInt;
+  const AComparer: IComparer<T>);
+var
+  I, J: SizeInt;
+  P, Q: T;
+begin
+  if ((ARight - ALeft) <= 0) or (Length(AValues) = 0) then
+    Exit;
+  repeat
+    I := ALeft;
+    J := ARight;
+    P := AValues[ALeft + (ARight - ALeft) shr 1];
+    repeat
+        while AComparer.Compare(AValues[I], P) < 0 do
+          I += 1;
+        while AComparer.Compare(AValues[J], P) > 0 do
+          J -= 1;
+      if I <= J then
+      begin
+        if I <> J then
+        begin
+          Q := AValues[I];
+          AValues[I] := AValues[J];
+          AValues[J] := Q;
+        end;
+        I += 1;
+        J -= 1;
+      end;
+    until I > J;
+    // sort the smaller range recursively
+    // sort the bigger range via the loop
+    // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
+    if J - ALeft < ARight - I then
+    begin
+      if ALeft < J then
+        QuickSort(AValues, ALeft, J, AComparer);
+      ALeft := I;
+    end
+    else
+    begin
+      if I < ARight then
+        QuickSort(AValues, I, ARight, AComparer);
+      ARight := J;
+    end;
+   until ALeft >= ARight;
+end;
+
+class function TArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T;
+  out AFoundIndex: SizeInt; const AComparer: IComparer<T>;
+  AIndex, ACount: SizeInt): Boolean;
+var
+  imin, imax, imid: Int32;
+  LCompare: SizeInt;
+begin
+  // continually narrow search until just one element remains
+  imin := AIndex;
+  imax := Pred(AIndex + ACount);
+
+  // http://en.wikipedia.org/wiki/Binary_search_algorithm
+  while (imin < imax) do
+  begin
+        imid := imin + ((imax - imin) shr 1);
+
+        // code must guarantee the interval is reduced at each iteration
+        // assert(imid < imax);
+        // note: 0 <= imin < imax implies imid will always be less than imax
+
+        LCompare := AComparer.Compare(AValues[imid], AItem);
+        // reduce the search
+        if (LCompare < 0) then
+          imin := imid + 1
+        else
+        begin
+          imax := imid;
+          if LCompare = 0 then
+          begin
+            AFoundIndex := imid;
+            Exit(True);
+          end;
+        end;
+  end;
+    // At exit of while:
+    //   if A[] is empty, then imax < imin
+    //   otherwise imax == imin
+
+    // deferred test for equality
+
+  LCompare := AComparer.Compare(AValues[imin], AItem);
+  if (imax = imin) and (LCompare = 0) then
+  begin
+    AFoundIndex := imin;
+    Exit(True);
+  end
+  else
+  begin
+    AFoundIndex := -1;
+    Exit(False);
+  end;
+end;
+
+{ TEnumerator<T> }
+
+function TEnumerator<T>.MoveNext: boolean;
+begin
+  Exit(DoMoveNext);
+end;
+
+{ TEnumerable<T> }
+
+function TEnumerable<T>.ToArrayImpl(ACount: SizeInt): TArray<T>;
+var
+  i: SizeInt;
+  LEnumerator: TEnumerator<T>;
+begin
+  SetLength(Result, ACount);
+
+  try
+    LEnumerator := GetEnumerator;
+
+    i := 0;
+    while LEnumerator.MoveNext do
+    begin
+      Result[i] := LEnumerator.Current;
+      Inc(i);
+    end;
+  finally
+    LEnumerator.Free;
+  end;
+end;
+
+function TEnumerable<T>.GetEnumerator: TEnumerator;
+begin
+  Exit(DoGetEnumerator);
+end;
+
+function TEnumerable<T>.ToArray: TArray<T>;
+var
+  LEnumerator: TEnumerator<T>;
+  LBuffer: TList<T>;
+begin
+  LBuffer := TList<T>.Create;
+  try
+    LEnumerator := GetEnumerator;
+
+    while LEnumerator.MoveNext do
+      LBuffer.Add(LEnumerator.Current);
+
+    Result := LBuffer.ToArray;
+  finally
+    LBuffer.Free;
+    LEnumerator.Free;
+  end;
+end;
+
+{ TCustomList<T> }
+
+function TCustomList<T>.PrepareAddingItem: SizeInt;
+begin
+  Result := Length(FItems);
+
+  if (FItemsLength < 4) and (Result < 4) then
+    SetLength(FItems, 4)
+  else if FItemsLength = High(FItemsLength) then
+    OutOfMemoryError
+  else if FItemsLength = Result then
+    SetLength(FItems, CUSTOM_LIST_CAPACITY_INC);
+
+  Result := FItemsLength;
+  Inc(FItemsLength);
+end;
+
+function TCustomList<T>.PrepareAddingRange(ACount: SizeInt): SizeInt;
+begin
+  if ACount < 0 then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+  if ACount = 0 then
+    Exit(FItemsLength - 1);
+
+  if (FItemsLength = 0) and (Length(FItems) = 0) then
+    SetLength(FItems, 4)
+  else if FItemsLength = High(FItemsLength) then
+    OutOfMemoryError;
+
+  Result := Length(FItems);
+  while Pred(FItemsLength + ACount) >= Result do
+  begin
+    SetLength(FItems, CUSTOM_LIST_CAPACITY_INC);
+    Result := Length(FItems);
+  end;
+
+  Result := FItemsLength;
+  Inc(FItemsLength, ACount);
+end;
+
+function TCustomList<T>.ToArray: TArray<T>;
+begin
+  Result := ToArrayImpl(Count);
+end;
+
+function TCustomList<T>.GetCount: SizeInt;
+begin
+  Result := FItemsLength;
+end;
+
+procedure TCustomList<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification);
+begin
+  if Assigned(FOnNotify) then
+    FOnNotify(Self, AValue, ACollectionNotification);
+end;
+
+function TCustomList<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T;
+begin
+  if (AIndex < 0) or (AIndex >= FItemsLength) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  Result := FItems[AIndex];
+  Dec(FItemsLength);
+
+  FItems[AIndex] := Default(T);
+  if AIndex <> FItemsLength then
+  begin
+    System.Move(FItems[AIndex + 1], FItems[AIndex], (FItemsLength - AIndex) * SizeOf(T));
+    FillChar(FItems[FItemsLength], SizeOf(T), 0);
+  end;
+
+  Notify(Result, ACollectionNotification);
+end;
+
+function TCustomList<T>.GetCapacity: SizeInt;
+begin
+  Result := Length(FItems);
+end;
+
+{ TCustomListEnumerator<T> }
+
+function TCustomListEnumerator<T>.DoMoveNext: boolean;
+begin
+  Inc(FIndex);
+  Result := (FList.FItemsLength <> 0) and (FIndex < FList.FItemsLength)
+end;
+
+function TCustomListEnumerator<T>.DoGetCurrent: T;
+begin
+  Result := GetCurrent;
+end;
+
+function TCustomListEnumerator<T>.GetCurrent: T;
+begin
+  Result := FList.FItems[FIndex];
+end;
+
+constructor TCustomListEnumerator<T>.Create(AList: TCustomList<T>);
+begin
+  inherited Create;
+  FIndex := -1;
+  FList := AList;
+end;
+
+{ TList<T> }
+
+constructor TList<T>.Create;
+begin
+  FComparer := TComparer<T>.Default;
+end;
+
+constructor TList<T>.Create(const AComparer: IComparer<T>);
+begin
+  FComparer := AComparer;
+end;
+
+constructor TList<T>.Create(ACollection: TEnumerable<T>);
+var
+  LItem: T;
+begin
+  Create;
+  for LItem in ACollection do
+    Add(LItem);
+end;
+
+destructor TList<T>.Destroy;
+begin
+  SetCapacity(0);
+end;
+
+procedure TList<T>.SetCapacity(AValue: SizeInt);
+begin
+  if AValue < Count then
+    Count := AValue;
+
+  SetLength(FItems, AValue);
+end;
+
+procedure TList<T>.SetCount(AValue: SizeInt);
+begin
+  if AValue < 0 then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  if AValue > Capacity then
+    Capacity := AValue;
+  if AValue < Count then
+    DeleteRange(AValue, Count - AValue);
+
+  FItemsLength := AValue;
+end;
+
+function TList<T>.GetItem(AIndex: SizeInt): T;
+begin
+  if (AIndex < 0) or (AIndex >= Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  Result := FItems[AIndex];
+end;
+
+procedure TList<T>.SetItem(AIndex: SizeInt; const AValue: T);
+begin
+  if (AIndex < 0) or (AIndex >= Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  FItems[AIndex] := AValue;
+end;
+
+function TList<T>.GetEnumerator: TEnumerator;
+begin
+  Result := TEnumerator.Create(Self);
+end;
+
+function TList<T>.DoGetEnumerator: {Generics.Collections.}TEnumerator<T>;
+begin
+  Result := GetEnumerator;
+end;
+
+function TList<T>.Add(constref AValue: T): SizeInt;
+begin
+  Result := PrepareAddingItem;
+  FItems[Result] := AValue;
+  Notify(AValue, cnAdded);
+end;
+
+procedure TList<T>.AddRange(constref AValues: array of T);
+begin
+  InsertRange(Count, AValues);
+end;
+
+procedure TList<T>.AddRange(const AEnumerable: IEnumerable<T>);
+var
+  LValue: T;
+begin
+  for LValue in AEnumerable do
+    Add(LValue);
+end;
+
+procedure TList<T>.AddRange(AEnumerable: TEnumerable<T>);
+var
+  LValue: T;
+begin
+  for LValue in AEnumerable do
+    Add(LValue);
+end;
+
+procedure TList<T>.Insert(AIndex: SizeInt; constref AValue: T);
+begin
+  if (AIndex < 0) or (AIndex > Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  if AIndex <> PrepareAddingItem then
+  begin
+    System.Move(FItems[AIndex], FItems[AIndex + 1], ((Count - AIndex) - 1) * SizeOf(T));
+    FillChar(FItems[AIndex], SizeOf(T), 0);
+  end;
+
+  FItems[AIndex] := AValue;
+  Notify(AValue, cnAdded);
+end;
+
+procedure TList<T>.InsertRange(AIndex: SizeInt; constref AValues: array of T);
+var
+  i: SizeInt;
+  LLength: SizeInt;
+  LValue: ^T;
+begin
+  if (AIndex < 0) or (AIndex > Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  LLength := Length(AValues);
+  if LLength = 0 then
+    Exit;
+
+  if AIndex <> PrepareAddingRange(LLength) then
+  begin
+    System.Move(FItems[AIndex], FItems[AIndex + LLength], ((Count - AIndex) - LLength) * SizeOf(T));
+    FillChar(FItems[AIndex], SizeOf(T) * LLength, 0);
+  end;
+
+  LValue := @AValues[0];
+  for i := AIndex to Pred(AIndex + LLength) do
+  begin
+    FItems[i] := LValue^;
+    Notify(LValue^, cnAdded);
+    Inc(LValue);
+  end;
+end;
+
+procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: IEnumerable<T>);
+var
+  LValue: T;
+  i: SizeInt;
+begin
+  if (AIndex < 0) or (AIndex > Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  i := 0;
+  for LValue in AEnumerable do
+  begin
+    Insert(Aindex + i, LValue);
+    Inc(i);
+  end;
+end;
+
+procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerable<T>);
+var
+  LValue: T;
+  i:  SizeInt;
+begin
+  if (AIndex < 0) or (AIndex > Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  i := 0;
+  for LValue in AEnumerable do
+  begin
+    Insert(Aindex + i, LValue);
+    Inc(i);
+  end;
+end;
+
+function TList<T>.Remove(constref AValue: T): SizeInt;
+begin
+  Result := IndexOf(AValue);
+  if Result >= 0 then
+    DoRemove(Result, cnRemoved);
+end;
+
+procedure TList<T>.Delete(AIndex: SizeInt);
+begin
+  DoRemove(AIndex, cnRemoved);
+end;
+
+procedure TList<T>.DeleteRange(AIndex, ACount: SizeInt);
+var
+  LDeleted: array of T;
+  i: SizeInt;
+  LMoveDelta: SizeInt;
+begin
+  if ACount = 0 then
+    Exit;
+
+  if (ACount < 0) or (AIndex < 0) or (AIndex + ACount > Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  SetLength(LDeleted, Count);
+  System.Move(FItems[AIndex], LDeleted[0], ACount * SizeOf(T));
+
+  LMoveDelta := Count - (AIndex + ACount);
+
+  if LMoveDelta = 0 then
+    FillChar(FItems[AIndex], ACount * SizeOf(T), #0)
+  else
+  begin
+    System.Move(FItems[AIndex + ACount], FItems[AIndex], LMoveDelta * SizeOf(T));
+    FillChar(FItems[Count - ACount], ACount * SizeOf(T), #0);
+  end;
+
+  FItemsLength -= ACount;
+
+  for i := 0 to High(LDeleted) do
+    Notify(LDeleted[i], cnRemoved);
+end;
+
+function TList<T>.ExtractIndex(const AIndex: SizeInt): T;
+begin
+  Result := DoRemove(AIndex, cnExtracted);
+end;
+
+function TList<T>.Extract(constref AValue: T): T;
+var
+  LIndex: SizeInt;
+begin
+  LIndex := IndexOf(AValue);
+  if LIndex < 0 then
+    Exit(Default(T));
+
+  Result := DoRemove(LIndex, cnExtracted);
+end;
+
+procedure TList<T>.Exchange(AIndex1, AIndex2: SizeInt);
+var
+  LTemp: T;
+begin
+  LTemp := FItems[AIndex1];
+  FItems[AIndex1] := FItems[AIndex2];
+  FItems[AIndex2] := LTemp;
+end;
+
+procedure TList<T>.Move(AIndex, ANewIndex: SizeInt);
+var
+  LTemp: T;
+begin
+  if ANewIndex = AIndex then
+    Exit;
+
+  if (ANewIndex < 0) or (ANewIndex >= Count) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  LTemp := FItems[AIndex];
+  FItems[AIndex] := Default(T);
+
+  if AIndex < ANewIndex then
+    System.Move(FItems[Succ(AIndex)], FItems[AIndex], (ANewIndex - AIndex) * SizeOf(T))
+  else
+    System.Move(FItems[ANewIndex], FItems[Succ(ANewIndex)], (AIndex - ANewIndex) * SizeOf(T));
+
+  FillChar(FItems[ANewIndex], SizeOf(T), #0);
+  FItems[ANewIndex] := LTemp;
+end;
+
+function TList<T>.First: T;
+begin
+  Result := Items[0];
+end;
+
+function TList<T>.Last: T;
+begin
+  Result := Items[Pred(Count)];
+end;
+
+procedure TList<T>.Clear;
+begin
+  SetCount(0);
+  SetCapacity(0);
+end;
+
+procedure TList<T>.TrimExcess;
+begin
+  SetCapacity(Count);
+end;
+
+function TList<T>.Contains(constref AValue: T): Boolean;
+begin
+  Result := IndexOf(AValue) >= 0;
+end;
+
+function TList<T>.IndexOf(constref AValue: T): SizeInt;
+var
+  i: SizeInt;
+begin
+  for i := 0 to Count - 1 do
+    if FComparer.Compare(AValue, FItems[i]) = 0 then
+      Exit(i);
+  Result := -1;
+end;
+
+function TList<T>.LastIndexOf(constref AValue: T): SizeInt;
+var
+  i: SizeInt;
+begin
+  for i := Count - 1 downto 0 do
+    if FComparer.Compare(AValue, FItems[i]) = 0 then
+      Exit(i);
+  Result := -1;
+end;
+
+procedure TList<T>.Reverse;
+var
+  a, b: SizeInt;
+  LTemp: T;
+begin
+  a := 0;
+  b := Count - 1;
+  while a < b do
+  begin
+    LTemp := FItems[a];
+    FItems[a] := FItems[b];
+    FItems[b] := LTemp;
+    Inc(a);
+    Dec(b);
+  end;
+end;
+
+procedure TList<T>.Sort;
+begin
+  TArrayHelperBugHack.Sort(FItems, FComparer, 0, Count);
+end;
+
+procedure TList<T>.Sort(const AComparer: IComparer<T>);
+begin
+  TArrayHelperBugHack.Sort(FItems, AComparer, 0, Count);
+end;
+
+function TList<T>.BinarySearch(constref AItem: T; out AIndex: SizeInt): Boolean;
+begin
+  Result := TArrayHelperBugHack.BinarySearch(FItems, AItem, AIndex);
+end;
+
+function TList<T>.BinarySearch(constref AItem: T; out AIndex: SizeInt; const AComparer: IComparer<T>): Boolean;
+begin
+  Result := TArrayHelperBugHack.BinarySearch(FItems, AItem, AIndex, AComparer);
+end;
+
+{ TQueue<T>.TEnumerator }
+
+constructor TQueue<T>.TEnumerator.Create(AQueue: TQueue<T>);
+begin
+  inherited Create(AQueue);
+
+  FIndex := Pred(AQueue.FLow);
+end;
+
+{ TQueue<T> }
+
+function TQueue<T>.GetEnumerator: TEnumerator;
+begin
+  Result := TEnumerator.Create(Self);
+end;
+
+function TQueue<T>.DoGetEnumerator: {Generics.Collections.}TEnumerator<T>;
+begin
+  Result := GetEnumerator;
+end;
+
+function TQueue<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T;
+begin
+  Result := FItems[AIndex];
+  FItems[AIndex] := Default(T);
+  Notify(Result, ACollectionNotification);
+  FLow += 1;
+  if FLow = FItemsLength then
+  begin
+    FLow := 0;
+    FItemsLength := 0;
+  end;
+end;
+
+procedure TQueue<T>.SetCapacity(AValue: SizeInt);
+begin
+  if AValue < Count then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  if AValue = FItemsLength then
+    Exit;
+
+  if (Count > 0) and (FLow > 0) then
+  begin
+    Move(FItems[FLow], FItems[0], Count * SizeOf(T));
+    FillChar(FItems[Count], (FItemsLength - Count) * SizeOf(T), #0);
+  end;
+
+  SetLength(FItems, AValue);
+  FItemsLength := Count;
+  FLow := 0;
+end;
+
+function TQueue<T>.GetCount: SizeInt;
+begin
+  Result := FItemsLength - FLow;
+end;
+
+constructor TQueue<T>.Create(ACollection: TEnumerable<T>);
+var
+  LItem: T;
+begin
+  for LItem in ACollection do
+    Enqueue(LItem);
+end;
+
+destructor TQueue<T>.Destroy;
+begin
+  Clear;
+end;
+
+procedure TQueue<T>.Enqueue(constref AValue: T);
+var
+  LIndex: SizeInt;
+begin
+  LIndex := PrepareAddingItem;
+  FItems[LIndex] := AValue;
+  Notify(AValue, cnAdded);
+end;
+
+function TQueue<T>.Dequeue: T;
+begin
+  Result := DoRemove(FLow, cnRemoved);
+end;
+
+function TQueue<T>.Extract: T;
+begin
+  Result := DoRemove(FLow, cnExtracted);
+end;
+
+function TQueue<T>.Peek: T;
+begin
+  if (Count = 0) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  Result := FItems[FLow];
+end;
+
+procedure TQueue<T>.Clear;
+begin
+  while Count <> 0 do
+    Dequeue;
+  FLow := 0;
+  FItemsLength := 0;
+end;
+
+procedure TQueue<T>.TrimExcess;
+begin
+  SetCapacity(Count);
+end;
+
+{ TStack<T> }
+
+function TStack<T>.GetEnumerator: TEnumerator;
+begin
+  Result := TEnumerator.Create(Self);
+end;
+
+function TStack<T>.DoGetEnumerator: {Generics.Collections.}TEnumerator<T>;
+begin
+  Result := GetEnumerator;
+end;
+
+constructor TStack<T>.Create(ACollection: TEnumerable<T>);
+var
+  LItem: T;
+begin
+  for LItem in ACollection do
+    Push(LItem);
+end;
+
+function TStack<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T;
+begin
+  if AIndex < 0 then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  Result := FItems[AIndex];
+  FItems[AIndex] := Default(T);
+  FItemsLength -= 1;
+  Notify(Result, ACollectionNotification);
+end;
+
+destructor TStack<T>.Destroy;
+begin
+  Clear;
+end;
+
+procedure TStack<T>.Clear;
+begin
+  while Count <> 0 do
+    Pop;
+end;
+
+procedure TStack<T>.SetCapacity(AValue: SizeInt);
+begin
+  if AValue < Count then
+    AValue := Count;
+
+  SetLength(FItems, AValue);
+end;
+
+procedure TStack<T>.Push(constref AValue: T);
+var
+  LIndex: SizeInt;
+begin
+  LIndex := PrepareAddingItem;
+  FItems[LIndex] := AValue;
+  Notify(AValue, cnAdded);
+end;
+
+function TStack<T>.Pop: T;
+begin
+  Result := DoRemove(FItemsLength - 1, cnRemoved);
+end;
+
+function TStack<T>.Peek: T;
+begin
+  if (Count = 0) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  Result := FItems[FItemsLength - 1];
+end;
+
+function TStack<T>.Extract: T;
+begin
+  Result := DoRemove(FItemsLength - 1, cnExtracted);
+end;
+
+procedure TStack<T>.TrimExcess;
+begin
+  SetCapacity(Count);
+end;
+
+{ TObjectList<T> }
+
+procedure TObjectList<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification);
+begin
+  inherited Notify(AValue, ACollectionNotification);
+
+  if FObjectsOwner and (ACollectionNotification = cnRemoved) then
+    TObject(AValue).Free;
+end;
+
+constructor TObjectList<T>.Create(AOwnsObjects: Boolean);
+begin
+  inherited Create;
+
+  FObjectsOwner := AOwnsObjects;
+end;
+
+constructor TObjectList<T>.Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean);
+begin
+  inherited Create(AComparer);
+
+  FObjectsOwner := AOwnsObjects;
+end;
+
+constructor TObjectList<T>.Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean);
+begin
+  inherited Create(ACollection);
+
+  FObjectsOwner := AOwnsObjects;
+end;
+
+{ TObjectQueue<T> }
+
+procedure TObjectQueue<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification);
+begin
+  inherited Notify(AValue, ACollectionNotification);
+  if FObjectsOwner and (ACollectionNotification = cnRemoved) then
+    TObject(AValue).Free;
+end;
+
+constructor TObjectQueue<T>.Create(AOwnsObjects: Boolean);
+begin
+  inherited Create;
+
+  FObjectsOwner := AOwnsObjects;
+end;
+
+constructor TObjectQueue<T>.Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean);
+begin
+  inherited Create(ACollection);
+
+  FObjectsOwner := AOwnsObjects;
+end;
+
+procedure TObjectQueue<T>.Dequeue;
+begin
+  inherited Dequeue;
+end;
+
+{ TObjectStack<T> }
+
+procedure TObjectStack<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification);
+begin
+  inherited Notify(AValue, ACollectionNotification);
+  if FObjectsOwner and (ACollectionNotification = cnRemoved) then
+    TObject(AValue).Free;
+end;
+
+constructor TObjectStack<T>.Create(AOwnsObjects: Boolean);
+begin
+  inherited Create;
+
+  FObjectsOwner := AOwnsObjects;
+end;
+
+constructor TObjectStack<T>.Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean);
+begin
+  inherited Create(ACollection);
+
+  FObjectsOwner := AOwnsObjects;
+end;
+
+function TObjectStack<T>.Pop: T;
+begin
+  Result := inherited Pop;
+end;
+
+{$I inc\generics.dictionaries.inc}
+
+end.

+ 3270 - 0
packages/rtl-generics/src/generics.defaults.pas

@@ -0,0 +1,3270 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit Generics.Defaults;
+
+{$MODE DELPHI}{$H+}
+{$POINTERMATH ON}
+{$MACRO ON}
+{$COPERATORS ON}
+{$HINTS OFF}
+{$WARNINGS OFF}
+{$NOTES OFF}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+
+interface
+
+uses
+  Classes, SysUtils, Generics.Hashes, TypInfo, Variants, Math, Generics.Strings, Generics.Helpers;
+
+type
+  IComparer<T> = interface
+    function Compare(constref Left, Right: T): Integer; overload;
+  end;
+
+  TOnComparison<T> = function(constref Left, Right: T): Integer of object;
+  TComparisonFunc<T> = function(constref Left, Right: T): Integer;
+
+  TComparer<T> = class(TInterfacedObject, IComparer<T>)
+  public
+    class function Default: IComparer<T>; static;
+    function Compare(constref ALeft, ARight: T): Integer; virtual; abstract; overload;
+
+    class function Construct(const AComparison: TOnComparison<T>): IComparer<T>; overload;
+    class function Construct(const AComparison: TComparisonFunc<T>): IComparer<T>; overload;
+  end;
+
+  TDelegatedComparerEvents<T> = class(TComparer<T>)
+  private
+    FComparison: TOnComparison<T>;
+  public
+    function Compare(constref ALeft, ARight: T): Integer; override;
+    constructor Create(AComparison: TOnComparison<T>);
+  end;
+
+  TDelegatedComparerFunc<T> = class(TComparer<T>)
+  private
+    FComparison: TComparisonFunc<T>;
+  public
+    function Compare(constref ALeft, ARight: T): Integer; override;
+    constructor Create(AComparison: TComparisonFunc<T>);
+  end;
+
+  IEqualityComparer<T> = interface
+    function Equals(constref ALeft, ARight: T): Boolean;
+    function GetHashCode(constref AValue: T): UInt32;
+  end;
+
+  IExtendedEqualityComparer<T> = interface(IEqualityComparer<T>)
+    procedure GetHashList(constref AValue: T; AHashList: PUInt32); // for double hashing and more
+  end;
+
+  ShortString1 = string[1];
+  ShortString2 = string[2];
+  ShortString3 = string[3];
+
+  { TAbstractInterface }
+
+  TInterface = class
+  public
+    function QueryInterface(constref {%H-}IID: TGUID;{%H-} out Obj): HResult; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
+    function _AddRef: Integer; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual; abstract;
+    function _Release: Integer; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};  virtual; abstract;
+  end;
+
+  { TRawInterface }
+
+  TRawInterface = class(TInterface)
+  public
+    function _AddRef: Integer; override;
+    function _Release: Integer; override;
+  end;
+
+  { TComTypeSizeInterface }
+
+  // INTERNAL USE ONLY!
+  TComTypeSizeInterface = class(TInterface)
+  public
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    function _AddRef: Integer; override;
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    function _Release: Integer; override;
+  end;
+
+  { TSingletonImplementation }
+
+  TSingletonImplementation = class(TRawInterface, IInterface)
+  public
+    function QueryInterface(constref IID: TGUID; out Obj): HResult; override;
+  end;
+
+  TCompare = class
+  protected
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class function _Binary(constref ALeft, ARight): Integer;
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class function _DynArray(constref ALeft, ARight: Pointer): Integer;
+  public
+    class function Integer(constref ALeft, ARight: Integer): Integer;
+    class function Int8(constref ALeft, ARight: Int8): Integer;
+    class function Int16(constref ALeft, ARight: Int16): Integer;
+    class function Int32(constref ALeft, ARight: Int32): Integer;
+    class function Int64(constref ALeft, ARight: Int64): Integer;
+    class function UInt8(constref ALeft, ARight: UInt8): Integer;
+    class function UInt16(constref ALeft, ARight: UInt16): Integer;
+    class function UInt32(constref ALeft, ARight: UInt32): Integer;
+    class function UInt64(constref ALeft, ARight: UInt64): Integer;
+    class function Single(constref ALeft, ARight: Single): Integer;
+    class function Double(constref ALeft, ARight: Double): Integer;
+    class function Extended(constref ALeft, ARight: Extended): Integer;
+    class function Currency(constref ALeft, ARight: Currency): Integer;
+    class function Comp(constref ALeft, ARight: Comp): Integer;
+    class function Binary(constref ALeft, ARight; const ASize: SizeInt): Integer;
+    class function DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Integer;
+    class function ShortString1(constref ALeft, ARight: ShortString1): Integer;
+    class function ShortString2(constref ALeft, ARight: ShortString2): Integer;
+    class function ShortString3(constref ALeft, ARight: ShortString3): Integer;
+    class function &String(constref ALeft, ARight: string): Integer;
+    class function ShortString(constref ALeft, ARight: ShortString): Integer;
+    class function AnsiString(constref ALeft, ARight: AnsiString): Integer;
+    class function WideString(constref ALeft, ARight: WideString): Integer;
+    class function UnicodeString(constref ALeft, ARight: UnicodeString): Integer;
+    class function Method(constref ALeft, ARight: TMethod): Integer;
+    class function Variant(constref ALeft, ARight: PVariant): Integer;
+    class function Pointer(constref ALeft, ARight: PtrUInt): Integer;
+  end;
+
+  { TEquals }
+
+  TEquals = class
+  protected
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class function _Binary(constref ALeft, ARight): Boolean;
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class function _DynArray(constref ALeft, ARight: Pointer): Boolean;
+  public
+    class function Integer(constref ALeft, ARight: Integer): Boolean;
+    class function Int8(constref ALeft, ARight: Int8): Boolean;
+    class function Int16(constref ALeft, ARight: Int16): Boolean;
+    class function Int32(constref ALeft, ARight: Int32): Boolean;
+    class function Int64(constref ALeft, ARight: Int64): Boolean;
+    class function UInt8(constref ALeft, ARight: UInt8): Boolean;
+    class function UInt16(constref ALeft, ARight: UInt16): Boolean;
+    class function UInt32(constref ALeft, ARight: UInt32): Boolean;
+    class function UInt64(constref ALeft, ARight: UInt64): Boolean;
+    class function Single(constref ALeft, ARight: Single): Boolean;
+    class function Double(constref ALeft, ARight: Double): Boolean;
+    class function Extended(constref ALeft, ARight: Extended): Boolean;
+    class function Currency(constref ALeft, ARight: Currency): Boolean;
+    class function Comp(constref ALeft, ARight: Comp): Boolean;
+    class function Binary(constref ALeft, ARight; const ASize: SizeInt): Boolean;
+    class function DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Boolean;
+    class function &Class(constref ALeft, ARight: TObject): Boolean;
+    class function ShortString1(constref ALeft, ARight: ShortString1): Boolean;
+    class function ShortString2(constref ALeft, ARight: ShortString2): Boolean;
+    class function ShortString3(constref ALeft, ARight: ShortString3): Boolean;
+    class function &String(constref ALeft, ARight: String): Boolean;
+    class function ShortString(constref ALeft, ARight: ShortString): Boolean;
+    class function AnsiString(constref ALeft, ARight: AnsiString): Boolean;
+    class function WideString(constref ALeft, ARight: WideString): Boolean;
+    class function UnicodeString(constref ALeft, ARight: UnicodeString): Boolean;
+    class function Method(constref ALeft, ARight: TMethod): Boolean;
+    class function Variant(constref ALeft, ARight: PVariant): Boolean;
+    class function Pointer(constref ALeft, ARight: PtrUInt): Boolean;
+  end;
+
+  THashServiceClass = class of THashService;
+  TExtendedHashServiceClass = class of TExtendedHashService;
+  THashFactoryClass = class of THashFactory;
+
+  TExtendedHashFactoryClass = class of TExtendedHashFactory;
+
+  { TComparerService }
+
+{$DEFINE STD_RAW_INTERFACE_METHODS :=
+    QueryInterface: @TRawInterface.QueryInterface;
+    _AddRef       : @TRawInterface._AddRef;
+    _Release      : @TRawInterface._Release
+}
+
+{$DEFINE STD_COM_TYPESIZE_INTERFACE_METHODS :=
+    QueryInterface: @TComTypeSizeInterface.QueryInterface;
+    _AddRef       : @TComTypeSizeInterface._AddRef;
+    _Release      : @TComTypeSizeInterface._Release
+}
+
+  TGetHashListOptions = set of (ghloHashListAsInitData);
+
+  THashFactory = class
+  private type
+    PPEqualityComparerVMT = ^PEqualityComparerVMT;
+    PEqualityComparerVMT = ^TEqualityComparerVMT;
+    TEqualityComparerVMT = packed record
+      QueryInterface: Pointer;
+      _AddRef: Pointer;
+      _Release: Pointer;
+      Equals: Pointer;
+      GetHashCode: Pointer;
+      __Reserved: Pointer; // initially or TExtendedEqualityComparerVMT compatibility
+                           // (important when ExtendedEqualityComparer is calling Binary method)
+      __ClassRef: THashFactoryClass; // hidden field in VMT. For class ref THashFactoryClass
+    end;
+
+  private
+(***********************************************************************************************************************
+      Hashes
+(**********************************************************************************************************************)
+
+    class function Int8         (constref AValue: Int8         ): UInt32; overload;
+    class function Int16        (constref AValue: Int16        ): UInt32; overload;
+    class function Int32        (constref AValue: Int32        ): UInt32; overload;
+    class function Int64        (constref AValue: Int64        ): UInt32; overload;
+    class function UInt8        (constref AValue: UInt8        ): UInt32; overload;
+    class function UInt16       (constref AValue: UInt16       ): UInt32; overload;
+    class function UInt32       (constref AValue: UInt32       ): UInt32; overload;
+    class function UInt64       (constref AValue: UInt64       ): UInt32; overload;
+    class function Single       (constref AValue: Single       ): UInt32; overload;
+    class function Double       (constref AValue: Double       ): UInt32; overload;
+    class function Extended     (constref AValue: Extended     ): UInt32; overload;
+    class function Currency     (constref AValue: Currency     ): UInt32; overload;
+    class function Comp         (constref AValue: Comp         ): UInt32; overload;
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class function Binary       (constref AValue               ): UInt32; overload;
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class function DynArray     (constref AValue: Pointer      ): UInt32; overload;
+    class function &Class       (constref AValue: TObject      ): UInt32; overload;
+    class function ShortString1 (constref AValue: ShortString1 ): UInt32; overload;
+    class function ShortString2 (constref AValue: ShortString2 ): UInt32; overload;
+    class function ShortString3 (constref AValue: ShortString3 ): UInt32; overload;
+    class function ShortString  (constref AValue: ShortString   ): UInt32; overload;
+    class function AnsiString   (constref AValue: AnsiString   ): UInt32; overload;
+    class function WideString   (constref AValue: WideString   ): UInt32; overload;
+    class function UnicodeString(constref AValue: UnicodeString): UInt32; overload;
+    class function Method       (constref AValue: TMethod      ): UInt32; overload;
+    class function Variant      (constref AValue: PVariant     ): UInt32; overload;
+    class function Pointer      (constref AValue: Pointer      ): UInt32; overload;
+  public
+    const MAX_HASHLIST_COUNT = 1;
+    const HASH_FUNCTIONS_COUNT = 1;
+    const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (1);
+    const HASH_FUNCTIONS_MASK_SIZE = 1;
+
+    class function GetHashService: THashServiceClass; virtual; abstract;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; virtual; abstract; reintroduce;
+  end;
+
+  TExtendedHashFactory = class(THashFactory)
+  private type
+    PPExtendedEqualityComparerVMT = ^PExtendedEqualityComparerVMT;
+    PExtendedEqualityComparerVMT = ^TExtendedEqualityComparerVMT;
+    TExtendedEqualityComparerVMT = packed record
+      QueryInterface: Pointer;
+      _AddRef: Pointer;
+      _Release: Pointer;
+      Equals: Pointer;
+      GetHashCode: Pointer;
+      GetHashList: Pointer;
+      __ClassRef: TExtendedHashFactoryClass; // hidden field in VMT. For class ref THashFactoryClass
+    end;
+  private
+(***********************************************************************************************************************
+      Hashes 2
+(**********************************************************************************************************************)
+
+    class procedure Int8         (constref AValue: Int8         ; AHashList: PUInt32); overload;
+    class procedure Int16        (constref AValue: Int16        ; AHashList: PUInt32); overload;
+    class procedure Int32        (constref AValue: Int32        ; AHashList: PUInt32); overload;
+    class procedure Int64        (constref AValue: Int64        ; AHashList: PUInt32); overload;
+    class procedure UInt8        (constref AValue: UInt8        ; AHashList: PUInt32); overload;
+    class procedure UInt16       (constref AValue: UInt16       ; AHashList: PUInt32); overload;
+    class procedure UInt32       (constref AValue: UInt32       ; AHashList: PUInt32); overload;
+    class procedure UInt64       (constref AValue: UInt64       ; AHashList: PUInt32); overload;
+    class procedure Single       (constref AValue: Single       ; AHashList: PUInt32); overload;
+    class procedure Double       (constref AValue: Double       ; AHashList: PUInt32); overload;
+    class procedure Extended     (constref AValue: Extended     ; AHashList: PUInt32); overload;
+    class procedure Currency     (constref AValue: Currency     ; AHashList: PUInt32); overload;
+    class procedure Comp         (constref AValue: Comp         ; AHashList: PUInt32); overload;
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class procedure Binary       (constref AValue               ; AHashList: PUInt32); overload;
+    // warning ! self as PSpoofInterfacedTypeSizeObject
+    class procedure DynArray     (constref AValue: Pointer      ; AHashList: PUInt32); overload;
+    class procedure &Class       (constref AValue: TObject      ; AHashList: PUInt32); overload;
+    class procedure ShortString1 (constref AValue: ShortString1 ; AHashList: PUInt32); overload;
+    class procedure ShortString2 (constref AValue: ShortString2 ; AHashList: PUInt32); overload;
+    class procedure ShortString3 (constref AValue: ShortString3 ; AHashList: PUInt32); overload;
+    class procedure ShortString  (constref AValue: ShortString   ; AHashList: PUInt32); overload;
+    class procedure AnsiString   (constref AValue: AnsiString   ; AHashList: PUInt32); overload;
+    class procedure WideString   (constref AValue: WideString   ; AHashList: PUInt32); overload;
+    class procedure UnicodeString(constref AValue: UnicodeString; AHashList: PUInt32); overload;
+    class procedure Method       (constref AValue: TMethod      ; AHashList: PUInt32); overload;
+    class procedure Variant      (constref AValue: PVariant     ; AHashList: PUInt32); overload;
+    class procedure Pointer      (constref AValue: Pointer      ; AHashList: PUInt32); overload;
+  public
+    class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); virtual; abstract;
+  end;
+
+  TComparerService = class abstract
+  private type
+    TSelectMethod = function(ATypeData: PTypeData; ASize: SizeInt): Pointer of object;
+  private
+    class function SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract;
+    class function SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract;
+    class function SelectShortStringEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract;
+    class function SelectBinaryEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract;
+    class function SelectDynArrayEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract;
+  private type
+    PSpoofInterfacedTypeSizeObject = ^TSpoofInterfacedTypeSizeObject;
+    TSpoofInterfacedTypeSizeObject = record
+      VMT: Pointer;
+      RefCount: Integer;
+      Size: SizeInt;
+    end;
+
+    PInstance = ^TInstance;
+    TInstance = record
+      Selector: Boolean;
+      Instance: Pointer;
+
+      class function Create(ASelector: Boolean; AInstance: Pointer): TComparerService.TInstance; static;
+    end;
+
+    PComparerVMT = ^TComparerVMT;
+    TComparerVMT = packed record
+      QueryInterface: Pointer;
+      _AddRef: Pointer;
+      _Release: Pointer;
+      Compare: Pointer;
+    end;
+
+    TSelectFunc = function(ATypeData: PTypeData; ASize: SizeInt): Pointer;
+
+  private
+    class function CreateInterface(AVMT: Pointer; ASize: SizeInt): PSpoofInterfacedTypeSizeObject; static;
+
+    class function SelectIntegerComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static;
+    class function SelectInt64Comparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static;
+    class function SelectFloatComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static;
+    class function SelectShortStringComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static;
+    class function SelectBinaryComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static;
+    class function SelectDynArrayComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static;
+  private const
+    // IComparer VMT
+    Comparer_Int8_VMT  : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int8);
+    Comparer_Int16_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int16 );
+    Comparer_Int32_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int32 );
+    Comparer_Int64_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int64 );
+    Comparer_UInt8_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt8 );
+    Comparer_UInt16_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt16);
+    Comparer_UInt32_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt32);
+    Comparer_UInt64_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt64);
+
+    Comparer_Single_VMT  : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Single  );
+    Comparer_Double_VMT  : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Double  );
+    Comparer_Extended_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Extended);
+
+    Comparer_Currency_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Currency);
+    Comparer_Comp_VMT    : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Comp    );
+
+    Comparer_Binary_VMT  : TComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Compare: @TCompare._Binary  );
+    Comparer_DynArray_VMT: TComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Compare: @TCompare._DynArray);
+
+    Comparer_ShortString1_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString1 );
+    Comparer_ShortString2_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString2 );
+    Comparer_ShortString3_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString3 );
+    Comparer_ShortString_VMT  : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString  );
+    Comparer_AnsiString_VMT   : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.AnsiString   );
+    Comparer_WideString_VMT   : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.WideString   );
+    Comparer_UnicodeString_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UnicodeString);
+
+    Comparer_Method_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Method );
+    Comparer_Variant_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Variant);
+    Comparer_Pointer_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Pointer);
+
+    // Instances
+    Comparer_Int8_Instance  : Pointer = @Comparer_Int8_VMT  ;
+    Comparer_Int16_Instance : Pointer = @Comparer_Int16_VMT ;
+    Comparer_Int32_Instance : Pointer = @Comparer_Int32_VMT ;
+    Comparer_Int64_Instance : Pointer = @Comparer_Int64_VMT ;
+    Comparer_UInt8_Instance : Pointer = @Comparer_UInt8_VMT ;
+    Comparer_UInt16_Instance: Pointer = @Comparer_UInt16_VMT;
+    Comparer_UInt32_Instance: Pointer = @Comparer_UInt32_VMT;
+    Comparer_UInt64_Instance: Pointer = @Comparer_UInt64_VMT;
+
+    Comparer_Single_Instance  : Pointer = @Comparer_Single_VMT  ;
+    Comparer_Double_Instance  : Pointer = @Comparer_Double_VMT  ;
+    Comparer_Extended_Instance: Pointer = @Comparer_Extended_VMT;
+
+    Comparer_Currency_Instance: Pointer = @Comparer_Currency_VMT;
+    Comparer_Comp_Instance    : Pointer = @Comparer_Comp_VMT    ;
+
+    //Comparer_Binary_Instance  : Pointer = @Comparer_Binary_VMT  ;  // dynamic instance
+    //Comparer_DynArray_Instance: Pointer = @Comparer_DynArray_VMT;  // dynamic instance
+
+    Comparer_ShortString1_Instance : Pointer = @Comparer_ShortString1_VMT ;
+    Comparer_ShortString2_Instance : Pointer = @Comparer_ShortString2_VMT ;
+    Comparer_ShortString3_Instance : Pointer = @Comparer_ShortString3_VMT ;
+    Comparer_ShortString_Instance  : Pointer = @Comparer_ShortString_VMT  ;
+    Comparer_AnsiString_Instance   : Pointer = @Comparer_AnsiString_VMT   ;
+    Comparer_WideString_Instance   : Pointer = @Comparer_WideString_VMT   ;
+    Comparer_UnicodeString_Instance: Pointer = @Comparer_UnicodeString_VMT;
+
+    Comparer_Method_Instance : Pointer = @Comparer_Method_VMT ;
+    Comparer_Variant_Instance: Pointer = @Comparer_Variant_VMT;
+    Comparer_Pointer_Instance: Pointer = @Comparer_Pointer_VMT;
+
+    ComparerInstances: array[TTypeKind] of TInstance =
+      (
+        // tkUnknown
+        (Selector: True;  Instance: @TComparerService.SelectBinaryComparer),
+        // tkInteger
+        (Selector: True;  Instance: @TComparerService.SelectIntegerComparer),
+        // tkChar
+        (Selector: False; Instance: @Comparer_UInt8_Instance),
+        // tkEnumeration
+        (Selector: True;  Instance: @TComparerService.SelectIntegerComparer),
+        // tkFloat
+        (Selector: True;  Instance: @TComparerService.SelectFloatComparer),
+        // tkSet
+        (Selector: True;  Instance: @TComparerService.SelectBinaryComparer),
+        // tkMethod
+        (Selector: False; Instance: @Comparer_Method_Instance),
+        // tkSString
+        (Selector: True;  Instance: @TComparerService.SelectShortStringComparer),
+        // tkLString - only internal use / deprecated in compiler
+        (Selector: False; Instance: @Comparer_AnsiString_Instance), // <- unsure
+        // tkAString
+        (Selector: False; Instance: @Comparer_AnsiString_Instance),
+        // tkWString
+        (Selector: False; Instance: @Comparer_WideString_Instance),
+        // tkVariant
+        (Selector: False; Instance: @Comparer_Variant_Instance),
+        // tkArray
+        (Selector: True;  Instance: @TComparerService.SelectBinaryComparer),
+        // tkRecord
+        (Selector: True;  Instance: @TComparerService.SelectBinaryComparer),
+        // tkInterface
+        (Selector: False; Instance: @Comparer_Pointer_Instance),
+        // tkClass
+        (Selector: False; Instance: @Comparer_Pointer_Instance),
+        // tkObject
+        (Selector: True;  Instance: @TComparerService.SelectBinaryComparer),
+        // tkWChar
+        (Selector: False; Instance: @Comparer_UInt16_Instance),
+        // tkBool
+        (Selector: True;  Instance: @TComparerService.SelectIntegerComparer),
+        // tkInt64
+        (Selector: False;  Instance: @Comparer_Int64_Instance),
+        // tkQWord
+        (Selector: False;  Instance: @Comparer_UInt64_Instance),
+        // tkDynArray
+        (Selector: True;  Instance: @TComparerService.SelectDynArrayComparer),
+        // tkInterfaceRaw
+        (Selector: False; Instance: @Comparer_Pointer_Instance),
+        // tkProcVar
+        (Selector: False; Instance: @Comparer_Pointer_Instance),
+        // tkUString
+        (Selector: False; Instance: @Comparer_UnicodeString_Instance),
+        // tkUChar - WTF? ... http://bugs.freepascal.org/view.php?id=24609
+        (Selector: False; Instance: @Comparer_UInt16_Instance), // <- unsure maybe Comparer_UInt32_Instance
+        // tkHelper
+        (Selector: False; Instance: @Comparer_Pointer_Instance),
+        // tkFile
+        (Selector: True;  Instance: @TComparerService.SelectBinaryComparer), // <- unsure what type?
+        // tkClassRef
+        (Selector: False; Instance: @Comparer_Pointer_Instance),
+        // tkPointer
+        (Selector: False; Instance: @Comparer_Pointer_Instance)
+      );
+  public
+    class function LookupComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; static;
+  end;
+
+  THashService = class(TComparerService)
+  public
+    class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; virtual; abstract;
+  end;
+
+  TExtendedHashService = class(THashService)
+  public
+    class function LookupExtendedEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; virtual; abstract;
+  end;
+
+{$DEFINE HASH_FACTORY := PPEqualityComparerVMT(Self)^.__ClassRef}
+{$DEFINE EXTENDED_HASH_FACTORY := PPExtendedEqualityComparerVMT(Self)^.__ClassRef}
+
+  { THashService }
+
+  THashService<T: THashFactory> = class(THashService)
+  private
+    class function SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectShortStringEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectBinaryEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectDynArrayEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+  private const
+    // IEqualityComparer VMT templates
+{$WARNINGS OFF}
+    EqualityComparer_Int8_VMT  : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int8  ; GetHashCode: @THashFactory.Int8  );
+    EqualityComparer_Int16_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int16 ; GetHashCode: @THashFactory.Int16 );
+    EqualityComparer_Int32_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int32 ; GetHashCode: @THashFactory.Int32 );
+    EqualityComparer_Int64_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int64 ; GetHashCode: @THashFactory.Int64 );
+    EqualityComparer_UInt8_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt8 ; GetHashCode: @THashFactory.UInt8 );
+    EqualityComparer_UInt16_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt16; GetHashCode: @THashFactory.UInt16);
+    EqualityComparer_UInt32_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt32; GetHashCode: @THashFactory.UInt32);
+    EqualityComparer_UInt64_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt64; GetHashCode: @THashFactory.UInt64);
+
+    EqualityComparer_Single_VMT  : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Single  ; GetHashCode: @THashFactory.Single  );
+    EqualityComparer_Double_VMT  : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Double  ; GetHashCode: @THashFactory.Double  );
+    EqualityComparer_Extended_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Extended; GetHashCode: @THashFactory.Extended);
+
+    EqualityComparer_Currency_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Currency; GetHashCode: @THashFactory.Currency);
+    EqualityComparer_Comp_VMT    : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Comp    ; GetHashCode: @THashFactory.Comp    );
+
+    EqualityComparer_Binary_VMT  : THashFactory.TEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._Binary  ; GetHashCode: @THashFactory.Binary  );
+    EqualityComparer_DynArray_VMT: THashFactory.TEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._DynArray; GetHashCode: @THashFactory.DynArray);
+
+    EqualityComparer_Class_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.&Class; GetHashCode: @THashFactory.&Class);
+
+    EqualityComparer_ShortString1_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString1 ; GetHashCode: @THashFactory.ShortString1 );
+    EqualityComparer_ShortString2_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString2 ; GetHashCode: @THashFactory.ShortString2 );
+    EqualityComparer_ShortString3_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString3 ; GetHashCode: @THashFactory.ShortString3 );
+    EqualityComparer_ShortString_VMT  : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString  ; GetHashCode: @THashFactory.ShortString  );
+    EqualityComparer_AnsiString_VMT   : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.AnsiString   ; GetHashCode: @THashFactory.AnsiString   );
+    EqualityComparer_WideString_VMT   : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.WideString   ; GetHashCode: @THashFactory.WideString   );
+    EqualityComparer_UnicodeString_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UnicodeString; GetHashCode: @THashFactory.UnicodeString);
+
+    EqualityComparer_Method_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Method ; GetHashCode: @THashFactory.Method );
+    EqualityComparer_Variant_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Variant; GetHashCode: @THashFactory.Variant);
+    EqualityComparer_Pointer_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Pointer; GetHashCode: @THashFactory.Pointer);
+{$WARNINGS ON}
+  private class var
+    // IEqualityComparer VMT
+    FEqualityComparer_Int8_VMT  : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Int16_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Int32_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Int64_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_UInt8_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_UInt16_VMT: THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_UInt32_VMT: THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_UInt64_VMT: THashFactory.TEqualityComparerVMT;
+
+    FEqualityComparer_Single_VMT  : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Double_VMT  : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Extended_VMT: THashFactory.TEqualityComparerVMT;
+
+    FEqualityComparer_Currency_VMT: THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Comp_VMT    : THashFactory.TEqualityComparerVMT;
+
+    FEqualityComparer_Binary_VMT  : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_DynArray_VMT: THashFactory.TEqualityComparerVMT;
+
+    FEqualityComparer_Class_VMT: THashFactory.TEqualityComparerVMT;
+
+    FEqualityComparer_ShortString1_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_ShortString2_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_ShortString3_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_ShortString_VMT  : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_AnsiString_VMT   : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_WideString_VMT   : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_UnicodeString_VMT: THashFactory.TEqualityComparerVMT;
+
+    FEqualityComparer_Method_VMT : THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Variant_VMT: THashFactory.TEqualityComparerVMT;
+    FEqualityComparer_Pointer_VMT: THashFactory.TEqualityComparerVMT;
+
+    FEqualityComparer_Int8_Instance         : Pointer;
+    FEqualityComparer_Int16_Instance        : Pointer;
+    FEqualityComparer_Int32_Instance        : Pointer;
+    FEqualityComparer_Int64_Instance        : Pointer;
+    FEqualityComparer_UInt8_Instance        : Pointer;
+    FEqualityComparer_UInt16_Instance       : Pointer;
+    FEqualityComparer_UInt32_Instance       : Pointer;
+    FEqualityComparer_UInt64_Instance       : Pointer;
+
+    FEqualityComparer_Single_Instance       : Pointer;
+    FEqualityComparer_Double_Instance       : Pointer;
+    FEqualityComparer_Extended_Instance     : Pointer;
+
+    FEqualityComparer_Currency_Instance     : Pointer;
+    FEqualityComparer_Comp_Instance         : Pointer;
+
+    //FEqualityComparer_Binary_Instance     : Pointer;  // dynamic instance
+    //FEqualityComparer_DynArray_Instance   : Pointer;  // dynamic instance
+
+    FEqualityComparer_ShortString1_Instance : Pointer;
+    FEqualityComparer_ShortString2_Instance : Pointer;
+    FEqualityComparer_ShortString3_Instance : Pointer;
+    FEqualityComparer_ShortString_Instance  : Pointer;
+    FEqualityComparer_AnsiString_Instance   : Pointer;
+    FEqualityComparer_WideString_Instance   : Pointer;
+    FEqualityComparer_UnicodeString_Instance: Pointer;
+
+    FEqualityComparer_Method_Instance       : Pointer;
+    FEqualityComparer_Variant_Instance      : Pointer;
+    FEqualityComparer_Pointer_Instance      : Pointer;
+
+
+    FEqualityComparerInstances: array[TTypeKind] of TInstance;
+  private
+    class constructor Create;
+  public
+    class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override;
+  end;
+
+  { TExtendedHashService }
+
+  TExtendedHashService<T: TExtendedHashFactory> = class(TExtendedHashService)
+  private
+    class function SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectShortStringEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectBinaryEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+    class function SelectDynArrayEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override;
+  private const
+    // IExtendedEqualityComparer VMT templates
+{$WARNINGS OFF}
+    ExtendedEqualityComparer_Int8_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int8  ; GetHashCode: @THashFactory.Int8  ; GetHashList: @TExtendedHashFactory.Int8  );
+    ExtendedEqualityComparer_Int16_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int16 ; GetHashCode: @THashFactory.Int16 ; GetHashList: @TExtendedHashFactory.Int16 );
+    ExtendedEqualityComparer_Int32_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int32 ; GetHashCode: @THashFactory.Int32 ; GetHashList: @TExtendedHashFactory.Int32 );
+    ExtendedEqualityComparer_Int64_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int64 ; GetHashCode: @THashFactory.Int64 ; GetHashList: @TExtendedHashFactory.Int64 );
+    ExtendedEqualityComparer_UInt8_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt8 ; GetHashCode: @THashFactory.UInt8 ; GetHashList: @TExtendedHashFactory.UInt8 );
+    ExtendedEqualityComparer_UInt16_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt16; GetHashCode: @THashFactory.UInt16; GetHashList: @TExtendedHashFactory.UInt16);
+    ExtendedEqualityComparer_UInt32_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt32; GetHashCode: @THashFactory.UInt32; GetHashList: @TExtendedHashFactory.UInt32);
+    ExtendedEqualityComparer_UInt64_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt64; GetHashCode: @THashFactory.UInt64; GetHashList: @TExtendedHashFactory.UInt64);
+
+    ExtendedEqualityComparer_Single_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Single  ; GetHashCode: @THashFactory.Single  ; GetHashList: @TExtendedHashFactory.Single  );
+    ExtendedEqualityComparer_Double_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Double  ; GetHashCode: @THashFactory.Double  ; GetHashList: @TExtendedHashFactory.Double  );
+    ExtendedEqualityComparer_Extended_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Extended; GetHashCode: @THashFactory.Extended; GetHashList: @TExtendedHashFactory.Extended);
+
+    ExtendedEqualityComparer_Currency_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Currency; GetHashCode: @THashFactory.Currency; GetHashList: @TExtendedHashFactory.Currency);
+    ExtendedEqualityComparer_Comp_VMT    : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Comp    ; GetHashCode: @THashFactory.Comp    ; GetHashList: @TExtendedHashFactory.Comp    );
+
+    ExtendedEqualityComparer_Binary_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._Binary  ; GetHashCode: @THashFactory.Binary  ; GetHashList: @TExtendedHashFactory.Binary   );
+    ExtendedEqualityComparer_DynArray_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._DynArray; GetHashCode: @THashFactory.DynArray; GetHashList: @TExtendedHashFactory.DynArray);
+
+    ExtendedEqualityComparer_Class_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.&Class; GetHashCode: @THashFactory.&Class; GetHashList: @TExtendedHashFactory.&Class);
+
+    ExtendedEqualityComparer_ShortString1_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString1 ; GetHashCode: @THashFactory.ShortString1 ; GetHashList: @TExtendedHashFactory.ShortString1 );
+    ExtendedEqualityComparer_ShortString2_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString2 ; GetHashCode: @THashFactory.ShortString2 ; GetHashList: @TExtendedHashFactory.ShortString2 );
+    ExtendedEqualityComparer_ShortString3_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString3 ; GetHashCode: @THashFactory.ShortString3 ; GetHashList: @TExtendedHashFactory.ShortString3 );
+    ExtendedEqualityComparer_ShortString_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString  ; GetHashCode: @THashFactory.ShortString  ; GetHashList: @TExtendedHashFactory.ShortString  );
+    ExtendedEqualityComparer_AnsiString_VMT   : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.AnsiString   ; GetHashCode: @THashFactory.AnsiString   ; GetHashList: @TExtendedHashFactory.AnsiString   );
+    ExtendedEqualityComparer_WideString_VMT   : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.WideString   ; GetHashCode: @THashFactory.WideString   ; GetHashList: @TExtendedHashFactory.WideString   );
+    ExtendedEqualityComparer_UnicodeString_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UnicodeString; GetHashCode: @THashFactory.UnicodeString; GetHashList: @TExtendedHashFactory.UnicodeString);
+
+    ExtendedEqualityComparer_Method_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Method ; GetHashCode: @THashFactory.Method ; GetHashList: @TExtendedHashFactory.Method );
+    ExtendedEqualityComparer_Variant_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Variant; GetHashCode: @THashFactory.Variant; GetHashList: @TExtendedHashFactory.Variant);
+    ExtendedEqualityComparer_Pointer_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Pointer; GetHashCode: @THashFactory.Pointer; GetHashList: @TExtendedHashFactory.Pointer);
+{$WARNINGS ON}
+  private class var
+    // IExtendedEqualityComparer VMT
+    FExtendedEqualityComparer_Int8_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Int16_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Int32_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Int64_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_UInt8_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_UInt16_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_UInt32_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_UInt64_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+
+    FExtendedEqualityComparer_Single_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Double_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Extended_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+
+    FExtendedEqualityComparer_Currency_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Comp_VMT    : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+
+    FExtendedEqualityComparer_Binary_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_DynArray_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+
+    FExtendedEqualityComparer_Class_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+
+    FExtendedEqualityComparer_ShortString1_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_ShortString2_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_ShortString3_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_ShortString_VMT  : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_AnsiString_VMT   : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_WideString_VMT   : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_UnicodeString_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+
+    FExtendedEqualityComparer_Method_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Variant_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+    FExtendedEqualityComparer_Pointer_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT;
+
+    FExtendedEqualityComparer_Int8_Instance         : Pointer;
+    FExtendedEqualityComparer_Int16_Instance        : Pointer;
+    FExtendedEqualityComparer_Int32_Instance        : Pointer;
+    FExtendedEqualityComparer_Int64_Instance        : Pointer;
+    FExtendedEqualityComparer_UInt8_Instance        : Pointer;
+    FExtendedEqualityComparer_UInt16_Instance       : Pointer;
+    FExtendedEqualityComparer_UInt32_Instance       : Pointer;
+    FExtendedEqualityComparer_UInt64_Instance       : Pointer;
+
+    FExtendedEqualityComparer_Single_Instance       : Pointer;
+    FExtendedEqualityComparer_Double_Instance       : Pointer;
+    FExtendedEqualityComparer_Extended_Instance     : Pointer;
+
+    FExtendedEqualityComparer_Currency_Instance     : Pointer;
+    FExtendedEqualityComparer_Comp_Instance         : Pointer;
+
+    //FExtendedEqualityComparer_Binary_Instance     : Pointer;  // dynamic instance
+    //FExtendedEqualityComparer_DynArray_Instance   : Pointer;  // dynamic instance
+
+    FExtendedEqualityComparer_ShortString1_Instance : Pointer;
+    FExtendedEqualityComparer_ShortString2_Instance : Pointer;
+    FExtendedEqualityComparer_ShortString3_Instance : Pointer;
+    FExtendedEqualityComparer_ShortString_Instance  : Pointer;
+    FExtendedEqualityComparer_AnsiString_Instance   : Pointer;
+    FExtendedEqualityComparer_WideString_Instance   : Pointer;
+    FExtendedEqualityComparer_UnicodeString_Instance: Pointer;
+
+    FExtendedEqualityComparer_Method_Instance       : Pointer;
+    FExtendedEqualityComparer_Variant_Instance      : Pointer;
+    FExtendedEqualityComparer_Pointer_Instance      : Pointer;
+
+    // all instances
+    FExtendedEqualityComparerInstances: array[TTypeKind] of TInstance;
+  private
+    class constructor Create;
+  public
+    class function LookupExtendedEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override;
+  end;
+
+  TOnEqualityComparison<T> = function(constref ALeft, ARight: T): Boolean of object;
+  TEqualityComparisonFunc<T> = function(constref ALeft, ARight: T): Boolean;
+
+  TOnHasher<T> = function(constref AValue: T): UInt32 of object;
+  TOnExtendedHasher<T> = procedure(constref AValue: T; AHashList: PUInt32) of object;
+  THasherFunc<T> = function(constref AValue: T): UInt32;
+  TExtendedHasherFunc<T> = procedure(constref AValue: T; AHashList: PUInt32);
+
+  TEqualityComparer<T> = class(TInterfacedObject, IEqualityComparer<T>)
+  public
+    class function Default: IEqualityComparer<T>; static; overload;
+    class function Default(AHashFactoryClass: THashFactoryClass): IEqualityComparer<T>; static; overload;
+
+    class function Construct(const AEqualityComparison: TOnEqualityComparison<T>;
+      const AHasher: TOnHasher<T>): IEqualityComparer<T>; overload;
+    class function Construct(const AEqualityComparison: TEqualityComparisonFunc<T>;
+      const AHasher: THasherFunc<T>): IEqualityComparer<T>; overload;
+
+    function Equals(constref ALeft, ARight: T): Boolean; virtual; overload; abstract;
+    function GetHashCode(constref AValue: T): UInt32;  virtual; overload; abstract;
+  end;
+
+  { TDelegatedEqualityComparerEvent }
+
+  TDelegatedEqualityComparerEvents<T> = class(TEqualityComparer<T>)
+  private
+    FEqualityComparison: TOnEqualityComparison<T>;
+    FHasher: TOnHasher<T>;
+  public
+    function Equals(constref ALeft, ARight: T): Boolean; override;
+    function GetHashCode(constref AValue: T): UInt32; override;
+
+    constructor Create(const AEqualityComparison: TOnEqualityComparison<T>;
+      const AHasher: TOnHasher<T>);
+  end;
+
+  TDelegatedEqualityComparerFunc<T> = class(TEqualityComparer<T>)
+  private
+    FEqualityComparison: TEqualityComparisonFunc<T>;
+    FHasher: THasherFunc<T>;
+  public
+    function Equals(constref ALeft, ARight: T): Boolean; override;
+    function GetHashCode(constref AValue: T): UInt32; override;
+
+    constructor Create(const AEqualityComparison: TEqualityComparisonFunc<T>;
+      const AHasher: THasherFunc<T>);
+  end;
+
+  { TExtendedEqualityComparer }
+
+  TExtendedEqualityComparer<T> = class(TEqualityComparer<T>, IExtendedEqualityComparer<T>)
+  public
+    class function Default: IExtendedEqualityComparer<T>; static; overload; reintroduce;
+    class function Default(AExtenedHashFactoryClass: TExtendedHashFactoryClass): IExtendedEqualityComparer<T>; static; overload; reintroduce;
+
+    class function Construct(const AEqualityComparison: TOnEqualityComparison<T>;
+       const AHasher: TOnHasher<T>; const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>; overload; reintroduce;
+    class function Construct(const AEqualityComparison: TEqualityComparisonFunc<T>;
+       const AHasher: THasherFunc<T>; const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>; overload; reintroduce;
+    class function Construct(const AEqualityComparison: TOnEqualityComparison<T>;
+       const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>; overload; reintroduce;
+    class function Construct(const AEqualityComparison: TEqualityComparisonFunc<T>;
+       const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>; overload; reintroduce;
+
+    procedure GetHashList(constref AValue: T; AHashList: PUInt32); virtual; abstract;
+  end;
+
+  TDelegatedExtendedEqualityComparerEvents<T> = class(TExtendedEqualityComparer<T>)
+  private
+    FEqualityComparison: TOnEqualityComparison<T>;
+    FHasher: TOnHasher<T>;
+    FExtendedHasher: TOnExtendedHasher<T>;
+
+    function GetHashCodeMethod(constref AValue: T): UInt32;
+  public
+    function Equals(constref ALeft, ARight: T): Boolean; override;
+    function GetHashCode(constref AValue: T): UInt32; override;
+    procedure GetHashList(constref AValue: T; AHashList: PUInt32); override;
+
+    constructor Create(const AEqualityComparison: TOnEqualityComparison<T>;
+      const AHasher: TOnHasher<T>; const AExtendedHasher: TOnExtendedHasher<T>); overload;
+    constructor Create(const AEqualityComparison: TOnEqualityComparison<T>;
+      const AExtendedHasher: TOnExtendedHasher<T>); overload;
+  end;
+
+  TDelegatedExtendedEqualityComparerFunc<T> = class(TExtendedEqualityComparer<T>)
+  private
+    FEqualityComparison: TEqualityComparisonFunc<T>;
+    FHasher: THasherFunc<T>;
+    FExtendedHasher: TExtendedHasherFunc<T>;
+  public
+    function Equals(constref ALeft, ARight: T): Boolean; override;
+    function GetHashCode(constref AValue: T): UInt32; override;
+    procedure GetHashList(constref AValue: T; AHashList: PUInt32); override;
+
+    constructor Create(const AEqualityComparison: TEqualityComparisonFunc<T>;
+      const AHasher: THasherFunc<T>; const AExtendedHasher: TExtendedHasherFunc<T>); overload;
+    constructor Create(const AEqualityComparison: TEqualityComparisonFunc<T>;
+      const AExtendedHasher: TExtendedHasherFunc<T>); overload;
+  end;
+
+  { TDelphiHashFactory }
+
+  TDelphiHashFactory = class(THashFactory)
+  public
+    class function GetHashService: THashServiceClass; override;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override;
+  end;
+
+  { TAdler32HashFactory }
+
+  TAdler32HashFactory = class(THashFactory)
+  public
+    class function GetHashService: THashServiceClass; override;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override;
+  end;
+
+  { TSdbmHashFactory }
+
+  TSdbmHashFactory = class(THashFactory)
+  public
+    class function GetHashService: THashServiceClass; override;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override;
+  end;
+
+  { TSdbmHashFactory }
+
+  TSimpleChecksumFactory = class(THashFactory)
+  public
+    class function GetHashService: THashServiceClass; override;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override;
+  end;
+
+  { TDelphiDoubleHashFactory }
+
+  TDelphiDoubleHashFactory = class(TExtendedHashFactory)
+  public
+    const MAX_HASHLIST_COUNT = 2;
+    const HASH_FUNCTIONS_COUNT = 1;
+    const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (2);
+    const HASH_FUNCTIONS_MASK_SIZE = 1;
+    const HASH_FUNCTIONS_MASK = 1; // 00000001b
+
+    class function GetHashService: THashServiceClass; override;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override;
+    class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); override;
+  end;
+
+  TDelphiQuadrupleHashFactory = class(TExtendedHashFactory)
+  public
+    const MAX_HASHLIST_COUNT = 4;
+    const HASH_FUNCTIONS_COUNT = 2;
+    const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (2, 2);
+    const HASH_FUNCTIONS_MASK_SIZE = 2;
+    const HASH_FUNCTIONS_MASK = 3; // 00000011b
+
+    class function GetHashService: THashServiceClass; override;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override;
+    class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); override;
+  end;
+
+  TDelphiSixfoldHashFactory = class(TExtendedHashFactory)
+  public
+    const MAX_HASHLIST_COUNT = 6;
+    const HASH_FUNCTIONS_COUNT = 3;
+    const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (2, 2, 2);
+    const HASH_FUNCTIONS_MASK_SIZE = 3;
+    const HASH_FUNCTIONS_MASK = 7; // 00000111b
+
+    class function GetHashService: THashServiceClass; override;
+    class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override;
+    class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); override;
+  end;
+
+  TDefaultHashFactory = TDelphiQuadrupleHashFactory;
+
+  TDefaultGenericInterface = (giComparer, giEqualityComparer, giExtendedEqualityComparer);
+
+  TCustomComparer<T> = class(TSingletonImplementation, IComparer<T>, IEqualityComparer<T>, IExtendedEqualityComparer<T>)
+  protected
+    function Compare(constref Left, Right: T): Integer; virtual; abstract;
+    function Equals(constref Left, Right: T): Boolean; reintroduce; overload; virtual; abstract;
+    function GetHashCode(constref Value: T): UInt32; reintroduce; overload; virtual; abstract;
+    procedure GetHashList(constref Value: T; AHashList: PUInt32); virtual; abstract;
+  end;
+
+  TOrdinalComparer<T, THashFactory> = class(TCustomComparer<T>)
+  protected class var
+    FComparer: IComparer<T>;
+    FEqualityComparer: IEqualityComparer<T>;
+    FExtendedEqualityComparer: IExtendedEqualityComparer<T>;
+
+    class constructor Create;
+  public
+    class function Ordinal: TCustomComparer<T>; virtual; abstract;
+  end;
+
+  // TGStringComparer will be renamed to TStringComparer -> bug #26030
+  // anyway class var can't be used safely -> bug #24848
+
+  TGStringComparer<T, THashFactory> = class(TOrdinalComparer<T, THashFactory>)
+  private class var
+    FOrdinal: TCustomComparer<T>;
+    class destructor Destroy;
+  public
+    class function Ordinal: TCustomComparer<T>; override;
+  end;
+
+  TGStringComparer<T> = class(TGStringComparer<T, TDelphiQuadrupleHashFactory>);
+  TStringComparer = class(TGStringComparer<string>);
+  TAnsiStringComparer = class(TGStringComparer<AnsiString>);
+  TUnicodeStringComparer = class(TGStringComparer<UnicodeString>);
+
+  { TGOrdinalStringComparer }
+
+  // TGOrdinalStringComparer will be renamed to TOrdinalStringComparer -> bug #26030
+  // anyway class var can't be used safely -> bug #24848
+  TGOrdinalStringComparer<T, THashFactory> = class(TGStringComparer<T, THashFactory>)
+  public
+    function Compare(constref ALeft, ARight: T): Integer; override;
+    function Equals(constref ALeft, ARight: T): Boolean; overload; override;
+    function GetHashCode(constref AValue: T): UInt32; overload; override;
+    procedure GetHashList(constref AValue: T; AHashList: PUInt32); override;
+  end;
+
+  TGOrdinalStringComparer<T> = class(TGOrdinalStringComparer<T, TDelphiQuadrupleHashFactory>);
+  TOrdinalStringComparer = class(TGOrdinalStringComparer<string>);
+
+  TGIStringComparer<T, THashFactory> = class(TOrdinalComparer<T, THashFactory>)
+  private class var
+    FOrdinal: TCustomComparer<T>;
+    class destructor Destroy;
+  public
+    class function Ordinal: TCustomComparer<T>; override;
+  end;
+
+  TGIStringComparer<T> = class(TGIStringComparer<T, TDelphiQuadrupleHashFactory>);
+  TIStringComparer = class(TGIStringComparer<string>);
+  TIAnsiStringComparer = class(TGIStringComparer<AnsiString>);
+  TIUnicodeStringComparer = class(TGIStringComparer<UnicodeString>);
+
+  TGOrdinalIStringComparer<T, THashFactory> = class(TGIStringComparer<T, THashFactory>)
+  public
+    function Compare(constref ALeft, ARight: T): Integer; override;
+    function Equals(constref ALeft, ARight: T): Boolean; overload; override;
+    function GetHashCode(constref AValue: T): UInt32; overload; override;
+    procedure GetHashList(constref AValue: T; AHashList: PUInt32); override;
+  end;
+
+  TGOrdinalIStringComparer<T> = class(TGOrdinalIStringComparer<T, TDelphiQuadrupleHashFactory>);
+  TOrdinalIStringComparer = class(TGOrdinalIStringComparer<string>);
+
+// Delphi version of Bob Jenkins Hash
+function BobJenkinsHash(const AData; ALength, AInitData: Integer): Integer; // same result as HashLittle_Delphi, just different interface
+function BinaryCompare(const ALeft, ARight: Pointer; ASize: PtrUInt): Integer; inline;
+
+function _LookupVtableInfo(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; inline;
+function _LookupVtableInfoEx(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt;
+  AFactory: THashFactoryClass): Pointer;
+
+implementation
+
+{ TComparer<T> }
+
+class function TComparer<T>.Default: IComparer<T>;
+begin
+  Result := _LookupVtableInfo(giComparer, TypeInfo(T), SizeOf(T));
+end;
+
+class function TComparer<T>.Construct(const AComparison: TOnComparison<T>): IComparer<T>;
+begin
+  Result := TDelegatedComparerEvents<T>.Create(AComparison);
+end;
+
+class function TComparer<T>.Construct(const AComparison: TComparisonFunc<T>): IComparer<T>;
+begin
+  Result := TDelegatedComparerFunc<T>.Create(AComparison);
+end;
+
+function TDelegatedComparerEvents<T>.Compare(constref ALeft, ARight: T): Integer;
+begin
+  Result := FComparison(ALeft, ARight);
+end;
+
+constructor TDelegatedComparerEvents<T>.Create(AComparison: TOnComparison<T>);
+begin
+  FComparison := AComparison;
+end;
+
+function TDelegatedComparerFunc<T>.Compare(constref ALeft, ARight: T): Integer;
+begin
+  Result := FComparison(ALeft, ARight);
+end;
+
+constructor TDelegatedComparerFunc<T>.Create(AComparison: TComparisonFunc<T>);
+begin
+  FComparison := AComparison;
+end;
+
+{ TInterface }
+
+function TInterface.QueryInterface(constref IID: TGUID; out Obj): HResult;
+begin
+  Result := E_NOINTERFACE;
+end;
+
+{ TRawInterface }
+
+function TRawInterface._AddRef: Integer;
+begin
+  Result := -1;
+end;
+
+function TRawInterface._Release: Integer;
+begin
+  Result := -1;
+end;
+
+{ TComTypeSizeInterface }
+
+function TComTypeSizeInterface._AddRef: Integer;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  Result := InterLockedIncrement(_self.RefCount);
+end;
+
+function TComTypeSizeInterface._Release: Integer;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  Result := InterLockedDecrement(_self.RefCount);
+  if _self.RefCount = 0 then
+    Dispose(_self);
+end;
+
+{ TSingletonImplementation }
+
+function TSingletonImplementation.QueryInterface(constref IID: TGUID; out Obj): HResult;
+begin
+  if GetInterface(IID, Obj) then
+    Result := S_OK
+  else
+    Result := E_NOINTERFACE;
+end;
+
+{ TCompare }
+
+(***********************************************************************************************************************
+  Comparers
+(**********************************************************************************************************************)
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers Int8 - Int32 and UInt8 - UInt32
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare.Integer(constref ALeft, ARight: Integer): Integer;
+begin
+  Result := Math.CompareValue(ALeft, ARight);
+end;
+
+class function TCompare.Int8(constref ALeft, ARight: Int8): Integer;
+begin
+  Result := ALeft - ARight;
+end;
+
+class function TCompare.Int16(constref ALeft, ARight: Int16): Integer;
+begin
+  Result := ALeft - ARight;
+end;
+
+class function TCompare.Int32(constref ALeft, ARight: Int32): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.Int64(constref ALeft, ARight: Int64): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.UInt8(constref ALeft, ARight: UInt8): Integer;
+begin
+  Result := System.Integer(ALeft) - System.Integer(ARight);
+end;
+
+class function TCompare.UInt16(constref ALeft, ARight: UInt16): Integer;
+begin
+  Result := System.Integer(ALeft) - System.Integer(ARight);
+end;
+
+class function TCompare.UInt32(constref ALeft, ARight: UInt32): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.UInt64(constref ALeft, ARight: UInt64): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers for Float types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare.Single(constref ALeft, ARight: Single): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.Double(constref ALeft, ARight: Double): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.Extended(constref ALeft, ARight: Extended): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers for other number types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare.Currency(constref ALeft, ARight: Currency): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.Comp(constref ALeft, ARight: Comp): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers for binary data (records etc) and dynamics arrays
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare._Binary(constref ALeft, ARight): Integer;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  Result := CompareMemRange(@ALeft, @ARight, _self.Size);
+end;
+
+class function TCompare._DynArray(constref ALeft, ARight: Pointer): Integer;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+  LLength, LLeftLength, LRightLength: Integer;
+begin
+  LLeftLength := DynArraySize(ALeft);
+  LRightLength := DynArraySize(ARight);
+  if LLeftLength > LRightLength then
+    LLength := LRightLength
+  else
+    LLength := LLeftLength;
+
+  Result := CompareMemRange(ALeft, ARight, LLength * _self.Size);
+
+  if Result = 0 then
+    Result := LLeftLength - LRightLength;
+end;
+
+class function TCompare.Binary(constref ALeft, ARight; const ASize: SizeInt): Integer;
+begin
+  Result := CompareMemRange(@ALeft, @ARight, ASize);
+end;
+
+class function TCompare.DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Integer;
+var
+  LLength, LLeftLength, LRightLength: Integer;
+begin
+  LLeftLength := DynArraySize(ALeft);
+  LRightLength := DynArraySize(ARight);
+  if LLeftLength > LRightLength then
+    LLength := LRightLength
+  else
+    LLength := LLeftLength;
+
+  Result := CompareMemRange(ALeft, ARight, LLength * AElementSize);
+
+  if Result = 0 then
+    Result := LLeftLength - LRightLength;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers for string types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare.ShortString1(constref ALeft, ARight: ShortString1): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.ShortString2(constref ALeft, ARight: ShortString2): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.ShortString3(constref ALeft, ARight: ShortString3): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.ShortString(constref ALeft, ARight: ShortString): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+class function TCompare.&String(constref ALeft, ARight: String): Integer;
+begin
+  Result := CompareStr(ALeft, ARight);
+end;
+
+class function TCompare.AnsiString(constref ALeft, ARight: AnsiString): Integer;
+begin
+  Result := AnsiCompareStr(ALeft, ARight);
+end;
+
+class function TCompare.WideString(constref ALeft, ARight: WideString): Integer;
+begin
+  Result := WideCompareStr(ALeft, ARight);
+end;
+
+class function TCompare.UnicodeString(constref ALeft, ARight: UnicodeString): Integer;
+begin
+  Result := UnicodeCompareStr(ALeft, ARight);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers for Delegates
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare.Method(constref ALeft, ARight: TMethod): Integer;
+begin
+  Result := CompareMemRange(@ALeft, @ARight, SizeOf(System.TMethod));
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers for Variant
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare.Variant(constref ALeft, ARight: PVariant): Integer;
+var
+  LLeftString, LRightString: string;
+begin
+  try
+    case VarCompareValue(ALeft^, ARight^) of
+      vrGreaterThan:
+        Exit(1);
+      vrLessThan:
+        Exit(-1);
+      vrEqual:
+        Exit(0);
+      vrNotEqual:
+        if VarIsEmpty(ALeft^) or VarIsNull(ALeft^) then
+          Exit(1)
+        else
+          Exit(-1);
+    end;
+  except
+    try
+      LLeftString := ALeft^;
+      LRightString := ARight^;
+      Result := CompareStr(LLeftString, LRightString);
+    except
+      Result := CompareMemRange(ALeft, ARight, SizeOf(System.Variant));
+    end;
+  end;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Comparers for Pointer
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TCompare.Pointer(constref ALeft, ARight: PtrUInt): Integer;
+begin
+  if ALeft > ARight then
+    Exit(1)
+  else if ALeft < ARight then
+    Exit(-1)
+  else
+    Exit(0);
+end;
+
+{ TEquals }
+
+(***********************************************************************************************************************
+  Equality Comparers
+(**********************************************************************************************************************)
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers Int8 - Int32 and UInt8 - UInt32
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.Integer(constref ALeft, ARight: Integer): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.Int8(constref ALeft, ARight: Int8): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.Int16(constref ALeft, ARight: Int16): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.Int32(constref ALeft, ARight: Int32): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.Int64(constref ALeft, ARight: Int64): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.UInt8(constref ALeft, ARight: UInt8): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.UInt16(constref ALeft, ARight: UInt16): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.UInt32(constref ALeft, ARight: UInt32): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.UInt64(constref ALeft, ARight: UInt64): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for Float types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.Single(constref ALeft, ARight: Single): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.Double(constref ALeft, ARight: Double): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.Extended(constref ALeft, ARight: Extended): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for other number types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.Currency(constref ALeft, ARight: Currency): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.Comp(constref ALeft, ARight: Comp): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for binary data (records etc) and dynamics arrays
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals._Binary(constref ALeft, ARight): Boolean;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  Result := CompareMem(@ALeft, @ARight, _self.Size);
+end;
+
+class function TEquals._DynArray(constref ALeft, ARight: Pointer): Boolean;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+  LLength: Integer;
+begin
+  LLength := DynArraySize(ALeft);
+  if LLength <> DynArraySize(ARight) then
+    Exit(False);
+
+  Result := CompareMem(ALeft, ARight, LLength * _self.Size);
+end;
+
+class function TEquals.Binary(constref ALeft, ARight; const ASize: SizeInt): Boolean;
+begin
+  Result := CompareMem(@ALeft, @ARight, ASize);
+end;
+
+class function TEquals.DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Boolean;
+var
+  LLength: Integer;
+begin
+  LLength := DynArraySize(ALeft);
+  if LLength <> DynArraySize(ARight) then
+    Exit(False);
+
+  Result := CompareMem(ALeft, ARight, LLength * AElementSize);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for classes
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.&class(constref ALeft, ARight: TObject): Boolean;
+begin
+  if ALeft <> nil then
+    Exit(ALeft.Equals(ARight))
+  else
+    Exit(ARight = nil);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for string types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.ShortString1(constref ALeft, ARight: ShortString1): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.ShortString2(constref ALeft, ARight: ShortString2): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.ShortString3(constref ALeft, ARight: ShortString3): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.&String(constref ALeft, ARight: String): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.ShortString(constref ALeft, ARight: ShortString): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.AnsiString(constref ALeft, ARight: AnsiString): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.WideString(constref ALeft, ARight: WideString): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+class function TEquals.UnicodeString(constref ALeft, ARight: UnicodeString): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for Delegates
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.Method(constref ALeft, ARight: TMethod): Boolean;
+begin
+  Result := (ALeft.Code = ARight.Code) and (ALeft.Data = ARight.Data);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for Variant
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.Variant(constref ALeft, ARight: PVariant): Boolean;
+begin
+  Result := VarCompareValue(ALeft^, ARight^) = vrEqual;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  Equality Comparers for Pointer
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function TEquals.Pointer(constref ALeft, ARight: PtrUInt): Boolean;
+begin
+  Result := ALeft = ARight;
+end;
+
+(***********************************************************************************************************************
+  Hashes
+(**********************************************************************************************************************)
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode Int8 - Int32 and UInt8 - UInt32
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.Int8(constref AValue: Int8): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int8), 0);
+end;
+
+class function THashFactory.Int16(constref AValue: Int16): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int16), 0);
+end;
+
+class function THashFactory.Int32(constref AValue: Int32): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int32), 0);
+end;
+
+class function THashFactory.Int64(constref AValue: Int64): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int64), 0);
+end;
+
+class function THashFactory.UInt8(constref AValue: UInt8): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt8), 0);
+end;
+
+class function THashFactory.UInt16(constref AValue: UInt16): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt16), 0);
+end;
+
+class function THashFactory.UInt32(constref AValue: UInt32): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt32), 0);
+end;
+
+class function THashFactory.UInt64(constref AValue: UInt64): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt64), 0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Float types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.Single(constref AValue: Single): UInt32;
+var
+  LMantissa: Float;
+  LExponent: Integer;
+begin
+  Frexp(AValue, LMantissa, LExponent);
+
+  if LMantissa = 0 then
+    LMantissa := Abs(LMantissa);
+
+  Result := HASH_FACTORY.GetHashCode(@LMantissa, SizeOf(Math.Float), 0);
+  Result := HASH_FACTORY.GetHashCode(@LExponent, SizeOf(System.Integer), Result);
+end;
+
+class function THashFactory.Double(constref AValue: Double): UInt32;
+var
+  LMantissa: Float;
+  LExponent: Integer;
+begin
+  Frexp(AValue, LMantissa, LExponent);
+
+  if LMantissa = 0 then
+    LMantissa := Abs(LMantissa);
+
+  Result := HASH_FACTORY.GetHashCode(@LMantissa, SizeOf(Math.Float), 0);
+  Result := HASH_FACTORY.GetHashCode(@LExponent, SizeOf(System.Integer), Result);
+end;
+
+class function THashFactory.Extended(constref AValue: Extended): UInt32;
+var
+  LMantissa: Float;
+  LExponent: Integer;
+begin
+  Frexp(AValue, LMantissa, LExponent);
+
+  if LMantissa = 0 then
+    LMantissa := Abs(LMantissa);
+
+  Result := HASH_FACTORY.GetHashCode(@LMantissa, SizeOf(Math.Float), 0);
+  Result := HASH_FACTORY.GetHashCode(@LExponent, SizeOf(System.Integer), Result);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for other number types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.Currency(constref AValue: Currency): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int64), 0);
+end;
+
+class function THashFactory.Comp(constref AValue: Comp): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int64), 0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for binary data (records etc) and dynamics arrays
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.Binary(constref AValue): UInt32;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, _self.Size, 0);
+end;
+
+class function THashFactory.DynArray(constref AValue: Pointer): UInt32;
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  Result := HASH_FACTORY.GetHashCode(AValue, DynArraySize(AValue) * _self.Size, 0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for classes
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.&Class(constref AValue: TObject): UInt32;
+begin
+  if AValue = nil then
+    Exit($2A);
+
+  Result := AValue.GetHashCode;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for string types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.ShortString1(constref AValue: ShortString1): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0);
+end;
+
+class function THashFactory.ShortString2(constref AValue: ShortString2): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0);
+end;
+
+class function THashFactory.ShortString3(constref AValue: ShortString3): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0);
+end;
+
+class function THashFactory.ShortString(constref AValue: ShortString): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0);
+end;
+
+class function THashFactory.AnsiString(constref AValue: AnsiString): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue) * SizeOf(System.AnsiChar), 0);
+end;
+
+class function THashFactory.WideString(constref AValue: WideString): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue) * SizeOf(System.WideChar), 0);
+end;
+
+class function THashFactory.UnicodeString(constref AValue: UnicodeString): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue) * SizeOf(System.UnicodeChar), 0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Delegates
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.Method(constref AValue: TMethod): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.TMethod), 0);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Variant
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.Variant(constref AValue: PVariant): UInt32;
+begin
+  try
+    Result := HASH_FACTORY.UnicodeString(AValue^);
+  except
+    Result := HASH_FACTORY.GetHashCode(AValue, SizeOf(System.Variant), 0);
+  end;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Pointer
+{----------------------------------------------------------------------------------------------------------------------}
+
+class function THashFactory.Pointer(constref AValue: Pointer): UInt32;
+begin
+  Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Pointer), 0);
+end;
+
+{ TExtendedHashFactory }
+
+(***********************************************************************************************************************
+  Hashes 2
+(**********************************************************************************************************************)
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode Int8 - Int32 and UInt8 - UInt32
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.Int8(constref AValue: Int8; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int8), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.Int16(constref AValue: Int16; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int16), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.Int32(constref AValue: Int32; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int32), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.Int64(constref AValue: Int64; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int64), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.UInt8(constref AValue: UInt8; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt8), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.UInt16(constref AValue: UInt16; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt16), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.UInt32(constref AValue: UInt32; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt32), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.UInt64(constref AValue: UInt64; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt64), AHashList, []);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Float types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.Single(constref AValue: Single; AHashList: PUInt32);
+var
+  LMantissa: Float;
+  LExponent: Integer;
+begin
+  Frexp(AValue, LMantissa, LExponent);
+
+  if LMantissa = 0 then
+    LMantissa := Abs(LMantissa);
+
+  EXTENDED_HASH_FACTORY.GetHashList(@LMantissa, SizeOf(Math.Float), AHashList, []);
+  EXTENDED_HASH_FACTORY.GetHashList(@LExponent, SizeOf(System.Integer), AHashList, [ghloHashListAsInitData]);
+end;
+
+class procedure TExtendedHashFactory.Double(constref AValue: Double; AHashList: PUInt32);
+var
+  LMantissa: Float;
+  LExponent: Integer;
+begin
+  Frexp(AValue, LMantissa, LExponent);
+
+  if LMantissa = 0 then
+    LMantissa := Abs(LMantissa);
+
+  EXTENDED_HASH_FACTORY.GetHashList(@LMantissa, SizeOf(Math.Float), AHashList, []);
+  EXTENDED_HASH_FACTORY.GetHashList(@LExponent, SizeOf(System.Integer), AHashList, [ghloHashListAsInitData]);
+end;
+
+class procedure TExtendedHashFactory.Extended(constref AValue: Extended; AHashList: PUInt32);
+var
+  LMantissa: Float;
+  LExponent: Integer;
+begin
+  Frexp(AValue, LMantissa, LExponent);
+
+  if LMantissa = 0 then
+    LMantissa := Abs(LMantissa);
+
+  EXTENDED_HASH_FACTORY.GetHashList(@LMantissa, SizeOf(Math.Float), AHashList, []);
+  EXTENDED_HASH_FACTORY.GetHashList(@LExponent, SizeOf(System.Integer), AHashList, [ghloHashListAsInitData]);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for other number types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.Currency(constref AValue: Currency; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int64), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.Comp(constref AValue: Comp; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int64), AHashList, []);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for binary data (records etc) and dynamics arrays
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.Binary(constref AValue; AHashList: PUInt32);
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, _self.Size, AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.DynArray(constref AValue: Pointer; AHashList: PUInt32);
+var
+  _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self;
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(AValue, DynArraySize(AValue) * _self.Size, AHashList, []);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for classes
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.&Class(constref AValue: TObject; AHashList: PUInt32);
+var
+  LValue: PtrInt;
+begin
+  if AValue = nil then
+  begin
+    LValue := $2A;
+    EXTENDED_HASH_FACTORY.GetHashList(@LValue, SizeOf(LValue), AHashList, []);
+    Exit;
+  end;
+
+  LValue := AValue.GetHashCode;
+  EXTENDED_HASH_FACTORY.GetHashList(@LValue, SizeOf(LValue), AHashList, []);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for string types
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.ShortString1(constref AValue: ShortString1; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.ShortString2(constref AValue: ShortString2; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.ShortString3(constref AValue: ShortString3; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.ShortString(constref AValue: ShortString; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.AnsiString(constref AValue: AnsiString; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue) * SizeOf(System.AnsiChar), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.WideString(constref AValue: WideString; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue) * SizeOf(System.WideChar), AHashList, []);
+end;
+
+class procedure TExtendedHashFactory.UnicodeString(constref AValue: UnicodeString; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue) * SizeOf(System.UnicodeChar), AHashList, []);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Delegates
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.Method(constref AValue: TMethod; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.TMethod), AHashList, []);
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Variant
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.Variant(constref AValue: PVariant; AHashList: PUInt32);
+begin
+  try
+    EXTENDED_HASH_FACTORY.UnicodeString(AValue^, AHashList);
+  except
+    EXTENDED_HASH_FACTORY.GetHashList(AValue, SizeOf(System.Variant), AHashList, []);
+  end;
+end;
+
+{-----------------------------------------------------------------------------------------------------------------------
+  GetHashCode for Pointer
+{----------------------------------------------------------------------------------------------------------------------}
+
+class procedure TExtendedHashFactory.Pointer(constref AValue: Pointer; AHashList: PUInt32);
+begin
+  EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Pointer), AHashList, []);
+end;
+
+{ TComparerService }
+
+class function TComparerService.CreateInterface(AVMT: Pointer; ASize: SizeInt): PSpoofInterfacedTypeSizeObject;
+begin
+    Result := New(PSpoofInterfacedTypeSizeObject);
+    Result.VMT      := AVMT;
+    Result.RefCount := 0;
+    Result.Size     := ASize;
+end;
+
+class function TComparerService.SelectIntegerComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  case ATypeData.OrdType of
+    otSByte:
+      Exit(@Comparer_Int8_Instance);
+    otUByte:
+      Exit(@Comparer_UInt8_Instance);
+    otSWord:
+      Exit(@Comparer_Int16_Instance);
+    otUWord:
+      Exit(@Comparer_UInt16_Instance);
+    otSLong:
+      Exit(@Comparer_Int32_Instance);
+    otULong:
+      Exit(@Comparer_UInt32_Instance);
+  else
+    System.Error(reRangeError);
+    Exit(nil);
+  end;
+end;
+
+class function TComparerService.SelectInt64Comparer(ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  if ATypeData.MaxInt64Value > ATypeData.MinInt64Value then
+    Exit(@Comparer_Int64_Instance)
+  else
+    Exit(@Comparer_UInt64_Instance);
+end;
+
+class function TComparerService.SelectFloatComparer(ATypeData: PTypeData;
+  ASize: SizeInt): Pointer;
+begin
+  case ATypeData.FloatType of
+    ftSingle:
+      Exit(@Comparer_Single_Instance);
+    ftDouble:
+      Exit(@Comparer_Double_Instance);
+    ftExtended:
+      Exit(@Comparer_Extended_Instance);
+    ftComp:
+      Exit(@Comparer_Comp_Instance);
+    ftCurr:
+      Exit(@Comparer_Currency_Instance);
+  else
+    System.Error(reRangeError);
+    Exit(nil);
+  end;
+end;
+
+class function TComparerService.SelectShortStringComparer(ATypeData: PTypeData;
+  ASize: SizeInt): Pointer;
+begin
+  case ASize of
+    2: Exit(@Comparer_ShortString1_Instance);
+    3: Exit(@Comparer_ShortString2_Instance);
+    4: Exit(@Comparer_ShortString3_Instance);
+  else
+    Exit(@Comparer_ShortString_Instance);
+  end;
+end;
+
+class function TComparerService.SelectBinaryComparer(ATypeData: PTypeData;
+  ASize: SizeInt): Pointer;
+begin
+  case ASize of
+    1: Exit(@Comparer_UInt8_Instance);
+    2: Exit(@Comparer_UInt16_Instance);
+    4: Exit(@Comparer_UInt32_Instance);
+{$IFDEF CPU64}
+    8: Exit(@Comparer_UInt64_Instance)
+{$ENDIF}
+  else
+    Result := CreateInterface(@Comparer_Binary_VMT, ASize);
+  end;
+end;
+
+class function TComparerService.SelectDynArrayComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  Result := CreateInterface(@Comparer_DynArray_VMT, ATypeData.elSize);
+end;
+
+class function TComparerService.LookupComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer;
+var
+  LInstance: PInstance;
+begin
+  if ATypeInfo = nil then
+    Exit(SelectBinaryComparer(GetTypeData(ATypeInfo), ASize))
+  else
+  begin
+    LInstance := @ComparerInstances[ATypeInfo.Kind];
+    Result := LInstance.Instance;
+    if LInstance.Selector then
+      Result := TSelectFunc(Result)(GetTypeData(ATypeInfo), ASize);
+  end;
+end;
+
+{ TComparerService.TInstance }
+
+class function TComparerService.TInstance.Create(ASelector: Boolean;
+  AInstance: Pointer): TComparerService.TInstance;
+begin
+  Result.Selector := ASelector;
+  Result.Instance := AInstance;
+end;
+
+{ THashService }
+
+class function THashService<T>.SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  case ATypeData.OrdType of
+    otSByte:
+      Exit(@FEqualityComparer_Int8_Instance);
+    otUByte:
+      Exit(@FEqualityComparer_UInt8_Instance);
+    otSWord:
+      Exit(@FEqualityComparer_Int16_Instance);
+    otUWord:
+      Exit(@FEqualityComparer_UInt16_Instance);
+    otSLong:
+      Exit(@FEqualityComparer_Int32_Instance);
+    otULong:
+      Exit(@FEqualityComparer_UInt32_Instance);
+  else
+    System.Error(reRangeError);
+    Exit(nil);
+  end;
+end;
+
+class function THashService<T>.SelectFloatEqualityComparer(ATypeData: PTypeData;
+  ASize: SizeInt): Pointer;
+begin
+  case ATypeData.FloatType of
+    ftSingle:
+      Exit(@FEqualityComparer_Single_Instance);
+    ftDouble:
+      Exit(@FEqualityComparer_Double_Instance);
+    ftExtended:
+      Exit(@FEqualityComparer_Extended_Instance);
+    ftComp:
+      Exit(@FEqualityComparer_Comp_Instance);
+    ftCurr:
+      Exit(@FEqualityComparer_Currency_Instance);
+  else
+    System.Error(reRangeError);
+    Exit(nil);
+  end;
+end;
+
+class function THashService<T>.SelectShortStringEqualityComparer(
+  ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  case ASize of
+    2: Exit(@FEqualityComparer_ShortString1_Instance);
+    3: Exit(@FEqualityComparer_ShortString2_Instance);
+    4: Exit(@FEqualityComparer_ShortString3_Instance);
+  else
+    Exit(@FEqualityComparer_ShortString_Instance);
+  end
+end;
+
+class function THashService<T>.SelectBinaryEqualityComparer(ATypeData: PTypeData;
+  ASize: SizeInt): Pointer;
+begin
+  case ASize of
+    1: Exit(@FEqualityComparer_UInt8_Instance);
+    2: Exit(@FEqualityComparer_UInt16_Instance);
+    4: Exit(@FEqualityComparer_UInt32_Instance);
+{$IFDEF CPU64}
+    8: Exit(@FEqualityComparer_UInt64_Instance)
+{$ENDIF}
+  else
+    Result := CreateInterface(@FEqualityComparer_Binary_VMT, ASize);
+  end;
+end;
+
+class function THashService<T>.SelectDynArrayEqualityComparer(
+  ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  Result := CreateInterface(@FEqualityComparer_DynArray_VMT, ATypeData.elSize);
+end;
+
+class function THashService<T>.LookupEqualityComparer(ATypeInfo: PTypeInfo;
+  ASize: SizeInt): Pointer;
+var
+  LInstance: PInstance;
+  LSelectMethod: TSelectMethod;
+begin
+  if ATypeInfo = nil then
+    Exit(SelectBinaryEqualityComparer(GetTypeData(ATypeInfo), ASize))
+  else
+  begin
+    LInstance := @FEqualityComparerInstances[ATypeInfo.Kind];
+    Result := LInstance.Instance;
+    if LInstance.Selector then
+    begin
+      TMethod(LSelectMethod).Code := Result;
+      TMethod(LSelectMethod).Data := Self;
+      Result := LSelectMethod(GetTypeData(ATypeInfo), ASize);
+    end;
+  end;
+end;
+
+class constructor THashService<T>.Create;
+begin
+  FEqualityComparer_Int8_VMT          := EqualityComparer_Int8_VMT         ;
+  FEqualityComparer_Int16_VMT         := EqualityComparer_Int16_VMT        ;
+  FEqualityComparer_Int32_VMT         := EqualityComparer_Int32_VMT        ;
+  FEqualityComparer_Int64_VMT         := EqualityComparer_Int64_VMT        ;
+  FEqualityComparer_UInt8_VMT         := EqualityComparer_UInt8_VMT        ;
+  FEqualityComparer_UInt16_VMT        := EqualityComparer_UInt16_VMT       ;
+  FEqualityComparer_UInt32_VMT        := EqualityComparer_UInt32_VMT       ;
+  FEqualityComparer_UInt64_VMT        := EqualityComparer_UInt64_VMT       ;
+  FEqualityComparer_Single_VMT        := EqualityComparer_Single_VMT       ;
+  FEqualityComparer_Double_VMT        := EqualityComparer_Double_VMT       ;
+  FEqualityComparer_Extended_VMT      := EqualityComparer_Extended_VMT     ;
+  FEqualityComparer_Currency_VMT      := EqualityComparer_Currency_VMT     ;
+  FEqualityComparer_Comp_VMT          := EqualityComparer_Comp_VMT         ;
+  FEqualityComparer_Binary_VMT        := EqualityComparer_Binary_VMT       ;
+  FEqualityComparer_DynArray_VMT      := EqualityComparer_DynArray_VMT     ;
+  FEqualityComparer_Class_VMT         := EqualityComparer_Class_VMT        ;
+  FEqualityComparer_ShortString1_VMT  := EqualityComparer_ShortString1_VMT ;
+  FEqualityComparer_ShortString2_VMT  := EqualityComparer_ShortString2_VMT ;
+  FEqualityComparer_ShortString3_VMT  := EqualityComparer_ShortString3_VMT ;
+  FEqualityComparer_ShortString_VMT   := EqualityComparer_ShortString_VMT  ;
+  FEqualityComparer_AnsiString_VMT    := EqualityComparer_AnsiString_VMT   ;
+  FEqualityComparer_WideString_VMT    := EqualityComparer_WideString_VMT   ;
+  FEqualityComparer_UnicodeString_VMT := EqualityComparer_UnicodeString_VMT;
+  FEqualityComparer_Method_VMT        := EqualityComparer_Method_VMT       ;
+  FEqualityComparer_Variant_VMT       := EqualityComparer_Variant_VMT      ;
+  FEqualityComparer_Pointer_VMT       := EqualityComparer_Pointer_VMT      ;
+
+  /////
+  FEqualityComparer_Int8_VMT.__ClassRef          := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Int16_VMT.__ClassRef         := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Int32_VMT.__ClassRef         := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Int64_VMT.__ClassRef         := THashFactoryClass(T.ClassType);
+  FEqualityComparer_UInt8_VMT.__ClassRef         := THashFactoryClass(T.ClassType);
+  FEqualityComparer_UInt16_VMT.__ClassRef        := THashFactoryClass(T.ClassType);
+  FEqualityComparer_UInt32_VMT.__ClassRef        := THashFactoryClass(T.ClassType);
+  FEqualityComparer_UInt64_VMT.__ClassRef        := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Single_VMT.__ClassRef        := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Double_VMT.__ClassRef        := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Extended_VMT.__ClassRef      := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Currency_VMT.__ClassRef      := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Comp_VMT.__ClassRef          := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Binary_VMT.__ClassRef        := THashFactoryClass(T.ClassType);
+  FEqualityComparer_DynArray_VMT.__ClassRef      := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Class_VMT.__ClassRef         := THashFactoryClass(T.ClassType);
+  FEqualityComparer_ShortString1_VMT.__ClassRef  := THashFactoryClass(T.ClassType);
+  FEqualityComparer_ShortString2_VMT.__ClassRef  := THashFactoryClass(T.ClassType);
+  FEqualityComparer_ShortString3_VMT.__ClassRef  := THashFactoryClass(T.ClassType);
+  FEqualityComparer_ShortString_VMT.__ClassRef   := THashFactoryClass(T.ClassType);
+  FEqualityComparer_AnsiString_VMT.__ClassRef    := THashFactoryClass(T.ClassType);
+  FEqualityComparer_WideString_VMT.__ClassRef    := THashFactoryClass(T.ClassType);
+  FEqualityComparer_UnicodeString_VMT.__ClassRef := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Method_VMT.__ClassRef        := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Variant_VMT.__ClassRef       := THashFactoryClass(T.ClassType);
+  FEqualityComparer_Pointer_VMT.__ClassRef       := THashFactoryClass(T.ClassType);
+
+  ///////
+  FEqualityComparer_Int8_Instance          := @FEqualityComparer_Int8_VMT         ;
+  FEqualityComparer_Int16_Instance         := @FEqualityComparer_Int16_VMT        ;
+  FEqualityComparer_Int32_Instance         := @FEqualityComparer_Int32_VMT        ;
+  FEqualityComparer_Int64_Instance         := @FEqualityComparer_Int64_VMT        ;
+  FEqualityComparer_UInt8_Instance         := @FEqualityComparer_UInt8_VMT        ;
+  FEqualityComparer_UInt16_Instance        := @FEqualityComparer_UInt16_VMT       ;
+  FEqualityComparer_UInt32_Instance        := @FEqualityComparer_UInt32_VMT       ;
+  FEqualityComparer_UInt64_Instance        := @FEqualityComparer_UInt64_VMT       ;
+  FEqualityComparer_Single_Instance        := @FEqualityComparer_Single_VMT       ;
+  FEqualityComparer_Double_Instance        := @FEqualityComparer_Double_VMT       ;
+  FEqualityComparer_Extended_Instance      := @FEqualityComparer_Extended_VMT     ;
+  FEqualityComparer_Currency_Instance      := @FEqualityComparer_Currency_VMT     ;
+  FEqualityComparer_Comp_Instance          := @FEqualityComparer_Comp_VMT         ;
+  //FEqualityComparer_Binary_Instance        := @FEqualityComparer_Binary_VMT       ;  // dynamic instance
+  //FEqualityComparer_DynArray_Instance      := @FEqualityComparer_DynArray_VMT     ;  // dynamic instance
+  FEqualityComparer_ShortString1_Instance  := @FEqualityComparer_ShortString1_VMT ;
+  FEqualityComparer_ShortString2_Instance  := @FEqualityComparer_ShortString2_VMT ;
+  FEqualityComparer_ShortString3_Instance  := @FEqualityComparer_ShortString3_VMT ;
+  FEqualityComparer_ShortString_Instance   := @FEqualityComparer_ShortString_VMT  ;
+  FEqualityComparer_AnsiString_Instance    := @FEqualityComparer_AnsiString_VMT   ;
+  FEqualityComparer_WideString_Instance    := @FEqualityComparer_WideString_VMT   ;
+  FEqualityComparer_UnicodeString_Instance := @FEqualityComparer_UnicodeString_VMT;
+  FEqualityComparer_Method_Instance        := @FEqualityComparer_Method_VMT       ;
+  FEqualityComparer_Variant_Instance       := @FEqualityComparer_Variant_VMT      ;
+  FEqualityComparer_Pointer_Instance       := @FEqualityComparer_Pointer_VMT      ;
+
+  //////
+  FEqualityComparerInstances[tkUnknown]      := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code);
+  FEqualityComparerInstances[tkInteger]      := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectIntegerEqualityComparer)).Code);
+  FEqualityComparerInstances[tkChar]         := TInstance.Create(False, @FEqualityComparer_UInt8_Instance);
+  FEqualityComparerInstances[tkEnumeration]  := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectIntegerEqualityComparer)).Code);
+  FEqualityComparerInstances[tkFloat]        := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectFloatEqualityComparer)).Code);
+  FEqualityComparerInstances[tkSet]          := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code);
+  FEqualityComparerInstances[tkMethod]       := TInstance.Create(False, @FEqualityComparer_Method_Instance);
+  FEqualityComparerInstances[tkSString]      := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectShortStringEqualityComparer)).Code);
+  FEqualityComparerInstances[tkLString]      := TInstance.Create(False, @FEqualityComparer_AnsiString_Instance);
+  FEqualityComparerInstances[tkAString]      := TInstance.Create(False, @FEqualityComparer_AnsiString_Instance);
+  FEqualityComparerInstances[tkWString]      := TInstance.Create(False, @FEqualityComparer_WideString_Instance);
+  FEqualityComparerInstances[tkVariant]      := TInstance.Create(False, @FEqualityComparer_Variant_Instance);
+  FEqualityComparerInstances[tkArray]        := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code);
+  FEqualityComparerInstances[tkRecord]       := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code);
+  FEqualityComparerInstances[tkInterface]    := TInstance.Create(False, @FEqualityComparer_Pointer_Instance);
+  FEqualityComparerInstances[tkClass]        := TInstance.Create(False, @FEqualityComparer_Pointer_Instance);
+  FEqualityComparerInstances[tkObject]       := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code);
+  FEqualityComparerInstances[tkWChar]        := TInstance.Create(False, @FEqualityComparer_UInt16_Instance);
+  FEqualityComparerInstances[tkBool]         := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectIntegerEqualityComparer)).Code);
+  FEqualityComparerInstances[tkInt64]        := TInstance.Create(False, @FEqualityComparer_Int64_Instance);
+  FEqualityComparerInstances[tkQWord]        := TInstance.Create(False, @FEqualityComparer_UInt64_Instance);
+  FEqualityComparerInstances[tkDynArray]     := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectDynArrayEqualityComparer)).Code);
+  FEqualityComparerInstances[tkInterfaceRaw] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance);
+  FEqualityComparerInstances[tkProcVar]      := TInstance.Create(False, @FEqualityComparer_Pointer_Instance);
+  FEqualityComparerInstances[tkUString]      := TInstance.Create(False, @FEqualityComparer_UnicodeString_Instance);
+  FEqualityComparerInstances[tkUChar]        := TInstance.Create(False, @FEqualityComparer_UInt16_Instance);
+  FEqualityComparerInstances[tkHelper]       := TInstance.Create(False, @FEqualityComparer_Pointer_Instance);
+  FEqualityComparerInstances[tkFile]         := TInstance.Create(True, TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code);
+  FEqualityComparerInstances[tkClassRef]     := TInstance.Create(False, @FEqualityComparer_Pointer_Instance);
+  FEqualityComparerInstances[tkPointer]      := TInstance.Create(False, @FEqualityComparer_Pointer_Instance)
+end;
+
+{ TExtendedHashService }
+
+class function TExtendedHashService<T>.SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  case ATypeData.OrdType of
+    otSByte:
+      Exit(@FExtendedEqualityComparer_Int8_Instance);
+    otUByte:
+      Exit(@FExtendedEqualityComparer_UInt8_Instance);
+    otSWord:
+      Exit(@FExtendedEqualityComparer_Int16_Instance);
+    otUWord:
+      Exit(@FExtendedEqualityComparer_UInt16_Instance);
+    otSLong:
+      Exit(@FExtendedEqualityComparer_Int32_Instance);
+    otULong:
+      Exit(@FExtendedEqualityComparer_UInt32_Instance);
+  else
+    System.Error(reRangeError);
+    Exit(nil);
+  end;
+end;
+
+class function TExtendedHashService<T>.SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  case ATypeData.FloatType of
+    ftSingle:
+      Exit(@FExtendedEqualityComparer_Single_Instance);
+    ftDouble:
+      Exit(@FExtendedEqualityComparer_Double_Instance);
+    ftExtended:
+      Exit(@FExtendedEqualityComparer_Extended_Instance);
+    ftComp:
+      Exit(@FExtendedEqualityComparer_Comp_Instance);
+    ftCurr:
+      Exit(@FExtendedEqualityComparer_Currency_Instance);
+  else
+    System.Error(reRangeError);
+    Exit(nil);
+  end;
+end;
+
+class function TExtendedHashService<T>.SelectShortStringEqualityComparer(ATypeData: PTypeData;
+  ASize: SizeInt): Pointer;
+begin
+  case ASize of
+    2: Exit(@FExtendedEqualityComparer_ShortString1_Instance);
+    3: Exit(@FExtendedEqualityComparer_ShortString2_Instance);
+    4: Exit(@FExtendedEqualityComparer_ShortString3_Instance);
+  else
+    Exit(@FExtendedEqualityComparer_ShortString_Instance);
+  end
+end;
+
+class function TExtendedHashService<T>.SelectBinaryEqualityComparer(ATypeData: PTypeData;
+  ASize: SizeInt): Pointer;
+begin
+  case ASize of
+    1: Exit(@FExtendedEqualityComparer_UInt8_Instance);
+    2: Exit(@FExtendedEqualityComparer_UInt16_Instance);
+    4: Exit(@FExtendedEqualityComparer_UInt32_Instance);
+{$IFDEF CPU64}
+    8: Exit(@FExtendedEqualityComparer_UInt64_Instance)
+{$ENDIF}
+  else
+    Result := CreateInterface(@FExtendedEqualityComparer_Binary_VMT, ASize);
+  end;
+end;
+
+class function TExtendedHashService<T>.SelectDynArrayEqualityComparer(
+  ATypeData: PTypeData; ASize: SizeInt): Pointer;
+begin
+  Result := CreateInterface(@FExtendedEqualityComparer_DynArray_VMT, ATypeData.elSize);
+end;
+
+class function TExtendedHashService<T>.LookupExtendedEqualityComparer(
+  ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer;
+var
+  LInstance: PInstance;
+  LSelectMethod: TSelectMethod;
+begin
+  if ATypeInfo = nil then
+    Exit(SelectBinaryEqualityComparer(GetTypeData(ATypeInfo), ASize))
+  else
+  begin
+    LInstance := @FExtendedEqualityComparerInstances[ATypeInfo.Kind];
+    Result := LInstance.Instance;
+    if LInstance.Selector then
+    begin
+      TMethod(LSelectMethod).Code := Result;
+      TMethod(LSelectMethod).Data := Self;
+      Result := LSelectMethod(GetTypeData(ATypeInfo), ASize);
+    end;
+  end;
+end;
+
+class constructor TExtendedHashService<T>.Create;
+begin
+  FExtendedEqualityComparer_Int8_VMT          := ExtendedEqualityComparer_Int8_VMT         ;
+  FExtendedEqualityComparer_Int16_VMT         := ExtendedEqualityComparer_Int16_VMT        ;
+  FExtendedEqualityComparer_Int32_VMT         := ExtendedEqualityComparer_Int32_VMT        ;
+  FExtendedEqualityComparer_Int64_VMT         := ExtendedEqualityComparer_Int64_VMT        ;
+  FExtendedEqualityComparer_UInt8_VMT         := ExtendedEqualityComparer_UInt8_VMT        ;
+  FExtendedEqualityComparer_UInt16_VMT        := ExtendedEqualityComparer_UInt16_VMT       ;
+  FExtendedEqualityComparer_UInt32_VMT        := ExtendedEqualityComparer_UInt32_VMT       ;
+  FExtendedEqualityComparer_UInt64_VMT        := ExtendedEqualityComparer_UInt64_VMT       ;
+  FExtendedEqualityComparer_Single_VMT        := ExtendedEqualityComparer_Single_VMT       ;
+  FExtendedEqualityComparer_Double_VMT        := ExtendedEqualityComparer_Double_VMT       ;
+  FExtendedEqualityComparer_Extended_VMT      := ExtendedEqualityComparer_Extended_VMT     ;
+  FExtendedEqualityComparer_Currency_VMT      := ExtendedEqualityComparer_Currency_VMT     ;
+  FExtendedEqualityComparer_Comp_VMT          := ExtendedEqualityComparer_Comp_VMT         ;
+  FExtendedEqualityComparer_Binary_VMT        := ExtendedEqualityComparer_Binary_VMT       ;
+  FExtendedEqualityComparer_DynArray_VMT      := ExtendedEqualityComparer_DynArray_VMT     ;
+  FExtendedEqualityComparer_Class_VMT         := ExtendedEqualityComparer_Class_VMT        ;
+  FExtendedEqualityComparer_ShortString1_VMT  := ExtendedEqualityComparer_ShortString1_VMT ;
+  FExtendedEqualityComparer_ShortString2_VMT  := ExtendedEqualityComparer_ShortString2_VMT ;
+  FExtendedEqualityComparer_ShortString3_VMT  := ExtendedEqualityComparer_ShortString3_VMT ;
+  FExtendedEqualityComparer_ShortString_VMT   := ExtendedEqualityComparer_ShortString_VMT  ;
+  FExtendedEqualityComparer_AnsiString_VMT    := ExtendedEqualityComparer_AnsiString_VMT   ;
+  FExtendedEqualityComparer_WideString_VMT    := ExtendedEqualityComparer_WideString_VMT   ;
+  FExtendedEqualityComparer_UnicodeString_VMT := ExtendedEqualityComparer_UnicodeString_VMT;
+  FExtendedEqualityComparer_Method_VMT        := ExtendedEqualityComparer_Method_VMT       ;
+  FExtendedEqualityComparer_Variant_VMT       := ExtendedEqualityComparer_Variant_VMT      ;
+  FExtendedEqualityComparer_Pointer_VMT       := ExtendedEqualityComparer_Pointer_VMT      ;
+
+  /////
+  FExtendedEqualityComparer_Int8_VMT.__ClassRef          := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Int16_VMT.__ClassRef         := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Int32_VMT.__ClassRef         := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Int64_VMT.__ClassRef         := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_UInt8_VMT.__ClassRef         := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_UInt16_VMT.__ClassRef        := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_UInt32_VMT.__ClassRef        := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_UInt64_VMT.__ClassRef        := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Single_VMT.__ClassRef        := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Double_VMT.__ClassRef        := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Extended_VMT.__ClassRef      := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Currency_VMT.__ClassRef      := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Comp_VMT.__ClassRef          := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Binary_VMT.__ClassRef        := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_DynArray_VMT.__ClassRef      := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Class_VMT.__ClassRef         := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_ShortString1_VMT.__ClassRef  := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_ShortString2_VMT.__ClassRef  := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_ShortString3_VMT.__ClassRef  := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_ShortString_VMT.__ClassRef   := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_AnsiString_VMT.__ClassRef    := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_WideString_VMT.__ClassRef    := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_UnicodeString_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Method_VMT.__ClassRef        := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Variant_VMT.__ClassRef       := TExtendedHashFactoryClass(T.ClassType);
+  FExtendedEqualityComparer_Pointer_VMT.__ClassRef       := TExtendedHashFactoryClass(T.ClassType);
+
+  ///////
+  FExtendedEqualityComparer_Int8_Instance          := @FExtendedEqualityComparer_Int8_VMT         ;
+  FExtendedEqualityComparer_Int16_Instance         := @FExtendedEqualityComparer_Int16_VMT        ;
+  FExtendedEqualityComparer_Int32_Instance         := @FExtendedEqualityComparer_Int32_VMT        ;
+  FExtendedEqualityComparer_Int64_Instance         := @FExtendedEqualityComparer_Int64_VMT        ;
+  FExtendedEqualityComparer_UInt8_Instance         := @FExtendedEqualityComparer_UInt8_VMT        ;
+  FExtendedEqualityComparer_UInt16_Instance        := @FExtendedEqualityComparer_UInt16_VMT       ;
+  FExtendedEqualityComparer_UInt32_Instance        := @FExtendedEqualityComparer_UInt32_VMT       ;
+  FExtendedEqualityComparer_UInt64_Instance        := @FExtendedEqualityComparer_UInt64_VMT       ;
+  FExtendedEqualityComparer_Single_Instance        := @FExtendedEqualityComparer_Single_VMT       ;
+  FExtendedEqualityComparer_Double_Instance        := @FExtendedEqualityComparer_Double_VMT       ;
+  FExtendedEqualityComparer_Extended_Instance      := @FExtendedEqualityComparer_Extended_VMT     ;
+  FExtendedEqualityComparer_Currency_Instance      := @FExtendedEqualityComparer_Currency_VMT     ;
+  FExtendedEqualityComparer_Comp_Instance          := @FExtendedEqualityComparer_Comp_VMT         ;
+  //FExtendedEqualityComparer_Binary_Instance        := @FExtendedEqualityComparer_Binary_VMT       ;  // dynamic instance
+  //FExtendedEqualityComparer_DynArray_Instance      := @FExtendedEqualityComparer_DynArray_VMT     ;  // dynamic instance
+  FExtendedEqualityComparer_ShortString1_Instance  := @FExtendedEqualityComparer_ShortString1_VMT ;
+  FExtendedEqualityComparer_ShortString2_Instance  := @FExtendedEqualityComparer_ShortString2_VMT ;
+  FExtendedEqualityComparer_ShortString3_Instance  := @FExtendedEqualityComparer_ShortString3_VMT ;
+  FExtendedEqualityComparer_ShortString_Instance   := @FExtendedEqualityComparer_ShortString_VMT  ;
+  FExtendedEqualityComparer_AnsiString_Instance    := @FExtendedEqualityComparer_AnsiString_VMT   ;
+  FExtendedEqualityComparer_WideString_Instance    := @FExtendedEqualityComparer_WideString_VMT   ;
+  FExtendedEqualityComparer_UnicodeString_Instance := @FExtendedEqualityComparer_UnicodeString_VMT;
+  FExtendedEqualityComparer_Method_Instance        := @FExtendedEqualityComparer_Method_VMT       ;
+  FExtendedEqualityComparer_Variant_Instance       := @FExtendedEqualityComparer_Variant_VMT      ;
+  FExtendedEqualityComparer_Pointer_Instance       := @FExtendedEqualityComparer_Pointer_VMT      ;
+
+  //////
+  FExtendedEqualityComparerInstances[tkUnknown]      := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkInteger]      := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectIntegerEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkChar]         := TInstance.Create(False, @FExtendedEqualityComparer_UInt8_Instance);
+  FExtendedEqualityComparerInstances[tkEnumeration]  := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectIntegerEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkFloat]        := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectFloatEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkSet]          := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkMethod]       := TInstance.Create(False, @FExtendedEqualityComparer_Method_Instance);
+  FExtendedEqualityComparerInstances[tkSString]      := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectShortStringEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkLString]      := TInstance.Create(False, @FExtendedEqualityComparer_AnsiString_Instance);
+  FExtendedEqualityComparerInstances[tkAString]      := TInstance.Create(False, @FExtendedEqualityComparer_AnsiString_Instance);
+  FExtendedEqualityComparerInstances[tkWString]      := TInstance.Create(False, @FExtendedEqualityComparer_WideString_Instance);
+  FExtendedEqualityComparerInstances[tkVariant]      := TInstance.Create(False, @FExtendedEqualityComparer_Variant_Instance);
+  FExtendedEqualityComparerInstances[tkArray]        := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkRecord]       := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkInterface]    := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance);
+  FExtendedEqualityComparerInstances[tkClass]        := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance);
+  FExtendedEqualityComparerInstances[tkObject]       := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkWChar]        := TInstance.Create(False, @FExtendedEqualityComparer_UInt16_Instance);
+  FExtendedEqualityComparerInstances[tkBool]         := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectIntegerEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkInt64]        := TInstance.Create(False, @FExtendedEqualityComparer_Int64_Instance);
+  FExtendedEqualityComparerInstances[tkQWord]        := TInstance.Create(False, @FExtendedEqualityComparer_UInt64_Instance);
+  FExtendedEqualityComparerInstances[tkDynArray]     := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectDynArrayEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkInterfaceRaw] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance);
+  FExtendedEqualityComparerInstances[tkProcVar]      := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance);
+  FExtendedEqualityComparerInstances[tkUString]      := TInstance.Create(False, @FExtendedEqualityComparer_UnicodeString_Instance);
+  FExtendedEqualityComparerInstances[tkUChar]        := TInstance.Create(False, @FExtendedEqualityComparer_UInt16_Instance);
+  FExtendedEqualityComparerInstances[tkHelper]       := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance);
+  FExtendedEqualityComparerInstances[tkFile]         := TInstance.Create(True, TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code);
+  FExtendedEqualityComparerInstances[tkClassRef]     := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance);
+  FExtendedEqualityComparerInstances[tkPointer]      := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance);
+end;
+
+{ TEqualityComparer<T> }
+
+class function TEqualityComparer<T>.Default: IEqualityComparer<T>;
+begin
+  Result := _LookupVtableInfo(giEqualityComparer, TypeInfo(T), SizeOf(T));
+end;
+
+class function TEqualityComparer<T>.Default(AHashFactoryClass: THashFactoryClass): IEqualityComparer<T>;
+begin
+  if AHashFactoryClass.InheritsFrom(TExtendedHashFactory) then
+    Result := _LookupVtableInfoEx(giExtendedEqualityComparer, TypeInfo(T), SizeOf(T), AHashFactoryClass)
+  else if AHashFactoryClass.InheritsFrom(THashFactory) then
+    Result := _LookupVtableInfoEx(giEqualityComparer, TypeInfo(T), SizeOf(T), AHashFactoryClass);
+end;
+
+class function  TEqualityComparer<T>.Construct(const AEqualityComparison: TOnEqualityComparison<T>;
+  const AHasher: TOnHasher<T>): IEqualityComparer<T>;
+begin
+  Result := TDelegatedEqualityComparerEvents<T>.Create(AEqualityComparison, AHasher);
+end;
+
+class function  TEqualityComparer<T>.Construct(const AEqualityComparison: TEqualityComparisonFunc<T>;
+  const AHasher: THasherFunc<T>): IEqualityComparer<T>;
+begin
+  Result := TDelegatedEqualityComparerFunc<T>.Create(AEqualityComparison, AHasher);
+end;
+
+{ TDelegatedEqualityComparerEvents<T> }
+
+function TDelegatedEqualityComparerEvents<T>.Equals(constref ALeft, ARight: T): Boolean;
+begin
+  Result := FEqualityComparison(ALeft, ARight);
+end;
+
+function TDelegatedEqualityComparerEvents<T>.GetHashCode(constref AValue: T): UInt32;
+begin
+  Result := FHasher(AValue);
+end;
+
+constructor TDelegatedEqualityComparerEvents<T>.Create(const AEqualityComparison: TOnEqualityComparison<T>;
+  const AHasher: TOnHasher<T>);
+begin
+  FEqualityComparison := AEqualityComparison;
+  FHasher := AHasher;
+end;
+
+{ TDelegatedEqualityComparerFunc<T> }
+
+function TDelegatedEqualityComparerFunc<T>.Equals(constref ALeft, ARight: T): Boolean;
+begin
+  Result := FEqualityComparison(ALeft, ARight);
+end;
+
+function TDelegatedEqualityComparerFunc<T>.GetHashCode(constref AValue: T): UInt32;
+begin
+  Result := FHasher(AValue);
+end;
+
+constructor TDelegatedEqualityComparerFunc<T>.Create(const AEqualityComparison: TEqualityComparisonFunc<T>;
+  const AHasher: THasherFunc<T>);
+begin
+  FEqualityComparison := AEqualityComparison;
+  FHasher := AHasher;
+end;
+
+{ TDelegatedExtendedEqualityComparerEvents<T> }
+
+function TDelegatedExtendedEqualityComparerEvents<T>.GetHashCodeMethod(constref AValue: T): UInt32;
+var
+  LHashList: array[0..1] of Int32;
+  LHashListParams: array[0..3] of Int16 absolute LHashList;
+begin
+  LHashListParams[0] := -1;
+  FExtendedHasher(AValue, @LHashList[0]);
+  Result := LHashList[1];
+end;
+
+function TDelegatedExtendedEqualityComparerEvents<T>.Equals(constref ALeft, ARight: T): Boolean;
+begin
+  Result := FEqualityComparison(ALeft, ARight);
+end;
+
+function TDelegatedExtendedEqualityComparerEvents<T>.GetHashCode(constref AValue: T): UInt32;
+begin
+  Result := FHasher(AValue);
+end;
+
+procedure TDelegatedExtendedEqualityComparerEvents<T>.GetHashList(constref AValue: T; AHashList: PUInt32);
+begin
+  FExtendedHasher(AValue, AHashList);
+end;
+
+constructor TDelegatedExtendedEqualityComparerEvents<T>.Create(const AEqualityComparison: TOnEqualityComparison<T>;
+  const AHasher: TOnHasher<T>; const AExtendedHasher: TOnExtendedHasher<T>);
+begin
+  FEqualityComparison := AEqualityComparison;
+  FHasher := AHasher;
+  FExtendedHasher := AExtendedHasher;
+end;
+
+constructor TDelegatedExtendedEqualityComparerEvents<T>.Create(const AEqualityComparison: TOnEqualityComparison<T>;
+  const AExtendedHasher: TOnExtendedHasher<T>);
+begin
+  Create(AEqualityComparison, GetHashCodeMethod, AExtendedHasher);
+end;
+
+{ TDelegatedExtendedEqualityComparerFunc<T> }
+
+function TDelegatedExtendedEqualityComparerFunc<T>.Equals(constref ALeft, ARight: T): Boolean;
+begin
+  Result := FEqualityComparison(ALeft, ARight);
+end;
+
+function TDelegatedExtendedEqualityComparerFunc<T>.GetHashCode(constref AValue: T): UInt32;
+var
+  LHashList: array[0..1] of Int32;
+  LHashListParams: array[0..3] of Int16 absolute LHashList;
+begin
+  if not Assigned(FHasher) then
+  begin
+    LHashListParams[0] := -1;
+    FExtendedHasher(AValue, @LHashList[0]);
+    Result := LHashList[1];
+  end
+  else
+    Result := FHasher(AValue);
+end;
+
+procedure TDelegatedExtendedEqualityComparerFunc<T>.GetHashList(constref AValue: T; AHashList: PUInt32);
+begin
+  FExtendedHasher(AValue, AHashList);
+end;
+
+constructor TDelegatedExtendedEqualityComparerFunc<T>.Create(const AEqualityComparison: TEqualityComparisonFunc<T>;
+  const AHasher: THasherFunc<T>; const AExtendedHasher: TExtendedHasherFunc<T>);
+begin
+  FEqualityComparison := AEqualityComparison;
+  FHasher := AHasher;
+  FExtendedHasher := AExtendedHasher;
+end;
+
+constructor TDelegatedExtendedEqualityComparerFunc<T>.Create(const AEqualityComparison: TEqualityComparisonFunc<T>;
+  const AExtendedHasher: TExtendedHasherFunc<T>);
+begin
+  Create(AEqualityComparison, nil, AExtendedHasher);
+end;
+
+{ TExtendedEqualityComparer<T> }
+
+class function TExtendedEqualityComparer<T>.Default: IExtendedEqualityComparer<T>;
+begin
+  Result := _LookupVtableInfo(giExtendedEqualityComparer, TypeInfo(T), SizeOf(T));
+end;
+
+class function TExtendedEqualityComparer<T>.Default(
+  AExtenedHashFactoryClass: TExtendedHashFactoryClass
+  ): IExtendedEqualityComparer<T>;
+begin
+  Result := _LookupVtableInfoEx(giExtendedEqualityComparer, TypeInfo(T), SizeOf(T), AExtenedHashFactoryClass);
+end;
+
+class function TExtendedEqualityComparer<T>.Construct(
+  const AEqualityComparison: TOnEqualityComparison<T>; const AHasher: TOnHasher<T>;
+  const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>;
+begin
+  Result := TDelegatedExtendedEqualityComparerEvents<T>.Create(AEqualityComparison, AHasher, AExtendedHasher);
+end;
+
+class function TExtendedEqualityComparer<T>.Construct(
+  const AEqualityComparison: TEqualityComparisonFunc<T>; const AHasher: THasherFunc<T>;
+  const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>;
+begin
+  Result := TDelegatedExtendedEqualityComparerFunc<T>.Create(AEqualityComparison, AHasher, AExtendedHasher);
+end;
+
+class function TExtendedEqualityComparer<T>.Construct(
+  const AEqualityComparison: TOnEqualityComparison<T>;
+  const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>;
+begin
+  Result := TDelegatedExtendedEqualityComparerEvents<T>.Create(AEqualityComparison, AExtendedHasher);
+end;
+
+class function TExtendedEqualityComparer<T>.Construct(
+  const AEqualityComparison: TEqualityComparisonFunc<T>;
+  const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>;
+begin
+  Result := TDelegatedExtendedEqualityComparerFunc<T>.Create(AEqualityComparison, AExtendedHasher);
+end;
+
+{ TDelphiHashFactory }
+
+class function TDelphiHashFactory.GetHashService: THashServiceClass;
+begin
+  Result := THashService<TDelphiHashFactory>;
+end;
+
+class function TDelphiHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32;
+begin
+  Result := DelphiHashLittle(AKey, ASize, AInitVal);
+end;
+
+{ TAdler32HashFactory }
+
+class function TAdler32HashFactory.GetHashService: THashServiceClass;
+begin
+  Result := THashService<TAdler32HashFactory>;
+end;
+
+class function TAdler32HashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt;
+  AInitVal: UInt32): UInt32;
+begin
+  Result := Adler32(AKey, ASize);
+end;
+
+{ TSdbmHashFactory }
+
+class function TSdbmHashFactory.GetHashService: THashServiceClass;
+begin
+  Result := THashService<TSdbmHashFactory>;
+end;
+
+class function TSdbmHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt;
+  AInitVal: UInt32): UInt32;
+begin
+  Result := sdbm(AKey, ASize);
+end;
+
+{ TSimpleChecksumFactory }
+
+class function TSimpleChecksumFactory.GetHashService: THashServiceClass;
+begin
+  Result := THashService<TSimpleChecksumFactory>;
+end;
+
+class function TSimpleChecksumFactory.GetHashCode(AKey: Pointer; ASize: SizeInt;
+  AInitVal: UInt32): UInt32;
+begin
+  Result := SimpleChecksumHash(AKey, ASize);
+end;
+
+{ TDelphiDoubleHashFactory }
+
+class function TDelphiDoubleHashFactory.GetHashService: THashServiceClass;
+begin
+  Result := TExtendedHashService<TDelphiDoubleHashFactory>;
+end;
+
+class function TDelphiDoubleHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32;
+begin
+  Result := DelphiHashLittle(AKey, ASize, AInitVal);
+end;
+
+class procedure TDelphiDoubleHashFactory.GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32;
+        AOptions: TGetHashListOptions);
+var
+  LHash: UInt32;
+  AHashListParams: PUInt16 absolute AHashList;
+begin
+{$WARNINGS OFF}
+  case AHashListParams[0] of
+    -2:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]);
+        Exit;
+      end;
+    -1:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    0: Exit;
+    1:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    2:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+        begin
+          AHashList[1] := 0;
+          AHashList[2] := 0;
+        end;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]);
+        Exit;
+      end;
+  else
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+  end;
+{$WARNINGS ON}
+end;
+
+{ TDelphiQuadrupleHashFactory }
+
+class function TDelphiQuadrupleHashFactory.GetHashService: THashServiceClass;
+begin
+  Result := TExtendedHashService<TDelphiQuadrupleHashFactory>;
+end;
+
+class function TDelphiQuadrupleHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32;
+begin
+  Result := DelphiHashLittle(AKey, ASize, AInitVal);
+end;
+
+class procedure TDelphiQuadrupleHashFactory.GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32;
+        AOptions: TGetHashListOptions);
+var
+  LHash: UInt32;
+  AHashListParams: PInt16 absolute AHashList;
+begin
+  case AHashListParams[0] of
+    -4:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 1988;
+        LHash := 2004;
+        DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]);
+        Exit;
+      end;
+    -3:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 2004;
+        LHash := 1988;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    -2:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]);
+        Exit;
+      end;
+    -1:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    0: Exit;
+    1:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    2:
+      begin
+        case AHashListParams[1] of
+          0, 1:
+            begin
+              if not (ghloHashListAsInitData in AOptions) then
+              begin
+                AHashList[1] := 0;
+                AHashList[2] := 0;
+              end;
+              DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]);
+              Exit;
+            end;
+          2:
+            begin
+              if not (ghloHashListAsInitData in AOptions) then
+              begin
+                AHashList[1] := 2004;
+                AHashList[2] := 1988;
+              end;
+              DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]);
+              Exit;
+            end;
+        else
+          raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+        end;
+      end;
+    4:
+      case AHashListParams[1] of
+        1:
+          begin
+            if not (ghloHashListAsInitData in AOptions) then
+            begin
+              AHashList[1] := 0;
+              AHashList[2] := 0;
+            end;
+            DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]);
+            Exit;
+          end;
+        2:
+          begin
+            if not (ghloHashListAsInitData in AOptions) then
+            begin
+              AHashList[3] := 2004;
+              AHashList[4] := 1988;
+            end;
+            DelphiHashLittle2(AKey, ASize, AHashList[3], AHashList[4]);
+            Exit;
+          end;
+      else
+        raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+      end;
+  else
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+  end;
+end;
+
+{ TDelphiSixfoldHashFactory }
+
+class function TDelphiSixfoldHashFactory.GetHashService: THashServiceClass;
+begin
+  Result := TExtendedHashService<TDelphiSixfoldHashFactory>;
+end;
+
+class function TDelphiSixfoldHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32;
+begin
+  Result := DelphiHashLittle(AKey, ASize, AInitVal);
+end;
+
+class procedure TDelphiSixfoldHashFactory.GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32;
+        AOptions: TGetHashListOptions);
+var
+  LHash: UInt32;
+  AHashListParams: PInt16 absolute AHashList;
+begin
+  case AHashListParams[0] of
+    -6:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 2;
+        LHash := 1;
+        DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]);
+        Exit;
+      end;
+    -5:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 1;
+        LHash := 2;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    -4:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 1988;
+        LHash := 2004;
+        DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]);
+        Exit;
+      end;
+    -3:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 2004;
+        LHash := 1988;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    -2:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]);
+        Exit;
+      end;
+    -1:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    0: Exit;
+    1:
+      begin
+        if not (ghloHashListAsInitData in AOptions) then
+          AHashList[1] := 0;
+        LHash := 0;
+        DelphiHashLittle2(AKey, ASize, AHashList[1], LHash);
+        Exit;
+      end;
+    2:
+      begin
+        case AHashListParams[1] of
+          0, 1:
+            begin
+              if not (ghloHashListAsInitData in AOptions) then
+              begin
+                AHashList[1] := 0;
+                AHashList[2] := 0;
+              end;
+              DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]);
+              Exit;
+            end;
+          2:
+            begin
+              if not (ghloHashListAsInitData in AOptions) then
+              begin
+                AHashList[1] := 2004;
+                AHashList[2] := 1988;
+              end;
+              DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]);
+              Exit;
+            end;
+        else
+          raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+        end;
+      end;
+    6:
+      case AHashListParams[1] of
+        1:
+          begin
+            if not (ghloHashListAsInitData in AOptions) then
+            begin
+              AHashList[1] := 0;
+              AHashList[2] := 0;
+            end;
+            DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]);
+            Exit;
+          end;
+        2:
+          begin
+            if not (ghloHashListAsInitData in AOptions) then
+            begin
+              AHashList[3] := 2004;
+              AHashList[4] := 1988;
+            end;
+            DelphiHashLittle2(AKey, ASize, AHashList[3], AHashList[4]);
+            Exit;
+          end;
+        3:
+          begin
+            if not (ghloHashListAsInitData in AOptions) then
+            begin
+              AHashList[5] := 1;
+              AHashList[6] := 2;
+            end;
+            DelphiHashLittle2(AKey, ASize, AHashList[5], AHashList[6]);
+            Exit;
+          end;
+      else
+        raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+      end;
+  else
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+  end;
+end;
+
+{ TOrdinalComparer<T, THashFactory> }
+
+class constructor TOrdinalComparer<T, THashFactory>.Create;
+begin
+  if THashFactory.InheritsFrom(TExtendedHashService) then
+  begin
+    FExtendedEqualityComparer := TExtendedEqualityComparer<T>.Default(TExtendedHashFactoryClass(THashFactory));
+    FEqualityComparer := IEqualityComparer<T>(FExtendedEqualityComparer);
+  end
+  else
+    FEqualityComparer := TEqualityComparer<T>.Default(THashFactory);
+  FComparer := TComparer<T>.Default;
+end;
+
+{ TGStringComparer<T, THashFactory> }
+
+class destructor TGStringComparer<T, THashFactory>.Destroy;
+begin
+  if Assigned(FOrdinal) then
+    FOrdinal.Free;
+end;
+
+class function TGStringComparer<T, THashFactory>.Ordinal: TCustomComparer<T>;
+begin
+  if not Assigned(FOrdinal) then
+    FOrdinal := TGOrdinalStringComparer<T, THashFactory>.Create;
+  Result := FOrdinal;
+end;
+
+{ TGOrdinalStringComparer<T, THashFactory> }
+
+function TGOrdinalStringComparer<T, THashFactory>.Compare(constref ALeft, ARight: T): Integer;
+begin
+  Result := FComparer.Compare(ALeft, ARight);
+end;
+
+function TGOrdinalStringComparer<T, THashFactory>.Equals(constref ALeft, ARight: T): Boolean;
+begin
+  Result := FEqualityComparer.Equals(ALeft, ARight);
+end;
+
+function TGOrdinalStringComparer<T, THashFactory>.GetHashCode(constref AValue: T): UInt32;
+begin
+  Result := FEqualityComparer.GetHashCode(AValue);
+end;
+
+procedure TGOrdinalStringComparer<T, THashFactory>.GetHashList(constref AValue: T; AHashList: PUInt32);
+begin
+  FExtendedEqualityComparer.GetHashList(AValue, AHashList);
+end;
+
+{ TGIStringComparer<T, THashFactory> }
+
+class destructor TGIStringComparer<T, THashFactory>.Destroy;
+begin
+  if Assigned(FOrdinal) then
+    FOrdinal.Free;
+end;
+
+class function TGIStringComparer<T, THashFactory>.Ordinal: TCustomComparer<T>;
+begin
+  if not Assigned(FOrdinal) then
+    FOrdinal := TGOrdinalIStringComparer<T, THashFactory>.Create;
+  Result := FOrdinal;
+end;
+
+{ TGOrdinalIStringComparer<T, THashFactory> }
+
+function TGOrdinalIStringComparer<T, THashFactory>.Compare(constref ALeft, ARight: T): Integer;
+begin
+  Result := FComparer.Compare(ALeft.ToLower, ARight.ToLower);
+end;
+
+function TGOrdinalIStringComparer<T, THashFactory>.Equals(constref ALeft, ARight: T): Boolean;
+begin
+  Result := FEqualityComparer.Equals(ALeft.ToLower, ARight.ToLower);
+end;
+
+function TGOrdinalIStringComparer<T, THashFactory>.GetHashCode(constref AValue: T): UInt32;
+begin
+  Result := FEqualityComparer.GetHashCode(AValue.ToLower);
+end;
+
+procedure TGOrdinalIStringComparer<T, THashFactory>.GetHashList(constref AValue: T; AHashList: PUInt32);
+begin
+  FExtendedEqualityComparer.GetHashList(AValue.ToLower, AHashList);
+end;
+
+function BobJenkinsHash(const AData; ALength, AInitData: Integer): Integer;
+begin
+  Result := DelphiHashLittle(@AData, ALength, AInitData);
+end;
+
+function BinaryCompare(const ALeft, ARight: Pointer; ASize: PtrUInt): Integer;
+begin
+  Result := CompareMemRange(ALeft, ARight, ASize);
+end;
+
+function _LookupVtableInfo(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer;
+begin
+  Result := _LookupVtableInfoEx(AGInterface, ATypeInfo, ASize, nil);
+end;
+
+function _LookupVtableInfoEx(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt;
+  AFactory: THashFactoryClass): Pointer;
+begin
+  case AGInterface of
+    giComparer:
+        Exit(
+          TComparerService.LookupComparer(ATypeInfo, ASize));
+    giEqualityComparer:
+      begin
+        if AFactory = nil then
+          AFactory := TDelphiHashFactory;
+
+        Exit(
+          AFactory.GetHashService.LookupEqualityComparer(ATypeInfo, ASize));
+      end;
+    giExtendedEqualityComparer:
+      begin
+        if AFactory = nil then
+          AFactory := TDelphiDoubleHashFactory;
+
+        Exit(
+          TExtendedHashServiceClass(AFactory.GetHashService).LookupExtendedEqualityComparer(ATypeInfo, ASize));
+      end;
+  else
+    System.Error(reRangeError);
+    Exit(nil);
+  end;
+end;
+
+end.
+

+ 915 - 0
packages/rtl-generics/src/generics.hashes.pas

@@ -0,0 +1,915 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit Generics.Hashes;
+
+{$MODE DELPHI}{$H+}
+{$POINTERMATH ON}
+{$MACRO ON}
+{$COPERATORS ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+
+interface
+
+uses
+  Classes, SysUtils;
+
+// Original version of Bob Jenkins Hash
+// http://burtleburtle.net/bob/c/lookup3.c
+function HashWord(
+  AKey: PLongWord;                   //* the key, an array of uint32_t values */
+  ALength: SizeInt;                  //* the length of the key, in uint32_ts */
+  AInitVal: UInt32): UInt32;         //* the previous hash, or an arbitrary value */
+procedure HashWord2 (
+  AKey: PLongWord;                   //* the key, an array of uint32_t values */
+  ALength: SizeInt;                  //* the length of the key, in uint32_ts */
+  var APrimaryHashAndInitVal: UInt32;                  //* IN: seed OUT: primary hash value */
+  var ASecondaryHashAndInitVal: UInt32);               //* IN: more seed OUT: secondary hash value */
+
+function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32;
+procedure HashLittle2(
+  AKey: Pointer;        //* the key to hash */
+  ALength: SizeInt;     //* length of the key */
+  var APrimaryHashAndInitVal: UInt32;                  //* IN: primary initval, OUT: primary hash */
+  var ASecondaryHashAndInitVal: UInt32);               //* IN: secondary initval, OUT: secondary hash */
+
+function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32;
+procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32);
+
+// hash function from fstl
+function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32;
+
+// some other hashes
+// http://stackoverflow.com/questions/14409466/simple-hash-functions
+// http://www.partow.net/programming/hashfunctions/
+// http://en.wikipedia.org/wiki/List_of_hash_functions
+// http://www.cse.yorku.ca/~oz/hash.html
+
+// https://code.google.com/p/hedgewars/source/browse/hedgewars/adler32.pas
+function Adler32(AKey: Pointer; ALength: SizeInt): UInt32;
+function sdbm(AKey: Pointer; ALength: SizeInt): UInt32;
+
+implementation
+
+function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32;
+var
+  i: Integer;
+  ABuffer: PUInt8 absolute AKey;
+begin
+  Result := 0;
+  for i := 0 to ALength - 1 do
+     Inc(Result,ABuffer[i]);
+end;
+
+function Adler32(AKey: Pointer; ALength: SizeInt): UInt32;
+const
+  MOD_ADLER = 65521;
+var
+  ABuffer: PUInt8 absolute AKey;
+  a: UInt32 = 1;
+  b: UInt32 = 0;
+  n: Integer;
+begin
+  for n := 0 to ALength -1 do
+  begin
+    a := (a + ABuffer[n]) mod MOD_ADLER;
+    b := (b + a) mod MOD_ADLER;
+  end;
+  Result := (b shl 16) or a;
+end;
+
+function sdbm(AKey: Pointer; ALength: SizeInt): UInt32;
+var
+  c: PUInt8 absolute AKey;
+  i: Integer;
+begin
+  Result := 0;
+  c := AKey;
+  for i := 0 to ALength - 1 do
+  begin
+    Result := c^ + (Result shl 6) + (Result shl 16) {%H-}- Result;
+    Inc(c);
+  end;
+end;
+
+{ BobJenkinsHash }
+
+{$define mix_abc :=
+  a -= c;  a := a xor (((c)shl(4)) or ((c)shr(32-(4))));  c += b;
+  b -= a;  b := b xor (((a)shl(6)) or ((a)shr(32-(6))));  a += c;
+  c -= b;  c := c xor (((b)shl(8)) or ((b)shr(32-(8))));  b += a;
+  a -= c;  a := a xor (((c)shl(16)) or ((c)shr(32-(16))));  c += b;
+  b -= a;  b := b xor (((a)shl(19)) or ((a)shr(32-(19))));  a += c;
+  c -= b;  c := c xor (((b)shl(4)) or ((b)shr(32-(4))));  b += a
+}
+
+{$define final_abc :=
+  c := c xor b; c -= (((b)shl(14)) or ((b)shr(32-(14))));
+  a := a xor c; a -= (((c)shl(11)) or ((c)shr(32-(11))));
+  b := b xor a; b -= (((a)shl(25)) or ((a)shr(32-(25))));
+  c := c xor b; c -= (((b)shl(16)) or ((b)shr(32-(16))));
+  a := a xor c; a -= (((c)shl(4)) or ((c)shr(32-(4))));
+  b := b xor a; b -= (((a)shl(14)) or ((a)shr(32-(14))));
+  c := c xor b; c -= (((b)shl(24)) or ((b)shr(32-(24))))
+}
+
+function HashWord(
+  AKey: PLongWord;                   //* the key, an array of uint32_t values */
+  ALength: SizeInt;               //* the length of the key, in uint32_ts */
+  AInitVal: UInt32): UInt32;         //* the previous hash, or an arbitrary value */
+var
+  a,b,c: UInt32;
+label
+  Case0, Case1, Case2, Case3;
+begin
+  //* Set up the internal state */
+  a := $DEADBEEF + (UInt32(ALength) shl 2) + AInitVal;
+  b := a;
+  c := b;
+
+  //*------------------------------------------------- handle most of the key */
+  while ALength > 3 do
+  begin
+    a += AKey[0];
+    b += AKey[1];
+    c += AKey[2];
+    mix_abc;
+    ALength -= 3;
+    AKey += 3;
+  end;
+
+  //*------------------------------------------- handle the last 3 uint32_t's */
+  case ALength of //* all the case statements fall through */
+    3: goto Case3;
+    2: goto Case2;
+    1: goto Case1;
+    0: goto Case0;
+  end;
+  Case3: c+=AKey[2];
+  Case2: b+=AKey[1];
+  Case1: a+=AKey[0];
+    final_abc;
+  Case0:     //* case 0: nothing left to add */
+  //*------------------------------------------------------ report the result */
+  Result := c;
+end;
+
+procedure HashWord2 (
+AKey: PLongWord;                   //* the key, an array of uint32_t values */
+ALength: SizeInt;               //* the length of the key, in uint32_ts */
+var APrimaryHashAndInitVal: UInt32;                      //* IN: seed OUT: primary hash value */
+var ASecondaryHashAndInitVal: UInt32);               //* IN: more seed OUT: secondary hash value */
+var
+  a,b,c: UInt32;
+label
+  Case0, Case1, Case2, Case3;
+begin
+  //* Set up the internal state */
+  a := $deadbeef + (UInt32(ALength shl 2)) + APrimaryHashAndInitVal;
+  b := a;
+  c := b;
+  c += ASecondaryHashAndInitVal;
+
+  //*------------------------------------------------- handle most of the key */
+  while ALength > 3 do
+  begin
+    a += AKey[0];
+    b += AKey[1];
+    c += AKey[2];
+    mix_abc;
+    ALength -= 3;
+    AKey += 3;
+  end;
+
+  //*------------------------------------------- handle the last 3 uint32_t's */
+  case ALength of                     //* all the case statements fall through */
+    3: goto Case3;
+    2: goto Case2;
+    1: goto Case1;
+    0: goto Case0;
+  end;
+  Case3: c+=AKey[2];
+  Case2: b+=AKey[1];
+  Case1: a+=AKey[0];
+    final_abc;
+  Case0:     //* case 0: nothing left to add */
+  //*------------------------------------------------------ report the result */
+  APrimaryHashAndInitVal := c;
+  ASecondaryHashAndInitVal := b;
+end;
+
+function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32;
+var
+  a, b, c: UInt32;
+  u: record case byte of
+    0: (ptr: Pointer);
+    1: (i: PtrUint);
+  end absolute AKey;
+
+  k32: ^UInt32 absolute AKey;
+  k16: ^UInt16 absolute AKey;
+  k8: ^UInt8 absolute AKey;
+
+label _10, _8, _6, _4, _2;
+label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
+
+begin
+  a := $DEADBEEF + UInt32(ALength) + AInitVal;
+  b := a;
+  c := b;
+
+{$IFDEF ENDIAN_LITTLE}
+  if (u.i and $3) = 0 then
+  begin
+    while (ALength > 12) do
+    begin
+      a += k32[0];
+      b += k32[1];
+      c += k32[2];
+      mix_abc;
+      ALength -= 12;
+      k32 += 3;
+    end;
+
+    case ALength of
+      12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
+      11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
+      10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
+      9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
+      8 : begin b += k32[1]; a += k32[0]; end;
+      7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
+      6 : begin b += k32[1] and $ffff; a += k32[0]; end;
+      5 : begin b += k32[1] and $ff; a += k32[0]; end;
+      4 : begin a += k32[0]; end;
+      3 : begin a += k32[0] and $ffffff; end;
+      2 : begin a += k32[0] and $ffff; end;
+      1 : begin a += k32[0] and $ff; end;
+      0 : Exit(c);              // zero length strings require no mixing
+    end
+  end
+  else
+  if (u.i and $1) = 0 then
+  begin
+    while (ALength > 12) do
+    begin
+      a += k16[0] + (UInt32(k16[1]) shl 16);
+      b += k16[2] + (UInt32(k16[3]) shl 16);
+      c += k16[4] + (UInt32(k16[5]) shl 16);
+      mix_abc;
+      ALength -= 12;
+      k16 += 6;
+    end;
+
+    case ALength of
+      12:
+        begin
+          c+=k16[4]+((UInt32(k16[5])) shl 16);
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      11:
+        begin
+          c+=(UInt32(k8[10])) shl 16;     //* fall through */
+          goto _10;
+        end;
+      10:
+        begin _10:
+          c+=k16[4];
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      9 :
+        begin
+          c+=k8[8];                      //* fall through */
+          goto _8;
+        end;
+      8 :
+        begin _8:
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      7 :
+        begin
+          b+=(UInt32(k8[6])) shl 16;      //* fall through */
+          goto _6;
+        end;
+      6 :
+        begin _6:
+          b+=k16[2];
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      5 :
+        begin
+          b+=k8[4];                      //* fall through */
+          goto _4;
+        end;
+      4 :
+        begin _4:
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      3 :
+        begin
+          a+=(UInt32(k8[2])) shl 16;      //* fall through */
+          goto _2;
+        end;
+      2 :
+        begin _2:
+          a+=k16[0];
+        end;
+      1 :
+        begin
+          a+=k8[0];
+        end;
+      0 : Exit(c);                     //* zero length requires no mixing */
+    end;
+  end
+  else
+{$ENDIF}
+  begin
+    while ALength > 12 do
+    begin
+      a += k8[0];
+      a += (UInt32(k8[1])) shl 8;
+      a += (UInt32(k8[2])) shl 16;
+      a += (UInt32(k8[3])) shl 24;
+      b += k8[4];
+      b += (UInt32(k8[5])) shl 8;
+      b += (UInt32(k8[6])) shl 16;
+      b += (UInt32(k8[7])) shl 24;
+      c += k8[8];
+      c += (UInt32(k8[9])) shl 8;
+      c += (UInt32(k8[10])) shl 16;
+      c += (UInt32(k8[11])) shl 24;
+      mix_abc;
+      ALength -= 12;
+      k8 += 12;
+    end;
+
+    case ALength of
+      12: goto Case12;
+      11: goto Case11;
+      10: goto Case10;
+      9 : goto Case9;
+      8 : goto Case8;
+      7 : goto Case7;
+      6 : goto Case6;
+      5 : goto Case5;
+      4 : goto Case4;
+      3 : goto Case3;
+      2 : goto Case2;
+      1 : goto Case1;
+      0 : Exit(c);
+    end;
+
+    Case12: c+=(UInt32(k8[11])) shl 24;
+    Case11: c+=(UInt32(k8[10])) shl 16;
+    Case10: c+=(UInt32(k8[9])) shl 8;
+    Case9: c+=k8[8];
+    Case8: b+=(UInt32(k8[7])) shl 24;
+    Case7: b+=(UInt32(k8[6])) shl 16;
+    Case6: b+=(UInt32(k8[5])) shl 8;
+    Case5: b+=k8[4];
+    Case4: a+=(UInt32(k8[3])) shl 24;
+    Case3: a+=(UInt32(k8[2])) shl 16;
+    Case2: a+=(UInt32(k8[1])) shl 8;
+    Case1: a+=k8[0];
+  end;
+
+  final_abc;
+  Result := c;
+end;
+
+(*
+ * hashlittle2: return 2 32-bit hash values
+ *
+ * This is identical to hashlittle(), except it returns two 32-bit hash
+ * values instead of just one.  This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key.  *pc is better mixed than *pb, so use *pc first.  If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ *)
+procedure HashLittle2(
+  AKey: Pointer;        //* the key to hash */
+  ALength: SizeInt;    //* length of the key */
+  var APrimaryHashAndInitVal: UInt32;                      //* IN: primary initval, OUT: primary hash */
+  var ASecondaryHashAndInitVal: UInt32);               //* IN: secondary initval, OUT: secondary hash */
+var
+  a,b,c: UInt32;
+  u: record case byte of
+    0: (ptr: Pointer);
+    1: (i: PtrUint);
+  end absolute AKey;
+
+  k32: ^UInt32 absolute AKey;
+  k16: ^UInt16 absolute AKey;
+  k8: ^UInt8 absolute AKey;
+
+label _10, _8, _6, _4, _2;
+label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
+
+begin
+  //* Set up the internal state */
+  a := $DEADBEEF + UInt32(ALength) + APrimaryHashAndInitVal;
+  b := a;
+  c := b;
+  c += ASecondaryHashAndInitVal;
+
+{$IFDEF ENDIAN_LITTLE}
+  if (u.i and $3) = 0 then
+  begin
+    while (ALength > 12) do
+    begin
+      a += k32[0];
+      b += k32[1];
+      c += k32[2];
+      mix_abc;
+      ALength -= 12;
+      k32 += 3;
+    end;
+
+    case ALength of
+      12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
+      11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
+      10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
+      9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
+      8 : begin b += k32[1]; a += k32[0]; end;
+      7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
+      6 : begin b += k32[1] and $ffff; a += k32[0]; end;
+      5 : begin b += k32[1] and $ff; a += k32[0]; end;
+      4 : begin a += k32[0]; end;
+      3 : begin a += k32[0] and $ffffff; end;
+      2 : begin a += k32[0] and $ffff; end;
+      1 : begin a += k32[0] and $ff; end;
+      0 :
+        begin
+          APrimaryHashAndInitVal := c;
+          ASecondaryHashAndInitVal := b;
+          Exit;              // zero length strings require no mixing
+        end;
+    end
+  end
+  else
+  if (u.i and $1) = 0 then
+  begin
+    while (ALength > 12) do
+    begin
+      a += k16[0] + (UInt32(k16[1]) shl 16);
+      b += k16[2] + (UInt32(k16[3]) shl 16);
+      c += k16[4] + (UInt32(k16[5]) shl 16);
+      mix_abc;
+      ALength -= 12;
+      k16 += 6;
+    end;
+
+    case ALength of
+      12:
+        begin
+          c+=k16[4]+((UInt32(k16[5])) shl 16);
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      11:
+        begin
+          c+=(UInt32(k8[10])) shl 16;     //* fall through */
+          goto _10;
+        end;
+      10:
+        begin _10:
+          c+=k16[4];
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      9 :
+        begin
+          c+=k8[8];                      //* fall through */
+          goto _8;
+        end;
+      8 :
+        begin _8:
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      7 :
+        begin
+          b+=(UInt32(k8[6])) shl 16;      //* fall through */
+          goto _6;
+        end;
+      6 :
+        begin _6:
+          b+=k16[2];
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      5 :
+        begin
+          b+=k8[4];                      //* fall through */
+          goto _4;
+        end;
+      4 :
+        begin _4:
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      3 :
+        begin
+          a+=(UInt32(k8[2])) shl 16;      //* fall through */
+          goto _2;
+        end;
+      2 :
+        begin _2:
+          a+=k16[0];
+        end;
+      1 :
+        begin
+          a+=k8[0];
+        end;
+      0 :
+        begin
+          APrimaryHashAndInitVal := c;
+          ASecondaryHashAndInitVal := b;
+          Exit;              // zero length strings require no mixing
+        end;
+    end;
+  end
+  else
+{$ENDIF}
+  begin
+    while ALength > 12 do
+    begin
+      a += k8[0];
+      a += (UInt32(k8[1])) shl 8;
+      a += (UInt32(k8[2])) shl 16;
+      a += (UInt32(k8[3])) shl 24;
+      b += k8[4];
+      b += (UInt32(k8[5])) shl 8;
+      b += (UInt32(k8[6])) shl 16;
+      b += (UInt32(k8[7])) shl 24;
+      c += k8[8];
+      c += (UInt32(k8[9])) shl 8;
+      c += (UInt32(k8[10])) shl 16;
+      c += (UInt32(k8[11])) shl 24;
+      mix_abc;
+      ALength -= 12;
+      k8 += 12;
+    end;
+
+    case ALength of
+      12: goto Case12;
+      11: goto Case11;
+      10: goto Case10;
+      9 : goto Case9;
+      8 : goto Case8;
+      7 : goto Case7;
+      6 : goto Case6;
+      5 : goto Case5;
+      4 : goto Case4;
+      3 : goto Case3;
+      2 : goto Case2;
+      1 : goto Case1;
+      0 :
+        begin
+          APrimaryHashAndInitVal := c;
+          ASecondaryHashAndInitVal := b;
+          Exit;              // zero length strings require no mixing
+        end;
+    end;
+
+    Case12: c+=(UInt32(k8[11])) shl 24;
+    Case11: c+=(UInt32(k8[10])) shl 16;
+    Case10: c+=(UInt32(k8[9])) shl 8;
+    Case9: c+=k8[8];
+    Case8: b+=(UInt32(k8[7])) shl 24;
+    Case7: b+=(UInt32(k8[6])) shl 16;
+    Case6: b+=(UInt32(k8[5])) shl 8;
+    Case5: b+=k8[4];
+    Case4: a+=(UInt32(k8[3])) shl 24;
+    Case3: a+=(UInt32(k8[2])) shl 16;
+    Case2: a+=(UInt32(k8[1])) shl 8;
+    Case1: a+=k8[0];
+  end;
+
+  final_abc;
+  APrimaryHashAndInitVal := c;
+  ASecondaryHashAndInitVal := b;
+end;
+
+procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32);
+var
+  a,b,c: UInt32;
+  u: record case byte of
+    0: (ptr: Pointer);
+    1: (i: PtrUint);
+  end absolute AKey;
+
+  k32: ^UInt32 absolute AKey;
+  k16: ^UInt16 absolute AKey;
+  k8: ^UInt8 absolute AKey;
+
+label _10, _8, _6, _4, _2;
+label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
+
+begin
+  //* Set up the internal state */
+  a := $DEADBEEF + UInt32(ALength shl 2) + APrimaryHashAndInitVal; // delphi version bug? original version don't have "shl 2"
+  b := a;
+  c := b;
+  c += ASecondaryHashAndInitVal;
+
+{$IFDEF ENDIAN_LITTLE}
+  if (u.i and $3) = 0 then
+  begin
+    while (ALength > 12) do
+    begin
+      a += k32[0];
+      b += k32[1];
+      c += k32[2];
+      mix_abc;
+      ALength -= 12;
+      k32 += 3;
+    end;
+
+    case ALength of
+      12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
+      11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
+      10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
+      9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
+      8 : begin b += k32[1]; a += k32[0]; end;
+      7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
+      6 : begin b += k32[1] and $ffff; a += k32[0]; end;
+      5 : begin b += k32[1] and $ff; a += k32[0]; end;
+      4 : begin a += k32[0]; end;
+      3 : begin a += k32[0] and $ffffff; end;
+      2 : begin a += k32[0] and $ffff; end;
+      1 : begin a += k32[0] and $ff; end;
+      0 :
+        begin
+          APrimaryHashAndInitVal := c;
+          ASecondaryHashAndInitVal := b;
+          Exit;              // zero length strings require no mixing
+        end;
+    end
+  end
+  else
+  if (u.i and $1) = 0 then
+  begin
+    while (ALength > 12) do
+    begin
+      a += k16[0] + (UInt32(k16[1]) shl 16);
+      b += k16[2] + (UInt32(k16[3]) shl 16);
+      c += k16[4] + (UInt32(k16[5]) shl 16);
+      mix_abc;
+      ALength -= 12;
+      k16 += 6;
+    end;
+
+    case ALength of
+      12:
+        begin
+          c+=k16[4]+((UInt32(k16[5])) shl 16);
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      11:
+        begin
+          c+=(UInt32(k8[10])) shl 16;     //* fall through */
+          goto _10;
+        end;
+      10:
+        begin _10:
+          c+=k16[4];
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      9 :
+        begin
+          c+=k8[8];                      //* fall through */
+          goto _8;
+        end;
+      8 :
+        begin _8:
+          b+=k16[2]+((UInt32(k16[3])) shl 16);
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      7 :
+        begin
+          b+=(UInt32(k8[6])) shl 16;      //* fall through */
+          goto _6;
+        end;
+      6 :
+        begin _6:
+          b+=k16[2];
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      5 :
+        begin
+          b+=k8[4];                      //* fall through */
+          goto _4;
+        end;
+      4 :
+        begin _4:
+          a+=k16[0]+((UInt32(k16[1])) shl 16);
+        end;
+      3 :
+        begin
+          a+=(UInt32(k8[2])) shl 16;      //* fall through */
+          goto _2;
+        end;
+      2 :
+        begin _2:
+          a+=k16[0];
+        end;
+      1 :
+        begin
+          a+=k8[0];
+        end;
+      0 :
+        begin
+          APrimaryHashAndInitVal := c;
+          ASecondaryHashAndInitVal := b;
+          Exit;              // zero length strings require no mixing
+        end;
+    end;
+  end
+  else
+{$ENDIF}
+  begin
+    while ALength > 12 do
+    begin
+      a += k8[0];
+      a += (UInt32(k8[1])) shl 8;
+      a += (UInt32(k8[2])) shl 16;
+      a += (UInt32(k8[3])) shl 24;
+      b += k8[4];
+      b += (UInt32(k8[5])) shl 8;
+      b += (UInt32(k8[6])) shl 16;
+      b += (UInt32(k8[7])) shl 24;
+      c += k8[8];
+      c += (UInt32(k8[9])) shl 8;
+      c += (UInt32(k8[10])) shl 16;
+      c += (UInt32(k8[11])) shl 24;
+      mix_abc;
+      ALength -= 12;
+      k8 += 12;
+    end;
+
+    case ALength of
+      12: goto Case12;
+      11: goto Case11;
+      10: goto Case10;
+      9 : goto Case9;
+      8 : goto Case8;
+      7 : goto Case7;
+      6 : goto Case6;
+      5 : goto Case5;
+      4 : goto Case4;
+      3 : goto Case3;
+      2 : goto Case2;
+      1 : goto Case1;
+      0 :
+        begin
+          APrimaryHashAndInitVal := c;
+          ASecondaryHashAndInitVal := b;
+          Exit;              // zero length strings require no mixing
+        end;
+    end;
+
+    Case12: c+=(UInt32(k8[11])) shl 24;
+    Case11: c+=(UInt32(k8[10])) shl 16;
+    Case10: c+=(UInt32(k8[9])) shl 8;
+    Case9: c+=k8[8];
+    Case8: b+=(UInt32(k8[7])) shl 24;
+    Case7: b+=(UInt32(k8[6])) shl 16;
+    Case6: b+=(UInt32(k8[5])) shl 8;
+    Case5: b+=k8[4];
+    Case4: a+=(UInt32(k8[3])) shl 24;
+    Case3: a+=(UInt32(k8[2])) shl 16;
+    Case2: a+=(UInt32(k8[1])) shl 8;
+    Case1: a+=k8[0];
+  end;
+
+  final_abc;
+  APrimaryHashAndInitVal := c;
+  ASecondaryHashAndInitVal := b;
+end;
+
+function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32;
+var
+  a, b, c: UInt32;
+  u: record case byte of
+    0: (ptr: Pointer);
+    1: (i: PtrUint);
+  end absolute AKey;
+
+  k32: ^UInt32 absolute AKey;
+  //k16: ^UInt16 absolute AKey;
+  k8: ^UInt8 absolute AKey;
+
+label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1;
+
+begin
+  a := $DEADBEEF + UInt32(ALength shl 2) + AInitVal; // delphi version bug? original version don't have "shl 2"
+  b := a;
+  c := b;
+
+{.$IFDEF ENDIAN_LITTLE} // Delphi version don't care
+  if (u.i and $3) = 0 then
+  begin
+    while (ALength > 12) do
+    begin
+      a += k32[0];
+      b += k32[1];
+      c += k32[2];
+      mix_abc;
+      ALength -= 12;
+      k32 += 3;
+    end;
+
+    case ALength of
+      12: begin c += k32[2]; b += k32[1]; a += k32[0]; end;
+      11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end;
+      10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end;
+      9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end;
+      8 : begin b += k32[1]; a += k32[0]; end;
+      7 : begin b += k32[1] and $ffffff; a += k32[0]; end;
+      6 : begin b += k32[1] and $ffff; a += k32[0]; end;
+      5 : begin b += k32[1] and $ff; a += k32[0]; end;
+      4 : begin a += k32[0]; end;
+      3 : begin a += k32[0] and $ffffff; end;
+      2 : begin a += k32[0] and $ffff; end;
+      1 : begin a += k32[0] and $ff; end;
+      0 : Exit(c);              // zero length strings require no mixing
+    end
+  end
+  else
+{.$ENDIF}
+  begin
+    while ALength > 12 do
+    begin
+      a += k8[0];
+      a += (UInt32(k8[1])) shl 8;
+      a += (UInt32(k8[2])) shl 16;
+      a += (UInt32(k8[3])) shl 24;
+      b += k8[4];
+      b += (UInt32(k8[5])) shl 8;
+      b += (UInt32(k8[6])) shl 16;
+      b += (UInt32(k8[7])) shl 24;
+      c += k8[8];
+      c += (UInt32(k8[9])) shl 8;
+      c += (UInt32(k8[10])) shl 16;
+      c += (UInt32(k8[11])) shl 24;
+      mix_abc;
+      ALength -= 12;
+      k8 += 12;
+    end;
+
+    case ALength of
+      12: goto Case12;
+      11: goto Case11;
+      10: goto Case10;
+      9 : goto Case9;
+      8 : goto Case8;
+      7 : goto Case7;
+      6 : goto Case6;
+      5 : goto Case5;
+      4 : goto Case4;
+      3 : goto Case3;
+      2 : goto Case2;
+      1 : goto Case1;
+      0 : Exit(c);
+    end;
+
+    Case12: c+=(UInt32(k8[11])) shl 24;
+    Case11: c+=(UInt32(k8[10])) shl 16;
+    Case10: c+=(UInt32(k8[9])) shl 8;
+    Case9: c+=k8[8];
+    Case8: b+=(UInt32(k8[7])) shl 24;
+    Case7: b+=(UInt32(k8[6])) shl 16;
+    Case6: b+=(UInt32(k8[5])) shl 8;
+    Case5: b+=k8[4];
+    Case4: a+=(UInt32(k8[3])) shl 24;
+    Case3: a+=(UInt32(k8[2])) shl 16;
+    Case2: a+=(UInt32(k8[1])) shl 8;
+    Case1: a+=k8[0];
+  end;
+
+  final_abc;
+  Result := Int32(c);
+end;
+
+end.
+

+ 144 - 0
packages/rtl-generics/src/generics.helpers.pas

@@ -0,0 +1,144 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit Generics.Helpers;
+
+{$MODE DELPHI}{$H+}
+{$MODESWITCH TYPEHELPERS}
+
+interface
+
+uses
+  Classes, SysUtils;
+
+type
+  { TValueAnsiStringHelper }
+
+  TValueAnsiStringHelper = record helper for AnsiString
+    function ToLower: AnsiString; inline;
+  end;
+
+  { TValuewideStringHelper }
+
+  TValueWideStringHelper = record helper for WideString
+    function ToLower: WideString; inline;
+  end;
+
+  { TValueUnicodeStringHelper }
+
+  TValueUnicodeStringHelper = record helper for UnicodeString
+    function ToLower: UnicodeString; inline;
+  end;
+
+  { TValueShortStringHelper }
+
+  TValueShortStringHelper = record helper for ShortString
+    function ToLower: ShortString; inline;
+  end;
+
+  { TValueUTF8StringHelper }
+
+  TValueUTF8StringHelper = record helper for UTF8String
+    function ToLower: UTF8String; inline;
+  end;
+
+  { TValueRawByteStringHelper }
+
+  TValueRawByteStringHelper = record helper for RawByteString
+    function ToLower: RawByteString; inline;
+  end;
+
+  { TValueUInt32Helper }
+
+  TValueUInt32Helper = record helper for UInt32
+    class function GetSignMask: UInt32; static; inline;
+    class function GetSizedSignMask(ABits: Byte): UInt32; static; inline;
+    class function GetBitsLength: Byte; static; inline;
+
+    const
+      SIZED_SIGN_MASK: array[1..32] of UInt32 = (
+        $80000000, $C0000000, $E0000000, $F0000000, $F8000000, $FC000000, $FE000000, $FF000000,
+        $FF800000, $FFC00000, $FFE00000, $FFF00000, $FFF80000, $FFFC0000, $FFFE0000, $FFFF0000,
+        $FFFF8000, $FFFFC000, $FFFFE000, $FFFFF000, $FFFFF800, $FFFFFC00, $FFFFFE00, $FFFFFF00,
+        $FFFFFF80, $FFFFFFC0, $FFFFFFE0, $FFFFFFF0, $FFFFFFF8, $FFFFFFFC, $FFFFFFFE, $FFFFFFFF);
+      BITS_LENGTH = 32;
+  end;
+
+implementation
+
+{ TRawDataStringHelper }
+
+function TValueAnsiStringHelper.ToLower: AnsiString;
+begin
+  Result := LowerCase(Self);
+end;
+
+{ TValueWideStringHelper }
+
+function TValueWideStringHelper.ToLower: WideString;
+begin
+  Result := LowerCase(Self);
+end;
+
+{ TValueUnicodeStringHelper }
+
+function TValueUnicodeStringHelper.ToLower: UnicodeString;
+begin
+  Result := LowerCase(Self);
+end;
+
+{ TValueShortStringHelper }
+
+function TValueShortStringHelper.ToLower: ShortString;
+begin
+  Result := LowerCase(Self);
+end;
+
+{ TValueUTF8StringHelper }
+
+function TValueUTF8StringHelper.ToLower: UTF8String;
+begin
+  Result := LowerCase(Self);
+end;
+
+{ TValueRawByteStringHelper }
+
+function TValueRawByteStringHelper.ToLower: RawByteString;
+begin
+  Result := LowerCase(Self);
+end;
+
+{ TValueUInt32Helper }
+
+class function TValueUInt32Helper.GetSignMask: UInt32;
+begin
+  Result := $80000000;
+end;
+
+class function TValueUInt32Helper.GetSizedSignMask(ABits: Byte): UInt32;
+begin
+  Result := SIZED_SIGN_MASK[ABits];
+end;
+
+class function TValueUInt32Helper.GetBitsLength: Byte;
+begin
+  Result := BITS_LENGTH;
+end;
+
+end.
+

+ 236 - 0
packages/rtl-generics/src/generics.memoryexpanders.pas

@@ -0,0 +1,236 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit Generics.MemoryExpanders;
+// Memory expanders
+
+{$mode delphi}
+{$MACRO ON}
+{.$WARN 5024 OFF}
+{.$WARN 4079 OFF}
+
+interface
+
+uses
+  Classes, SysUtils;
+
+type
+  TProbeSequence = class
+  public
+  end;
+
+  { TLinearProbing }
+
+  TLinearProbing = class(TProbeSequence)
+  public
+    class function Probe(I, {%H-}M, Hash: UInt32): UInt32; static; inline;
+
+    const MAX_LOAD_FACTOR = 1;
+    const DEFAULT_LOAD_FACTOR = 0.75;
+  end;
+
+  { TQuadraticProbing }
+
+  TQuadraticProbing = class(TProbeSequence)
+  private
+    class constructor Create;
+  public
+    class var C1: UInt32;
+    class var C2: UInt32;
+
+    class function Probe(I, {%H-}M, Hash: UInt32): UInt32; static; inline;
+
+    const MAX_LOAD_FACTOR = 0.5;
+    const DEFAULT_LOAD_FACTOR = 0.5;
+  end;
+
+  { TDoubleHashing }
+
+  TDoubleHashing = class(TProbeSequence)
+  public
+    class function Probe(I, {%H-}M, Hash1: UInt32; Hash2: UInt32 = 1): UInt32; static; inline;
+
+    const MAX_LOAD_FACTOR = 1;
+    const DEFAULT_LOAD_FACTOR = 0.85;
+  end;
+
+const
+  // http://stackoverflow.com/questions/757059/position-of-least-significant-bit-that-is-set
+  // MultiplyDeBruijnBitPosition[uint32(((numberInt32 and -numberInt32) * $077CB531)) shr 27]
+  MultiplyDeBruijnBitPosition: array[0..31] of Int32 =
+  (
+    0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+    31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+  );
+
+  // http://primes.utm.edu/lists/2small/0bit.html
+  // http://www.math.niu.edu/~rusin/known-math/98/pi_x
+  // http://oeis.org/A014234/
+  PrimaryNumbersJustLessThanPowerOfTwo: array[0..31] of UInt32 =
+  (
+    0, 1, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071,
+    262139, 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
+    134217689, 268435399, 536870909, 1073741789, 2147483647
+  );
+
+  // http://oeis.org/A014210
+  // http://oeis.org/A203074
+  PrimaryNumbersJustBiggerThanPowerOfTwo: array[0..31] of UInt32 = (
+    2,3,5,11,17,37,67,131,257,521,1031,2053,4099,
+    8209,16411,32771,65537,131101,262147,524309,
+    1048583,2097169,4194319,8388617,16777259,33554467,
+    67108879,134217757,268435459,536870923,1073741827,
+    2147483659);
+
+  // Fibonacci numbers
+  FibonacciNumbers: array[0..44] of UInt32 = (
+    {0,1,1,2,3,}0,5,8,13,21,34,55,89,144,233,377,610,987,
+    1597,2584,4181,6765,10946,17711,28657,46368,75025,
+    121393,196418,317811,514229,832040,1346269,
+    2178309,3524578,5702887,9227465,14930352,24157817,
+    39088169, 63245986, 102334155, 165580141, 267914296,
+    433494437, 701408733, 1134903170, 1836311903, 2971215073,
+    {! not fib number - this is memory limit} 4294967295);
+
+  // Largest prime not exceeding Fibonacci(n)
+  // http://oeis.org/A138184/list
+  // http://www.numberempire.com/primenumbers.php
+  PrimaryNumbersJustLessThanFibonacciNumbers: array[0..44] of UInt32 = (
+    {! not correlated to fib number. For empty table} 0,
+    5,7,13,19,31,53,89,139,233,373,607,983,1597,
+    2579,4177,6763,10939,17707,28657,46351,75017,
+    121379,196387,317797,514229,832003,1346249,
+    2178283,3524569,5702867,9227443,14930341,24157811,
+    39088157,63245971,102334123,165580123,267914279,
+    433494437,701408717,1134903127,1836311879,2971215073,
+    {! not correlated to fib number - this is prime memory limit} 4294967291);
+
+  // Smallest prime >= n-th Fibonacci number.
+  // http://oeis.org/A138185
+  PrimaryNumbersJustBiggerThanFibonacciNumbers: array[0..44] of UInt32 = (
+    {! not correlated to fib number. For empty table} 0,
+    5,11,13,23,37,59,89,149,233,379,613,
+    991,1597,2591,4201,6779,10949,17713,28657,46381,
+    75029,121403,196429,317827,514229,832063,1346273,
+    2178313,3524603,5702897,9227479,14930387,24157823,
+    39088193,63245989,102334157,165580147,267914303,
+    433494437,701408753,1134903179,1836311951,2971215073,
+    {! not correlated to fib number - this is prime memory limit} 4294967291);
+
+type
+
+  { TCuckooHashingCfg }
+
+  TCuckooHashingCfg = class
+  public
+    const D = 2;
+    const MAX_LOAD_FACTOR = 0.5;
+
+    class function LoadFactor(M: Integer): Integer; virtual;
+  end;
+
+  TStdCuckooHashingCfg = class(TCuckooHashingCfg)
+  public
+    const MAX_LOOP = 1000;
+  end;
+
+  TDeamortizedCuckooHashingCfg = class(TCuckooHashingCfg)
+  public
+    const L = 5;
+  end;
+
+  TDeamortizedCuckooHashingCfg_D2 = TDeamortizedCuckooHashingCfg;
+
+  { TDeamortizedCuckooHashingCfg_D4 }
+
+  TDeamortizedCuckooHashingCfg_D4 = class(TDeamortizedCuckooHashingCfg)
+  public
+    const D = 4;
+    const L = 20;
+    const MAX_LOAD_FACTOR = 0.9;
+
+    class function LoadFactor(M: Integer): Integer; override;
+  end;
+
+  { TDeamortizedCuckooHashingCfg_D6 }
+
+  TDeamortizedCuckooHashingCfg_D6 = class(TDeamortizedCuckooHashingCfg)
+  public
+    const D = 6;
+    const L = 170;
+    const MAX_LOAD_FACTOR = 0.99;
+
+    class function LoadFactor(M: Integer): Integer; override;
+  end;
+
+  TL5CuckooHashingCfg = class(TCuckooHashingCfg)
+  public
+  end;
+
+implementation
+
+{ TDeamortizedCuckooHashingCfg_D6 }
+
+class function TDeamortizedCuckooHashingCfg_D6.LoadFactor(M: Integer): Integer;
+begin
+  Result:=Pred(Round(MAX_LOAD_FACTOR*M));
+end;
+
+{ TDeamortizedCuckooHashingCfg_D4 }
+
+class function TDeamortizedCuckooHashingCfg_D4.LoadFactor(M: Integer): Integer;
+begin
+  Result:=Pred(Round(MAX_LOAD_FACTOR*M));
+end;
+
+{ TCuckooHashingCfg }
+
+class function TCuckooHashingCfg.LoadFactor(M: Integer): Integer;
+begin
+  Result := Pred(M shr 1);
+end;
+
+{ TLinearProbing }
+
+class function TLinearProbing.Probe(I, M, Hash: UInt32): UInt32;
+begin
+  Result := (Hash + I)
+end;
+
+{ TQuadraticProbing }
+
+class constructor TQuadraticProbing.Create;
+begin
+  C1 := 1;
+  C2 := 1;
+end;
+
+class function TQuadraticProbing.Probe(I, M, Hash: UInt32): UInt32;
+begin
+  Result := (Hash + C1 * I {%H-}+ C2 * Sqr(I));
+end;
+
+{ TDoubleHashingNoMod }
+
+class function TDoubleHashing.Probe(I, M, Hash1: UInt32; Hash2: UInt32): UInt32;
+begin
+  Result := Hash1 + I * Hash2;
+end;
+
+end.
+

+ 34 - 0
packages/rtl-generics/src/generics.strings.pas

@@ -0,0 +1,34 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit Generics.Strings;
+
+{$mode objfpc}{$H+}
+
+interface
+
+resourcestring
+  SArgumentOutOfRange = 'Argument out of range';
+  SDuplicatesNotAllowed = 'Duplicates not allowed in dictionary';
+  SDictionaryKeyDoesNotExist = 'Dictionary key does not exist';
+  SItemNotFound = 'Item not found';
+
+implementation
+
+end.
+

+ 1859 - 0
packages/rtl-generics/src/inc/generics.dictionaries.inc

@@ -0,0 +1,1859 @@
+{%MainUnit generics.collections.pas}
+
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{ TPair<TKey,TValue> }
+
+class function TPair<TKey, TValue>.Create(AKey: TKey;
+  AValue: TValue): TPair<TKey, TValue>;
+begin
+  Result.Key := AKey;
+  Result.Value := AValue;
+end;
+
+{ TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS> }
+
+procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.PairNotify(constref APair: TPair<TKey, TValue>;
+  ACollectionNotification: TCollectionNotification);
+begin
+  KeyNotify(APair.Key, ACollectionNotification);
+  ValueNotify(APair.Value, ACollectionNotification);
+end;
+
+procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.KeyNotify(constref AKey: TKey;
+  ACollectionNotification: TCollectionNotification);
+begin
+  if Assigned(FOnKeyNotify) then
+    FOnKeyNotify(Self, AKey, ACollectionNotification);
+end;
+
+procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.SetValue(var AValue: TValue; constref ANewValue: TValue);
+var
+  LOldValue: TValue;
+begin
+  LOldValue := AValue;
+  AValue := ANewValue;
+
+  ValueNotify(LOldValue, cnRemoved);
+  ValueNotify(ANewValue, cnAdded);
+end;
+
+procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.ValueNotify(constref AValue: TValue;
+  ACollectionNotification: TCollectionNotification);
+begin
+  if Assigned(FOnValueNotify) then
+    FOnValueNotify(Self, AValue, ACollectionNotification);
+end;
+
+constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create;
+begin
+  Create(0);
+end;
+
+constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACapacity: SizeInt); overload;
+begin
+  Create(ACapacity, TEqualityComparer<TKey>.Default(THashFactory));
+end;
+
+constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACapacity: SizeInt;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+  FEqualityComparer := AComparer;
+  SetCapacity(ACapacity);
+end;
+
+constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(const AComparer: IEqualityComparer<TKey>);
+begin
+  Create(0, AComparer);
+end;
+
+constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>);
+begin
+  Create(ACollection, TEqualityComparer<TKey>.Default(THashFactory));
+end;
+
+constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>;
+  const AComparer: IEqualityComparer<TKey>); overload;
+var
+  LItem: TPair<TKey, TValue>;
+begin
+  Create(AComparer);
+  for LItem in ACollection do
+    Add(LItem);
+end;
+
+destructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Destroy;
+begin
+  Clear;
+  FKeys.Free;
+  FValues.Free;
+  inherited;
+end;
+
+function TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray(ACount: SizeInt): TArray<TDictionaryPair>;
+var
+  i: SizeInt;
+  LEnumerator: TEnumerator<TDictionaryPair>;
+begin
+  SetLength(Result, ACount);
+  LEnumerator := DoGetEnumerator;
+
+  i := 0;
+  while LEnumerator.MoveNext do
+  begin
+    Result[i] := LEnumerator.Current;
+    Inc(i);
+  end;
+  LEnumerator.Free;
+end;
+
+function TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray: TArray<TDictionaryPair>;
+begin
+  Result := ToArray(Count);
+end;
+
+{ TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS> }
+
+constructor TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>.Create(
+  ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
+begin
+  inherited Create;
+  FIndex := -1;
+  FDictionary := ADictionary;
+end;
+
+function TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>.DoGetCurrent: T;
+begin
+  Result := GetCurrent;
+end;
+
+{ TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS> }
+
+constructor TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.Create(
+  ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
+begin
+  FDictionary := ADictionary;
+end;
+
+function TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.
+  DoGetEnumerator: TDictionaryEnumerator;
+begin
+  Result := TDictionaryEnumerator(TDictionaryEnumerator.NewInstance);
+  TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>(Result).Create(FDictionary);
+end;
+
+function TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.GetCount: SizeInt;
+begin
+  Result := TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>(FDictionary).Count;
+end;
+
+function TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray: TArray;
+begin
+  Result := ToArrayImpl(FDictionary.Count);
+end;
+
+{ TOpenAddressingEnumerator<T, DICTIONARY_CONSTRAINTS> }
+
+function TOpenAddressingEnumerator<T, OPEN_ADDRESSING_CONSTRAINTS>.DoMoveNext: Boolean;
+var
+  LLength: SizeInt;
+begin
+  Inc(FIndex);
+
+  LLength := Length(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems);
+
+  if FIndex >= LLength then
+    Exit(False);
+
+  // maybe related to bug #24098
+  // compiler error for (TDictionary<DICTIONARY_CONSTRAINTS>(FDictionary).FItems[FIndex].Hash and UInt32.GetSignMask) = 0
+  while ((TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Hash) and UInt32.GetSignMask) = 0 do
+  begin
+    Inc(FIndex);
+    if FIndex = LLength then
+      Exit(False);
+  end;
+
+  Result := True;
+end;
+
+{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS> }
+
+constructor TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+  inherited Create(ACapacity, AComparer);
+
+  FMaxLoadFactor := TProbeSequence.DEFAULT_LOAD_FACTOR;
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetKeys: TKeyCollection;
+begin
+  if not Assigned(FKeys) then
+    FKeys := TKeyCollection.Create(Self);
+  Result := TKeyCollection(FKeys);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetValues: TValueCollection;
+begin
+  if not Assigned(FValues) then
+    FValues := TValueCollection.Create(Self);
+  Result := TValueCollection(FValues);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AKey: TKey): SizeInt;
+var
+  LHash: UInt32;
+begin
+  Result := FindBucketIndex(FItems, AKey, LHash);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.PrepareAddingItem: SizeInt;
+begin
+  if RealItemsLength > FItemsThreshold then
+    Rehash(Length(FItems) shl 1)
+  else if FItemsThreshold = 0 then
+  begin
+    SetLength(FItems, 8);
+    UpdateItemsThreshold(8);
+  end
+  else if FItemsLength = $40000001 then // High(TIndex) ... Error: Type mismatch
+    OutOfMemoryError;
+
+  Result := FItemsLength;
+  Inc(FItemsLength);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt);
+begin
+  if ASize = $40000000 then
+    FItemsThreshold := $40000001
+  else
+    FItemsThreshold := Pred(Round(ASize * FMaxLoadFactor));
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.AddItem(var AItem: TItem; constref AKey: TKey;
+  constref AValue: TValue; const AHash: UInt32);
+begin
+  AItem.Hash := AHash;
+  AItem.Pair.Key := AKey;
+  AItem.Pair.Value := AValue;
+
+  PairNotify(AItem.Pair, cnAdded);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Add(constref AKey: TKey; constref AValue: TValue);
+begin
+  DoAdd(AKey, AValue);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Add(constref APair: TPair<TKey, TValue>);
+begin
+  DoAdd(APair.Key, APair.Value);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.DoAdd(constref AKey: TKey; constref AValue: TValue): SizeInt;
+var
+  LHash: UInt32;
+begin
+  PrepareAddingItem;
+
+  Result := FindBucketIndex(FItems, AKey, LHash);
+  if Result >= 0 then
+    raise EListError.CreateRes(@SDuplicatesNotAllowed);
+
+  Result := not Result;
+  AddItem(FItems[Result], AKey, AValue, LHash);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.DoRemove(AIndex: SizeInt;
+  ACollectionNotification: TCollectionNotification): TValue;
+var
+  LItem: PItem;
+  LPair: TPair<TKey, TValue>;
+begin
+  LItem := @FItems[AIndex];
+  LItem.Hash := 0;
+  Result := LItem.Pair.Value;
+  LPair := LItem.Pair;
+  LItem.Pair := Default(TPair<TKey, TValue>);
+  Dec(FItemsLength);
+  PairNotify(LPair, ACollectionNotification);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Remove(constref AKey: TKey);
+var
+  LIndex: SizeInt;
+begin
+  LIndex := FindBucketIndex(AKey);
+  if LIndex  < 0 then
+    Exit;
+
+  DoRemove(LIndex, cnRemoved);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ExtractPair(constref AKey: TKey): TPair<TKey, TValue>;
+var
+  LIndex: SizeInt;
+begin
+  LIndex := FindBucketIndex(AKey);
+  if LIndex  < 0 then
+    Exit(Default(TPair<TKey, TValue>));
+
+  Result.Key := AKey;
+  Result.Value := DoRemove(LIndex, cnExtracted);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Clear;
+var
+  LItem: PItem;
+  i: SizeInt;
+  LOldItems: array of TItem;
+begin
+  FItemsLength := 0;
+  FItemsThreshold := 0;
+  // ClearTombstones;
+  LOldItems := FItems;
+  FItems := nil;
+
+  for i := 0 to High(LOldItems) do
+  begin
+    LItem := @LOldItems[i];
+    if (LItem.Hash and UInt32.GetSignMask = 0) then
+      Continue;
+
+    PairNotify(LItem.Pair, cnRemoved);
+  end;
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.RealItemsLength: SizeInt;
+begin
+  Result := FItemsLength;
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Rehash(ASizePow2: SizeInt; AForce: Boolean): Boolean;
+var
+  LNewItems: TArray<TItem>;
+  LHash: UInt32;
+  LIndex: SizeInt;
+  i: SizeInt;
+  LItem, LNewItem: PItem;
+begin
+  if (ASizePow2 = Length(FItems)) and not AForce then
+    Exit(False);
+  if ASizePow2 < 0 then
+    OutOfMemoryError;
+
+  SetLength(LNewItems, ASizePow2);
+  UpdateItemsThreshold(ASizePow2);
+
+  for i := 0 to High(FItems) do
+  begin
+    LItem := @FItems[i];
+
+    if (LItem.Hash and UInt32.GetSignMask) <> 0 then
+    begin
+      LIndex := FindBucketIndex(LNewItems, LItem.Pair.Key, LHash);
+      LIndex := not LIndex;
+
+      LNewItem := @LNewItems[LIndex];
+      LNewItem.Hash := LHash;
+      LNewItem.Pair := LItem.Pair;
+    end;
+  end;
+
+  FItems := LNewItems;
+  Result := True;
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.DoGetEnumerator: TEnumerator<TDictionaryPair>;
+begin
+  Result := GetEnumerator;
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.SetCapacity(ACapacity: SizeInt);
+begin
+  if ACapacity < FItemsLength then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  Resize(ACapacity);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.SetMaxLoadFactor(AValue: single);
+var
+  LItemsLength: SizeInt;
+begin
+  if (AValue > TProbeSequence.MAX_LOAD_FACTOR) or (AValue <= 0) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  FMaxLoadFactor := AValue;
+
+  repeat
+    LItemsLength := Length(FItems);
+    UpdateItemsThreshold(LItemsLength);
+    if RealItemsLength > FItemsThreshold then
+      Rehash(LItemsLength shl 1);
+  until RealItemsLength <= FItemsThreshold;
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetLoadFactor: single;
+begin
+  Result := FItemsLength / Length(FItems);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetCapacity: SizeInt;
+begin
+  Result := Length(FItems);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Resize(ANewSize: SizeInt);
+var
+  LNewSize: SizeInt;
+begin
+  if ANewSize < 0 then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  LNewSize := 0;
+  if ANewSize > 0 then
+  begin
+    LNewSize := 8;
+    while LNewSize < ANewSize do
+      LNewSize := LNewSize shl 1;
+  end;
+
+  Rehash(LNewSize);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetEnumerator: TPairEnumerator;
+begin
+  Result := TPairEnumerator.Create(Self);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetItem(const AKey: TKey): TValue;
+var
+  LIndex: SizeInt;
+begin
+  LIndex := FindBucketIndex(AKey);
+  if LIndex < 0 then
+    raise EListError.CreateRes(@SDictionaryKeyDoesNotExist);
+  Result := FItems[LIndex].Pair.Value;
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TrimExcess;
+begin
+  SetCapacity(Succ(FItemsLength));
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.SetItem(const AKey: TKey; const AValue: TValue);
+var
+  LIndex: SizeInt;
+begin
+  LIndex := FindBucketIndex(AKey);
+  if LIndex < 0 then
+    raise EListError.CreateRes(@SItemNotFound);
+
+  SetValue(FItems[LIndex].Pair.Value, AValue);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean;
+var
+  LIndex: SizeInt;
+begin
+  LIndex := FindBucketIndex(AKey);
+  Result := LIndex >= 0;
+
+  if Result then
+    AValue := FItems[LIndex].Pair.Value
+  else
+    AValue := Default(TValue);
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.AddOrSetValue(constref AKey: TKey; constref AValue: TValue);
+var
+  LIndex: SizeInt;
+  LHash: UInt32;
+begin
+  LIndex := FindBucketIndex(FItems, AKey, LHash);
+
+  if LIndex < 0 then
+    DoAdd(AKey, AValue)
+  else
+    SetValue(FItems[LIndex].Pair.Value, AValue);
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ContainsKey(constref AKey: TKey): Boolean;
+var
+  LIndex: SizeInt;
+begin
+  LIndex := FindBucketIndex(AKey);
+  Result := LIndex >= 0;
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ContainsValue(constref AValue: TValue): Boolean;
+begin
+  Result := ContainsValue(AValue, TEqualityComparer<TValue>.Default(THashFactory));
+end;
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ContainsValue(constref AValue: TValue;
+  const AEqualityComparer: IEqualityComparer<TValue>): Boolean;
+var
+  i: SizeInt;
+  LItem: PItem;
+begin
+  if Length(FItems) = 0 then
+    Exit(False);
+
+  for i := 0 to High(FItems) do
+  begin
+    LItem := @FItems[i];
+    if (LItem.Hash and UInt32.GetSignMask) = 0 then
+      Continue;
+
+    if AEqualityComparer.Equals(AValue, LItem.Pair.Value) then
+      Exit(True);
+  end;
+  Result := False;
+end;
+
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetMemoryLayout(
+  const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition);
+var
+  i: SizeInt;
+begin
+  for i := 0 to High(FItems) do
+    if (FItems[i].Hash and UInt32.GetSignMask) <> 0 then
+      AOnGetMemoryLayoutKeyPosition(Self, i);
+end;
+
+{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPairEnumerator }
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPairEnumerator.GetCurrent: TPair<TKey, TValue>;
+begin
+  Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair;
+end;
+
+{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TValueEnumerator }
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TValueEnumerator.GetCurrent: TValue;
+begin
+  Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Value;
+end;
+
+{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TKeyEnumerator }
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TKeyEnumerator.GetCurrent: TKey;
+begin
+  Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Key;
+end;
+
+{ TOpenAddressingLP<DICTIONARY_CONSTRAINTS> }
+
+procedure TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.NotifyIndexChange(AFrom, ATo: SizeInt);
+begin
+end;
+
+function TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.DoRemove(AIndex: SizeInt;
+  ACollectionNotification: TCollectionNotification): TValue;
+var
+  LItem: PItem;
+  LPair: TPair<TKey, TValue>;
+  LLengthMask: SizeInt;
+  i, m, LIndex, LGapIndex: SizeInt;
+  LHash, LBucket: UInt32;
+begin
+  LItem := @FItems[AIndex];
+  LPair := LItem.Pair;
+
+  // try fill gap
+  LHash := LItem.Hash;
+  LItem.Hash := 0; // prevents an infinite searching loop
+  m := Length(FItems);
+  LLengthMask := m - 1;
+  i := Succ(AIndex - (LHash and LLengthMask));
+  LGapIndex := AIndex;
+  repeat
+    LIndex := TProbeSequence.Probe(i, m, LHash) and LLengthMask;
+    LItem := @FItems[LIndex];
+
+    // Empty position
+    if (LItem.Hash and UInt32.GetSignMask) = 0 then
+      Break; // breaking bad!
+
+    LBucket := LItem.Hash and LLengthMask;
+    if not InCircularRange(LGapIndex, LBucket, LIndex) then
+    begin
+      NotifyIndexChange(LIndex, LGapIndex);
+      FItems[LGapIndex] := LItem^;
+      LItem.Hash := 0; // new gap
+      LGapIndex := LIndex;
+    end;
+    Inc(i);
+  until false;
+
+  LItem := @FItems[LGapIndex];
+  LItem.Hash := 0;
+  LItem.Pair := Default(TPair<TKey, TValue>);
+  Dec(FItemsLength);
+
+  Result := LPair.Value;
+  PairNotify(LPair, ACollectionNotification);
+end;
+
+function TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AItems: TArray<TItem>;
+  constref AKey: TKey; out AHash: UInt32): SizeInt;
+var
+  LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613
+  LLengthMask: SizeInt;
+  i, m: SizeInt;
+  LHash: UInt32;
+begin
+  m := Length(AItems);
+  LLengthMask := m - 1;
+
+  LHash := FEqualityComparer.GetHashCode(AKey);
+
+  i := 0;
+  AHash := LHash or UInt32.GetSignMask;
+
+  if m = 0 then
+    Exit(-1);
+
+  Result := AHash and LLengthMask;
+
+  repeat
+    LItem := _TItem(AItems[Result]);
+
+    // Empty position
+    if (LItem.Hash and UInt32.GetSignMask) = 0 then
+      Exit(not Result); // insert!
+
+    // Same position?
+    if LItem.Hash = AHash then
+      if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then
+        Exit;
+
+    Inc(i);
+
+    Result := TProbeSequence.Probe(i, m, AHash) and LLengthMask;
+
+  until false;
+end;
+
+{ TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS> }
+
+function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.Rehash(ASizePow2: SizeInt; AForce: Boolean): Boolean;
+begin
+  if inherited then
+    FTombstonesCount := 0;
+end;
+
+function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.RealItemsLength: SizeInt;
+begin
+  Result := FItemsLength + FTombstonesCount
+end;
+
+procedure TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.ClearTombstones;
+begin
+  Rehash(Length(FItems), True);
+end;
+
+procedure TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.Clear;
+begin
+  FTombstonesCount := 0;
+  inherited;
+end;
+
+function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.DoRemove(AIndex: SizeInt;
+  ACollectionNotification: TCollectionNotification): TValue;
+begin
+  Result := inherited;
+
+  FItems[AIndex].Hash := 1;
+  Inc(FTombstonesCount);
+end;
+
+function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.DoAdd(constref AKey: TKey;
+  constref AValue: TValue): SizeInt;
+var
+  LHash: UInt32;
+begin
+  PrepareAddingItem;
+
+  Result := FindBucketIndexOrTombstone(FItems, AKey, LHash);
+  if Result >= 0 then
+    raise EListError.CreateRes(@SDuplicatesNotAllowed);
+
+  Result := not Result;
+  // Can't ovverride because we lost info about old hash
+  if FItems[Result].Hash <> 0 then
+    Dec(FTombstonesCount);
+
+  AddItem(FItems[Result], AKey, AValue, LHash);
+end;
+
+{ TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS> }
+
+function TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AItems: TArray<TItem>;
+  constref AKey: TKey; out AHash: UInt32): SizeInt;
+var
+  LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613
+  LLengthMask: SizeInt;
+  i, m: SizeInt;
+  LHash: UInt32;
+begin
+  m := Length(AItems);
+  LLengthMask := m - 1;
+
+  LHash := FEqualityComparer.GetHashCode(AKey);
+
+  i := 0;
+  AHash := LHash or UInt32.GetSignMask;
+
+  if m = 0 then
+    Exit(-1);
+
+  Result := AHash and LLengthMask;
+
+  repeat
+    LItem := _TItem(AItems[Result]);
+    // Empty position
+    if LItem.Hash = 0 then
+      Exit(not Result); // insert!
+
+    // Same position?
+    if LItem.Hash = AHash then
+      if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then
+        Exit;
+
+    Inc(i);
+
+    Result := TProbeSequence.Probe(i, m, AHash) and LLengthMask;
+
+  until false;
+end;
+
+function TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndexOrTombstone(constref AItems: TArray<TItem>;
+  constref AKey: TKey; out AHash: UInt32): SizeInt;
+var
+  LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613
+  LLengthMask: SizeInt;
+  i, m: SizeInt;
+  LHash: UInt32;
+begin
+  m := Length(AItems);
+  LLengthMask := m - 1;
+
+  LHash := FEqualityComparer.GetHashCode(AKey);
+
+  i := 0;
+  AHash := LHash or UInt32.GetSignMask;
+
+  if m = 0 then
+    Exit(-1);
+
+  Result := AHash and LLengthMask;
+
+  repeat
+    LItem := _TItem(AItems[Result]);
+
+    // Empty position or tombstone
+    if LItem.Hash and UInt32.GetSignMask = 0 then
+      Exit(not Result); // insert!
+
+    // Same position?
+    if LItem.Hash = AHash then
+      if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then
+        Exit;
+
+    Inc(i);
+
+    Result := TProbeSequence.Probe(i, m, AHash) and LLengthMask;
+
+  until false;
+end;
+
+{ TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS> }
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+end;
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(const AComparer: IEqualityComparer<TKey>);
+begin
+end;
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+end;
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt);
+begin
+  Create(ACapacity, TExtendedEqualityComparer<TKey>.Default(THashFactory));
+end;
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>);
+begin
+  Create(ACollection, TExtendedEqualityComparer<TKey>.Default(THashFactory));
+end;
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt;
+  const AComparer: IExtendedEqualityComparer<TKey>);
+begin
+  FMaxLoadFactor := TProbeSequence.DEFAULT_LOAD_FACTOR;
+  FEqualityComparer := AComparer;
+  SetCapacity(ACapacity);
+end;
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(const AComparer: IExtendedEqualityComparer<TKey>);
+begin
+  Create(0, AComparer);
+end;
+
+constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>;
+  const AComparer: IExtendedEqualityComparer<TKey>);
+var
+  LItem: TPair<TKey, TValue>;
+begin
+  Create(AComparer);
+  for LItem in ACollection do
+    Add(LItem);
+end;
+
+procedure TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt);
+begin
+  inherited;
+  R :=
+    PrimaryNumbersJustLessThanPowerOfTwo[
+      MultiplyDeBruijnBitPosition[UInt32(((ASize and -ASize) * $077CB531)) shr 27]]
+end;
+
+function TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AItems: TArray<TItem>;
+  constref AKey: TKey; out AHash: UInt32): SizeInt;
+var
+  LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613
+  LLengthMask: SizeInt;
+  i, m: SizeInt;
+  LHash: array[-1..1] of UInt32;
+  LHash1: UInt32 absolute LHash[0];
+  LHash2: UInt32 absolute LHash[1];
+begin
+  m := Length(AItems);
+  LLengthMask := m - 1;
+  LHash[-1] := 2; // number of hashes
+
+  IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(AKey, @LHash[-1]);
+
+  i := 0;
+  AHash := LHash1 or UInt32.GetSignMask;
+
+  if m = 0 then
+    Exit(-1);
+
+  Result := LHash1 and LLengthMask;
+  // second hash function must be special
+  LHash2 := (R - (LHash2 mod R)) or 1;
+
+  repeat
+    LItem := _TItem(AItems[Result]);
+
+    // Empty position
+    if LItem.Hash = 0 then
+      Exit(not Result);
+
+    // Same position?
+    if LItem.Hash = AHash then
+      if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then
+        Exit;
+
+    Inc(i);
+
+    Result := TProbeSequence.Probe(i, m, AHash, LHash2) and LLengthMask;
+  until false;
+end;
+
+function TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndexOrTombstone(constref AItems: TArray<TItem>;
+  constref AKey: TKey; out AHash: UInt32): SizeInt;
+var
+  LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613
+  LLengthMask: SizeInt;
+  i, m: SizeInt;
+  LHash: array[-1..1] of UInt32;
+  LHash1: UInt32 absolute LHash[0];
+  LHash2: UInt32 absolute LHash[1];
+begin
+  m := Length(AItems);
+  LLengthMask := m - 1;
+  LHash[-1] := 2; // number of hashes
+
+  IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(AKey, @LHash[-1]);
+
+  i := 0;
+  AHash := LHash1 or UInt32.GetSignMask;
+
+  if m = 0 then
+    Exit(-1);
+
+  Result := LHash1 and LLengthMask;
+  // second hash function must be special
+  LHash2 := (R - (LHash2 mod R)) or 1;
+
+  repeat
+    LItem := _TItem(AItems[Result]);
+
+    // Empty position or tombstone
+    if LItem.Hash and UInt32.GetSignMask = 0 then
+      Exit(not Result);
+
+    // Same position?
+    if LItem.Hash = AHash then
+      if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then
+        Exit;
+
+    Inc(i);
+
+    Result := TProbeSequence.Probe(i, m, AHash, LHash2) and LLengthMask;
+  until false;
+end;
+
+{ TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS> }
+
+constructor TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS>.Create(
+  ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
+begin
+  inherited;
+  if ADictionary.Count = 0 then
+    FMainIndex := TCuckooCfg.D
+  else
+    FMainIndex := 0;
+end;
+
+function TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS>.DoMoveNext: Boolean;
+var
+  LLength: SizeInt;
+  LArray: TItemsArray;
+begin
+  Inc(FIndex);
+
+  if (FMainIndex = TCuckooCfg.D) then // queue
+  begin
+    LLength := Length(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems);
+    if FIndex >= LLength then
+      Exit(False);
+
+    while ((TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Hash)
+      and UInt32.GetSignMask) = 0 do
+    begin
+      Inc(FIndex);
+      if FIndex = LLength then
+        Exit(False);
+    end;
+  end
+  else // d-array
+  begin
+    LArray := TItemsArray(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex]);
+    LLength := Length(LArray);
+    if FIndex >= LLength then
+    begin
+      Inc(FMainIndex);
+      FIndex := -1;
+      Exit(DoMoveNext);
+    end;
+
+    while ((LArray[FIndex].Hash) and UInt32.GetSignMask) = 0 do
+    begin
+      Inc(FIndex);
+      if FIndex = LLength then
+      begin
+        Inc(FMainIndex);
+        FIndex := -1;
+        Exit(DoMoveNext);
+      end;
+    end;
+  end;
+
+  Result := True;
+end;
+
+{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS> }
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Rehash(ASizePow2: SizeInt;
+  AForce: boolean): Boolean;
+var
+  FOldIdx: array of TKey;
+  i: SizeInt;
+begin
+  SetLength(FOldIdx, FIdx.Count);
+  for i := 0 to FIdx.Count - 1 do
+    FOldIdx[i] := FItems[FIdx[i]].Pair.Key;
+
+  Result := inherited Rehash(ASizePow2, AForce);
+
+  for i := 0 to FIdx.Count - 1 do
+    FIdx[i] := FindBucketIndex(FOldIdx[i]);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.NotifyIndexChange(AFrom, ATo: SizeInt);
+var
+  i: SizeInt;
+begin
+  // notify change position
+  for i := 0 to FIdx.Count-1 do
+    if FIdx[i] = AFrom then
+    begin
+      FIdx[i] := ATo;
+      Exit;
+    end;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.InsertIntoBack(AItem: Pointer);
+//var
+//  LItem: TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PItem; absolute AItem; !!! bug #25917
+var
+  LItem: TQueueDictionary.PValue absolute AItem;
+  LIndex: SizeInt;
+begin
+  LIndex := DoAdd(LItem.Pair.Key, LItem^);
+  FIdx.Insert(0, LIndex);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.InsertIntoHead(AItem: Pointer);
+//var
+//  LItem: TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PItem absolute AItem; !!! bug #25917
+var
+  LItem: TQueueDictionary.PValue absolute AItem;
+  LIndex: SizeInt;
+begin
+  LIndex := DoAdd(LItem.Pair.Key, LItem^);
+  FIdx.Add(LIndex);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.IsEmpty: Boolean;
+begin
+  Result := FIdx.Count = 0;
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Pop: Pointer;
+var
+  AIndex, LGap: SizeInt;
+  //LResult: TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TItem; !!!bug #25917
+begin
+  AIndex := FIdx.DoRemove(FIdx.Count - 1, cnExtracted);
+
+  Result := New(TQueueDictionary.PValue);
+  TQueueDictionary.PValue(Result)^ := DoRemove(AIndex, cnExtracted);
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Create(ACapacity: SizeInt;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+  FIdx := TList<UInt32>.Create;
+  inherited Create(ACapacity, AComparer);
+end;
+
+destructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Destroy;
+begin
+  FIdx.Free;
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetQueueCount: SizeInt;
+begin
+  Result := FQueue.Count;
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACapacity: SizeInt;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(const AComparer: IEqualityComparer<TKey>);
+begin
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create;
+begin
+  Create(0);
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACapacity: SizeInt);
+begin
+  Create(ACapacity, TExtendedEqualityComparer<TKey>.Default(THashFactory));
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>);
+begin
+  Create(ACollection, TExtendedEqualityComparer<TKey>.Default(THashFactory));
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACapacity: SizeInt;
+  const AComparer: IExtendedEqualityComparer<TKey>);
+begin
+  FMaxLoadFactor := TCuckooCfg.MAX_LOAD_FACTOR;
+  FQueue := TQueueDictionary.Create;
+  FCDM   := TCDM.Create;
+
+  // to do - check constraint consts
+
+  if TCuckooCfg.D > THashFactory.MAX_HASHLIST_COUNT then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  // should be moved to class constructor, but bug #24848
+  CUCKOO_SIGN := UInt32.GetSizedSignMask(THashFactory.HASH_FUNCTIONS_MASK_SIZE + 1);
+  CUCKOO_INDEX_SIZE := UInt32.GetBitsLength - (THashFactory.HASH_FUNCTIONS_MASK_SIZE + 1);
+  CUCKOO_HASH_SIGN := THashFactory.HASH_FUNCTIONS_MASK shl CUCKOO_INDEX_SIZE;
+
+  FEqualityComparer := AComparer;
+  SetCapacity(ACapacity);
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(const AComparer: IExtendedEqualityComparer<TKey>);
+begin
+  Create(0, AComparer);
+end;
+
+constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>;
+  const AComparer: IExtendedEqualityComparer<TKey>);
+var
+  LItem: TPair<TKey, TValue>;
+begin
+  Create(AComparer);
+  for LItem in ACollection do
+    Add(LItem);
+end;
+
+destructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Destroy;
+begin
+  inherited;
+  FQueue.Free;
+  FCDM.Free;
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetKeys: TKeyCollection;
+begin
+  if not Assigned(FKeys) then
+    FKeys := TKeyCollection.Create(Self);
+  Result := TKeyCollection(FKeys);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetValues: TValueCollection;
+begin
+  if not Assigned(FValues) then
+    FValues := TValueCollection.Create(Self);
+  Result := TValueCollection(FValues);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Lookup(constref AKey: TKey;
+  var AHashListOrIndex: PUInt32): SizeInt;
+begin
+  Result := Lookup(FItems, AKey, AHashListOrIndex);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Lookup(constref AItems: TItemsDArray; constref AKey: TKey;
+  var AHashListOrIndex: PUInt32): SizeInt;
+var
+  LLengthMask: SizeInt;
+  i, j, k: SizeInt;
+  AHashList: PUInt32 absolute AHashListOrIndex;
+  AHashListParams: PUInt16 absolute AHashListOrIndex;
+  AIndex: PtrInt absolute AHashListOrIndex;
+  // LBloomFilter: UInt32; // to rethink. now is useless
+begin
+  if Length(AItems[0]) = 0 then
+    Exit(LR_NIL);
+
+  LLengthMask := Length(AItems[0]) - 1;
+  AHashListParams[0] := TCuckooCfg.D; // number of hashes
+
+  i := 1; // ineks iteracji iteracji haszy
+  k := 1; // indeks iteracji haszy
+  // LBloomFilter := 0;
+  repeat
+    AHashListParams[1] := i; // iteration
+    IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(AKey, AHashList);
+    for j := 0 to THashFactory.HASHLIST_COUNT_PER_FUNCTION[i] - 1 do
+    begin
+      AHashList[k] := AHashList[k] or CUCKOO_SIGN;
+      // LBloomFilter := LBloomFilter or AHashList[k];
+
+      with AItems[k-1][AHashList[k] and LLengthMask] do
+        if (Hash and UInt32.GetSignMask) <> 0 then
+          if (AHashList[k] = Hash or CUCKOO_SIGN) and FEqualityComparer.Equals(AKey, Pair.Key) then
+            Exit(k-1);
+
+      Inc(k);
+    end;
+    Inc(i);
+  until k > TCuckooCfg.D;
+
+  i := FQueue.FindBucketIndex(AKey);
+  if i >= 0 then
+  begin
+    AIndex := i;
+    Exit(LR_QUEUE);
+  end;
+
+{  LBloomFilter := not LBloomFilter;
+  for i := 0 to FDicQueueList.Count - 1 do
+    // with FQueue[i] do
+    if LBloomFilter and FQueue[i].Hash = 0 then
+      for j := 1 to TCuckooCfg.D do
+        if (FQueue[i].Hash or CUCKOO_SIGN = AHashList[j]) then
+          if FEqualityComparer.Equals(AKey, FQueue[i].Pair.Key) then
+          begin
+            AIndex := i;
+            Exit(LR_QUEUE);
+          end;     }
+
+  Result := LR_NIL;
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PrepareAddingItem: SizeInt;
+var
+  i: SizeInt;
+begin
+  if FItemsLength > FItemsThreshold then
+    Rehash(Length(FItems[0]) shl 1)
+  else if FItemsThreshold = 0 then
+  begin
+    for i := 0 to TCuckooCfg.D - 1 do
+      SetLength(FItems[i], 4);
+    UpdateItemsThreshold(4);
+  end
+  else if FItemsLength = $40000001 then // High(TIndex) ... Error: Type mismatch
+    OutOfMemoryError;
+
+  Result := FItemsLength;
+  Inc(FItemsLength);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt);
+var
+  LLength: SizeInt;
+begin
+  LLength := ASize*TCuckooCfg.D;
+  if LLength = $40000000 then
+    FItemsThreshold := $40000001
+  else
+    FItemsThreshold := Pred(Round(LLength * FMaxLoadFactor));
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.AddItem(constref AItems: TItemsDArray; constref AKey: TKey;
+  constref AValue: TValue; const AHashList: PUInt32);
+var
+  LNewItem: TItem;
+  LPNewItem: PItem;
+  y: boolean = false;
+  b: UInt32;
+  LIndex: UInt32;
+  i, j, LLengthMask: SizeInt;
+  LTempItem: TItem;
+  LHashList: array[0..1] of UInt32;
+  LHashListParams: array[0..3] of UInt16 absolute LHashList;
+begin
+  LLengthMask := Length(AItems[0]) - 1;
+
+  LNewItem.Pair.Key := AKey;
+  LNewItem.Pair.Value := AValue;
+  // by concept already sign bit is set
+  LNewItem.Hash := ((not CUCKOO_HASH_SIGN) and AHashList[1]) or UInt32.GetSignMask; // start at array [0]
+  FQueue.InsertIntoBack(@LNewItem);
+
+  for i := 0 to TCuckooCfg.L - 1 do
+  begin
+    if not y then
+      if FQueue.IsEmpty then
+        Exit
+      else
+      begin
+        LPNewItem := FQueue.Pop; // bug #25917 workaround
+        LNewItem := LPNewItem^;
+        Dispose(LPNewItem);
+        b := (LNewItem.Hash and CUCKOO_HASH_SIGN) shr CUCKOO_INDEX_SIZE;
+        y := true;
+      end;
+    LIndex := LNewItem.Hash and LLengthMask;
+    if (AItems[b][LIndex].Hash and UInt32.GetSignMask) = 0 then // insert!
+    begin
+      AItems[b][LIndex] := LNewItem;
+      FCDM.Clear;
+      y := false;
+    end
+    else
+    begin
+      if FCDM.ContainsKey(LNewItem.Pair.Key) then // found second cycle
+      begin
+        FQueue.InsertIntoBack(@LNewItem);
+        FCDM.Clear;
+        y := false;
+      end
+      else
+      begin
+        LTempItem := AItems[b][LIndex];
+        AItems[b][LIndex] := LNewItem;
+        LNewItem.Hash := LNewItem.Hash or CUCKOO_SIGN;
+        FCDM.AddOrSetValue(LNewItem.Pair.Key, EmptyRecord);
+
+        LNewItem := LTempItem;
+        b := b + 1;
+        if b >= TCuckooCfg.D then
+          b := 0;
+        LHashListParams[0] := -Succ(b);
+        IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(LNewItem.Pair.Key, @LHashList[0]);
+        LNewItem.Hash := (LHashList[1] and not CUCKOO_SIGN) or (b shl CUCKOO_INDEX_SIZE) or UInt32.GetSignMask;
+        //  y := True; // always true in this place
+      end;
+    end;
+  end;
+  if y then
+    FQueue.InsertIntoHead(@LNewItem);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoAdd(constref AKey: TKey; constref AValue: TValue;
+  const AHashList: PUInt32);
+begin
+  AddItem(FItems, AKey, AValue, AHashList);
+  KeyNotify(AKey, cnAdded);
+  ValueNotify(AValue, cnAdded);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Add(constref AKey: TKey; constref AValue: TValue);
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+begin
+  PrepareAddingItem;
+  LHashListOrIndex := @LHashList[0];
+  if Lookup(AKey, LHashListOrIndex) <> LR_NIL then
+    raise EListError.CreateRes(@SDuplicatesNotAllowed);
+
+  DoAdd(AKey, AValue, LHashListOrIndex);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Add(constref APair: TPair<TKey, TValue>);
+begin
+  Add(APair.Key, APair.Value);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoRemove(const AHashListOrIndex: PUInt32;
+  ALookupResult: SizeInt; ACollectionNotification: TCollectionNotification): TValue;
+var
+  LItem: PItem;
+  LIndex: UInt32;
+  LQueueIndex: SizeInt absolute AHashListOrIndex;
+  LPair: TPair<TKey, TValue>;
+begin
+  case ALookupResult of
+    LR_QUEUE:
+      LPair := FQueue.FItems[LQueueIndex].Pair.Value.Pair;
+    LR_NIL:
+      raise ERangeError.Create(SItemNotFound);
+  else
+    LIndex := AHashListOrIndex[ALookupResult + 1] and (Length(FItems[0]) - 1);
+    LItem := @FItems[ALookupResult][LIndex];
+    LItem.Hash := 0;
+    LPair := LItem.Pair;
+    LItem.Pair := Default(TPair<TKey, TValue>);
+  end;
+
+  Result := LPair.Value;
+  Dec(FItemsLength);
+  if ALookupResult = LR_QUEUE then
+  begin
+    FQueue.FIdx.Remove(LQueueIndex);
+    FQueue.DoRemove(LQueueIndex, cnRemoved);
+  end;
+
+  FCDM.Remove(LPair.Key); // item can exist in CDM
+
+  PairNotify(LPair, ACollectionNotification);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Remove(constref AKey: TKey);
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+  LLookupResult: SizeInt;
+begin
+  LHashListOrIndex := @LHashList[0];
+  LLookupResult := Lookup(AKey, LHashListOrIndex);
+  if LLookupResult = LR_NIL then
+    Exit;
+
+  DoRemove(LHashListOrIndex, LLookupResult, cnRemoved);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ExtractPair(constref AKey: TKey): TPair<TKey, TValue>;
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+  LLookupResult: SizeInt;
+begin
+  LHashListOrIndex := @LHashList[0];
+  LLookupResult := Lookup(AKey, LHashListOrIndex);
+  if LLookupResult = LR_NIL then
+    Exit(Default(TPair<TKey, TValue>));
+
+  Result.Key := AKey;
+  Result.Value := DoRemove(LHashListOrIndex, LLookupResult, cnExtracted);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Clear;
+var
+  LItem: PItem;
+  i, j: SizeInt;
+  LOldItems: TItemsDArray;
+  LOldQueueItems: TQueueDictionary.TItemsArray;
+  LQueueItem: TQueueDictionary._TItem;
+begin
+  FItemsLength := 0;
+  FItemsThreshold := 0;
+  LOldItems := FItems;
+  for i := 0 to TCuckooCfg.D - 1 do
+    FItems[i] := nil;
+
+  for i := 0 to TCuckooCfg.D - 1 do
+  begin
+    for j := 0 to High(LOldItems[0]) do
+    begin
+      LItem := @LOldItems[i][j];
+      if (LItem.Hash and UInt32.GetSignMask <> 0) then
+        PairNotify(LItem.Pair, cnRemoved);
+    end;
+  end;
+
+  FCDM.Clear;
+
+  // queue
+  FQueue.FItemsLength := 0;
+  FQueue.FItemsThreshold := 0;
+  LOldQueueItems := FQueue.FItems;
+  FQueue.FItems := nil;
+
+  for i := 0 to High(LOldQueueItems) do
+  begin
+    LQueueItem := TQueueDictionary._TItem(LOldQueueItems[i]);
+    if (LQueueItem.Hash and UInt32.GetSignMask = 0) then
+      Continue;
+
+    PairNotify(LQueueItem.Pair.Value.Pair, cnRemoved);
+  end;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Rehash(ASizePow2: SizeInt);
+var
+  LNewItems: TItemsDArray;
+  LHash: UInt32;
+  LIndex: SizeInt;
+  i, j: SizeInt;
+  LItem, LNewItem: PItem;
+  LOldQueue: TQueueDictionary;
+var
+  LHashList: array[0..1] of UInt32;
+  LHashListParams: array[0..3] of Int16 absolute LHashList;
+begin
+  if ASizePow2 = Length(FItems[0]) then
+    Exit;
+  if ASizePow2 < 0 then
+    OutOfMemoryError;
+
+  for i := 0 to TCuckooCfg.D - 1 do
+    SetLength(LNewItems[i], ASizePow2);
+
+  LHashListParams[0] := -1;
+
+  // opportunity to clear the queue
+  LOldQueue := FQueue;
+  FCDM.Clear;
+  FQueue := TQueueDictionary.Create;
+  for i := 0 to LOldQueue.FIdx.Count - 1 do
+  begin
+   LItem := @LOldQueue.FItems[LOldQueue.FIdx[i]].Pair.Value;
+   LHashList[1] := FEqualityComparer.GetHashCode(LItem.Pair.Key);
+   AddItem(LNewItems, LItem.Pair.Key, LItem.Pair.Value, @LHashList[0]);
+  end;
+  LOldQueue.Free;
+
+  // copy the old elements
+  for i := 0 to TCuckooCfg.D - 1 do
+    for j := 0 to High(FItems[0]) do
+    begin
+      LItem := @FItems[i][j];
+      if (LItem.Hash and UInt32.GetSignMask) = 0 then
+        Continue;
+
+      // small optimization. most of items exist in table 0
+      if LItem.Hash and CUCKOO_HASH_SIGN = 0 then
+      begin
+        LHashList[1] := LItem.Hash;
+        AddItem(LNewItems, LItem.Pair.Key, LItem.Pair.Value, @LHashList[0]);
+      end
+      else
+      begin
+        LHashList[1] := FEqualityComparer.GetHashCode(LItem.Pair.Key);
+        AddItem(LNewItems, LItem.Pair.Key, LItem.Pair.Value, @LHashList[0]);
+      end;
+    end;
+
+  FItems := LNewItems;
+  UpdateItemsThreshold(ASizePow2);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoGetEnumerator: TEnumerator<TDictionaryPair>;
+begin
+  Result := GetEnumerator;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetCapacity(ACapacity: SizeInt);
+begin
+  if ACapacity < FItemsLength then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  Resize(ACapacity);
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetMaxLoadFactor(AValue: single);
+var
+  LItemsLength: SizeInt;
+begin
+  if (AValue > TCuckooCfg.MAX_LOAD_FACTOR) or (AValue <= 0) then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  FMaxLoadFactor := AValue;
+
+  repeat
+    LItemsLength := Length(FItems[0]);
+    UpdateItemsThreshold(LItemsLength);
+    if FItemsLength > FItemsThreshold then
+      Rehash(LItemsLength shl 1);
+  until FItemsLength <= FItemsThreshold;
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetLoadFactor: single;
+begin
+  Result := FItemsLength / (Length(FItems[0]) * TCuckooCfg.D);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetCapacity: SizeInt;
+begin
+  Result := Length(FItems[0]) * TCuckooCfg.D;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Resize(ANewSize: SizeInt);
+var
+  LNewSize: SizeInt;
+begin
+  if ANewSize < 0 then
+    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
+
+  LNewSize := 0;
+  if ANewSize > 0 then
+  begin
+    LNewSize := 4;
+    while LNewSize * TCuckooCfg.D < ANewSize do
+      LNewSize := LNewSize shl 1;
+  end;
+
+  Rehash(LNewSize);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetEnumerator: TPairEnumerator;
+begin
+  Result := TPairEnumerator.Create(Self);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetItem(const AKey: TKey): TValue;
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+  LLookupResult: SizeInt;
+  LIndex: UInt32;
+begin
+  LHashListOrIndex := @LHashList[0];
+  LLookupResult := Lookup(AKey, LHashListOrIndex);
+
+  case LLookupResult of
+    LR_QUEUE:
+      Result := FQueue.FItems[PtrInt(LHashListOrIndex)].Pair.Value.Pair.Value;
+    LR_NIL:
+      raise EListError.CreateRes(@SDictionaryKeyDoesNotExist);
+  else
+    LIndex := LHashListOrIndex[LLookupResult + 1] and (Length(FItems[0]) - 1);
+    Result := FItems[LLookupResult][LIndex].Pair.Value;
+  end;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TrimExcess;
+begin
+  SetCapacity(Succ(FItemsLength));
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetItem(constref AValue: TValue;
+  const AHashListOrIndex: PUInt32; ALookupResult: SizeInt);
+var
+  LIndex: UInt32;
+begin
+  case ALookupResult of
+    LR_QUEUE:
+      SetValue(FQueue.FItems[PtrInt(AHashListOrIndex)].Pair.Value.Pair.Value, AValue);
+    LR_NIL:
+      raise EListError.CreateRes(@SItemNotFound);
+  else
+    LIndex := AHashListOrIndex[ALookupResult + 1] and (Length(FItems[0]) - 1);
+    SetValue(FItems[ALookupResult][LIndex].Pair.Value, AValue);
+  end;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetItem(const AKey: TKey; const AValue: TValue);
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+  LLookupResult: SizeInt;
+  LIndex: UInt32;
+begin
+  LHashListOrIndex := @LHashList[0];
+  LLookupResult := Lookup(AKey, LHashListOrIndex);
+
+  SetItem(AValue, LHashListOrIndex, LLookupResult);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean;
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+  LLookupResult: SizeInt;
+  LIndex: UInt32;
+begin
+  LHashListOrIndex := @LHashList[0];
+  LLookupResult := Lookup(AKey, LHashListOrIndex);
+
+  Result := LLookupResult <> LR_NIL;
+
+  case LLookupResult of
+    LR_QUEUE:
+      AValue := FQueue.FItems[PtrInt(LHashListOrIndex)].Pair.Value.Pair.Value;
+    LR_NIL:
+      AValue := Default(TValue);
+  else
+    LIndex := LHashListOrIndex[LLookupResult + 1] and (Length(FItems[0]) - 1);
+    AValue := FItems[LLookupResult][LIndex].Pair.Value;
+  end;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.AddOrSetValue(constref AKey: TKey; constref AValue: TValue);
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+  LLookupResult: SizeInt;
+  LIndex: UInt32;
+begin
+  LHashListOrIndex := @LHashList[0];
+  LLookupResult := Lookup(AKey, LHashListOrIndex);
+
+  if LLookupResult = LR_NIL then
+  begin
+    PrepareAddingItem;
+    DoAdd(AKey, AValue, LHashListOrIndex);
+  end
+  else
+    SetItem(AValue, LHashListOrIndex, LLookupResult);
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ContainsKey(constref AKey: TKey): Boolean;
+var
+  LHashList: array[0..TCuckooCfg.D] of UInt32;
+  LHashListOrIndex: PUint32;
+begin
+  LHashListOrIndex := @LHashList[0];
+  Result := Lookup(AKey, LHashListOrIndex) <> LR_NIL;
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ContainsValue(constref AValue: TValue): Boolean;
+begin
+  Result := ContainsValue(AValue, TEqualityComparer<TValue>.Default(THashFactory));
+end;
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ContainsValue(constref AValue: TValue;
+  const AEqualityComparer: IEqualityComparer<TValue>): Boolean;
+var
+  i, j: SizeInt;
+  LItem: PItem;
+begin
+  if Length(FItems[0]) = 0 then
+    Exit(False);
+
+  for i := 0 to TCuckooCfg.D - 1 do
+    for j := 0 to High(FItems[0]) do
+    begin
+      LItem := @FItems[i][j];
+      if (LItem.Hash and UInt32.GetSignMask) = 0 then
+        Continue;
+
+      if AEqualityComparer.Equals(AValue, LItem.Pair.Value) then
+        Exit(True);
+    end;
+  Result := False;
+end;
+
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetMemoryLayout(
+  const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition);
+var
+  i, j, k: SizeInt;
+begin
+  k := 0;
+  for i := 0 to TCuckooCfg.D - 1 do
+    for j := 0 to High(FItems[0]) do
+    begin
+      if FItems[i][j].Hash and UInt32.GetSignMask <> 0 then
+        AOnGetMemoryLayoutKeyPosition(Self, k);
+      inc(k);
+    end;
+end;
+
+{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPairEnumerator }
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPairEnumerator.GetCurrent: TPair<TKey, TValue>;
+begin
+  if FMainIndex = TCuckooCfg.D then
+    Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair
+  else
+    Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair;
+end;
+
+{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TValueEnumerator }
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TValueEnumerator.GetCurrent: TValue;
+begin
+  if FMainIndex = TCuckooCfg.D then
+    Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Value
+  else
+    Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Value;
+end;
+
+{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TKeyEnumerator }
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TKeyEnumerator.GetCurrent: TKey;
+begin
+  if FMainIndex = TCuckooCfg.D then
+    Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Key
+  else
+    Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Key;
+end;
+
+{ TObjectDictionary<DICTIONARY_CONSTRAINTS> }
+
+procedure TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.KeyNotify(
+  constref AKey: TKey; ACollectionNotification: TCollectionNotification);
+begin
+  inherited;
+
+  if (doOwnsKeys in FOwnerships) and (ACollectionNotification = cnRemoved) then
+    TObject(AKey).Free;
+end;
+
+procedure TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ValueNotify(constref AValue: TValue;
+  ACollectionNotification: TCollectionNotification);
+begin
+  inherited;
+
+  if (doOwnsValues in FOwnerships) and (ACollectionNotification = cnRemoved) then
+    TObject(AValue).Free;
+end;
+
+constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(
+  AOwnerships: TDictionaryOwnerships);
+begin
+  Create(AOwnerships, 0);
+end;
+
+constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(
+  AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt);
+begin
+  inherited Create(ACapacity);
+
+  FOwnerships := AOwnerships;
+end;
+
+constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(
+  AOwnerships: TDictionaryOwnerships; const AComparer: IExtendedEqualityComparer<TKey>);
+begin
+  inherited Create(AComparer);
+
+  FOwnerships := AOwnerships;
+end;
+
+constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(
+  AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt; const AComparer: IExtendedEqualityComparer<TKey>);
+begin
+  inherited Create(ACapacity, AComparer);
+
+  FOwnerships := AOwnerships;
+end;
+
+procedure TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.KeyNotify(
+  constref AKey: TKey; ACollectionNotification: TCollectionNotification);
+begin
+  inherited;
+
+  if (doOwnsKeys in FOwnerships) and (ACollectionNotification = cnRemoved) then
+    TObject(AKey).Free;
+end;
+
+procedure TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.ValueNotify(
+  constref AValue: TValue; ACollectionNotification: TCollectionNotification);
+begin
+  inherited;
+
+  if (doOwnsValues in FOwnerships) and (ACollectionNotification = cnRemoved) then
+    TObject(AValue).Free;
+end;
+
+constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships);
+begin
+  Create(AOwnerships, 0);
+end;
+
+constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships;
+  ACapacity: SizeInt);
+begin
+  inherited Create(ACapacity);
+
+  FOwnerships := AOwnerships;
+end;
+
+constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships;
+  const AComparer: IEqualityComparer<TKey>);
+begin
+  inherited Create(AComparer);
+
+  FOwnerships := AOwnerships;
+end;
+
+constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships;
+  ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>);
+begin
+  inherited Create(ACapacity, AComparer);
+
+  FOwnerships := AOwnerships;
+end;

+ 533 - 0
packages/rtl-generics/src/inc/generics.dictionariesh.inc

@@ -0,0 +1,533 @@
+{%MainUnit generics.collections.pas}
+
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2014 by Maciej Izak (hnb)
+    member of the Free Sparta development team (http://freesparta.com)
+
+    Copyright(c) 2004-2014 DaThoX
+
+    It contains the Free Pascal generics library
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{$WARNINGS OFF}
+type
+  TEmptyRecord = record // special record for Dictionary TValue (Dictionary as Set)
+  end;
+
+  { TPair }
+
+  TPair<TKey, TValue> = record
+  public
+    Key: TKey;
+    Value: TValue;
+    class function Create(AKey: TKey; AValue: TValue): TPair<TKey, TValue>; static;
+  end;
+
+  { TCustomDictionary }
+
+  // bug #24283 and #24097 (forward declaration) - should be:
+  // TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS> = class(TEnumerable<TPair<TKey, TValue> >);
+  TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract
+  public type
+    //  workaround... no generics types in generics types
+    TDictionaryPair = TPair<TKey, TValue>;
+    PDictionaryPair = ^TDictionaryPair;
+    PKey = ^TKey;
+    PValue = ^TValue;
+    THashFactoryClass = THashFactory;
+  public
+    FItemsLength: SizeInt;
+    FEqualityComparer: IEqualityComparer<TKey>;
+    FKeys: TEnumerable<TKey>;
+    FValues: TEnumerable<TValue>;
+    FMaxLoadFactor: single;
+  protected
+    procedure SetCapacity(ACapacity: SizeInt); virtual; abstract;
+    // bug #24283. workaround for this class because can't inherit from TEnumerable
+    function DoGetEnumerator: TEnumerator<TDictionaryPair>; virtual; abstract; {override;}
+
+    procedure SetMaxLoadFactor(AValue: single); virtual; abstract;
+    function GetLoadFactor: single; virtual; abstract;
+    function GetCapacity: SizeInt; virtual; abstract;
+  public
+    property MaxLoadFactor: single read FMaxLoadFactor write SetMaxLoadFactor;
+    property LoadFactor: single read GetLoadFactor;
+    property Capacity: SizeInt read GetCapacity write SetCapacity;
+
+    property Count: SizeInt read FItemsLength;
+
+    procedure Clear; virtual; abstract;
+    procedure Add(constref APair: TPair<TKey, TValue>); virtual; abstract;
+  strict private // bug #24283. workaround for this class because can't inherit from TEnumerable
+    function ToArray(ACount: SizeInt): TArray<TDictionaryPair>; overload;
+  public
+    function ToArray: TArray<TDictionaryPair>; virtual; final; {override; final; // bug #24283} overload;
+
+    constructor Create; virtual; overload;
+    constructor Create(ACapacity: SizeInt); virtual; overload;
+    constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); virtual; overload;
+    constructor Create(const AComparer: IEqualityComparer<TKey>); overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>); virtual; overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); virtual; overload;
+
+    destructor Destroy; override;
+  private
+    FOnKeyNotify: TCollectionNotifyEvent<TKey>;
+    FOnValueNotify: TCollectionNotifyEvent<TValue>;
+  protected
+    procedure UpdateItemsThreshold(ASize: SizeInt); virtual; abstract;
+
+    procedure KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); virtual;
+    procedure ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); virtual;
+    procedure PairNotify(constref APair: TPair<TKey, TValue>; ACollectionNotification: TCollectionNotification); inline;
+    procedure SetValue(var AValue: TValue; constref ANewValue: TValue);
+  public
+    property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify;
+    property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify;
+  end;
+
+  { TCustomDictionaryEnumerator }
+
+  TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract(TEnumerator< T >)
+  private
+    FDictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>;
+    FIndex: SizeInt;
+  protected
+    function DoGetCurrent: T; override;
+    function GetCurrent: T; virtual; abstract;
+  public
+    constructor Create(ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
+  end;
+
+  { TDictionaryEnumerable }
+
+  TDictionaryEnumerable<TDictionaryEnumerator: TObject; // ... inherits from TCustomDictionaryEnumerator. workaround...
+    T, CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract(TEnumerable<T>)
+  private
+    FDictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>;
+    function GetCount: SizeInt;
+  public
+    constructor Create(ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
+    function DoGetEnumerator: TDictionaryEnumerator; override;
+    function ToArray: TArray<T>; override; final;
+    property Count: SizeInt read GetCount;
+  end;
+
+  // more info : http://en.wikipedia.org/wiki/Open_addressing
+
+  { TDictionaryEnumerable }
+
+  TOpenAddressingEnumerator<T, OPEN_ADDRESSING_CONSTRAINTS> = class abstract(TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>)
+  protected
+    function DoMoveNext: Boolean; override;
+  end;
+
+  TOnGetMemoryLayoutKeyPosition = procedure(Sender: TObject; AKeyPos: UInt32) of object;
+
+  TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS> = class abstract(TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>)
+  private type
+    PItem = ^TItem;
+    TItem = record
+      Hash: UInt32;
+      Pair: TPair<TKey, TValue>;
+    end;
+
+    TItemsArray = array of TItem;
+  private var
+    FItemsThreshold: SizeInt;
+    FItems: TItemsArray;
+
+    procedure Resize(ANewSize: SizeInt);
+    function PrepareAddingItem: SizeInt;
+  protected
+    function RealItemsLength: SizeInt; virtual;
+    function Rehash(ASizePow2: SizeInt; AForce: Boolean = False): boolean; virtual;
+    function FindBucketIndex(constref AKey: TKey): SizeInt; overload; inline;
+    function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey; out AHash: UInt32): SizeInt; virtual; abstract; overload;
+  public
+    type
+      // Enumerators
+      TPairEnumerator = class(TOpenAddressingEnumerator<TDictionaryPair, OPEN_ADDRESSING_CONSTRAINTS>)
+      protected
+        function GetCurrent: TPair<TKey,TValue>; override;
+      end;
+
+      TValueEnumerator = class(TOpenAddressingEnumerator<TValue, OPEN_ADDRESSING_CONSTRAINTS>)
+      protected
+        function GetCurrent: TValue; override;
+      end;
+
+      TKeyEnumerator = class(TOpenAddressingEnumerator<TKey, OPEN_ADDRESSING_CONSTRAINTS>)
+      protected
+        function GetCurrent: TKey; override;
+      end;
+
+      // Collections
+      TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TValue, CUSTOM_DICTIONARY_CONSTRAINTS>);
+
+      TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TKey, CUSTOM_DICTIONARY_CONSTRAINTS>);
+
+    // bug #24283 - workaround related to lack of DoGetEnumerator
+    function GetEnumerator: TPairEnumerator; reintroduce;
+  private
+    function GetKeys: TKeyCollection;
+    function GetValues: TValueCollection;
+  private
+    function GetItem(const AKey: TKey): TValue; inline;
+    procedure SetItem(const AKey: TKey; const AValue: TValue); inline;
+    procedure AddItem(var AItem: TItem; constref AKey: TKey; constref AValue: TValue; const AHash: UInt32); inline;
+  protected
+     // useful for using dictionary as array
+    function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): TValue; virtual;
+    function DoAdd(constref AKey: TKey; constref AValue: TValue): SizeInt; virtual;
+
+    procedure UpdateItemsThreshold(ASize: SizeInt); override;
+
+    procedure SetCapacity(ACapacity: SizeInt); override;
+    // bug #24283 - can't descadent from TEnumerable
+    function DoGetEnumerator: TEnumerator<TDictionaryPair>; override;
+    procedure SetMaxLoadFactor(AValue: single); override;
+    function GetLoadFactor: single; override;
+    function GetCapacity: SizeInt; override;
+  public
+    // many constructors because bug #25607
+    constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload;
+
+    procedure Add(constref APair: TPair<TKey, TValue>); override; overload;
+    procedure Add(constref AKey: TKey; constref AValue: TValue); overload; inline;
+    procedure Remove(constref AKey: TKey);
+    function ExtractPair(constref AKey: TKey): TPair<TKey, TValue>;
+    procedure Clear; override;
+    procedure TrimExcess;
+    function TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean;
+    procedure AddOrSetValue(constref AKey: TKey; constref AValue: TValue);
+    function ContainsKey(constref AKey: TKey): Boolean; inline;
+    function ContainsValue(constref AValue: TValue): Boolean; overload;
+    function ContainsValue(constref AValue: TValue; const AEqualityComparer: IEqualityComparer<TValue>): Boolean; virtual; overload;
+
+    property Items[Index: TKey]: TValue read GetItem write SetItem; default;
+    property Keys: TKeyCollection read GetKeys;
+    property Values: TValueCollection read GetValues;
+
+    procedure GetMemoryLayout(const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition);
+  end;
+
+  TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>)
+  private type // for workaround Lazarus bug #25613
+    _TItem = record
+      Hash: UInt32;
+      Pair: TPair<TKey, TValue>;
+    end;
+  protected
+    procedure NotifyIndexChange(AFrom, ATo: SizeInt); virtual;
+    function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): TValue; override;
+    function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey; out AHash: UInt32): SizeInt; override; overload;
+  end;
+
+  // More info and TODO
+  // https://github.com/OpenHFT/UntitledCollectionsProject/wiki/Tombstones-purge-from-hashtable:-theory-and-practice
+
+  TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS> = class abstract(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>)
+  private
+    FTombstonesCount: SizeInt;
+  protected
+    function Rehash(ASizePow2: SizeInt; AForce: Boolean = False): boolean; override;
+    function RealItemsLength: SizeInt; override;
+
+    function FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; constref AKey: TKey;
+      out AHash: UInt32): SizeInt; virtual; abstract;
+
+    function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): TValue; override;
+    function DoAdd(constref AKey: TKey; constref AValue: TValue): SizeInt; override;
+  public
+    property TombstonesCount: SizeInt read FTombstonesCount;
+    procedure ClearTombstones; virtual;
+    procedure Clear; override;
+  end;
+
+  TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>)
+  private type // for workaround Lazarus bug #25613
+    _TItem = record
+      Hash: UInt32;
+      Pair: TPair<TKey, TValue>;
+    end;
+  protected
+    function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey;
+      out AHash: UInt32): SizeInt; override; overload;
+    function FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; constref AKey: TKey;
+      out AHash: UInt32): SizeInt; override;
+  end;
+
+  TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>)
+  private type // for workaround Lazarus bug #25613
+    _TItem = record
+      Hash: UInt32;
+      Pair: TPair<TKey, TValue>;
+    end;
+  private
+    R: UInt32;
+  protected
+    procedure UpdateItemsThreshold(ASize: SizeInt); override;
+    function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey;
+      out AHash: UInt32): SizeInt; override; overload;
+    function FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; constref AKey: TKey;
+      out AHash: UInt32): SizeInt; override;
+  strict protected
+    constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload;
+    constructor Create(const AComparer: IEqualityComparer<TKey>); reintroduce; overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); override; overload;
+  public // bug #26181 (redundancy of constructors)
+    constructor Create(ACapacity: SizeInt); override; overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>); override; overload;
+    constructor Create(ACapacity: SizeInt; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload;
+    constructor Create(const AComparer: IExtendedEqualityComparer<TKey>); overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload;
+  end;
+
+  TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS> = class abstract(TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>)
+  private type // for workaround Lazarus bug #25613
+    TItem = record
+      Hash: UInt32;
+      Pair: TPair<TKey, TValue>;
+    end;
+    TItemsArray = array of TItem;
+  private
+    FMainIndex: SizeInt;
+  protected
+    function DoMoveNext: Boolean; override;
+  public
+    constructor Create(ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
+  end;
+
+  // more info :
+  // http://arxiv.org/abs/0903.0391
+
+  TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS> = class(TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>)
+  private const // Lookup Result
+    LR_NIL = -1;
+    LR_QUEUE = -2;
+  private type
+    PItem = ^TItem;
+    TItem = record
+      Hash: UInt32;
+      Pair: TPair<TKey, TValue>;
+    end;
+    TValueForQueue = TItem;
+
+    TQueueDictionary = class(TOpenAddressingLP<TKey, TValueForQueue, TDelphiHashFactory, TLinearProbing>)
+    private type // for workaround Lazarus bug #25613
+      _TItem = record
+        Hash: UInt32;
+        Pair: TPair<TKey, TValueForQueue>;
+      end;
+    private
+      FIdx: TList<UInt32>; // list to keep order
+    protected
+      procedure NotifyIndexChange(AFrom, ATo: SizeInt); override;
+      function Rehash(ASizePow2: SizeInt; AForce: Boolean = False): Boolean; override;
+    public
+      procedure InsertIntoBack(AItem: Pointer);
+      procedure InsertIntoHead(AItem: Pointer);
+      function IsEmpty: Boolean;
+      function Pop: Pointer;
+      constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload;
+      destructor Destroy; override;
+    end;
+
+    // cycle-detection mechanism class
+    TCDM = class(TOpenAddressingSH<TKey, TEmptyRecord, TDelphiHashFactory, TLinearProbing>);
+    TItemsArray = array of TItem;
+    TItemsDArray = array[0..Pred(TCuckooCfg.D)] of TItemsArray;
+  private var
+    FQueue: TQueueDictionary;  // probably can be optimized - hash TItem give information from TItem.Hash for cuckoo ...
+      // currently is kept in "TQueueDictionary = class(TOpenAddressingSH<TKey, TItem, ...>"
+
+    FCDM: TCDM; // cycle-detection mechanism
+    FItemsThreshold: SizeInt;
+    FItems: TItemsDArray;
+  // sadly there is bug #24848 for class var ...
+  {class} var
+    CUCKOO_SIGN, CUCKOO_INDEX_SIZE, CUCKOO_HASH_SIGN: UInt32;
+    // CUCKOO_MAX_ITEMS_LENGTH: <- to do : calc max length for items based on CUCKOO sign
+    // maybe some CDM bloom filter?
+
+    procedure UpdateItemsThreshold(ASize: SizeInt); override;
+    procedure Resize(ANewSize: SizeInt);
+    procedure Rehash(ASizePow2: SizeInt);
+    function PrepareAddingItem: SizeInt;
+  protected
+    function Lookup(constref AKey: TKey; var AHashListOrIndex: PUInt32): SizeInt; inline; overload;
+    function Lookup(constref AItems: TItemsDArray; constref AKey: TKey; var AHashListOrIndex: PUInt32): SizeInt; virtual; overload;
+  public
+    type
+      // Enumerators
+      TPairEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<TDictionaryPair, CUCKOO_CONSTRAINTS>)
+      protected
+        function GetCurrent: TPair<TKey,TValue>; override;
+      end;
+
+      TValueEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<TValue, CUCKOO_CONSTRAINTS>)
+      protected
+        function GetCurrent: TValue; override;
+      end;
+
+      TKeyEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<TKey, CUCKOO_CONSTRAINTS>)
+      protected
+        function GetCurrent: TKey; override;
+      end;
+
+      // Collections
+      TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TValue, CUSTOM_DICTIONARY_CONSTRAINTS>);
+
+      TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TKey, CUSTOM_DICTIONARY_CONSTRAINTS>);
+
+    // bug #24283 - workaround related to lack of DoGetEnumerator
+    function GetEnumerator: TPairEnumerator; reintroduce;
+  private
+    function GetKeys: TKeyCollection;
+    function GetValues: TValueCollection;
+  private
+    function GetItem(const AKey: TKey): TValue; inline;
+    procedure SetItem(const AKey: TKey; const AValue: TValue); overload; inline;
+    procedure SetItem(constref AValue: TValue; const AHashListOrIndex: PUInt32; ALookupResult: SizeInt); overload;
+
+    procedure AddItem(constref AItems: TItemsDArray; constref AKey: TKey; constref AValue: TValue; const AHashList: PUInt32); overload;
+    procedure DoAdd(constref AKey: TKey; constref AValue: TValue; const AHashList: PUInt32); overload; inline;
+    function DoRemove(const AHashListOrIndex: PUInt32; ALookupResult: SizeInt;
+      ACollectionNotification: TCollectionNotification): TValue;
+
+    function GetQueueCount: SizeInt;
+  protected
+    procedure SetCapacity(ACapacity: SizeInt); override;
+    // bug #24283 - can't descadent from TEnumerable
+    function DoGetEnumerator: TEnumerator<TDictionaryPair>; override;
+    procedure SetMaxLoadFactor(AValue: single); override;
+    function GetLoadFactor: single; override;
+    function GetCapacity: SizeInt; override;
+  strict protected // bug #26181
+    constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload;
+    constructor Create(const AComparer: IEqualityComparer<TKey>); reintroduce; overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); override; overload;
+  public
+    // TODO: function TryFlushQueue(ACount: SizeInt): SizeInt;
+
+    constructor Create; override; overload;
+    constructor Create(ACapacity: SizeInt); override; overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>); override; overload;
+    constructor Create(ACapacity: SizeInt; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload;
+    constructor Create(const AComparer: IExtendedEqualityComparer<TKey>); overload;
+    constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload;
+    destructor Destroy; override;
+
+    procedure Add(constref APair: TPair<TKey, TValue>); override; overload;
+    procedure Add(constref AKey: TKey; constref AValue: TValue); overload;
+    procedure Remove(constref AKey: TKey);
+    function ExtractPair(constref AKey: TKey): TPair<TKey, TValue>;
+    procedure Clear; override;
+    procedure TrimExcess;
+    function TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean;
+    procedure AddOrSetValue(constref AKey: TKey; constref AValue: TValue);
+    function ContainsKey(constref AKey: TKey): Boolean; inline;
+    function ContainsValue(constref AValue: TValue): Boolean; overload;
+    function ContainsValue(constref AValue: TValue; const AEqualityComparer: IEqualityComparer<TValue>): Boolean; virtual; overload;
+
+    property Items[Index: TKey]: TValue read GetItem write SetItem; default;
+    property Keys: TKeyCollection read GetKeys;
+    property Values: TValueCollection read GetValues;
+
+    property QueueCount: SizeInt read GetQueueCount;
+    procedure GetMemoryLayout(const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition);
+  end;
+
+  TDictionaryOwnerships = set of (doOwnsKeys, doOwnsValues);
+
+  TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS> = class(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>)
+  private
+    FOwnerships: TDictionaryOwnerships;
+  protected
+    procedure KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); override;
+    procedure ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); override;
+  public
+    // can't be as "Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt = 0)"
+    // because bug #25607
+    constructor Create(AOwnerships: TDictionaryOwnerships); overload;
+    constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt); overload;
+    constructor Create(AOwnerships: TDictionaryOwnerships;
+      const AComparer: IExtendedEqualityComparer<TKey>); overload;
+    constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt;
+      const AComparer: IExtendedEqualityComparer<TKey>); overload;
+  end;
+
+  TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>)
+  private
+    FOwnerships: TDictionaryOwnerships;
+  protected
+    procedure KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); override;
+    procedure ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); override;
+  public
+    // can't be as "Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt = 0)"
+    // because bug #25607
+    constructor Create(AOwnerships: TDictionaryOwnerships); overload;
+    constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt); overload;
+    constructor Create(AOwnerships: TDictionaryOwnerships;
+      const AComparer: IEqualityComparer<TKey>); overload;
+    constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt;
+      const AComparer: IEqualityComparer<TKey>); overload;
+  end;
+
+  // useful generics overloads
+  TOpenAddressingLP<TKey, TValue, THashFactory> = class(TOpenAddressingLP<TKey, TValue, THashFactory, TLinearProbing>);
+  TOpenAddressingLP<TKey, TValue>  = class(TOpenAddressingLP<TKey, TValue, TDelphiHashFactory, TLinearProbing>);
+
+  TObjectOpenAddressingLP<TKey, TValue, THashFactory> = class(TObjectOpenAddressingLP<TKey, TValue, THashFactory, TLinearProbing>);
+  TObjectOpenAddressingLP<TKey, TValue> = class(TObjectOpenAddressingLP<TKey, TValue, TDelphiHashFactory, TLinearProbing>);
+
+  // Linear Probing with Tombstones (LPT)
+  TOpenAddressingLPT<TKey, TValue, THashFactory> = class(TOpenAddressingSH<TKey, TValue, THashFactory, TLinearProbing>);
+  TOpenAddressingLPT<TKey, TValue> = class(TOpenAddressingSH<TKey, TValue, TDelphiHashFactory, TLinearProbing>);
+
+  TOpenAddressingQP<TKey, TValue, THashFactory> = class(TOpenAddressingSH<TKey, TValue, THashFactory, TQuadraticProbing>);
+  TOpenAddressingQP<TKey, TValue> = class(TOpenAddressingSH<TKey, TValue, TDelphiHashFactory, TQuadraticProbing>);
+
+  TOpenAddressingDH<TKey, TValue, THashFactory> = class(TOpenAddressingDH<TKey, TValue, THashFactory, TDoubleHashing>);
+  TOpenAddressingDH<TKey, TValue> = class(TOpenAddressingDH<TKey, TValue, TDelphiDoubleHashFactory, TDoubleHashing>);
+
+  TCuckooD2<TKey, TValue, THashFactory> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D2>);
+  TCuckooD2<TKey, TValue> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiDoubleHashFactory, TDeamortizedCuckooHashingCfg_D2>);
+
+  TCuckooD4<TKey, TValue, THashFactory> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D4>);
+  TCuckooD4<TKey, TValue> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiQuadrupleHashFactory, TDeamortizedCuckooHashingCfg_D4>);
+
+  TCuckooD6<TKey, TValue, THashFactory> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D6>);
+  TCuckooD6<TKey, TValue> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiSixfoldHashFactory, TDeamortizedCuckooHashingCfg_D6>);
+
+  TObjectCuckooD2<TKey, TValue, THashFactory> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D2>);
+  TObjectCuckooD2<TKey, TValue> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiDoubleHashFactory, TDeamortizedCuckooHashingCfg_D2>);
+
+  TObjectCuckooD4<TKey, TValue, THashFactory> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D4>);
+  TObjectCuckooD4<TKey, TValue> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiQuadrupleHashFactory, TDeamortizedCuckooHashingCfg_D4>);
+
+  TObjectCuckooD6<TKey, TValue, THashFactory> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D6>);
+  TObjectCuckooD6<TKey, TValue> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiSixfoldHashFactory, TDeamortizedCuckooHashingCfg_D6>);
+
+  // for normal programmers to normal use =)
+  TDictionary<TKey, TValue> = class(TOpenAddressingLP<TKey, TValue>);
+  TObjectDictionary<TKey, TValue> = class(TObjectOpenAddressingLP<TKey, TValue>);
+
+  TFastHashMap<TKey, TValue> = class(TCuckooD2<TKey, TValue>);
+  TFastObjectHashMap<TKey, TValue> = class(TObjectCuckooD2<TKey, TValue>);
+
+  THashMap<TKey, TValue> = class(TCuckooD4<TKey, TValue>);
+  TObjectHashMap<TKey, TValue> = class(TObjectCuckooD4<TKey, TValue>);
+
+var
+  EmptyRecord: TEmptyRecord;