|
|
{$INCLUDE ..\cDefines.inc} unit cUtils; { } { Miscellaneous utility functions v3.36 } { } { This unit is copyright ?2000-2004 by David J Butler } { } { This unit is part of Delphi Fundamentals. } { Its original file name is cUtils.pas } { It was generated 1 Aug 2004 23:29. } { The latest version is available from the Fundamentals home page } { http://fundementals.sourceforge.net/ } { } { I invite you to use this unit, free of charge. } { I invite you to distibute this unit, but it must be for free. } { I also invite you to contribute to its development, } { but do not distribute a modified copy of this file. } { } { A forum is available on SourceForge for general discussion } { http://sourceforge.net/forum/forum.php?forum_id=2117 } { } { } { Revision history: } { 2000/02/02 0.01 Initial version } { 2000/03/08 1.02 Added RealArray / IntegerArray functions. } { 2000/04/10 1.03 Added Append, Renamed Delete to Remove and added } { StringArrays. } { 2000/05/03 1.04 Added Path functions. } { 2000/05/08 1.05 Revision. } { 188 lines interface. 1171 lines implementation. } { 2000/06/01 1.06 Added Range and Dup constructors for dynamic arrays. } { 2000/06/03 1.07 Added ArrayInsert functions. } { 2000/06/06 1.08 Moved bit functions from cMaths. } { 2000/06/08 1.09 Removed TInteger, TReal, TRealArray, TIntegerArray. } { 299 lines interface. 2019 lines implementations. } { 2000/06/10 1.10 Added linked lists for Integer, Int64, Extended and } { String. } { 518 lines interface. 3396 lines implementation. } { 2000/06/14 1.11 cUtils now generated from a template using a source } { pre-processor that uses cUtils. } { 560 lines interface. 1328 lines implementation. } { Produced source: 644 lines interface, 4716 lines } { implementation. } { 2000/07/04 1.12 Revision for Fundamentals release. } { 2000/07/24 1.13 Added TrimArray functions. } { 2000/07/26 1.14 Added Difference functions. } { 2000/09/02 1.15 Added RemoveDuplicates functions. } { Added Count functions. } { Fixed bug in Sort. } { 2000/09/27 1.16 Fixed bug in ArrayInsert. } { 2000/11/29 1.17 Moved SetFPUPrecision to cSysUtils. } { 2001/05/03 1.18 Improved bit functions. Added Pascal versions of } { assembly routines. } { Templ: 867 lines interface, 2886 lines implementation. } { Source: 939 lines interface, 9796 lines implementation. } { 2001/05/13 1.19 Added CharCount. } { 2001/05/15 1.20 Added PosNext (ClassType, ObjectArray). } { 2001/05/18 1.21 Added hashing functions from cMaths. } { 2001/07/07 1.22 Added TBinaryTreeNode. } { 2001/11/11 2.23 Revision. } { 2002/01/03 2.24 Moved EncodeBase64, DecodeBase64 from cMaths and } { optimized. Added LongWordToHex, HexToLongWord. } { 2002/03/30 2.25 Fixed bug in DecodeBase64. } { 2002/04/02 2.26 Removed dependencies on all other units (incl. Delphi ) { units) to remove initialization code associated with } { SysUtils. This allows usage of cUtils in projects } { and still have very small binaries. } { Fixed bug in LongWordToHex. } { 2002/05/31 3.27 Refactored for Fundamentals 3. } { Moved linked lists to cLinkedLists. } { 2002/08/09 3.28 Added HashInteger. } { 2002/10/06 3.29 Renamed Cond to iif. } { 2002/12/12 3.30 Small revisions. } { 2003/03/14 3.31 Removed ApproxZero. Added FloatZero, FloatsEqual and } { FloatsCompare. Added documentation and test cases for } { comparison functions. } { Added support for Currency type. } { 2003/07/27 3.32 Added fast ZeroMem and FillMem routines. } { 2003/09/11 3.33 Added InterfaceArray functions. } { 2004/01/18 3.34 Added WideStringArray functions. } { 2004/07/24 3.35 Optimizations of Sort functions. } { 2005/08/01 3.36 Improved validation in base conversion routines. } { } interface const UnitName = 'cUtils'; UnitVersion = '3.36'; UnitDesc = 'Miscelleanous utility functions'; UnitCopyright = 'Copyright (c) 2000-2004 David J Butler'; FundamentalsMajorVersion = 3; FundamentalsMinorVersion = 28; {$WRITEABLECONST OFF} { } { Integer types } { Byte unsigned 8 bits } { Word unsigned 16 bits } { LongWord unsigned 32 bits } { ShortInt signed 8 bits } { SmallInt signed 16 bits } { LongInt signed 32 bits } { Int64 signed 64 bits } { Integer signed system word } { Cardinal unsigned system word } { } type Int8 = ShortInt; Int16 = SmallInt; Int32 = LongInt; LargeInt = Int64; PLargeInt = ^LargeInt; Word8 = Byte; Word16 = Word; Word32 = LongWord; {$IFDEF DELPHI5_DOWN} PBoolean = ^Boolean; PByte = ^Byte; PWord = ^Word; PLongWord = ^LongWord; PShortInt = ^ShortInt; PSmallInt = ^SmallInt; PLongInt = ^LongInt; PInteger = ^Integer; PInt64 = ^Int64; {$ENDIF} LongIntRec = packed record case Integer of 0 : (Lo, Hi : Word); 1 : (Words : Array[0..1] of Word); 2 : (Bytes : Array[0..3] of Byte); end; const MinByte = Low(Byte); MaxByte = High(Byte); MinWord = Low(Word); MaxWord = High(Word); MinShortInt = Low(ShortInt); MaxShortInt = High(ShortInt); MinSmallInt = Low(SmallInt); MaxSmallInt = High(SmallInt); MinLongWord = LongWord(Low(LongWord)); MaxLongWord = LongWord(High(LongWord)); MinLongInt = LongInt(Low(LongInt)); MaxLongInt = LongInt(High(LongInt)); MaxInt64 = Int64(High(Int64)); MinInt64 = Int64(Low(Int64)); MinInteger = Integer(Low(Integer)); MaxInteger = Integer(High(Integer)); MinCardinal = Cardinal(Low(Cardinal)); MaxCardinal = Cardinal(High(Cardinal)); const BitsPerByte = 8; BitsPerWord = 16; BitsPerLongWord = 32; BytesPerCardinal = Sizeof(Cardinal); BitsPerCardinal = BytesPerCardinal * 8; { Min returns smallest of A and B } { Max returns greatest of A and B } function MinI(const A, B: Integer): Integer; function MaxI(const A, B: Integer): Integer; function MinC(const A, B: Cardinal): Cardinal; function MaxC(const A, B: Cardinal): Cardinal; { Clip returns Value if in Low..High range, otherwise Low or High } function Clip(const Value: Integer; const Low, High: Integer): Integer; function ClipByte(const Value: Integer): Integer; function ClipWord(const Value: Integer): Integer; function ClipLongWord(const Value: Int64): LongWord; function SumClipI(const A, I: Integer): Integer; function SumClipC(const A: Cardinal; const I: Integer): Cardinal; { InXXXRange returns True if A in range of type XXX } function InByteRange(const A: Int64): Boolean; function InWordRange(const A: Int64): Boolean; function InLongWordRange(const A: Int64): Boolean; function InShortIntRange(const A: Int64): Boolean; function InSmallIntRange(const A: Int64): Boolean; function InLongIntRange(const A: Int64): Boolean; { } { Real types } { } { Floating point: } { Single 32 bits 7-8 significant digits } { Double 64 bits 15-16 significant digits } { Extended 80 bits 19-20 significant digits } { } { Fixed point: } { Currency 64 bits 19-20 significant digits, 4 after the decimal point. } { } type Float = Extended; PFloat = ^Float; const MinSingle : Single = 1.5E-45; MaxSingle : Single = 3.4E+38; MinDouble : Double = 5.0E-324; MaxDouble : Double = 1.7E+308; MinExtended : Extended = 3.4E-4932; MaxExtended : Extended = 1.1E+4932; {$IFDEF FREEPASCAL} MinCurrency = -922337203685477.5807; MaxCurrency = 922337203685477.5807; {$ELSE} MinCurrency : Currency = -922337203685477.5807; MaxCurrency : Currency = 922337203685477.5807; {$ENDIF} {$IFDEF DELPHI5_DOWN} type PSingle = ^Single; PDouble = ^Double; PExtended = ^Extended; PCurrency = ^Currency; {$ENDIF} type TExtended = packed record Case Boolean of True: ( Mantissa : packed Array[0..1] of LongWord; { MSB of [1] is the normalized 1 bit } Exponent : Word; { MSB is the sign bit } ); False: (Value: Extended); end; const ExtendedNan : TExtended = (Mantissa:($FFFFFFFF, $FFFFFFFF); Exponent:$7FFF); ExtendedInfinity : TExtended = (Mantissa:($00000000, $80000000); Exponent:$7FFF); { Min returns smallest of A and B } { Max returns greatest of A and B } { Clip returns Value if in Low..High range, otherwise Low or High } function MinF(const A, B: Extended): Extended; function MaxF(const A, B: Extended): Extended; function ClipF(const Value: Extended; const Low, High: Extended): Extended; { InXXXRange returns True if A in range of type XXX } function InSingleRange(const A: Extended): Boolean; function InDoubleRange(const A: Extended): Boolean; function InCurrencyRange(const A: Extended): Boolean; overload; function InCurrencyRange(const A: Int64): Boolean; overload; { } { Bit functions } { All bit functions operate on 32-bit values (LongWord). } { } function ClearBit(const Value, BitIndex: LongWord): LongWord; function SetBit(const Value, BitIndex: LongWord): LongWord; function IsBitSet(const Value, BitIndex: LongWord): Boolean; function ToggleBit(const Value, BitIndex: LongWord): LongWord; function IsHighBitSet(const Value: LongWord): Boolean; function SetBitScanForward(const Value: LongWord): Integer; overload; function SetBitScanForward(const Value, BitIndex: LongWord): Integer; overload; function SetBitScanReverse(const Value: LongWord): Integer; overload; function SetBitScanReverse(const Value, BitIndex: LongWord): Integer; overload; function ClearBitScanForward(const Value: LongWord): Integer; overload; function ClearBitScanForward(const Value, BitIndex: LongWord): Integer; overload; function ClearBitScanReverse(const Value: LongWord): Integer; overload; function ClearBitScanReverse(const Value, BitIndex: LongWord): Integer; overload; function ReverseBits(const Value: LongWord): LongWord; overload; function ReverseBits(const Value: LongWord; const BitCount: Integer): LongWord; overload; function SwapEndian(const Value: LongWord): LongWord; Procedure SwapEndianBuf(var Buf; const Count: Integer); function TwosComplement(const Value: LongWord): LongWord; function RotateLeftBits(const Value: LongWord; const Bits: Byte): LongWord; function RotateRightBits(const Value: LongWord; const Bits: Byte): LongWord; function BitCount(const Value: LongWord): LongWord; function IsPowerOfTwo(const Value: LongWord): Boolean; function LowBitMask(const HighBitIndex: LongWord): LongWord; function HighBitMask(const LowBitIndex: LongWord): LongWord; function RangeBitMask(const LowBitIndex, HighBitIndex: LongWord): LongWord; function SetBitRange(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): LongWord; function ClearBitRange(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): LongWord; function ToggleBitRange(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): LongWord; function IsBitRangeSet(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): Boolean; function IsBitRangeClear(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): Boolean; const BitMaskTable: Array[0..31] of LongWord = ($00000001, $00000002, $00000004, $00000008, $00000010, $00000020, $00000040, $00000080, $00000100, $00000200, $00000400, $00000800, $00001000, $00002000, $00004000, $00008000, $00010000, $00020000, $00040000, $00080000, $00100000, $00200000, $00400000, $00800000, $01000000, $02000000, $04000000, $08000000, $10000000, $20000000, $40000000, $80000000); { } { Sets } { } type CharSet = Set of Char; ByteSet = Set of Byte; PCharSet = ^CharSet; PByteSet = ^ByteSet; const CompleteCharSet = [#0..#255]; CompleteByteSet = [0..255]; function AsCharSet(const C: Array of Char): CharSet; function AsByteSet(const C: Array of Byte): ByteSet; procedure ComplementChar(var C: CharSet; const Ch: Char); procedure ClearCharSet(var C: CharSet); procedure FillCharSet(var C: CharSet); procedure ComplementCharSet(var C: CharSet); procedure AssignCharSet(var DestSet: CharSet; const SourceSet: CharSet); overload; procedure Union(var DestSet: CharSet; const SourceSet: CharSet); overload; procedure Difference(var DestSet: CharSet; const SourceSet: CharSet); overload; procedure Intersection(var DestSet: CharSet; const SourceSet: CharSet); overload; procedure XORCharSet(var DestSet: CharSet; const SourceSet: CharSet); function IsSubSet(const A, B: CharSet): Boolean; function IsEqual(const A, B: CharSet): Boolean; overload; function IsEmpty(const C: CharSet): Boolean; function IsComplete(const C: CharSet): Boolean; function CharCount(const C: CharSet): Integer; overload; procedure ConvertCaseInsensitive(var C: CharSet); function CaseInsensitiveCharSet(const C: CharSet): CharSet; { } { Range functions } { } function IntRangeLength(const Low, High: Integer): Int64; function IntRangeAdjacent(const Low1, High1, Low2, High2: Integer): Boolean; function IntRangeOverlap(const Low1, High1, Low2, High2: Integer): Boolean; function IntRangeHasElement(const Low, High, Element: Integer): Boolean; function IntRangeIncludeElement(var Low, High: Integer; const Element: Integer): Boolean; function IntRangeIncludeElementRange(var Low, High: Integer; const LowElement, HighElement: Integer): Boolean; function CardinalRangeLength(const Low, High: Cardinal): Int64; function CardinalRangeAdjacent(const Low1, High1, Low2, High2: Cardinal): Boolean; function CardinalRangeOverlap(const Low1, High1, Low2, High2: Cardinal): Boolean; function CardinalRangeHasElement(const Low, High, Element: Cardinal): Boolean; function CardinalRangeIncludeElement(var Low, High: Cardinal; const Element: Cardinal): Boolean; function CardinalRangeIncludeElementRange(var Low, High: Cardinal; const LowElement, HighElement: Cardinal): Boolean; { } { Swap } { } procedure Swap(var X, Y: Boolean); overload; procedure Swap(var X, Y: Byte); overload; procedure Swap(var X, Y: Word); overload; procedure Swap(var X, Y: LongWord); overload; procedure Swap(var X, Y: ShortInt); overload; procedure Swap(var X, Y: SmallInt); overload; procedure Swap(var X, Y: LongInt); overload; procedure Swap(var X, Y: Int64); overload; procedure Swap(var X, Y: Single); overload; procedure Swap(var X, Y: Double); overload; procedure Swap(var X, Y: Extended); overload; procedure Swap(var X, Y: Currency); overload; procedure Swap(var X, Y: String); overload; procedure Swap(var X, Y: WideString); overload; procedure Swap(var X, Y: Pointer); overload; procedure Swap(var X, Y: TObject); overload; procedure SwapObjects(var X, Y); { } { Inline if } { } { iif returns TrueValue if Expr is True, otherwise it returns FalseValue. } { } function iif(const Expr: Boolean; const TrueValue: Integer; const FalseValue: Integer = 0): Integer; overload; function iif(const Expr: Boolean; const TrueValue: Int64; const FalseValue: Int64 = 0): Int64; overload; function iif(const Expr: Boolean; const TrueValue: Extended; const FalseValue: Extended = 0.0): Extended; overload; function iif(const Expr: Boolean; const TrueValue: String; const FalseValue: String = ''): String; overload; function iif(const Expr: Boolean; const TrueValue: TObject; const FalseValue: TObject = nil): TObject; overload; { } { Comparison } { } type TCompareResult = ( crLess, crEqual, crGreater, crUndefined); TCompareResultSet = Set of TCompareResult; function ReverseCompareResult(const C: TCompareResult): TCompareResult; { } { Direct comparison } { } { Compare(I1, I2) returns crLess if I1 < I2, crEqual if I1 = I2 or } { crGreater if I1 > I2. } { } function Compare(const I1, I2: Boolean): TCompareResult; overload; function Compare(const I1, I2: Integer): TCompareResult; overload; function Compare(const I1, I2: Int64): TCompareResult; overload; function Compare(const I1, I2: Extended): TCompareResult; overload; function Compare(const I1, I2: String): TCompareResult; overload; function WideCompare(const I1, I2: WideString): TCompareResult; { } { Approximate comparison of floating point values } { } { FloatZero, FloatOne, FloatsEqual and FloatsCompare are functions for } { comparing floating point numbers based on a fixed CompareDelta difference } { between the values. This means that values are considered equal if the } { unsigned difference between the values are less than CompareDelta. } { } const // Minimum CompareDelta values for the different floating point types: // The values were chosen to be slightly higher than the minimum value that // the floating-point type can store. SingleCompareDelta = 1.0E-34; DoubleCompareDelta = 1.0E-280; ExtendedCompareDelta = 1.0E-4400; // Default CompareDelta is set to SingleCompareDelta. This allows any type // of floating-point value to be compared with any other. DefaultCompareDelta = SingleCompareDelta; function FloatZero(const A: Extended; const CompareDelta: Extended = DefaultCompareDelta): Boolean; function FloatOne(const A: Extended; const CompareDelta: Extended = DefaultCompareDelta): Boolean; function FloatsEqual(const A, B: Extended; const CompareDelta: Extended = DefaultCompareDelta): Boolean; function FloatsCompare(const A, B: Extended; const CompareDelta: Extended = DefaultCompareDelta): TCompareResult; { } { Scaled approximate comparison of floating point values } { } { ApproxEqual and ApproxCompare are functions for comparing floating point } { numbers based on a scaled order of magnitude difference between the } { values. CompareEpsilon is the ratio applied to the largest of the two } { exponents to give the maximum difference (CompareDelta) for comparison. } { } { For example: } { } { When the CompareEpsilon is 1.0E-9, the result of } { } { ApproxEqual(1.0E+20, 1.000000001E+20) = False, but the result of } { ApproxEqual(1.0E+20, 1.0000000001E+20) = True, ie the first 9 digits of } { the mantissas of the values must be the same. } { } { Note that for A <> 0.0, the value of ApproxEqual(A, 0.0) will always be } { False. Rather use the unscaled FloatZero, FloatsEqual and FloatsCompare } { functions when specifically testing for zero. } { } const // Smallest (most sensitive) CompareEpsilon values allowed for the different // floating point types: SingleCompareEpsilon = 1.0E-5; DoubleCompareEpsilon = 1.0E-13; ExtendedCompareEpsilon = 1.0E-17; // Default CompareEpsilon is set for half the significant digits of the // Extended type. DefaultCompareEpsilon = 1.0E-10; function ApproxEqual(const A, B: Extended; const CompareEpsilon: Double = DefaultCompareEpsilon): Boolean; function ApproxCompare(const A, B: Extended; const CompareEpsilon: Double = DefaultCompareEpsilon): TCompareResult; { } { Special floating-point values } { } { FloatIsInfinity is True if A is a positive or negative infinity. } { FloatIsNaN is True if A is Not-a-Number. } { } function FloatIsInfinity(const A: Extended): Boolean; function FloatIsNaN(const A: Extended): Boolean; { } { Base Conversion } { } { EncodeBase64 converts a binary string (S) to a base 64 string using } { Alphabet. if Pad is True, the result will be padded with PadChar to be a } { multiple of PadMultiple. } { } { DecodeBase64 converts a base 64 string using Alphabet (64 characters for } { values 0-63) to a binary string. } { } const s_HexDigitsUpper: String[16] = '0123456789ABCDEF'; s_HexDigitsLower: String[16] = '0123456789abcdef'; function IsHexChar(const Ch: Char): Boolean; function IsHexWideChar(const Ch: WideChar): Boolean; function HexCharValue(const Ch: Char): Byte; function HexWideCharValue(const Ch: WideChar): Byte; function LongWordToBin(const I: LongWord; const Digits: Byte = 0): String; function LongWordToOct(const I: LongWord; const Digits: Byte = 0): String; function LongWordToHex(const I: LongWord; const Digits: Byte = 0; const UpperCase: Boolean = True): String; function LongWordToStr(const I: LongWord; const Digits: Byte = 0): String; function IsValidBinStr(const S: String): Boolean; function IsValidOctStr(const S: String): Boolean; function IsValidDecStr(const S: String): Boolean; function IsValidHexStr(const S: String): Boolean; { xxxStrToLongWord converts a number in a specific base to a LongWord value. } { Valid is False on return if the string could not be converted. } function BinStrToLongWord(const S: String; var Valid: Boolean): LongWord; function OctStrToLongWord(const S: String; var Valid: Boolean): LongWord; function DecStrToLongWord(const S: String; var Valid: Boolean): LongWord; function HexStrToLongWord(const S: String; var Valid: Boolean): LongWord; function EncodeBase64(const S, Alphabet: String; const Pad: Boolean = False; const PadMultiple: Integer = 4; const PadChar: Char = '='): String; function DecodeBase64(const S, Alphabet: String; const PadSet: CharSet = []): String; const b64_MIMEBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; b64_UUEncode = ' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'; b64_XXEncode = '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; function MIMEBase64Decode(const S: String): String; function MIMEBase64Encode(const S: String): String; function UUDecode(const S: String): String; function XXDecode(const S: String): String; function BytesToHex(const P: Pointer; const Count: Integer; const UpperCase: Boolean = True): String; { } { Type conversion } { } function PointerToStr(const P: Pointer): String; function StrToPointer(const S: String): Pointer; function ObjectClassName(const O: TObject): String; function ClassClassName(const C: TClass): String; function ObjectToStr(const O: TObject): String; function ClassToStr(const C: TClass): String; function CharSetToStr(const C: CharSet): String; function StrToCharSet(const S: String): CharSet; { } { Hashing functions } { } { HashBuf uses a every byte in the buffer to calculate a hash. } { } { HashStrBuf/HashStr is a general purpose string hashing function. } { For large strings, HashStr will sample up to 48 bytes from the string. } { } { If Slots = 0 the hash value is in the LongWord range (0-$FFFFFFFF), } { otherwise the value is in the range from 0 to Slots-1. Note that the } { 'mod' operation, which is used when Slots <> 0, is comparitively slow. } { } function HashBuf(const Buf; const BufSize: Integer; const Slots: LongWord = 0): LongWord; function HashStrBuf(const StrBuf: Pointer; const StrLength: Integer; const Slots: LongWord = 0): LongWord; function HashStrBufNoCase(const StrBuf: Pointer; const StrLength: Integer; const Slots: LongWord = 0): LongWord; function HashStr(const S: String; const Slots: LongWord = 0; const CaseSensitive: Boolean = True): LongWord; function HashInteger(const I: Integer; const Slots: LongWord = 0): LongWord; function HashLongWord(const I: LongWord; const Slots: LongWord = 0): LongWord; { } { Memory operations } { } {$IFDEF DELPHI5_DOWN} type PPointer = ^Pointer; {$ENDIF} const Bytes1KB = 1024; Bytes1MB = 1024 * Bytes1KB; Bytes1GB = 1024 * Bytes1MB; Bytes64KB = 64 * Bytes1KB; Bytes64MB = 64 * Bytes1MB; Bytes2GB = 2 * LongWord(Bytes1GB); procedure FillMem(var Buf; const Count: Integer; const Value: Byte); procedure ZeroMem(var Buf; const Count: Integer); procedure MoveMem(const Source; var Dest; const Count: Integer); function CompareMem(const Buf1; const Buf2; const Count: Integer): Boolean; function CompareMemNoCase(const Buf1; const Buf2; const Count: Integer): TCompareResult; procedure ReverseMem(var Buf; const Size: Integer); { } { IInterface } { } {$IFDEF DELPHI5_DOWN} type IInterface = interface ['{00000000-0000-0000-C000-000000000046}'] function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; {$ENDIF} { } { Array pointers } { } { Maximum array elements } const MaxArraySize = $7FFFFFFF; // 2 Gigabytes MaxByteArrayElements = MaxArraySize div Sizeof(Byte); MaxWordArrayElements = MaxArraySize div Sizeof(Word); MaxLongWordArrayElements = MaxArraySize div Sizeof(LongWord); MaxCardinalArrayElements = MaxArraySize div Sizeof(Cardinal); MaxShortIntArrayElements = MaxArraySize div Sizeof(ShortInt); MaxSmallIntArrayElements = MaxArraySize div Sizeof(SmallInt); MaxLongIntArrayElements = MaxArraySize div Sizeof(LongInt); MaxIntegerArrayElements = MaxArraySize div Sizeof(Integer); MaxInt64ArrayElements = MaxArraySize div Sizeof(Int64); MaxSingleArrayElements = MaxArraySize div Sizeof(Single); MaxDoubleArrayElements = MaxArraySize div Sizeof(Double); MaxExtendedArrayElements = MaxArraySize div Sizeof(Extended); MaxCurrencyArrayElements = MaxArraySize div Sizeof(Currency); MaxStringArrayElements = MaxArraySize div Sizeof(String); MaxWideStringArrayElements = MaxArraySize div Sizeof(WideString); MaxPointerArrayElements = MaxArraySize div Sizeof(Pointer); MaxObjectArrayElements = MaxArraySize div Sizeof(TObject); MaxInterfaceArrayElements = MaxArraySize div Sizeof(IInterface); MaxBooleanArrayElements = MaxArraySize div Sizeof(Boolean); MaxCharSetArrayElements = MaxArraySize div Sizeof(CharSet); MaxByteSetArrayElements = MaxArraySize div Sizeof(ByteSet); { Static array types } type TStaticByteArray = Array[0..MaxByteArrayElements - 1] of Byte; TStaticWordArray = Array[0..MaxWordArrayElements - 1] of Word; TStaticLongWordArray = Array[0..MaxLongWordArrayElements - 1] of LongWord; TStaticShortIntArray = Array[0..MaxShortIntArrayElements - 1] of ShortInt; TStaticSmallIntArray = Array[0..MaxSmallIntArrayElements - 1] of SmallInt; TStaticLongIntArray = Array[0..MaxLongIntArrayElements - 1] of LongInt; TStaticInt64Array = Array[0..MaxInt64ArrayElements - 1] of Int64; TStaticSingleArray = Array[0..MaxSingleArrayElements - 1] of Single; TStaticDoubleArray = Array[0..MaxDoubleArrayElements - 1] of Double; TStaticExtendedArray = Array[0..MaxExtendedArrayElements - 1] of Extended; TStaticCurrencyArray = Array[0..MaxCurrencyArrayElements - 1] of Currency; TStaticStringArray = Array[0..MaxStringArrayElements - 1] of String; TStaticWideStringArray = Array[0..MaxWideStringArrayElements - 1] of WideString; TStaticPointerArray = Array[0..MaxPointerArrayElements - 1] of Pointer; TStaticObjectArray = Array[0..MaxObjectArrayElements - 1] of TObject; TStaticInterfaceArray = Array[0..MaxInterfaceArrayElements - 1] of IInterface; TStaticBooleanArray = Array[0..MaxBooleanArrayElements - 1] of Boolean; TStaticCharSetArray = Array[0..MaxCharSetArrayElements - 1] of CharSet; TStaticByteSetArray = Array[0..MaxByteSetArrayElements - 1] of ByteSet; TStaticCardinalArray = TStaticLongWordArray; TStaticIntegerArray = TStaticLongIntArray; { Array pointers } type PByteArray = ^TStaticByteArray; PWordArray = ^TStaticWordArray; PLongWordArray = ^TStaticLongWordArray; PCardinalArray = ^TStaticCardinalArray; PShortIntArray = ^TStaticShortIntArray; PSmallIntArray = ^TStaticSmallIntArray; PLongIntArray = ^TStaticLongIntArray; PIntegerArray = ^TStaticIntegerArray; PInt64Array = ^TStaticInt64Array; PSingleArray = ^TStaticSingleArray; PDoubleArray = ^TStaticDoubleArray; PExtendedArray = ^TStaticExtendedArray; PCurrencyArray = ^TStaticCurrencyArray; PStringArray = ^TStaticStringArray; PWideStringArray = ^TStaticWideStringArray; PPointerArray = ^TStaticPointerArray; PObjectArray = ^TStaticObjectArray; PInterfaceArray = ^TStaticInterfaceArray; PBooleanArray = ^TStaticBooleanArray; PCharSetArray = ^TStaticCharSetArray; PByteSetArray = ^TStaticByteSetArray; { } { Dynamic arrays } { } type ByteArray = Array of Byte; WordArray = Array of Word; LongWordArray = Array of LongWord; ShortIntArray = Array of ShortInt; SmallIntArray = Array of SmallInt; LongIntArray = Array of LongInt; Int64Array = Array of Int64; SingleArray = Array of Single; DoubleArray = Array of Double; ExtendedArray = Array of Extended; CurrencyArray = Array of Currency; StringArray = Array of String; WideStringArray = Array of WideString; PointerArray = Array of Pointer; ObjectArray = Array of TObject; InterfaceArray = Array of IInterface; BooleanArray = Array of Boolean; CharSetArray = Array of CharSet; ByteSetArray = Array of ByteSet; IntegerArray = LongIntArray; CardinalArray = LongWordArray; function Append(var V: ByteArray; const R: Byte): Integer; overload; function Append(var V: WordArray; const R: Word): Integer; overload; function Append(var V: LongWordArray; const R: LongWord): Integer; overload; function Append(var V: ShortIntArray; const R: ShortInt): Integer; overload; function Append(var V: SmallIntArray; const R: SmallInt): Integer; overload; function Append(var V: LongIntArray; const R: LongInt): Integer; overload; function Append(var V: Int64Array; const R: Int64): Integer; overload; function Append(var V: SingleArray; const R: Single): Integer; overload; function Append(var V: DoubleArray; const R: Double): Integer; overload; function Append(var V: ExtendedArray; const R: Extended): Integer; overload; function Append(var V: CurrencyArray; const R: Currency): Integer; overload; function Append(var V: StringArray; const R: String): Integer; overload; function Append(var V: WideStringArray; const R: WideString): Integer; overload; function Append(var V: BooleanArray; const R: Boolean): Integer; overload; function Append(var V: PointerArray; const R: Pointer): Integer; overload; function Append(var V: ObjectArray; const R: TObject): Integer; overload; function Append(var V: InterfaceArray; const R: IInterface): Integer; overload; function Append(var V: ByteSetArray; const R: ByteSet): Integer; overload; function Append(var V: CharSetArray; const R: CharSet): Integer; overload; function AppendByteArray(var V: ByteArray; const R: Array of Byte): Integer; overload; function AppendWordArray(var V: WordArray; const R: Array of Word): Integer; overload; function AppendCardinalArray(var V: CardinalArray; const R: Array of LongWord): Integer; overload; function AppendShortIntArray(var V: ShortIntArray; const R: Array of ShortInt): Integer; overload; function AppendSmallIntArray(var V: SmallIntArray; const R: Array of SmallInt): Integer; overload; function AppendIntegerArray(var V: IntegerArray; const R: Array of LongInt): Integer; overload; function AppendInt64Array(var V: Int64Array; const R: Array of Int64): Integer; overload; function AppendSingleArray(var V: SingleArray; const R: Array of Single): Integer; overload; function AppendDoubleArray(var V: DoubleArray; const R: Array of Double): Integer; overload; function AppendExtendedArray(var V: ExtendedArray; const R: Array of Extended): Integer; overload; function AppendCurrencyArray(var V: CurrencyArray; const R: Array of Currency): Integer; overload; function AppendStringArray(var V: StringArray; const R: Array of String): Integer; overload; function AppendPointerArray(var V: PointerArray; const R: Array of Pointer): Integer; overload; function AppendObjectArray(var V: ObjectArray; const R: ObjectArray): Integer; overload; function AppendCharSetArray(var V: CharSetArray; const R: Array of CharSet): Integer; overload; function AppendByteSetArray(var V: ByteSetArray; const R: Array of ByteSet): Integer; overload; function Remove(var V: ByteArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: WordArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: LongWordArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: ShortIntArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: SmallIntArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: LongIntArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: Int64Array; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: SingleArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: DoubleArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: ExtendedArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: CurrencyArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: StringArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: WideStringArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: PointerArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; function Remove(var V: ObjectArray; const Idx: Integer; const Count: Integer = 1; const FreeObjects: Boolean = False): Integer; overload; function Remove(var V: InterfaceArray; const Idx: Integer; const Count: Integer = 1): Integer; overload; procedure RemoveDuplicates(var V: ByteArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: WordArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: LongWordArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: ShortIntArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: SmallIntArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: LongIntArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: Int64Array; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: SingleArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: DoubleArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: ExtendedArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: StringArray; const IsSorted: Boolean); overload; procedure RemoveDuplicates(var V: PointerArray; const IsSorted: Boolean); overload; procedure TrimArrayLeft(var S: ByteArray; const TrimList: Array of Byte); overload; procedure TrimArrayLeft(var S: WordArray; const TrimList: Array of Word); overload; procedure TrimArrayLeft(var S: LongWordArray; const TrimList: Array of LongWord); overload; procedure TrimArrayLeft(var S: ShortIntArray; const TrimList: Array of ShortInt); overload; procedure TrimArrayLeft(var S: SmallIntArray; const TrimList: Array of SmallInt); overload; procedure TrimArrayLeft(var S: LongIntArray; const TrimList: Array of LongInt); overload; procedure TrimArrayLeft(var S: Int64Array; const TrimList: Array of Int64); overload; procedure TrimArrayLeft(var S: SingleArray; const TrimList: Array of Single); overload; procedure TrimArrayLeft(var S: DoubleArray; const TrimList: Array of Double); overload; procedure TrimArrayLeft(var S: ExtendedArray; const TrimList: Array of Extended); overload; procedure TrimArrayLeft(var S: StringArray; const TrimList: Array of String); overload; procedure TrimArrayLeft(var S: PointerArray; const TrimList: Array of Pointer); overload; procedure TrimArrayRight(var S: ByteArray; const TrimList: Array of Byte); overload; procedure TrimArrayRight(var S: WordArray; const TrimList: Array of Word); overload; procedure TrimArrayRight(var S: LongWordArray; const TrimList: Array of LongWord); overload; procedure TrimArrayRight(var S: ShortIntArray; const TrimList: Array of ShortInt); overload; procedure TrimArrayRight(var S: SmallIntArray; const TrimList: Array of SmallInt); overload; procedure TrimArrayRight(var S: LongIntArray; const TrimList: Array of LongInt); overload; procedure TrimArrayRight(var S: Int64Array; const TrimList: Array of Int64); overload; procedure TrimArrayRight(var S: SingleArray; const TrimList: Array of Single); overload; procedure TrimArrayRight(var S: DoubleArray; const TrimList: Array of Double); overload; procedure TrimArrayRight(var S: ExtendedArray; const TrimList: Array of Extended); overload; procedure TrimArrayRight(var S: StringArray; const TrimList: Array of String); overload; procedure TrimArrayRight(var S: PointerArray; const TrimList: Array of Pointer); overload; function ArrayInsert(var V: ByteArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: WordArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: LongWordArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: ShortIntArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: SmallIntArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: LongIntArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: Int64Array; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: SingleArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: DoubleArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: ExtendedArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: CurrencyArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: StringArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: WideStringArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: PointerArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: ObjectArray; const Idx: Integer; const Count: Integer): Integer; overload; function ArrayInsert(var V: InterfaceArray; const Idx: Integer; const Count: Integer): Integer; overload; procedure FreeObjectArray(var V); overload; procedure FreeObjectArray(var V; const LoIdx, HiIdx: Integer); overload; procedure FreeAndNilObjectArray(var V: ObjectArray); function PosNext(const Find: Byte; const V: ByteArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: Word; const V: WordArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: LongWord; const V: LongWordArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: ShortInt; const V: ShortIntArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: SmallInt; const V: SmallIntArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: LongInt; const V: LongIntArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: Int64; const V: Int64Array; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: Single; const V: SingleArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: Double; const V: DoubleArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: Extended; const V: ExtendedArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: Boolean; const V: BooleanArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: String; const V: StringArray; const PrevPos: Integer = -1; const IsSortedAscending: Boolean = False): Integer; overload; function PosNext(const Find: Pointer; const V: PointerArray; const PrevPos: Integer = -1): Integer; overload; function PosNext(const Find: TObject; const V: ObjectArray; const PrevPos: Integer = -1): Integer; overload; function PosNext(const ClassType: TClass; const V: ObjectArray; const PrevPos: Integer = -1): Integer; overload; function PosNext(const ClassName: String; const V: ObjectArray; const PrevPos: Integer = -1): Integer; overload; function Count(const Find: Byte; const V: ByteArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: Word; const V: WordArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: LongWord; const V: LongWordArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: ShortInt; const V: ShortIntArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: SmallInt; const V: SmallIntArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: LongInt; const V: LongIntArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: Int64; const V: Int64Array; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: Single; const V: SingleArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: Double; const V: DoubleArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: Extended; const V: ExtendedArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: String; const V: StringArray; const IsSortedAscending: Boolean = False): Integer; overload; function Count(const Find: Boolean; const V: BooleanArray; const IsSortedAscending: Boolean = False): Integer; overload; procedure RemoveAll(const Find: Byte; var V: ByteArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: Word; var V: WordArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: LongWord; var V: LongWordArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: ShortInt; var V: ShortIntArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: SmallInt; var V: SmallIntArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: LongInt; var V: LongIntArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: Int64; var V: Int64Array; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: Single; var V: SingleArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: Double; var V: DoubleArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: Extended; var V: ExtendedArray; const IsSortedAscending: Boolean = False); overload; procedure RemoveAll(const Find: String; var V: StringArray; const IsSortedAscending: Boolean = False); overload; function Intersection(const V1, V2: ByteArray; const IsSortedAscending: Boolean = False): ByteArray; overload; function Intersection(const V1, V2: WordArray; const IsSortedAscending: Boolean = False): WordArray; overload; function Intersection(const V1, V2: LongWordArray; const IsSortedAscending: Boolean = False): LongWordArray; overload; function Intersection(const V1, V2: ShortIntArray; const IsSortedAscending: Boolean = False): ShortIntArray; overload; function Intersection(const V1, V2: SmallIntArray; const IsSortedAscending: Boolean = False): SmallIntArray; overload; function Intersection(const V1, V2: LongIntArray; const IsSortedAscending: Boolean = False): LongIntArray; overload; function Intersection(const V1, V2: Int64Array; const IsSortedAscending: Boolean = False): Int64Array; overload; function Intersection(const V1, V2: SingleArray; const IsSortedAscending: Boolean = False): SingleArray; overload; function Intersection(const V1, V2: DoubleArray; const IsSortedAscending: Boolean = False): DoubleArray; overload; function Intersection(const V1, V2: ExtendedArray; const IsSortedAscending: Boolean = False): ExtendedArray; overload; function Intersection(const V1, V2: StringArray; const IsSortedAscending: Boolean = False): StringArray; overload; function Difference(const V1, V2: ByteArray; const IsSortedAscending: Boolean = False): ByteArray; overload; function Difference(const V1, V2: WordArray; const IsSortedAscending: Boolean = False): WordArray; overload; function Difference(const V1, V2: LongWordArray; const IsSortedAscending: Boolean = False): LongWordArray; overload; function Difference(const V1, V2: ShortIntArray; const IsSortedAscending: Boolean = False): ShortIntArray; overload; function Difference(const V1, V2: SmallIntArray; const IsSortedAscending: Boolean = False): SmallIntArray; overload; function Difference(const V1, V2: LongIntArray; const IsSortedAscending: Boolean = False): LongIntArray; overload; function Difference(const V1, V2: Int64Array; const IsSortedAscending: Boolean = False): Int64Array; overload; function Difference(const V1, V2: SingleArray; const IsSortedAscending: Boolean = False): SingleArray; overload; function Difference(const V1, V2: DoubleArray; const IsSortedAscending: Boolean = False): DoubleArray; overload; function Difference(const V1, V2: ExtendedArray; const IsSortedAscending: Boolean = False): ExtendedArray; overload; function Difference(const V1, V2: StringArray; const IsSortedAscending: Boolean = False): StringArray; overload; procedure Reverse(var V: ByteArray); overload; procedure Reverse(var V: WordArray); overload; procedure Reverse(var V: LongWordArray); overload; procedure Reverse(var V: ShortIntArray); overload; procedure Reverse(var V: SmallIntArray); overload; procedure Reverse(var V: LongIntArray); overload; procedure Reverse(var V: Int64Array); overload; procedure Reverse(var V: SingleArray); overload; procedure Reverse(var V: DoubleArray); overload; procedure Reverse(var V: ExtendedArray); overload; procedure Reverse(var V: StringArray); overload; procedure Reverse(var V: PointerArray); overload; procedure Reverse(var V: ObjectArray); overload; function AsBooleanArray(const V: Array of Boolean): BooleanArray; overload; function AsByteArray(const V: Array of Byte): ByteArray; overload; function AsWordArray(const V: Array of Word): WordArray; overload; function AsLongWordArray(const V: Array of LongWord): LongWordArray; overload; function AsCardinalArray(const V: Array of Cardinal): CardinalArray; overload; function AsShortIntArray(const V: Array of ShortInt): ShortIntArray; overload; function AsSmallIntArray(const V: Array of SmallInt): SmallIntArray; overload; function AsLongIntArray(const V: Array of LongInt): LongIntArray; overload; function AsIntegerArray(const V: Array of Integer): IntegerArray; overload; function AsInt64Array(const V: Array of Int64): Int64Array; overload; function AsSingleArray(const V: Array of Single): SingleArray; overload; function AsDoubleArray(const V: Array of Double): DoubleArray; overload; function AsExtendedArray(const V: Array of Extended): ExtendedArray; overload; function AsCurrencyArray(const V: Array of Currency): CurrencyArray; overload; function AsStringArray(const V: Array of String): StringArray; overload; function AsWideStringArray(const V: Array of WideString): WideStringArray; overload; function AsPointerArray(const V: Array of Pointer): PointerArray; overload; function AsCharSetArray(const V: Array of CharSet): CharSetArray; overload; function AsObjectArray(const V: Array of TObject): ObjectArray; overload; function AsInterfaceArray(const V: Array of IInterface): InterfaceArray; overload; function RangeByte(const First: Byte; const Count: Integer; const Increment: Byte = 1): ByteArray; function RangeWord(const First: Word; const Count: Integer; const Increment: Word = 1): WordArray; function RangeLongWord(const First: LongWord; const Count: Integer; const Increment: LongWord = 1): LongWordArray; function RangeCardinal(const First: Cardinal; const Count: Integer; const Increment: Cardinal = 1): CardinalArray; function RangeShortInt(const First: ShortInt; const Count: Integer; const Increment: ShortInt = 1): ShortIntArray; function RangeSmallInt(const First: SmallInt; const Count: Integer; const Increment: SmallInt = 1): SmallIntArray; function RangeLongInt(const First: LongInt; const Count: Integer; const Increment: LongInt = 1): LongIntArray; function RangeInteger(const First: Integer; const Count: Integer; const Increment: Integer = 1): IntegerArray; function RangeInt64(const First: Int64; const Count: Integer; const Increment: Int64 = 1): Int64Array; function RangeSingle(const First: Single; const Count: Integer; const Increment: Single = 1): SingleArray; function RangeDouble(const First: Double; const Count: Integer; const Increment: Double = 1): DoubleArray; function RangeExtended(const First: Extended; const Count: Integer; const Increment: Extended = 1): ExtendedArray; function DupByte(const V: Byte; const Count: Integer): ByteArray; function DupWord(const V: Word; const Count: Integer): WordArray; function DupLongWord(const V: LongWord; const Count: Integer): LongWordArray; function DupCardinal(const V: Cardinal; const Count: Integer): CardinalArray; function DupShortInt(const V: ShortInt; const Count: Integer): ShortIntArray; function DupSmallInt(const V: SmallInt; const Count: Integer): SmallIntArray; function DupLongInt(const V: LongInt; const Count: Integer): LongIntArray; function DupInteger(const V: Integer; const Count: Integer): IntegerArray; function DupInt64(const V: Int64; const Count: Integer): Int64Array; function DupSingle(const V: Single; const Count: Integer): SingleArray; function DupDouble(const V: Double; const Count: Integer): DoubleArray; function DupExtended(const V: Extended; const Count: Integer): ExtendedArray; function DupCurrency(const V: Currency; const Count: Integer): CurrencyArray; function DupString(const V: String; const Count: Integer): StringArray; function DupCharSet(const V: CharSet; const Count: Integer): CharSetArray; function DupObject(const V: TObject; const Count: Integer): ObjectArray; procedure SetLengthAndZero(var V: ByteArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: WordArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: LongWordArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: ShortIntArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: SmallIntArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: LongIntArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: Int64Array; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: SingleArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: DoubleArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: ExtendedArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: CurrencyArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: CharSetArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: BooleanArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: PointerArray; const NewLength: Integer); overload; procedure SetLengthAndZero(var V: ObjectArray; const NewLength: Integer; const FreeObjects: Boolean = False); overload; function IsEqual(const V1, V2: ByteArray): Boolean; overload; function IsEqual(const V1, V2: WordArray): Boolean; overload; function IsEqual(const V1, V2: LongWordArray): Boolean; overload; function IsEqual(const V1, V2: ShortIntArray): Boolean; overload; function IsEqual(const V1, V2: SmallIntArray): Boolean; overload; function IsEqual(const V1, V2: LongIntArray): Boolean; overload; function IsEqual(const V1, V2: Int64Array): Boolean; overload; function IsEqual(const V1, V2: SingleArray): Boolean; overload; function IsEqual(const V1, V2: DoubleArray): Boolean; overload; function IsEqual(const V1, V2: ExtendedArray): Boolean; overload; function IsEqual(const V1, V2: CurrencyArray): Boolean; overload; function IsEqual(const V1, V2: StringArray): Boolean; overload; function IsEqual(const V1, V2: CharSetArray): Boolean; overload; function ByteArrayToLongIntArray(const V: ByteArray): LongIntArray; function WordArrayToLongIntArray(const V: WordArray): LongIntArray; function ShortIntArrayToLongIntArray(const V: ShortIntArray): LongIntArray; function SmallIntArrayToLongIntArray(const V: SmallIntArray): LongIntArray; function LongIntArrayToInt64Array(const V: LongIntArray): Int64Array; function LongIntArrayToSingleArray(const V: LongIntArray): SingleArray; function LongIntArrayToDoubleArray(const V: LongIntArray): DoubleArray; function LongIntArrayToExtendedArray(const V: LongIntArray): ExtendedArray; function SingleArrayToDoubleArray(const V: SingleArray): DoubleArray; function SingleArrayToExtendedArray(const V: SingleArray): ExtendedArray; function SingleArrayToCurrencyArray(const V: SingleArray): CurrencyArray; function SingleArrayToLongIntArray(const V: SingleArray): LongIntArray; function SingleArrayToInt64Array(const V: SingleArray): Int64Array; function DoubleArrayToExtendedArray(const V: DoubleArray): ExtendedArray; function DoubleArrayToCurrencyArray(const V: DoubleArray): CurrencyArray; function DoubleArrayToLongIntArray(const V: DoubleArray): LongIntArray; function DoubleArrayToInt64Array(const V: DoubleArray): Int64Array; function ExtendedArrayToCurrencyArray(const V: ExtendedArray): CurrencyArray; function ExtendedArrayToLongIntArray(const V: ExtendedArray): LongIntArray; function ExtendedArrayToInt64Array(const V: ExtendedArray): Int64Array; function ByteArrayFromIndexes(const V: ByteArray; const Indexes: IntegerArray): ByteArray; function WordArrayFromIndexes(const V: WordArray; const Indexes: IntegerArray): WordArray; function LongWordArrayFromIndexes(const V: LongWordArray; const Indexes: IntegerArray): LongWordArray; function CardinalArrayFromIndexes(const V: CardinalArray; const Indexes: IntegerArray): CardinalArray; function ShortIntArrayFromIndexes(const V: ShortIntArray; const Indexes: IntegerArray): ShortIntArray; function SmallIntArrayFromIndexes(const V: SmallIntArray; const Indexes: IntegerArray): SmallIntArray; function LongIntArrayFromIndexes(const V: LongIntArray; const Indexes: IntegerArray): LongIntArray; function IntegerArrayFromIndexes(const V: IntegerArray; const Indexes: IntegerArray): IntegerArray; function Int64ArrayFromIndexes(const V: Int64Array; const Indexes: IntegerArray): Int64Array; function SingleArrayFromIndexes(const V: SingleArray; const Indexes: IntegerArray): SingleArray; function DoubleArrayFromIndexes(const V: DoubleArray; const Indexes: IntegerArray): DoubleArray; function ExtendedArrayFromIndexes(const V: ExtendedArray; const Indexes: IntegerArray): ExtendedArray; function StringArrayFromIndexes(const V: StringArray; const Indexes: IntegerArray): StringArray; procedure Sort(const V: ByteArray); overload; procedure Sort(const V: WordArray); overload; procedure Sort(const V: LongWordArray); overload; procedure Sort(const V: ShortIntArray); overload; procedure Sort(const V: SmallIntArray); overload; procedure Sort(const V: LongIntArray); overload; procedure Sort(const V: Int64Array); overload; procedure Sort(const V: SingleArray); overload; procedure Sort(const V: DoubleArray); overload; procedure Sort(const V: ExtendedArray); overload; procedure Sort(const V: StringArray); overload; procedure Sort(const Key: IntegerArray; const Data: IntegerArray); overload; procedure Sort(const Key: IntegerArray; const Data: Int64Array); overload; procedure Sort(const Key: IntegerArray; const Data: StringArray); overload; procedure Sort(const Key: IntegerArray; const Data: ExtendedArray); overload; procedure Sort(const Key: IntegerArray; const Data: PointerArray); overload; procedure Sort(const Key: StringArray; const Data: IntegerArray); overload; procedure Sort(const Key: StringArray; const Data: Int64Array); overload; procedure Sort(const Key: StringArray; const Data: StringArray); overload; procedure Sort(const Key: StringArray; const Data: ExtendedArray); overload; procedure Sort(const Key: StringArray; const Data: PointerArray); overload; procedure Sort(const Key: ExtendedArray; const Data: IntegerArray); overload; procedure Sort(const Key: ExtendedArray; const Data: Int64Array); overload; procedure Sort(const Key: ExtendedArray; const Data: StringArray); overload; procedure Sort(const Key: ExtendedArray; const Data: ExtendedArray); overload; procedure Sort(const Key: ExtendedArray; const Data: PointerArray); overload; { } { Self testing code } { } procedure SelfTest; implementation {$IFDEF DELPHI}{$IFDEF OS_WIN32}{$IFDEF CPU_INTEL386} {$DEFINE USE_ASM386} {$ENDIF}{$ENDIF}{$ENDIF} { } { Integer } { } function MinI(const A, B: Integer): Integer; begin if A < B then Result := A else Result := B; end; function MaxI(const A, B: Integer): Integer; begin if A > B then Result := A else Result := B; end; function MinC(const A, B: Cardinal): Cardinal; begin if A < B then Result := A else Result := B; end; function MaxC(const A, B: Cardinal): Cardinal; begin if A > B then Result := A else Result := B; end; function Clip(const Value: Integer; const Low, High: Integer): Integer; begin if Value < Low then Result := Low else if Value > High then Result := High else Result := Value; end; function ClipByte(const Value: Integer): Integer; begin if Value < MinByte then Result := MinByte else if Value > MaxByte then Result := MaxByte else Result := Value; end; function ClipWord(const Value: Integer): Integer; begin if Value < MinWord then Result := MinWord else if Value > MaxWord then Result := MaxWord else Result := Value; end; function ClipLongWord(const Value: Int64): LongWord; begin if Value < MinLongWord then Result := MinLongWord else if Value > MaxLongWord then Result := MaxLongWord else Result := LongWord(Value); end; function SumClipI(const A, I: Integer): Integer; begin if I >= 0 then if A >= MaxInteger - I then Result := MaxInteger else Result := A + I else if A <= MinInteger - I then Result := MinInteger else Result := A + I; end; function SumClipC(const A: Cardinal; const I: Integer): Cardinal; var B : Cardinal; begin if I >= 0 then if A >= MaxCardinal - Cardinal(I) then Result := MaxCardinal else Result := A + Cardinal(I) else begin B := Cardinal(-I); if A <= B then Result := 0 else Result := A - B; end; end; function InByteRange(const A: Int64): Boolean; begin Result := (A >= MinByte) and (A <= MaxByte); end; function InWordRange(const A: Int64): Boolean; begin Result := (A >= MinWord) and (A <= MaxWord); end; function InLongWordRange(const A: Int64): Boolean; begin Result := (A >= MinLongWord) and (A <= MaxLongWord); end; function InShortIntRange(const A: Int64): Boolean; begin Result := (A >= MinShortInt) and (A <= MaxShortInt); end; function InSmallIntRange(const A: Int64): Boolean; begin Result := (A >= MinSmallInt) and (A <= MaxSmallInt); end; function InLongIntRange(const A: Int64): Boolean; begin Result := (A >= MinLongInt) and (A <= MaxLongInt); end; { } { Real } { } function MinF(const A, B: Extended): Extended; begin if A < B then Result := A else Result := B; end; function MaxF(const A, B: Extended): Extended; begin if A > B then Result := A else Result := B; end; function ClipF(const Value: Extended; const Low, High: Extended): Extended; begin if Value < Low then Result := Low else if Value > High then Result := High else Result := Value; end; function InSingleRange(const A: Extended): Boolean; var B : Extended; begin B := Abs(A); Result := (B >= MinSingle) and (B <= MaxSingle); end; function InDoubleRange(const A: Extended): Boolean; var B : Extended; begin B := Abs(A); Result := (B >= MinDouble) and (B <= MaxDouble); end; function InCurrencyRange(const A: Extended): Boolean; begin Result := (A >= MinCurrency) and (A <= MaxCurrency); end; function InCurrencyRange(const A: Int64): Boolean; begin Result := (A >= MinCurrency) and (A <= MaxCurrency); end; { } { Bit functions } { } { Assembly versions of ReverseBits and SwapEndian taken from the } { Delphi Encryption Compendium by Hagen Reddmann (HaReddmann@aol.com) } {$IFDEF USE_ASM386} function ReverseBits(const Value: LongWord): LongWord; asm BSWAP EAX MOV EDX, EAX AND EAX, 0AAAAAAAAh SHR EAX, 1 AND EDX, 055555555h SHL EDX, 1 OR EAX, EDX MOV EDX, EAX AND EAX, 0CCCCCCCCh SHR EAX, 2 AND EDX, 033333333h SHL EDX, 2 OR EAX, EDX MOV EDX, EAX AND EAX, 0F0F0F0F0h SHR EAX, 4 AND EDX, 00F0F0F0Fh SHL EDX, 4 OR EAX, EDX end; {$ELSE} function ReverseBits(const Value: LongWord): LongWord; var I : Byte; begin Result := 0; For I := 0 to 31 do if Value and BitMaskTable[I] <> 0 then Result := Result or BitMaskTable[31 - I]; end; {$ENDIF} function ReverseBits(const Value: LongWord; const BitCount: Integer): LongWord; var I : Integer; V : LongWord; begin V := Value; Result := 0; For I := 0 to MinI(BitCount, BitsPerLongWord) - 1 do begin Result := (Result shl 1) or (V and 1); V := V shr 1; end; end; {$IFDEF USE_ASM386} function SwapEndian(const Value: LongWord): LongWord; asm XCHG AH, AL ROL EAX, 16 XCHG AH, AL end; {$ELSE} function SwapEndian(const Value: LongWord): LongWord; type Bytes4 = packed record B1, B2, B3, B4 : Byte; end; var Val : Bytes4 absolute Value; Res : Bytes4 absolute Result; begin Res.B4 := Val.B1; Res.B3 := Val.B2; Res.B2 := Val.B3; Res.B1 := Val.B4; end; {$ENDIF} procedure SwapEndianBuf(var Buf; const Count: Integer); var P : PLongWord; I : Integer; begin P := @Buf; For I := 1 to Count do begin P^ := SwapEndian(P^); Inc(P); end; end; {$IFDEF USE_ASM386} function TwosComplement(const Value: LongWord): LongWord; asm NEG EAX end; {$ELSE} function TwosComplement(const Value: LongWord): LongWord; begin Result := not Value + 1; end; {$ENDIF} {$IFDEF USE_ASM386} function RotateLeftBits(const Value: LongWord; const Bits: Byte): LongWord; asm MOV CL, DL ROL EAX, CL end; {$ELSE} function RotateLeftBits(const Value: LongWord; const Bits: Byte): LongWord; var I : Integer; begin Result := Value; For I := 1 to Bits do if Value and $80000000 = 0 then Result := Value shl 1 else Result := (Value shl 1) or 1; end; {$ENDIF} {$IFDEF USE_ASM386} function RotateRightBits(const Value: LongWord; const Bits: Byte): LongWord; asm MOV CL, DL ROL EAX, CL end; {$ELSE} function RotateRightBits(const Value: LongWord; const Bits: Byte): LongWord; var I : Integer; begin Result := Value; For I := 1 to Bits do if Value and 1 = 0 then Result := Value shr 1 else Result := (Value shr 1) or $80000000; end; {$ENDIF} {$IFDEF USE_ASM386} function SetBit(const Value, BitIndex: LongWord): LongWord; asm {$IFOPT R+} CMP BitIndex, BitsPerLongWord JAE @Fin {$ENDIF} OR EAX, DWORD PTR [BitIndex * 4 + BitMaskTable] @Fin: end; {$ELSE} function SetBit(const Value, BitIndex: LongWord): LongWord; begin Result := Value or BitMaskTable[BitIndex]; end; {$ENDIF} {$IFDEF USE_ASM386} function ClearBit(const Value, BitIndex: LongWord): LongWord; asm {$IFOPT R+} CMP BitIndex, BitsPerLongWord JAE @Fin {$ENDIF} MOV ECX, DWORD PTR [BitIndex * 4 + BitMaskTable] NOT ECX AND EAX, ECX @Fin: end; {$ELSE} function ClearBit(const Value, BitIndex: LongWord): LongWord; begin Result := Value and not BitMaskTable[BitIndex]; end; {$ENDIF} {$IFDEF USE_ASM386} function ToggleBit(const Value, BitIndex: LongWord): LongWord; asm {$IFOPT R+} CMP BitIndex, BitsPerLongWord JAE @Fin {$ENDIF} XOR EAX, DWORD PTR [BitIndex * 4 + BitMaskTable] @Fin: end; {$ELSE} function ToggleBit(const Value, BitIndex: LongWord): LongWord; begin Result := Value xor BitMaskTable[BitIndex]; end; {$ENDIF} {$IFDEF USE_ASM386} function IsHighBitSet(const Value: LongWord): Boolean; asm TEST Value, $80000000 SETNZ AL end; {$ELSE} function IsHighBitSet(const Value: LongWord): Boolean; begin Result := Value and $80000000 <> 0; end; {$ENDIF} {$IFDEF USE_ASM386} function IsBitSet(const Value, BitIndex: LongWord): Boolean; asm {$IFOPT R+} CMP BitIndex, BitsPerLongWord JAE @Fin {$ENDIF} MOV ECX, DWORD PTR BitMaskTable [BitIndex * 4] TEST Value, ECX SETNZ AL @Fin: end; {$ELSE} function IsBitSet(const Value, BitIndex: LongWord): Boolean; begin Result := Value and BitMaskTable[BitIndex] <> 0; end; {$ENDIF} {$IFDEF USE_ASM386} function SetBitScanForward(const Value: LongWord): Integer; asm OR EAX, EAX JZ @NoBits BSF EAX, EAX RET @NoBits: MOV EAX, -1 end; function SetBitScanForward(const Value, BitIndex: LongWord): Integer; asm {$IFOPT R+} CMP BitIndex, BitsPerLongWord JAE @@zq {$ENDIF} MOV ECX, BitIndex MOV EDX, $FFFFFFFF SHL EDX, CL AND EDX, EAX JE @@zq BSF EAX, EDX RET @@zq: MOV EAX, -1 end; {$ELSE} function SetBitScanForward(const Value, BitIndex: LongWord): Integer; var I : Byte; begin {$IFOPT R+} if BitIndex < BitsPerLongWord then {$ENDIF} For I := Byte(BitIndex) to 31 do if Value and BitMaskTable[I] <> 0 then begin Result := I; exit; end; Result := -1; end; function SetBitScanForward(const Value: LongWord): Integer; begin Result := SetBitScanForward(Value, 0); end; {$ENDIF} {$IFDEF USE_ASM386} function SetBitScanReverse(const Value: LongWord): Integer; asm OR EAX, EAX JZ @NoBits BSR EAX, EAX RET @NoBits: MOV EAX, -1 end; function SetBitScanReverse(const Value, BitIndex: LongWord): Integer; asm {$IFOPT R+} CMP EDX, BitsPerLongWord JAE @@zq {$ENDIF} LEA ECX, [EDX-31] MOV EDX, $FFFFFFFF NEG ECX SHR EDX, CL AND EDX, EAX JE @@zq BSR EAX, EDX RET @@zq: MOV EAX, -1 end; {$ELSE} function SetBitScanReverse(const Value, BitIndex: LongWord): Integer; var I : Byte; begin {$IFOPT R+} if BitIndex < BitsPerLongWord then {$ENDIF} For I := Byte(BitIndex) downto 0 do if Value and BitMaskTable[I] <> 0 then begin Result := I; exit; end; Result := -1; end; function SetBitScanReverse(const Value: LongWord): Integer; begin Result := SetBitScanReverse(Value, 31); end; {$ENDIF} {$IFDEF USE_ASM386} function ClearBitScanForward(const Value: LongWord): Integer; asm NOT EAX OR EAX, EAX JZ @NoBits BSF EAX, EAX RET @NoBits: MOV EAX, -1 end; function ClearBitScanForward(const Value, BitIndex: LongWord): Integer; asm {$IFOPT R+} CMP EDX, BitsPerLongWord JAE @@zq {$ENDIF} MOV ECX, EDX MOV EDX, $FFFFFFFF NOT EAX SHL EDX, CL AND EDX, EAX JE @@zq BSF EAX, EDX RET @@zq: MOV EAX, -1 end; {$ELSE} function ClearBitScanForward(const Value, BitIndex: LongWord): Integer; var I : Byte; begin {$IFOPT R+} if BitIndex < BitsPerLongWord then {$ENDIF} For I := Byte(BitIndex) to 31 do if Value and BitMaskTable[I] = 0 then begin Result := I; exit; end; Result := -1; end; function ClearBitScanForward(const Value: LongWord): Integer; begin Result := ClearBitScanForward(Value, 0); end; {$ENDIF} {$IFDEF USE_ASM386} function ClearBitScanReverse(const Value: LongWord): Integer; asm NOT EAX OR EAX, EAX JZ @NoBits BSR EAX, EAX RET @NoBits: MOV EAX, -1 end; function ClearBitScanReverse(const Value, BitIndex: LongWord): Integer; asm {$IFOPT R+} CMP EDX, BitsPerLongWord JAE @@zq {$ENDIF} LEA ECX, [EDX-31] MOV EDX, $FFFFFFFF NEG ECX NOT EAX SHR EDX, CL AND EDX, EAX JE @@zq BSR EAX, EDX RET @@zq: MOV EAX, -1 end; {$ELSE} function ClearBitScanReverse(const Value, BitIndex: LongWord): Integer; var I : Byte; begin {$IFOPT R+} if BitIndex < BitsPerLongWord then {$ENDIF} For I := Byte(BitIndex) downto 0 do if Value and BitMaskTable[I] = 0 then begin Result := I; exit; end; Result := -1; end; function ClearBitScanReverse(const Value: LongWord): Integer; begin Result := ClearBitScanReverse(Value, 31); end; {$ENDIF} const BitCountTable : Array[0..255] of Byte = (0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8); {$IFDEF USE_ASM386} function BitCount(const Value: LongWord): LongWord; asm MOVZX EDX, AL MOVZX EDX, BYTE PTR [EDX + BitCountTable] MOVZX ECX, AH ADD DL, BYTE PTR [ECX + BitCountTable] SHR EAX, 16 MOVZX ECX, AH ADD DL, BYTE PTR [ECX + BitCountTable] AND EAX, $FF ADD DL, BYTE PTR [EAX + BitCountTable] MOV AL, DL end; {$ELSE} function BitCount(const Value: LongWord): LongWord; var V : Array[0..3] of Byte absolute Value; begin Result := BitCountTable[V[0]] + BitCountTable[V[1]] + BitCountTable[V[2]] + BitCountTable[V[3]]; end; {$ENDIF} function IsPowerOfTwo(const Value: LongWord): Boolean; begin Result := BitCount(Value) = 1; end; function LowBitMask(const HighBitIndex: LongWord): LongWord; begin {$IFOPT R+} if HighBitIndex >= BitsPerLongWord then Result := 0 else {$ENDIF} Result := BitMaskTable[HighBitIndex] - 1; end; function HighBitMask(const LowBitIndex: LongWord): LongWord; begin {$IFOPT R+} if LowBitIndex >= BitsPerLongWord then Result := 0 else {$ENDIF} Result := not BitMaskTable[LowBitIndex] + 1; end; function RangeBitMask(const LowBitIndex, HighBitIndex: LongWord): LongWord; begin {$IFOPT R+} if (LowBitIndex >= BitsPerLongWord) and (HighBitIndex >= BitsPerLongWord) then begin Result := 0; exit; end; {$ENDIF} Result := $FFFFFFFF; if LowBitIndex > 0 then Result := Result xor (BitMaskTable[LowBitIndex] - 1); if HighBitIndex < 31 then Result := Result xor (not BitMaskTable[HighBitIndex + 1] + 1); end; function SetBitRange(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): LongWord; begin Result := Value or RangeBitMask(LowBitIndex, HighBitIndex); end; function ClearBitRange(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): LongWord; begin Result := Value and not RangeBitMask(LowBitIndex, HighBitIndex); end; function ToggleBitRange(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): LongWord; begin Result := Value xor RangeBitMask(LowBitIndex, HighBitIndex); end; function IsBitRangeSet(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): Boolean; var M: LongWord; begin M := RangeBitMask(LowBitIndex, HighBitIndex); Result := Value and M = M; end; function IsBitRangeClear(const Value: LongWord; const LowBitIndex, HighBitIndex: LongWord): Boolean; begin Result := Value and RangeBitMask(LowBitIndex, HighBitIndex) = 0; end; { } { Sets } { } function AsCharSet(const C: Array of Char): CharSet; var I: Integer; begin Result := []; For I := 0 to High(C) do Include(Result, C[I]); end; function AsByteSet(const C: Array of Byte): ByteSet; var I: Integer; begin Result := []; For I := 0 to High(C) do Include(Result, C[I]); end; {$IFDEF USE_ASM386} procedure ComplementChar(var C: CharSet; const Ch: Char); asm MOVZX ECX, DL BTC [EAX], ECX end; {$ELSE} procedure ComplementChar(var C: CharSet; const Ch: Char); begin if Ch in C then Exclude(C, Ch) else Include(C, Ch); end; {$ENDIF} {$IFDEF USE_ASM386} procedure ClearCharSet(var C: CharSet); asm XOR EDX, EDX MOV [EAX], EDX MOV [EAX + 4], EDX MOV [EAX + 8], EDX MOV [EAX + 12], EDX MOV [EAX + 16], EDX MOV [EAX + 20], EDX MOV [EAX + 24], EDX MOV [EAX + 28], EDX end; {$ELSE} procedure ClearCharSet(var C: CharSet); begin C := []; end; {$ENDIF} {$IFDEF USE_ASM386} procedure FillCharSet(var C: CharSet); asm MOV EDX, $FFFFFFFF MOV [EAX], EDX MOV [EAX + 4], EDX MOV [EAX + 8], EDX MOV [EAX + 12], EDX MOV [EAX + 16], EDX MOV [EAX + 20], EDX MOV [EAX + 24], EDX MOV [EAX + 28], EDX end; {$ELSE} procedure FillCharSet(var C: CharSet); begin C := [#0..#255]; end; {$ENDIF} {$IFDEF USE_ASM386} procedure ComplementCharSet(var C: CharSet); asm NOT DWORD PTR [EAX] NOT DWORD PTR [EAX + 4] NOT DWORD PTR [EAX + 8] NOT DWORD PTR [EAX + 12] NOT DWORD PTR [EAX + 16] NOT DWORD PTR [EAX + 20] NOT DWORD PTR [EAX + 24] NOT DWORD PTR [EAX + 28] end; {$ELSE} procedure ComplementCharSet(var C: CharSet); begin C := [#0..#255] - C; end; {$ENDIF} {$IFDEF USE_ASM386} procedure AssignCharSet(var DestSet: CharSet; const SourceSet: CharSet); asm MOV ECX, [EDX] MOV [EAX], ECX MOV ECX, [EDX + 4] MOV [EAX + 4], ECX MOV ECX, [EDX + 8] MOV [EAX + 8], ECX MOV ECX, [EDX + 12] MOV [EAX + 12], ECX MOV ECX, [EDX + 16] MOV [EAX + 16], ECX MOV ECX, [EDX + 20] MOV [EAX + 20], ECX MOV ECX, [EDX + 24] MOV [EAX + 24], ECX MOV ECX, [EDX + 28] MOV [EAX + 28], ECX end; {$ELSE} procedure AssignCharSet(var DestSet: CharSet; const SourceSet: CharSet); begin DestSet := SourceSet; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Union(var DestSet: CharSet; const SourceSet: CharSet); asm MOV ECX, [EDX] OR [EAX], ECX MOV ECX, [EDX + 4] OR [EAX + 4], ECX MOV ECX, [EDX + 8] OR [EAX + 8], ECX MOV ECX, [EDX + 12] OR [EAX + 12], ECX MOV ECX, [EDX + 16] OR [EAX + 16], ECX MOV ECX, [EDX + 20] OR [EAX + 20], ECX MOV ECX, [EDX + 24] OR [EAX + 24], ECX MOV ECX, [EDX + 28] OR [EAX + 28], ECX end; {$ELSE} procedure Union(var DestSet: CharSet; const SourceSet: CharSet); begin DestSet := DestSet + SourceSet; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Difference(var DestSet: CharSet; const SourceSet: CharSet); asm MOV ECX, [EDX] NOT ECX AND [EAX], ECX MOV ECX, [EDX + 4] NOT ECX AND [EAX + 4], ECX MOV ECX, [EDX + 8] NOT ECX AND [EAX + 8],ECX MOV ECX, [EDX + 12] NOT ECX AND [EAX + 12], ECX MOV ECX, [EDX + 16] NOT ECX AND [EAX + 16], ECX MOV ECX, [EDX + 20] NOT ECX AND [EAX + 20], ECX MOV ECX, [EDX + 24] NOT ECX AND [EAX + 24], ECX MOV ECX, [EDX + 28] NOT ECX AND [EAX + 28], ECX end; {$ELSE} procedure Difference(var DestSet: CharSet; const SourceSet: CharSet); begin DestSet := DestSet - SourceSet; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Intersection(var DestSet: CharSet; const SourceSet: CharSet); asm MOV ECX, [EDX] AND [EAX], ECX MOV ECX, [EDX + 4] AND [EAX + 4], ECX MOV ECX, [EDX + 8] AND [EAX + 8], ECX MOV ECX, [EDX + 12] AND [EAX + 12], ECX MOV ECX, [EDX + 16] AND [EAX + 16], ECX MOV ECX, [EDX + 20] AND [EAX + 20], ECX MOV ECX, [EDX + 24] AND [EAX + 24], ECX MOV ECX, [EDX + 28] AND [EAX + 28], ECX end; {$ELSE} procedure Intersection(var DestSet: CharSet; const SourceSet: CharSet); begin DestSet := DestSet * SourceSet; end; {$ENDIF} {$IFDEF USE_ASM386} procedure XORCharSet(var DestSet: CharSet; const SourceSet: CharSet); asm MOV ECX, [EDX] XOR [EAX], ECX MOV ECX, [EDX + 4] XOR [EAX + 4], ECX MOV ECX, [EDX + 8] XOR [EAX + 8], ECX MOV ECX, [EDX + 12] XOR [EAX + 12], ECX MOV ECX, [EDX + 16] XOR [EAX + 16], ECX MOV ECX, [EDX + 20] XOR [EAX + 20], ECX MOV ECX, [EDX + 24] XOR [EAX + 24], ECX MOV ECX, [EDX + 28] XOR [EAX + 28], ECX end; {$ELSE} procedure XORCharSet(var DestSet: CharSet; const SourceSet: CharSet); var Ch: Char; begin For Ch := #0 to #255 do if Ch in DestSet then begin if Ch in SourceSet then Exclude(DestSet, Ch); end else if Ch in SourceSet then Include(DestSet, Ch); end; {$ENDIF} {$IFDEF USE_ASM386} function IsSubSet(const A, B: CharSet): Boolean; asm MOV ECX, [EDX] NOT ECX AND ECX, [EAX] JNE @Fin0 MOV ECX, [EDX + 4] NOT ECX AND ECX, [EAX + 4] JNE @Fin0 MOV ECX, [EDX + 8] NOT ECX AND ECX, [EAX + 8] JNE @Fin0 MOV ECX, [EDX + 12] NOT ECX AND ECX, [EAX + 12] JNE @Fin0 MOV ECX, [EDX + 16] NOT ECX AND ECX, [EAX + 16] JNE @Fin0 MOV ECX, [EDX + 20] NOT ECX AND ECX, [EAX + 20] JNE @Fin0 MOV ECX, [EDX + 24] NOT ECX AND ECX, [EAX + 24] JNE @Fin0 MOV ECX, [EDX + 28] NOT ECX AND ECX, [EAX + 28] JNE @Fin0 MOV EAX, 1 RET @Fin0: XOR EAX, EAX end; {$ELSE} function IsSubSet(const A, B: CharSet): Boolean; begin Result := A <= B; end; {$ENDIF} {$IFDEF USE_ASM386} function IsEqual(const A, B: CharSet): Boolean; asm MOV ECX, [EDX] XOR ECX, [EAX] JNE @Fin0 MOV ECX, [EDX + 4] XOR ECX, [EAX + 4] JNE @Fin0 MOV ECX, [EDX + 8] XOR ECX, [EAX + 8] JNE @Fin0 MOV ECX, [EDX + 12] XOR ECX, [EAX + 12] JNE @Fin0 MOV ECX, [EDX + 16] XOR ECX, [EAX + 16] JNE @Fin0 MOV ECX, [EDX + 20] XOR ECX, [EAX + 20] JNE @Fin0 MOV ECX, [EDX + 24] XOR ECX, [EAX + 24] JNE @Fin0 MOV ECX, [EDX + 28] XOR ECX, [EAX + 28] JNE @Fin0 MOV EAX, 1 RET @Fin0: XOR EAX, EAX end; {$ELSE} function IsEqual(const A, B: CharSet): Boolean; begin Result := A = B; end; {$ENDIF} {$IFDEF USE_ASM386} function IsEmpty(const C: CharSet): Boolean; asm MOV EDX, [EAX] OR EDX, [EAX + 4] OR EDX, [EAX + 8] OR EDX, [EAX + 12] OR EDX, [EAX + 16] OR EDX, [EAX + 20] OR EDX, [EAX + 24] OR EDX, [EAX + 28] JNE @Fin0 MOV EAX, 1 RET @Fin0: XOR EAX,EAX end; {$ELSE} function IsEmpty(const C: CharSet): Boolean; begin Result := C = []; end; {$ENDIF} {$IFDEF USE_ASM386} function IsComplete(const C: CharSet): Boolean; asm MOV EDX, [EAX] AND EDX, [EAX + 4] AND EDX, [EAX + 8] AND EDX, [EAX + 12] AND EDX, [EAX + 16] AND EDX, [EAX + 20] AND EDX, [EAX + 24] AND EDX, [EAX + 28] CMP EDX, $FFFFFFFF JNE @Fin0 MOV EAX, 1 RET @Fin0: XOR EAX, EAX end; {$ELSE} function IsComplete(const C: CharSet): Boolean; begin Result := C = CompleteCharSet; end; {$ENDIF} {$IFDEF USE_ASM386} function CharCount(const C: CharSet): Integer; asm PUSH EBX PUSH ESI MOV EBX, EAX XOR ESI, ESI MOV EAX, [EBX] CALL BitCount ADD ESI, EAX MOV EAX, [EBX + 4] CALL BitCount ADD ESI, EAX MOV EAX, [EBX + 8] CALL BitCount ADD ESI, EAX MOV EAX, [EBX + 12] CALL BitCount ADD ESI, EAX MOV EAX, [EBX + 16] CALL BitCount ADD ESI, EAX MOV EAX, [EBX + 20] CALL BitCount ADD ESI, EAX MOV EAX, [EBX + 24] CALL BitCount ADD ESI, EAX MOV EAX, [EBX + 28] CALL BitCount ADD EAX, ESI POP ESI POP EBX end; {$ELSE} function CharCount(const C: CharSet): Integer; var I: Char; begin Result := 0; For I := #0 to #255 do if I in C then Inc(Result); end; {$ENDIF} {$IFDEF USE_ASM386} procedure ConvertCaseInsensitive(var C: CharSet); asm MOV ECX, [EAX + 12] AND ECX, $3FFFFFF OR [EAX + 8], ECX MOV ECX, [EAX + 8] AND ECX, $3FFFFFF OR [EAX + 12], ECX end; {$ELSE} procedure ConvertCaseInsensitive(var C: CharSet); var Ch: Char; begin For Ch := 'A' to 'Z' do if Ch in C then Include(C, Char(Ord(Ch) + 32)); For Ch := 'a' to 'z' do if Ch in C then Include(C, Char(Ord(Ch) - 32)); end; {$ENDIF} function CaseInsensitiveCharSet(const C: CharSet): CharSet; begin AssignCharSet(Result, C); ConvertCaseInsensitive(Result); end; { } { Range functions } { } function IntRangeLength(const Low, High: Integer): Int64; begin if Low > High then Result := 0 else Result := Int64(High - Low) + 1; end; function IntRangeAdjacent(const Low1, High1, Low2, High2: Integer): Boolean; begin Result := ((Low2 > MinInteger) and (High1 = Low2 - 1)) or ((High2 < MaxInteger) and (Low1 = High2 + 1)); end; function IntRangeOverlap(const Low1, High1, Low2, High2: Integer): Boolean; begin Result := ((Low1 >= Low2) and (Low1 <= High2)) or ((Low2 >= Low1) and (Low2 <= High1)); end; function IntRangeHasElement(const Low, High, Element: Integer): Boolean; begin Result := (Element >= Low) and (Element <= High); end; function IntRangeIncludeElement(var Low, High: Integer; const Element: Integer): Boolean; begin Result := (Element >= Low) and (Element <= High); if Result then exit; if (Element < Low) and (Element + 1 = Low) then begin Low := Element; Result := True; end else if (Element > High) and (Element - 1 = High) then begin High := Element; Result := True; end; end; function IntRangeIncludeElementRange(var Low, High: Integer; const LowElement, HighElement: Integer): Boolean; begin Result := (LowElement >= Low) and (HighElement <= High); if Result then exit; if ((Low >= LowElement) and (Low <= HighElement)) or ((Low > MinInteger) and (Low - 1 = HighElement)) then begin Low := LowElement; Result := True; end; if ((High >= LowElement) and (High <= HighElement)) or ((High < MaxInteger) and (High + 1 = LowElement)) then begin High := HighElement; Result := True; end; end; function CardinalRangeLength(const Low, High: Cardinal): Int64; begin if Low > High then Result := 0 else Result := Int64(High - Low) + 1; end; function CardinalRangeAdjacent(const Low1, High1, Low2, High2: Cardinal): Boolean; begin Result := ((Low2 > MinCardinal) and (High1 = Low2 - 1)) or ((High2 < MaxCardinal) and (Low1 = High2 + 1)); end; function CardinalRangeOverlap(const Low1, High1, Low2, High2: Cardinal): Boolean; begin Result := ((Low1 >= Low2) and (Low1 <= High2)) or ((Low2 >= Low1) and (Low2 <= High1)); end; function CardinalRangeHasElement(const Low, High, Element: Cardinal): Boolean; begin Result := (Element >= Low) and (Element <= High); end; function CardinalRangeIncludeElement(var Low, High: Cardinal; const Element: Cardinal): Boolean; begin Result := (Element >= Low) and (Element <= High); if Result then exit; if (Element < Low) and (Element + 1 = Low) then begin Low := Element; Result := True; end else if (Element > High) and (Element - 1 = High) then begin High := Element; Result := True; end; end; function CardinalRangeIncludeElementRange(var Low, High: Cardinal; const LowElement, HighElement: Cardinal): Boolean; begin Result := (LowElement >= Low) and (HighElement <= High); if Result then exit; if ((Low >= LowElement) and (Low <= HighElement)) or ((Low > MinCardinal) and (Low - 1 = HighElement)) then begin Low := LowElement; Result := True; end; if ((High >= LowElement) and (High <= HighElement)) or ((High < MaxCardinal) and (High + 1 = LowElement)) then begin High := HighElement; Result := True; end; end; { } { Swap } { } {$IFDEF USE_ASM386} procedure Swap(var X, Y: Boolean); asm mov cl, [edx] xchg byte ptr [eax], cl mov [edx], cl end; {$ELSE} procedure Swap(var X, Y: Boolean); var F: Boolean; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: Byte); asm mov cl, [edx] xchg byte ptr [eax], cl mov [edx], cl end; {$ELSE} procedure Swap(var X, Y: Byte); var F: Byte; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: ShortInt); asm mov cl, [edx] xchg byte ptr [eax], cl mov [edx], cl end; {$ELSE} procedure Swap(var X, Y: ShortInt); var F: ShortInt; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: Word); asm mov cx, [edx] xchg word ptr [eax], cx mov [edx], cx end; {$ELSE} procedure Swap(var X, Y: Word); var F: Word; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: SmallInt); asm mov cx, [edx] xchg word ptr [eax], cx mov [edx], cx end; {$ELSE} procedure Swap(var X, Y: SmallInt); var F: SmallInt; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: LongInt); asm mov ecx, [edx] xchg [eax], ecx mov [edx], ecx end; {$ELSE} procedure Swap(var X, Y: LongInt); var F: LongInt; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: LongWord); asm mov ecx, [edx] xchg [eax], ecx mov [edx], ecx end; {$ELSE} procedure Swap(var X, Y: LongWord); var F: LongWord; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: Pointer); asm mov ecx, [edx] xchg [eax], ecx mov [edx], ecx end; {$ELSE} procedure Swap(var X, Y: Pointer); var F: Pointer; begin F := X; X := Y; Y := F; end; {$ENDIF} {$IFDEF USE_ASM386} procedure Swap(var X, Y: TObject); asm mov ecx, [edx] xchg [eax], ecx mov [edx], ecx end; {$ELSE} procedure Swap(var X, Y: TObject); var F: TObject; begin F := X; X := Y; Y := F; end; {$ENDIF} procedure Swap(var X, Y: Int64); var F: Int64; begin F := X; X := Y; Y := F; end; procedure Swap(var X, Y: Single); var F: Single; begin F := X; X := Y; Y := F; end; procedure Swap(var X, Y: Double); var F: Double; begin F := X; X := Y; Y := F; end; procedure Swap(var X, Y: Extended); var F: Extended; begin F := X; X := Y; Y := F; end; procedure Swap(var X, Y: Currency); var F: Currency; begin F := X; X := Y; Y := F; end; procedure Swap(var X, Y: String); var F: String; begin F := X; X := Y; Y := F; end; procedure Swap(var X, Y: WideString); var F: WideString; begin F := X; X := Y; Y := F; end; {$IFDEF USE_ASM386} procedure SwapObjects(var X, Y); asm mov ecx, [edx] xchg [eax], ecx mov [edx], ecx end; {$ELSE} procedure SwapObjects(var X, Y); var F: TObject; begin F := TObject(X); TObject(X) := TObject(Y); TObject(Y) := F; end; {$ENDIF} { } { iif } { } function iif(const Expr: Boolean; const TrueValue, FalseValue: Integer): Integer; begin if Expr then Result := TrueValue else Result := FalseValue; end; function iif(const Expr: Boolean; const TrueValue, FalseValue: Int64): Int64; begin if Expr then Result := TrueValue else Result := FalseValue; end; function iif(const Expr: Boolean; const TrueValue, FalseValue: Extended): Extended; begin if Expr then Result := TrueValue else Result := FalseValue; end; function iif(const Expr: Boolean; const TrueValue, FalseValue: String): String; begin if Expr then Result := TrueValue else Result := FalseValue; end; function iif(const Expr: Boolean; const TrueValue, FalseValue: TObject): TObject; begin if Expr then Result := TrueValue else Result := FalseValue; end; { } { Compare } { } function ReverseCompareResult(const C: TCompareResult): TCompareResult; begin if C = crLess then Result := crGreater else if C = crGreater then Result := crLess else Result := C; end; function Compare(const I1, I2: Integer): TCompareResult; begin if I1 < I2 then Result := crLess else if I1 > I2 then Result := crGreater else Result := crEqual; end; function Compare(const I1, I2: Int64): TCompareResult; begin if I1 < I2 then Result := crLess else if I1 > I2 then Result := crGreater else Result := crEqual; end; function Compare(const I1, I2: Extended): TCompareResult; begin if I1 < I2 then Result := crLess else if I1 > I2 then Result := crGreater else Result := crEqual; end; function Compare(const I1, I2: Boolean): TCompareResult; begin if I1 = I2 then Result := crEqual else if I1 then Result := crGreater else Result := crLess; end; function Compare(const I1, I2: String): TCompareResult; begin if I1 = I2 then Result := crEqual else if I1 > I2 then Result := crGreater else Result := crLess; end; function WideCompare(const I1, I2: WideString): TCompareResult; begin if I1 = I2 then Result := crEqual else if I1 > I2 then Result := crGreater else Result := crLess; end; { } { Approximate comparison } { } function FloatZero(const A: Extended; const CompareDelta: Extended): Boolean; begin Assert(CompareDelta >= 0.0, 'CompareDelta >= 0.0'); Result := Abs(A) <= CompareDelta; end; function FloatOne(const A: Extended; const CompareDelta: Extended): Boolean; begin Assert(CompareDelta >= 0.0, 'CompareDelta >= 0.0'); Result := Abs(A - 1.0) <= CompareDelta; end; function FloatsEqual(const A, B: Extended; const CompareDelta: Extended): Boolean; begin Assert(CompareDelta >= 0.0, 'CompareDelta >= 0.0'); Result := Abs(A - B) <= CompareDelta; end; function FloatsCompare(const A, B: Extended; const CompareDelta: Extended): TCompareResult; var D: Extended; begin Assert(CompareDelta >= 0.0, 'CompareDelta >= 0.0'); D := A - B; if Abs(D) <= CompareDelta then Result := crEqual else if D >= CompareDelta then Result := crGreater else Result := crLess; end; { } { Scaled approximate comparison } { } { The ApproxEqual and ApproxCompare functions were taken from the freeware } { FltMath unit by Tempest Software, as taken from Knuth, Seminumerical } { Algorithms, 2nd ed., Addison-Wesley, 1981, pp. 217-220. } { } function ApproxEqual(const A, B: Extended; const CompareEpsilon: Double): Boolean; var ExtA : TExtended absolute A; ExtB : TExtended absolute B; ExpA : Word; ExpB : Word; Exp : TExtended; begin ExpA := ExtA.Exponent and $7FFF; ExpB := ExtB.Exponent and $7FFF; if (ExpA = $7FFF) and ((ExtA.Mantissa[1] <> $80000000) or (ExtA.Mantissa[0] <> 0)) then { A is NaN } Result := False else if (ExpB = $7FFF) and ((ExtB.Mantissa[1] <> $80000000) or (ExtB.Mantissa[0] <> 0)) then { B is NaN } Result := False else if (ExpA = $7FFF) or (ExpB = $7FFF) then { A or B is infinity. Use the builtin comparison, which will } { properly account for signed infinities, comparing infinity with } { infinity, or comparing infinity with a finite value. } Result := A = B else begin { We are comparing two finite values, so take the difference and } { compare that against the scaled Epsilon. } Exp.Value := 1.0; if ExpA < ExpB then Exp.Exponent := ExpB else Exp.Exponent := ExpA; Result := Abs(A - B) <= (CompareEpsilon * Exp.Value); end; end; function ApproxCompare(const A, B: Extended; const CompareEpsilon: Double): TCompareResult; var ExtA : TExtended absolute A; ExtB : TExtended absolute B; ExpA : Word; ExpB : Word; Exp : TExtended; D, E : Extended; begin ExpA := ExtA.Exponent and $7FFF; ExpB := ExtB.Exponent and $7FFF; if (ExpA = $7FFF) and ((ExtA.Mantissa[1] <> $80000000) or (ExtA.Mantissa[0] <> 0)) then { A is NaN } Result := crUndefined else if (ExpB = $7FFF) and ((ExtB.Mantissa[1] <> $80000000) or (ExtB.Mantissa[0] <> 0)) then { B is NaN } Result := crUndefined else if (ExpA = $7FFF) or (ExpB = $7FFF) then { A or B is infinity. Use the builtin comparison, which will } { properly account for signed infinities, comparing infinity with } { infinity, or comparing infinity with a finite value. } Result := Compare(A, B) else begin { We are comparing two finite values, so take the difference and } { compare that against the scaled Epsilon. } Exp.Value := 1.0; if ExpA < ExpB then Exp.Exponent := ExpB else Exp.Exponent := ExpA; E := CompareEpsilon * Exp.Value; D := A - B; if Abs(D) <= E then Result := crEqual else if D >= E then Result := crGreater else Result := crLess; end; end; { } { Special floating-point values } { } function FloatIsInfinity(const A: Extended): Boolean; var Ext : TExtended absolute A; begin if Ext.Exponent and $7FFF <> $7FFF then Result := False else Result := (Ext.Mantissa[1] = $80000000) and (Ext.Mantissa[0] = 0); end; function FloatIsNaN(const A: Extended): Boolean; var Ext : TExtended absolute A; begin if Ext.Exponent and $7FFF <> $7FFF then Result := False else Result := (Ext.Mantissa[1] <> $80000000) or (Ext.Mantissa[0] <> 0) end; { } { Base Conversion } { } function LongWordToBase(const I: LongWord; const Digits, Base: Byte; const UpperCase: Boolean = True): String; var D : LongWord; L : Byte; P : PChar; V : Byte; begin Assert(Base <= 16, 'Maximum base is 16'); if I = 0 then begin if Digits = 0 then L := 1 else L := Digits; SetLength(Result, L); FillChar(Pointer(Result)^, L, '0'); exit; end; L := 0; D := I; While D > 0 do begin Inc(L); D := D div Base; end; if L < Digits then L := Digits; SetLength(Result, L); P := Pointer(Result); Inc(P, L - 1); D := I; While D > 0 do begin V := D mod Base + 1; if UpperCase then P^ := s_HexDigitsUpper[V] else P^ := s_HexDigitsLower[V]; Dec(P); Dec(L); D := D div Base; end; While L > 0 do begin P^ := '0'; Dec(P); Dec(L); end; end; function LongWordToBin(const I: LongWord; const Digits: Byte): String; begin Result := LongWordToBase(I, Digits, 2); end; function LongWordToOct(const I: LongWord; const Digits: Byte): String; begin Result := LongWordToBase(I, Digits, 8); end; function LongWordToHex(const I: LongWord; const Digits: Byte; const UpperCase: Boolean): String; begin Result := LongWordToBase(I, Digits, 16, UpperCase); end; function LongWordToStr(const I: LongWord; const Digits: Byte): String; begin Result := LongWordToBase(I, Digits, 10); end; const HexLookup: Array[Char] of Byte = ( $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, $FF, $FF, $FF, $FF, $FF, $FF, $FF, 10, 11, 12, 13, 14, 15, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, 10, 11, 12, 13, 14, 15, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF); function IsHexChar(const Ch: Char): Boolean; begin Result := HexLookup[Ch] <= 15; end; function IsHexWideChar(const Ch: WideChar): Boolean; begin if Ord(Ch) <= $FF then Result := HexLookup[Char(Ch)] <= 15 else Result := False; end; function HexCharValue(const Ch: Char): Byte; begin Result := HexLookup[Ch]; end; function HexWideCharValue(const Ch: WideChar): Byte; begin if Ord(Ch) <= $FF then Result := HexLookup[Char(Ch)] else Result := $FF; end; function IsValidBaseStr(const S: String; const V: CharSet): Boolean; var I : Integer; P : PChar; begin I := Length(S); if I = 0 then begin Result := False; exit; end; P := Pointer(S); While I > 0 do if not (P^ in V) then begin Result := False; exit; end else begin Dec(I); Inc(P); end; Result := True; end; function IsValidBinStr(const S: String): Boolean; begin Result := IsValidBaseStr(S, ['0'..'1']); end; function IsValidOctStr(const S: String): Boolean; begin Result := IsValidBaseStr(S, ['0'..'7']); end; function IsValidDecStr(const S: String): Boolean; begin Result := IsValidBaseStr(S, ['0'..'9']); end; function IsValidHexStr(const S: String): Boolean; begin Result := IsValidBaseStr(S, ['0'..'9', 'A'..'F', 'a'..'f']); end; function BaseStrToLongWord(const S: String; const BaseLog2: Byte; var Valid: Boolean): LongWord; var M : Byte; L : LongWord; P : Byte; C : Byte; Q : PChar; begin Assert(BaseLog2 <= 4, 'BaseLog2 <= 4'); P := Length(S); if P = 0 then // empty string is invalid begin Valid := False; Result := 0; exit; end; M := (1 shl BaseLog2) - 1; // maximum digit value L := 0; Result := 0; Q := Pointer(S); Inc(Q, P - 1); Repeat C := HexLookup[Q^]; if C > M then // invalid digit begin Valid := False; Result := 0; exit; end; Inc(Result, LongWord(C) shl L); Inc(L, BaseLog2); if L > 32 then // overflow begin Valid := False; Result := 0; exit; end; Dec(P); Dec(Q); Until P = 0; Valid := True; end; function BinStrToLongWord(const S: String; var Valid: Boolean): LongWord; begin Result := BaseStrToLongWord(S, 1, Valid); end; function OctStrToLongWord(const S: String; var Valid: Boolean): LongWord; begin Result := BaseStrToLongWord(S, 3, Valid); end; function HexStrToLongWord(const S: String; var Valid: Boolean): LongWord; begin Result := BaseStrToLongWord(S, 4, Valid); end; function DecStrToLongWord(const S: String; var Valid: Boolean): LongWord; var L : Integer; P : PChar; C : Char; F : LongWord; R : Int64; begin L := Length(S); if L = 0 then // empty string begin Result := 0; Valid := False; exit; end; R := 0; F := 1; P := Pointer(S); Inc(P, L - 1); Repeat C := P^; if not (C in ['0'..'9']) then // invalid character begin Valid := False; Result := 0; exit; end; Inc(R, Int64(Ord(C) - Ord('0')) * F); if R > MaxLongWord then // overflow, value too large begin Valid := False; Result := 0; exit; end; Dec(P); Dec(L); if L > 0 then begin if F = 1000000000 then // overflow, too many digits begin Valid := False; Result := 0; exit; end; F := F * 10; end; Until L = 0; Valid := True; Result := LongWord(R); end; function EncodeBase64(const S, Alphabet: String; const Pad: Boolean; const PadMultiple: Integer; const PadChar: Char): String; var R, C : Byte; F, L, M, N, U : Integer; P : PChar; T : Boolean; begin Assert(Length(Alphabet) = 64, 'Alphabet must contain 64 characters'); L := Length(S); if L = 0 then begin Result := ''; exit; end; M := L mod 3; N := (L div 3) * 4 + M; if M > 0 then Inc(N); T := Pad and (PadMultiple > 1); if T then begin U := N mod PadMultiple; if U > 0 then begin U := PadMultiple - U; Inc(N, U); end; end else U := 0; SetLength(Result, N); P := Pointer(Result); R := 0; For F := 0 to L - 1 do begin C := Byte(S [F + 1]); Case F mod 3 of 0 : begin P^ := Alphabet[C shr 2 + 1]; Inc(P); R := (C and 3) shl 4; end; 1 : begin P^ := Alphabet[C shr 4 + R + 1]; Inc(P); R := (C and $0F) shl 2; end; 2 : begin P^ := Alphabet[C shr 6 + R + 1]; Inc(P); P^ := Alphabet[C and $3F + 1]; Inc(P); end; end; end; if M > 0 then begin P^ := Alphabet[R + 1]; Inc(P); end; For F := 1 to U do begin P^ := PadChar; Inc(P); end; end; function DecodeBase64(const S, Alphabet: String; const PadSet: CharSet): String; var F, L, M, P : Integer; B, OutPos : Byte; OutB : Array[1..3] of Byte; Lookup : Array[Char] of Byte; R : PChar; begin Assert(Length(Alphabet) = 64, 'Alphabet must contain 64 characters'); L := Length(S); P := 0; if PadSet <> [] then While (L - P > 0) and (S[L - P] in PadSet) do Inc(P); M := L - P; if M = 0 then begin Result := ''; exit; end; SetLength(Result, (M * 3) div 4); FillChar(Lookup, Sizeof(Lookup), #0); For F := 0 to 63 do Lookup[Alphabet[F + 1]] := Byte(F); R := Pointer(Result); OutPos := 0; For F := 1 to L - P do begin B := Lookup[S[F]]; Case OutPos of 0 : OutB[1] := B shl 2; 1 : begin OutB[1] := OutB[1] or (B shr 4); R^ := Char(OutB[1]); Inc(R); OutB[2] := (B shl 4) and $FF; end; 2 : begin OutB[2] := OutB[2] or (B shr 2); R^ := Char(OutB[2]); Inc(R); OutB[3] := (B shl 6) and $FF; end; 3 : begin OutB[3] := OutB[3] or B; R^ := Char(OutB[3]); Inc(R); end; end; OutPos := (OutPos + 1) mod 4; end; if (OutPos > 0) and (P = 0) then // incomplete encoding, add the partial byte if not 0 if OutB[OutPos] <> 0 then Result := Result + Char(OutB[OutPos]); end; function MIMEBase64Encode(const S: String): String; begin Result := EncodeBase64(S, b64_MIMEBase64, True, 4, '='); end; function UUDecode(const S: String): String; begin // Line without size indicator (first byte = length + 32) Result := DecodeBase64(S, b64_UUEncode, ['`']); end; function MIMEBase64Decode(const S: String): String; begin Result := DecodeBase64(S, b64_MIMEBase64, ['=']); end; function XXDecode(const S: String): String; begin Result := DecodeBase64(S, b64_XXEncode, []); end; function BytesToHex(const P: Pointer; const Count: Integer; const UpperCase: Boolean): String; var Q : PByte; D : PChar; L : Integer; V : Byte; begin Q := P; L := Count; if (L <= 0) or not Assigned(Q) then begin Result := ''; exit; end; SetLength(Result, Count * 2); D := Pointer(Result); While L > 0 do begin V := Q^ shr 4 + 1; if UpperCase then D^ := s_HexDigitsUpper[V] else D^ := s_HexDigitsLower[V]; Inc(D); V := Q^ and $F + 1; if UpperCase then D^ := s_HexDigitsUpper[V] else D^ := s_HexDigitsLower[V]; Inc(D); Inc(Q); Dec(L); end; end; { } { Type conversion } { } function PointerToStr(const P: Pointer): String; begin Result := '$' + LongWordToHex(LongWord(P), 8); end; function StrToPointer(const S: String): Pointer; var V : Boolean; begin Result := Pointer(HexStrToLongWord(S, V)); end; function ObjectClassName(const O: TObject): String; begin if not Assigned(O) then Result := 'nil' else Result := O.ClassName; end; function ClassClassName(const C: TClass): String; begin if not Assigned(C) then Result := 'nil' else Result := C.ClassName; end; function ObjectToStr(const O: TObject): String; begin if not Assigned(O) then Result := 'nil' else Result := O.ClassName + '@' + LongWordToHex(LongWord(O), 8); end; function ClassToStr(const C: TClass): String; begin if not Assigned(C) then Result := 'nil' else Result := C.ClassName + '@' + LongWordToHex(LongWord(C), 8); end; {$IFDEF USE_ASM386} function CharSetToStr(const C: CharSet): String; // Andrew N. Driazgov asm PUSH EBX MOV ECX, $100 MOV EBX, EAX PUSH ESI MOV EAX, EDX SUB ESP, ECX XOR ESI, ESI XOR EDX, EDX @@lp: BT [EBX], EDX JC @@mm @@nx: INC EDX DEC ECX JNE @@lp MOV ECX, ESI MOV EDX, ESP CALL System.@LStrFromPCharLen ADD ESP, $100 POP ESI POP EBX RET @@mm: MOV [ESP + ESI], DL INC ESI JMP @@nx end; {$ELSE} function CharSetToStr(const C: CharSet): String; // Implemented recursively to avoid multiple memory allocations procedure CharMatch(const Start: Char; const Count: Integer); var Ch : Char; begin For Ch := Start to #255 do if Ch in C then begin if Ch = #255 then SetLength(Result, Count + 1) else CharMatch(Char(Byte(Ch) + 1), Count + 1); Result[Count + 1] := Ch; exit; end; SetLength(Result, Count); end; begin CharMatch(#0, 0); end; {$ENDIF} {$IFDEF USE_ASM386} function StrToCharSet(const S: String): CharSet; // Andrew N. Driazgov asm XOR ECX, ECX MOV [EDX], ECX MOV [EDX + 4], ECX MOV [EDX + 8], ECX MOV [EDX + 12], ECX MOV [EDX + 16], ECX MOV [EDX + 20], ECX MOV [EDX + 24], ECX MOV [EDX + 28], ECX TEST EAX, EAX JE @@qt MOV ECX, [EAX - 4] PUSH EBX SUB ECX, 8 JS @@nx @@lp: MOVZX EBX, BYTE PTR [EAX] BTS [EDX], EBX MOVZX EBX, BYTE PTR [EAX + 1] BTS [EDX], EBX MOVZX EBX, BYTE PTR [EAX + 2] BTS [EDX], EBX MOVZX EBX, BYTE PTR [EAX + 3] BTS [EDX], EBX MOVZX EBX, BYTE PTR [EAX + 4] BTS [EDX], EBX MOVZX EBX, BYTE PTR [EAX + 5] BTS [EDX], EBX MOVZX EBX, BYTE PTR [EAX + 6] BTS [EDX], EBX MOVZX EBX, BYTE PTR [EAX + 7] BTS [EDX], EBX ADD EAX, 8 SUB ECX, 8 JNS @@lp @@nx: JMP DWORD PTR @@tV[ECX * 4 + 32] @@tV: DD @@ex, @@t1, @@t2, @@t3 DD @@t4, @@t5, @@t6, @@t7 @@t7: MOVZX EBX, BYTE PTR [EAX + 6] BTS [EDX], EBX @@t6: MOVZX EBX, BYTE PTR [EAX + 5] BTS [EDX], EBX @@t5: MOVZX EBX, BYTE PTR [EAX + 4] BTS [EDX], EBX @@t4: MOVZX EBX, BYTE PTR [EAX + 3] BTS [EDX], EBX @@t3: MOVZX EBX, BYTE PTR [EAX + 2] BTS [EDX], EBX @@t2: MOVZX EBX, BYTE PTR [EAX + 1] BTS [EDX], EBX @@t1: MOVZX EBX, BYTE PTR [EAX] BTS [EDX], EBX @@ex: POP EBX @@qt: end; {$ELSE} function StrToCharSet(const S: String): CharSet; var I: Integer; begin ClearCharSet(Result); For I := 1 to Length(S) do Include(Result, S [I]); end; {$ENDIF} { } { Hash functions } { Derived from a CRC32 algorithm. } { } var HashTableInit : Boolean = False; HashTable : Array[Byte] of LongWord; HashTableNoCase : Array[Byte] of LongWord; HashPoly : LongWord = $EDB88320; procedure InitHashTable; var I, J : Byte; R : LongWord; begin For I := $00 to $FF do begin R := I; For J := 8 downto 1 do if R and 1 <> 0 then R := (R shr 1) xor HashPoly else R := R shr 1; HashTable[I] := R; end; Move(HashTable, HashTableNoCase, Sizeof(HashTable)); For I := Ord('A') to Ord('Z') do HashTableNoCase[I] := HashTableNoCase[I or 32]; HashTableInit := True; end; function Hash(const Hash: LongWord; const Buf; const BufSize: Integer): LongWord; var P : PByte; I : Integer; begin P := @Buf; Result := Hash; For I := 1 to BufSize do begin Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); Inc(P); end; end; function HashNoCase(const Hash: LongWord; const Buf; const BufSize: Integer): LongWord; var P : PByte; I : Integer; begin P := @Buf; Result := Hash; For I := 1 to BufSize do begin Result := HashTableNoCase[P^] xor (Result shr 8); Inc(P); end; end; function HashBuf(const Buf; const BufSize: Integer; const Slots: LongWord): LongWord; begin if not HashTableInit then InitHashTable; Result := not Hash($FFFFFFFF, Buf, BufSize); // Mod into slots if Slots <> 0 then Result := Result mod Slots; end; function HashStrBuf(const StrBuf: Pointer; const StrLength: Integer; const Slots: LongWord): LongWord; var P : PChar; I, J : Integer; begin if not HashTableInit then InitHashTable; P := StrBuf; if StrLength <= 48 then // Hash all characters for short strings Result := Hash($FFFFFFFF, P^, StrLength) else begin // Hash first 16 bytes Result := Hash($FFFFFFFF, P^, 16); // Hash last 16 bytes Inc(P, StrLength - 16); Result := Hash(Result, P^, 16); // Hash 16 bytes sampled from rest of string I := (StrLength - 48) div 16; P := StrBuf; Inc(P, 16); For J := 1 to 16 do begin Result := HashTable[Byte(Result) xor Byte(P^)] xor (Result shr 8); Inc(P, I + 1); end; end; // Mod into slots if Slots <> 0 then Result := Result mod Slots; end; function HashStrBufNoCase(const StrBuf: Pointer; const StrLength: Integer; const Slots: LongWord): LongWord; var P : PChar; I, J : Integer; begin if not HashTableInit then InitHashTable; P := StrBuf; if StrLength <= 48 then // Hash all characters for short strings Result := HashNoCase($FFFFFFFF, P^, StrLength) else begin // Hash first 16 bytes Result := HashNoCase($FFFFFFFF, P^, 16); // Hash last 16 bytes Inc(P, StrLength - 16); Result := HashNoCase(Result, P^, 16); // Hash 16 bytes sampled from rest of string I := (StrLength - 48) div 16; P := StrBuf; Inc(P, 16); For J := 1 to 16 do begin Result := HashTableNoCase[Byte(P^)] xor (Result shr 8); Inc(P, I + 1); end; end; // Mod into slots if Slots <> 0 then Result := Result mod Slots; end; function HashStr(const S: String; const Slots: LongWord; const CaseSensitive: Boolean): LongWord; begin if CaseSensitive then Result := HashStrBuf(Pointer(S), Length(S), Slots) else Result := HashStrBufNoCase(Pointer(S), Length(S), Slots); end; { HashInteger based on the CRC32 algorithm. It is a very good all purpose hash } { with a highly uniform distribution of results. } function HashInteger(const I: Integer; const Slots: LongWord): LongWord; var P : PByte; begin if not HashTableInit then InitHashTable; Result := $FFFFFFFF; P := @I; Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); Inc(P); Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); Inc(P); Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); Inc(P); Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); if Slots <> 0 then Result := Result mod Slots; end; function HashLongWord(const I: LongWord; const Slots: LongWord): LongWord; var P : PByte; begin if not HashTableInit then InitHashTable; Result := $FFFFFFFF; P := @I; Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); Inc(P); Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); Inc(P); Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); Inc(P); Result := HashTable[Byte(Result) xor P^] xor (Result shr 8); if Slots <> 0 then Result := Result mod Slots; end; { } { Memory } { } {$IFDEF USE_ASM386} procedure FillMem(var Buf; const Count: Integer; const Value: Byte); asm OR EDX, EDX JLE @Fin PUSH EDI MOV EDI, EAX MOV CH, CL MOV EAX, ECX SHL EAX, 16 MOV AX, CX CMP EDX, 12 JBE @SmallFillMem @GeneralFillMem: MOV ECX, EDX SHR ECX, 2 REP STOSD AND EDX, 3 @SmallFillMem: JMP DWORD PTR @JumpTable[EDX * 4] @JumpTable: DD @Fill0, @Fill1, @Fill2, @Fill3 DD @Fill4, @Fill5, @Fill6, @Fill7 DD @Fill8, @Fill9, @Fill10, @Fill11 DD @Fill12 @Fill12: MOV DWORD PTR [EDI], EAX MOV DWORD PTR [EDI + 4], EAX MOV DWORD PTR [EDI + 8], EAX POP EDI RET @Fill11: MOV BYTE PTR [EDI + 10], AL @Fill10: MOV DWORD PTR [EDI], EAX MOV DWORD PTR [EDI + 4], EAX MOV WORD PTR [EDI + 8], AX POP EDI RET @Fill9: MOV BYTE PTR [EDI + 8], AL @Fill8: MOV DWORD PTR [EDI], EAX MOV DWORD PTR [EDI + 4], EAX POP EDI RET @Fill7: MOV BYTE PTR [EDI + 6], AL @Fill6: MOV DWORD PTR [EDI], EAX MOV WORD PTR [EDI + 4], AX POP EDI RET @Fill5: MOV BYTE PTR [EDI + 4], AL @Fill4: MOV DWORD PTR [EDI], EAX POP EDI RET @Fill3: MOV BYTE PTR [EDI + 2], AL @Fill2: MOV WORD PTR [EDI], AX POP EDI RET @Fill1: MOV BYTE PTR [EDI], AL @Fill0: POP EDI @Fin: RET end; {$ELSE} procedure FillMem(var Buf; const Count: Integer; const Value: Byte); begin FillChar(Buf, Count, Value); end; {$ENDIF} {$IFDEF USE_ASM386} procedure ZeroMem(var Buf; const Count: Integer); asm OR EDX, EDX JLE @Zero0 CMP EDX, 12 JA @GeneralZeroMem XOR ECX, ECX JMP DWORD PTR @JumpTable[EDX * 4] @JumpTable: DD @Zero0, @Zero1, @Zero2, @Zero3 DD @Zero4, @Zero5, @Zero6, @Zero7 DD @Zero8, @Zero9, @Zero10, @Zero11 DD @Zero12 @Zero12: MOV DWORD PTR [EAX], ECX MOV DWORD PTR [EAX + 4], ECX MOV DWORD PTR [EAX + 8], ECX RET @Zero11: MOV BYTE PTR [EAX + 10], CL @Zero10: MOV DWORD PTR [EAX], ECX MOV DWORD PTR [EAX + 4], ECX MOV WORD PTR [EAX + 8], CX RET @Zero9: MOV BYTE PTR [EAX + 8], CL @Zero8: MOV DWORD PTR [EAX], ECX MOV DWORD PTR [EAX + 4], ECX RET @Zero7: MOV BYTE PTR [EAX + 6], CL @Zero6: MOV DWORD PTR [EAX], ECX MOV WORD PTR [EAX + 4], CX RET @Zero5: MOV BYTE PTR [EAX + 4], CL @Zero4: MOV DWORD PTR [EAX], ECX RET @Zero3: MOV BYTE PTR [EAX + 2], CL @Zero2: MOV WORD PTR [EAX], CX RET @Zero1: MOV BYTE PTR [EAX], CL @Zero0: RET @GeneralZeroMem: PUSH EDI MOV EDI, EAX XOR EAX, EAX MOV ECX, EDX SHR ECX, 2 REP STOSD AND EDX, 3 XOR ECX, ECX MOV EAX, EDI POP EDI JMP DWORD PTR @JumpTable[EDX * 4] end; {$ELSE} procedure ZeroMem(var Buf; const Count: Integer); begin FillChar(Buf, Count, #0); end; {$ENDIF} {$IFDEF USE_ASM386} procedure MoveMem(const Source; var Dest; const Count: Integer); asm OR ECX, ECX JLE @Move0 CMP ECX, 10 JA @GeneralMove JMP DWORD PTR @JumpTable[ECX * 4] @JumpTable: DD @Move0, @Move1, @Move2, @Move3 DD @Move4, @Move5, @Move6, @GeneralMove DD @Move8, @GeneralMove, @Move10, @GeneralMove DD @Move12 @Move12: MOV ECX, [EAX] MOV [EDX], ECX MOV ECX, [EAX + 4] MOV EAX, [EAX + 8] MOV [EDX + 4], ECX MOV [EDX + 8], EAX RET @Move10: MOV ECX, [EAX] MOV [EDX], ECX MOV ECX, [EAX + 4] MOV AX, [EAX + 8] MOV [EDX + 4], ECX MOV [EDX + 8], AX RET @Move8: MOV ECX, [EAX] MOV EAX, [EAX + 4] MOV [EDX], ECX MOV [EDX + 4], EAX RET @Move6: MOV ECX, [EAX] MOV AX, [EAX + 4] MOV [EDX], ECX MOV [EDX + 4], AX RET @Move5: MOV ECX, [EAX] MOV AL, [EAX + 4] MOV [EDX], ECX MOV [EDX + 4], AL RET @Move4: MOV ECX, [EAX] MOV [EDX], ECX RET @Move3: MOV CX, [EAX] MOV AL, [EAX + 2] MOV [EDX], CX MOV [EDX + 2], AL RET @Move2: MOV CX, [EAX] MOV [EDX], CX RET @Move1: MOV CL, [EAX] MOV [EDX], CL RET @GeneralMove: CALL Move @Move0: RET end; {$ELSE} procedure MoveMem(const Source; var Dest; const Count: Integer); begin if Count <= 0 then exit; if Count > 4 then Move(Source, Dest, Count) else Case Count of // optimization for small moves 1 : PByte(@Dest)^ := PByte(@Source)^; 2 : PWord(@Dest)^ := PWord(@Source)^; 4 : PLongWord(@Dest)^ := PLongWord(@Source)^; else Move(Source, Dest, Count); end; end; {$ENDIF} {$IFDEF USE_ASM386} function CompareMem(const Buf1; const Buf2; const Count: Integer): Boolean; assembler; asm PUSH ESI PUSH EDI MOV ESI, Buf1 MOV EDI, Buf2 MOV EDX, ECX XOR EAX, EAX AND EDX, 3 SHR ECX, 1 SHR ECX, 1 REPE CMPSD JNE @Fin MOV ECX, EDX REPE CMPSB JNE @Fin INC EAX @Fin: POP EDI POP ESI end; {$ELSE} function CompareMem(const Buf1; const Buf2; const Count: Integer): Boolean; var P, Q : Pointer; D, I : Integer; begin if Count <= 0 then begin Result := True; exit; end; P := @Buf1; Q := @Buf2; D := LongWord(Count) div 4; For I := 1 to D do if PLongWord(P)^ = PLongWord(Q)^ then begin Inc(PLongWord(P)); Inc(PLongWord(Q)); end else begin Result := False; exit; end; D := LongWord(Count) and 3; For I := 1 to D do if PByte(P)^ = PByte(Q)^ then begin Inc(PByte(P)); Inc(PByte(Q)); end else begin Result := False; exit; end; Result := True; end; {$ENDIF} function CompareMemNoCase(const Buf1; const Buf2; const Count: Integer): TCompareResult; var P, Q : Pointer; I : Integer; C, D : Byte; begin if Count <= 0 then begin Result := crEqual; exit; end; P := @Buf1; Q := @Buf2; For I := 1 to Count do begin C := PByte(P)^; D := PByte(Q)^; if C in [Ord('A')..Ord('Z')] then C := C or 32; if D in [Ord('A')..Ord('Z')] then D := D or 32; if C = D then begin Inc(PByte(P)); Inc(PByte(Q)); end else begin if C < D then Result := crLess else Result := crGreater; exit; end; end; Result := crEqual; end; procedure ReverseMem(var Buf; const Size: Integer); var I : Integer; P : PByte; Q : PByte; T : Byte; begin P := @Buf; Q := P; Inc(Q, Size - 1); For I := 1 to Size div 2 do begin T := P^; P^ := Q^; Q^ := T; Inc(P); Dec(Q); end; end; { } { Append } { } function Append(var V: ByteArray; const R: Byte): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: WordArray; const R: Word): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: LongWordArray; const R: LongWord): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: ShortIntArray; const R: ShortInt): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: SmallIntArray; const R: SmallInt): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: LongIntArray; const R: LongInt): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: Int64Array; const R: Int64): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: SingleArray; const R: Single): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: DoubleArray; const R: Double): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: ExtendedArray; const R: Extended): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: CurrencyArray; const R: Currency): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: StringArray; const R: String): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: WideStringArray; const R: WideString): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: BooleanArray; const R: Boolean): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: PointerArray; const R: Pointer): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: ObjectArray; const R: TObject): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: InterfaceArray; const R: IInterface): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: ByteSetArray; const R: ByteSet): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function Append(var V: CharSetArray; const R: CharSet): Integer; begin Result := Length(V); SetLength(V, Result + 1); V[Result] := R; end; function AppendByteArray(var V: ByteArray; const R: Array of Byte): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Byte) * L); end; end; function AppendWordArray(var V: WordArray; const R: Array of Word): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Word) * L); end; end; function AppendCardinalArray(var V: CardinalArray; const R: Array of LongWord): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(LongWord) * L); end; end; function AppendShortIntArray(var V: ShortIntArray; const R: Array of ShortInt): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(ShortInt) * L); end; end; function AppendSmallIntArray(var V: SmallIntArray; const R: Array of SmallInt): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(SmallInt) * L); end; end; function AppendIntegerArray(var V: IntegerArray; const R: Array of LongInt): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(LongInt) * L); end; end; function AppendInt64Array(var V: Int64Array; const R: Array of Int64): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Int64) * L); end; end; function AppendSingleArray(var V: SingleArray; const R: Array of Single): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Single) * L); end; end; function AppendDoubleArray(var V: DoubleArray; const R: Array of Double): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Double) * L); end; end; function AppendExtendedArray(var V: ExtendedArray; const R: Array of Extended): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Extended) * L); end; end; function AppendCurrencyArray(var V: CurrencyArray; const R: Array of Currency): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Currency) * L); end; end; function AppendPointerArray(var V: PointerArray; const R: Array of Pointer): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(Pointer) * L); end; end; function AppendCharSetArray(var V: CharSetArray; const R: Array of CharSet): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(CharSet) * L); end; end; function AppendByteSetArray(var V: ByteSetArray; const R: Array of ByteSet): Integer; var L : Integer; begin Result := Length(V); L := Length(R); if L > 0 then begin SetLength(V, Result + L); Move(R[0], V[Result], Sizeof(ByteSet) * L); end; end; function AppendObjectArray(var V: ObjectArray; const R: ObjectArray): Integer; var I, LR : Integer; begin Result := Length(V); LR := Length(R); if LR > 0 then begin SetLength(V, Result + LR); For I := 0 to LR - 1 do V[Result + I] := R[I]; end; end; function AppendStringArray(var V: StringArray; const R: Array of String): Integer; var I, LR : Integer; begin Result := Length(V); LR := Length(R); if LR > 0 then begin SetLength(V, Result + LR); For I := 0 to LR - 1 do V[Result + I] := R[I]; end; end; { } { FreeAndNil } { } procedure FreeAndNil(var Obj); var Temp : TObject; begin Temp := TObject(Obj); Pointer(Obj) := nil; Temp.Free; end; { } { Remove } { } function Remove(var V: ByteArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Byte)); SetLength(V, L - J); Result := J; end; function Remove(var V: WordArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Word)); SetLength(V, L - J); Result := J; end; function Remove(var V: LongWordArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(LongWord)); SetLength(V, L - J); Result := J; end; function Remove(var V: ShortIntArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(ShortInt)); SetLength(V, L - J); Result := J; end; function Remove(var V: SmallIntArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(SmallInt)); SetLength(V, L - J); Result := J; end; function Remove(var V: LongIntArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(LongInt)); SetLength(V, L - J); Result := J; end; function Remove(var V: Int64Array; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Int64)); SetLength(V, L - J); Result := J; end; function Remove(var V: SingleArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Single)); SetLength(V, L - J); Result := J; end; function Remove(var V: DoubleArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Double)); SetLength(V, L - J); Result := J; end; function Remove(var V: ExtendedArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Extended)); SetLength(V, L - J); Result := J; end; function Remove(var V: CurrencyArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Currency)); SetLength(V, L - J); Result := J; end; function Remove(var V: PointerArray; const Idx: Integer; const Count: Integer): Integer; var I, J, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Pointer)); SetLength(V, L - J); Result := J; end; function Remove(var V: ObjectArray; const Idx: Integer; const Count: Integer; const FreeObjects: Boolean): Integer; var I, J, K, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); if FreeObjects then For K := I to I + J - 1 do FreeAndNil(V[K]); M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(Pointer)); SetLength(V, L - J); Result := J; end; function Remove(var V: StringArray; const Idx: Integer; const Count: Integer): Integer; var I, J, K, L : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); For K := I to L - J - 1 do V[K] := V[K + J]; SetLength(V, L - J); Result := J; end; function Remove(var V: WideStringArray; const Idx: Integer; const Count: Integer): Integer; var I, J, K, L : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); For K := I to L - J - 1 do V[K] := V[K + J]; SetLength(V, L - J); Result := J; end; function Remove(var V: InterfaceArray; const Idx: Integer; const Count: Integer): Integer; var I, J, K, L, M : Integer; begin L := Length(V); if (Idx >= L) or (Idx + Count <= 0) or (L = 0) or (Count = 0) then begin Result := 0; exit; end; I := MaxI(Idx, 0); J := MinI(Count, L - I); For K := I to I + J - 1 do V[K] := nil; M := L - J - I; if M > 0 then Move(V[I + J], V[I], M * SizeOf(IInterface)); FillChar(V[L - J], J * SizeOf(IInterface), #0); SetLength(V, L - J); Result := J; end; procedure FreeObjectArray(var V); var I : Integer; A : ObjectArray absolute V; begin For I := Length(A) - 1 downto 0 do FreeAndNil(A[I]); end; procedure FreeObjectArray(var V; const LoIdx, HiIdx: Integer); var I : Integer; A : ObjectArray absolute V; begin For I := HiIdx downto LoIdx do FreeAndNil(A[I]); end; // Note: The parameter can not be changed to be untyped and then typecasted // using an absolute variable, as in FreeObjectArray. The reference counting // will be done incorrectly. procedure FreeAndNilObjectArray(var V: ObjectArray); var W : ObjectArray; begin W := V; V := nil; FreeObjectArray(W); end; { } { RemoveDuplicates } { } procedure RemoveDuplicates(var V: ByteArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : Byte; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: WordArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : Word; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: LongWordArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : LongWord; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: ShortIntArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : ShortInt; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: SmallIntArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : SmallInt; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: LongIntArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : LongInt; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: Int64Array; const IsSorted: Boolean); var I, C, J, L : Integer; F : Int64; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: SingleArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : Single; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: DoubleArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : Double; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: ExtendedArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : Extended; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: StringArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : String; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure RemoveDuplicates(var V: PointerArray; const IsSorted: Boolean); var I, C, J, L : Integer; F : Pointer; begin L := Length(V); if L = 0 then exit; if IsSorted then begin J := 0; Repeat F := V[J]; I := J + 1; While (I < L) and (V[I] = F) do Inc(I); C := I - J; if C > 1 then begin Remove(V, J + 1, C - 1); Dec(L, C - 1); Inc(J); end else J := I; Until J >= L; end else begin J := 0; Repeat Repeat I := PosNext(V[J], V, J); if I >= 0 then Remove(V, I, 1); Until I < 0; Inc(J); Until J >= Length(V); end; end; procedure TrimArrayLeft(var S: ByteArray; const TrimList: Array of Byte); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: WordArray; const TrimList: Array of Word); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: LongWordArray; const TrimList: Array of LongWord); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: ShortIntArray; const TrimList: Array of ShortInt); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: SmallIntArray; const TrimList: Array of SmallInt); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: LongIntArray; const TrimList: Array of LongInt); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: Int64Array; const TrimList: Array of Int64); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: SingleArray; const TrimList: Array of Single); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: DoubleArray; const TrimList: Array of Double); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: ExtendedArray; const TrimList: Array of Extended); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: StringArray; const TrimList: Array of String); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayLeft(var S: PointerArray; const TrimList: Array of Pointer); overload; var I, J : Integer; R : Boolean; begin I := 0; R := True; While R and (I < Length(S)) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Inc(I); break; end; end; if I > 0 then Remove(S, 0, I - 1); end; procedure TrimArrayRight(var S: ByteArray; const TrimList: Array of Byte); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: WordArray; const TrimList: Array of Word); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: LongWordArray; const TrimList: Array of LongWord); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: ShortIntArray; const TrimList: Array of ShortInt); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: SmallIntArray; const TrimList: Array of SmallInt); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: LongIntArray; const TrimList: Array of LongInt); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: Int64Array; const TrimList: Array of Int64); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: SingleArray; const TrimList: Array of Single); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: DoubleArray; const TrimList: Array of Double); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: ExtendedArray; const TrimList: Array of Extended); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: StringArray; const TrimList: Array of String); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; procedure TrimArrayRight(var S: PointerArray; const TrimList: Array of Pointer); overload; var I, J : Integer; R : Boolean; begin I := Length(S) - 1; R := True; While R and (I >= 0) do begin R := False; For J := 0 to High(TrimList) do if S[I] = TrimList[J] then begin R := True; Dec(I); break; end; end; if I < Length(S) - 1 then SetLength(S, I + 1); end; { } { ArrayInsert } { } function ArrayInsert(var V: ByteArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Byte)); FillChar(P^, Count * Sizeof(Byte), #0); Result := I; end; function ArrayInsert(var V: WordArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Word)); FillChar(P^, Count * Sizeof(Word), #0); Result := I; end; function ArrayInsert(var V: LongWordArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(LongWord)); FillChar(P^, Count * Sizeof(LongWord), #0); Result := I; end; function ArrayInsert(var V: ShortIntArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(ShortInt)); FillChar(P^, Count * Sizeof(ShortInt), #0); Result := I; end; function ArrayInsert(var V: SmallIntArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(SmallInt)); FillChar(P^, Count * Sizeof(SmallInt), #0); Result := I; end; function ArrayInsert(var V: LongIntArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(LongInt)); FillChar(P^, Count * Sizeof(LongInt), #0); Result := I; end; function ArrayInsert(var V: Int64Array; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Int64)); FillChar(P^, Count * Sizeof(Int64), #0); Result := I; end; function ArrayInsert(var V: SingleArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Single)); FillChar(P^, Count * Sizeof(Single), #0); Result := I; end; function ArrayInsert(var V: DoubleArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Double)); FillChar(P^, Count * Sizeof(Double), #0); Result := I; end; function ArrayInsert(var V: ExtendedArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Extended)); FillChar(P^, Count * Sizeof(Extended), #0); Result := I; end; function ArrayInsert(var V: CurrencyArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Currency)); FillChar(P^, Count * Sizeof(Currency), #0); Result := I; end; function ArrayInsert(var V: StringArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(String)); FillChar(P^, Count * Sizeof(String), #0); Result := I; end; function ArrayInsert(var V: WideStringArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(WideString)); FillChar(P^, Count * Sizeof(WideString), #0); Result := I; end; function ArrayInsert(var V: PointerArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Pointer)); FillChar(P^, Count * Sizeof(Pointer), #0); Result := I; end; function ArrayInsert(var V: ObjectArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(Pointer)); FillChar(P^, Count * Sizeof(Pointer), #0); Result := I; end; function ArrayInsert(var V: InterfaceArray; const Idx: Integer; const Count: Integer): Integer; var I, L : Integer; P : Pointer; begin L := Length(V); if (Idx > L) or (Idx + Count <= 0) or (Count <= 0) then begin Result := -1; exit; end; SetLength(V, L + Count); I := Idx; if I < 0 then I := 0; P := @V[I]; if I < L then Move(P^, V[I + Count], (L - I) * Sizeof(IInterface)); FillChar(P^, Count * Sizeof(IInterface), #0); Result := I; end; { } { PosNext } { PosNext finds the next occurance of Find in V, -1 if it was not found. } { Searches from Item[PrevPos + 1], ie PrevPos = -1 to find first } { occurance. } { } function PosNext(const Find: Byte; const V: ByteArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : Byte; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: Word; const V: WordArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : Word; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: LongWord; const V: LongWordArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : LongWord; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: ShortInt; const V: ShortIntArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : ShortInt; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: SmallInt; const V: SmallIntArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : SmallInt; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: LongInt; const V: LongIntArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : LongInt; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: Int64; const V: Int64Array; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : Int64; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: Single; const V: SingleArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : Single; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: Double; const V: DoubleArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : Double; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: Extended; const V: ExtendedArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : Extended; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: Boolean; const V: BooleanArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : Boolean; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: String; const V: StringArray; const PrevPos: Integer; const IsSortedAscending: Boolean): Integer; var I, L, H : Integer; D : String; begin if IsSortedAscending then // binary search begin if MaxI(PrevPos + 1, 0) = 0 then // find first begin L := 0; H := Length(V) - 1; While L <= H do begin I := (L + H) div 2; D := V[I]; if Find = D then begin While (I > 0) and (V[I - 1] = Find) do Dec(I); Result := I; exit; end else if D > Find then H := I - 1 else L := I + 1; end; Result := -1; end else // find next if PrevPos >= Length(V) - 1 then Result := -1 else if V[PrevPos + 1] = Find then Result := PrevPos + 1 else Result := -1; end else begin // linear search For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; end; function PosNext(const Find: TObject; const V: ObjectArray; const PrevPos: Integer): Integer; var I : Integer; begin For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; function PosNext(const ClassType: TClass; const V: ObjectArray; const PrevPos: Integer): Integer; var I : Integer; begin For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] is ClassType then begin Result := I; exit; end; Result := -1; end; function PosNext(const ClassName: String; const V: ObjectArray; const PrevPos: Integer): Integer; var I : Integer; T : TObject; begin For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do begin T := V[I]; if Assigned(T) and (T.ClassName = ClassName) then begin Result := I; exit; end; end; Result := -1; end; function PosNext(const Find: Pointer; const V: PointerArray; const PrevPos: Integer): Integer; var I : Integer; begin For I := MaxI(PrevPos + 1, 0) to Length(V) - 1 do if V[I] = Find then begin Result := I; exit; end; Result := -1; end; { } { Count } { } function Count(const Find: Byte; const V: ByteArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: Word; const V: WordArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: LongWord; const V: LongWordArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: ShortInt; const V: ShortIntArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: SmallInt; const V: SmallIntArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: LongInt; const V: LongIntArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: Int64; const V: Int64Array; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: Single; const V: SingleArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: Double; const V: DoubleArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: Extended; const V: ExtendedArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: String; const V: StringArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; function Count(const Find: Boolean; const V: BooleanArray; const IsSortedAscending: Boolean = False): Integer; var I, J : Integer; begin if IsSortedAscending then begin I := PosNext(Find, V, -1, True); if I = -1 then Result := 0 else begin Result := 1; J := Length(V); While (I + Result < J) and (V[I + Result] = Find) do Inc(Result); end; end else begin J := -1; Result := 0; Repeat I := PosNext(Find, V, J, False); if I >= 0 then begin Inc(Result); J := I; end; Until I < 0; end; end; { } { RemoveAll } { } procedure RemoveAll(const Find: Byte; var V: ByteArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: Word; var V: WordArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: LongWord; var V: LongWordArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: ShortInt; var V: ShortIntArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: SmallInt; var V: SmallIntArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: LongInt; var V: LongIntArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: Int64; var V: Int64Array; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: Single; var V: SingleArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: Double; var V: DoubleArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: Extended; var V: ExtendedArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; procedure RemoveAll(const Find: String; var V: StringArray; const IsSortedAscending: Boolean = False); var I, J : Integer; begin I := PosNext(Find, V, -1, IsSortedAscending); While I >= 0 do begin J := 1; While (I + J < Length(V)) and (V[I + J] = Find) do Inc(J); Remove(V, I, J); I := PosNext(Find, V, I, IsSortedAscending); end; end; { } { Intersection } { If both arrays are sorted ascending then time is o(n) instead of o(n^2). } { } function Intersection(const V1, V2: SingleArray; const IsSortedAscending: Boolean): SingleArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: DoubleArray; const IsSortedAscending: Boolean): DoubleArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: ExtendedArray; const IsSortedAscending: Boolean): ExtendedArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: ByteArray; const IsSortedAscending: Boolean): ByteArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: WordArray; const IsSortedAscending: Boolean): WordArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: LongWordArray; const IsSortedAscending: Boolean): LongWordArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: ShortIntArray; const IsSortedAscending: Boolean): ShortIntArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: SmallIntArray; const IsSortedAscending: Boolean): SmallIntArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: LongIntArray; const IsSortedAscending: Boolean): LongIntArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: Int64Array; const IsSortedAscending: Boolean): Int64Array; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Intersection(const V1, V2: StringArray; const IsSortedAscending: Boolean): StringArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] = V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) >= 0) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; { } { Difference } { Returns elements in V1 but not in V2. } { If both arrays are sorted ascending then time is o(n) instead of o(n^2). } { } function Difference(const V1, V2: SingleArray; const IsSortedAscending: Boolean): SingleArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: DoubleArray; const IsSortedAscending: Boolean): DoubleArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: ExtendedArray; const IsSortedAscending: Boolean): ExtendedArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: ByteArray; const IsSortedAscending: Boolean): ByteArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: WordArray; const IsSortedAscending: Boolean): WordArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: LongWordArray; const IsSortedAscending: Boolean): LongWordArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: ShortIntArray; const IsSortedAscending: Boolean): ShortIntArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: SmallIntArray; const IsSortedAscending: Boolean): SmallIntArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: LongIntArray; const IsSortedAscending: Boolean): LongIntArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: Int64Array; const IsSortedAscending: Boolean): Int64Array; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; function Difference(const V1, V2: StringArray; const IsSortedAscending: Boolean): StringArray; var I, J, L, LV : Integer; begin SetLength(Result, 0); if IsSortedAscending then begin I := 0; J := 0; L := Length(V1); LV := Length(V2); While (I < L) and (J < LV) do begin While (I < L) and (V1[I] < V2[J]) do Inc(I); if I < L then begin if V1[I] <> V2[J] then Append(Result, V1[I]); While (J < LV) and (V2[J] <= V1[I]) do Inc(J); end; end; end else For I := 0 to Length(V1) - 1 do if (PosNext(V1[I], V2) = -1) and (PosNext(V1[I], Result) = -1) then Append(Result, V1[I]); end; { } { Reverse } { } procedure Reverse(var V: ByteArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: WordArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: LongWordArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: ShortIntArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: SmallIntArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: LongIntArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: Int64Array); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: StringArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: PointerArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: ObjectArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: SingleArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: DoubleArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; procedure Reverse(var V: ExtendedArray); var I, L : Integer; begin L := Length(V); For I := 1 to L div 2 do Swap(V[I - 1], V[L - I]); end; { } { Returns an open array (V) as a dynamic array. } { } function AsBooleanArray(const V: Array of Boolean): BooleanArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsByteArray(const V: Array of Byte): ByteArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsWordArray(const V: Array of Word): WordArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsLongWordArray(const V: Array of LongWord): LongWordArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsCardinalArray(const V: Array of Cardinal): CardinalArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsShortIntArray(const V: Array of ShortInt): ShortIntArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsSmallIntArray(const V: Array of SmallInt): SmallIntArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsLongIntArray(const V: Array of LongInt): LongIntArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsIntegerArray(const V: Array of Integer): IntegerArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsInt64Array(const V: Array of Int64): Int64Array; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsSingleArray(const V: Array of Single): SingleArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsDoubleArray(const V: Array of Double): DoubleArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsExtendedArray(const V: Array of Extended): ExtendedArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsCurrencyArray(const V: Array of Currency): CurrencyArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsStringArray(const V: Array of String): StringArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsWideStringArray(const V: Array of WideString): WideStringArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsPointerArray(const V: Array of Pointer): PointerArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsCharSetArray(const V: Array of CharSet): CharSetArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsObjectArray(const V: Array of TObject): ObjectArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function AsInterfaceArray(const V: Array of IInterface): InterfaceArray; var I : Integer; begin SetLength(Result, High(V) + 1); For I := 0 to High(V) do Result[I] := V[I]; end; function RangeByte(const First: Byte; const Count: Integer; const Increment: Byte): ByteArray; var I : Integer; J : Byte; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeWord(const First: Word; const Count: Integer; const Increment: Word): WordArray; var I : Integer; J : Word; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeLongWord(const First: LongWord; const Count: Integer; const Increment: LongWord): LongWordArray; var I : Integer; J : LongWord; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeCardinal(const First: Cardinal; const Count: Integer; const Increment: Cardinal): CardinalArray; var I : Integer; J : Cardinal; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeShortInt(const First: ShortInt; const Count: Integer; const Increment: ShortInt): ShortIntArray; var I : Integer; J : ShortInt; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeSmallInt(const First: SmallInt; const Count: Integer; const Increment: SmallInt): SmallIntArray; var I : Integer; J : SmallInt; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeLongInt(const First: LongInt; const Count: Integer; const Increment: LongInt): LongIntArray; var I : Integer; J : LongInt; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeInteger(const First: Integer; const Count: Integer; const Increment: Integer): IntegerArray; var I : Integer; J : Integer; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeInt64(const First: Int64; const Count: Integer; const Increment: Int64): Int64Array; var I : Integer; J : Int64; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeSingle(const First: Single; const Count: Integer; const Increment: Single): SingleArray; var I : Integer; J : Single; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeDouble(const First: Double; const Count: Integer; const Increment: Double): DoubleArray; var I : Integer; J : Double; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; function RangeExtended(const First: Extended; const Count: Integer; const Increment: Extended): ExtendedArray; var I : Integer; J : Extended; begin SetLength(Result, Count); J := First; For I := 0 to Count - 1 do begin Result[I] := J; J := J + Increment; end; end; { } { Dup } { } function DupByte(const V: Byte; const Count: Integer): ByteArray; begin SetLength(Result, Count); FillChar(Result[0], Count, V); end; function DupWord(const V: Word; const Count: Integer): WordArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupLongWord(const V: LongWord; const Count: Integer): LongWordArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupCardinal(const V: Cardinal; const Count: Integer): CardinalArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupShortInt(const V: ShortInt; const Count: Integer): ShortIntArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupSmallInt(const V: SmallInt; const Count: Integer): SmallIntArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupLongInt(const V: LongInt; const Count: Integer): LongIntArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupInteger(const V: Integer; const Count: Integer): IntegerArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupInt64(const V: Int64; const Count: Integer): Int64Array; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupSingle(const V: Single; const Count: Integer): SingleArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupDouble(const V: Double; const Count: Integer): DoubleArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupExtended(const V: Extended; const Count: Integer): ExtendedArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupCurrency(const V: Currency; const Count: Integer): CurrencyArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupString(const V: String; const Count: Integer): StringArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupCharSet(const V: CharSet; const Count: Integer): CharSetArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; function DupObject(const V: TObject; const Count: Integer): ObjectArray; var I : Integer; begin SetLength(Result, Count); For I := 0 to Count - 1 do Result[I] := V; end; { } { SetLengthAndZero } { } procedure SetLengthAndZero(var V: ByteArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Byte) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: WordArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Word) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: LongWordArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(LongWord) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: ShortIntArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(ShortInt) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: SmallIntArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(SmallInt) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: LongIntArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(LongInt) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: Int64Array; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Int64) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: SingleArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Single) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: DoubleArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Double) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: ExtendedArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Extended) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: CurrencyArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Currency) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: CharSetArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(CharSet) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: BooleanArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Boolean) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: PointerArray; const NewLength: Integer); var OldLen, NewLen : Integer; begin NewLen := NewLength; if NewLen < 0 then NewLen := 0; OldLen := Length(V); if OldLen = NewLen then exit; SetLength(V, NewLen); if OldLen > NewLen then exit; FillChar(Pointer(@V[OldLen])^, Sizeof(Pointer) * (NewLen - OldLen), #0); end; procedure SetLengthAndZero(var V: ObjectArray; const NewLength: Integer; const FreeObjects: Boolean); var I, L : Integer; begin L := Length(V); if L = NewLength then exit; if (L > NewLength) and FreeObjects then For I := NewLength to L - 1 do FreeAndNil(V[I]); SetLength(V, NewLength); if L > NewLength then exit; FillChar(V[L], Sizeof(Pointer) * (NewLength - L), #0); end; { } { IsEqual } { } function IsEqual(const V1, V2: ByteArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(Byte) * L); end; function IsEqual(const V1, V2: WordArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(Word) * L); end; function IsEqual(const V1, V2: LongWordArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(LongWord) * L); end; function IsEqual(const V1, V2: ShortIntArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(ShortInt) * L); end; function IsEqual(const V1, V2: SmallIntArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(SmallInt) * L); end; function IsEqual(const V1, V2: LongIntArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(LongInt) * L); end; function IsEqual(const V1, V2: Int64Array): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(Int64) * L); end; function IsEqual(const V1, V2: SingleArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(Single) * L); end; function IsEqual(const V1, V2: DoubleArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(Double) * L); end; function IsEqual(const V1, V2: ExtendedArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(Extended) * L); end; function IsEqual(const V1, V2: CurrencyArray): Boolean; var L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; Result := CompareMem(Pointer(V1)^, Pointer(V2)^, Sizeof(Currency) * L); end; function IsEqual(const V1, V2: StringArray): Boolean; var I, L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; For I := 0 to L - 1 do if V1[I] <> V2[I] then begin Result := False; exit; end; Result := True; end; function IsEqual(const V1, V2: CharSetArray): Boolean; var I, L : Integer; begin L := Length(V1); if L <> Length(V2) then begin Result := False; exit; end; For I := 0 to L - 1 do if V1[I] <> V2[I] then begin Result := False; exit; end; Result := True; end; { } { Dynamic array to Dynamic array } { } function ByteArrayToLongIntArray(const V: ByteArray): LongIntArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function WordArrayToLongIntArray(const V: WordArray): LongIntArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function ShortIntArrayToLongIntArray(const V: ShortIntArray): LongIntArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function SmallIntArrayToLongIntArray(const V: SmallIntArray): LongIntArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function LongIntArrayToInt64Array(const V: LongIntArray): Int64Array; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function LongIntArrayToSingleArray(const V: LongIntArray): SingleArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function LongIntArrayToDoubleArray(const V: LongIntArray): DoubleArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function LongIntArrayToExtendedArray(const V: LongIntArray): ExtendedArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function SingleArrayToDoubleArray(const V: SingleArray): DoubleArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function SingleArrayToExtendedArray(const V: SingleArray): ExtendedArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function SingleArrayToCurrencyArray(const V: SingleArray): CurrencyArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function SingleArrayToLongIntArray(const V: SingleArray): LongIntArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := LongInt(Trunc(V[I])); end; function SingleArrayToInt64Array(const V: SingleArray): Int64Array; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := Trunc(V[I]); end; function DoubleArrayToExtendedArray(const V: DoubleArray): ExtendedArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function DoubleArrayToCurrencyArray(const V: DoubleArray): CurrencyArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function DoubleArrayToLongIntArray(const V: DoubleArray): LongIntArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := LongInt(Trunc(V[I])); end; function DoubleArrayToInt64Array(const V: DoubleArray): Int64Array; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := Trunc(V[I]); end; function ExtendedArrayToCurrencyArray(const V: ExtendedArray): CurrencyArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[I]; end; function ExtendedArrayToLongIntArray(const V: ExtendedArray): LongIntArray; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := LongInt(Trunc(V[I])); end; function ExtendedArrayToInt64Array(const V: ExtendedArray): Int64Array; var I, L : Integer; begin L := Length(V); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := Trunc(V[I]); end; { } { Array from indexes } { } function ByteArrayFromIndexes(const V: ByteArray; const Indexes: IntegerArray): ByteArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function WordArrayFromIndexes(const V: WordArray; const Indexes: IntegerArray): WordArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function LongWordArrayFromIndexes(const V: LongWordArray; const Indexes: IntegerArray): LongWordArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function CardinalArrayFromIndexes(const V: CardinalArray; const Indexes: IntegerArray): CardinalArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function ShortIntArrayFromIndexes(const V: ShortIntArray; const Indexes: IntegerArray): ShortIntArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function SmallIntArrayFromIndexes(const V: SmallIntArray; const Indexes: IntegerArray): SmallIntArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function LongIntArrayFromIndexes(const V: LongIntArray; const Indexes: IntegerArray): LongIntArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function IntegerArrayFromIndexes(const V: IntegerArray; const Indexes: IntegerArray): IntegerArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function Int64ArrayFromIndexes(const V: Int64Array; const Indexes: IntegerArray): Int64Array; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function SingleArrayFromIndexes(const V: SingleArray; const Indexes: IntegerArray): SingleArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function DoubleArrayFromIndexes(const V: DoubleArray; const Indexes: IntegerArray): DoubleArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function ExtendedArrayFromIndexes(const V: ExtendedArray; const Indexes: IntegerArray): ExtendedArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; function StringArrayFromIndexes(const V: StringArray; const Indexes: IntegerArray): StringArray; var I, L : Integer; begin L := Length(Indexes); SetLength(Result, L); For I := 0 to L - 1 do Result[I] := V[Indexes[I]]; end; { } { Dynamic array sort } { } procedure Sort(const V: ByteArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Byte; P, Q : PByte; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: WordArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Word; P, Q : PWord; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: LongWordArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : LongWord; P, Q : PLongWord; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: ShortIntArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : ShortInt; P, Q : PShortInt; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: SmallIntArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : SmallInt; P, Q : PSmallInt; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: LongIntArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : LongInt; P, Q : PLongInt; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: Int64Array); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Int64; P, Q : PInt64; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: SingleArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Single; P, Q : PSingle; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: DoubleArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Double; P, Q : PDouble; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: ExtendedArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Extended; P, Q : PExtended; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const V: StringArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : String; P, Q : PString; begin Repeat I := L; P := @V[I]; J := R; Q := @V[J]; M := (L + R) shr 1; W := V[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin I := Length(V); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: IntegerArray; const Data: IntegerArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Integer; P, Q : PInteger; A : Integer; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: IntegerArray; const Data: Int64Array); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Integer; P, Q : PInteger; A : Int64; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: IntegerArray; const Data: StringArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Integer; P, Q : PInteger; A : String; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: IntegerArray; const Data: ExtendedArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Integer; P, Q : PInteger; A : Extended; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: IntegerArray; const Data: PointerArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Integer; P, Q : PInteger; A : Pointer; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: StringArray; const Data: IntegerArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : String; P, Q : PString; A : Integer; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: StringArray; const Data: Int64Array); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : String; P, Q : PString; A : Int64; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: StringArray; const Data: StringArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : String; P, Q : PString; A : String; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: StringArray; const Data: ExtendedArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : String; P, Q : PString; A : Extended; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: StringArray; const Data: PointerArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : String; P, Q : PString; A : Pointer; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: ExtendedArray; const Data: IntegerArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Extended; P, Q : PExtended; A : Integer; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: ExtendedArray; const Data: Int64Array); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Extended; P, Q : PExtended; A : Int64; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: ExtendedArray; const Data: StringArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Extended; P, Q : PExtended; A : String; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: ExtendedArray; const Data: ExtendedArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Extended; P, Q : PExtended; A : Extended; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; procedure Sort(const Key: ExtendedArray; const Data: PointerArray); procedure QuickSort(L, R: Integer); var I, J, M : Integer; W, T : Extended; P, Q : PExtended; A : Pointer; begin Repeat I := L; P := @Key[I]; J := R; Q := @Key[J]; M := (L + R) shr 1; W := Key[M]; Repeat While P^ < W do begin Inc(P); Inc(I); end; While Q^ > W do begin Dec(Q); Dec(J); end; if I <= J then begin T := P^; P^ := Q^; Q^ := T; A := Data[I]; Data[I] := Data[J]; Data[J] := A; if M = I then begin M := J; W := Q^; end else if M = J then begin M := I; W := P^; end; Inc(P); Inc(I); Dec(Q); Dec(J); end; Until I > J; if L < J then QuickSort(L, J); L := I; Until I >= R; end; var I : Integer; begin Assert(Length(Key) = Length(Data), 'Sort pair must be of equal length'); I := Length(Key); if I > 0 then QuickSort(0, I - 1); end; { } { Test cases } { } {$ASSERTIONS ON} procedure Test_Misc; var A, B : String; L, H : Cardinal; I, J : Integer; V : Boolean; begin // Clip Assert(SumClipI(1, 2) = 3, 'SumClipI'); Assert(SumClipI(1, -2) = -1, 'SumClipI'); Assert(SumClipI(MaxInteger - 1, 0) = MaxInteger - 1, 'SumClipI'); Assert(SumClipI(MaxInteger - 1, 1) = MaxInteger, 'SumClipI'); Assert(SumClipI(MaxInteger - 1, 2) = MaxInteger, 'SumClipI'); Assert(SumClipI(MinInteger + 1, 0) = MinInteger + 1, 'SumClipI'); Assert(SumClipI(MinInteger + 1, -1) = MinInteger, 'SumClipI'); Assert(SumClipI(MinInteger + 1, -2) = MinInteger, 'SumClipI'); Assert(SumClipC(1, 2) = 3, 'SumClipC'); Assert(SumClipC(3, -2) = 1, 'SumClipC'); Assert(SumClipC(MaxCardinal - 1, 0) = MaxCardinal - 1, 'SumClipC'); Assert(SumClipC(MaxCardinal - 1, 1) = MaxCardinal, 'SumClipC'); Assert(SumClipC(MaxCardinal - 1, 2) = MaxCardinal, 'SumClipC'); Assert(SumClipC(1, 0) = 1, 'SumClipC'); Assert(SumClipC(1, -1) = 0, 'SumClipC'); Assert(SumClipC(1, -2) = 0, 'SumClipC'); // Ranges L := 10; H := 20; Assert(CardinalRangeIncludeElementRange(L, H, 10, 20), 'RangeInclude'); Assert((L = 10) and (H = 20), 'RangeInclude'); Assert(CardinalRangeIncludeElementRange(L, H, 9, 21), 'RangeInclude'); Assert((L = 9) and (H = 21), 'RangeInclude'); Assert(CardinalRangeIncludeElementRange(L, H, 7, 10), 'RangeInclude'); Assert((L = 7) and (H = 21), 'RangeInclude'); Assert(CardinalRangeIncludeElementRange(L, H, 5, 6), 'RangeInclude'); Assert((L = 5) and (H = 21), 'RangeInclude'); Assert(not CardinalRangeIncludeElementRange(L, H, 1, 3), 'RangeInclude'); Assert((L = 5) and (H = 21), 'RangeInclude'); Assert(CardinalRangeIncludeElementRange(L, H, 20, 22), 'RangeInclude'); Assert((L = 5) and (H = 22), 'RangeInclude'); Assert(CardinalRangeIncludeElementRange(L, H, 23, 24), 'RangeInclude'); Assert((L = 5) and (H = 24), 'RangeInclude'); Assert(not CardinalRangeIncludeElementRange(L, H, 26, 27), 'RangeInclude'); Assert((L = 5) and (H = 24), 'RangeInclude'); // iif Assert(iif(True, 1, 2) = 1, 'iif'); Assert(iif(False, 1, 2) = 2, 'iif'); Assert(iif(True, -1, -2) = -1, 'iif'); Assert(iif(False, -1, -2) = -2, 'iif'); Assert(iif(True, '1', '2') = '1', 'iif'); Assert(iif(False, '1', '2') = '2', 'iif'); Assert(iif(True, 1.1, 2.2) = 1.1, 'iif'); Assert(iif(False, 1.1, 2.2) = 2.2, 'iif'); // CharSet Assert(CharCount([]) = 0, 'CharCount'); Assert(CharCount(['a'..'z']) = 26, 'CharCount'); Assert(CharCount([#0, #255]) = 2, 'CharCount'); // Compare Assert(Compare(1, 1) = crEqual, 'Compare'); Assert(Compare(1, 2) = crLess, 'Compare'); Assert(Compare(1, 0) = crGreater, 'Compare'); Assert(Compare(1.0, 1.0) = crEqual, 'Compare'); Assert(Compare(1.0, 1.1) = crLess, 'Compare'); Assert(Compare(1.0, 0.9) = crGreater, 'Compare'); Assert(Compare(False, False) = crEqual, 'Compare'); Assert(Compare(True, True) = crEqual, 'Compare'); Assert(Compare(False, True) = crLess, 'Compare'); Assert(Compare(True, False) = crGreater, 'Compare'); Assert(Compare('', '') = crEqual, 'Compare'); Assert(Compare('a', 'a') = crEqual, 'Compare'); Assert(Compare('a', 'b') = crLess, 'Compare'); Assert(Compare('b', 'a') = crGreater, 'Compare'); Assert(Compare('', 'a') = crLess, 'Compare'); Assert(Compare('a', '') = crGreater, 'Compare'); Assert(Compare('aa', 'a') = crGreater, 'Compare'); Assert(not FloatZero(1e-1, 1e-2), 'FloatZero'); Assert(FloatZero(1e-2, 1e-2), 'FloatZero'); Assert(not FloatZero(1e-1, 1e-9), 'FloatZero'); Assert(not FloatZero(1e-8, 1e-9), 'FloatZero'); Assert(FloatZero(1e-9, 1e-9), 'FloatZero'); Assert(FloatZero(1e-10, 1e-9), 'FloatZero'); Assert(not FloatZero(0.2, 1e-1), 'FloatZero'); Assert(FloatZero(0.09, 1e-1), 'FloatZero'); Assert(FloatOne(1.0, 1e-1), 'FloatOne'); Assert(FloatOne(1.09999, 1e-1), 'FloatOne'); Assert(FloatOne(0.90001, 1e-1), 'FloatOne'); Assert(not FloatOne(1.10001, 1e-1), 'FloatOne'); Assert(not FloatOne(1.2, 1e-1), 'FloatOne'); Assert(not FloatOne(0.89999, 1e-1), 'FloatOne'); Assert(not FloatsEqual(2.0, -2.0, 1e-1), 'FloatsEqual'); Assert(not FloatsEqual(1.0, 0.0, 1e-1), 'FloatsEqual'); Assert(FloatsEqual(2.0, 2.0, 1e-1), 'FloatsEqual'); Assert(FloatsEqual(2.0, 2.09, 1e-1), 'FloatsEqual'); Assert(FloatsEqual(2.0, 1.90000001, 1e-1), 'FloatsEqual'); Assert(not FloatsEqual(2.0, 2.10001, 1e-1), 'FloatsEqual'); Assert(not FloatsEqual(2.0, 2.2, 1e-1), 'FloatsEqual'); Assert(not FloatsEqual(2.0, 1.8999999, 1e-1), 'FloatsEqual'); Assert(FloatsEqual(2.00000000011, 2.0, 1e-2), 'FloatsEqual'); Assert(FloatsEqual(2.00000000011, 2.0, 1e-9), 'FloatsEqual'); Assert(not FloatsEqual(2.00000000011, 2.0, 1e-10), 'FloatsEqual'); Assert(not FloatsEqual(2.00000000011, 2.0, 1e-11), 'FloatsEqual'); Assert(FloatsCompare(0.0, 0.0, MinExtended) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(1.2, 1.2, MinExtended) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(1.23456789e-300, 1.23456789e-300, MinExtended) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(1.23456780e-300, 1.23456789e-300, MinExtended) = crLess, 'FloatsCompare'); Assert(FloatsCompare(1.4e-5, 1.5e-5, 1e-4) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(1.4e-5, 1.5e-5, 1e-5) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(1.4e-5, 1.5e-5, 1e-6) = crLess, 'FloatsCompare'); Assert(FloatsCompare(1.4e-5, 1.5e-5, 1e-7) = crLess, 'FloatsCompare'); Assert(FloatsCompare(0.5003, 0.5001, 1e-1) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(0.5003, 0.5001, 1e-2) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(0.5003, 0.5001, 1e-3) = crEqual, 'FloatsCompare'); Assert(FloatsCompare(0.5003, 0.5001, 1e-4) = crGreater, 'FloatsCompare'); Assert(FloatsCompare(0.5003, 0.5001, 1e-5) = crGreater, 'FloatsCompare'); Assert(ApproxEqual(0.0, 0.0), 'ApproxEqual'); Assert(not ApproxEqual(0.0, 1e-100, 1e-10), 'ApproxEqual'); Assert(not ApproxEqual(1.0, 1e-100, 1e-10), 'ApproxEqual'); Assert(ApproxEqual(1.0, 1.0), 'ApproxEqual'); Assert(ApproxEqual(-1.0, -1.0), 'ApproxEqual'); Assert(not ApproxEqual(1.0, -1.0), 'ApproxEqual'); Assert(ApproxEqual(1e-100, 1e-100, 1e-10), 'ApproxEqual'); Assert(not ApproxEqual(0.0, 1.0, 1e-9), 'ApproxEqual'); Assert(not ApproxEqual(-1.0, 1.0, 1e-9), 'ApproxEqual'); Assert(ApproxEqual(0.12345, 0.12349, 1e-3), 'ApproxEqual'); Assert(not ApproxEqual(0.12345, 0.12349, 1e-4), 'ApproxEqual'); Assert(not ApproxEqual(0.12345, 0.12349, 1e-5), 'ApproxEqual'); Assert(ApproxEqual(1.2345e+100, 1.2349e+100, 1e-3), 'ApproxEqual'); Assert(not ApproxEqual(1.2345e+100, 1.2349e+100, 1e-4), 'ApproxEqual'); Assert(not ApproxEqual(1.2345e+100, 1.2349e+100, 1e-5), 'ApproxEqual'); Assert(ApproxEqual(1.2345e-100, 1.2349e-100, 1e-3), 'ApproxEqual'); Assert(not ApproxEqual(1.2345e-100, 1.2349e-100, 1e-4), 'ApproxEqual'); Assert(not ApproxEqual(1.2345e-100, 1.2349e-100, 1e-5), 'ApproxEqual'); Assert(not ApproxEqual(1.0e+20, 1.00000001E+20, 1e-8), 'ApproxEqual'); Assert(ApproxEqual(1.0e+20, 1.000000001E+20, 1e-8), 'ApproxEqual'); Assert(not ApproxEqual(1.0e+20, 1.000000001E+20, 1e-9), 'ApproxEqual'); Assert(ApproxEqual(1.0e+20, 1.0000000001E+20, 1e-9), 'ApproxEqual'); Assert(not ApproxEqual(1.0e+20, 1.0000000001E+20, 1e-10), 'ApproxEqual'); Assert(ApproxCompare(0.0, 0.0) = crEqual, 'ApproxCompare'); Assert(ApproxCompare(0.0, 1.0) = crLess, 'ApproxCompare'); Assert(ApproxCompare(1.0, 0.0) = crGreater, 'ApproxCompare'); Assert(ApproxCompare(-1.0, 1.0) = crLess, 'ApproxCompare'); Assert(ApproxCompare(1.2345e+10, 1.2349e+10, 1e-3) = crEqual, 'ApproxCompare'); Assert(ApproxCompare(1.2345e+10, 1.2349e+10, 1e-4) = crLess, 'ApproxCompare'); Assert(ApproxCompare(-1.2345e-10, -1.2349e-10, 1e-3) = crEqual, 'ApproxCompare'); Assert(ApproxCompare(-1.2345e-10, -1.2349e-10, 1e-4) = crGreater, 'ApproxCompare'); Assert(ReverseCompareResult(crLess) = crGreater, 'ReverseCompareResult'); Assert(ReverseCompareResult(crGreater) = crLess, 'ReverseCompareResult'); // MoveMem For I := -8 to 16 do begin A := '0123456789ABCDEFGHIJ'; B := ' '; MoveMem(A[1], B[1], I); For J := 1 to MinI(I, 10) do Assert(B[J] = Char(48 + J - 1), 'MoveMem'); For J := 11 to MinI(I, 16) do Assert(B[J] = Char(65 + J - 11), 'MoveMem'); For J := MaxI(I + 1, 1) to 20 do Assert(B[J] = ' '); end; // ZeroMem For I := -8 to 16 do begin A := '0123456789ABCDEFGHIJ'; ZeroMem(A[1], I); For J := 1 to I do Assert(A[J] = #0, 'ZeroMem'); For J := MaxI(I + 1, 1) to 10 do Assert(A[J] = Char(48 + J - 1), 'ZeroMem'); For J := MaxI(I + 1, 11) to 20 do Assert(A[J] = Char(65 + J - 11), 'ZeroMem'); end; // FillMem For I := -8 to 16 do begin A := '0123456789ABCDEFGHIJ'; FillMem(A[1], I, Ord('Z')); For J := 1 to I do Assert(A[J] = 'Z', 'FillMem'); For J := MaxI(I + 1, 1) to 10 do Assert(A[J] = Char(48 + J - 1), 'FillMem'); For J := MaxI(I + 1, 11) to 20 do Assert(A[J] = Char(65 + J - 11), 'FillMem'); end; // Hash Assert(HashStr('Fundamentals') = $3FB7796E, 'HashStr'); // Encodings Assert(HexCharValue('A') = 10, 'HexCharValue'); Assert(HexCharValue('a') = 10, 'HexCharValue'); Assert(HexCharValue('1') = 1, 'HexCharValue'); Assert(HexCharValue('G') = $FF, 'HexCharValue'); Assert(LongWordToStr(123) = '123', 'LongWordToStr'); Assert(LongWordToStr(0) = '0', 'LongWordToStr'); Assert(LongWordToStr($FFFFFFFF) = '4294967295', 'LongWordToStr'); Assert(LongWordToStr(10000) = '10000', 'LongWordToStr'); Assert(LongWordToStr(99999) = '99999', 'LongWordToStr'); Assert(LongWordToStr(1, 1) = '1', 'LongWordToStr'); Assert(LongWordToStr(1, 3) = '001', 'LongWordToStr'); Assert(LongWordToStr(1234, 3) = '1234', 'LongWordToStr'); Assert(DecStrToLongWord('', V) = 0, 'DecStrToLongWord'); Assert(V = False, 'DecStrToLongWord'); Assert(DecStrToLongWord('123', V) = 123, 'DecStrToLongWord'); Assert(V = True, 'DecStrToLongWord'); Assert(DecStrToLongWord('4294967295', V) = $FFFFFFFF, 'DecStrToLongWord'); Assert(V = True, 'DecStrToLongWord'); Assert(DecStrToLongWord('99999', V) = 99999, 'DecStrToLongWord'); Assert(LongWordToHex(0) = '0', 'LongWordToHex'); Assert(LongWordToHex($FFFFFFFF) = 'FFFFFFFF', 'LongWordToHex'); Assert(LongWordToHex($10000) = '10000', 'LongWordToHex'); Assert(LongWordToHex($12345678) = '12345678', 'LongWordToHex'); Assert(LongWordToHex($AB, 4) = '00AB', 'LongWordToHex'); Assert(LongWordToHex($ABCD, 8) = '0000ABCD', 'LongWordToHex'); Assert(LongWordToHex(0, 8) = '00000000', 'LongWordToHex'); Assert(LongWordToHex($CDEF, 2) = 'CDEF', 'LongWordToHex'); Assert(HexStrToLongWord('FFFFFFFF', V) = $FFFFFFFF, 'HexStrToLongWord'); Assert(V = True, 'HexStrToLongWord'); Assert(HexStrToLongWord('0', V) = 0, 'HexStrToLongWord'); Assert(V = True, 'HexStrToLongWord'); Assert(HexStrToLongWord('123456', V) = $123456, 'HexStrToLongWord'); Assert(HexStrToLongWord('ABC', V) = $ABC, 'HexStrToLongWord'); Assert(HexStrToLongWord('', V) = 0, 'HexStrToLongWord'); Assert(V = False, 'HexStrToLongWord'); Assert(HexStrToLongWord('x', V) = 0, 'HexStrToLongWord'); Assert(V = False, 'HexStrToLongWord'); Assert(HexStrToLongWord('1000', V) = $1000, 'HexStrToLongWord'); end; procedure Test_BitFunctions; begin Assert(SetBit($100F, 5) = $102F, 'SetBit'); Assert(ClearBit($102F, 5) = $100F, 'ClearBit'); Assert(ToggleBit($102F, 5) = $100F, 'ToggleBit'); Assert(ToggleBit($100F, 5) = $102F, 'ToggleBit'); Assert(IsBitSet($102F, 5), 'IsBitSet'); Assert(not IsBitSet($100F, 5), 'IsBitSet'); Assert(SetBitScanForward(0) = -1, 'SetBitScanForward'); Assert(SetBitScanForward($1020) = 5, 'SetBitScanForward'); Assert(SetBitScanReverse($1020) = 12, 'SetBitScanForward'); Assert(SetBitScanForward($1020, 6) = 12, 'SetBitScanForward'); Assert(SetBitScanReverse($1020, 11) = 5, 'SetBitScanForward'); Assert(ClearBitScanForward($FFFFFFFF) = -1, 'ClearBitScanForward'); Assert(ClearBitScanForward($1020) = 0, 'ClearBitScanForward'); Assert(ClearBitScanReverse($1020) = 31, 'ClearBitScanForward'); Assert(ClearBitScanForward($1020, 5) = 6, 'ClearBitScanForward'); Assert(ClearBitScanReverse($1020, 12) = 11, 'ClearBitScanForward'); Assert(ReverseBits($12345678) = $1E6A2C48, 'ReverseBits'); Assert(SwapEndian($12345678) = $78563412, 'SwapEndian'); Assert(BitCount($12341234) = 10, 'BitCount'); Assert(LowBitMask(10) = $3FF, 'LowBitMask'); Assert(HighBitMask(28) = $F0000000, 'HighBitMask'); Assert(RangeBitMask(2, 6) = $7C, 'RangeBitMask'); Assert(SetBitRange($101, 2, 6) = $17D, 'SetBitRange'); Assert(ClearBitRange($17D, 2, 6) = $101, 'ClearBitRange'); Assert(ToggleBitRange($17D, 2, 6) = $101, 'ToggleBitRange'); Assert(IsBitRangeSet($17D, 2, 6), 'IsBitRangeSet'); Assert(not IsBitRangeSet($101, 2, 6), 'IsBitRangeSet'); Assert(not IsBitRangeClear($17D, 2, 6), 'IsBitRangeClear'); Assert(IsBitRangeClear($101, 2, 6), 'IsBitRangeClear'); end; procedure Test_IntegerArray; var S, T : IntegerArray; F : Integer; begin S := nil; For F := 1 to 100 do begin Append(S, F); Assert(Length(S) = F, 'Append'); Assert(S[F - 1] = F, 'Append'); end; T := Copy(S); AppendIntegerArray(S, T); For F := 1 to 100 do Assert(S[F + 99] = F, 'Append'); Assert(PosNext(60, S) = 59, 'PosNext'); Assert(PosNext(60, T) = 59, 'PosNext'); Assert(PosNext(60, S, 59) = 159, 'PosNext'); Assert(PosNext(60, T, 59) = -1, 'PosNext'); Assert(PosNext(60, T, -1, True) = 59, 'PosNext'); Assert(PosNext(60, T, 59, True) = -1, 'PosNext'); For F := 1 to 100 do begin Remove(S, PosNext(F, S), 1); Assert(Length(S) = 200 - F, 'Remove'); end; For F := 99 downto 0 do begin Remove(S, PosNext(F xor 3 + 1, S), 1); Assert(Length(S) = F, 'Remove'); end; S := AsIntegerArray([3, 1, 2, 5, 4]); Sort(S); Assert(S[0] = 1, 'Sort'); Assert(S[1] = 2, 'Sort'); Assert(S[2] = 3, 'Sort'); Assert(S[3] = 4, 'Sort'); Assert(S[4] = 5, 'Sort'); S := AsIntegerArray([3, 5, 5, 2, 5, 5, 1]); Sort(S); Assert(S[0] = 1, 'Sort'); Assert(S[1] = 2, 'Sort'); Assert(S[2] = 3, 'Sort'); Assert(S[3] = 5, 'Sort'); Assert(S[4] = 5, 'Sort'); Assert(S[5] = 5, 'Sort'); Assert(S[6] = 5, 'Sort'); SetLength(S, 1000); For F := 0 to 999 do S[F] := F mod 5; Sort(S); For F := 0 to 999 do Assert(S[F] = F div 200, 'Sort'); S := AsIntegerArray([6, 3, 5, 1]); T := AsIntegerArray([1, 2, 3, 4]); Sort(S, T); Assert(S[0] = 1, 'Sort'); Assert(S[1] = 3, 'Sort'); Assert(S[2] = 5, 'Sort'); Assert(S[3] = 6, 'Sort'); Assert(T[0] = 4, 'Sort'); Assert(T[1] = 2, 'Sort'); Assert(T[2] = 3, 'Sort'); Assert(T[3] = 1, 'Sort'); end; procedure SelfTest; begin Test_Misc; Test_BitFunctions; Test_IntegerArray; end; end.