Unit CastleUtils

DescriptionUsesClasses, Interfaces, Objects and RecordsFunctions and ProceduresTypesConstantsVariables

Description

Various basic utilities. Developed for "Castle Game Engine", but generally usable.

  • Lists of primitives, using FPC generics. Like TIntegerList, TFloatList etc.

  • Basic operations on numbers.

  • Some OS-dependent things.

  • Filenames operations (they somehow complement the standard set of routines in SysUtils).

  • Basic algorithms: Sort.

This unit is a bag for simple and generally useful things. As a rule (to not let myself put too much things here) this unit must not depend on the Classes unit (see CastleClassUtils for those). Or any higher-level GUI libs like LCL, VCL, or CLX. The only classes defined and used here are exceptions (the base Exception class comes from SysUtils unit) and primitives lists classes.

Initialization of this unit does some generally-useful things:

  • Calls Randomize (so that you never forget about it).

  • Sets DecimalSeparator to '.'.

    Delphi and FPC define DecimalSeparator based on local settings (like configured user's country). But this makes things like StrToFloat and FloatToStr less predictable — they may give different results on different systems, which limits their use. E.g. FloatToStr(0.9) may output '0,9' on some system. And if you write '0,9' to a text file, it may not be understood by StrToFloat on some other system.

    Initial (probably localized) value of DecimalSeparator is saved in LocaleDecimalSeparator variable.

  • Installs my handler for ExceptProc, see comments at HaltCodeOnException.

Uses

  • BaseUnix
  • Unix
  • Dl
  • Variants
  • SysUtils
  • Math
  • FGL

Overview

Classes, Interfaces, Objects and Records

Name Description
Class TCodeBreaker Class to be raised (like an exception) and caught, to exit from some code blocks.
Class EInternalError Internal error in the program.
Class ECheckFailed  
Class TLongWordList  
Class TFloatList  
Class TSingleList  
Class TDoubleList  
Class TCardinalList  
Class TBooleanList  
Class TLongIntList  
Class TIntegerList  
Class EWithHiddenClassName Class of exceptions that will not have ClassName displayed by various routines.
Class BreakProgram Exception specially handled by my exception handler.

Functions and Procedures

procedure Sort(Arr: pointer; ArrRecordSize: Cardinal; IsSmallerFunc: TIsSmallerFunc; IsSmallerFuncData: Pointer; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;
procedure Sort(Arr: pointer; ArrRecordSize: Cardinal; ArrStride: integer; IsSmallerFunc: TIsSmallerFunc; IsSmallerFuncData: Pointer; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;
procedure SortByObject(Arr: pointer; ArrRecordSize: Cardinal; IsSmallerFunc: TIsSmallerFuncByObject; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;
procedure SortByObject(Arr: pointer; ArrRecordSize: Cardinal; ArrStride: integer; IsSmallerFunc: TIsSmallerFuncByObject; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;
procedure Check(TrueValue: boolean; const ErrMessage: string = 'Check failed');
function ArrayPosStr(const A: string; const Arr: array of string): Integer; overload;
function ArrayPosText(const A: string; const Arr: array of string; IgnoreCase: boolean = true): Integer; overload;
function PArrayPosStr(const A: string; Arr: PString; ArrCount: Integer): Integer; overload;
function PArrayPosText(const A: string; Arr: PString; ArrCount: Integer; IgnoreCase: boolean = true): Integer; overload;
function Iff(boolval: boolean; trueval, falseval: string) : string; overload;
function Iff(boolval: boolean; trueval, falseval: Integer) : Integer; overload;
function Iff(boolval: boolean; trueval, falseval: Float) : Float; overload;
function Iff(boolval: boolean; trueval, falseval: Cardinal): Cardinal; overload;
function Iff(boolval: boolean; trueval, falseval: char) : char; overload;
function SFPCVersion: string;
function SCompilerDescription: string;
function SCastleEngineProgramHelpSuffix(const DisplayApplicationName: string; const Version: string; WrapLines: boolean): string;
procedure OSCheck(TrueValue: boolean); overload;
procedure OSCheck(TrueValue: boolean; const Place: string); overload;
function ExceptMessage(E: TObject; ExceptAddr: Pointer = nil): string; overload;
procedure OutputException(E: TObject; ExceptAddr: Pointer = nil); overload;
procedure HaltBool(Value: boolean);
procedure HaltOnException(proc: TProcedure; HaltCode: integer); overload;
procedure HaltOnException(proc: TProcedure); overload;
procedure ProgramBreak(AHaltCode: Integer = 0); overload;
function CastleReadLink(const FileName: string): string;
procedure SwapValues(var a, b: Byte ); overload; inline;
procedure SwapValues(var a, b: Int64 ); overload; inline;
procedure SwapValues(var a, b: Integer ); overload; inline;
procedure SwapValues(var a, b: Cardinal); overload; inline;
procedure SwapValues(var a, b: Single ); overload; inline;
procedure SwapValues(var a, b: Double ); overload; inline;
procedure SwapValues(var a, b: char ); overload; inline;
procedure SwapValues(var a, b: Pointer ); overload; inline;
procedure OrderUp(var Smaller, Larger: Int64 ); overload; inline;
procedure OrderUp(var Smaller, Larger: Integer ); overload; inline;
procedure OrderUp(var Smaller, Larger: Cardinal); overload; inline;
procedure OrderUp(var Smaller, Larger: Single ); overload; inline;
procedure OrderUp(var Smaller, Larger: Double ); overload; inline;
procedure OrderUp(x, y: Integer; var Smaller, Larger: Integer ); overload; inline;
procedure OrderUp(x, y: Cardinal; var Smaller, Larger: Cardinal); overload; inline;
procedure OrderUp(x, y: Single; var Smaller, Larger: Single ); overload; inline;
procedure OrderUp(x, y: Double; var Smaller, Larger: Double ); overload; inline;
function min(const a, b: Int64 ): Int64 ; overload; inline;
function min(const a, b: integer ): integer ; overload; inline;
function min(const a, b: cardinal): cardinal; overload; inline;
function min(const a, b: Single ): Single ; overload; inline;
function min(const a, b: Double ): Double ; overload; inline;
function min(const a, b, c: Int64 ): Int64 ; overload; inline;
function min(const a, b, c: integer ): integer ; overload; inline;
function min(const a, b, c: cardinal): cardinal; overload; inline;
function min(const a, b, c: Single ): Single ; overload; inline;
function min(const a, b, c: Double ): Double ; overload; inline;
function max(const a, b: Int64 ): Int64 ; overload; inline;
function max(const a, b: integer ): integer ; overload; inline;
function max(const a, b: cardinal): cardinal; overload; inline;
function max(const a, b: Single ): Single ; overload; inline;
function max(const a, b: Double ): Double ; overload; inline;
function max(const a, b, c: Int64 ): Int64 ; overload; inline;
function max(const a, b, c: integer ): integer ; overload; inline;
function max(const a, b, c: cardinal): cardinal; overload; inline;
function max(const a, b, c: Single ): Single ; overload; inline;
function max(const a, b, c: Double ): Double ; overload; inline;
procedure MinTo1st(var a: Int64 ; const b: Int64 ); overload; inline;
procedure MinTo1st(var a: Integer ; const b: Integer ); overload; inline;
procedure MinTo1st(var a: Cardinal; const b: Cardinal); overload; inline;
procedure MinTo1st(var a: Single ; const b: Single ); overload; inline;
procedure MinTo1st(var a: Double ; const b: Double ); overload; inline;
procedure MaxTo1st(var a: Int64 ; const b: Int64 ); overload; inline;
procedure MaxTo1st(var a: Integer ; const b: Integer ); overload; inline;
procedure MaxTo1st(var a: Cardinal; const b: Cardinal); overload; inline;
procedure MaxTo1st(var a: Single ; const b: Single ); overload; inline;
procedure MaxTo1st(var a: Double ; const b: Double ); overload; inline;
function IndexMax(const a0, a1, a2: Double): Integer; overload; inline;
function IndexMin(const a0, a1, a2: Double): Integer; overload; inline;
function Between(const a, vBegin, vEnd: Int64 ): boolean; overload; inline;
function Between(const a, vBegin, vEnd: integer ): boolean; overload; inline;
function Between(const a, vBegin, vEnd: cardinal): boolean; overload; inline;
function Between(const a, vBegin, vEnd: Float ): boolean; overload; inline;
function Between(const a, vBegin, vEnd: Char ): boolean; overload; inline;
function RoundClamp255(const A: Single): Byte; inline;
function Clamped(const a, vBegin, vEnd: Int64 ): Int64 ; overload; inline;
function Clamped(const a, vBegin, vEnd: integer ): integer ; overload; inline;
function Clamped(const a, vBegin, vEnd: cardinal): cardinal; overload; inline;
function Clamped(const a, vBegin, vEnd: Single ): Single ; overload; inline;
function Clamped(const a, vBegin, vEnd: Double ): Double ; overload; inline;
procedure Clamp(var a: Int64 ; const vBegin, vEnd: Int64 ); overload; inline;
procedure Clamp(var a: integer ; const vBegin, vEnd: integer ); overload; inline;
procedure Clamp(var a: cardinal; const vBegin, vEnd: cardinal); overload; inline;
procedure Clamp(var a: Single ; const vBegin, vEnd: Single ); overload; inline;
procedure Clamp(var a: Double ; const vBegin, vEnd: Double ); overload; inline;
procedure RestOf3dCoords(coord: integer; out first, second: integer);
function ChangeIntCycle(value, change, maxValue: integer): integer;
function Lerp(const a: Single; const l, h: Integer): Single; overload; inline;
function Lerp(const a: Single; const l, h: Cardinal): Single; overload; inline;
function Lerp(const a, l, h: Single): Single; overload; inline;
function Lerp(const a: Double; const l, h: Integer): Double; overload; inline;
function Lerp(const a: Double; const l, h: Cardinal): Double; overload; inline;
function Lerp(const a, l, h: Double): Double; overload; inline;
function RoundUpToMultiply(value, multiplicator: Integer): Integer;
function BiggestPowerOf2(Value: Cardinal): Cardinal;
function Biggest2Exponent(Value: Cardinal): integer;
function Smallest2Exponent(Value: Cardinal): Integer;
function Smallest2Power(Value: Cardinal): Cardinal;
function IsPowerOf2(Value: Cardinal): boolean;
function DivRoundUp(Value, Divider: Cardinal): Cardinal; overload;
function DivRoundUp(Value, Divider: Integer): Integer; overload;
function MapRange(sourceVal, sourceBegin, sourceEnd, destBegin, destEnd: integer): float; overload;
function MapRange(sourceVal, sourceBegin, sourceEnd, destBegin, destEnd: float ): float; overload;
function RandomFloatRange(const RangeBegin, RangeEnd: Float): Float;
function AngleRadPointToPoint(x1, y1, x2, y2: Single): Single;
function NatNatPower(Base, Exponent: Cardinal): Cardinal;
function RandomPlusMinus: integer;
function ArcCot(x: Float): Float;
function SmallFactorial(n: Integer): Int64;
procedure CastleDivMod(Dividend: Integer; Divisor: Word; out Result, Remainder: SmallInt);
procedure DivUnsignedMod(Dividend: Integer; Divisor: Word; out Result: Smallint; out Remainder: Word);
function CeilDiv(const A, B: Cardinal): Cardinal;
procedure FloatDivMod(const A, B: Double; out DivResult: Int64; out Remainder: Double);
function FloatModulo(const A, B: Double): Double;
procedure MinMax(const x0, x1, x2: Double; out min, max: Double); overload;
procedure MinMax(const x0, x1, x2: Single; out min, max: Single); overload;
function CastleCoTan(const Value: Float): Float;
function IntSqrt(const Value: Cardinal): Cardinal;
function SmoothStep(const Edge0, Edge1, X: Single): Single;
function DeleteFileExt(const FileName: string): string;
function ExtractFileDoubleExt(const FileName: string): string;
function ExtractOnlyFilename(const FileName: string): string; deprecated;
function ChangeFilePath(const FileName, NewPath: string): string; deprecated;
function InclPathDelim(const s: string): string;
function ExclPathDelim(const s: string): string;
function IsPathAbsolute(const Path: string): boolean;
function IsPathAbsoluteOnDrive(const Path: string): boolean;
function SpecialDirName(const DirectoryName: string): boolean;
function AppendToFilename(const FileName, Suffix: string): string;
function PointerAdd(p: pointer; add: integer): pointer;
function GetClearMem(Size: integer; ClearValue: byte = 0): pointer; overload;
procedure FreeMemNiling(var p: pointer);
function CheckIsMemCharFilled(const Data; Size: Integer; AChar: Char): Integer;
function IsMemCharFilled(const Data; Size: Integer; AChar: Char): boolean;
function IsMemWordFilled(const Data; Size: Integer; Value: Word): boolean;
function IsMemDWordFilled(const Data; Size: Integer; Value: DWord): boolean;
function Offset(var A, B): Pointer;
procedure ErrorWrite(const s: string); overload;
procedure WarningWrite(const s: string); overload;
procedure InfoWrite(const s: string); overload;
procedure ErrorWrite(const s: string; const args: array of const); overload;
procedure WarningWrite(const s: string; const args: array of const); overload;
procedure InfoWrite(const s: string; const args: array of const); overload;
procedure InfoWriteParts(const TitleFormat: string; const Messages: array of string); deprecated;

Types

TIsSmallerFunc = function (const A, B, Data: Pointer): boolean;
TIsSmallerFuncByObject = function (const A, B: Pointer): boolean of object;
Float = Math.Float;
PFloat = Math.PFloat;
PCardinal = ˆCardinal;
PLongWord = ˆLongWord;
PShortint = ˆShortint;
PBoolean = ˆBoolean;
PByteArray = ˆTByteArray;
TByteArray = array[0..MaxInt div SizeOf(Byte)-1] of Byte;
TArray_PChar = array[0..MaxInt div SizeOf(PChar)-1]of PChar;
PArray_PCharTArray_PChar;
TArray_TObject = array[0..MaxInt div SizeOf(Pointer)-1]of TObject;
PArray_TObjectTArray_TObject;
PString = ˆAnsiString;
PtrObject = ˆTObject;
TArray_Single = packed array [0..MaxInt div SizeOf(Single) - 1] of Single;
PArray_Single = ˆTArray_Single;
TArray_LongInt = packed array [0..MaxInt div SizeOf(LongInt) - 1] of LongInt;
PArray_LongInt = ˆTArray_LongInt;

Constants

DefaultCountToUseSimpleSort = 10;
NL = LineEnding;
enatural = 2.71828182845905;
sqrt2 = 1.4142135623730950488016887242097;
Sqrt3 = 1.7320508075688773;
HalfPi = 1.57079632679489661923;
RootDir = '/' ;
ExeExtension = '' ;

Variables

BonusErrorMessg: string ='';
HaltCodeOnException: Integer = 1;
LocaleDecimalSeparator: char;

Description

Functions and Procedures

procedure Sort(Arr: pointer; ArrRecordSize: Cardinal; IsSmallerFunc: TIsSmallerFunc; IsSmallerFuncData: Pointer; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;

Sort given table of items.

Sorts items ascending, that is Arr[FirstIndex] <= ... <= Arr[LastIndex].

Parameters
Arr
Pointer to items array in memory.
ArrRecordSize
Size (in bytes) of every item. This is the size of item that will be moved around in the memory.
IsSmallerFunc
Comparison function, should return is "A < B" true.

I'm assuming here that IsSmallerFunc works like mathematical "<": it's not reflexive (IsSmallerFunc(A, A) = False), for A <> B exactly one of IsSmallerFunc(A, B) or IsSmallerFunc(B, A) is true, and it's transitive.

Note that IsSmallerFunc gets only the pointers to the items. These may be pointers to the Arr, or a pointer to internal temporary copy of some array item. So IsSmallerFunc cannot modify the item underneath (it would not work for internal copy, and also would create problems with types that need initialization/finalization since our internal copy is done using low-level memory copying.)

FirstIndex
FirstIndex and LastIndex allow you to sort only given part of the array. We don't touch items outside of this range. Note that you could achieve the effect of FirstIndex > 0 also by increasing the Arr pointer, but FirstIndex is usually more comfortable.

If FirstIndex > LastIndex, we do nothing.

ArrStride
Distance (in bytes) between array items in memory. If you don't provide it, we'll assume ArrRecordSize. ArrStride is useful if your array is interleaved with another array, and you want to keep the other data untouched by sorting.

ArrStride must be > 0, actually it must be > ArrRecordSize for sensible behavior. (Unless ArrRecordSize is 0, then ArrStride may be 0 too.).

procedure Sort(Arr: pointer; ArrRecordSize: Cardinal; ArrStride: integer; IsSmallerFunc: TIsSmallerFunc; IsSmallerFuncData: Pointer; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;
 
procedure SortByObject(Arr: pointer; ArrRecordSize: Cardinal; IsSmallerFunc: TIsSmallerFuncByObject; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;
 
procedure SortByObject(Arr: pointer; ArrRecordSize: Cardinal; ArrStride: integer; IsSmallerFunc: TIsSmallerFuncByObject; FirstIndex, LastIndex: integer; CountToUseSimpleSort: Integer = DefaultCountToUseSimpleSort); overload;
 
procedure Check(TrueValue: boolean; const ErrMessage: string = 'Check failed');

Check condition.

Exceptions raised
ECheckFailed
Raised with ErrMessage if condition TrueValue if false.
function ArrayPosStr(const A: string; const Arr: array of string): Integer; overload;

Search the array for a given value. Returns index (zero-based) or -1 if not found.

Useful for writing case as:

  case ArrayPosStr(variable, [val1, val2]) of
    0 : Something1;
    1 : Something2;
    else SomethingElse;
  end;

function ArrayPosText(const A: string; const Arr: array of string; IgnoreCase: boolean = true): Integer; overload;
 
function PArrayPosStr(const A: string; Arr: PString; ArrCount: Integer): Integer; overload;
 
function PArrayPosText(const A: string; Arr: PString; ArrCount: Integer; IgnoreCase: boolean = true): Integer; overload;
 
function Iff(boolval: boolean; trueval, falseval: string) : string; overload;
 
function Iff(boolval: boolean; trueval, falseval: Integer) : Integer; overload;
 
function Iff(boolval: boolean; trueval, falseval: Float) : Float; overload;
 
function Iff(boolval: boolean; trueval, falseval: Cardinal): Cardinal; overload;
 
function Iff(boolval: boolean; trueval, falseval: char) : char; overload;
 
function SFPCVersion: string;

Describe FPC version. In the form 'version.release.patch'.

This is actually a constant (for every run of a program it has always the same value) but I can't declare it as a Pascal constant because it must use "Format" function that is not allowed in constant expressions.

function SCompilerDescription: string;

Short name and version of Pascal compiler used to compile this unit. It is a constant, actually, but I cannot declare it as a constant because it must call SFPCVersion that is not declared as a constant.

function SCastleEngineProgramHelpSuffix(const DisplayApplicationName: string; const Version: string; WrapLines: boolean): string;

Print some common info for programs released on [http://castle-engine.sourceforge.net/]. This is useful only for programs released on this WWW page by Michalis. Resulting string is multiline.

Parameters
DisplayApplicationName
Usually ApplicationName, but you can give here something else if you want.
Version
For my programs this usually looks like '%d.%d.%d' and conforms to [http://castle-engine.sourceforge.net/versioning.php]
WrapLines
If true then resulting string will not have lines longer than 80 characters. Suitable for printing program help message on stdout, e.g. in response to --help option.
procedure OSCheck(TrueValue: boolean); overload;

If not TrueValue then RaiseLastOSError.

procedure OSCheck(TrueValue: boolean; const Place: string); overload;
 
function ExceptMessage(E: TObject; ExceptAddr: Pointer = nil): string; overload;

Nice exception description. Contains exception ClassName (if not descends from EWithHiddenClassName), exception Message (if descends from Exception), and ExceptAddr (if not Nil, and code is compiled with -dDEBUG), and BonusErrorMesssg.

procedure OutputException(E: TObject; ExceptAddr: Pointer = nil); overload;

Show nice exception description on console or (for GUI Windows programs) by a message box.

procedure HaltBool(Value: boolean);

If Value then Halt(0), else Halt(1).

It is the standard convention of command-line programs to exit with code 0 on success and <> 0 on failure. Or (for some programs like `test') exit with code 0 to indicate true result and <> 0 to indicate false result. So you will probably want to pass here some boolean variable indicating "Success" or "TestPassed".

procedure HaltOnException(proc: TProcedure; HaltCode: integer); overload;

Call Proc, catch all exceptions inside the Proc, and in case of exception make OutputException and Halt(HaltCode). The result is that HaltOnException doesn't raise any exception, never. It always deals with exceptions inside Proc itself.

Version without HaltCode parameter uses global HaltCodeOnException value.

For the special exception class BreakProgram, it does simply Halt(BreakProgram(E).ExitCode)) (no OutputException in this case).

When symbol DEBUG is defined, then HaltOnException works differently — it just calls Proc (and doesn't catch any exceptions).

This is particularly useful under Delphi/Win32. There main program should never exit with exception. Because such exception (because of Delphi stupidity ?) shows ugly Windows dialog box saying something like "Program exited unexpectedly, contact with author etc. bullshit". There is no way for me to avoid this dialog box, even by my own ExceptProc.

procedure HaltOnException(proc: TProcedure); overload;
 
procedure ProgramBreak(AHaltCode: Integer = 0); overload;

Raise BreakProgram with AHaltCode, causing the program to stop with given exit code nicely (finalizes all exceptions try..finally and such).

function CastleReadLink(const FileName: string): string;

Return the symlink target path. Like Libc.ReadLink or FpReadLink, but more comfortable, it returns a normal Pascal string.

Exceptions raised
EOSError
In case of any failure (non-existing FileName etc.)
procedure SwapValues(var a, b: Byte ); overload; inline;

Swap variables values.

procedure SwapValues(var a, b: Int64 ); overload; inline;
 
procedure SwapValues(var a, b: Integer ); overload; inline;
 
procedure SwapValues(var a, b: Cardinal); overload; inline;
 
procedure SwapValues(var a, b: Single ); overload; inline;
 
procedure SwapValues(var a, b: Double ); overload; inline;
 
procedure SwapValues(var a, b: char ); overload; inline;
 
procedure SwapValues(var a, b: Pointer ); overload; inline;
 
procedure OrderUp(var Smaller, Larger: Int64 ); overload; inline;

Make sure the Smaller value is <= than the Larger value, by eventually swapping them.

procedure OrderUp(var Smaller, Larger: Integer ); overload; inline;
 
procedure OrderUp(var Smaller, Larger: Cardinal); overload; inline;
 
procedure OrderUp(var Smaller, Larger: Single ); overload; inline;
 
procedure OrderUp(var Smaller, Larger: Double ); overload; inline;
 
procedure OrderUp(x, y: Integer; var Smaller, Larger: Integer ); overload; inline;

Assign the smaller value from X, Y to Smaller variable, the other one to Larger variable.

procedure OrderUp(x, y: Cardinal; var Smaller, Larger: Cardinal); overload; inline;
 
procedure OrderUp(x, y: Single; var Smaller, Larger: Single ); overload; inline;
 
procedure OrderUp(x, y: Double; var Smaller, Larger: Double ); overload; inline;
 
function min(const a, b: Int64 ): Int64 ; overload; inline;

Return minimum / maximum from 2 / 3 items.

function min(const a, b: integer ): integer ; overload; inline;
 
function min(const a, b: cardinal): cardinal; overload; inline;
 
function min(const a, b: Single ): Single ; overload; inline;
 
function min(const a, b: Double ): Double ; overload; inline;
 
function min(const a, b, c: Int64 ): Int64 ; overload; inline;
 
function min(const a, b, c: integer ): integer ; overload; inline;
 
function min(const a, b, c: cardinal): cardinal; overload; inline;
 
function min(const a, b, c: Single ): Single ; overload; inline;
 
function min(const a, b, c: Double ): Double ; overload; inline;
 
function max(const a, b: Int64 ): Int64 ; overload; inline;
 
function max(const a, b: integer ): integer ; overload; inline;
 
function max(const a, b: cardinal): cardinal; overload; inline;
 
function max(const a, b: Single ): Single ; overload; inline;
 
function max(const a, b: Double ): Double ; overload; inline;
 
function max(const a, b, c: Int64 ): Int64 ; overload; inline;
 
function max(const a, b, c: integer ): integer ; overload; inline;
 
function max(const a, b, c: cardinal): cardinal; overload; inline;
 
function max(const a, b, c: Single ): Single ; overload; inline;
 
function max(const a, b, c: Double ): Double ; overload; inline;
 
procedure MinTo1st(var a: Int64 ; const b: Int64 ); overload; inline;

Update value of A to be a minimum of A, B. Works like A := Min(A, B), but is marginally faster, since you don't have to do anything when A is already smaller.

procedure MinTo1st(var a: Integer ; const b: Integer ); overload; inline;
 
procedure MinTo1st(var a: Cardinal; const b: Cardinal); overload; inline;
 
procedure MinTo1st(var a: Single ; const b: Single ); overload; inline;
 
procedure MinTo1st(var a: Double ; const b: Double ); overload; inline;
 
procedure MaxTo1st(var a: Int64 ; const b: Int64 ); overload; inline;

Update value of A to be a maximum of A, B. Works like A := Max(A, B), but is marginally faster, since you don't have to do anything when A is already larger.

procedure MaxTo1st(var a: Integer ; const b: Integer ); overload; inline;
 
procedure MaxTo1st(var a: Cardinal; const b: Cardinal); overload; inline;
 
procedure MaxTo1st(var a: Single ; const b: Single ); overload; inline;
 
procedure MaxTo1st(var a: Double ; const b: Double ); overload; inline;
 
function IndexMax(const a0, a1, a2: Double): Integer; overload; inline;

Index (0, 1 or 2) of maximum / minimum of 3 numbers.

function IndexMin(const a0, a1, a2: Double): Integer; overload; inline;
 
function Between(const a, vBegin, vEnd: Int64 ): boolean; overload; inline;
 
function Between(const a, vBegin, vEnd: integer ): boolean; overload; inline;
 
function Between(const a, vBegin, vEnd: cardinal): boolean; overload; inline;
 
function Between(const a, vBegin, vEnd: Float ): boolean; overload; inline;
 
function Between(const a, vBegin, vEnd: Char ): boolean; overload; inline;
 
function RoundClamp255(const A: Single): Byte; inline;
 
function Clamped(const a, vBegin, vEnd: Int64 ): Int64 ; overload; inline;
 
function Clamped(const a, vBegin, vEnd: integer ): integer ; overload; inline;
 
function Clamped(const a, vBegin, vEnd: cardinal): cardinal; overload; inline;
 
function Clamped(const a, vBegin, vEnd: Single ): Single ; overload; inline;
 
function Clamped(const a, vBegin, vEnd: Double ): Double ; overload; inline;
 
procedure Clamp(var a: Int64 ; const vBegin, vEnd: Int64 ); overload; inline;
 
procedure Clamp(var a: integer ; const vBegin, vEnd: integer ); overload; inline;
 
procedure Clamp(var a: cardinal; const vBegin, vEnd: cardinal); overload; inline;
 
procedure Clamp(var a: Single ; const vBegin, vEnd: Single ); overload; inline;
 
procedure Clamp(var a: Double ; const vBegin, vEnd: Double ); overload; inline;
 
procedure RestOf3dCoords(coord: integer; out first, second: integer);

3D coordinates (0, 1 or 2) except the given coordinate. If Coord = 0, then it sets First = 1 and Second = 2. And so on — for each Coord value, we set First and Second to the remaining indexes.

function ChangeIntCycle(value, change, maxValue: integer): integer;

Increase Value by Change, nicely wrapping in [0..MaxValue], accepting also negative Change. The final value is always in the [0..MaxValue] range, even when initial Value was outside.

function Lerp(const a: Single; const l, h: Integer): Single; overload; inline;

Linear interpolation between two values. Returns (1-A)*L + A*H.

function Lerp(const a: Single; const l, h: Cardinal): Single; overload; inline;
 
function Lerp(const a, l, h: Single): Single; overload; inline;
 
function Lerp(const a: Double; const l, h: Integer): Double; overload; inline;
 
function Lerp(const a: Double; const l, h: Cardinal): Double; overload; inline;
 
function Lerp(const a, l, h: Double): Double; overload; inline;
 
function RoundUpToMultiply(value, multiplicator: Integer): Integer;

Smallest multiple of Multiplicator that is still >= Value.

function BiggestPowerOf2(Value: Cardinal): Cardinal;

Largest power of 2 still <= Value. When Value = 0 returns 0.

function Biggest2Exponent(Value: Cardinal): integer;

Exponent of the largest power of 2 that it's still <= Value. Like BiggestPowerOf2, except that this returns which power of 2 it is, while BiggestPowerOf2 just returns exactly this power. Bigget2Exponent(0) = -1.

function Smallest2Exponent(Value: Cardinal): Integer;

Smallest exponent such that 2ˆthis exponent is >= Value. Smallest2Exponent(0) = -1 (this is different situation than Smallest2Exponent(1), when we return 0.

function Smallest2Power(Value: Cardinal): Cardinal;

Smallest power of 2 that is >= Value. Like Smallest2Exponent, except here we return 2ˆSmallest2Exponent(Value). Returns 0 when Value = 0.

function IsPowerOf2(Value: Cardinal): boolean;

Check is Value an exact power of 2.

function DivRoundUp(Value, Divider: Cardinal): Cardinal; overload;
 
function DivRoundUp(Value, Divider: Integer): Integer; overload;
 
function MapRange(sourceVal, sourceBegin, sourceEnd, destBegin, destEnd: integer): float; overload;

Linearly map value from a one range to another.

Consider how SourceVal is placed in the [SourceBegin .. SourceEnd] (it may be outside of this range, it all still works OK). It has some distance to range start (SourceBegin), and some distance to range end (SourceEnd).

We want to find another number, that is identically placed in another range [DestBegin .. DestEnd].

  1. Such that Distance(SourceVal, SourceBegin) / Distance(SourceVal, SourceEnd) = Distance(Result, DestBegin) / Distance(Result, DestEnd).

  2. And such that it's on the same side of the range. So if SourceVal is beyond SourceEnd (that is, SourceBegin < SourceEnd < SourceVal or SourceBegin > SourceEnd > SourceVal) then the result must be similarly beyond DestEnd.

    As you can see, this works regardless if one, or both, of the ranges increase (range end is larger than range begin).

function MapRange(sourceVal, sourceBegin, sourceEnd, destBegin, destEnd: float ): float; overload;
 
function RandomFloatRange(const RangeBegin, RangeEnd: Float): Float;

Random float value in the given range. Make sure RangeBegin < RangeEnd.

function AngleRadPointToPoint(x1, y1, x2, y2: Single): Single;

Angle between a 2D line segments and OX axis. Angle 0 means that Y1 = Y2 and X2 > X1, then the angle increases as you rotate CCW. In radians.

function NatNatPower(Base, Exponent: Cardinal): Cardinal;

Calculate power Base to Exponent, knowing both arguments (and so, also the result) are >= 0.

function RandomPlusMinus: integer;

Random -1 or +1.

function ArcCot(x: Float): Float;
 
function SmallFactorial(n: Integer): Int64;

Trivial factorial with Int64 result. Beware, the results very quickly stop to fit inside Int64 range.

procedure CastleDivMod(Dividend: Integer; Divisor: Word; out Result, Remainder: SmallInt);

Better DivMod version, in case Dividend may be < 0.

This fixes lack of DivMod with negative Remainder (for FPC at least older than 2.2.4, see fpc-devel thread "Math.DivMod results should be signed" on 2006-03-21, http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg04565.html).

And workarounds faulty DivMod behavior with FPC 2.4.0, see http://bugs.freepascal.org/view.php?id=15453

procedure DivUnsignedMod(Dividend: Integer; Divisor: Word; out Result: Smallint; out Remainder: Word);

Like DivMod (return result of integer division and a remainder), but always return Remainder >= 0.

This is useful in case when Dividend < 0. Standard DivMod (and Pascal div and mod operators) return then Result rounded toward zero, and Remainder may be < 0. This procedure will return Result rounded toward negative infinity, and Remainder will always be >= 0.

function CeilDiv(const A, B: Cardinal): Cardinal;

Returns Ceil(A / B), but calculated faster and more precisely (without floating-point help).

procedure FloatDivMod(const A, B: Double; out DivResult: Int64; out Remainder: Double);

Calculate integer division and modulo on two float arguments. Requires that A >= 0 and B > 0, and the Result is always >= 0.

Tries to secure against floating point imprecision. It's always guaranteed that Remainder >= 0 and <= B (and usually should be < B, but this cannot be guaranteed).

function FloatModulo(const A, B: Double): Double;

Calculate float modulo of division on two float arguments. Works for any A (lesser than zero too). Assumes that B > 0.

Tries to secure against floating point imprecision. It's always guaranteed that Remainder >= 0 and <= B (and usually should be < B, but this cannot be guaranteed).

procedure MinMax(const x0, x1, x2: Double; out min, max: Double); overload;
 
procedure MinMax(const x0, x1, x2: Single; out min, max: Single); overload;
 
function CastleCoTan(const Value: Float): Float;

Our version of CoTan, to workaround http://www.freepascal.org/mantis/view.php?id=9944.

function IntSqrt(const Value: Cardinal): Cardinal;

Floor from Sqrt(Value).

function SmoothStep(const Edge0, Edge1, X: Single): Single;

Hermite interpolation between two values. Just like GLSL smoothstep: http://www.khronos.org/opengles/sdk/docs/manglsl/xhtml/smoothstep.xml

function DeleteFileExt(const FileName: string): string;

Remove from the FileName the last extension (including the dot). Note that if the FileName had a couple of extensions (e.g. blah.x3d.gz) this will remove only the last one. Will remove nothing if filename has no extension.

It is not adviced to use this function, better to operate on URLs and MIME types instead of filenames and extensions, see CastleURIUtils.

function ExtractFileDoubleExt(const FileName: string): string;

Extracts two last extensions from the filename, if it has two extensions. If the filename has only one extension, returns that one extension, if the filename has no extension — returns empty string, similar to ExtractFileExt.

This is useful to detect file types from filenames like model.x3d.gz, where ExtractFileExt returns only .gz. This function will return .x3d.gz.

It is not adviced to use this function, better to operate on URLs and MIME types instead of filenames and extensions, see CastleURIUtils.

function ExtractOnlyFilename(const FileName: string): string; deprecated;

Warning: this symbol is deprecated.

Extracts from FileName the name of file, without directory, without last extension and without any Windows drive letter.

Deprecated, since we use URLs everywhere and also because this has very low usage. Use DeleteURIExt(ExtractURIName(URL)) if you really need to.

function ChangeFilePath(const FileName, NewPath: string): string; deprecated;

Warning: this symbol is deprecated.

Returns FileName with directory (path) part replaced with given NewPath. NewPath must contain trailing PathDelim.

Deprecated, since we use URLs everywhere and also because this has very low usage.

function InclPathDelim(const s: string): string;

Include / exclude the last path delimiter, if necessary. They are just comfortable shorter names for IncludeTrailingPathDelimiter and ExcludeTrailingPathDelimiter.

function ExclPathDelim(const s: string): string;
 
function IsPathAbsolute(const Path: string): boolean;

Check is the given Path absolute.

Path may point to directory or normal file, it doesn't matter. Also it doesn't matter whether Path ends with PathDelim or not.

Note for Windows: while it's obvious that 'c:\autoexec.bat' is an absolute path, and 'autoexec.bat' is not, there's a question whether path like '\autoexec.bat' is absolute? It doesn't specify drive letter, but it does specify full directory hierarchy on some drive. This function treats this as not absolute, on the reasoning that "not all information is contained in Path".

See also
IsPathAbsoluteOnDrive
Just like IsPathAbsolute, but on Windows accepts also paths that specify full directory tree without drive letter.
function IsPathAbsoluteOnDrive(const Path: string): boolean;

Just like IsPathAbsolute, but on Windows accepts also paths that specify full directory tree without drive letter.

See also
IsPathAbsolute
Check is the given Path absolute.
function SpecialDirName(const DirectoryName: string): boolean;

Checks is the directory name special, like "." or "..".

The precise definition of "special" is that you cannot ever create or even have any filenames / directories named like this.

function AppendToFilename(const FileName, Suffix: string): string;

Add Suffix to the filename, right before extension. Returns DeleteFileExt(FileName) + Suffix + ExtractFileExt(FileName).

function PointerAdd(p: pointer; add: integer): pointer;

Pointer arithmetic. Will wrap over if you add too much. Add may be negative. This is just a shortcut for PtrInt(Result) := PtrInt(P)+Add, without any range / overflow checks.

function GetClearMem(Size: integer; ClearValue: byte = 0): pointer; overload;
 
procedure FreeMemNiling(var p: pointer);

Safer version of FreeMem, checks is parameter Nil, and sets it to Nil afterwards.

function CheckIsMemCharFilled(const Data; Size: Integer; AChar: Char): Integer;

Check is memory filled with the given character. Returns -1 is True, or the number (between 0 .. Size - 1) or the first character different than AChar.

function IsMemCharFilled(const Data; Size: Integer; AChar: Char): boolean;

Check is memory filled with the given character. Returns simple boolean, use CheckIsMemCharFilled to get more informative result.

function IsMemWordFilled(const Data; Size: Integer; Value: Word): boolean;

Check is memory filled with the Word (2 byte sequence). Size if the number of words (not bytes), this is consequent with Size parameter from FillWord from FPC's RTL.

function IsMemDWordFilled(const Data; Size: Integer; Value: DWord): boolean;

Check is memory filled with the DWord (4 byte sequence). Size if the number of dwords (not bytes), this is consequent with Size parameter from FillDWord from FPC's RTL.

function Offset(var A, B): Pointer;

Calculate shift between A and B addresses (in bytes), and cast to Pointer. Useful to pass as offsets to OpenGL glVertexPointer and similar functions. This is simply Result := A - B, except we do some typecasting.

procedure ErrorWrite(const s: string); overload;

Write using a dialog box or console.

If we are a Windows GUI program (not IsConsole) then we use native Windows dialog boxes. Otherwise (a console is available, which is always true on non-Windows) we output the message using simple Writeln (to standard output for InfoWrite, or ErrOutput for ErrorWrite and WarningWrite).

procedure WarningWrite(const s: string); overload;
 
procedure InfoWrite(const s: string); overload;
 
procedure ErrorWrite(const s: string; const args: array of const); overload;
 
procedure WarningWrite(const s: string; const args: array of const); overload;
 
procedure InfoWrite(const s: string; const args: array of const); overload;
 
procedure InfoWriteParts(const TitleFormat: string; const Messages: array of string); deprecated;

Warning: this symbol is deprecated.

Output messages, using console or dialog box.

If we're not on Windows or IsConsole, then we simply output Messages using Writeln.

If we're on Windows and not IsConsole, then every Messages is displayed in a separate dialog box. Dialog box uses our InfoBox routine, with Messages[I] being message content and title being Format(TitleFormat, [I + 1, Messages.Count]).

This is good for outputting a lot of information.

Deprecated. This just looks ugly in GUI version. It's better to present long information using only a console (just use Writeln), or only a full-featured GUI (like Lazarus LCL or our CastleUIControls).

Types

TIsSmallerFunc = function (const A, B, Data: Pointer): boolean;
 
TIsSmallerFuncByObject = function (const A, B: Pointer): boolean of object;
 
Float = Math.Float;
 
PFloat = Math.PFloat;
 
PCardinal = ˆCardinal;
 
PLongWord = ˆLongWord;
 
PShortint = ˆShortint;
 
PBoolean = ˆBoolean;

Pointer to a boolean. Defined as ˆByte in some Delphi Windows unit, for FPC 1.0.x PBoolean is not available at all.

PByteArray = ˆTByteArray;
 
TByteArray = array[0..MaxInt div SizeOf(Byte)-1] of Byte;
 
TArray_PChar = array[0..MaxInt div SizeOf(PChar)-1]of PChar;
 
PArray_PCharTArray_PChar;
 
TArray_TObject = array[0..MaxInt div SizeOf(Pointer)-1]of TObject;
 
PArray_TObjectTArray_TObject;
 
PString = ˆAnsiString;
 
PtrObject = ˆTObject;

Pointer to TObject. Don't call this PObject or PTObject to avoid possible name clashes with other units (pointers are often used in situations that prevent good type-checking, so better to avoid name clashes to avoid some nasty errors).

TArray_Single = packed array [0..MaxInt div SizeOf(Single) - 1] of Single;
 
PArray_Single = ˆTArray_Single;
 
TArray_LongInt = packed array [0..MaxInt div SizeOf(LongInt) - 1] of LongInt;
 
PArray_LongInt = ˆTArray_LongInt;
 

Constants

DefaultCountToUseSimpleSort = 10;

When should the complicated sorting algorithm fallback to a simpler one. If number of items is <= CountToUseSimpleSort, then Sort will fallback to SimpleSort (= sort by choosing for now) instead of recursive QuickSort. Set CountToUseSimpleSort = 0 to make it never fall back to SimpleSort.

By default this is DefaultCountToUseSimpleSort.

NL = LineEnding;

New line. Short name for LineEnding.

enatural = 2.71828182845905;
 
sqrt2 = 1.4142135623730950488016887242097;
 
Sqrt3 = 1.7320508075688773;
 
HalfPi = 1.57079632679489661923;

Half of Pi. Taken from FPC sources, file rtl/inc/genmath.inc

RootDir = '/' ;

Root dir name. Empty if not applicable to this OS.

ExeExtension = '' ;
 

Variables

BonusErrorMessg: string ='';

Additional message output when you end program with an exception.

HaltCodeOnException: Integer = 1;
 
LocaleDecimalSeparator: char;