123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- unit GR32_Bindings;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Run-time Function Bindings for Graphics32
- *
- * The Initial Developer of the Original Code is
- * Mattias Andersson
- * [email protected]
- *
- * Portions created by the Initial Developer are Copyright (C) 2005-2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$I GR32.inc}
- uses
- Classes, GR32_System;
- type
- TFunctionName = type string;
- TFunctionID = type Integer;
- PFunctionInfo = ^TFunctionInfo;
- TFunctionInfo = record
- FunctionID: Integer;
- Proc: Pointer;
- CPUFeatures: TCPUFeatures;
- Flags: Integer;
- end;
- TFunctionPriority = function (Info: PFunctionInfo): Integer;
- PFunctionBinding = ^TFunctionBinding;
- TFunctionBinding = record
- FunctionID: Integer;
- BindVariable: PPointer;
- end;
- { TFunctionRegistry }
- { This class fascilitates a registry that allows multiple function to be
- registered together with information about their CPU requirements and
- an additional 'flags' parameter. Functions that share the same FunctionID
- can be assigned to a function variable through the rebind methods.
- A priority callback function is used to assess the most optimal function. }
- TFunctionRegistry = class(TPersistent)
- private
- FItems: TList;
- FBindings: TList;
- FName: string;
- procedure SetName(const Value: string);
- function GetItems(Index: Integer): PFunctionInfo;
- procedure SetItems(Index: Integer; const Value: PFunctionInfo);
- public
- constructor Create; virtual;
- destructor Destroy; override;
- procedure Clear;
- procedure Add(FunctionID: Integer; Proc: Pointer; CPUFeatures: TCPUFeatures = []; Flags: Integer = 0);
- // function rebinding support
- procedure RegisterBinding(FunctionID: Integer; BindVariable: PPointer);
- procedure RebindAll(PriorityCallback: TFunctionPriority = nil);
- procedure Rebind(FunctionID: Integer; PriorityCallback: TFunctionPriority = nil);
- function FindFunction(FunctionID: Integer; PriorityCallback: TFunctionPriority = nil): Pointer;
- property Items[Index: Integer]: PFunctionInfo read GetItems write SetItems;
- published
- property Name: string read FName write SetName;
- end;
- function NewRegistry(const Name: string = ''): TFunctionRegistry;
- function DefaultPriorityProc(Info: PFunctionInfo): Integer;
- var
- DefaultPriority: TFunctionPriority = DefaultPriorityProc;
- const
- INVALID_PRIORITY: Integer = MaxInt;
- implementation
- uses
- Math;
- var
- Registers: TList;
- function NewRegistry(const Name: string): TFunctionRegistry;
- begin
- if Registers = nil then
- Registers := TList.Create;
- Result := TFunctionRegistry.Create;
- Result.Name := Name;
- Registers.Add(Result);
- end;
- function DefaultPriorityProc(Info: PFunctionInfo): Integer;
- begin
- Result := IfThen(Info^.CPUFeatures <= GR32_System.CPUFeatures, 0, INVALID_PRIORITY);
- end;
- { TFunctionRegistry }
- procedure TFunctionRegistry.Add(FunctionID: Integer; Proc: Pointer;
- CPUFeatures: TCPUFeatures; Flags: Integer);
- var
- Info: PFunctionInfo;
- begin
- New(Info);
- Info^.FunctionID := FunctionID;
- Info^.Proc := Proc;
- Info^.CPUFeatures := CPUFeatures;
- Info^.Flags := Flags;
- FItems.Add(Info);
- end;
- procedure TFunctionRegistry.Clear;
- var
- I: Integer;
- begin
- for I := 0 to FItems.Count - 1 do
- Dispose(PFunctionInfo(FItems[I]));
- FItems.Clear;
- for I := 0 to FBindings.Count - 1 do
- Dispose(PFunctionBinding(FBindings[I]));
- FBindings.Clear;
- end;
- constructor TFunctionRegistry.Create;
- begin
- FItems := TList.Create;
- FBindings := TList.Create;
- end;
- destructor TFunctionRegistry.Destroy;
- begin
- Clear;
- FItems.Free;
- FBindings.Free;
- inherited;
- end;
- function TFunctionRegistry.FindFunction(FunctionID: Integer;
- PriorityCallback: TFunctionPriority): Pointer;
- var
- I, MinPriority, P: Integer;
- Info: PFunctionInfo;
- begin
- if not Assigned(PriorityCallback) then PriorityCallback := DefaultPriority;
- Result := nil;
- MinPriority := INVALID_PRIORITY;
- for I := FItems.Count - 1 downto 0 do
- begin
- Info := FItems[I];
- if (Info^.FunctionID = FunctionID) then
- begin
- P := PriorityCallback(Info);
- if P < MinPriority then
- begin
- Result := Info^.Proc;
- MinPriority := P;
- end;
- end;
- end;
- end;
- function TFunctionRegistry.GetItems(Index: Integer): PFunctionInfo;
- begin
- Result := FItems[Index];
- end;
- procedure TFunctionRegistry.Rebind(FunctionID: Integer;
- PriorityCallback: TFunctionPriority);
- var
- P: PFunctionBinding;
- I: Integer;
- begin
- for I := 0 to FBindings.Count - 1 do
- begin
- P := PFunctionBinding(FBindings[I]);
- if P^.FunctionID = FunctionID then
- P^.BindVariable^ := FindFunction(FunctionID, PriorityCallback);
- end;
- end;
- procedure TFunctionRegistry.RebindAll(PriorityCallback: TFunctionPriority);
- var
- I: Integer;
- P: PFunctionBinding;
- begin
- for I := 0 to FBindings.Count - 1 do
- begin
- P := PFunctionBinding(FBindings[I]);
- P^.BindVariable^ := FindFunction(P^.FunctionID, PriorityCallback);
- end;
- end;
- procedure TFunctionRegistry.RegisterBinding(FunctionID: Integer;
- BindVariable: PPointer);
- var
- Binding: PFunctionBinding;
- begin
- New(Binding);
- Binding^.FunctionID := FunctionID;
- Binding^.BindVariable := BindVariable;
- FBindings.Add(Binding);
- end;
- procedure TFunctionRegistry.SetItems(Index: Integer;
- const Value: PFunctionInfo);
- begin
- FItems[Index] := Value;
- end;
- procedure TFunctionRegistry.SetName(const Value: string);
- begin
- FName := Value;
- end;
- procedure FreeRegisters;
- var
- I: Integer;
- begin
- if Assigned(Registers) then
- begin
- for I := Registers.Count - 1 downto 0 do
- TFunctionRegistry(Registers[I]).Free;
- Registers.Free;
- Registers := nil;
- end;
- end;
- initialization
- finalization
- FreeRegisters;
- end.
|