Atomic operations for TDataValue

This commit is contained in:
Michael Schimmel
2025-09-30 13:07:21 +02:00
parent 9010bb1890
commit 1ac605ee57
4 changed files with 259 additions and 15 deletions
+83 -14
View File
@@ -4,6 +4,7 @@ interface
uses
System.SysUtils,
System.SyncObjs,
Myc.Utils,
Myc.Data.Scalar,
Myc.Data.Series;
@@ -35,7 +36,6 @@ type
FScalar: TScalar;
FInterface: IInterface;
function GetKind: TDataValueKind; inline;
function GetIsVoid: Boolean; inline;
public
@@ -50,8 +50,9 @@ type
class operator Implicit(const AValue: TDataValue.TFunc): TDataValue; overload; inline;
class operator Implicit(const AValue: TObject): TDataValue; overload; inline;
class function CompareAndSet(var Target: TDataValue; const Expected, NewValue: TDataValue): Boolean; static;
class function Reset(var Target: TDataValue; const NewValue: TDataValue): TDataValue; static;
// atomic operations
function CompareAndSet(const Expected, NewValue: TDataValue): Boolean;
function Reset(const NewValue: TDataValue): TDataValue;
class function FromIntf<T: IInterface>(const AValue: T): TDataValue; static;
function AsIntf<T: IInterface>: T; inline;
@@ -78,7 +79,7 @@ type
function ToString: String;
property IsVoid: Boolean read GetIsVoid;
property Kind: TDataValueKind read GetKind;
property Kind: TDataValueKind read FKind;
end;
TDataValueKindHelper = record helper for TDataValueKind
@@ -89,7 +90,7 @@ type
implementation
uses
TypInfo;
System.TypInfo;
type
TMapSeries = class(TInterfacedObject, ISeries)
@@ -197,9 +198,51 @@ begin
Result := (FInterface as TVal<String>).Value;
end;
class function TDataValue.CompareAndSet(var Target: TDataValue; const Expected, NewValue: TDataValue): Boolean;
function TDataValue.CompareAndSet(const Expected, NewValue: TDataValue): Boolean;
function IntfCompareExchange(var VTarget: IInterface; const AValue, Compare: IInterface): IInterface; inline;
begin
if AValue <> nil then
AValue._AddRef;
Result := IInterface(TInterlocked.CompareExchange(Pointer(VTarget), Pointer(AValue), Pointer(Compare)));
if (AValue <> nil) and (Pointer(Result) <> Pointer(Compare)) then
AValue._Release;
end;
begin
// Result := ;
Result := false;
if FKind <> Expected.Kind then
exit;
if FKind <> NewValue.Kind then
raise EArgumentException.Create('Value kinds have to match');
if FKind = vkVoid then
raise EArgumentException.Create('Value is void');
case FKind of
vkScalar:
case FScalar.Kind of
TScalar.TKind.Ordinal:
Result :=
TInterlocked
.CompareExchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64, Expected.AsScalar.Value.AsInt64)
= Expected.AsScalar.Value.AsInt64;
TScalar.TKind.Float:
Result :=
TInterlocked
.CompareExchange(FScalar.Value.AsDouble, NewValue.AsScalar.Value.AsDouble, Expected.AsScalar.Value.AsDouble)
= Expected.AsScalar.Value.AsDouble;
end;
vkPointer:
Result :=
TInterlocked.CompareExchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64, Expected.AsScalar.Value.AsInt64)
= Expected.AsScalar.Value.AsInt64;
vkText, vkSeries, vkRecordSeries, vkRecord, vkManagedObject, vkMethod, vkInterface, vkGeneric:
Result := IntfCompareExchange(FInterface, NewValue.FInterface, Expected.FInterface) = Expected.FInterface;
end;
end;
class function TDataValue.FromIntf<T>(const AValue: T): TDataValue;
@@ -257,19 +300,45 @@ begin
Result := FKind = vkVoid;
end;
function TDataValue.GetKind: TDataValueKind;
begin
Result := TDataValueKind(FKind);
end;
class function TDataValue.Map(const SourceSeries: ISeries; const MapperFunc: TFunc): ISeries;
begin
Result := TMapSeries.Create(SourceSeries, MapperFunc);
end;
class function TDataValue.Reset(var Target: TDataValue; const NewValue: TDataValue): TDataValue;
function TDataValue.Reset(const NewValue: TDataValue): TDataValue;
function IntfExchange(var VTarget: IInterface; const AValue: IInterface): IInterface; inline;
begin
if AValue <> nil then
AValue._AddRef;
Result := IInterface(TInterlocked.Exchange(Pointer(VTarget), Pointer(AValue)));
if AValue <> nil then
AValue._Release;
end;
begin
// Result := ;
if FKind <> NewValue.Kind then
raise EArgumentException.Create('Value kinds have to match');
if FKind = vkVoid then
raise EArgumentException.Create('Value is void');
case FKind of
vkScalar:
case FScalar.Kind of
TScalar.TKind.Ordinal: Result := TInterlocked.Exchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64);
TScalar.TKind.Float: Result := TInterlocked.Exchange(FScalar.Value.AsDouble, NewValue.AsScalar.Value.AsDouble);
end;
vkPointer: Result := TInterlocked.Exchange(FScalar.Value.AsInt64, NewValue.AsScalar.Value.AsInt64);
vkText, vkSeries, vkRecordSeries, vkRecord, vkManagedObject, vkMethod, vkInterface, vkGeneric:
begin
Result.FKind := FKind;
Result.FInterface := IntfExchange(FInterface, NewValue.FInterface);
end;
end;
end;
function TDataValue.ToString: String;