{$MODE OBJFPC}
{$MODESWITCH AUTODEREF}
unit datomicvalue;

interface

uses
  dobjects,
  dmutex;

type
generic TAtomicValue<TValue> = object(TObject)
private
  FValue: TValue;
  FMutex: TMutex;
  function GetValue: TValue;
  procedure SetValue(aValue: TValue);
public
  constructor Init(const aValue: TValue);
  destructor Done; virtual;
  property Value: TValue read GetValue write SetValue;
end;

TAtomicInt = object
private
  FValue: LongInt;
  function GetValue: LongInt; inline;
  procedure SetValue(aValue: LongInt); inline;
public
  constructor Init(aValue: LongInt = 0);
  destructor Done; virtual;
  // Functions return resulting value
  function Inc: LongInt; inline;
  function Dec: LongInt; inline;
  function Exchange(aValue: LongInt): LongInt; inline;
  function ExchangeAdd(aValue: LongInt): LongInt; inline;
  function CompareExchange(aValue, Comperand: LongInt): LongInt; inline;
  property Value: LongInt read GetValue write SetValue;
end;

implementation

function TAtomicValue.GetValue: TValue;
begin
  FMutex.Enter;
  Result := FValue;
  FMutex.Leave;
end;

procedure TAtomicValue.SetValue(aValue: TValue);
begin
  FMutex.Enter;
  FValue := aValue;
  FMutex.Leave;
end;

constructor TAtomicValue.Init(const aValue: TValue);
begin
  FValue := aValue;
  FMutex.Init;
end;

destructor TAtomicValue.Done;
begin
  FMutex.Done;
end;

function TAtomicInt.GetValue: LongInt;
begin
  Result := FValue;
end;

procedure TAtomicInt.SetValue(aValue: LongInt);
begin
  FValue := aValue;
end;

constructor TAtomicInt.Init(aValue: LongInt = 0);
begin
  FValue := aValue;
end;

destructor TAtomicInt.Done;
begin
end;

function TAtomicInt.Inc: LongInt;
begin
  Result := InterLockedIncrement(FValue);
end;

function TAtomicInt.Dec: LongInt;
begin
  Result := InterLockedDecrement(FValue);
end;

function TAtomicInt.Exchange(aValue: LongInt): LongInt;
begin
  Result := InterLockedExchange(FValue, aValue);
end;

function TAtomicInt.ExchangeAdd(aValue: LongInt): LongInt;
begin
  Result := InterLockedExchangeAdd(FValue, aValue);
end;

function TAtomicInt.CompareExchange(aValue, Comperand: LongInt): LongInt;
begin
  Result := InterlockedCompareExchange(FValue, aValue, Comperand);
end;

end.
