FSM
x) Add whatFile for fast cached lookup of filenames from a path x) Debug renames x) Add default OnChanged handler that does nothing x) Cleanups to the FSM stuff
This commit is contained in:
parent
959b9aac05
commit
a3e79e83b4
55
imm/FSM.cs
55
imm/FSM.cs
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Optional;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -13,25 +15,25 @@ public record class Context : imm.Recorded<Context>
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public record class State<T, CTX>( CTX Context ) : imm.Recorded<State<T, CTX>>
|
public record class State<TSUB, CTX>( CTX Context ) : imm.Recorded<TSUB>
|
||||||
where T : State<T, CTX>
|
where TSUB : State<TSUB, CTX>
|
||||||
where CTX : Context
|
where CTX : Context
|
||||||
{
|
{
|
||||||
virtual public (CTX, T) onEnter(CTX ctx, State<T, CTX> oldState)
|
virtual public (CTX, TSUB) onEnter(CTX ctx, State<TSUB, CTX> oldState)
|
||||||
{
|
{
|
||||||
return (ctx, (T)this);
|
return (ctx, (TSUB)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual public (CTX, T) onExit(CTX ctx, State<T, CTX> newState)
|
virtual public (CTX, TSUB) onExit(CTX ctx, State<TSUB, CTX> newState)
|
||||||
{
|
{
|
||||||
return (ctx, (T)this);
|
return (ctx, (TSUB)this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public record class FSM<T, ST, CTX> : imm.Recorded<FSM<T, ST, CTX>>
|
public record class FSM<TSUB, ST, CTX> : imm.Recorded<TSUB>
|
||||||
where T : FSM<T, ST, CTX>
|
where TSUB : FSM<TSUB, ST, CTX>
|
||||||
where ST : State<ST, CTX>
|
where ST : State<ST, CTX>
|
||||||
where CTX : Context
|
where CTX : Context
|
||||||
{
|
{
|
||||||
@ -44,37 +46,54 @@ public record class FSM<T, ST, CTX> : imm.Recorded<FSM<T, ST, CTX>>
|
|||||||
State = stStart;
|
State = stStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FSM<T, ST, CTX> Transition(ST newState)
|
public TSUB Transition(ST newState, string reason,
|
||||||
|
[CallerMemberName] string memberName = "",
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerArgumentExpression("fn")]
|
||||||
|
string expression = default
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
log.debug( $"Trans from {State.GetType().Name} to {newState.GetType().Name} for {reason}" );
|
||||||
|
|
||||||
var origState = State;
|
var origState = State;
|
||||||
|
|
||||||
var (newOldCTX, oldState) = State.onExit(Context, newState);
|
var (newCtx, oldState) = State.onExit(Context, newState);
|
||||||
|
|
||||||
var (newCTX, storeState) = newState.onEnter(newOldCTX, oldState);
|
var (newCTX, storeState) = newState.onEnter(newCtx, oldState);
|
||||||
|
|
||||||
var newFSM = this.Process( this with
|
var newFSM = this.Process( (v) => (this as TSUB) with
|
||||||
{
|
{
|
||||||
Context = newCTX,
|
Context = newCTX,
|
||||||
State = storeState,
|
State = storeState,
|
||||||
}, $"Trans: {origState.GetType().Name} to {newState.GetType().Name}" );
|
}, $"{reason}" );
|
||||||
|
|
||||||
return newFSM;
|
return newFSM;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FSM<T, ST, CTX> Process( Func<ST, ST> fn, string reason )
|
/*
|
||||||
|
public TSUB ( Func<ST, ST> fn, string reason,
|
||||||
|
[CallerMemberName] string member = "",
|
||||||
|
[CallerFilePath] string file = "",
|
||||||
|
[CallerLineNumber] int line = 0,
|
||||||
|
[CallerArgumentExpression("fn")]
|
||||||
|
string expression = default
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var newState = fn( State );
|
var newState = fn( State );
|
||||||
|
|
||||||
if( object.ReferenceEquals( newState, State ) ) return this;
|
if( object.ReferenceEquals( newState, State ) ) return (TSUB)this;
|
||||||
|
|
||||||
FSM<T, ST, CTX> newFSM = this.Process( this with
|
TSUB newFSM = this.Process( this with
|
||||||
{
|
{
|
||||||
Context = Context,
|
Context = Context,
|
||||||
State = newState,
|
State = newState,
|
||||||
}, $"Processing: {newState.GetType().Name} for {reason}" );
|
}, $"Processing: {newState.GetType().Name} for {reason}",
|
||||||
|
member, file, line, expression );
|
||||||
|
|
||||||
return newFSM;
|
return (TSUB)newFSM;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
71
imm/Imm.cs
71
imm/Imm.cs
@ -14,23 +14,23 @@ static public class Util
|
|||||||
{
|
{
|
||||||
//This can handle both Timed and Recorded
|
//This can handle both Timed and Recorded
|
||||||
static public T Process<T>( ref T obj, Func<T, T> fn, string reason = "",
|
static public T Process<T>( ref T obj, Func<T, T> fn, string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
[CallerArgumentExpression("fn")]
|
[CallerArgumentExpression("fn")]
|
||||||
string expression = default )
|
string dbgExp = default )
|
||||||
where T : Recorded<T>
|
where T : Recorded<T>
|
||||||
{
|
{
|
||||||
obj = obj.Process( fn, reason, memberName, filePath, lineNumber, expression );
|
obj = obj.Process( fn, reason, dbgName, dbgPath, lineNumber, dbgExp );
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static public T LightProcess<T>( ref T obj, Func<T, T> fn, string reason = "",
|
static public T LightProcess<T>( ref T obj, Func<T, T> fn, string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
[CallerArgumentExpression("fn")]
|
[CallerArgumentExpression("fn")]
|
||||||
string expression = default )
|
string dbgExp = default )
|
||||||
where T : Versioned<T>
|
where T : Versioned<T>
|
||||||
{
|
{
|
||||||
obj = obj.Process( fn, reason );
|
obj = obj.Process( fn, reason );
|
||||||
@ -61,7 +61,7 @@ public record class Versioned<T>
|
|||||||
|
|
||||||
public MetaData Meta => MetaStorage;
|
public MetaData Meta => MetaStorage;
|
||||||
|
|
||||||
public ChangeDelegate OnChange;
|
public ChangeDelegate OnChange = (x, y) => {};
|
||||||
|
|
||||||
public T Process( Func<T, T> fn, string reason = "" )
|
public T Process( Func<T, T> fn, string reason = "" )
|
||||||
{
|
{
|
||||||
@ -88,7 +88,7 @@ public record class Recorded<T> : Versioned<T>
|
|||||||
public string Expression { get; internal set; } = "";
|
public string Expression { get; internal set; } = "";
|
||||||
public string MemberName { get; internal set; } = "";
|
public string MemberName { get; internal set; } = "";
|
||||||
public string FilePath { get; internal set; } = "";
|
public string FilePath { get; internal set; } = "";
|
||||||
public int LineNumber { get; internal set; } = -1;
|
public int LineNumber { get; internal set; } = -1;
|
||||||
|
|
||||||
public MetaData() { }
|
public MetaData() { }
|
||||||
}
|
}
|
||||||
@ -105,29 +105,29 @@ public record class Recorded<T> : Versioned<T>
|
|||||||
|
|
||||||
|
|
||||||
virtual public T Record( string reason = "",
|
virtual public T Record( string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0 )
|
[CallerLineNumber] int lineNumber = 0 )
|
||||||
{
|
{
|
||||||
return Process( t => t, reason, memberName, filePath, lineNumber );
|
return Process( t => t, reason, dbgName, dbgPath, lineNumber );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual public T Process( T next, string reason = "",
|
virtual public T Process( T next, string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
[CallerArgumentExpression("next")]
|
[CallerArgumentExpression("next")]
|
||||||
string expression = default )
|
string dbgExp = default )
|
||||||
{
|
{
|
||||||
return Process( ( old ) => next, reason, memberName, filePath, lineNumber, expression );
|
return Process( ( old ) => next, reason, dbgName, dbgPath, lineNumber, dbgExp );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual public T Process( Func<T, T> fn, string reason = "",
|
virtual public T Process( Func<T, T> fn, string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
[CallerArgumentExpression("fn")]
|
[CallerArgumentExpression("fn")]
|
||||||
string expression = default )
|
string dbgExp = default )
|
||||||
{
|
{
|
||||||
var orig = ( T )this;
|
var orig = ( T )this;
|
||||||
|
|
||||||
@ -142,8 +142,8 @@ public record class Recorded<T> : Versioned<T>
|
|||||||
Reason = reason,
|
Reason = reason,
|
||||||
|
|
||||||
ZZOld = orig,
|
ZZOld = orig,
|
||||||
MemberName = memberName,
|
MemberName = dbgName,
|
||||||
FilePath = filePath,
|
FilePath = dbgPath,
|
||||||
LineNumber = lineNumber,
|
LineNumber = lineNumber,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -178,30 +178,31 @@ public record class Timed<T> : Recorded<T>
|
|||||||
|
|
||||||
|
|
||||||
override public T Record( string reason = "",
|
override public T Record( string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0 )
|
[CallerLineNumber] int lineNumber = 0 )
|
||||||
{
|
{
|
||||||
return Process( t => t, reason, memberName, filePath, lineNumber );
|
return Process( t => t, reason, dbgName, dbgPath, lineNumber );
|
||||||
}
|
}
|
||||||
|
|
||||||
override public T Process( T next, string reason = "",
|
override public T Process( T next, string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
[CallerArgumentExpression("next")]
|
[CallerArgumentExpression("next")]
|
||||||
string expression = default )
|
string dbgExp = default )
|
||||||
{
|
{
|
||||||
return Process( ( old ) => next, reason, memberName, filePath, lineNumber, expression );
|
return Process( ( old ) => next, reason, dbgName, dbgPath, lineNumber, dbgExp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override public T Process( Func<T, T> fn, string reason = "",
|
override public T Process( Func<T, T> fn, string reason = "",
|
||||||
[CallerMemberName] string memberName = "",
|
[CallerMemberName] string dbgName = "",
|
||||||
[CallerFilePath] string filePath = "",
|
[CallerFilePath] string dbgPath = "",
|
||||||
[CallerLineNumber] int lineNumber = 0,
|
[CallerLineNumber] int dbgLine = 0,
|
||||||
[CallerArgumentExpression("fn")]
|
[CallerArgumentExpression("fn")]
|
||||||
string expression = default )
|
string dbgExp = default
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var orig = ( T )this;
|
var orig = ( T )this;
|
||||||
|
|
||||||
@ -216,9 +217,9 @@ public record class Timed<T> : Recorded<T>
|
|||||||
Reason = reason,
|
Reason = reason,
|
||||||
|
|
||||||
//Recorded
|
//Recorded
|
||||||
MemberName = memberName,
|
MemberName = dbgName,
|
||||||
FilePath = filePath,
|
FilePath = dbgPath,
|
||||||
LineNumber = lineNumber,
|
LineNumber = dbgLine,
|
||||||
ZZOld = orig,
|
ZZOld = orig,
|
||||||
|
|
||||||
//Timed
|
//Timed
|
||||||
|
|||||||
@ -9,6 +9,7 @@ using System.Reflection;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
//using System.Threading.Tasks;
|
//using System.Threading.Tasks;
|
||||||
|
|
||||||
static public class log
|
static public class log
|
||||||
@ -99,6 +100,35 @@ static public class log
|
|||||||
|
|
||||||
public delegate void Log_delegate( LogEvent evt );
|
public delegate void Log_delegate( LogEvent evt );
|
||||||
|
|
||||||
|
static ImmutableDictionary<int, string> s_files = ImmutableDictionary<int, string>.Empty;
|
||||||
|
|
||||||
|
static public string whatFile(string path)
|
||||||
|
{
|
||||||
|
var file = "";
|
||||||
|
|
||||||
|
var pathHash = path.GetHashCode();
|
||||||
|
if (s_files.TryGetValue(pathHash, out var autoCat))
|
||||||
|
{
|
||||||
|
file = autoCat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pathPieces = path.Split('\\');
|
||||||
|
|
||||||
|
if (pathPieces.Length < 2)
|
||||||
|
{
|
||||||
|
pathPieces = path.Split('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastDir = pathPieces[pathPieces.Length - 1];
|
||||||
|
|
||||||
|
ImmutableInterlocked.AddOrUpdate(ref s_files, pathHash, lastDir, (key, value) => { return lastDir; });
|
||||||
|
|
||||||
|
file = lastDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user