2
0

GR32_Bindings.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. unit GR32_Bindings;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Run-time Function Bindings for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Mattias Andersson
  26. * [email protected]
  27. *
  28. * Portions created by the Initial Developer are Copyright (C) 2005-2010
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * Contributor(s):
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$include GR32.inc}
  36. uses
  37. {$if not defined(FRAMEWORK_LCL)}
  38. System.Generics.Collections,
  39. System.Classes,
  40. {$else}
  41. Generics.Collections,
  42. Classes,
  43. {$ifend}
  44. GR32.CPUID;
  45. //------------------------------------------------------------------------------
  46. //
  47. // CPU feature convenience aliases
  48. //
  49. //------------------------------------------------------------------------------
  50. // For use in CPU dispatch bindings
  51. // For the most common usage, these aliases avoids the need to reference the
  52. // GR32.CPUID unit directly.
  53. //------------------------------------------------------------------------------
  54. type
  55. TCPU = GR32.CPUID.TCPU;
  56. TInstructionSupport = GR32.CPUID.TInstructionSupport;
  57. TCPUInstructionSet = GR32.CPUID.TCPUInstructionSet;
  58. const
  59. isPascal = GR32.CPUID.TCPUInstructionSet.isPascal;
  60. isAssembler = GR32.CPUID.TCPUInstructionSet.isAssembler;
  61. isReference = GR32.CPUID.TCPUInstructionSet.isReference;
  62. isMMX = GR32.CPUID.TCPUInstructionSet.isMMX;
  63. isExMMX = GR32.CPUID.TCPUInstructionSet.isExMMX;
  64. isSSE = GR32.CPUID.TCPUInstructionSet.isSSE;
  65. isSSE2 = GR32.CPUID.TCPUInstructionSet.isSSE2;
  66. isSSE3 = GR32.CPUID.TCPUInstructionSet.isSSE3;
  67. isSSSE3 = GR32.CPUID.TCPUInstructionSet.isSSSE3;
  68. isSSE41 = GR32.CPUID.TCPUInstructionSet.isSSE41;
  69. isSSE42 = GR32.CPUID.TCPUInstructionSet.isSSE42;
  70. isAVX = GR32.CPUID.TCPUInstructionSet.isAVX;
  71. isAVX2 = GR32.CPUID.TCPUInstructionSet.isAVX2;
  72. isAVX512f = GR32.CPUID.TCPUInstructionSet.isAVX512f;
  73. const
  74. BindingPriorityDefault = 0; // Default priority
  75. BindingPriorityBetter = -1; // Negative = Better
  76. BindingPriorityWorse = 1; // Positive = Worse
  77. //------------------------------------------------------------------------------
  78. //
  79. // IFunctionInfo
  80. //
  81. //------------------------------------------------------------------------------
  82. // Interface that describes a function implementation.
  83. //------------------------------------------------------------------------------
  84. type
  85. IBindingInfo = interface;
  86. IFunctionInfo = interface
  87. function GetBinding: IBindingInfo;
  88. function GetEnabled: boolean;
  89. procedure SetEnabled(Value: boolean);
  90. function GetProc: Pointer;
  91. function GetInstructionSupport: TInstructionSupport;
  92. function GetPriority: Integer;
  93. procedure SetPriority(Value: Integer);
  94. function GetFlags: Cardinal;
  95. procedure DoSetFlags(const Value: Cardinal);
  96. function GetName: string;
  97. procedure DoSetName(const Value: string);
  98. function SetFlags(const Value: Cardinal): IFunctionInfo; experimental; // Fluid API; Do not use
  99. function SetName(const Value: string): IFunctionInfo; experimental; // Fluid API; Do not use
  100. // Binding: The binding this function implements
  101. property Binding: IBindingInfo read GetBinding;
  102. // Enabled: Used to temporaily enable or disable an implementation. Default True.
  103. property Enabled: boolean read GetEnabled write SetEnabled;
  104. // Proc: Pointer to the implementing function
  105. property Proc: Pointer read GetProc;
  106. // InstructionSupport: The CPU features required by this implementation
  107. property InstructionSupport: TInstructionSupport read GetInstructionSupport;
  108. // Priority: Function priority; Smaller is better. Used by default TFunctionPriority callback
  109. property Priority: Integer read GetPriority write SetPriority;
  110. // Flags: Optional, user defined flags for use in a custom TFunctionPriority callback
  111. property Flags: Cardinal read GetFlags write DoSetFlags;
  112. // Name: Optional, implementation name
  113. property Name: string read GetName write DoSetName;
  114. end;
  115. //------------------------------------------------------------------------------
  116. //
  117. // TFunctionPriority
  118. //
  119. //------------------------------------------------------------------------------
  120. // Delegate used when evaluating a binding resolution.
  121. //------------------------------------------------------------------------------
  122. TFunctionPriority = function(const Info: IFunctionInfo): Integer;
  123. //------------------------------------------------------------------------------
  124. //
  125. // IBindingInfo
  126. //
  127. //------------------------------------------------------------------------------
  128. // Interface that provides access to the function binding meta data.
  129. //
  130. // A binding represents a single function. This function can have one or more
  131. // different implementations. The function registry Rebind function selects
  132. // among these implementation and chooses the one best suitable for the current
  133. // host system.
  134. //------------------------------------------------------------------------------
  135. IBindingInfo = interface
  136. function GetFunctionID: NativeInt;
  137. function GetBindVariable: PPointer;
  138. function GetName: string;
  139. procedure SetName(const Value: string);
  140. function GetNeedRebind: boolean;
  141. procedure SetNeedRebind(Value: boolean);
  142. // FunctionID: Either an ID or a pointer which uniquely identifies the binding
  143. property FunctionID: NativeInt read GetFunctionID;
  144. // BindVariable: Pointer to the function delegate
  145. property BindVariable: PPointer read GetBindVariable;
  146. // NeedRebind: Indicates if the binding's implementation has been modified
  147. // so the binding needs to be rebound.
  148. property NeedRebind: boolean read GetNeedRebind write SetNeedRebind;
  149. // Name: Optional, binding name
  150. property Name: string read GetName write SetName;
  151. // Register function binding implementations;
  152. function Add(AProc: Pointer; AInstructionSupport: TInstructionSupport; APriority: Integer = BindingPriorityDefault): IFunctionInfo;
  153. function FindImplementation(const Name: string): IFunctionInfo; overload;
  154. function FindImplementation(Proc: pointer): IFunctionInfo; overload;
  155. // List of functions implementing this binding.
  156. function GetEnumerator: TEnumerator<IFunctionInfo>;
  157. function FindFunction(PriorityCallback: TFunctionPriority = nil): Pointer;
  158. function Rebind(PriorityCallback: TFunctionPriority = nil; AForce: boolean = False): boolean;
  159. end;
  160. //------------------------------------------------------------------------------
  161. //
  162. // TFunctionRegistry
  163. //
  164. //------------------------------------------------------------------------------
  165. // This class fascilitates a registry that allows multiple function to be
  166. // registered together with information about their CPU requirements and
  167. // an additional 'flags' parameter. Functions that share the same FunctionID
  168. // can be assigned to a function variable through the rebind methods.
  169. // A priority callback function is used to assess the most optimal function.
  170. //------------------------------------------------------------------------------
  171. type
  172. TFunctionRegistry = class(TPersistent)
  173. private type
  174. TBindingInfoList = TDictionary<NativeInt, IBindingInfo>;
  175. private class var
  176. FBindingRegistries: TObjectList<TFunctionRegistry>;
  177. private
  178. FBindings: TBindingInfoList;
  179. FName: string;
  180. class function NewRegistry(const Name: string): TFunctionRegistry;
  181. class destructor Destroy;
  182. protected
  183. function BindVariableToFunctionID(BindVariable: PPointer): NativeInt;
  184. function GetBinding(const Name: string): IBindingInfo; overload;
  185. function GetBinding(BindVariable: PPointer): IBindingInfo; overload;
  186. function GetBinding(FunctionID: NativeInt): IBindingInfo; overload;
  187. function GetNeedRebind: boolean;
  188. public const
  189. INVALID_PRIORITY: Integer = MaxInt;
  190. BEST_PRIORITY: integer = -MaxInt;
  191. WORST_PRIORITY: integer = MaxInt-1;
  192. public
  193. constructor Create; virtual;
  194. destructor Destroy; override;
  195. procedure Clear;
  196. // Register function bindings;
  197. // Identify bound function using function IDs
  198. function RegisterBinding(FunctionID: NativeInt; BindVariable: PPointer; const Name: string = ''): IBindingInfo; overload;
  199. // Identify bound function using pointer to binding variable
  200. function RegisterBinding(BindVariable: PPointer; const Name: string = ''): IBindingInfo; overload;
  201. // Register function binding implementations;
  202. // Identify bound function using function IDs
  203. function Add(FunctionID: NativeInt; Proc: Pointer; InstructionSupport: TInstructionSupport; Priority: Integer = BindingPriorityDefault; Flags: Cardinal = 0): IFunctionInfo; overload; deprecated 'Use Bindings[].Add';
  204. // Identify bound function using pointer to binding variable
  205. function Add(BindVariable: PPointer; Proc: Pointer; InstructionSupport: TInstructionSupport; Priority: Integer = BindingPriorityDefault; Flags: Cardinal = 0): IFunctionInfo; overload; deprecated 'Use Bindings[].Add';
  206. // Function rebinding support
  207. procedure RebindAll(AForce: boolean; PriorityCallback: TFunctionPriority = nil); overload; deprecated 'Use RebindAll(PriorityCallback, AForce)';
  208. procedure RebindAll(PriorityCallback: TFunctionPriority = nil; AForce: boolean = False); overload;
  209. function Rebind(FunctionID: NativeInt; PriorityCallback: TFunctionPriority = nil): boolean; overload; deprecated 'Use Bindings[].Rebind';
  210. function Rebind(BindVariable: PPointer; PriorityCallback: TFunctionPriority = nil): boolean; overload; deprecated 'Use Bindings[].Rebind';
  211. function FindFunction(FunctionID: NativeInt; PriorityCallback: TFunctionPriority = nil): Pointer; overload; deprecated 'Use Bindings[].FindFunction';
  212. function FindFunction(BindVariable: PPointer; PriorityCallback: TFunctionPriority = nil): Pointer; overload; deprecated 'Use Bindings[].FindFunction';
  213. function FindImplementation(const Name: string): IFunctionInfo; overload; deprecated 'Use Bindings[].FindImplementation';
  214. function FindImplementation(Proc: pointer): IFunctionInfo; overload; deprecated 'Use Bindings[].FindImplementation';
  215. function FindBinding(const Name: string): IBindingInfo; overload;
  216. function FindBinding(BindVariable: PPointer): IBindingInfo; overload;
  217. function FindBinding(FunctionID: NativeInt): IBindingInfo; overload;
  218. property Bindings[BindVariable: PPointer]: IBindingInfo read GetBinding; default;
  219. {$if (not defined(FPC)) and (not defined(BCB))}
  220. property Bindings[FunctionID: NativeInt]: IBindingInfo read GetBinding; default;
  221. property Bindings[const Name: string]: IBindingInfo read GetBinding; default;
  222. {$else} // Lazarus 2.6/FPC 3.0 broke support for overloaded properties. See FPC #15384
  223. property BindingsByName[const Name: string]: IBindingInfo read GetBinding;
  224. property BindingsByID[FunctionID: NativeInt]: IBindingInfo read GetBinding;
  225. {$ifend}
  226. // List of bindings in this registry.
  227. function GetEnumerator: TEnumerator<IBindingInfo>;
  228. property Name: string read FName write FName;
  229. // NeedRebind: True if any binding has been modified and needs rebinding
  230. property NeedRebind: boolean read GetNeedRebind;
  231. end;
  232. const
  233. INVALID_PRIORITY: Integer = MaxInt deprecated 'Use TFunctionRegistry.INVALID_PRIORITY';
  234. //------------------------------------------------------------------------------
  235. //
  236. // NewRegistry
  237. //
  238. //------------------------------------------------------------------------------
  239. // Create a new binding registry
  240. //------------------------------------------------------------------------------
  241. function NewRegistry(const Name: string = ''): TFunctionRegistry;
  242. //------------------------------------------------------------------------------
  243. function DefaultPriorityProc(const Info: IFunctionInfo): Integer;
  244. var
  245. DefaultPriority: TFunctionPriority = DefaultPriorityProc;
  246. //------------------------------------------------------------------------------
  247. //------------------------------------------------------------------------------
  248. //------------------------------------------------------------------------------
  249. implementation
  250. uses
  251. {$if not defined(FRAMEWORK_LCL)}
  252. System.Math,
  253. System.SysUtils,
  254. {$else}
  255. Math,
  256. SysUtils,
  257. {$ifend}
  258. GR32_System;
  259. //------------------------------------------------------------------------------
  260. function NewRegistry(const Name: string): TFunctionRegistry;
  261. begin
  262. Result := TFunctionRegistry.NewRegistry(Name);
  263. end;
  264. //------------------------------------------------------------------------------
  265. function DefaultPriorityProc(const Info: IFunctionInfo): Integer;
  266. begin
  267. if (Info.InstructionSupport <= GR32_System.CPU.InstructionSupport) then
  268. Result := Info.Priority
  269. else
  270. Result := TFunctionRegistry.INVALID_PRIORITY;
  271. end;
  272. //------------------------------------------------------------------------------
  273. //
  274. // IFunctionInfo
  275. //
  276. //------------------------------------------------------------------------------
  277. type
  278. TFunctionInfo = class(TInterfacedObject, IFunctionInfo)
  279. private
  280. FBinding: pointer;// weak reference to a IBindingInfo
  281. FEnabled: boolean;
  282. FProc: Pointer;
  283. FInstructionSupport: TInstructionSupport;
  284. FPriority: Integer;
  285. FFlags: Cardinal;
  286. FName: string;
  287. private
  288. // IFunctionInfo
  289. function GetBinding: IBindingInfo;
  290. function GetEnabled: boolean;
  291. procedure SetEnabled(Value: boolean);
  292. function GetProc: Pointer;
  293. function GetInstructionSupport: TInstructionSupport;
  294. function GetPriority: Integer;
  295. procedure SetPriority(Value: Integer);
  296. function GetFlags: Cardinal;
  297. procedure DoSetFlags(const Value: Cardinal);
  298. function GetName: string;
  299. procedure DoSetName(const Value: string);
  300. function SetFlags(const Value: Cardinal): IFunctionInfo;
  301. function SetName(const Value: string): IFunctionInfo;
  302. private
  303. property Binding: IBindingInfo read GetBinding;
  304. public
  305. constructor Create(const ABinding: IBindingInfo; AProc: Pointer; AInstructionSupport: TInstructionSupport; APriority: Integer);
  306. end;
  307. //------------------------------------------------------------------------------
  308. constructor TFunctionInfo.Create(const ABinding: IBindingInfo; AProc: Pointer; AInstructionSupport: TInstructionSupport; APriority: Integer);
  309. begin
  310. inherited Create;
  311. FBinding := ABinding;
  312. FEnabled := True;
  313. FProc := AProc;
  314. FInstructionSupport := AInstructionSupport;
  315. FPriority := APriority;
  316. end;
  317. //------------------------------------------------------------------------------
  318. function TFunctionInfo.GetBinding: IBindingInfo;
  319. begin
  320. Result := IBindingInfo(FBinding);
  321. end;
  322. function TFunctionInfo.GetEnabled: boolean;
  323. begin
  324. Result := FEnabled;
  325. end;
  326. function TFunctionInfo.GetFlags: Cardinal;
  327. begin
  328. Result := FFlags;
  329. end;
  330. function TFunctionInfo.GetInstructionSupport: TInstructionSupport;
  331. begin
  332. Result := FInstructionSupport;
  333. end;
  334. function TFunctionInfo.GetName: string;
  335. begin
  336. Result := FName;
  337. if (Result = '') then
  338. Result := '@'+IntToHex(NativeInt(Self));
  339. end;
  340. function TFunctionInfo.GetPriority: Integer;
  341. begin
  342. Result := FPriority;
  343. end;
  344. function TFunctionInfo.GetProc: Pointer;
  345. begin
  346. Result := FProc;
  347. end;
  348. procedure TFunctionInfo.DoSetFlags(const Value: Cardinal);
  349. begin
  350. FFlags := Value;
  351. Binding.NeedRebind := True;
  352. end;
  353. procedure TFunctionInfo.DoSetName(const Value: string);
  354. begin
  355. FName := Value;
  356. end;
  357. procedure TFunctionInfo.SetEnabled(Value: boolean);
  358. begin
  359. FEnabled := True;
  360. Binding.NeedRebind := True;
  361. end;
  362. function TFunctionInfo.SetFlags(const Value: Cardinal): IFunctionInfo;
  363. begin
  364. FFlags := Value;
  365. Binding.NeedRebind := True;
  366. Result := Self;
  367. end;
  368. function TFunctionInfo.SetName(const Value: string): IFunctionInfo;
  369. begin
  370. FName := Value;
  371. Binding.NeedRebind := True;
  372. Result := Self;
  373. end;
  374. procedure TFunctionInfo.SetPriority(Value: Integer);
  375. begin
  376. FPriority := Value;
  377. Binding.NeedRebind := True;
  378. end;
  379. //------------------------------------------------------------------------------
  380. //
  381. // IBindingInfo
  382. //
  383. //------------------------------------------------------------------------------
  384. type
  385. TBindingInfo = class(TInterfacedObject, IBindingInfo)
  386. private type
  387. TFunctionInfoList = TList<IFunctionInfo>;
  388. private
  389. FNeedRebind: boolean;
  390. FFunctionID: NativeInt; // Either an ID or a pointer
  391. FBindVariable: PPointer; // Pointer to the function delegate
  392. FName: string;
  393. FFunctions: TFunctionInfoList;
  394. private
  395. function FindBestFunctionInfo(PriorityCallback: TFunctionPriority = nil): IFunctionInfo;
  396. private
  397. // IBindingInfo
  398. function GetFunctionID: NativeInt;
  399. function GetBindVariable: PPointer;
  400. function GetNeedRebind: boolean;
  401. procedure SetNeedRebind(Value: boolean);
  402. function GetName: string;
  403. procedure SetName(const Value: string);
  404. function Add(AProc: Pointer; AInstructionSupport: TInstructionSupport; APriority: Integer): IFunctionInfo;
  405. function FindImplementation(const Name: string): IFunctionInfo; overload;
  406. function FindImplementation(Proc: pointer): IFunctionInfo; overload;
  407. function GetEnumerator: TEnumerator<IFunctionInfo>;
  408. function FindFunction(PriorityCallback: TFunctionPriority = nil): Pointer;
  409. function Rebind(PriorityCallback: TFunctionPriority = nil; AForce: boolean = False): boolean;
  410. public
  411. constructor Create(AFunctionID: NativeInt; ABindVariable: PPointer);
  412. destructor Destroy; override;
  413. end;
  414. //------------------------------------------------------------------------------
  415. constructor TBindingInfo.Create(AFunctionID: NativeInt; ABindVariable: PPointer);
  416. begin
  417. inherited Create;
  418. FFunctions := TFunctionInfoList.Create;
  419. FFunctionID := AFunctionID;
  420. FBindVariable := ABindVariable;
  421. FNeedRebind := True;
  422. end;
  423. destructor TBindingInfo.Destroy;
  424. begin
  425. FFunctions.Free;
  426. inherited;
  427. end;
  428. //------------------------------------------------------------------------------
  429. function TBindingInfo.FindBestFunctionInfo(PriorityCallback: TFunctionPriority = nil): IFunctionInfo;
  430. var
  431. MinPriority, Priority: Integer;
  432. FunctionInfo: IFunctionInfo;
  433. begin
  434. if not Assigned(PriorityCallback) then
  435. PriorityCallback := DefaultPriority;
  436. Result := nil;
  437. MinPriority := TFunctionRegistry.INVALID_PRIORITY;
  438. for FunctionInfo in IBindingInfo(Self) do
  439. begin
  440. if (not FunctionInfo.Enabled) then
  441. continue;
  442. Priority := PriorityCallback(FunctionInfo);
  443. // For functions with equal priority we use the one that has the highest
  444. // instruction support (e.g. ASM trumps Pascal, SSE trumps MMX, AVX
  445. // trumps SSE, etc).
  446. if (Priority < MinPriority) or ((Result <> nil) and (Priority = MinPriority) and (UInt64(FunctionInfo.InstructionSupport) > UInt64(Result.InstructionSupport))) then
  447. begin
  448. Result := FunctionInfo;
  449. MinPriority := Priority;
  450. end;
  451. end;
  452. end;
  453. //------------------------------------------------------------------------------
  454. function TBindingInfo.FindFunction(PriorityCallback: TFunctionPriority): Pointer;
  455. var
  456. Info: IFunctionInfo;
  457. begin
  458. Info := FindBestFunctionInfo(PriorityCallback);
  459. if (Info <> nil) then
  460. Result := Info.Proc
  461. else
  462. Result := nil;
  463. end;
  464. //------------------------------------------------------------------------------
  465. function TBindingInfo.Rebind(PriorityCallback: TFunctionPriority; AForce: boolean): boolean;
  466. begin
  467. if (not AForce) and (not FNeedRebind) then
  468. Exit(False);
  469. FBindVariable^ := FindFunction(PriorityCallback);
  470. Result := (FBindVariable^ <> nil);
  471. FNeedRebind := True;
  472. end;
  473. //------------------------------------------------------------------------------
  474. function TBindingInfo.FindImplementation(Proc: pointer): IFunctionInfo;
  475. var
  476. FunctionInfo: IFunctionInfo;
  477. begin
  478. for FunctionInfo in FFunctions do
  479. if (FunctionInfo.Proc = Proc) then
  480. Exit(FunctionInfo);
  481. Result := nil;
  482. end;
  483. function TBindingInfo.FindImplementation(const Name: string): IFunctionInfo;
  484. var
  485. FunctionInfo: IFunctionInfo;
  486. begin
  487. for FunctionInfo in FFunctions do
  488. if (FunctionInfo.Name = Name) then
  489. Exit(FunctionInfo);
  490. Result := nil;
  491. end;
  492. //------------------------------------------------------------------------------
  493. function TBindingInfo.Add(AProc: Pointer; AInstructionSupport: TInstructionSupport; APriority: Integer): IFunctionInfo;
  494. begin
  495. Result := TFunctionInfo.Create(Self, AProc, AInstructionSupport, APriority);
  496. // We need to get the last first when enumerating, so the list must be in reverse insertion order
  497. FFunctions.Insert(0, Result);
  498. FNeedRebind := True;
  499. end;
  500. //------------------------------------------------------------------------------
  501. function TBindingInfo.GetFunctionID: NativeInt;
  502. begin
  503. Result := FFunctionID;
  504. end;
  505. function TBindingInfo.GetBindVariable: PPointer;
  506. begin
  507. Result := FBindVariable;
  508. end;
  509. function TBindingInfo.GetName: string;
  510. begin
  511. Result := FName;
  512. if (Result = '') then
  513. Result := '@'+IntToHex(NativeInt(Self));
  514. end;
  515. function TBindingInfo.GetNeedRebind: boolean;
  516. begin
  517. Result := FNeedRebind;
  518. end;
  519. procedure TBindingInfo.SetName(const Value: string);
  520. begin
  521. FName := Value;
  522. end;
  523. procedure TBindingInfo.SetNeedRebind(Value: boolean);
  524. begin
  525. FNeedRebind := Value;
  526. end;
  527. //------------------------------------------------------------------------------
  528. function TBindingInfo.GetEnumerator: TEnumerator<IFunctionInfo>;
  529. begin
  530. Result := FFunctions.GetEnumerator;
  531. end;
  532. //------------------------------------------------------------------------------
  533. //
  534. // TFunctionRegistry
  535. //
  536. //------------------------------------------------------------------------------
  537. constructor TFunctionRegistry.Create;
  538. begin
  539. FBindings := TBindingInfoList.Create;
  540. end;
  541. destructor TFunctionRegistry.Destroy;
  542. begin
  543. Clear;
  544. FBindings.Free;
  545. inherited;
  546. end;
  547. //------------------------------------------------------------------------------
  548. class destructor TFunctionRegistry.Destroy;
  549. begin
  550. FBindingRegistries.Free;
  551. FBindingRegistries := nil;
  552. end;
  553. class function TFunctionRegistry.NewRegistry(const Name: string): TFunctionRegistry;
  554. begin
  555. if (FBindingRegistries = nil) then
  556. FBindingRegistries := TObjectList<TFunctionRegistry>.Create;
  557. Result := TFunctionRegistry.Create;
  558. FBindingRegistries.Add(Result);
  559. Result.Name := Name;
  560. end;
  561. //------------------------------------------------------------------------------
  562. function TFunctionRegistry.Add(BindVariable: PPointer; Proc: Pointer; InstructionSupport: TInstructionSupport; Priority: Integer; Flags: Cardinal): IFunctionInfo;
  563. var
  564. BindingInfo: IBindingInfo;
  565. FunctionID: NativeInt;
  566. begin
  567. BindingInfo := FindBinding(BindVariable);
  568. if (BindingInfo = nil) then
  569. begin
  570. FunctionID := BindVariableToFunctionID(BindVariable);
  571. if (FunctionID <> -1) then
  572. BindingInfo := FindBinding(FunctionID);
  573. end;
  574. {$if defined(BINDING_AUTO_REGISTER)}
  575. // Auto-register the binding if it isn't already registered
  576. if (BindingInfo = nil) then
  577. BindingInfo := RegisterBinding(BindVariable);
  578. {$else}
  579. if (BindingInfo = nil) then
  580. raise Exception.CreateFmt('Binding %p not registered', [BindVariable]);
  581. {$ifend}
  582. Result := BindingInfo.Add(Proc, InstructionSupport, Priority);
  583. Result.Flags := Flags;
  584. end;
  585. function TFunctionRegistry.Add(FunctionID: NativeInt; Proc: Pointer; InstructionSupport: TInstructionSupport; Priority: Integer; Flags: Cardinal): IFunctionInfo;
  586. var
  587. BindingInfo: IBindingInfo;
  588. begin
  589. BindingInfo := GetBinding(FunctionID);
  590. Result := BindingInfo.Add(Proc, InstructionSupport, Priority);
  591. Result.Flags := Flags;
  592. end;
  593. //------------------------------------------------------------------------------
  594. procedure TFunctionRegistry.Clear;
  595. begin
  596. FBindings.Clear;
  597. end;
  598. //------------------------------------------------------------------------------
  599. function TFunctionRegistry.BindVariableToFunctionID(BindVariable: PPointer): NativeInt;
  600. var
  601. BindingInfo: IBindingInfo;
  602. begin
  603. Result := -1;
  604. for BindingInfo in Self do
  605. if (BindingInfo.BindVariable = BindVariable) then
  606. begin
  607. Result := BindingInfo.FunctionID;
  608. break;
  609. end;
  610. end;
  611. //------------------------------------------------------------------------------
  612. function TFunctionRegistry.FindFunction(BindVariable: PPointer; PriorityCallback: TFunctionPriority): Pointer;
  613. begin
  614. Result := Bindings[BindVariable].FindFunction(PriorityCallback);
  615. end;
  616. function TFunctionRegistry.FindFunction(FunctionID: NativeInt; PriorityCallback: TFunctionPriority): Pointer;
  617. begin
  618. Result := GetBinding(FunctionID).FindFunction(PriorityCallback);
  619. end;
  620. //------------------------------------------------------------------------------
  621. function TFunctionRegistry.GetBinding(const Name: string): IBindingInfo;
  622. begin
  623. Result := FindBinding(Name);
  624. if (Result = nil) then
  625. raise Exception.CreateFmt('Binding "%s" not registered', [Name]);
  626. end;
  627. function TFunctionRegistry.GetBinding(BindVariable: PPointer): IBindingInfo;
  628. begin
  629. Result := FindBinding(BindVariable);
  630. if (Result = nil) then
  631. raise Exception.CreateFmt('Binding "%p" not registered', [BindVariable]);
  632. end;
  633. function TFunctionRegistry.GetBinding(FunctionID: NativeInt): IBindingInfo;
  634. begin
  635. Result := FindBinding(FunctionID);
  636. if (Result = nil) then
  637. raise Exception.CreateFmt('Binding "%d" not registered', [FunctionID]);
  638. end;
  639. //------------------------------------------------------------------------------
  640. function TFunctionRegistry.FindBinding(const Name: string): IBindingInfo;
  641. var
  642. BindingInfo: IBindingInfo;
  643. begin
  644. for BindingInfo in Self do
  645. if (BindingInfo.Name = Name) then
  646. Exit(BindingInfo);
  647. Result := nil;
  648. end;
  649. function TFunctionRegistry.FindBinding(BindVariable: PPointer): IBindingInfo;
  650. var
  651. BindingInfo: IBindingInfo;
  652. begin
  653. for BindingInfo in Self do
  654. if (BindingInfo.BindVariable = BindVariable) then
  655. Exit(BindingInfo);
  656. Result := nil;
  657. end;
  658. function TFunctionRegistry.FindBinding(FunctionID: NativeInt): IBindingInfo;
  659. begin
  660. if (not FBindings.TryGetValue(FunctionID, Result)) then
  661. Result := nil;
  662. end;
  663. //------------------------------------------------------------------------------
  664. function TFunctionRegistry.FindImplementation(const Name: string): IFunctionInfo;
  665. var
  666. BindingInfo: IBindingInfo;
  667. begin
  668. for BindingInfo in Self do
  669. begin
  670. Result := BindingInfo.FindImplementation(Name);
  671. if (Result <> nil) then
  672. exit;
  673. end;
  674. Result := nil;
  675. end;
  676. function TFunctionRegistry.FindImplementation(Proc: pointer): IFunctionInfo;
  677. var
  678. BindingInfo: IBindingInfo;
  679. begin
  680. for BindingInfo in Self do
  681. begin
  682. Result := BindingInfo.FindImplementation(Proc);
  683. if (Result <> nil) then
  684. exit;
  685. end;
  686. Result := nil;
  687. end;
  688. //------------------------------------------------------------------------------
  689. function TFunctionRegistry.GetEnumerator: TEnumerator<IBindingInfo>;
  690. begin
  691. Result := FBindings.Values.GetEnumerator;
  692. end;
  693. //------------------------------------------------------------------------------
  694. function TFunctionRegistry.GetNeedRebind: boolean;
  695. var
  696. BindingInfo: IBindingInfo;
  697. begin
  698. for BindingInfo in Self do
  699. if (BindingInfo.NeedRebind) then
  700. Exit(True);
  701. Result := False;
  702. end;
  703. //------------------------------------------------------------------------------
  704. function TFunctionRegistry.Rebind(BindVariable: PPointer; PriorityCallback: TFunctionPriority): boolean;
  705. begin
  706. Result := Bindings[BindVariable].Rebind(PriorityCallback);
  707. end;
  708. function TFunctionRegistry.Rebind(FunctionID: NativeInt; PriorityCallback: TFunctionPriority): boolean;
  709. begin
  710. Result := GetBinding(FunctionID).Rebind(PriorityCallback);
  711. end;
  712. //------------------------------------------------------------------------------
  713. procedure TFunctionRegistry.RebindAll(AForce: boolean; PriorityCallback: TFunctionPriority);
  714. begin
  715. RebindAll(PriorityCallback, AForce);
  716. end;
  717. procedure TFunctionRegistry.RebindAll(PriorityCallback: TFunctionPriority; AForce: boolean);
  718. var
  719. BindingInfo: IBindingInfo;
  720. begin
  721. for BindingInfo in Self do
  722. BindingInfo.Rebind(PriorityCallback, AForce);
  723. end;
  724. //------------------------------------------------------------------------------
  725. function TFunctionRegistry.RegisterBinding(BindVariable: PPointer; const Name: string): IBindingInfo;
  726. begin
  727. Result := RegisterBinding(NativeInt(BindVariable), BindVariable, Name);
  728. end;
  729. function TFunctionRegistry.RegisterBinding(FunctionID: NativeInt; BindVariable: PPointer; const Name: string): IBindingInfo;
  730. begin
  731. Result := TBindingInfo.Create(FunctionID, BindVariable);
  732. FBindings.Add(FunctionID, Result);
  733. Result.Name := Name;
  734. end;
  735. //------------------------------------------------------------------------------
  736. end.