diff --git a/.gitattributes b/.gitattributes index 733f2d6e50..6a33465fec 100644 --- a/.gitattributes +++ b/.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 diff --git a/packages/fpmake_add.inc b/packages/fpmake_add.inc index 3157934b5e..d99ae8d436 100644 --- a/packages/fpmake_add.inc +++ b/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')); diff --git a/packages/fpmake_proc.inc b/packages/fpmake_proc.inc index 354455fe59..328bcdab63 100644 --- a/packages/fpmake_proc.inc +++ b/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} diff --git a/packages/rtl-generics/Makefile b/packages/rtl-generics/Makefile new file mode 100644 index 0000000000..369046a9ac --- /dev/null +++ b/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 diff --git a/packages/rtl-generics/Makefile.fpc b/packages/rtl-generics/Makefile.fpc new file mode 100644 index 0000000000..06cdbe473d --- /dev/null +++ b/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 diff --git a/packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpi b/packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpi new file mode 100644 index 0000000000..45b6b1eea4 --- /dev/null +++ b/packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpi @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + <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> diff --git a/packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpr b/packages/rtl-generics/examples/tarraydouble/tarrayprojectdouble.lpr new file mode 100644 index 0000000000..8ed5c2bf4a --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpi b/packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpi new file mode 100644 index 0000000000..6d2ee412de --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpr b/packages/rtl-generics/examples/tarraysingle/tarrayprojectsingle.lpr new file mode 100644 index 0000000000..49bec2cfca --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/tcomparer/tcomparerproject.lpi b/packages/rtl-generics/examples/tcomparer/tcomparerproject.lpi new file mode 100644 index 0000000000..66e8d8be35 --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/tcomparer/tcomparerproject.lpr b/packages/rtl-generics/examples/tcomparer/tcomparerproject.lpr new file mode 100644 index 0000000000..b7c12823a0 --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/thashmap/thashmapproject.lpi b/packages/rtl-generics/examples/thashmap/thashmapproject.lpi new file mode 100644 index 0000000000..61bd73c661 --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/thashmap/thashmapproject.lpr b/packages/rtl-generics/examples/thashmap/thashmapproject.lpr new file mode 100644 index 0000000000..d9598cab9d --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpi b/packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpi new file mode 100644 index 0000000000..0c2d179d7d --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpr b/packages/rtl-generics/examples/thashmapcaseinsensitive/thashmapcaseinsensitive.lpr new file mode 100644 index 0000000000..377bd69c19 --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpi b/packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpi new file mode 100644 index 0000000000..b32ad72067 --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpr b/packages/rtl-generics/examples/thashmapextendedequalitycomparer/thashmapextendedequalitycomparer.lpr new file mode 100644 index 0000000000..d3c9116c77 --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpi b/packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpi new file mode 100644 index 0000000000..63511b3e9c --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpr b/packages/rtl-generics/examples/tobjectlist/tobjectlistproject.lpr new file mode 100644 index 0000000000..179d88595e --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/tqueue/tqueueproject.lpi b/packages/rtl-generics/examples/tqueue/tqueueproject.lpi new file mode 100644 index 0000000000..5eec3b87fd --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/tqueue/tqueueproject.lpr b/packages/rtl-generics/examples/tqueue/tqueueproject.lpr new file mode 100644 index 0000000000..87e51cd101 --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/examples/tstack/tstackproject.lpi b/packages/rtl-generics/examples/tstack/tstackproject.lpi new file mode 100644 index 0000000000..ccc9bd6793 --- /dev/null +++ b/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> diff --git a/packages/rtl-generics/examples/tstack/tstackproject.lpr b/packages/rtl-generics/examples/tstack/tstackproject.lpr new file mode 100644 index 0000000000..1a53e1872a --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/fpmake.pp b/packages/rtl-generics/fpmake.pp new file mode 100644 index 0000000000..dbd04bdcac --- /dev/null +++ b/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} diff --git a/packages/rtl-generics/src/generics.collections.pas b/packages/rtl-generics/src/generics.collections.pas new file mode 100644 index 0000000000..0643f88a15 --- /dev/null +++ b/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. diff --git a/packages/rtl-generics/src/generics.defaults.pas b/packages/rtl-generics/src/generics.defaults.pas new file mode 100644 index 0000000000..e3d4e3c72b --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/src/generics.hashes.pas b/packages/rtl-generics/src/generics.hashes.pas new file mode 100644 index 0000000000..ec1bb2b763 --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/src/generics.helpers.pas b/packages/rtl-generics/src/generics.helpers.pas new file mode 100644 index 0000000000..00c27297e5 --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/src/generics.memoryexpanders.pas b/packages/rtl-generics/src/generics.memoryexpanders.pas new file mode 100644 index 0000000000..156715486c --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/src/generics.strings.pas b/packages/rtl-generics/src/generics.strings.pas new file mode 100644 index 0000000000..1f9c2690ea --- /dev/null +++ b/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. + diff --git a/packages/rtl-generics/src/inc/generics.dictionaries.inc b/packages/rtl-generics/src/inc/generics.dictionaries.inc new file mode 100644 index 0000000000..74820d7554 --- /dev/null +++ b/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; diff --git a/packages/rtl-generics/src/inc/generics.dictionariesh.inc b/packages/rtl-generics/src/inc/generics.dictionariesh.inc new file mode 100644 index 0000000000..adfc914151 --- /dev/null +++ b/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;