Why am I getting
[DCC Error] ProjectCOWArray.dpr(23): E2426 Inline function must not have asm block
program ProjectCOWArray;
{$APPTYPE CONSOLE}
{$R *.res}
type
PRefCount = ^TRefCount;
TRefCount = array[0..1] of integer;
TCOWArray<T> = record
private
fData: TArray<T>;
private
procedure IncRefCount; <<-- not inline
end;
{ TCOWArray<T> }
procedure TCOWArray<T>.IncRefCount;
asm
{$if defined(win32)}
mov eax,fData;
lock inc dword ptr [eax - 8];
{$ifend}
{$if defined(win64)}
mov rax,fData;
lock inc dword ptr[rax -12];
{$ifend}
end;
begin
end.
Delphi XE2 does not have AtomicIncrement
, so how do I solve this issue?
It'd like to retain the assembler, because otherwise I cannot have the lock
prefix in and I do not want to use InterlockedIncrement
because that's a WinAPI function and I do not want that kind of overhead.
This is because the generics functionality is implemented on top of the inlining engine. The same restrictions that apply to inline functions apply to generic functions. The compiler writers just haven't taken the extra step to make the error messages specific to generics rather than inline functions.
I think that calling InterlockedIncrement
is probably your best option, for Delphi versions that don't have the AtomicIncrement
intrinsic. Or, alternatively, create your own version of AtomicIncrement
, that is only defined in versions of Delphi that do not include it. And that function can be written in asm. Well, it clearly has to be written in asm of course.
{$IFNDEF AtomicFunctionsAvailable}
function AtomicIncrement(var Target: Integer): Integer;
asm
....
end;
{$ENDIF}
Or as @TLama suggests, you can use TInterlocked
from the System.SyncObjs
unit to provide atomic operations.
With all that said, I see no need to meddle with the internals in this way. Implement a copy of write array by calling SetLength(...)
whenever you write to the array. For instance, here's a very simple copy on write array implementation:
unit COWArray;
interface
type
TCOWArray<T> = record
private
FItems: TArray<T>;
function GetLength: Integer;
procedure SetLength(Value: Integer);
function GetItem(Index: Integer): T;
procedure SetItem(Index: Integer; const Value: T);
public
class function New(const Values: array of T): TCOWArray<T>; static;
property Length: Integer read GetLength write SetLength;
property Items[Index: Integer]: T read GetItem write SetItem; default;
end;
implementation
function TCOWArray<T>.GetLength: Integer;
begin
Result := System.Length(FItems);
end;
procedure TCOWArray<T>.SetLength(Value: Integer);
begin
System.SetLength(FItems, Value); // SetLength enforces uniqueness
end;
function TCOWArray<T>.GetItem(Index: Integer): T;
begin
Result := FItems[Index];
end;
procedure TCOWArray<T>.SetItem(Index: Integer; const Value: T);
begin
System.SetLength(FItems, System.Length(FItems)); // SetLength enforces uniqueness
FItems[Index] := Value;
end;
class function TCOWArray<T>.New(const Values: array of T): TCOWArray<T>;
var
i: Integer;
begin
System.SetLength(Result.FItems, System.Length(Values));
for i := 0 to high(Values) do
Result.FItems[i] := Values[i];
end;
end.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With