///Stuff common for the OmniThreadLibrary project. ///Primoz Gabrijelcic /// ///This software is distributed under the BSD license. /// ///Copyright (c) 2009, Primoz Gabrijelcic ///All rights reserved. /// ///Redistribution and use in source and binary forms, with or without modification, ///are permitted provided that the following conditions are met: ///- Redistributions of source code must retain the above copyright notice, this /// list of conditions and the following disclaimer. ///- Redistributions in binary form must reproduce the above copyright notice, /// this list of conditions and the following disclaimer in the documentation /// and/or other materials provided with the distribution. ///- The name of the Primoz Gabrijelcic may not be used to endorse or promote /// products derived from this software without specific prior written permission. /// ///THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ///ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ///WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ///DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ///ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ///(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ///LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ///ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ///(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ///SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// /// /// Home : http://otl.17slon.com /// Support : http://otl.17slon.com/forum/ /// Author : Primoz Gabrijelcic /// E-Mail : primoz@gabrijelcic.org /// Blog : http://thedelphigeek.com /// Web : http://gp.17slon.com /// Contributors : GJ, Lee_Nover /// /// Creation date : 2008-06-12 /// Last modification : 2009-01-26 /// Version : 1.01 /// /// History: /// 1.01: 2009-01-26 /// - Implemented TOmniCS critical section wrapper. /// - Added TOmniWaitableValue class. /// 1.0d: 2008-10-05 /// - Use GetGoodHashSize from GpStringHash unit. /// 1.0c: 2008-09-26 /// - Check PostMessage result. /// 1.0b: 2008-09-19 /// - Bug fixed: TOmniValue.Null was not really initialized to Null. /// 1.0a: 2008-09-02 /// - Fixed memory leak that could occur in TOmniMonitorSupport.Notify (in fact it /// was possible to cause it in demo 11). /// 1.0: 2008-08-26 /// - First official release. /// {$WARN SYMBOL_PLATFORM OFF} unit OtlCommon; interface uses Windows, SysUtils, Classes, Variants, SyncObjs, GpStuff; const // reserved exit statuses EXIT_OK = 0; EXIT_EXCEPTION = integer($80000000); EXIT_THREADPOOL_QUEUE_TOO_LONG = EXIT_EXCEPTION + 1; EXIT_THREADPOOL_STALE_TASK = EXIT_EXCEPTION + 2; EXIT_THREADPOOL_CANCELLED = EXIT_EXCEPTION + 3; EXIT_THREADPOOL_INTERNAL_ERROR = EXIT_EXCEPTION + 4; type TOmniValue = packed record private ovData: int64; ovIntf: IInterface; ovType: (ovtNull, ovtBoolean, ovtInteger, ovtDouble, ovtExtended, ovtString, ovtObject, ovtInterface, ovtVariant); function GetAsBoolean: boolean; inline; function GetAsCardinal: cardinal; inline; function GetAsDouble: Double; function GetAsExtended: Extended; function GetAsInt64: int64; inline; function GetAsInteger: integer; inline; function GetAsInterface: IInterface; inline; function GetAsObject: TObject; inline; function GetAsString: string; function GetAsVariant: Variant; function GetAsVariantArr(idx: integer): Variant; procedure SetAsBoolean(const value: boolean); inline; procedure SetAsCardinal(const value: cardinal); inline; procedure SetAsDouble(value: Double); inline; procedure SetAsExtended(value: Extended); procedure SetAsInt64(const value: int64); inline; procedure SetAsInteger(const value: integer); inline; procedure SetAsInterface(const value: IInterface); inline; procedure SetAsObject(const value: TObject); inline; procedure SetAsString(const value: string); procedure SetAsVariant(const value: Variant); public procedure Clear; inline; function IsBoolean: boolean; inline; function IsEmpty: boolean; inline; function IsFloating: boolean; inline; function IsInterface: boolean; inline; function IsObject: boolean; inline; function IsString: boolean; inline; function IsVariant: boolean; inline; class function Null: TOmniValue; static; function RawData: PInt64; inline; procedure RawZero; inline; class operator Equal(const a: TOmniValue; i: integer): boolean; inline; class operator Equal(const a: TOmniValue; const s: string): boolean; inline; class operator Implicit(const a: boolean): TOmniValue; inline; class operator Implicit(const a: Double): TOmniValue; inline; class operator Implicit(const a: Extended): TOmniValue; class operator Implicit(const a: integer): TOmniValue; inline; class operator Implicit(const a: int64): TOmniValue; inline; class operator Implicit(const a: string): TOmniValue; class operator Implicit(const a: IInterface): TOmniValue; class operator Implicit(const a: TObject): TOmniValue; inline; class operator Implicit(const a: TOmniValue): int64; inline; class operator Implicit(const a: TOmniValue): TObject; inline; class operator Implicit(const a: TOmniValue): Double; inline; class operator Implicit(const a: TOmniValue): Extended; class operator Implicit(const a: TOmniValue): IInterface; class operator Implicit(const a: TOmniValue): integer; inline; class operator Implicit(const a: TOmniValue): string; class operator Implicit(const a: TOmniValue): boolean; inline; class operator Implicit(const a: Variant): TOmniValue; inline; property AsBoolean: boolean read GetAsBoolean write SetAsBoolean; property AsCardinal: cardinal read GetAsCardinal write SetAsCardinal; property AsDouble: Double read GetAsDouble write SetAsDouble; property AsExtended: Extended read GetAsExtended write SetAsExtended; property AsInt64: int64 read GetAsInt64 write SetAsInt64; property AsInteger: integer read GetAsInteger write SetAsInteger; property AsInterface: IInterface read GetAsInterface write SetAsInterface; property AsObject: TObject read GetAsObject write SetAsObject; property AsString: string read GetAsString write SetAsString; property AsVariant: Variant read GetAsVariant write SetAsVariant; property AsVariantArr[idx: integer]: Variant read GetAsVariantArr; default; end; { TOmniValue } TOmniWaitableValue = class public Handle: THandle; Value : TOmniValue; constructor Create; destructor Destroy; override; procedure Reset; inline; procedure Signal; overload; inline; procedure Signal(const data: TOmniValue); overload; inline; function WaitFor(maxWait_ms: cardinal = INFINITE): boolean; inline; end; { Implicit } TOmniValueContainer = class strict private ovcCanModify: boolean; ovcNames : TStringList; ovcValues : array of TOmniValue; strict protected procedure Clear; procedure Grow; public constructor Create; destructor Destroy; override; procedure Add(const paramValue: TOmniValue; paramName: string = ''); procedure Assign(const parameters: array of TOmniValue); function IsLocked: boolean; inline; procedure Lock; inline; function ParamByIdx(paramIdx: integer): TOmniValue; function ParamByName(const paramName: string): TOmniValue; end; { TOmniValueContainer } IOmniMonitorParams = interface function GetLParam: integer; function GetMessage: cardinal; function GetWindow: THandle; function GetWParam: integer; // property Window: THandle read GetWindow; property Msg: cardinal read GetMessage; property WParam: integer read GetWParam; property LParam: integer read GetLParam; end; { IOmniMonitorParams } IOmniMonitorSupport = interface ['{6D5F1191-9E4A-4DD5-99D8-694C95B0DE90}'] function GetMonitor: IOmniMonitorParams; // procedure Notify; overload; procedure Notify(obj: TObject); overload; procedure RemoveMonitor; procedure SetMonitor(const monitor: IOmniMonitorParams); property Monitor: IOmniMonitorParams read GetMonitor; end; { IOmniMonitorSupport } IOmniCounter = interface ['{3A73CCF3-EDC5-484F-8459-532B8C715E3C}'] function GetValue: integer; procedure SetValue(const value: integer); // function Increment: integer; function Decrement: integer; property Value: integer read GetValue write SetValue; end; { IOmniCounter } TInterfaceDictionaryPair = class strict private idpKey : int64; idpValue: IInterface; protected procedure SetKeyValue(const key: int64; const value: IInterface); public property Key: int64 read idpKey; property Value: IInterface read idpValue; end; { TInterfaceDictionaryPair } IInterfaceDictionaryEnumerator = interface function GetCurrent: TInterfaceDictionaryPair; function MoveNext: boolean; property Current: TInterfaceDictionaryPair read GetCurrent; end; { IInterfaceDictionaryEnumerator } IInterfaceDictionary = interface ['{619FCCF3-E810-4DCF-B902-1EF1A5A72DB5}'] function GetEnumerator: IInterfaceDictionaryEnumerator; // procedure Add(const key: int64; const value: IInterface); procedure Clear; procedure Remove(const key: int64); function ValueOf(const key: int64): IInterface; end; { IInterfaceHash } IOmniCriticalSection = interface ['{AA92906B-B92E-4C54-922C-7B87C23DABA9}'] procedure Acquire; procedure Release; end; { IOmniCriticalSection } TOmniCS = record private ocsSync: IOmniCriticalSection; public procedure Initialize; procedure Acquire; inline; procedure Release; inline; end; { TOmniCS } function CreateCounter(initialValue: integer = 0): IOmniCounter; function CreateOmniMonitorParams(window: THandle; msg: cardinal; wParam, lParam: integer): IOmniMonitorParams; function CreateOmniMonitorSupport: IOmniMonitorSupport; function CreateInterfaceDictionary: IInterfaceDictionary; function CreateOmniCriticalSection: IOmniCriticalSection; procedure SetThreadName(const name: string); function VarToObj(const v: Variant): TObject; inline; var OtlUID: TGp8AlignedInt; implementation uses DSiWin32, GpStringHash; type IOmniStringData = interface ['{21E52E56-390C-4066-B9FC-83862FFBCBF3}'] function GetValue: string; procedure SetValue(const value: string); property Value: string read GetValue write SetValue; end; { IOmniStringData } TOmniStringData = class(TInterfacedObject, IOmniStringData) strict private osdValue: string; public constructor Create(const value: string); function GetValue: string; procedure SetValue(const value: string); property Value: string read GetValue write SetValue; end; { TOmniStringData } IOmniVariantData = interface ['{65311D7D-67F1-452E-A0BD-C90596671FC8}'] function GetValue: Variant; procedure SetValue(const value: Variant); property Value: Variant read GetValue write SetValue; end; { IOmniVariantData } TOmniVariantData = class(TInterfacedObject, IOmniVariantData) strict private ovdValue: Variant; public constructor Create(const value: Variant); function GetValue: Variant; procedure SetValue(const value: Variant); property Value: Variant read GetValue write SetValue; end; { TOmniVariantData } IOmniExtendedData = interface ['{B6CD371F-A461-436A-8767-9BCA194B1D0E}'] function GetValue: Extended; procedure SetValue(const value: Extended); property Value: Extended read GetValue write SetValue; end; { IOmniExtendedData } TOmniExtendedData = class(TInterfacedObject, IOmniExtendedData) strict private oedValue: Extended; public constructor Create(const value: Extended); function GetValue: Extended; procedure SetValue(const value: Extended); property Value: Extended read GetValue write SetValue; end; { TOmniExtendedData } TOmniCounter = class(TInterfacedObject, IOmniCounter) strict private ocValue: TGp4AlignedInt; protected function GetValue: integer; procedure SetValue(const value: integer); public constructor Create(initialValue: integer); function Decrement: integer; function Increment: integer; property Value: integer read GetValue write SetValue; end; { TOmniCounter } TOmniMonitorParams = class(TInterfacedObject, IOmniMonitorParams) strict private ompLParam : integer; ompMessage: cardinal; ompWindow : THandle; ompWParam : integer; protected function GetLParam: integer; function GetMessage: cardinal; function GetWindow: THandle; function GetWParam: integer; public constructor Create(window: THandle; msg: cardinal; wParam, lParam: integer); destructor Destroy; override; property LParam: integer read GetLParam; property Msg: cardinal read GetMessage; property Window: THandle read GetWindow; property WParam: integer read GetWParam; end; { TOmniMonitorParams } TOmniMonitorSupport = class(TInterfacedObject, IOmniMonitorSupport) strict private omsMonitor: IOmniMonitorParams; protected function GetMonitor: IOmniMonitorParams; public procedure Notify; overload; procedure Notify(obj: TObject); overload; procedure RemoveMonitor; procedure SetMonitor(const monitor: IOmniMonitorParams); property Monitor: IOmniMonitorParams read GetMonitor; end; { TOmniMonitorSupport } PPHashItem = ^PHashItem; PHashItem = ^THashItem; THashItem = record Next : PHashItem; Key : int64; Value: IInterface; end; { THashItem } TBucketArray = array of PHashItem; PBucketArray = ^TBucketArray; TInterfaceDictionaryEnumerator = class(TInterfacedObject, IInterfaceDictionaryEnumerator) strict private ideBuckets : PBucketArray; ideBucketIdx: integer; ideCurrent : PHashItem; ideItem : PHashItem; idePair : TInterfaceDictionaryPair; public constructor Create(buckets: PBucketArray); destructor Destroy; override; function GetCurrent: TInterfaceDictionaryPair; function MoveNext: boolean; property Current: TInterfaceDictionaryPair read GetCurrent; end; { IInterfaceDictionaryEnumerator } TInterfaceDictionary = class(TInterfacedObject, IInterfaceDictionary) strict private idBuckets: TBucketArray; idCount : int64; strict protected function Find(const key: int64): PPHashItem; function HashOf(const key: int64): integer; inline; procedure Resize(size: Cardinal); public constructor Create; destructor Destroy; override; procedure Add(const key: int64; const value: IInterface); procedure Clear; function GetEnumerator: IInterfaceDictionaryEnumerator; procedure Remove(const key: int64); function ValueOf(const key: int64): IInterface; end; { TInterfaceDictionary } TOmniCriticalSection = class(TInterfacedObject, IOmniCriticalSection) strict private ocsCritSect: TSynchroObject; public constructor Create; destructor Destroy; override; procedure Acquire; inline; procedure Release; inline; end; { TOmniCriticalSection } { exports } function CreateCounter(initialValue: integer): IOmniCounter; begin Result := TOmniCounter.Create(initialValue); end; { CreateCounter } function CreateOmniMonitorParams(window: THandle; msg: cardinal; wParam, lParam: integer): IOmniMonitorParams; begin Result := TOmniMonitorParams.Create(window, msg, wParam, lParam); end; { CreateOmniMonitorParams } function CreateOmniMonitorSupport: IOmniMonitorSupport; begin Result := TOmniMonitorSupport.Create; end; { CreateOmniMonitorSupport } function CreateInterfaceDictionary: IInterfaceDictionary; begin Result := TInterfaceDictionary.Create; end; { CreateInterfaceDictionary } function CreateOmniCriticalSection: IOmniCriticalSection; begin Result := TOmniCriticalSection.Create; end; { CreateOmniCriticalSection } procedure SetThreadName(const name: string); type TThreadNameInfo = record FType : LongWord; // must be 0x1000 FName : PAnsiChar;// pointer to name (in user address space) FThreadID: LongWord; // thread ID (-1 indicates caller thread) FFlags : LongWord; // reserved for future use, must be zero end; { TThreadNameInfo } var ansiName : AnsiString; threadNameInfo: TThreadNameInfo; begin ansiName := AnsiString(name); threadNameInfo.FType := $1000; threadNameInfo.FName := PAnsiChar(ansiName); threadNameInfo.FThreadID := $FFFFFFFF; threadNameInfo.FFlags := 0; try RaiseException($406D1388, 0, SizeOf(threadNameInfo) div SizeOf(LongWord), @threadNameInfo); except {ignore} end; end; { SetThreadName } function VarToObj(const v: Variant): TObject; begin Result := TObject(cardinal(v)); end; { VarToObj } { TOmniValueContainer } constructor TOmniValueContainer.Create; begin inherited Create; ovcNames := TStringList.Create; ovcCanModify := true; end; { TOmniValueContainer.Create } destructor TOmniValueContainer.Destroy; begin FreeAndNil(ovcNames); inherited Destroy; end; { TOmniValueContainer.Destroy } procedure TOmniValueContainer.Add(const paramValue: TOmniValue; paramName: string = ''); var idxParam: integer; begin if not ovcCanModify then raise Exception.Create('TOmniValueContainer: Locked'); if paramName = '' then paramName := IntToStr(ovcNames.Count); idxParam := ovcNames.IndexOf(paramName); if idxParam < 0 then begin idxParam := ovcNames.Add(paramName); if ovcNames.Count > Length(ovcValues) then Grow; end; ovcValues[idxParam] := paramValue; end; { TOmniValueContainer.Add } procedure TOmniValueContainer.Assign(const parameters: array of TOmniValue); var value: TOmniValue; begin if not ovcCanModify then raise Exception.Create('TOmniValueContainer: Already locked'); Clear; SetLength(ovcValues, Length(parameters)); for value in parameters do Add(value); end; { TOmniValueContainer.Assign } procedure TOmniValueContainer.Clear; begin SetLength(ovcValues, 0); ovcNames.Clear; end; { TOmniValueContainer.Clear } procedure TOmniValueContainer.Grow; var iValue : integer; tmpValues: array of TOmniValue; begin SetLength(tmpValues, Length(ovcValues)); for iValue := 0 to High(ovcValues) - 1 do tmpValues[iValue] := ovcValues[iValue]; SetLength(ovcValues, 2*Length(ovcValues)+1); for iValue := 0 to High(tmpValues) - 1 do ovcValues[iValue] := tmpValues[iValue]; end; { TOmniValueContainer.Grow } function TOmniValueContainer.IsLocked: boolean; begin Result := not ovcCanModify; end; { TOmniValueContainer.IsLocked } procedure TOmniValueContainer.Lock; begin ovcCanModify := false; end; { TOmniValueContainer.Lock } function TOmniValueContainer.ParamByIdx(paramIdx: integer): TOmniValue; begin Result := ovcValues[paramIdx]; end; { TOmniValueContainer.ParamByIdx } function TOmniValueContainer.ParamByName(const paramName: string): TOmniValue; begin Result := ovcValues[ovcNames.IndexOf(paramName)]; end; { TOmniValueContainer.ParamByName } { TOmniCounter } constructor TOmniCounter.Create(initialValue: integer); begin Value := initialValue; end; { TOmniCounter.Create } function TOmniCounter.Decrement: integer; begin Result := ocValue.Decrement; end; { TOmniCounter.Decrement } function TOmniCounter.GetValue: integer; begin Result := ocValue; end; { TOmniCounter.GetValue } function TOmniCounter.Increment: integer; begin Result := ocValue.Increment; end; { TOmniCounter.Increment } procedure TOmniCounter.SetValue(const value: integer); begin ocValue.Value := value; end; { TOmniCounter.SetValue } { TOmniMonitorSupport } function TOmniMonitorSupport.GetMonitor: IOmniMonitorParams; begin Result := omsMonitor; end; { TOmniMonitorSupport.GetMonitor } procedure TOmniMonitorSupport.Notify; var params: IOmniMonitorParams; begin params := GetMonitor; if assigned(params) then Win32Check(PostMessage(params.Window, params.Msg, params.WParam, params.LParam)); end; { TOmniMonitorSupport.Notify } procedure TOmniMonitorSupport.Notify(obj: TObject); var params: IOmniMonitorParams; begin params := GetMonitor; if not (assigned(params) and PostMessage(params.Window, params.Msg, params.WParam, LParam(obj))) then FreeAndNil(obj); end; { TOmniMonitorSupport.Notify } procedure TOmniMonitorSupport.RemoveMonitor; begin omsMonitor := nil; end; { TOmniMonitorSupport.RemoveMonitor } procedure TOmniMonitorSupport.SetMonitor(const monitor: IOmniMonitorParams); begin omsMonitor := monitor; end; { TOmniMonitorSupport.SetMonitor } constructor TOmniMonitorParams.Create(window: THandle; msg: cardinal; wParam, lParam: integer); begin ompMessage := msg; ompLParam := lParam; ompWParam := wParam; ompWindow := window; end; { TOmniMonitorParams.Create } destructor TOmniMonitorParams.Destroy; begin inherited Destroy; end; function TOmniMonitorParams.GetLParam: integer; begin Result := ompLParam; end; { TOmniMonitorParams.GetLParam } function TOmniMonitorParams.GetMessage: cardinal; begin Result := ompMessage; end; { TOmniMonitorParams.GetMessage } function TOmniMonitorParams.GetWindow: THandle; begin Result := ompWindow; end; { TOmniMonitorParams.GetWindow } function TOmniMonitorParams.GetWParam: integer; begin Result := ompWParam; end; { TOmniMonitorParams.GetWParam } { TInterfaceDictionaryPair } procedure TInterfaceDictionaryPair.SetKeyValue(const key: int64; const value: IInterface); begin idpKey := key; idpValue := value; end; { TInterfaceDictionaryPair.SetKeyValue } { TInterfaceDictionaryEnumerator } constructor TInterfaceDictionaryEnumerator.Create(buckets: PBucketArray); begin ideBuckets := buckets; ideBucketIdx := Low(ideBuckets^) + 1; ideItem := nil; idePair := TInterfaceDictionaryPair.Create; end; { TInterfaceDictionaryEnumerator.Create } destructor TInterfaceDictionaryEnumerator.Destroy; begin FreeAndNil(idePair); inherited Destroy; end; { TInterfaceDictionaryEnumerator.Destroy } function TInterfaceDictionaryEnumerator.GetCurrent: TInterfaceDictionaryPair; begin idePair.SetKeyValue(ideCurrent^.Key, ideCurrent^.Value); Result := idePair; end; { TInterfaceDictionaryEnumerator.GetCurrent } function TInterfaceDictionaryEnumerator.MoveNext: boolean; begin Result := false; while not assigned(ideItem) do begin Inc(ideBucketIdx); if ideBucketIdx > High(ideBuckets^) then Exit; ideItem := ideBuckets^[ideBucketIdx]; end; ideCurrent := ideItem; ideItem := ideItem^.Next; Result := true; end; { TInterfaceDictionaryEnumerator.MoveNext } { TInterfaceHash } constructor TInterfaceDictionary.Create; begin inherited Create; Resize(1); end; { TInterfaceDictionary.Create } destructor TInterfaceDictionary.Destroy; begin Clear; inherited Destroy; end; { TInterfaceDictionary.Destroy } procedure TInterfaceDictionary.Add(const key: int64; const value: IInterface); var bucket: PHashItem; hash : integer; begin hash := HashOf(key); New(bucket); bucket^.Key := key; bucket^.Value := value; bucket^.Next := idBuckets[hash]; idBuckets[hash] := bucket; Inc(idCount); if idCount > (1.5 * Length(idBuckets)) then Resize(idCount * 2); end; { TInterfaceDictionary.Add } procedure TInterfaceDictionary.Clear; var bucket : PHashItem; iBucket: integer; next : PHashItem; begin for iBucket := 0 to Length(idBuckets) - 1 do begin bucket := idBuckets[iBucket]; while bucket <> nil do begin next := bucket^.Next; Dispose(bucket); bucket := next; end; idBuckets[iBucket] := nil; end; idCount := 0; end; { TInterfaceDictionary.Clear } function TInterfaceDictionary.Find(const key: int64): PPHashItem; var hash: integer; begin hash := HashOf(key); Result := @idBuckets[hash]; while Result^ <> nil do begin if Result^.key = key then Exit else Result := @Result^.Next; end; end; { TInterfaceDictionary.Find } function TInterfaceDictionary.GetEnumerator: IInterfaceDictionaryEnumerator; begin Result := TInterfaceDictionaryEnumerator.Create(@idBuckets); end; { TInterfaceDictionary.GetEnumerator } function TInterfaceDictionary.HashOf(const key: int64): integer; begin Result := key mod Length(idBuckets); end; { TInterfaceDictionary.HashOf } procedure TInterfaceDictionary.Remove(const key: int64); var bucket : PHashItem; bucketHead: PPHashItem; begin bucketHead := Find(key); bucket := bucketHead^; if assigned(bucket) then begin bucketHead^ := bucket^.Next; Dispose(bucket); Dec(idCount); end; end; { TInterfaceDictionary.Remove } procedure TInterfaceDictionary.Resize(size: Cardinal); var bucket : PHashItem; iBucket : integer; oldBuckets: TBucketArray; begin if Cardinal(Length(idBuckets)) >= size then Exit; oldBuckets := idBuckets; idBuckets := nil; SetLength(idBuckets, GetGoodHashSize(size)); for iBucket := 0 to High(oldBuckets) do begin bucket := oldBuckets[iBucket]; while assigned(bucket) do begin Add(bucket.Key, bucket.Value); bucket := bucket.Next; end; end; end; { TInterfaceDictionary.Resize } function TInterfaceDictionary.ValueOf(const key: int64): IInterface; var bucketHead: PHashItem; begin bucketHead := Find(key)^; if bucketHead <> nil then Result := bucketHead^.Value else Result := nil; end; { TInterfaceDictionary.ValueOf } { TOmniValue } procedure TOmniValue.Clear; begin ovData := 0; ovIntf := nil; ovType := ovtNull; end; { TOmniValue.Clear } function TOmniValue.GetAsBoolean: boolean; begin if ovType <> ovtBoolean then Exception.Create('TOmniValue cannot be converted to boolean'); Result := PByte(RawData)^ <> 0; end; { TOmniValue.GetAsBoolean } function TOmniValue.GetAsCardinal: cardinal; begin Result := AsInt64; end; { TOmniValue.GetAsCardinal } function TOmniValue.GetAsDouble: Double; begin case ovType of ovtInteger: Result := AsInt64; ovtDouble: Result := PDouble(RawData)^; ovtExtended: Result := (ovIntf as IOmniExtendedData).Value; else raise Exception.Create('TOmniValue cannot be converted to double'); end; end; { TOmniValue.GetAsDouble } function TOmniValue.GetAsExtended: Extended; begin case ovType of ovtInteger: Result := AsInt64; ovtDouble: Result := PDouble(RawData)^; ovtExtended: Result := (ovIntf as IOmniExtendedData).Value; else raise Exception.Create('TOmniValue cannot be converted to extended'); end; end; { TOmniValue.GetAsExtended } function TOmniValue.GetAsInt64: int64; begin if ovType <> ovtInteger then Exception.Create('TOmniValue cannot be converted to int64'); Result := ovData; end; { TOmniValue.GetAsInt64 } function TOmniValue.GetAsInteger: integer; begin Result := AsInt64; end; { TOmniValue.GetAsInteger } function TOmniValue.GetAsInterface: IInterface; begin if ovType <> ovtInterface then Exception.Create('TOmniValue cannot be converted to interface'); Result := ovIntf; end; { TOmniValue.GetAsInterface } function TOmniValue.GetAsObject: TObject; begin if ovType <> ovtObject then Exception.Create('TOmniValue cannot be converted to object'); Result := TObject(RawData^); end; { TOmniValue.GetAsObject } function TOmniValue.GetAsString: string; begin case ovType of ovtNull: Result := ''; ovtBoolean: Result := BoolToStr(AsBoolean, true); ovtInteger: Result := IntToStr(ovData); ovtDouble, ovtExtended: Result := FloatToStr(AsExtended); ovtString: Result := (ovIntf as IOmniStringData).Value; else raise Exception.Create('TOmniValue cannot be converted to string'); end; end; { TOmniValue.GetAsString } function TOmniValue.GetAsVariant: Variant; begin if ovType <> ovtVariant then Exception.Create('TOmniValue cannot be converted to variant'); Result := (ovIntf as IOmniVariantData).Value; end; { TOmniValue.GetAsVariant } function TOmniValue.GetAsVariantArr(idx: integer): Variant; begin Result := AsVariant[idx]; end; { TOmniValue.GetAsVariantArr } function TOmniValue.IsBoolean: boolean; begin Result := (ovType = ovtBoolean); end; { TOmniValue.IsBoolean } function TOmniValue.IsEmpty: boolean; begin Result := (ovType = ovtNull); end; { TOmniValue.IsEmpty } function TOmniValue.IsFloating: boolean; begin Result := (ovType in [ovtDouble, ovtExtended]); end; { TOmniValue.IsFloating } function TOmniValue.IsInterface: boolean; begin Result := (ovType = ovtInterface); end; { TOmniValue.IsInterface } function TOmniValue.IsObject: boolean; begin Result := (ovType = ovtObject); end; { TOmniValue.IsObject } function TOmniValue.IsString: boolean; begin Result := (ovType = ovtString); end; { TOmniValue.IsString } function TOmniValue.IsVariant: boolean; begin Result := (ovType = ovtVariant); end; { TOmniValue.IsVariant } class function TOmniValue.Null: TOmniValue; begin Result.ovType := ovtNull; end; { TOmniValue.Null } function TOmniValue.RawData: PInt64; begin Result := @ovData; end; { TOmniValue.RawData } procedure TOmniValue.RawZero; begin ovData := 0; pointer(ovIntf) := nil; ovType := ovtNull; end; { TOmniValue.RawZero } procedure TOmniValue.SetAsBoolean(const value: boolean); begin PByte(RawData)^ := Ord(value); ovType := ovtBoolean; end; { TOmniValue.SetAsBoolean } procedure TOmniValue.SetAsCardinal(const value: cardinal); begin AsInt64 := value; end; { TOmniValue.SetAsCardinal } procedure TOmniValue.SetAsDouble(value: Double); begin PDouble(RawData)^ := value; ovType := ovtDouble; end; { TOmniValue.SetAsDouble } procedure TOmniValue.SetAsExtended(value: Extended); begin ovIntf := TOmniExtendedData.Create(value); ovType := ovtExtended; end; { TOmniValue.SetAsExtended } procedure TOmniValue.SetAsInt64(const value: int64); begin ovData := value; ovType := ovtInteger; end; { TOmniValue.SetAsInt64 } procedure TOmniValue.SetAsInteger(const value: integer); begin AsInt64 := value; end; { TOmniValue.SetAsInteger } procedure TOmniValue.SetAsInterface(const value: IInterface); begin ovIntf := value; ovType := ovtInterface; end; { TOmniValue.SetAsInterface } procedure TOmniValue.SetAsObject(const value: TObject); begin RawData^ := int64(value); ovType := ovtObject; end; { TOmniValue.SetAsObject } procedure TOmniValue.SetAsString(const value: string); begin ovIntf := TOmniStringData.Create(value); ovType := ovtString; end; { TOmniValue.SetAsString } procedure TOmniValue.SetAsVariant(const value: Variant); begin ovIntf := TOmniVariantData.Create(value); ovType := ovtVariant; end; { TOmniValue.SetAsVariant } class operator TOmniValue.Equal(const a: TOmniValue; i: integer): boolean; begin Result := (a.AsInteger = i); end; { TOmniValue.Equal } class operator TOmniValue.Equal(const a: TOmniValue; const s: string): boolean; begin Result := (a.AsString = s); end; { TOmniValue.Equal } class operator TOmniValue.Implicit(const a: boolean): TOmniValue; begin Result.AsBoolean := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: Double): TOmniValue; begin Result.AsDouble := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: Extended): TOmniValue; begin Result.AsExtended := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: integer): TOmniValue; begin Result.AsInteger := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: int64): TOmniValue; begin Result.AsInt64 := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: string): TOmniValue; begin Result.AsString := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: IInterface): TOmniValue; begin Result.AsInterface := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TObject): TOmniValue; begin Result.AsObject := a; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): Double; begin Result := a.AsDouble; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): int64; begin Result := a.AsInt64; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): boolean; begin Result := a.AsBoolean; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): Extended; begin Result := a.AsExtended; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): IInterface; begin Result := a.AsInterface; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): integer; begin Result := a.AsInteger; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): TObject; begin Result := a.AsObject; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: TOmniValue): string; begin Result := a.AsString; end; { TOmniValue.Implicit } class operator TOmniValue.Implicit(const a: Variant): TOmniValue; begin Result.AsVariant := a; end; { TOmniValue.Implicit } { TOmniWaitableValue } constructor TOmniWaitableValue.Create; begin Handle := CreateEvent(nil, false, false, nil); Value := TOmniValue.Null; end; { TOmniWaitableValue.Create } destructor TOmniWaitableValue.Destroy; begin DSiCloseHandleAndInvalidate(Handle); end; { TOmniWaitableValue.Destroy } procedure TOmniWaitableValue.Reset; begin WaitForSingleObject(Handle, 0); end; { TOmniWaitableValue.Reset } procedure TOmniWaitableValue.Signal; begin SetEvent(Handle); end; { TOmniWaitableValue.Signal } procedure TOmniWaitableValue.Signal(const data: TOmniValue); begin Value := data; Signal; end; { TOmniWaitableValue.Signal } function TOmniWaitableValue.WaitFor(maxWait_ms: cardinal): boolean; begin Result := (WaitForSingleObject(Handle, maxWait_ms) = WAIT_OBJECT_0); end; { TOmniWaitableValue.WaitFor } { TOmniStringData } constructor TOmniStringData.Create(const value: string); begin inherited Create; osdValue := value; end; { TOmniStringData.Create } function TOmniStringData.GetValue: string; begin Result := osdValue; end; { TOmniStringData.GetValue } procedure TOmniStringData.SetValue(const value: string); begin osdValue := value; end; { TOmniStringData.SetValue } { TOmniVariantData } constructor TOmniVariantData.Create(const value: Variant); begin inherited Create; ovdValue := value; end; { TOmniVariantData.Create } function TOmniVariantData.GetValue: Variant; begin Result := ovdValue; end; { TOmniVariantData.GetValue } procedure TOmniVariantData.SetValue(const value: Variant); begin ovdValue := value; end; { TOmniVariantData.SetValue } { TOmniExtendedData } constructor TOmniExtendedData.Create(const value: Extended); begin inherited Create; oedValue := value; end; { TOmniExtendedData.Create } function TOmniExtendedData.GetValue: Extended; begin Result := oedValue; end; { TOmniExtendedData.GetValue } procedure TOmniExtendedData.SetValue(const value: Extended); begin oedValue := value; end; { TOmniExtendedData.SetValue } { TOmniCS } procedure TOmniCS.Acquire; begin Initialize; ocsSync.Acquire; end; { TOmniCS.Acquire } procedure TOmniCS.Initialize; var syncIntf: IOmniCriticalSection; begin Assert(cardinal(@ocsSync) mod 4 = 0, 'TOmniCS.Initialize: ocsSync is not 4-aligned!'); while not assigned(ocsSync) do begin syncIntf := CreateOmniCriticalSection; if InterlockedCompareExchange(PInteger(@ocsSync)^, integer(syncIntf), 0) = 0 then begin pointer(syncIntf) := nil; Exit; end; DSiYield; end; end; { TOmniCS.Initialize } procedure TOmniCS.Release; begin ocsSync.Release; end; { TOmniCS.Release } { TOmniCriticalSection } constructor TOmniCriticalSection.Create; begin ocsCritSect := TCriticalSection.Create; end; { TOmniCriticalSection.Create } destructor TOmniCriticalSection.Destroy; begin FreeAndNil(ocsCritSect); end; { TOmniCriticalSection.Destroy } procedure TOmniCriticalSection.Acquire; begin ocsCritSect.Acquire; end; { TOmniCriticalSection.Acquire } procedure TOmniCriticalSection.Release; begin ocsCritSect.Release; end; { TOmniCriticalSection.Release } initialization Assert(SizeOf(TObject) = SizeOf(cardinal)); Assert(SizeOf(pointer) = SizeOf(cardinal)); end.