Files
MycLib/Src/Myc.pas
T
Michael Schimmel 08a110b02f Heap Tests
2025-05-24 14:59:47 +02:00

3849 lines
132 KiB
ObjectPascal

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
///
/// Mycelium Scenes Library
/// -----------------------
///
/// (c)2007-2020 Michael Schimmel
/// Ehrenhainstr 40
/// 42329 Wuppertal / Germany
/// info@mycelium.net
///
/// All rights reserved.
///
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
unit Myc;
interface
uses
{$ifdef FullDebugMode}FastMM5, {$endif}
System.SysUtils, System.TypInfo, System.Generics.Collections,
System.Generics.Defaults;
{$minenumsize 4}
type
{$message hint 'Debug-Code! Const Params?'}
TMyc3Combiner<T, V> = reference to function( const Values: TArray<V> ): T;
TMyc3Interpolator<T> = reference to function( Delta: Double; const StartValue: T; out Value: T ): Boolean;
TMyc3TargetInterpolator<T> = reference to function( Delta: Double; const StartValue, TargetValue: T; out Value: T ): Boolean;
EMycInvalidParameter = class( Exception )
end;
EMycInvalidOperation = class( Exception )
end;
TConstFunc<A, T> = reference to function( const aa: A ): T;
TConstFunc<A, B, T> = reference to function( const aa: A; const bb: B ): T;
TConstFunc<A, B, C, T> = reference to function( const aa: A; const bb: B; const cc: C ): T;
TConstFunc<A, B, C, D, T> = reference to function( const aa: A; const bb: B; const cc: C ; const dd: D ): T;
TConstFunc<A, B, C, D, E, T> = reference to function( const aa: A; const bb: B; const cc: C ; const dd: D; const ee: E ): T;
TConstProc<A> = reference to procedure( const aa: A );
TConstProc<A, B> = reference to procedure( const aa: A; const bb: B );
TConstProc<A, B, C> = reference to procedure( const aa: A; const bb: B; const cc: C );
TCompareValues<T> = reference to function( const A, B: T ): Boolean;
/////////////////////////////////////////////////////////////////////////////
IMycEnumerator<T> = interface
function GetCurrent: T;
function MoveNext: Boolean;
procedure Reset;
property Current: T read GetCurrent;
end;
IMyc2Enumerable<T> = interface
function GetEnumerator: IMycEnumerator<T>;
end;
IMycCountable<T> = interface
{$region 'property access'}
function GetCount: Integer;
function GetItems( Idx: Integer ): T;
{$endregion}
property Count: Integer read GetCount;
property Items[Idx: Integer]: T read GetItems; default;
end;
/////////////////////////////////////////////////////////////////////////////
IAtomicStack<T> = interface
function Pop: T;
function TryPop( out Item: T ): Boolean;
procedure Push( const Data: T );
end;
TAtomicStack<T> = record
class function Create: IAtomicStack<T>; static;
end;
TProtected<T: IInterface> = record
private
[volatile]
FItem: T;
public
constructor Create( const AItem: T );
function Exchange( const Value: T ): T;
class operator Implicit( const Value: T ): TProtected<T>;
end;
/////////////////////////////////////////////////////////////////////////////
IMyc2Sink = interface
function Notify: Boolean;
end;
IMyc2Flag = interface( IMyc2Sink )
function Reset: Boolean;
end;
{$message hint 'Replace TSignalTag by IMycDeletable? '}
TSignalTag = NativeInt;
IMyc2Signal = interface
function Advise( const Sink: IMyc2Sink ): TSignalTag;
procedure Unadvise( Tag: TSignalTag );
end;
IMyc2Notifier = interface( IMyc2Sink )
{$region 'property access'}
function GetSignal: IMyc2Signal;
{$endregion}
property Signal: IMyc2Signal read GetSignal;
end;
IMyc2State = interface( IMyc2Signal )
{$region 'property access'}
function GetIsSet: Boolean;
{$endregion}
property IsSet: Boolean read GetIsSet;
end;
IMyc2Condition = interface( IMyc2Sink )
{$region 'property access'}
function GetState: IMyc2State;
{$endregion}
property State: IMyc2State read GetState;
end;
IMyc2Event = interface( IMyc2Condition )
function Reset: Boolean;
end;
IMycObserver<T: IMyc2Sink> = interface
function GetItem: T;
property Item: T read GetItem;
end;
IMycNotifyObserver = IMycObserver<IMyc2Notifier>;
IMycEventObserver = IMycObserver<IMyc2Event>;
TMycStateQueue = record
private
FStack: IAtomicStack<IMyc2State>;
public
constructor Create(const AStack: IAtomicStack<IMyc2State>); overload;
class function Create: TMycStateQueue; overload; static;
procedure Add( const S: IMyc2State );
procedure WaitFor;
end;
Signals = record
private
class function GetNull: IMyc2Condition; static;
public
class function CreateCounter( Count: Integer ): IMyc2Condition; static;
class function CreateEvent( Init: Boolean = false ): IMyc2Event; overload; static;
class function CreateNotifier: IMyc2Notifier; overload; static;
class function CreateSink(Once: Boolean; const Proc: TProc): IMyc2Sink; overload; static; deprecated;
class function CreateSink(const Proc: TProc): IMyc2Sink; overload; static;
class function CreateFlag(Init: Boolean): IMyc2Flag; static;
class function CreateObserver<T: IMyc2Sink>( const Signals: array of IMyc2Signal; const Sink: T ): IMycObserver<T>; static;
class function CreateNotifyObserver( const Signals: array of IMyc2Signal ): IMycNotifyObserver; overload; static;
class function CreateEventObserver( const Signals: array of IMyc2Signal ): IMycEventObserver; overload; static;
class function CreateNotifyObserver( const Signals: IMycCountable<IMyc2Signal> ): IMycNotifyObserver; overload; static;
class function CreateEventObserver( const Signals: IMycCountable<IMyc2Signal> ): IMycEventObserver; overload; static;
class function Concat( const States: array of IMyc2State ): IMyc2State; static;
class function Union( const Sigs: array of IMyc2Signal ): IMyc2Signal; static;
class function IsStatic( const Signal: IMyc2Signal ): Boolean; static; inline;
class function MakeValid( const Signal: IMyc2Signal ): IMyc2Signal; overload; static; inline;
class function MakeValid( const Signals: array of IMyc2Signal ): TArray<IMyc2Signal>; overload; static;
class property Null: IMyc2Condition read GetNull;
end;
/////////////////////////////////////////////////////////////////////////////
IMyc3Value<T> = interface
{$region 'property access'}
function GetValue: T;
{$endregion}
property Value: T read GetValue;
end;
TImmutable<T> = record
private
FThis: IMyc3Value<T>;
function GetValue: T; inline;
function GetHasValue: Boolean; inline;
class function GetNull: TImmutable<T>; static; inline;
public
constructor Create(const AValue: T); overload;
class operator NotEqual(ALeft, ARight: TImmutable<T>): Boolean;
class operator Equal(ALeft, ARight: TImmutable<T>): Boolean;
property Value: T read GetValue;
property HasValue: Boolean read GetHasValue;
class property Null: TImmutable<T> read GetNull;
end;
// IDEA:
// Mutable objects represent exactly *one* property of a dynamic system.
// As such, they provide a change signal and an immutable value
// that is *replaced*, when they change.
// Q: How do you maintain thread safety with such an object?
// A: Reading a mutable object needs locking. There's no way around it.
// But picking up a reference to an immutable can be done with almost no
// overhead using atomic operations.
// Given the nature of mutable objects, they should only be used within
// the scope of a single thread (which does not have to be the main thread!)
// Q: Is it getting any better this way?
// A: mmmh... at least it offloads the application from doing this kinda stuff.
// And it ensures separating data from logic.
// Q: Shouldn't IMutable then be derived from IValue<T> or from ISignal?
// A: To be considered. Given that IMutable is *not* the value itself, because
// IValue is immutable by definition, it seems to make more sense to derive
// it from ISignal. OTOH, it isn't a signal either. Maybe it should really
// stand for it's own.
// Mutable objects may change over time.
IMyc3Mutable = interface
{$region 'property access'}
function GetChanged: IMyc2Signal;
{$endregion}
property Changed: IMyc2Signal read GetChanged;
end;
// The Values of typed mutable objects are typed immutables. (And thus should
// be IValue<T> instead of T, see idea above).
IMyc3Mutable<T> = interface( IMyc3Mutable )
{$region 'property access'}
function GetValue: T;
{$endregion}
property Value: T read GetValue;
end;
IMyc3ObjectLink<T: class> = interface
{$region 'property access'}
function GetMutable: IMyc3Mutable<T>;
{$endregion}
procedure Destroyed;
property Mutable: IMyc3Mutable<T> read GetMutable;
end;
IMyc3Validatable = interface
{$region 'property access'}
function GetInvalidate: IMyc2Signal;
{$endregion}
function Validate: Boolean;
property Invalidate: IMyc2Signal read GetInvalidate;
end;
IMyc3Validatable<T> = interface( IMyc3Validatable )
{$region 'property access'}
function GetValue: T;
{$endregion}
property Value: T read GetValue;
end;
TValidatable = record
class function FromSignal(const Signal: IMyc2Signal): IMyc3Validatable; static;
end;
// This is the generic base interface for futures. Futures are used to initialize
// and hold immutable data.
//
// After the initialization is finished, the future and its value are considered
// to be immutable, which means statically constant and accessing them is always
// thread-safe and non-blocking.
//
// Reading the data before initialization is finished is not allowed! Other
// threads have to wait for the initialization signal before accessing the value.
// This can be done explicitly by waiting or by pipelining other futures.
IMyc3Future<T> = interface
{$region 'property access'}
function GetInitialized: IMyc2State;
function GetValue: T;
{$endregion}
// Wait until initialization is finished. Being a blocking operation, this is only
// allowed from the main thread.
{$message hint 'Sollte nichts zurückgeben, damit es nicht in Conditionals verwendet wird!'}
function WaitFor: T;
// Initialization state. This state is set exactly once in the lifetime of the
// future. It can be used to pipeline other futures.
//
property Initialized: IMyc2State read GetInitialized;
// Reading the value is NOT ALLOWED until the initialization is finished,
// otherwise an exception is raised.
//
// Use [WaitFor] to block execution until the value is ready.
property Value: T read GetValue;
end;
IMyc3Changeable<T> = interface
{$region 'property access'}
function GetMutable: IMyc3Mutable<T>;
{$endregion}
procedure SetChanged;
property Mutable: IMyc3Mutable<T> read GetMutable;
end;
IMyc3Generic<T> = interface( IMyc3Changeable<T> )
{$region 'property access'}
function GetFunc: TFunc<T>;
procedure SetFunc(const Value: TFunc<T>);
{$endregion}
property Func: TFunc<T> read GetFunc write SetFunc;
end;
IMyc3Writeable<T> = interface( IMyc3Changeable<T> )
function SetValue(const Value: T): Boolean;
end;
IMyc3ValidateMutable<T> = interface( IMyc3Mutable<T> )
procedure Validate;
end;
IMyc3Property<T> = interface( IMyc3Mutable<T> )
procedure Delete; overload;
procedure Delete( const DefaultValue: T ); overload;
end;
IMyc3MutableProperty<T> = interface( IMyc3Mutable<T> )
{$region 'property access'}
procedure SetMutable( const Value: IMyc3Mutable<T> );
{$endregion}
property Mutable: IMyc3Mutable<T> write SetMutable;
end;
IMyc3MutablePropertyEx<T> = interface( IMyc3Mutable<T> )
procedure Invalidate;
end;
IMyc3Animator = interface
procedure Tick( const Ticks: Int64 );
end;
IMyc3Animator<T> = interface( IMyc3Animator )
function GetCurrent: IMyc3Mutable<T>;
property Current: IMyc3Mutable<T> read GetCurrent;
end;
IMycDeletable = interface
procedure Delete;
end;
IMycArray<T> = interface( IMyc2Enumerable<T> )
{$region 'property access'}
function GetCount: Integer;
function GetItems( Idx: Integer ): T;
{$endregion}
function ToArray: TArray<T>;
function Sort( const Comparer: IComparer<T> = nil; First: Integer = 0; Count: Integer = -1 ): TArray<Integer>;
function Divide( const Comparer: IComparer<T> ): TArray<IMycArray<T>>;
function Divide1( const Comparer: IComparer<T> ): TArray<TArray<Integer>>;
function Range( First: Integer; Count: Integer ): IMycArray<T>;
function Rearrange( const Indices: TArray<Integer> ): IMycArray<T>;
property Count: Integer read GetCount;
property Items[Idx: Integer]: T read GetItems; default;
end;
IMycChain<T> = interface( IMyc2Enumerable<T> )
{$region 'property access'}
function GetChanged: IMyc2Signal;
{$endregion}
function AddFirst( const Item: T ): IMycDeletable;
function AddLast( const Item: T ): IMycDeletable;
function ToArray: TArray<T>;
property Changed: IMyc2Signal read GetChanged;
end;
TChain = record
public
class function Create<T>: IMycChain<T>; static;
end;
TMycArray = class {helper for TArray}
public
class function Create<T>( const Arr: array of T ): IMycArray<T>; overload; static;
class function Create<T>( Count: Integer; const Getter: TFunc<Integer, T> ): IMycArray<T>; overload; static;
class function Create<T>(const Src: IMyc2Enumerable<T>): IMycArray<T>; overload; static;
class function Create<S, T>( const Src: IMycArray<S>; const Converter: TConstFunc<S, T> ): IMycArray<T>; overload; static;
class procedure Divide1<TKey, TValue>( const Src: IMycArray<TPair<TKey, TValue>>; out Keys: TArray<TKey>; out Values:
TArray<IMycArray<TValue>>; const Comparer: IComparer<TKey> ); overload; static;
class function Divide<TKey, TValue>( const Src: IMycArray<TPair<TKey, TValue>>; const Comparer: IComparer<TKey> ): TArray<TPair<TKey,
IMycArray<TValue>>>; overload; static;
class function Divide<T>( const Src: TArray<T>; const Comparer: IComparer<T> ): TArray<TArray<T>>; overload; static;
class function Divide<TKey, TValue>( const Src: TArray<TPair<TKey, TValue>>; const Comparer: IComparer<TKey> ): TArray<TPair<TKey,
TArray<TValue>>>; overload; static;
class function GetKeys<TKey, TValue>( const Arr: TArray<TPair<TKey, TValue>> ): TArray<TKey>; static;
class function CreateConvert<T, S>( const Enum: IMyc2Enumerable<S>; const Conv: TConstFunc<S, T> ): IMyc2Enumerable<T>;
end;
IMyc3Set<S, T> = interface( IMyc3Mutable<T> )
function Add( const Item: S ): Integer;
procedure Remove( const Item: S );
procedure Delete( Idx: Integer );
procedure Clear;
end;
IMycEnumerable<T> = interface( IMyc3Mutable<TArray<T>> )
{$region 'property access'}
function GetCount: Integer;
{$endregion}
function GetEnumerator: IMycEnumerator<T>;
property Count: Integer read GetCount;
end;
IMycSetItem<T> = interface( IMycDeletable )
{$region 'property access'}
function GetValue: T;
{$endregion}
property Value: T read GetValue;
end;
IMycSet<T> = interface( IMycEnumerable<T> )
function Add( const Value: T ): IMycSetItem<T>;
function Pop: T;
procedure Clear;
end;
IMycEnumArray<T> = interface( IMycEnumerable<T> )
{$region 'property access'}
function GetItems( Idx: Integer ): T;
{$endregion}
function Sort( const Comparer: IComparer<T> = nil; First: Integer = 0; Count: Integer = -1 ): IMycArray<T>;
property Items[Idx: Integer]: T read GetItems; default;
end;
TSet<T> = record
public
class function Create: IMycSet<T>; overload; static;
class function Create( const Arr: IMyc3Mutable<TArray<T>> ): IMycEnumArray<T>; overload; static;
class function CreateEx( const Arr: TArray<T> ): IMycEnumArray<T>; overload; static;
end;
IMycAssembly<T> = interface( IMycSet<IMyc3Mutable<TArray<T>>> )
{$region 'property access'}
function GetItems: IMyc3Mutable<TArray<T>>;
{$endregion}
function Add( const Value: T ): IMycDeletable; overload;
function Add( const Values: array of T ): IMycDeletable; overload;
property Items: IMyc3Mutable<TArray<T>> read GetItems;
end deprecated;
TAssembly<T> = record
class function Create: IMycAssembly<T>; static;
end deprecated;
IMycStack<T> = interface
{$region 'property access'}
function GetCount: Integer;
{$endregion}
procedure Push( const Value: T );
function Pop: T;
procedure Clear;
function ToArray: TArray<T>;
property Count: Integer read GetCount;
end;
Stack = record
class function Create<T>: IMycStack<T>; static;
end;
TFunc<U, V, W, X, Y, T> = reference to function( P1: U; P2: V; P3: W; P4: X; P5: Y ): T;
TFunc<U, V, W, X, Y, Z, T> = reference to function( P1: U; P2: V; P3: W; P4: X; P5: Y; P6: Z ): T;
/////////////////////////////////////////////////////////////////////////////
// TValue
//
TValue<T> = class
type
TCalculator = reference to procedure( var Value: T );
class var
FDefaultMutable: IMyc3Mutable<T>;
FDefaultMutableFuture: IMyc3Mutable<IMyc3Future<T>>;
class constructor CreateClass;
class function GetDefaultFuture: IMyc3Future<T>; static;
public
class function AsImmutable( const Value: T ): IMyc3Value<T>; overload; static;
class function CreateLazy(const Func: TFunc<T>): IMyc3Value<T>; static;
// Create a constant future.
class function AsFuture( const Value: T ): IMyc3Future<T>; static;
// Create a generic future. Its fully up to the calculator to handle
// synchronization.
class function CreateFuture( const StartSignal: IMyc2Signal; const Calculator: TFunc<T> ): IMyc3Future<T>;
overload; static;
class function CreateFuture( const StartSignal: IMyc2Signal; const Calculator: TFunc < IMyc3Future < T >> )
: IMyc3Future<T>; overload; static;
class function CreateFutureArray( Count: Integer; const Calculator: TFunc<Integer, T> ): IMyc3Future<TArray<T>>; overload; static;
class function CreateFutureArray( const StartSignal: IMyc2Signal; Count: Integer; const Calculator: TFunc<Integer, T> ):
IMyc3Future<TArray<T>>; overload; static;
class function CreateFutures( Count: Integer; const Src: IMyc3Future < TArray < T >> ): TArray<IMyc3Future<T>>; overload; static;
// Create a generic immutable
class function CreateFuture( const Calculator: TFunc<T> ): IMyc3Future<T>; overload; static;
class function Convert<S>( P: IMyc3Future<S>; const Converter: TFunc<S, T> ): IMyc3Future<T>; static;
// Create an immutable from one other immutables.
class function CreateFuture<U>( P: IMyc3Future<U>; Calculator: TFunc<U, T> ): IMyc3Future<T>; overload; static;
class function CreateFuture<U>( P: IMyc3Future<U>; Calculator: TFunc < U, IMyc3Future < T >> ): IMyc3Future<T>;
overload; static;
class function CreateFuture<U, V>( P1: IMyc3Future<U>; P2: IMyc3Future<V>; Calculator: TFunc<U, V, T> ): IMyc3Future<T>;
overload; static;
class function CreateFuture<U, V>( P1: IMyc3Future<U>; P2: IMyc3Future<V>; Calculator: TFunc < U, V, IMyc3Future < T >> )
: IMyc3Future<T>; overload; static;
class function CreateFuture<U, V, W>( P1: IMyc3Future<U>; P2: IMyc3Future<V>; P3: IMyc3Future<W>;
Calculator: TFunc<U, V, W, T> ): IMyc3Future<T>; overload; static;
// Create an immutable array from an array of immutables.
class function CreateFuture( const Values: TArray < IMyc3Future < T >> ): IMyc3Future<TArray<T>>; overload; static;
class function CreateFuture<S>( const Values: TArray<IMyc3Future<S>>; const Calculator: TFunc<Integer, S, T> ): IMyc3Future<TArray<T>>;
overload; static;
// Calculate an immutable from a set of other immutables. This is a convenient
// function that passes the parameter Values as typed array to the calculator.
class function CreateFuture<S>( const Params: TArray<IMyc3Future<S>>; Calculator: TFunc<TArray<S>, T> ): IMyc3Future<T>;
overload; static;
// Create a future from the value of another future.
class function CreateFuture( Future: IMyc3Future<T>; Creator: TFunc<T, IMyc3Future<T>> ): IMyc3Future<T>;
overload; static;
// Execute on future init.
class function Execute( Future: IMyc3Future<T>; Proc: TConstFunc<T, IMyc2Signal> ): IMyc2State;
// Get value, if future is initialized.
class function TryGetValue( const Future: IMyc3Future<T>; out Value: T ): Boolean; static;
// Create a mutable from a constant value. The resulting mutable never changes.
class function AsConst( const Value: T ): IMyc3Mutable<T>; overload; static; deprecated 'use TMutable<T>()';
class function CreateMutable( const Value: T ): IMyc3Mutable<T>; overload; static; deprecated 'use TMutable<T>()';
class function CreateMutable( Calculator: TFunc<T> ): IMyc3Mutable<T>; overload; static;
experimental;
class function CreateMutable( const Changed: array of IMyc2Signal; const Calculator: TFunc<T> ): IMyc3Mutable<T>; overload; static; deprecated 'use TMutable<T>.FromSignals()';
class function CreateMutable(const Changed: array of IMyc2Signal; const Calculator: TFunc<IMyc3Mutable<T>>): IMyc3Mutable<T>; overload; static; deprecated 'use TMutable<T>.FromSignals()';
// Extend a mutable by a set of signals.
class function CreateMutable( const Changed: array of IMyc2Signal; const Mutable: IMyc3Mutable<T> ): IMyc3Mutable<T>; overload; static;
class function CreateMutable( const Event: IMycEventObserver; const Calculator: TFunc<T> ): IMyc3Mutable<T>; overload; static;
// Futures as mutables
class function AsMutable( const Value: IMyc3Mutable<IMyc3Value<T>> ): IMyc3Mutable<T>; overload; static;
class function AsMutable( const Value: IMyc3Mutable<IMyc3Mutable<T>> ): IMyc3Mutable<T>; overload; static;
class function AsMutable(const Value: IMyc3Future<T>): IMyc3Mutable<T>; overload; static;
class function AsMutable(const Value: IMyc3Mutable<IMyc3Future<T>>): IMyc3Mutable<T>; overload; static;
// Operators
class function CreateMutable<U>( P: IMyc3Mutable<U>; Calculator: TFunc<U, T> ): IMyc3Mutable<T>; overload; static;
class function CreateMutable<U, V>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; Calculator: TFunc<U, V, T> )
: IMyc3Mutable<T>; overload; static;
class function CreateMutable<U, V, W>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>;
Calculator: TFunc<U, V, W, T> ): IMyc3Mutable<T>; overload; static;
class function CreateMutable<U, V, W, X>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>;
P4: IMyc3Mutable<X>; Calculator: TFunc<U, V, W, X, T> ): IMyc3Mutable<T>; overload; static;
class function CreateMutable<U, V, W, X, Y>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>; P4: IMyc3Mutable<X>; P5:
IMyc3Mutable<Y>; Calculator: TFunc<U, V, W, X, Y, T> ): IMyc3Mutable<T>; overload; static;
class function CreateMutable<U, V, W, X, Y, Z>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>; P4: IMyc3Mutable<X>; P5:
IMyc3Mutable<Y>; P6: IMyc3Mutable<Z>; Calculator: TFunc<U, V, W, X, Y, Z, T> ): IMyc3Mutable<T>; overload; static;
// Mutable arrays
class function CreateMutable( const Arr: TArray < IMyc3Mutable < T >> ): IMyc3Mutable<TArray<T>>; overload; static; deprecated 'Mutable<T>.CreateArray';
class function CreateMutable<S>( const Arr: TArray<IMyc3Mutable<S>>; Calculator: TFunc<Integer, S, T> ):
IMyc3Mutable<TArray<T>>; overload; static;
class function CreateMutableEx<S>( Params: TArray<IMyc3Mutable<S>>; Calculator: TFunc<TArray<S>, T> ): IMyc3Mutable<T>; overload; static;
experimental;
{$message hint 'Debug-Code! Eigentlich ist das hier das wahre Lazy-Mutable'}
class function CreateGeneric(const Calculator: TFunc<T> = nil): IMyc3Generic<T>;
// Create a mutable, that supports direct changes to it's value.
class function CreateWriteable: IMyc3Writeable<T>; overload; static;
class function CreateWriteable( const InitValue: T ): IMyc3Writeable<T>; overload; static;
class function CreateWriteable( const InitValue: T; const EqualityComparison: TEqualityComparison<T> ): IMyc3Writeable<T>;
overload; static;
class function CreateValidate( const Calculator: TFunc<T> ): IMyc3ValidateMutable<T>; static;
class function CreateMutableProperty(const InitValue: IMyc3Mutable<T> = nil): IMyc3MutableProperty<T>; overload; static; experimental;
class function CreateProperty( const Creator: TFunc < IMyc3Mutable < T >> ): IMyc3MutablePropertyEx<T>; overload; static;
experimental;
class function CreatePropertyEx( const Decorated: IMyc3Mutable<T> ): IMyc3Property<T>; overload; static;
// Combining values
class function Combine<V>( Values: TArray<V>; Combiner: TMyc3Combiner<T, V> ): IMyc3Future<T>; overload; static;
class function Combine<V>(const Values: TArray<IMyc3Mutable<V>>; Combiner: TMyc3Combiner<T, V>): IMyc3Mutable<T>; overload; static;
class function Combine<V>( const Values: TArray<IMyc3Future<V>>; Combiner: TMyc3Combiner<T, V> ): IMyc3Future<T>;
overload; static;
class function CreateSet: IMycSet<T>; overload; static;
class function WaitFor( Future: IMyc3Future<T> ): T; overload; static;
class procedure WaitFor( const Futures: TArray<IMyc3Future<T>>; Exec: TProc<Integer, T> ); overload; static;
class function Capture( const Src: TArray<T> ): TArray<T>;
experimental;
class function CreateAnimator( const Target: IMyc3Mutable<T>; const Interpolator: TMyc3TargetInterpolator<T> )
: IMyc3Animator<T>; overload; static;
class function CreateAnimator( const Init: T; const ChangeSignal: IMyc2Signal; const Interpolator: TMyc3Interpolator<T> )
: IMyc3Animator<T>; overload; static;
class function MakeValid( const Value: IMyc3Future<T> ): IMyc3Future<T>; overload; static; inline;
class function MakeValid( const Value: IMyc3Mutable<T> ): IMyc3Mutable<T>; overload; static; inline;
class property DefaultFuture: IMyc3Future<T> read GetDefaultFuture;
class property DefaultMutable: IMyc3Mutable<T> read FDefaultMutable;
class property DefaultMutableFuture: IMyc3Mutable<IMyc3Future<T>> read FDefaultMutableFuture;
end;
TMutableFuture<T> = record
private
class var
FNull: IMyc3Mutable<IMyc3Future<T>>;
class function GetNull: IMyc3Mutable<IMyc3Future<T>>; static;
class constructor CreateClass;
public
class function Create<S>( const P: IMyc3Mutable<IMyc3Future<T>>; Calc: TFunc<T, S> ): IMyc3Mutable<IMyc3Future<S>>; static;
class property Null: IMyc3Mutable<IMyc3Future<T>> read GetNull;
end;
IMyc3MutableCache<T> = interface( IMyc3Mutable )
{$region 'property access'}
function GetCount: Integer;
{$endregion}
function Add( const Value: IMyc3Mutable<T> ): IMyc3Mutable<T>;
procedure Clear;
procedure Validate;
function GetEnumerator: IMycEnumerator<IMyc3Mutable<T>>;
property Count: Integer read GetCount;
end;
IMyc3MutableTable = interface
procedure Clear;
end;
IMyc3MutableTable<T> = interface( IMyc3MutableTable )
function Add( const Value: T ): IMyc3Mutable<T>;
end;
TMutableCache<T> = record
private
FThis: IMyc3MutableTable<T>;
function GetItem(const Value: T): IMyc3Mutable<T>;
public
constructor Create( const AThis: IMyc3MutableTable<T> );
procedure Clear;
property Item[const Value: T]: IMyc3Mutable<T> read GetItem; default;
end;
TMutable<T> = record
private
FThis: IMyc3Mutable<T>;
public
class function FromSignals(const Changed: array of IMyc2Signal; const Calculator: TFunc<T>): IMyc3Mutable<T>; overload; static;
class function FromSignals(const Changed: array of IMyc2Signal; const Calculator: TFunc<IMyc3Mutable<T>>): IMyc3Mutable<T>; overload; static;
class function From<S>(const Value: IMyc3Mutable<S>; const Conv: TFunc<S, IMyc3Mutable<T>>): TMutable<T>; overload; static;
class operator Explicit(const Value: T): TMutable<T>;
class operator Implicit(const Item: IMyc3Mutable<T>): TMutable<T>;
class operator Implicit(const Item: TMutable<T>): IMyc3Mutable<T>;
end;
TMutableFuture = record
// Arrays
class function FromArray<T>(const Value: TArray<IMyc3Mutable<IMyc3Future<T>>>): IMyc3Mutable<IMyc3Future<TArray<T>>>; overload; static;
end;
TFuture = record
class function From<S, T>(const Value: IMyc3Future<S>; const Conv: TFunc<S, T>): IMyc3Future<T>; overload; static;
class function From<S, T>(const Value: IMyc3Future<S>; const Conv: TFunc<S, IMyc3Future<T>>): IMyc3Future<T>; overload; static;
class function FromArray<T>(const Value: TArray<IMyc3Future<T>>): IMyc3Future<TArray<T>>; overload; static;
class function Combine<S, T>( const Value: TArray<IMyc3Future<S>>; const Calculator: TFunc<TArray<S>, T> ): IMyc3Future<T>; overload; static;
class function Merge<T>(const Parts: TArray<TArray<T>>): TArray<T>; overload; static;
class function Merge<T>(const Parts: TArray<IMyc3Future<TArray<T>>>): IMyc3Future<TArray<T>>; overload; static;
end;
Mutable = record
// convert
class function Convert<S, T>(const Value: IMyc3Mutable<S>; const Conv: TFunc<S, T>): IMyc3Mutable<T>; overload; static;
class function Convert<S, T>(const Value: IMyc3Mutable<IMyc3Future<S>>; const Conv: TFunc<S, T>): IMyc3Mutable<IMyc3Future<T>>; overload; static;
class function Convert<S, T>(const Value: IMyc3Mutable<IMyc3Future<S>>; const Conv: TFunc<S, IMyc3Future<T>>): IMyc3Mutable<IMyc3Future<T>>; overload; static;
// enclose
class function From<T>(const Value: T): IMyc3Mutable<T>; overload; static;
class function From<S, T>(const Value: IMyc3Mutable<S>; const Conv: TFunc<S, IMyc3Mutable<T>>): IMyc3Mutable<T>; overload; static;
class function From<R, S, T>(const ValueR: IMyc3Mutable<R>; const ValueS: IMyc3Mutable<S>; const Conv: TFunc<R, S, IMyc3Mutable<T>>): IMyc3Mutable<T>; overload; static;
// Arrays
class function FromArray<T>(const Value: TArray<IMyc3Mutable<T>>): IMyc3Mutable<TArray<T>>; overload; static;
class function FromArray<S, T>(const Value: IMyc3Mutable<TArray<S>>; const Conv: TFunc<S, T>): IMyc3Mutable<TArray<T>>; overload; static;
class function FromArray<S, T>(const Value: IMyc3Mutable<TArray<S>>; const Conv: TFunc<S, IMyc3Mutable<T>>): IMyc3Mutable<TArray<T>>; overload; static;
class function FilterArray<T>(const Values: IMyc3Mutable<TArray<T>>; const FilterFunc: TConstFunc<T, IMyc3Mutable<Boolean>>): IMyc3Mutable<TArray<T>>; static;
class function SortArray<T>(const Values: IMyc3Mutable<TArray<T>>; const Comparer: IComparer<T>): IMyc3Mutable<TArray<T>>; static;
class function TrimArray<T: IInterface>(const Values: IMyc3Mutable<TArray<T>>): IMyc3Mutable<TArray<T>>; static;
// bool
class function Create( Value: Boolean ): IMyc3Mutable<Boolean>; overload; static;
class function True: IMyc3Mutable<Boolean>; overload; static; deprecated 'use TMutableBool';
class function False: IMyc3Mutable<Boolean>; overload; static; deprecated 'use TMutableBool';
class function OpOR(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>; static; deprecated 'use TMutableBool';
class function OpAND(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>; static; deprecated 'use TMutableBool';
class function OpNOR(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>; static; deprecated 'use TMutableBool';
class function OpNAND(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>; static; deprecated 'use TMutableBool';
class function OpNOT(const A: IMyc3Mutable<Boolean>): IMyc3Mutable<Boolean>; static; deprecated 'use TMutableBool';
class function IfThen<T>(const Condition: IMyc3Mutable<Boolean>; const TrueValue: IMyc3Mutable<T>): IMyc3Mutable<T>; overload; static;
class function IfThen<T>(const Condition: IMyc3Mutable<Boolean>; const TrueValue: IMyc3Mutable<IMyc3Future<T>>): IMyc3Mutable<IMyc3Future<T>>; overload; static;
class function IfNotThen<T>(const Condition: IMyc3Mutable<Boolean>; const FalseValue: IMyc3Mutable<T>): IMyc3Mutable<T>; static;
class function IfThenElse<T>(const Condition: IMyc3Mutable<Boolean>; const TrueValue, FalseValue: IMyc3Mutable<T>): IMyc3Mutable<T>; static;
class function CreateOverride<T>(const Value, Ovrride: IMyc3Mutable<TImmutable<T>>): IMyc3Mutable<TImmutable<T>>; overload; static;
class function FromSignal(const Signal: IMyc2Signal): IMyc3Mutable<Boolean>; static;
class function FromState(const State: IMyc2State): IMyc3Mutable<Boolean>; static;
class function CreateValidator<T>( const Comparer: IComparer<T> = nil ): IMyc3MutableCache<T>; static;
class function CreateCache<T>( const Comparer: IComparer<T> = nil ): TMutableCache<T>; static;
class function CreateEventObserver<T>(const Mutables: TArray<IMyc3Mutable<T>>): IMycEventObserver; static;
class function CreateNotifyObserver<T>(const Mutables: TArray<IMyc3Mutable<T>>): IMycNotifyObserver; static;
class function ExtractSignals<T>(const Mutables: TArray<IMyc3Mutable<T>>): IMyc2Signal; static;
class function CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>): IMyc3Mutable<TArray<T>>; overload; static;
class function CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>): IMyc3Mutable<IMyc3Future<TArray<T>>>; overload; static;
class function CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>; const Creator: TFunc<TArray<T>, T>): IMyc3Mutable<T>; overload; static;
class function CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>; const Creator: TFunc<TArray<T>, T>):
IMyc3Mutable<IMyc3Future<T>>; overload; static;
class function CreateAssembly<T, S>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>; const Creator: TFunc<TArray<T>, S>): IMyc3Mutable<S>;
overload; static;
class function CreateAssembly<T, S>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>; const Creator: TFunc<TArray<T>, S>):
IMyc3Mutable<IMyc3Future<S>>; overload; static;
class function ConvertSet<T, S>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>; const Converter: TFunc<T, S>): IMyc3Mutable<TArray<
IMyc3Mutable<S>>>; overload; static;
class function ConvertSet<T, S>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>; const Converter: TFunc<T, S>): IMyc3Mutable<
TArray< IMyc3Mutable<IMyc3Future<S>>>>; overload; static;
class function Merge<T>(const Parts: IMyc3Mutable<TArray<TArray<T>>>): IMyc3Mutable<TArray<T>>; overload; static;
class function Merge<T>(const Parts: IMyc3Mutable<TArray<IMyc3Future<TArray<T>>>>): IMyc3Mutable<IMyc3Future<TArray<T>>>; overload; static;
class function CreateObjectLink<T: class>(Obj: T): IMyc3ObjectLink<T>; static;
class function CreateNullable<T>: IMyc3Writeable<TImmutable<T>>; static;
end;
TMutableBool = record
private
FThis: IMyc3Mutable<Boolean>;
class function GetDefaults(Value: Boolean): IMyc3Mutable<Boolean>; static; inline;
public
constructor Create(const AThis: IMyc3Mutable<Boolean>);
class operator LogicalNot(const Value: TMutableBool): TMutableBool;
class operator LogicalAnd(const A, B: TMutableBool): TMutableBool;
class operator LogicalOr(const A, B: TMutableBool): TMutableBool;
class operator Equal(const A, B: TMutableBool): TMutableBool;
class operator NotEqual(const A, B: TMutableBool): TMutableBool;
class operator Implicit(const Value: IMyc3Mutable<Boolean>): TMutableBool; inline;
class operator Implicit(const Value: TMutableBool): IMyc3Mutable<Boolean>; inline;
class property Defaults[Value: Boolean]: IMyc3Mutable<Boolean> read GetDefaults;
class function True: IMyc3Mutable<Boolean>; static; inline;
class function False: IMyc3Mutable<Boolean>; static; inline;
property This: IMyc3Mutable<Boolean> read FThis;
end;
Mutable<T> = class
private
class function GetComparer: IComparer<IMyc3Mutable<T>>; static; inline;
public
class function Default: IMyc3Mutable<T>; static; inline;
class function IfThen( const Condition: IMyc3Mutable<Boolean>; const TrueValue: IMyc3Mutable<T> ): IMyc3Mutable<T>; static; deprecated;
class function IfNotThen( const Condition: IMyc3Mutable<Boolean>; const FalseValue: IMyc3Mutable<T> ): IMyc3Mutable<T>; static; deprecated;
class function IfThenElse( const Condition: IMyc3Mutable<Boolean>; const TrueValue, FalseValue: IMyc3Mutable<T> ): IMyc3Mutable<T>; static; deprecated;
class function CreateArray( const Arr: TArray<IMyc3Mutable<T>> ): IMyc3Mutable<TArray<T>>; overload; static;
class function CreateArray<S>( const Arr: IMyc3Mutable<TArray<S>>; Calculator: TFunc<S, T> ): IMyc3Mutable<TArray<T>>; overload; static;
class property Comparer: IComparer<IMyc3Mutable<T>> read GetComparer;
end;
TMyc2ComputeProperty<T> = record
private
FDone: IMyc2State;
FValue: T;
public
constructor Create( const StartSignal: IMyc2Signal; const Creator: TFunc<T> );
function Value: T; inline;
procedure Terminate; inline;
property Done: IMyc2State read FDone;
end;
/////////////////////////////////////////////////////////////////////////////
// IMyc2TaskFactory
//
IMyc2TaskFactory = interface
{$region 'property access'}
function GetThreadCount: Integer;
{$endregion}
function CreateThread( const Proc: TProc ): IMyc2State;
function InMainThread: Boolean;
function InWorkerThread: Boolean;
function Run( StartCount: Integer; Proc: TProc ): IMyc2Sink;
procedure Teardown;
procedure WaitFor( State: IMyc2State );
property ThreadCount: Integer read GetThreadCount;
end;
TMyc3Tasks = class( TObject )
private
FApi: IMyc2TaskFactory;
FEnabled: Boolean;
function GetInMainThread: Boolean;
function GetThreadCount: Integer;
procedure SetEnabled( const Value: Boolean );
procedure Run( const StartSignal: IMyc2Signal; const Proc: TProc ); overload;
procedure Run( const Proc: TProc ); overload;
public
constructor Create( const AApi: IMyc2TaskFactory );
destructor Destroy; override;
function CreateThread( const Proc: TProc ): IMyc2State;
procedure ExpectSignaled( State: IMyc2State; const Msg: String = 'Expected state to be already set' );
function LoopUntil( const DoneSignal: IMyc2Signal; const Proc: TFunc<IMyc2State> ): IMyc2State;
function ParallelFor(const StartSignal: IMyc2Signal; LowVal, HighVal, Slice: Integer; const Proc: TProc<Integer, Integer>): IMyc2State; overload;
procedure ParallelFor(LowVal, HighVal, Slice: Integer; const Proc: TProc<Integer, Integer>); overload;
function Start( const StartSignal: IMyc2Signal; const Proc: TFunc<IMyc2Signal> ): IMyc2State; overload;
function Start( const StartSignal: IMyc2Signal; Proc: TProc ): IMyc2State; overload;
function Start<T1>( const StartSignal: IMyc2Signal; P1: T1; Proc: TProc<T1> ): IMyc2State; overload;
function Start<T1, T2>( const StartSignal: IMyc2Signal; P1: T1; P2: T2; Proc: TProc<T1, T2> ): IMyc2State; overload;
function Start( const Proc: TFunc<IMyc2Signal> ): IMyc2State; overload;
function Start( const Proc: TProc ): IMyc2State; overload;
function Enqueue( var Queue: IMyc2State; const Proc: TFunc<IMyc2Signal> ): IMyc2State; overload;
function Enqueue( var Queue: IMyc2State; const Proc: TProc ): IMyc2State; overload;
function Capture<T>( P: T; Proc: TProc<T> ): TProc; overload;
function Capture<T, R>( P1: T; P2: R; Proc: TProc<T, R> ): TProc; overload;
function Capture<T, R, U>( P1: T; P2: R; P3: U; Proc: TProc<T, R, U> ): TProc; overload;
function Capture<T, R>( P: T; Proc: TFunc<T, R> ): TFunc<R>; overload;
function Capture<T, U, R>( P: T; Proc: TFunc<T, U, R> ): TFunc<U, R>; overload;
function Capture<T, U, V, R>( P: T; Proc: TFunc<T, U, V, R> ): TFunc<U, V, R>; overload;
procedure WaitFor( const State: IMyc2State );
property InMainThread: Boolean read GetInMainThread;
property ThreadCount: Integer read GetThreadCount;
property Enabled: Boolean write SetEnabled;
end;
TTag = record
strict private
FManaged: IInterface;
FOrdinal: Int64;
{$ifdef DEBUG}
FTypeInfo: PTypeInfo;
{$endif}
public
class function From<T>(const Data: T): TTag; static;
function AsType<T>: T;
end;
// Parameters
TParameterValue = record
strict private
FMutable: IMyc3Mutable;
{$ifdef DEBUG}
FTypeInfo: PTypeInfo;
procedure CheckType(TI: PTypeInfo);
{$endif}
public
constructor Create( ATypeInfo: PTypeInfo; const AMutable: IMyc3Mutable ); overload;
function Get<T>: T;
class function Create<T>( const Intf: T ): TParameterValue; overload; static;
class function Create<T>( const Intf: IMyc3Mutable<T> ): TParameterValue; overload; static;
class function Compare( const A, B: TParameterValue ): Integer; static;
class function FromArray<T>( const Values: TArray<TParameterValue> ): TArray<IMyc3Mutable<T>>; overload; static;
class function FromVarRec( const VarRec: TVarRec ): TParameterValue; static;
constructor Assign( const Src: TParameterValue );
function AsType<T>: IMyc3Mutable<T>;
property Mutable: IMyc3Mutable read FMutable;
end;
TFieldID = Integer;
TParameterField = record
private
FID: TFieldID;
FValue: TParameterValue;
public
constructor Create( AID: TFieldID; const AValue: TParameterValue ); overload;
class function Create<T>( ID: TFieldID; const Intf: T ): TParameterField; overload; static;
class function Create<T>( ID: TFieldID; const Intf: IMyc3Mutable<T> ): TParameterField; overload; static;
property ID: TFieldID read FID;
property Value: TParameterValue read FValue write FValue;
end;
IMycParameterRecordDefinition = interface
{$region 'property access'}
function GetByName(const Caption: String): Integer;
function GetCount: Integer;
function GetFields( Idx: Integer ): TFieldID;
function GetIdx: Integer;
{$endregion}
function IndexOf( Field: TFieldID ): Integer;
property ByName[const Caption: String]: Integer read GetByName;
property Count: Integer read GetCount;
property Fields[Idx: Integer]: TFieldID read GetFields;
property Idx: Integer read GetIdx;
end;
IMyc3ParameterRecord = interface
{$region 'property access'}
function GetByName(const Caption: String): TParameterValue;
function GetDef: IMycParameterRecordDefinition;
function GetValues(ID: TFieldID): TParameterValue;
{$endregion}
function GetEnumerator: TEnumerator<TParameterField>;
property ByName[const Caption: String]: TParameterValue read GetByName;
property Def: IMycParameterRecordDefinition read GetDef;
property Values[ID: TFieldID]: TParameterValue read GetValues; default;
end;
TParameterRecord = record
private
FThis: IMyc3ParameterRecord;
function GetValues(ID: TFieldID): TParameterValue; inline;
function GetByName( const Caption: String ): TParameterValue; inline;
function GetDef: IMycParameterRecordDefinition; inline;
public
constructor Create( const AThis: IMyc3ParameterRecord );
function AsType<T>( ID: TFieldID ): IMyc3Mutable<T>; inline;
function Get<T>(ID: TFieldID): T; inline;
class operator Implicit(const Item: IMyc3ParameterRecord): TParameterRecord;
class operator Implicit(const Item: TParameterRecord): IMyc3ParameterRecord;
property Def: IMycParameterRecordDefinition read GetDef;
property Values[ID: TFieldID]: TParameterValue read GetValues; default;
property ByName[const Caption: String]: TParameterValue read GetByName;
end;
IMycParameterSpace = interface
{$region 'property access'}
function GetFieldCount: Integer;
function GetDefaultValues( FieldID: TFieldID ): TParameterValue;
function GetCaptions( FieldID: TFieldID ): String;
function GetComparer( FieldID: TFieldID ): IComparer<TParameterValue>;
function GetByName(const Caption: String): TFieldID;
{$endregion}
function AddField( TypInfo: PTypeInfo; const Caption: String; const DefaultValue: IMyc3Mutable; const Comparer: IComparer<TParameterValue> ): TFieldID;
function CompareValues( FieldID: TFieldID; const A, B: TParameterValue ): Integer;
function CreateRecord(const Fields: TArray<TParameterField>): IMyc3ParameterRecord;
function CreateDef(const Fields: TArray<TFieldID>): IMycParameterRecordDefinition;
property DefaultValues[FieldID: TFieldID]: TParameterValue read GetDefaultValues;
property Captions[FieldID: TFieldID]: String read GetCaptions;
property Comparer[FieldID: TFieldID]: IComparer<TParameterValue> read GetComparer;
property ByName[const Caption: String]: TFieldID read GetByName;
property FieldCount: Integer read GetFieldCount;
end;
TParameterSpace = record
private
FThis: IMycParameterSpace;
function GetFieldCount: Integer; inline;
function GetDefaultValues( FieldID: TFieldID ): TParameterValue; inline;
function GetCaptions( FieldID: TFieldID ): String; inline;
function GetComparer( FieldID: TFieldID ): IComparer<TParameterValue>; inline;
public
constructor Create( const AThis: IMycParameterSpace ); overload;
class function Create: TParameterSpace; overload; static;
{ TODO : ->Factory (mit D11 managed records) }
function AddField<T>(const Caption: String; const DefaultValue: T; const Comparer: IComparer<T> = nil): TFieldID;
function CompareValues( FieldID: TFieldID; const A, B: TParameterValue ): Integer;
function CreateRecord( const Fields: TArray<TParameterField> ): TParameterRecord;
function CreateDef(const Fields: TArray<TFieldID>): IMycParameterRecordDefinition;
class operator Implicit( const Item: TParameterSpace ): IMycParameterSpace;
class operator Implicit( const Item: IMycParameterSpace ): TParameterSpace;
property FieldCount: Integer read GetFieldCount;
property DefaultValues[FieldID: TFieldID]: TParameterValue read GetDefaultValues;
property Captions[FieldID: TFieldID]: String read GetCaptions;
property Comparer[FieldID: TFieldID]: IComparer<TParameterValue> read GetComparer;
end;
type
TStackTrace = record
const
Len = 64;
var
Msg: String;
StackTrace: array [0..Len-1] of NativeUInt;
constructor Create(ASkipFrames: Cardinal; const AMsg: String = '');
function ToText: String;
end;
var
Tasks: TMyc3Tasks;
procedure RaiseInvalidParameter( const Msg: String = '' );
procedure RaiseNullPointer;
procedure RaiseInvalidOperation( const Msg: String = '' ); overload;
procedure RaiseInvalidOperation( const Msg: String; const Args: array of const ); overload;
procedure ForEach( Count: Integer; Exec: TProc<Integer> ); overload;
procedure ForEach( Count1, Count2: Integer; Exec: TProc<Integer, Integer> ); overload;
procedure ForEach( Count1, Count2, Count3: Integer; Exec: TProc<Integer, Integer, Integer> ); overload;
procedure ForEach( LowIdx, HighIdx: Integer; Exec: TProc<Integer> ); overload;
implementation
uses
System.Classes, System.SyncObjs, System.SysConst, System.Math,
Myc.Signals, Myc.Tasks, Myc.Values, Myc.Values.Sets, Myc.Values.Validate,
Myc.Values.Properties, Myc.Values.Bool, Myc.Atomic, Myc.Future.Arrays,
Myc.Values.Parameter;
procedure RaiseInvalidParameter( const Msg: String = '' );
var
Str: String;
begin
Str := 'Invalid parameter';
if Msg <> '' then
Str := Str + ' (' + Msg + ')';
raise EMycInvalidParameter.Create( Str );
end;
procedure RaiseNullPointer;
begin
RaiseInvalidParameter( 'null pointer' );
end;
procedure RaiseInvalidOperation( const Msg: String ); overload;
begin
RaiseInvalidOperation( Msg, [] );
end;
procedure RaiseInvalidOperation( const Msg: String; const Args: array of const ); overload;
begin
if Msg = '' then
raise EMycInvalidOperation.Create( 'Invalid operation' )
else
raise EMycInvalidOperation.CreateFmt( 'Invalid operation: ' + Msg, Args )
end;
procedure ForEach( Count: Integer; Exec: TProc<Integer> );
var
i: Integer;
begin
for i := 0 to Count - 1 do
Exec( i );
end;
procedure ForEach( Count1, Count2: Integer; Exec: TProc<Integer, Integer> );
var
i, j: Integer;
begin
for i := 0 to Count1 - 1 do
for j := 0 to Count2 - 1 do
Exec( i, j );
end;
procedure ForEach( Count1, Count2, Count3: Integer; Exec: TProc<Integer, Integer, Integer> );
var
i, j, k: Integer;
begin
for i := 0 to Count1 - 1 do
for j := 0 to Count2 - 1 do
for k := 0 to Count3 - 1 do
Exec( i, j, k );
end;
procedure ForEach( LowIdx, HighIdx: Integer; Exec: TProc<Integer> ); overload;
var
i: Integer;
begin
for i := LowIdx to HighIdx do
Exec( i );
end;
{ TMyc3Tasks }
constructor TMyc3Tasks.Create( const AApi: IMyc2TaskFactory );
begin
inherited Create;
FApi := AApi;
FEnabled := True;
end;
destructor TMyc3Tasks.Destroy;
begin
FApi.Teardown;
inherited;
end;
function TMyc3Tasks.Capture<T, R, U>( P1: T; P2: R; P3: U; Proc: TProc<T, R, U> ): TProc;
begin
Result :=
procedure
begin
Proc( P1, P2, P3 );
end;
end;
function TMyc3Tasks.Capture<T, R>( P: T; Proc: TFunc<T, R> ): TFunc<R>;
begin
Result :=
function: R
begin
Result := Proc( P );
end;
end;
function TMyc3Tasks.Capture<T, R>( P1: T; P2: R; Proc: TProc<T, R> ): TProc;
begin
Result :=
procedure
begin
Proc( P1, P2 );
end;
end;
function TMyc3Tasks.Capture<T, U, R>( P: T; Proc: TFunc<T, U, R> ): TFunc<U, R>;
begin
Result :=
function( Q: U ): R
begin
Result := Proc( P, Q );
end;
end;
function TMyc3Tasks.Capture<T, U, V, R>( P: T; Proc: TFunc<T, U, V, R> ): TFunc<U, V, R>;
begin
Result :=
function( Q: U; R: V ): R
begin
Result := Proc( P, Q, R );
end;
end;
function TMyc3Tasks.Capture<T>( P: T; Proc: TProc<T> ): TProc;
begin
Result :=
procedure
begin
Proc( P );
end;
end;
function TMyc3Tasks.CreateThread( const Proc: TProc ): IMyc2State;
begin
Result := FApi.CreateThread( Proc );
end;
{ TSet<T> }
class function TSet<T>.Create: IMycSet<T>;
begin
Result := TMycSet<T>.Create;
end;
class function TSet<T>.CreateEx( const Arr: TArray<T> ): IMycEnumArray<T>;
begin
Result := TMycEnumArray<T>.CreateStatic( Arr );
end;
class function TSet<T>.Create( const Arr: IMyc3Mutable<TArray<T>> ): IMycEnumArray<T>;
begin
Result := TMycEnumArray<T>.CreateMutable( Arr );
end;
{ TFuture }
class function TFuture.From<S, T>(const Value: IMyc3Future<S>; const Conv: TFunc<S, T>): IMyc3Future<T>;
begin
Result := TMyc3Future<T>.CreateFuture( Value.Initialized,
function: T
begin
Result := Conv( Value.Value );
end );
end;
class function TFuture.Combine<S, T>(const Value: TArray<IMyc3Future<S>>;
const Calculator: TFunc<TArray<S>, T>): IMyc3Future<T>;
begin
Result := TValue<T>.CreateFuture<S>( Value, Calculator );
end;
class function TFuture.From<S, T>(const Value: IMyc3Future<S>; const Conv: TFunc<S, IMyc3Future<T>>): IMyc3Future<T>;
begin
Result := TMyc3Future<T>.CreateFuture( Value.Initialized,
function: IMyc3Future<T>
begin
Result := Conv( Value.Value );
end );
end;
class function TFuture.FromArray<T>(const Value: TArray<IMyc3Future<T>>): IMyc3Future<TArray<T>>;
begin
Result := TMyc3FutureArrayEx<T>.Create( Value );
end;
class function TFuture.Merge<T>(const Parts: TArray<TArray<T>>): TArray<T>;
var
i, j, n: Integer;
begin
n := 0;
for i := 0 to High(Parts) do
inc( n, Length(Parts[i]) );
SetLength( Result, n );
n := 0;
for i := 0 to High(Parts) do
begin
for j := 0 to High(Parts[i]) do
begin
Result[n] := Parts[i,j];
inc(n);
end;
end;
end;
class function TFuture.Merge<T>(const Parts: TArray<IMyc3Future<TArray<T>>>): IMyc3Future<TArray<T>>;
begin
if Length(Parts) = 0 then
Result := TValue<TArray<T>>.DefaultFuture
else if Length(Parts) = 1 then
Result := Parts[0]
else
Result := TValue<TArray<T>>.CreateFuture<TArray<TArray<T>>>(
TValue<TArray<T>>.CreateFuture( Parts ),
function( Parts: TArray<TArray<T>> ): TArray<T>
begin
Result := Merge<T>( Parts );
end );
end;
{ TMutableFuture<T> }
class constructor TMutableFuture<T>.CreateClass;
begin
FNull := TValue<IMyc3Future<T>>.CreateMutable( TValue<T>.DefaultFuture );
end;
class function TMutableFuture<T>.Create<S>( const P: IMyc3Mutable<IMyc3Future<T>>; Calc: TFunc<T, S> ): IMyc3Mutable<IMyc3Future<S>>;
begin
Result := TValue<IMyc3Future<S>>.CreateMutable<IMyc3Future<T>>(
P,
function( P: IMyc3Future<T> ): IMyc3Future<S>
begin
Result := TValue<S>.CreateFuture<T>(
P,
function( P: T ): S
begin
Result := Calc( P );
end );
end );
end;
class function TMutableFuture<T>.GetNull: IMyc3Mutable<IMyc3Future<T>>;
begin
Result := FNull;
end;
{ TImmutable<T> }
constructor TImmutable<T>.Create(const AValue: T);
begin
FThis := TMyc3Value<T>.Create( AValue );
end;
function TImmutable<T>.GetValue: T;
begin
if FThis<>nil then
Result := FThis.Value
else
Result := Default(T);
end;
function TImmutable<T>.GetHasValue: Boolean;
begin
Result := FThis<>nil;
end;
class function TImmutable<T>.GetNull: TImmutable<T>;
begin
Result := Default(TImmutable<T>);
end;
class operator TImmutable<T>.Equal(ALeft, ARight: TImmutable<T>): Boolean;
begin
if ALeft.HasValue and ARight.HasValue then
Result := TEqualityComparer<T>.Default.Equals(ALeft.Value, ARight.Value)
else
Result := ALeft.HasValue = ARight.HasValue;
end;
class operator TImmutable<T>.NotEqual(ALeft, ARight: TImmutable<T>): Boolean;
begin
if ALeft.HasValue and ARight.HasValue then
Result := not TEqualityComparer<T>.Default.Equals(ALeft.Value, ARight.Value)
else
Result := ALeft.HasValue <> ARight.HasValue;
end;
{ TMyc3Tasks }
function TMyc3Tasks.Enqueue( var Queue: IMyc2State; const Proc: TFunc<IMyc2Signal> ): IMyc2State;
var
Exec: IMyc2Condition;
[unsafe]
Q: IMyc2State;
begin
Exec := Signals.CreateCounter( 1 );
Result := Exec.State;
Result._AddRef;
Pointer( Q ) := TInterlocked.Exchange( Pointer( Queue ), Pointer( Result ) );
try
Start( Q, Proc ).Advise( Exec );
finally
Q._Release;
end;
end;
function TMyc3Tasks.Enqueue( var Queue: IMyc2State; const Proc: TProc ): IMyc2State;
var
Exec: IMyc2Condition;
[unsafe]
Q: IMyc2State;
begin
Exec := Signals.CreateCounter( 1 );
Result := Exec.State;
Result._AddRef;
Pointer( Q ) := TInterlocked.Exchange( Pointer( Queue ), Pointer( Result ) );
try
Start( Q, Proc ).Advise( Exec );
finally
Q._Release;
end;
end;
procedure TMyc3Tasks.ExpectSignaled( State: IMyc2State; const Msg: String = 'Expected state to be already set' );
begin
System.Assert( Signals.IsStatic( State ) or State.IsSet, Msg );
end;
function TMyc3Tasks.GetInMainThread: Boolean;
begin
Result := FApi.InMainThread;
end;
function TMyc3Tasks.GetThreadCount: Integer;
begin
Result := FApi.ThreadCount;
end;
function TMyc3Tasks.LoopUntil( const DoneSignal: IMyc2Signal; const Proc: TFunc<IMyc2State> ): IMyc2State;
var
Done: IMyc2Event;
CapturedProc: TFunc<IMyc2State>;
begin
if Signals.IsStatic( DoneSignal ) then
exit( Signals.Null.State );
DoneSignal._AddRef;
try
Done := Signals.CreateEvent( false );
DoneSignal.Advise( Done );
CapturedProc := Proc;
Result := FApi.CreateThread(
procedure
begin
try
while not Done.State.IsSet do
WaitFor( CapturedProc );
finally
CapturedProc := nil;
end;
end );
finally
DoneSignal._Release;
end;
end;
function TMyc3Tasks.ParallelFor(const StartSignal: IMyc2Signal; LowVal, HighVal, Slice: Integer; const Proc: TProc<Integer, Integer>):
IMyc2State;
function CallFunc( f, l: Integer; Proc: TProc<Integer, Integer> ): IMyc2State;
begin
Result := Start(
StartSignal,
procedure
begin
Proc( f, l );
end );
end;
var
l, f, n: Integer;
Counter: IMyc2Condition;
begin
if not Assigned( Proc ) or ( LowVal > HighVal ) then
exit;
if Slice <= 0 then
Slice := max( 1, (HighVal-LowVal+1) div ThreadCount );
n := 0;
f := LowVal;
while f <= HighVal do
begin
inc( f, Slice );
inc( n );
end;
if n=0 then
exit;
Counter := Signals.CreateCounter( n );
f := LowVal;
while f <= HighVal do
begin
l := f + Slice - 1;
if l > HighVal then
l := HighVal;
CallFunc( f, l, Proc ).Advise( Counter );
f := l + 1;
end;
Result := Counter.State;
end;
procedure TMyc3Tasks.ParallelFor(LowVal, HighVal, Slice: Integer; const Proc: TProc<Integer, Integer>);
begin
if Slice <= 0 then
Slice := max( 1, (HighVal-LowVal+1) div ThreadCount );
if HighVal - LowVal >= Slice then
WaitFor( ParallelFor( nil, LowVal, HighVal, Slice, Proc ) )
else
Proc( LowVal, HighVal );
end;
procedure TMyc3Tasks.Run( const StartSignal: IMyc2Signal; const Proc: TProc );
begin
if not Signals.IsStatic( StartSignal ) then
begin
if FEnabled then
StartSignal.Advise( FApi.Run( 1, Proc ) )
else
StartSignal.Advise( Signals.CreateSink( True, Proc ) );
end
else
Run( Proc );
end;
procedure TMyc3Tasks.Run( const Proc: TProc );
begin
if FEnabled then
FApi.Run( 0, Proc )
else
Proc( );
end;
procedure TMyc3Tasks.SetEnabled( const Value: Boolean );
begin
{$ifndef DisableThreading}
FEnabled := Value;
{$endif}
end;
function TMyc3Tasks.Start( const StartSignal: IMyc2Signal; const Proc: TFunc<IMyc2Signal> ): IMyc2State;
var
Done: IMyc2Condition;
CapturedProc: TFunc<IMyc2Signal>;
begin
if not Assigned( Proc ) then
exit( Signals.Null.State );
Done := Signals.CreateCounter( 1 );
CapturedProc := Proc;
Run( StartSignal,
procedure
var
Sig: IMyc2Signal;
begin
try
Sig := CapturedProc( );
finally
CapturedProc := nil;
if not Signals.IsStatic( Sig ) then
Sig.Advise( Done )
else
Done.Notify;
end;
end );
exit( Done.State );
end;
function TMyc3Tasks.Start( const StartSignal: IMyc2Signal; Proc: TProc ): IMyc2State;
var
Done: IMyc2Condition;
begin
Assert( Assigned( Proc ) );
Done := Signals.CreateCounter( 1 );
Run( StartSignal,
procedure
begin
try
Proc;
finally
Done.Notify;
end;
end );
exit( Done.State );
end;
function TMyc3Tasks.Start( const Proc: TFunc<IMyc2Signal> ): IMyc2State;
begin
Result := Start( nil, Proc );
end;
function TMyc3Tasks.Start( const Proc: TProc ): IMyc2State;
begin
Result := Start( nil, Proc );
end;
function TMyc3Tasks.Start<T1, T2>( const StartSignal: IMyc2Signal; P1: T1; P2: T2; Proc: TProc<T1, T2> ): IMyc2State;
begin
Result := Start( StartSignal,
procedure
begin
Proc( P1, P2 );
end );
end;
function TMyc3Tasks.Start<T1>( const StartSignal: IMyc2Signal; P1: T1; Proc: TProc<T1> ): IMyc2State;
begin
Result := Start( StartSignal,
procedure
begin
Proc( P1 );
end );
end;
procedure TMyc3Tasks.WaitFor( const State: IMyc2State );
begin
FApi.WaitFor( State );
end;
{ TValue<T> }
class constructor TValue<T>.CreateClass;
begin
FDefaultMutable := TMyc3ConstantMutable<T>.Create( Default(T) );
FDefaultMutableFuture := TMyc3ConstantMutable<IMyc3Future<T>>.Create( TMyc3ConstantFuture<T>.Create( Default(T) ) );
end;
class function TValue<T>.Capture( const Src: TArray<T> ): TArray<T>;
var
i: Integer;
begin
SetLength( Result, Length( Src ) );
for i := 0 to High( Src ) do
Result[i] := Src[i];
end;
class function TValue<T>.CreateFuture( Future: IMyc3Future<T>; Creator: TFunc < T, IMyc3Future < T >> ): IMyc3Future<T>;
begin
Result := TMyc3Future<T>.CreateFuture( Future.Initialized,
function: IMyc3Future<T>
begin
Result := Creator( Future.Value );
end );
end;
class function TValue<T>.CreateFuture( const StartSignal: IMyc2Signal; const Calculator: TFunc < IMyc3Future < T >> )
: IMyc3Future<T>;
begin
Result := TMyc3Future<T>.CreateFuture( StartSignal,
function: IMyc3Future<T>
begin
Result := Calculator( );
end );
end;
class function TValue<T>.Combine<V>( const Values: TArray<IMyc3Future<V>>; Combiner: TMyc3Combiner<T, V> ): IMyc3Future<T>;
begin
if Values=nil then
exit( DefaultFuture );
Result := CreateFuture<V>( Values,
function( Arr: TArray<V> ): T
begin
Result := Combiner( Arr );
end );
end;
class function TValue<T>.Combine<V>( Values: TArray<V>; Combiner: TMyc3Combiner<T, V> ): IMyc3Future<T>;
begin
if Values=nil then
exit( DefaultFuture );
Result := TValue<T>.CreateFuture(
function: T
begin
Result := Combiner( Values );
end );
end;
class function TValue<T>.Combine<V>(const Values: TArray<IMyc3Mutable<V>>; Combiner: TMyc3Combiner<T, V>): IMyc3Mutable<T>;
var
Chg: TArray<IMyc2Signal>;
i: Integer;
begin
Result := Mutable.Convert<TArray<V>, T>(
TValue<V>.CreateMutable(Values),
function( Values: TArray<V> ): T
begin
if not Assigned( Combiner ) then
exit( Default( T ) );
Result := Combiner( Values );
end );
end;
class function TValue<T>.CreateAnimator( const Target: IMyc3Mutable<T>; const Interpolator: TMyc3TargetInterpolator<T> )
: IMyc3Animator<T>;
begin
Result := CreateAnimator( Target.Value, Target.Changed,
function( Delta: Double; const StartValue: T; out Value: T ): Boolean
begin
Result := Interpolator( Delta, StartValue, Target.Value, Value );
if not Result then
Value := Target.Value;
end );
end;
class function TValue<T>.CreateAnimator( const Init: T; const ChangeSignal: IMyc2Signal;
const Interpolator: TMyc3Interpolator<T> ): IMyc3Animator<T>;
begin
Result := TMyc3Animator<T>.Create( Init, ChangeSignal, Interpolator );
end;
class function TValue<T>.AsFuture( const Value: T ): IMyc3Future<T>;
begin
Result := TMyc3ConstantFuture<T>.Create( Value );
end;
class function TValue<T>.CreateFuture( const StartSignal: IMyc2Signal; const Calculator: TFunc<T> ): IMyc3Future<T>;
begin
Result := TMyc3Future<T>.CreateFuture( StartSignal, Calculator );
end;
class function TValue<T>.CreateFuture( const Calculator: TFunc<T> ): IMyc3Future<T>;
begin
Result := TMyc3Future<T>.CreateFuture( Calculator );
end;
class function TValue<T>.CreateFuture<S>( const Params: TArray<IMyc3Future<S>>; Calculator: TFunc<TArray<S>, T> ): IMyc3Future<T>;
var
Counter: IMyc2Condition;
i: Integer;
Arr: TArray<IMyc3Future<S>>;
begin
Counter := Signals.CreateCounter( Length( Params ) );
SetLength( Arr, Length( Params ) );
for i := 0 to High( Params ) do
begin
if Params[i]<>nil then
begin
Arr[i] := Params[i];
Arr[i].Initialized.Advise( Counter );
end
else
Counter.Notify;
end;
Result := TMyc3Future<T>.CreateFuture( Counter.State,
function: T
var
Values: TArray<S>;
i: Integer;
begin
SetLength( Values, Length( Arr ) );
for i := 0 to High( Values ) do
if Arr[i]<>nil then
Values[i] := Arr[i].Value;
Result := Calculator( Values );
end );
end;
class function TValue<T>.CreateFuture<U, V>( P1: IMyc3Future<U>; P2: IMyc3Future<V>; Calculator: TFunc<U, V, T> ): IMyc3Future<T>;
var
Counter: IMyc2Condition;
begin
Assert( Assigned( P1 ) and Assigned( P2 ) );
Counter := Signals.CreateCounter( 2 );
P1.Initialized.Advise( Counter );
P2.Initialized.Advise( Counter );
Result := CreateFuture( Counter.State,
function: T
begin
Result := Calculator( P1.Value, P2.Value );
end );
end;
class function TValue<T>.CreateFuture<U, V>( P1: IMyc3Future<U>; P2: IMyc3Future<V>; Calculator: TFunc < U, V, IMyc3Future < T >>
): IMyc3Future<T>;
var
Counter: IMyc2Condition;
begin
Assert( Assigned( P1 ) and Assigned( P2 ) );
Counter := Signals.CreateCounter( 2 );
P1.Initialized.Advise( Counter );
P2.Initialized.Advise( Counter );
Result := CreateFuture( Counter.State,
function: IMyc3Future<T>
begin
Result := Calculator( P1.Value, P2.Value );
end );
end;
class function TValue<T>.CreateFuture<U>( P: IMyc3Future<U>; Calculator: TFunc<U, T> ): IMyc3Future<T>;
begin
Assert( Assigned( P ) );
Result := CreateFuture( P.Initialized,
function: T
begin
Result := Calculator( P.Value );
end );
end;
class function TValue<T>.CreateFuture<U>( P: IMyc3Future<U>; Calculator: TFunc < U, IMyc3Future < T >> ): IMyc3Future<T>;
begin
Assert( Assigned( P ) );
Result := CreateFuture( P.Initialized,
function: IMyc3Future<T>
begin
Result := Calculator( P.Value );
end );
end;
class function TValue<T>.AsImmutable( const Value: T ): IMyc3Value<T>;
begin
Result := TMyc3Value<T>.Create( Value );
end;
class function TValue<T>.CreateLazy(const Func: TFunc<T>): IMyc3Value<T>;
begin
Result := TMyc3Lazy<T>.Create( Func );
end;
class function TValue<T>.CreateFuture( const Values: TArray < IMyc3Future < T >> ): IMyc3Future<TArray<T>>;
begin
Result := TMyc3FutureArrayEx<T>.Create( Values );
end;
class function TValue<T>.CreateFuture<S>( const Values: TArray<IMyc3Future<S>>; const Calculator: TFunc<Integer, S, T> ):
IMyc3Future<TArray<T>>;
begin
Result := TMyc3FutureArrayConvert<T, S>.Create( Values, Calculator );
end;
class function TValue<T>.CreateFuture<U, V, W>( P1: IMyc3Future<U>; P2: IMyc3Future<V>; P3: IMyc3Future<W>;
Calculator: TFunc<U, V, W, T> ): IMyc3Future<T>;
var
Counter: IMyc2Condition;
begin
Assert( Assigned( P1 ) and Assigned( P2 ) and Assigned( P3 ) );
Counter := Signals.CreateCounter( 3 );
P1.Initialized.Advise( Counter );
P2.Initialized.Advise( Counter );
P3.Initialized.Advise( Counter );
Result := CreateFuture( Counter.State,
function: T
begin
Result := Calculator( P1.Value, P2.Value, P3.Value );
end );
end;
class function TValue<T>.CreateFutures( Count: Integer; const Src: IMyc3Future < TArray < T >> ): TArray<IMyc3Future<T>>;
begin
Result := TMyc3FutureArray<T>.CreateFutures( Count, Src );
end;
class function TValue<T>.CreateMutable( const Value: T ): IMyc3Mutable<T>;
begin
Result := AsConst( Value );
end;
class function TValue<T>.CreateMutable( const Changed: array of IMyc2Signal; const Calculator: TFunc<T> ): IMyc3Mutable<T>;
begin
Result := TMyc3Mutable<T>.CreateMutable( Changed, Calculator );
end;
class function TValue<T>.AsMutable( const Value: IMyc3Mutable<IMyc3Mutable<T>> ): IMyc3Mutable<T>;
begin
Result := TMyc3EnclosedMutable<T>.Create( Value );
end;
class function TValue<T>.AsMutable( const Value: IMyc3Mutable<IMyc3Value<T>> ): IMyc3Mutable<T>;
begin
Result := TValue<T>.CreateMutable<IMyc3Value<T>>(
Value,
function( Immutable: IMyc3Value<T> ): T
begin
if Immutable<>nil then
Result := Immutable.Value
else
Result := default ( T );
end );
end;
class function TValue<T>.AsConst( const Value: T ): IMyc3Mutable<T>;
begin
Result := TMyc3ConstantMutable<T>.Create( Value );
end;
class function TValue<T>.AsMutable(const Value: IMyc3Future<T>): IMyc3Mutable<T>;
begin
Result := TMyc3FutureAsMutable<T>.CreateFutureAsMutable( Value )
end;
class function TValue<T>.AsMutable(const Value: IMyc3Mutable<IMyc3Future<T>>): IMyc3Mutable<T>;
begin
Result := TMyc3EnclosedMutable<T>.Create(
TMyc3Mutable<IMyc3Mutable<T>>.CreateMutable(
Value.Changed,
function: IMyc3Mutable<T>
begin
Result := AsMutable( Value.Value );
end ) );
end;
class function TValue<T>.Convert<S>( P: IMyc3Future<S>; const Converter: TFunc<S, T> ): IMyc3Future<T>;
begin
if P.Initialized.IsSet then
Result := AsFuture( Converter( P.Value ) )
else
Result := CreateFuture<S>( P, Converter );
end;
class function TValue<T>.CreateGeneric(const Calculator: TFunc<T>): IMyc3Generic<T>;
begin
Result := TMyc3Changeable<T>.CreateGeneric( Calculator );
end;
class function TValue<T>.CreateFutureArray( const StartSignal: IMyc2Signal; Count: Integer; const Calculator: TFunc<Integer, T> ):
IMyc3Future<TArray<T>>;
var
Init: IMyc2State;
Arr: TArray<T>;
Calc: TFunc<Integer, T>;
begin
SetLength( Arr, Count );
Calc := Calculator;
Init := Tasks.ParallelFor(
StartSignal,
0, Count-1, 1,
procedure( A, B: Integer )
var
i: Integer;
begin
for i := A to B do
Calc( i )
end );
Result := TMyc3Future<TArray<T>>.CreateFuture( Init, Arr );
end;
class function TValue<T>.CreateFutureArray( Count: Integer; const Calculator: TFunc<Integer, T> ): IMyc3Future<TArray<T>>;
begin
Result := CreateFutureArray( Signals.Null.State, Count, Calculator );
end;
class function TValue<T>.CreateValidate( const Calculator: TFunc<T> ): IMyc3ValidateMutable<T>;
begin
Result := TMyc3ValidateMutable<T>.Create( Calculator );
end;
class function TValue<T>.CreateMutable( const Arr: TArray < IMyc3Mutable < T >> ): IMyc3Mutable<TArray<T>>;
begin
Result := TMyc3Mutable<T>.CreateArray( Arr );
end;
class function TValue<T>.CreateMutable( Calculator: TFunc<T> ): IMyc3Mutable<T>;
begin
Result := CreateMutable( [], Calculator );
end;
class function TValue<T>.CreateMutable( const Event: IMycEventObserver; const Calculator: TFunc<T> ): IMyc3Mutable<T>;
begin
Result := TMyc3Mutable<T>.CreateMutable( Event, Calculator );
end;
class function TValue<T>.CreateMutable( const Changed: array of IMyc2Signal; const Mutable: IMyc3Mutable<T> ): IMyc3Mutable<T>;
var
Notifier: IMyc2Notifier;
i: Integer;
begin
Notifier := Signals.CreateNotifier;
Mutable.Changed.Advise( Notifier );
for i := 0 to High( Changed ) do
Changed[i].Advise( Notifier );
Result := TMyc3Mutable<T>.CreateMutable(
Notifier.Signal,
function: T
begin
Result := Mutable.Value;
end );
end;
class function TValue<T>.CreateMutable(const Changed: array of IMyc2Signal; const Calculator: TFunc<IMyc3Mutable<T>>): IMyc3Mutable<T>;
begin
Result := TMyc3EnclosedMutable<T>.Create( TMyc3Mutable<IMyc3Mutable<T>>.CreateMutable( Changed, Calculator ) );
end;
class function TValue<T>.CreateMutable<U, V, W>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>;
Calculator: TFunc<U, V, W, T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( P1 ) and Assigned( P2 ) and Assigned( P3 ) );
if not Signals.IsStatic(P1.Changed) or not Signals.IsStatic(P2.Changed) or not Signals.IsStatic(P3.Changed) then
begin
Result := TMyc3Mutable<T>.CreateMutable(
[P1.Changed, P2.Changed, P3.Changed],
function: T
begin
Result := Calculator( P1.Value, P2.Value, P3.Value );
end );
end
else
Result := TMyc3ConstantMutable<T>.Create( Calculator( P1.Value, P2.Value, P3.Value ) );
end;
class function TValue<T>.CreateMutable<U, V, W, X>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>;
P4: IMyc3Mutable<X>; Calculator: TFunc<U, V, W, X, T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( P1 ) and Assigned( P2 ) and Assigned( P3 ) and Assigned( P4 ) );
if not Signals.IsStatic(P1.Changed) or not Signals.IsStatic(P2.Changed) or not Signals.IsStatic(P3.Changed) or not Signals.IsStatic(P4.Changed) then
begin
Result := TMyc3Mutable<T>.CreateMutable(
[P1.Changed, P2.Changed, P3.Changed, P4.Changed],
function: T
begin
Result := Calculator( P1.Value, P2.Value, P3.Value, P4.Value );
end );
end
else
Result := TMyc3ConstantMutable<T>.Create( Calculator( P1.Value, P2.Value, P3.Value, P4.Value ) );
end;
class function TValue<T>.CreateMutableEx<S>( Params: TArray<IMyc3Mutable<S>>; Calculator: TFunc<TArray<S>, T> ): IMyc3Mutable<T>;
var
i: Integer;
Sigs: TArray<IMyc2Signal>;
begin
case Length( Params ) of
0:
Result := CreateMutable(
function: T
begin
Result := Calculator( [] );
end );
1:
Result := CreateMutable<S>( Params[0],
function( P: S ): T
begin
Result := Calculator( [P] );
end );
2:
Result := CreateMutable<S, S>( Params[0], Params[1],
function( P1, P2: S ): T
begin
Result := Calculator( [P1, P2] );
end );
3:
Result := CreateMutable<S, S, S>( Params[0], Params[1], Params[2],
function( P1, P2, P3: S ): T
begin
Result := Calculator( [P1, P2, P3] );
end );
4:
Result := CreateMutable<S, S, S, S>( Params[0], Params[1], Params[2], Params[3],
function( P1, P2, P3, P4: S ): T
begin
Result := Calculator( [P1, P2, P3, P4] );
end );
else
begin
SetLength( Sigs, Length( Params ) );
for i := 0 to High( Sigs ) do
begin
Assert( Assigned( Params[i] ) );
Sigs[i] := Params[i].Changed;
end;
Result := TMyc3Mutable<T>.CreateMutable(
Sigs,
function: T
var
Values: TArray<S>;
Init: IMyc2Signal;
i: Integer;
begin
SetLength( Values, Length( Params ) );
for i := 0 to High( Values ) do
Values[i] := Params[i].Value;
Result := Calculator( Values );
end );
end;
end;
end;
class function TValue<T>.CreateMutable<S>( const Arr: TArray<IMyc3Mutable<S>>; Calculator: TFunc<Integer, S, T> ):
IMyc3Mutable<TArray<T>>;
begin
Result := TMyc3MutableArray<T, S>.Create( Arr, Calculator );
end;
class function TValue<T>.CreateMutable<U, V, W, X, Y, Z>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>; P4:
IMyc3Mutable<X>; P5: IMyc3Mutable<Y>; P6: IMyc3Mutable<Z>; Calculator: TFunc<U, V, W, X, Y, Z, T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( P1 ) and Assigned( P2 ) and Assigned( P3 ) and Assigned( P4 ) and Assigned( P5 ) and Assigned( P6 ) );
if not Signals.IsStatic(P1.Changed) or not Signals.IsStatic(P2.Changed) or not Signals.IsStatic(P3.Changed)
or not Signals.IsStatic(P4.Changed) or not Signals.IsStatic(P5.Changed) or not Signals.IsStatic(P6.Changed) then
begin
Result := TMyc3Mutable<T>.CreateMutable(
[P1.Changed, P2.Changed, P3.Changed, P4.Changed, P5.Changed, P6.Changed],
function: T
begin
Result := Calculator( P1.Value, P2.Value, P3.Value, P4.Value, P5.Value, P6.Value );
end );
end
else
Result := TMyc3ConstantMutable<T>.Create( Calculator( P1.Value, P2.Value, P3.Value, P4.Value, P5.Value, P6.Value ) );
end;
class function TValue<T>.CreateMutable<U, V, W, X, Y>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; P3: IMyc3Mutable<W>; P4: IMyc3Mutable<X>;
P5: IMyc3Mutable<Y>; Calculator: TFunc<U, V, W, X, Y, T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( P1 ) and Assigned( P2 ) and Assigned( P3 ) and Assigned( P4 ) and Assigned( P5 ) );
if not Signals.IsStatic(P1.Changed) or not Signals.IsStatic(P2.Changed) or not Signals.IsStatic(P3.Changed)
or not Signals.IsStatic(P4.Changed) or not Signals.IsStatic(P5.Changed) then
begin
Result := TMyc3Mutable<T>.CreateMutable(
[P1.Changed, P2.Changed, P3.Changed, P4.Changed, P5.Changed],
function: T
begin
Result := Calculator( P1.Value, P2.Value, P3.Value, P4.Value, P5.Value );
end );
end
else
Result := TMyc3ConstantMutable<T>.Create( Calculator( P1.Value, P2.Value, P3.Value, P4.Value, P5.Value ) );
end;
class function TValue<T>.CreateMutable<U, V>( P1: IMyc3Mutable<U>; P2: IMyc3Mutable<V>; Calculator: TFunc<U, V, T> )
: IMyc3Mutable<T>;
begin
Assert( Assigned( P1 ) and Assigned( P1 ) );
if not Signals.IsStatic(P1.Changed) or not Signals.IsStatic(P2.Changed) then
begin
Result := TMyc3Mutable<T>.CreateMutable(
[P1.Changed, P2.Changed],
function: T
begin
Result := Calculator( P1.Value, P2.Value );
end );
end
else
Result := TMyc3ConstantMutable<T>.Create( Calculator( P1.Value, P2.Value ) );
end;
class function TValue<T>.CreateMutable<U>( P: IMyc3Mutable<U>; Calculator: TFunc<U, T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( P ) );
if not Signals.IsStatic(P.Changed) then
begin
Result := TMyc3Mutable<T>.CreateMutable(
P.Changed,
function: T
begin
Result := Calculator( P.Value );
end );
end
else
Result := TMyc3ConstantMutable<T>.Create( Calculator( P.Value ) );
end;
class function TValue<T>.CreateWriteable( const InitValue: T ): IMyc3Writeable<T>;
begin
Result := TMyc3Writeable<T>.CreateWriteable( InitValue );
end;
class function TValue<T>.CreatePropertyEx( const Decorated: IMyc3Mutable<T> ): IMyc3Property<T>;
begin
Result := TMycProperty<T>.CreateProperty( Decorated );
end;
class function TValue<T>.CreateProperty( const Creator: TFunc < IMyc3Mutable < T >> ): IMyc3MutablePropertyEx<T>;
begin
Result := TMyc3MutablePropertyEx<T>.Create( Creator );
end;
class function TValue<T>.CreateMutableProperty(const InitValue: IMyc3Mutable<T>): IMyc3MutableProperty<T>;
begin
Result := TMyc3MutableProperty<T>.Create( InitValue );
end;
class function TValue<T>.CreateSet: IMycSet<T>;
begin
Result := TMycSet<T>.Create;
end;
class function TValue<T>.CreateWriteable( const InitValue: T; const EqualityComparison: TEqualityComparison<T> )
: IMyc3Writeable<T>;
begin
Result := TMyc3Writeable<T>.CreateWriteable( InitValue, EqualityComparison );
end;
class function TValue<T>.CreateWriteable: IMyc3Writeable<T>;
begin
Result := CreateWriteable( Default(T) );
end;
class function TValue<T>.Execute( Future: IMyc3Future<T>; Proc: TConstFunc<T, IMyc2Signal> ): IMyc2State;
begin
Result := Tasks.Start( Future.Initialized,
function: IMyc2Signal
begin
Result := Proc( Future.Value );
end );
end;
class function TValue<T>.GetDefaultFuture: IMyc3Future<T>;
begin
Result := TMyc3Future<T>.DefaultFuture;
end;
class function TValue<T>.MakeValid( const Value: IMyc3Future<T> ): IMyc3Future<T>;
begin
Result := Value;
if Result = nil then
Result := DefaultFuture;
end;
class function TValue<T>.MakeValid( const Value: IMyc3Mutable<T> ): IMyc3Mutable<T>;
begin
Result := Value;
if Result = nil then
Result := DefaultMutable;
end;
class function TValue<T>.TryGetValue( const Future: IMyc3Future<T>; out Value: T ): Boolean;
begin
Result := Future <> nil;
if Result then
begin
Result := Future.Initialized = Signals.Null.State;
if Result then
begin
Result := Future.Initialized.IsSet;
if Result then
Value := Future.Value;
end;
end;
end;
class function TValue<T>.WaitFor( Future: IMyc3Future<T> ): T;
begin
Tasks.WaitFor( Future.Initialized );
exit( Future.Value );
end;
class procedure TValue<T>.WaitFor( const Futures: TArray<IMyc3Future<T>>; Exec: TProc<Integer, T> );
var
i: Integer;
Arr: TArray<IMyc3Future<T>>;
begin
SetLength( Arr, Length( Futures ) );
for i := 0 to High( Futures ) do
if Futures[i].Initialized.IsSet then
Exec( i, Futures[i].Value )
else
Arr[i] := Futures[i];
for i := 0 to High( Arr ) do
if Arr[i] <> nil then
Exec( i, WaitFor( Futures[i] ) );
end;
{ TMyc2ComputeProperty<T> }
constructor TMyc2ComputeProperty<T>.Create( const StartSignal: IMyc2Signal; const Creator: TFunc<T> );
var
P: ^T;
begin
FValue := default ( T );
P := @FValue;
FDone := Tasks.Start( StartSignal,
procedure
begin
P^ := Creator( );
end );
end;
procedure TMyc2ComputeProperty<T>.Terminate;
begin
if FDone <> Signals.Null.State then
begin
Tasks.WaitFor( FDone );
FDone := Signals.Null.State;
end;
end;
function TMyc2ComputeProperty<T>.Value: T;
begin
Terminate;
Result := FValue;
end;
{ Signals }
class function Signals.CreateCounter( Count: Integer ): IMyc2Condition;
begin
Result := TMyc2Signal.CreateCounter( Count )
end;
class function Signals.CreateEvent( Init: Boolean = false ): IMyc2Event;
begin
Result := TMyc2Signal.CreateEvent( Init );
end;
class function Signals.CreateNotifier: IMyc2Notifier;
begin
Result := TMyc2Signal.CreateNotifier;
end;
class function Signals.CreateSink(Once: Boolean; const Proc: TProc): IMyc2Sink;
begin
Result := TMyc2SinkProc.CreateSink( Once, Proc );
end;
class function Signals.Concat( const States: array of IMyc2State ): IMyc2State;
begin
Result := TMyc2Signal.CreateConcat( States );
end;
class function Signals.CreateObserver<T>( const Signals: array of IMyc2Signal; const Sink: T ): IMycObserver<T>;
begin
Result := TMycObserver<T>.CreateObserver( Signals, Sink );
end;
class function Signals.CreateEventObserver( const Signals: array of IMyc2Signal ): IMycEventObserver;
begin
Result := CreateObserver<IMyc2Event>( Signals, CreateEvent( True ) );
end;
class function Signals.CreateNotifyObserver( const Signals: array of IMyc2Signal ): IMycNotifyObserver;
begin
Result := CreateObserver<IMyc2Notifier>( Signals, CreateNotifier );
end;
class function Signals.CreateNotifyObserver( const Signals: IMycCountable<IMyc2Signal> ): IMycNotifyObserver;
var
Arr: TArray<IMyc2Signal>;
i: Integer;
begin
SetLength( Arr, Signals.Count );
for i := 0 to High( Arr ) do
Arr[i] := Signals[i];
Result := CreateNotifyObserver( Arr );
end;
class function Signals.CreateEventObserver( const Signals: IMycCountable<IMyc2Signal> ): IMycEventObserver;
var
Arr: TArray<IMyc2Signal>;
i: Integer;
begin
SetLength( Arr, Signals.Count );
for i := 0 to High( Arr ) do
Arr[i] := Signals[i];
Result := CreateEventObserver( Arr );
end;
class function Signals.CreateFlag(Init: Boolean): IMyc2Flag;
begin
Result := TMyc2Flag.Create( Init );
end;
class function Signals.CreateSink(const Proc: TProc): IMyc2Sink;
begin
Result := TMyc2SinkProc.CreateSink( false, Proc );
end;
class function Signals.GetNull: IMyc2Condition;
begin
exit( TMyc2Signal.Null );
end;
class function Signals.IsStatic( const Signal: IMyc2Signal ): Boolean;
begin
Result := ( Signal = nil ) or ( Signal = Null.State );
end;
class function Signals.MakeValid( const Signal: IMyc2Signal ): IMyc2Signal;
begin
if IsStatic( Signal ) then
exit( Null.State )
else
exit( Signal );
end;
class function Signals.MakeValid( const Signals: array of IMyc2Signal ): TArray<IMyc2Signal>;
begin
Result := TMyc2Signal.MakeValid( Signals );
end;
class function Signals.Union( const Sigs: array of IMyc2Signal ): IMyc2Signal;
begin
Result := TMyc2Signal.CreateUnion( Sigs );
end;
{ TState }
class function TAtomicStack<T>.Create: IAtomicStack<T>;
begin
Result := TMycAtomicStack<T>.Create;
end;
{ TProtected<T> }
constructor TProtected<T>.Create( const AItem: T );
begin
FItem := AItem;
end;
function TProtected<T>.Exchange( const Value: T ): T;
begin
if Value <> nil then
Value._AddRef;
PPointer( @Result )^ := TInterlocked.Exchange( PPointer( @FItem )^, PPointer( @Value )^ );
end;
class operator TProtected<T>.Implicit( const Value: T ): TProtected<T>;
begin
Result.Create( Value );
end;
{ Mutable }
class function Mutable.ConvertSet<T, S>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>; const Converter: TFunc<T, S>): IMyc3Mutable<
TArray< IMyc3Mutable<S>>>;
begin
Result := TValue<TArray<IMyc3Mutable<S>>>.CreateMutable<TArray<IMyc3Mutable<T>>>(
Arr,
function( Arr: TArray<IMyc3Mutable<T>> ): TArray<IMyc3Mutable<S>>
var
i: Integer;
begin
SetLength( Result, Length(Arr) );
for i := 0 to High(Result) do
begin
Assert( Arr[i] <> nil );
Result[i] := TValue<S>.CreateMutable<T>( Arr[i], Converter );
end;
end );
end;
class function Mutable.ConvertSet<T, S>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>; const Converter: TFunc<T, S>):
IMyc3Mutable<TArray< IMyc3Mutable<IMyc3Future<S>>>>;
begin
Result := ConvertSet<IMyc3Future<T>, IMyc3Future<S>>(
Arr,
function( Item: IMyc3Future<T> ): IMyc3Future<S>
begin
Assert( Item <> nil );
Result := TValue<S>.CreateFuture<T>( Item, Converter );
end );
end;
class function Mutable.Create( Value: Boolean ): IMyc3Mutable<Boolean>;
begin
Result := TMycMutableBoolean.CreateBoolean( Value );
end;
class function Mutable.CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>): IMyc3Mutable<TArray<T>>;
begin
Result :=
Mutable.From<TArray<IMyc3Mutable<T>>, TArray<T>>(
Arr,
function( Arr: TArray<IMyc3Mutable<T>> ): IMyc3Mutable<TArray<T>>
begin
Result := TValue<T>.CreateMutable( Arr );
end );
end;
class function Mutable.CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>): IMyc3Mutable<IMyc3Future<TArray<T>>>;
begin
Result :=
Mutable.From<TArray<IMyc3Mutable<IMyc3Future<T>>>, IMyc3Future<TArray<T>>>(
Arr,
function( Arr: TArray<IMyc3Mutable<IMyc3Future<T>>> ): IMyc3Mutable<IMyc3Future<TArray<T>>>
begin
Result := TMutableFuture.FromArray<T>( Arr );
end );
end;
class function Mutable.CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>; const Creator: TFunc<TArray<T>, T>): IMyc3Mutable<T>;
begin
Result := TValue<T>.AsMutable(
TValue<IMyc3Mutable<T>>.CreateMutable<TArray<IMyc3Mutable<T>>>(
Arr,
function( Arr: TArray<IMyc3Mutable<T>> ): IMyc3Mutable<T>
begin
Result := TValue<T>.CreateMutable<TArray<T>>( TValue<T>.CreateMutable( Arr ), Creator ) ;
end ) );
end;
class function Mutable.CreateAssembly<T, S>(
const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>;
const Creator: TFunc<TArray<T>, S>): IMyc3Mutable<IMyc3Future<S>>;
begin
Result := CreateAssembly<IMyc3Future<T>, IMyc3Future<S>>( Arr,
function( Arr: TArray<IMyc3Future<T>> ): IMyc3Future<S>
begin
Result := TValue<S>.CreateFuture<TArray<T>>( TValue<T>.CreateFuture( Arr ), Creator );
end );
end;
class function Mutable.CreateAssembly<T, S>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<T>>>; const Creator: TFunc<TArray<T>, S>):
IMyc3Mutable<S>;
begin
Result := TValue<S>.AsMutable(
TValue<IMyc3Mutable<S>>.CreateMutable<TArray<IMyc3Mutable<T>>>(
Arr,
function( Arr: TArray<IMyc3Mutable<T>> ): IMyc3Mutable<S>
begin
Result := TValue<S>.CreateMutable<TArray<T>>( TValue<T>.CreateMutable( Arr ), Creator ) ;
end ) );
end;
class function Mutable.CreateAssembly<T>(const Arr: IMyc3Mutable<TArray<IMyc3Mutable<IMyc3Future<T>>>>; const Creator: TFunc<TArray<T>, T>)
: IMyc3Mutable<IMyc3Future<T>>;
begin
Result := CreateAssembly<IMyc3Future<T>>( Arr,
function( Arr: TArray<IMyc3Future<T>> ): IMyc3Future<T>
begin
Result := TValue<T>.CreateFuture<TArray<T>>( TValue<T>.CreateFuture( Arr ), Creator );
end );
end;
class function Mutable.FromSignal(const Signal: IMyc2Signal): IMyc3Mutable<Boolean>;
begin
Result := TMycMutableSignal.Create( Signal );
end;
class function Mutable.CreateOverride<T>(const Value, Ovrride: IMyc3Mutable<TImmutable<T>>): IMyc3Mutable<TImmutable<T>>;
begin
Result := TValue<TImmutable<T>>.CreateMutable<TImmutable<T>, TImmutable<T>>(
Value, Ovrride,
function( Value, Ovrride: TImmutable<T> ): TImmutable<T>
begin
if not Ovrride.HasValue then
Result := Value
else
Result := Ovrride;
end );
end;
class function Mutable.CreateCache<T>( const Comparer: IComparer<T> = nil ): TMutableCache<T>;
begin
Result.Create( TMycMutableTable<T>.Create( Comparer ) );
end;
class function Mutable.CreateNotifyObserver<T>(const Mutables: TArray<IMyc3Mutable<T>>): IMycNotifyObserver;
var
Sigs: TArray<IMyc2Signal>;
i: Integer;
begin
SetLength( Sigs, Length(Mutables) );
for i := 0 to High(Sigs) do
Sigs[i] := Mutables[i].Changed;
Result := Signals.CreateNotifyObserver(Sigs);
end;
class function Mutable.CreateEventObserver<T>(const Mutables: TArray<IMyc3Mutable<T>>): IMycEventObserver;
var
Sigs: TArray<IMyc2Signal>;
i: Integer;
begin
SetLength( Sigs, Length(Mutables) );
for i := 0 to High(Sigs) do
Sigs[i] := Mutables[i].Changed;
Result := Signals.CreateEventObserver(Sigs);
end;
class function Mutable.CreateValidator<T>( const Comparer: IComparer<T> = nil ): IMyc3MutableCache<T>;
begin
Result := TMycMutableCache<T>.CreateCache( Comparer );
end;
class function Mutable.ExtractSignals<T>(const Mutables: TArray<IMyc3Mutable<T>>): IMyc2Signal;
var
i: Integer;
Arr: TArray<IMyc2Signal>;
begin
SetLength( Arr, Length(Mutables) );
for i := 0 to High(Arr) do
Arr[i] := Mutables[i].Changed;
Result := Signals.Union( Arr );
end;
class function Mutable.False: IMyc3Mutable<Boolean>;
begin
Result := TMycMutableBoolean.CreateBoolean( System.False );
end;
class function Mutable.From<S, T>(const Value: IMyc3Mutable<S>; const Conv: TFunc<S, IMyc3Mutable<T>>): IMyc3Mutable<T>;
begin
Result := TMyc3EnclosedMutable<T>.Create(
TValue<IMyc3Mutable<T>>.CreateMutable<S>( Value, Conv ) );
end;
class function Mutable.Convert<S, T>(const Value: IMyc3Mutable<S>; const Conv: TFunc<S, T>): IMyc3Mutable<T>;
begin
Result := TValue<T>.CreateMutable<S>( Value, Conv );
end;
class function Mutable.Convert<S, T>(const Value: IMyc3Mutable<IMyc3Future<S>>; const Conv: TFunc<S, T>): IMyc3Mutable<IMyc3Future<T>>;
begin
Result := Convert<IMyc3Future<S>, IMyc3Future<T>>(
Value,
function( Value: IMyc3Future<S> ): IMyc3Future<T>
begin
Result := TFuture.From<S, T>( Value, Conv )
end );
end;
class function Mutable.Convert<S, T>(const Value: IMyc3Mutable<IMyc3Future<S>>; const Conv: TFunc<S, IMyc3Future<T>>): IMyc3Mutable<IMyc3Future<T>>;
begin
Result := Convert<IMyc3Future<S>, IMyc3Future<T>>(
Value,
function( Value: IMyc3Future<S> ): IMyc3Future<T>
begin
Result := TFuture.From<S, T>( Value, Conv )
end );
end;
class function Mutable.CreateNullable<T>: IMyc3Writeable<TImmutable<T>>;
begin
Result := TValue<TImmutable<T>>.CreateWriteable( TImmutable<T>.Null );
end;
class function Mutable.CreateObjectLink<T>(Obj: T): IMyc3ObjectLink<T>;
begin
Result := TMyc3ObjectLink<T>.Create( Obj );
end;
class function Mutable.TrimArray<T>(const Values: IMyc3Mutable<TArray<T>>): IMyc3Mutable<TArray<T>>;
begin
Result := TValue<TArray<T>>.CreateMutable<TArray<T>>(
Values,
function( Values: TArray<T> ): TArray<T>
var
i, n: Integer;
begin
n := 0;
for i := 0 to High(Values) do
if Assigned(Values[i]) then
inc(n);
SetLength( Result, n );
n := 0;
for i := 0 to High(Values) do
begin
Result[n] := Values[i];
inc(n);
end;
end );
end;
class function Mutable.FilterArray<T>(const Values: IMyc3Mutable<TArray<T>>; const FilterFunc: TConstFunc<T, IMyc3Mutable<Boolean>>): IMyc3Mutable<TArray<T>>;
var
Sieve: IMyc3Mutable<TArray<IMyc3Mutable<Boolean>>>;
begin
Sieve := TValue<TArray<IMyc3Mutable<Boolean>>>.CreateMutable<TArray<T>>(
Values,
function( Values: TArray<T> ): TArray<IMyc3Mutable<Boolean>>
var
i: Integer;
begin
SetLength( Result, Length( Values ) );
for i := 0 to High(Values) do
Result[i] := FilterFunc( Values[i] );
end );
Result := TValue<TArray<T>>.CreateMutable<TArray<Boolean>, TArray<T>>(
Mutable.CreateAssembly<Boolean>( Sieve ),
Values,
function( Sieve: TArray<Boolean>; GeoArr: TArray<T> ): TArray<T>
var
i, n: Integer;
begin
n := 0;
for i := 0 to High(GeoArr) do
if Sieve[i] then
inc( n );
SetLength( Result, n );
n := 0;
for i := 0 to High(GeoArr) do
if Sieve[i] then
begin
Result[n] := GeoArr[i];
inc(n);
end;
end );
end;
class function Mutable.From<R, S, T>(const ValueR: IMyc3Mutable<R>; const ValueS: IMyc3Mutable<S>; const Conv: TFunc<R, S, IMyc3Mutable<T>>): IMyc3Mutable<T>;
begin
Result := TMyc3EnclosedMutable<T>.Create(
TValue<IMyc3Mutable<T>>.CreateMutable<R, S>( ValueR, ValueS, Conv ) );
end;
class function Mutable.From<T>(const Value: T): IMyc3Mutable<T>;
begin
Result := TMyc3ConstantMutable<T>.Create( Value );
end;
class function Mutable.FromArray<S, T>(const Value: IMyc3Mutable<TArray<S>>; const Conv: TFunc<S, T>): IMyc3Mutable<TArray<T>>;
begin
Result :=
Convert<TArray<S>, TArray<T>>( Value,
function( Arr: TArray<S> ): TArray<T>
var
i: Integer;
begin
SetLength( Result, Length(Arr) );
for i := 0 to High(Arr) do
Result[i] := Conv( Arr[i] );
end );
end;
class function Mutable.FromArray<S, T>(const Value: IMyc3Mutable<TArray<S>>; const Conv: TFunc<S, IMyc3Mutable<T>>): IMyc3Mutable<TArray<T>>;
begin
Result := CreateAssembly<T>( FromArray<S, IMyc3Mutable<T>>( Value, Conv ) );
end;
class function Mutable.FromArray<T>(const Value: TArray<IMyc3Mutable<T>>): IMyc3Mutable<TArray<T>>;
begin
Result := TMyc3MutableArray<T, T>.Create(
Value,
function( Idx: Integer; Val: T ): T
begin
Result := Val;
end );
end;
class function Mutable.FromState(const State: IMyc2State): IMyc3Mutable<Boolean>;
begin
Result := TMycMutableState.Create( State );
end;
class function Mutable.IfNotThen<T>(const Condition: IMyc3Mutable<Boolean>; const FalseValue: IMyc3Mutable<T>): IMyc3Mutable<T>;
begin
Assert( Assigned( Condition ) and Assigned( FalseValue ) );
if Signals.IsStatic(Condition.Changed) then
begin
if Condition.Value then
exit( TValue<T>.DefaultMutable )
else
exit( FalseValue );
end;
Result := TMyc3Mutable<T>.CreateMutable(
[Condition.Changed, FalseValue.Changed],
function: T
begin
if Condition.Value then
Result := System.Default( T )
else
Result := FalseValue.Value;
end );
end;
class function Mutable.IfThen<T>(const Condition: IMyc3Mutable<Boolean>; const TrueValue: IMyc3Mutable<T>): IMyc3Mutable<T>;
begin
Assert( Assigned( Condition ) and Assigned( TrueValue ) );
if Signals.IsStatic(Condition.Changed) then
begin
if Condition.Value then
exit( TrueValue )
else
exit( TValue<T>.DefaultMutable );
end;
Result := TMyc3Mutable<T>.CreateMutable(
[Condition.Changed, TrueValue.Changed],
function: T
begin
if Condition.Value then
Result := TrueValue.Value
else
Result := System.Default( T );
end );
end;
class function Mutable.IfThen<T>(const Condition: IMyc3Mutable<Boolean>; const TrueValue: IMyc3Mutable<IMyc3Future<T>>): IMyc3Mutable<
IMyc3Future<T>>;
begin
Result := IfThenElse<IMyc3Future<T>>( Condition, TrueValue, TValue<T>.DefaultMutableFuture );
end;
class function Mutable.IfThenElse<T>(const Condition: IMyc3Mutable<Boolean>; const TrueValue, FalseValue: IMyc3Mutable<T>): IMyc3Mutable<T>;
begin
Assert( Assigned( Condition ) and Assigned( TrueValue ) and Assigned( FalseValue ) );
Result := TMyc3Mutable<T>.CreateMutable(
[Condition.Changed, TrueValue.Changed, FalseValue.Changed],
function: T
begin
if Condition.Value then
Result := TrueValue.Value
else
Result := FalseValue.Value;
end );
end;
class function Mutable.Merge<T>(const Parts: IMyc3Mutable<TArray<TArray<T>>>): IMyc3Mutable<TArray<T>>;
begin
Result := TValue<TArray<T>>.CreateMutable<TArray<TArray<T>>>(
Parts,
function( Parts: TArray<TArray<T>> ): TArray<T>
begin
Result := TFuture.Merge<T>( Parts );
end );
end;
class function Mutable.Merge<T>(const Parts: IMyc3Mutable<TArray<IMyc3Future<TArray<T>>>>): IMyc3Mutable<IMyc3Future<TArray<T>>>;
begin
Result := TValue<IMyc3Future<TArray<T>>>.CreateMutable<TArray<IMyc3Future<TArray<T>>>>(
Parts,
function( Parts: TArray<IMyc3Future<TArray<T>>> ): IMyc3Future<TArray<T>>
begin
Result := TFuture.Merge<T>( Parts );
end );
end;
class function Mutable.OpAND(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>;
begin
if Length(Arr)=2 then
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
Arr[0], Arr[1],
function( A, B: Boolean ): Boolean
begin
Result := A and B;
end )
else if Length(Arr)=1 then
Result := Arr[0]
else
Result := TValue<Boolean>.CreateMutable<TArray<Boolean>>(
TValue<Boolean>.CreateMutable(Arr),
function( Arr: TArray<Boolean> ): Boolean
var
i: Integer;
begin
for i := 0 to High(Arr) do
if not Arr[i] then
exit( System.False );
exit( System.true );
end );
end;
class function Mutable.OpNOT(const A: IMyc3Mutable<Boolean>): IMyc3Mutable<Boolean>;
begin
Result := TValue<Boolean>.CreateMutable<Boolean>(
A,
function( A: Boolean ): Boolean
begin
Result := not A;
end );
end;
class function Mutable.OpNOR(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>;
begin
if Length(Arr)=2 then
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
Arr[0], Arr[1],
function( A, B: Boolean ): Boolean
begin
Result := not (A or B);
end )
else if Length(Arr)=1 then
Result := OpNOT( Arr[0] )
else
Result := TValue<Boolean>.CreateMutable<TArray<Boolean>>(
TValue<Boolean>.CreateMutable(Arr),
function( Arr: TArray<Boolean> ): Boolean
var
i: Integer;
begin
for i := 0 to High(Arr) do
if not Arr[i] then
exit( System.true );
exit( System.False );
end );
end;
class function Mutable.OpNAND(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>;
begin
if Length(Arr)=2 then
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
Arr[0], Arr[1],
function( A, B: Boolean ): Boolean
begin
Result := not (A and B);
end )
else if Length(Arr)=1 then
Result := OpNOT( Arr[0] )
else
Result := TValue<Boolean>.CreateMutable<TArray<Boolean>>(
TValue<Boolean>.CreateMutable(Arr),
function( Arr: TArray<Boolean> ): Boolean
var
i: Integer;
begin
for i := 0 to High(Arr) do
if not Arr[i] then
exit( System.true );
exit( System.False );
end );
end;
class function Mutable.OpOR(const Arr: TArray<IMyc3Mutable<Boolean>>): IMyc3Mutable<Boolean>;
begin
if Length(Arr)=2 then
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
Arr[0], Arr[1],
function( A, B: Boolean ): Boolean
begin
Result := A or B;
end )
else if Length(Arr)=1 then
Result := Arr[0]
else
Result := TValue<Boolean>.CreateMutable<TArray<Boolean>>(
TValue<Boolean>.CreateMutable(Arr),
function( Arr: TArray<Boolean> ): Boolean
var
i: Integer;
begin
for i := 0 to High(Arr) do
if Arr[i] then
exit( System.true );
exit( System.False );
end );
end;
class function Mutable.SortArray<T>(const Values: IMyc3Mutable<TArray<T>>; const Comparer: IComparer<T>): IMyc3Mutable<TArray<T>>;
var
Cmp: IComparer<T>;
begin
Cmp := Comparer;
if not Assigned(Cmp) then
Cmp := TComparer<T>.Default;
Result := TValue<TArray<T>>.CreateMutable<TArray<T>>(
Values,
function( Values: TArray<T> ): TArray<T>
begin
SetLength( Result, Length(Values) );
TArray.Copy<T>( Values, Result, Length(Values) );
TArray.Sort<T>( Result, Cmp );
end );
end;
class function Mutable.True: IMyc3Mutable<Boolean>;
begin
Result := TMycMutableBoolean.CreateBoolean( System.True );
end;
class function Mutable<T>.GetComparer: IComparer<IMyc3Mutable<T>>;
begin
Result := TMyc3Mutable<T>.Comparer;
end;
class function Mutable<T>.CreateArray( const Arr: TArray<IMyc3Mutable<T>> ): IMyc3Mutable<TArray<T>>;
begin
Result := TMyc3Mutable<T>.CreateArray( Arr );
end;
class function Mutable<T>.CreateArray<S>( const Arr: IMyc3Mutable<TArray<S>>; Calculator: TFunc<S, T> ): IMyc3Mutable<TArray<T>>;
begin
Result := TMyc3Mutable<TArray<T>>.CreateMutable(
[Arr.Changed],
function: TArray<T>
var
i: Integer;
begin
SetLength( Result, Length( Arr.Value ) );
for i := 0 to High( Arr.Value ) do
Result[i] := Calculator( Arr.Value[i] );
end );
end;
class function Mutable<T>.Default: IMyc3Mutable<T>;
begin
Result := TValue<T>.DefaultMutable;
end;
class function Mutable<T>.IfThen( const Condition: IMyc3Mutable<Boolean>; const TrueValue: IMyc3Mutable<T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( Condition ) and Assigned( TrueValue ) );
if Condition = Mutable.True then
exit( TrueValue )
else if Condition = Mutable.False then
exit( default );
Result := TMyc3Mutable<T>.CreateMutable(
[Condition.Changed, TrueValue.Changed],
function: T
begin
if Condition.Value then
Result := TrueValue.Value
else
Result := System.Default( T );
end );
end;
class function Mutable<T>.IfNotThen( const Condition: IMyc3Mutable<Boolean>; const FalseValue: IMyc3Mutable<T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( Condition ) and Assigned( FalseValue ) );
if Condition = Mutable.True then
exit( default )
else if Condition = Mutable.False then
exit( FalseValue );
Result := TMyc3Mutable<T>.CreateMutable(
[Condition.Changed, FalseValue.Changed],
function: T
begin
if Condition.Value then
Result := System.Default( T )
else
Result := FalseValue.Value;
end );
end;
class function Mutable<T>.IfThenElse( const Condition: IMyc3Mutable<Boolean>; const TrueValue, FalseValue: IMyc3Mutable<T> ): IMyc3Mutable<T>;
begin
Assert( Assigned( Condition ) and Assigned( TrueValue ) and Assigned( FalseValue ) );
if Condition = Mutable.True then
exit( TrueValue );
if Condition = Mutable.False then
exit( FalseValue );
if TrueValue = default then
exit( IfNotThen( Condition, FalseValue ) );
if FalseValue = default then
exit( IfThen( Condition, TrueValue ) );
Result := TMyc3Mutable<T>.CreateMutable(
[Condition.Changed, TrueValue.Changed, FalseValue.Changed],
function: T
begin
if Condition.Value then
Result := TrueValue.Value
else
Result := FalseValue.Value;
end );
end;
{ TMutableBool }
constructor TMutableBool.Create(const AThis: IMyc3Mutable<Boolean>);
begin
FThis := AThis;
end;
class function TMutableBool.GetDefaults(Value: Boolean): IMyc3Mutable<Boolean>;
begin
Result := TMycMutableBoolean.CreateBoolean( Value );
end;
class function TMutableBool.True: IMyc3Mutable<Boolean>;
begin
Result := TMycMutableBoolean.CreateBoolean( System.true );
end;
class function TMutableBool.False: IMyc3Mutable<Boolean>;
begin
Result := TMycMutableBoolean.CreateBoolean( System.false );
end;
class operator TMutableBool.Equal(const A, B: TMutableBool): TMutableBool;
begin
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
A, B,
function( A, B: Boolean ): Boolean
begin
Result := A = B;
end );
end;
class operator TMutableBool.Implicit(const Value: IMyc3Mutable<Boolean>): TMutableBool;
begin
Result.Create( Value );
end;
class operator TMutableBool.Implicit(const Value: TMutableBool): IMyc3Mutable<Boolean>;
begin
Result := Value.This;
end;
class operator TMutableBool.LogicalAnd(const A, B: TMutableBool): TMutableBool;
begin
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
A, B,
function( A, B: Boolean ): Boolean
begin
Result := A and B;
end );
end;
class operator TMutableBool.LogicalNot(const Value: TMutableBool): TMutableBool;
begin
Result := TValue<Boolean>.CreateMutable<Boolean>(
Value,
function( Value: Boolean ): Boolean
begin
Result := not Value;
end );
end;
class operator TMutableBool.LogicalOr(const A, B: TMutableBool): TMutableBool;
begin
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
A, B,
function( A, B: Boolean ): Boolean
begin
Result := A or B;
end );
end;
class operator TMutableBool.NotEqual(const A, B: TMutableBool): TMutableBool;
begin
Result := TValue<Boolean>.CreateMutable<Boolean, Boolean>(
A, B,
function( A, B: Boolean ): Boolean
begin
Result := A <> B;
end );
end;
{ TAssembly<T> }
class function TAssembly<T>.Create: IMycAssembly<T>;
begin
Result := TMycAssembly<T>.Create;
end;
{ TMycArray<T> }
class function TMycArray.Create<T>( const Arr: array of T ): IMycArray<T>;
begin
Result := TMycCustomArray<T>.CreateArray( Arr );
end;
class function TMycArray.Create<T>( Count: Integer; const Getter: TFunc<Integer, T> ): IMycArray<T>;
begin
Result := TMycGenericArray<T>.Create( Count, Getter );
end;
class function TMycArray.Create<S, T>( const Src: IMycArray<S>; const Converter: TConstFunc<S, T> ): IMycArray<T>;
begin
Result := TMycCustomArray<T>.CreateConvert<S>( Src, Converter );
end;
class function TMycArray.Create<T>(const Src: IMyc2Enumerable<T>): IMycArray<T>;
var
n: Integer;
E: IMycEnumerator<T>;
Vals: TArray<T>;
begin
E := Src.GetEnumerator;
n := 0;
while E.MoveNext do
inc( n );
SetLength( Vals, n );
E.Reset;
n := 0;
while E.MoveNext do
begin
Vals[n] := E.Current;
inc(n);
end;
Result := TMycCustomArray<T>.CreateArray( Vals );
end;
class function TMycArray.CreateConvert<T, S>( const Enum: IMyc2Enumerable<S>; const Conv: TConstFunc<S, T> ): IMyc2Enumerable<T>;
begin
Result := TMyc2ConvertEnumerable<T, S>.Create( Enum, Conv );
end;
class function TMycArray.Divide<T>( const Src: TArray<T>; const Comparer: IComparer<T> ): TArray<TArray<T>>;
var
i: Integer;
Arr: TArray<IMycArray<T>>;
begin
Arr := Create<T>( Src ).Divide( Comparer );
SetLength( Result, Length( Arr ) );
for i := 0 to High( Result ) do
Result[i] := Arr[i].ToArray;
end;
class procedure TMycArray.Divide1<TKey, TValue>( const Src: IMycArray<TPair<TKey, TValue>>; out Keys: TArray<TKey>; out Values:
TArray<IMycArray<TValue>>; const Comparer: IComparer<TKey> );
var
Arr: TArray<IMycArray<TPair<TKey, TValue>>>;
i: Integer;
begin
Arr := Src.Divide(
TComparer<TPair<TKey, TValue>>.Construct(
function( const A, B: TPair<TKey, TValue> ): Integer
begin
Result := Comparer.Compare( A.Key, B.Key );
end ) );
SetLength( Keys, Length( Arr ) );
SetLength( Values, Length( Arr ) );
for i := 0 to High( Arr ) do
begin
Keys[i] := Arr[i][0].Key;
Values[i] := TMycCustomArray<TValue>.CreateConvert<TPair<TKey, TValue>>(
Arr[i],
function( const P: TPair<TKey, TValue> ): TValue
begin
Result := P.Value;
end );
end;
end;
class function TMycArray.Divide<TKey, TValue>( const Src: TArray<TPair<TKey, TValue>>; const Comparer: IComparer<TKey> ): TArray<TPair<TKey,
TArray<TValue>>>;
var
i, j: Integer;
Arr: TArray<IMycArray<TPair<TKey, TValue>>>;
begin
Arr := Create<TPair<TKey, TValue>>( Src ).Divide(
TComparer<TPair<TKey, TValue>>.Construct(
function( const A, B: TPair<TKey, TValue> ): Integer
begin
Result := Comparer.Compare( A.Key, B.Key );
end ) );
SetLength( Result, Length( Arr ) );
for i := 0 to High( Result ) do
begin
Result[i].Key := Arr[i][0].Key;
SetLength( Result[i].Value, Arr[i].Count );
for j := 0 to High( Result[i].Value ) do
Result[i].Value[j] := Arr[i][j].Value;
end;
end;
class function TMycArray.Divide<TKey, TValue>( const Src: IMycArray<TPair<TKey, TValue>>; const Comparer: IComparer<TKey> ):
TArray<TPair<TKey, IMycArray<TValue>>>;
var
Arr: TArray<IMycArray<TPair<TKey, TValue>>>;
i: Integer;
begin
Arr := Src.Divide(
TComparer<TPair<TKey, TValue>>.Construct(
function( const A, B: TPair<TKey, TValue> ): Integer
begin
Result := Comparer.Compare( A.Key, B.Key );
end ) );
SetLength( Result, Length( Arr ) );
for i := 0 to High( Result ) do
begin
Result[i] := TPair<TKey, IMycArray<TValue>>.Create(
Arr[i][0].Key,
TMycCustomArray<TValue>.CreateConvert<TPair<TKey, TValue>>(
Arr[i],
function( const P: TPair<TKey, TValue> ): TValue
begin
Result := P.Value;
end ) );
end;
end;
class function TMycArray.GetKeys<TKey, TValue>( const Arr: TArray<TPair<TKey, TValue>> ): TArray<TKey>;
var
i: Integer;
begin
SetLength( Result, Length( Arr ) );
for i := 0 to High( Arr ) do
Result[i] := Arr[i].Key;
end;
class function TChain.Create<T>: IMycChain<T>;
begin
Result := TMycChain<T>.Create;
end;
{ TMutableCache<T> }
constructor TMutableCache<T>.Create( const AThis: IMyc3MutableTable<T> );
begin
FThis := AThis;
end;
function TMutableCache<T>.GetItem(const Value: T): IMyc3Mutable<T>;
begin
Result := FThis.Add( Value );
end;
procedure TMutableCache<T>.Clear;
begin
FThis.Clear;
end;
class function Stack.Create<T>: IMycStack<T>;
begin
Result := TMycStack<T>.Create;
end;
{ TTag }
class function TTag.From<T>(const Data: T): TTag;
begin
{$ifdef DEBUG}
Result.FTypeInfo := TypeInfo(T);
Assert( (Result.FTypeInfo<>nil) and (Result.FTypeInfo.Name <> 'TTag'), 'Recursive tag declaration' );
{$endif}
case PTypeInfo(TypeInfo(T)).Kind of
tkInteger:
begin
case PTypeInfo(TypeInfo(T)).TypeData.OrdType of
otSByte: PShortInt(@Result.FOrdinal)^ := PShortInt(@Data)^;
otUByte: PByte(@Result.FOrdinal)^ := PByte(@Data)^;
otSWord: PSmallInt(@Result.FOrdinal)^ := PSmallInt(@Data)^;
otUWord: PWord(@Result.FOrdinal)^ := PWord(@Data)^;
otSLong: PInteger(@Result.FOrdinal)^ := PInteger(@Data)^;
otULong: PLongword(@Result.FOrdinal)^ := PLongword(@Data)^;
end;
end;
tkInt64:
begin
Result.FOrdinal := PInt64(@Data)^;
end;
tkFloat:
begin
case PTypeInfo(TypeInfo(T)).TypeData.FloatType of
ftSingle: PSingle(@Result.FOrdinal)^ := PSingle(@Data)^;
ftDouble: PDouble(@Result.FOrdinal)^ := PDouble(@Data)^;
else
begin
Result.FOrdinal := 0;
Result.FManaged := TMyc3Value<T>.Create(Data);
end;
end;
end;
{$IFNDEF AUTOREFCOUNT}
tkClass,
{$ENDIF}
tkPointer:
begin
PPointer(@Result.FOrdinal)^ := PPointer(@Data)^;
end;
tkInterface:
begin
Result.FOrdinal := 0;
Result.FManaged := IInterface(PPointer(@Data)^);
end;
else
begin
Result.FOrdinal := 0;
Result.FManaged := TMyc3Value<T>.Create(Data);
end;
end;
end;
function TTag.AsType<T>: T;
begin
{$ifdef DEBUG}
if FTypeInfo=nil then
RaiseInvalidOperation( 'TTag not initialized, value of type %s expected', [PTypeInfo(TypeInfo(T)).Name] );
if FTypeInfo <> TypeInfo(T) then
RaiseInvalidOperation( 'TTag<%s> can''t cast to %s', [FTypeInfo.Name, PTypeInfo(TypeInfo(T)).Name] );
{$endif}
case PTypeInfo(TypeInfo(T)).Kind of
tkInteger:
begin
case PTypeInfo(TypeInfo(T)).TypeData.OrdType of
otSByte: PShortInt(@Result)^ := PShortInt(@FOrdinal)^;
otUByte: PByte(@Result)^ := PByte(@FOrdinal)^;
otSWord: PSmallInt(@Result)^ := PSmallInt(@FOrdinal)^;
otUWord: PWord(@Result)^ := PWord(@FOrdinal)^;
otSLong: PInteger(@Result)^ := PInteger(@FOrdinal)^;
otULong: PLongword(@Result)^ := PLongword(@FOrdinal)^;
end;
end;
tkInt64:
begin
PInt64(@Result)^ := FOrdinal;
end;
tkFloat:
begin
case PTypeInfo(TypeInfo(T)).TypeData.FloatType of
ftSingle: PSingle(@Result)^ := PSingle(@FOrdinal)^;
ftDouble: PDouble(@Result)^ := PDouble(@FOrdinal)^;
else
Result := IMyc3Value<T>( FManaged ).Value;
end;
end;
{$IFNDEF AUTOREFCOUNT}
tkClass,
{$ENDIF}
tkPointer:
begin
PPointer(@Result)^ := PPointer(@FOrdinal)^;
end;
tkInterface:
begin
IInterface(PPointer(@Result)^) := FManaged;
end;
else
begin
Result := IMyc3Value<T>( FManaged ).Value;
end;
end;
end;
{ TMycStateQueue }
constructor TMycStateQueue.Create(const AStack: IAtomicStack<IMyc2State>);
begin
FStack := AStack;
end;
procedure TMycStateQueue.Add(const S: IMyc2State);
begin
FStack.Push( S );
end;
class function TMycStateQueue.Create: TMycStateQueue;
begin
Result.Create( TAtomicStack<IMyc2State>.Create );
end;
procedure TMycStateQueue.WaitFor;
var
S: IMyc2State;
begin
S := FStack.Pop;
while S<>nil do
begin
Tasks.WaitFor( S );
S := FStack.Pop;
end;
end;
{ TMutable<T> }
class function TMutable<T>.FromSignals(const Changed: array of IMyc2Signal; const Calculator: TFunc<T>): IMyc3Mutable<T>;
begin
Result := TMyc3Mutable<T>.CreateMutable( Changed, Calculator );
end;
class function TMutable<T>.FromSignals(const Changed: array of IMyc2Signal; const Calculator: TFunc<IMyc3Mutable<T>>): IMyc3Mutable<T>;
begin
Result := TMyc3EnclosedMutable<T>.Create( TMyc3Mutable<IMyc3Mutable<T>>.CreateMutable( Changed, Calculator ) );
end;
class function TMutable<T>.From<S>(const Value: IMyc3Mutable<S>; const Conv: TFunc<S, IMyc3Mutable<T>>): TMutable<T>;
begin
Result := TMyc3EnclosedMutable<T>.Create( TValue<IMyc3Mutable<T>>.CreateMutable<S>( Value, Conv ) );
end;
class operator TMutable<T>.Explicit(const Value: T): TMutable<T>;
begin
Result.FThis := TMyc3ConstantMutable<T>.Create( Value );
end;
class operator TMutable<T>.Implicit(
const Item: TMutable<T>): IMyc3Mutable<T>;
begin
Result := Item.FThis;
end;
class operator TMutable<T>.Implicit(
const Item: IMyc3Mutable<T>): TMutable<T>;
begin
Result.FThis := Item;
end;
{ TParameterValue }
constructor TParameterValue.Create( ATypeInfo: PTypeInfo; const AMutable: IMyc3Mutable );
begin
FMutable := AMutable;
{$ifdef DEBUG}
FTypeInfo := ATypeInfo;
{$endif}
end;
function TParameterValue.Get<T>: T;
begin
Assert( FMutable<>nil, 'Value is NULL' );
Result := AsType<T>.Value;
end;
function TParameterValue.AsType<T>: IMyc3Mutable<T>;
begin
{$ifdef DEBUG}
CheckType( TypeInfo( T ) );
{$endif}
Result := IMyc3Mutable<T>( FMutable );
end;
class function TParameterValue.Compare( const A, B: TParameterValue ): Integer;
begin
Result := CompareValue( NativeInt( A.Mutable ), NativeInt( B.Mutable ) );
end;
class function TParameterValue.FromArray<T>( const Values: TArray<TParameterValue> ): TArray<IMyc3Mutable<T>>;
var
i: Integer;
begin
SetLength( Result, Length( Values ) );
for i := 0 to High( Result ) do
Result[i] := Values[i].AsType<T>;
end;
class function TParameterValue.Create<T>( const Intf: T ): TParameterValue;
begin
Result.Create( TypeInfo( T ), TValue<T>.CreateMutable( Intf ) );
end;
class function TParameterValue.Create<T>( const Intf: IMyc3Mutable<T> ): TParameterValue;
begin
Result.Create( TypeInfo( T ), Intf );
end;
constructor TParameterValue.Assign( const Src: TParameterValue );
begin
{$ifdef DEBUG}
CheckType( Src.FTypeInfo );
{$endif}
FMutable := Src.FMutable;
end;
{$ifdef DEBUG}
procedure TParameterValue.CheckType(TI: PTypeInfo);
begin
Assert( FTypeInfo = TI, Format( 'Type mismatch (casting param %s to %s)', [FTypeInfo.Name, TI.Name] ) );
end;
{$endif}
class function TParameterValue.FromVarRec( const VarRec: TVarRec ): TParameterValue;
begin
case VarRec.VType of
vtInteger:
Result := TParameterValue.Create<Integer>( VarRec.VInteger );
vtBoolean:
Result := TParameterValue.Create<Boolean>( VarRec.VBoolean );
vtWideChar:
Result := TParameterValue.Create<WideChar>( VarRec.VWideChar );
vtInt64:
Result := TParameterValue.Create<Int64>( VarRec.VInt64^ );
vtChar:
Result := TParameterValue.Create<String>( String( VarRec.VChar ) );
vtPChar:
Result := TParameterValue.Create<String>( String( VarRec.VPChar ) );
vtPWideChar:
Result := TParameterValue.Create<String>( String( VarRec.VPWideChar ) );
vtString:
Result := TParameterValue.Create<String>( String( VarRec.VString^ ) );
vtWideString:
Result := TParameterValue.Create<String>( String( VarRec.VWideString ) );
vtAnsiString:
Result := TParameterValue.Create<String>( String( VarRec.VAnsiString ) );
vtUnicodeString:
Result := TParameterValue.Create<String>( String( VarRec.VUnicodeString ) );
vtObject:
Result := TParameterValue.Create<TObject>( TObject( VarRec.VObject ) );
vtClass:
Result := TParameterValue.Create<TClass>( VarRec.VClass );
vtVariant:
Result := TParameterValue.Create<Variant>( VarRec.VVariant^ );
vtPointer:
Result := TParameterValue.Create<Pointer>( VarRec.VPointer );
vtExtended:
Result := TParameterValue.Create<Extended>( VarRec.VExtended^ );
vtCurrency:
Result := TParameterValue.Create<Currency>( VarRec.VCurrency^ );
vtInterface:
Result := TParameterValue.Create<IInterface>( IInterface( VarRec.VInterface ) );
end;
end;
{ TParameterField }
constructor TParameterField.Create( AID: TFieldID; const AValue: TParameterValue );
begin
FID := AID;
FValue := AValue;
end;
class function TParameterField.Create<T>( ID: TFieldID; const Intf: IMyc3Mutable<T> ): TParameterField;
begin
Result := TParameterField.Create( ID, TParameterValue.Create<T>( Intf ) );
end;
class function TParameterField.Create<T>( ID: TFieldID; const Intf: T ): TParameterField;
begin
Result := TParameterField.Create( ID, TParameterValue.Create<T>( Intf ) );
end;
{ TParameterRecord }
constructor TParameterRecord.Create( const AThis: IMyc3ParameterRecord );
begin
FThis := AThis;
end;
function TParameterRecord.AsType<T>( ID: TFieldID ): IMyc3Mutable<T>;
begin
Result := GetValues( ID ).AsType<T>;
end;
function TParameterRecord.Get<T>(ID: TFieldID): T;
begin
Result := GetValues( ID ).Get<T>;
end;
function TParameterRecord.GetByName( const Caption: String ): TParameterValue;
begin
Result := FThis.ByName[Caption];
end;
function TParameterRecord.GetDef: IMycParameterRecordDefinition;
begin
Result := FThis.Def;
end;
function TParameterRecord.GetValues(ID: TFieldID): TParameterValue;
begin
Result := FThis.Values[ID];
end;
class operator TParameterRecord.Implicit(const Item: IMyc3ParameterRecord): TParameterRecord;
begin
Result.Create( Item );
end;
class operator TParameterRecord.Implicit(const Item: TParameterRecord): IMyc3ParameterRecord;
begin
Result := Item.FThis;
end;
{ TParameterSpace }
constructor TParameterSpace.Create( const AThis: IMycParameterSpace );
begin
FThis := AThis;
end;
function TParameterSpace.CompareValues( FieldID: TFieldID; const A, B: TParameterValue ): Integer;
begin
Result := FThis.CompareValues( FieldID, A, B );
end;
class function TParameterSpace.Create: TParameterSpace;
begin
Result.Create( TMycParameterSpace.Create );
end;
function TParameterSpace.CreateRecord( const Fields: TArray<TParameterField> ): TParameterRecord;
begin
Result.Create( FThis.CreateRecord( Fields ) );
end;
function TParameterSpace.GetCaptions( FieldID: TFieldID ): String;
begin
Result := FThis.Captions[FieldID];
end;
function TParameterSpace.GetComparer( FieldID: TFieldID ): IComparer<TParameterValue>;
begin
Result := FThis.Comparer[FieldID];
end;
function TParameterSpace.GetDefaultValues( FieldID: TFieldID ): TParameterValue;
begin
Result := FThis.DefaultValues[FieldID];
end;
function TParameterSpace.GetFieldCount: Integer;
begin
Result := FThis.FieldCount;
end;
function TParameterSpace.AddField<T>(const Caption: String; const DefaultValue: T; const Comparer: IComparer<T> = nil): TFieldID;
var
ValueComparer: IComparer<T>;
Comp: IComparer<TParameterValue>;
begin
ValueComparer := Comparer;
if ValueComparer=nil then
ValueComparer := TComparer<T>.Default;
Comp := TComparer<TParameterValue>.Construct(
function( const A, B: TParameterValue ): Integer
begin
if ( A.Mutable <> nil ) and ( B.Mutable<>nil ) then
Result := ValueComparer.Compare( A.AsType<T>.Value, B.AsType<T>.Value )
else if A.Mutable <> nil then
Result := 1
else if B.Mutable <> nil then
Result := -1
else
Result := 0;
end );
Result := FThis.AddField( TypeInfo( T ), Caption, TValue<T>.CreateMutable( DefaultValue ), Comp );
end;
function TParameterSpace.CreateDef(const Fields: TArray<TFieldID>): IMycParameterRecordDefinition;
begin
Result := FThis.CreateDef( Fields );
end;
class operator TParameterSpace.Implicit( const Item: TParameterSpace ): IMycParameterSpace;
begin
Result := Item.FThis;
end;
class operator TParameterSpace.Implicit( const Item: IMycParameterSpace ): TParameterSpace;
begin
Result.Create( Item );
end;
{ TMutableFuture }
class function TMutableFuture.FromArray<T>(const Value: TArray<IMyc3Mutable<IMyc3Future<T>>>): IMyc3Mutable<IMyc3Future<TArray<T>>>;
begin
Result := Mutable.Convert<TArray<IMyc3Future<T>>, IMyc3Future<TArray<T>>>(
Mutable.FromArray<IMyc3Future<T>>( Value ),
function( Value: TArray<IMyc3Future<T>> ): IMyc3Future<TArray<T>>
begin
Result := TFuture.FromArray<T>( Value );
end );
end;
constructor TStackTrace.Create(ASkipFrames: Cardinal; const AMsg: String = '');
begin
Msg := AMsg;
{$ifdef FullDebugMode}
FastMM_EnterDebugMode;
FastMM_GetStackTrace(@StackTrace, Length(StackTrace), 0);
{$endif}
end;
function TStackTrace.ToText: String;
{$ifdef FullDebugMode}
var
LStackTraceBuffer: array[0..Len * 160] of WideChar;
{$endif}
begin
Result := Msg;
if Result<>'' then
Result := Result + #13#10;
{$ifdef FullDebugMode}
FastMM_ConvertStackTraceToText(
@StackTrace, Length(StackTrace), @LStackTraceBuffer,
@LStackTraceBuffer[High(LStackTraceBuffer)]);
Result := Result + LStackTraceBuffer;
{$else}
Result := Result + 'StackTrace: FullDebugMode not enabled';
{$endif}
end;
class function TValidatable.FromSignal(const Signal: IMyc2Signal): IMyc3Validatable;
begin
Result := TMyc3ValidatableSignal.Create(Signal);
end;
initialization
Tasks := TMyc3Tasks.Create( TMyc2TaskFactory.Create );
finalization
FreeAndNil( Tasks );
end.