Lotsa fun
This commit is contained in:
parent
5a0adfc2b3
commit
da399343e2
@ -298,7 +298,7 @@ public record class Timed<T> : Recorded<T> where T : Timed<T>
|
||||
public override T Process(
|
||||
Func<T, T> fn,
|
||||
string reason = "",
|
||||
[CallerMemberName] string dbgName = "",
|
||||
[CallerMemberName] string dbgMethod = "",
|
||||
[CallerFilePath] string dbgPath = "",
|
||||
[CallerLineNumber] int dbgLine = 0,
|
||||
[CallerArgumentExpression( "fn" )] string dbgExpression = "" )
|
||||
@ -313,7 +313,7 @@ public record class Timed<T> : Recorded<T> where T : Timed<T>
|
||||
{
|
||||
Version = current.Meta.Version + 1,
|
||||
Reason = reason,
|
||||
MemberName = dbgName,
|
||||
MemberName = dbgMethod,
|
||||
FilePath = dbgPath,
|
||||
LineNumber = dbgLine,
|
||||
Expression = dbgExpression,
|
||||
|
||||
49
imm/List.cs
49
imm/List.cs
@ -24,39 +24,44 @@ public record class List<T> : Timed<List<T>>, IImmutableList<T>
|
||||
// Helper to apply changes using the Process method
|
||||
private List<T> Change(
|
||||
Func<ImmutableList<T>, ImmutableList<T>> listChange,
|
||||
[CallerMemberName] string memberName = "",
|
||||
[CallerFilePath] string filePath = "",
|
||||
[CallerLineNumber] int lineNumber = 0,
|
||||
[CallerArgumentExpression("listChange")] string reason = "")
|
||||
[CallerMemberName] string dbgMethod = "",
|
||||
[CallerFilePath] string dbgPath = "",
|
||||
[CallerLineNumber] int dbgLine = -1,
|
||||
[CallerArgumentExpression( "listChange" )] string reason = "" )
|
||||
{
|
||||
var newValues = listChange(Values);
|
||||
return ReferenceEquals(Values, newValues)
|
||||
? this
|
||||
: Process(l => l with { Values = newValues }, reason, memberName, filePath, lineNumber, reason);
|
||||
: Process(l => l with { Values = newValues }, reason, dbgMethod, dbgPath, dbgLine, reason);
|
||||
}
|
||||
|
||||
// --- IImmutableList<T> implementation using the Change helper ---
|
||||
public T this[int index] => Values[index];
|
||||
public int Count => Values.Count;
|
||||
|
||||
public List<T> Add(T value) => Change(v => v.Add(value));
|
||||
public List<T> AddRange(IEnumerable<T> items) => Change(v => v.AddRange(items));
|
||||
public List<T> Clear() => Change(v => v.Clear());
|
||||
// ... Implement all other IImmutableList methods similarly ...
|
||||
#region IImmutableList Implementation
|
||||
public List<T> Insert( int index, T element ) => Change( v => v.Insert( index, element ) );
|
||||
public List<T> InsertRange( int index, IEnumerable<T> items ) => Change( v => v.InsertRange( index, items ) );
|
||||
public List<T> Remove( T value, IEqualityComparer<T>? equalityComparer ) => Change( v => v.Remove( value, equalityComparer ) );
|
||||
public List<T> Remove( T value ) => Remove( value, EqualityComparer<T>.Default );
|
||||
public List<T> RemoveAll( Predicate<T> match ) => Change( v => v.RemoveAll( match ) );
|
||||
public List<T> RemoveAt( int index ) => Change( v => v.RemoveAt( index ) );
|
||||
public List<T> RemoveRange( IEnumerable<T> items, IEqualityComparer<T>? equalityComparer ) => Change( v => v.RemoveRange( items, equalityComparer ) );
|
||||
public List<T> RemoveRange( int index, int count ) => Change( v => v.RemoveRange( index, count ) );
|
||||
public List<T> Replace( T oldValue, T newValue, IEqualityComparer<T>? equalityComparer ) => Change( v => v.Replace( oldValue, newValue, equalityComparer ) );
|
||||
public List<T> SetItem( int index, T value ) => Change( v => v.SetItem( index, value ) );
|
||||
public List<T> Add(T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.Add(value), dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> AddRange(IEnumerable<T> items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.AddRange(items), dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> Clear([CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1) => Change(v => v.Clear(), dbgMethod, dbgPath, dbgLine);
|
||||
#region IImmutableList Implementati, dbgMethod, dbgPath, dbgLineon
|
||||
public List<T> Insert( int index, T element, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Insert( index, element ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> InsertRange( int index, IEnumerable<T> items, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.InsertRange( index, items ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> Remove( T value, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Remove( value, equalityComparer ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> Remove( T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Remove( value, EqualityComparer<T>.Default , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> RemoveAll( Predicate<T> match, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAll( match ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> RemoveAt( int index, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveAt( index ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> RemoveRange( int index, int count, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( index, count ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> RemoveRange( IEnumerable<T> items, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.RemoveRange( items, equalityComparer ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> Replace( T oldValue, T newValue, IEqualityComparer<T>? equalityComparer, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.Replace( oldValue, newValue, equalityComparer ) , dbgMethod, dbgPath, dbgLine);
|
||||
public List<T> SetItem( int index, T value, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => Change( v => v.SetItem( index, value ) , dbgMethod, dbgPath, dbgLine);
|
||||
|
||||
|
||||
|
||||
public int IndexOf( T item, int index, int count, IEqualityComparer<T>? equalityComparer ) => Values.IndexOf( item, index, count, equalityComparer ?? EqualityComparer<T>.Default );
|
||||
public int IndexOf( T item ) => IndexOf( item, 0, Count, EqualityComparer<T>.Default );
|
||||
public int LastIndexOf( T item, int index, int count, IEqualityComparer<T>? equalityComparer ) => Values.LastIndexOf( item, index, count, equalityComparer ?? EqualityComparer<T>.Default );
|
||||
public int LastIndexOf( T item, int index, int count, IEqualityComparer<T>? equalityComparer) => Values.LastIndexOf( item, index, count, equalityComparer ?? EqualityComparer<T>.Default );
|
||||
|
||||
public int IndexOf( T item, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) => IndexOf( item, 0, Count, EqualityComparer<T>.Default);
|
||||
|
||||
|
||||
IImmutableList<T> IImmutableList<T>.Clear() => Clear();
|
||||
IImmutableList<T> IImmutableList<T>.Add( T value ) => Add( value );
|
||||
IImmutableList<T> IImmutableList<T>.AddRange( IEnumerable<T> items ) => AddRange( items );
|
||||
|
||||
@ -204,25 +204,25 @@ static public class log
|
||||
|
||||
static ImmutableDictionary<int, string> s_shortname = ImmutableDictionary<int, string>.Empty;
|
||||
|
||||
public LogEvent( LogType logType, string msg, string path, int line, string member, string cat, string exp, object? obj )
|
||||
public LogEvent( LogType logType, string msg, string dbgPath, int dbgLine, string dbgMethod, string cat, string exp, object? obj )
|
||||
{
|
||||
|
||||
//Cache the automatic category names
|
||||
// R A R E and S L O W and S A F E
|
||||
if( string.IsNullOrEmpty( cat ) )
|
||||
{
|
||||
var pathHash = path.GetHashCode();
|
||||
var pathHash = dbgPath.GetHashCode();
|
||||
if( s_shortname.TryGetValue( pathHash, out var autoCat ) )
|
||||
{
|
||||
cat = autoCat;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pathPieces = path.Split( '\\' );
|
||||
var pathPieces = dbgPath.Split( '\\' );
|
||||
|
||||
if( pathPieces.Length < 2 )
|
||||
{
|
||||
pathPieces = path.Split( '/' );
|
||||
pathPieces = dbgPath.Split( '/' );
|
||||
}
|
||||
|
||||
var lastDir = pathPieces[pathPieces.Length - 2];
|
||||
@ -236,18 +236,18 @@ static public class log
|
||||
Time = DateTime.Now;
|
||||
LogType = logType;
|
||||
Msg = msg;
|
||||
Path = path;
|
||||
Line = line;
|
||||
Member = member;
|
||||
Path = dbgPath;
|
||||
Line = dbgLine;
|
||||
Member = dbgMethod;
|
||||
Cat = cat;
|
||||
Exp = exp;
|
||||
Obj = obj;
|
||||
}
|
||||
}
|
||||
|
||||
static LogEvent CreateLogEvent( LogType logType, string msg, string cat, object? obj, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", string exp = "" )
|
||||
static LogEvent CreateLogEvent( LogType logType, string msg, string cat, object? obj, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", string exp = "" )
|
||||
{
|
||||
var logEvent = new LogEvent( logType, msg, path, line, member, cat, exp, obj );
|
||||
var logEvent = new LogEvent( logType, msg, dbgPath, dbgLine, dbgMethod, cat, exp, obj );
|
||||
|
||||
return logEvent;
|
||||
}
|
||||
@ -324,9 +324,9 @@ static public class log
|
||||
return rel;
|
||||
}
|
||||
|
||||
static public string thisFilePath( [CallerFilePath] string path = "" )
|
||||
static public string thisFilePath( [CallerFilePath] string dbgPath = "" )
|
||||
{
|
||||
return relativePath( path );
|
||||
return relativePath( dbgPath );
|
||||
}
|
||||
#endregion // Util
|
||||
|
||||
@ -342,7 +342,7 @@ static public class log
|
||||
|
||||
/*
|
||||
static public void info( string msg, string cat = "", object? obj = null,
|
||||
[CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
[CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
*/
|
||||
|
||||
static public T var<T>( T val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" )
|
||||
@ -358,42 +358,42 @@ static public class log
|
||||
log.info( $"| Done", "", null, dbgPath, dbgLine, dbgName, dbgExp );
|
||||
}
|
||||
|
||||
static public void fatal( string msg, string cat = "", object? obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
static public void fatal( string msg, string cat = "", object? obj = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
{
|
||||
logBase( msg, LogType.Fatal, path, line, member, cat, dbgExp, obj );
|
||||
logBase( msg, LogType.Fatal, dbgPath, dbgLine, dbgMethod, cat, dbgExp, obj );
|
||||
}
|
||||
|
||||
[StackTraceHidden]
|
||||
static public void error( string msg, string cat = "", object? obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
static public void error( string msg, string cat = "", object? obj = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
{
|
||||
logBase( msg, LogType.Error, path, line, member, cat, dbgExp, obj );
|
||||
logBase( $"{dbgMethod}: {msg}", LogType.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExp, obj );
|
||||
}
|
||||
|
||||
[StackTraceHidden]
|
||||
static public void warn( string msg, string cat = "", object? obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
static public void warn( string msg, string cat = "", object? obj = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
{
|
||||
logBase( msg, LogType.Warn, path, line, member, cat, dbgExp, obj );
|
||||
logBase( msg, LogType.Warn, dbgPath, dbgLine, dbgMethod, cat, dbgExp, obj );
|
||||
}
|
||||
|
||||
static public void high( string msg, string cat = "", object? obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
static public void high( string msg, string cat = "", object? obj = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
{
|
||||
logBase( msg, LogType.High, path, line, member, cat, dbgExp, obj );
|
||||
logBase( msg, LogType.High, dbgPath, dbgLine, dbgMethod, cat, dbgExp, obj );
|
||||
}
|
||||
|
||||
static public void info( string msg, string cat = "", object? obj = null,
|
||||
[CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
[CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
{
|
||||
logBase( msg, LogType.Info, path, line, member, cat, dbgExp, obj );
|
||||
logBase( msg, LogType.Info, dbgPath, dbgLine, dbgMethod, cat, dbgExp, obj );
|
||||
}
|
||||
|
||||
static public void debug( string msg, string cat = "", object? obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
static public void debug( string msg, string cat = "", object? obj = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
{
|
||||
logBase( msg, LogType.Debug, path, line, member, cat, dbgExp, obj );
|
||||
logBase( msg, LogType.Debug, dbgPath, dbgLine, dbgMethod, cat, dbgExp, obj );
|
||||
}
|
||||
|
||||
static public void trace( string msg, string cat = "", object? obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
static public void trace( string msg, string cat = "", object? obj = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
|
||||
{
|
||||
logBase( msg, LogType.Trace, path, line, member, cat, dbgExp, obj );
|
||||
logBase( msg, LogType.Trace, dbgPath, dbgLine, dbgMethod, cat, dbgExp, obj );
|
||||
}
|
||||
|
||||
|
||||
@ -402,13 +402,13 @@ static public class log
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "", string prefix = "", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "", [CallerArgumentExpression( "obj" )] string dbgExpObj = "" )
|
||||
static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "", string prefix = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "obj" )] string dbgExpObj = "" )
|
||||
{
|
||||
var list = refl.GetAllProperties( obj.GetType() );
|
||||
|
||||
lock( s_lock )
|
||||
{
|
||||
var evt = new LogEvent( type, header, path, line, member, cat, dbgExpObj, obj );
|
||||
var evt = new LogEvent( type, header, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj, obj );
|
||||
{
|
||||
// Use Add instead of Enqueue
|
||||
s_events.Add( evt );
|
||||
@ -419,11 +419,11 @@ static public class log
|
||||
{
|
||||
var v = pi.GetValue( obj );
|
||||
|
||||
logBase( $"{prefix}{pi.Name} = {v}", type, path, line, member, dbgExpObj, cat );
|
||||
logBase( $"{prefix}{pi.Name} = {v}", type, dbgPath, dbgLine, dbgMethod, dbgExpObj, cat );
|
||||
}
|
||||
catch( Exception ex )
|
||||
{
|
||||
logBase( $"Exception processing {pi.Name} {ex.Message}", LogType.Error, path, line, member, cat, dbgExpObj, obj );
|
||||
logBase( $"Exception processing {pi.Name} {ex.Message}", LogType.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj, obj );
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,16 +462,16 @@ static public class log
|
||||
}
|
||||
|
||||
|
||||
static public LogEvent logCreateEvent( string msg, LogType type = LogType.Debug, string path = "", int line = -1, string member = "", string cat = "unk", string exp = "", object? obj = null )
|
||||
static public LogEvent logCreateEvent( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", object? obj = null )
|
||||
{
|
||||
LogEvent evt = new LogEvent( type, msg, path, line, member, cat, exp, obj );
|
||||
LogEvent evt = new LogEvent( type, msg, dbgPath, dbgLine, dbgMethod, cat, exp, obj );
|
||||
return evt;
|
||||
}
|
||||
|
||||
[StackTraceHidden]
|
||||
static public void logBase( string msg, LogType type = LogType.Debug, string path = "", int line = -1, string member = "", string cat = "unk", string exp = "", object? obj = null )
|
||||
static public void logBase( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", object? obj = null )
|
||||
{
|
||||
var evt = logCreateEvent( msg, type, path, line, member, cat, exp );
|
||||
var evt = logCreateEvent( msg, type, dbgPath, dbgLine, dbgMethod, cat, exp );
|
||||
|
||||
s_callbacks.TryGetValue( type, out var callback );
|
||||
|
||||
|
||||
365
math/Cent.cs
Normal file
365
math/Cent.cs
Normal file
@ -0,0 +1,365 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
sealed public record Vector3Cm( Cm x, Cm y, Cm z )
|
||||
{
|
||||
public bool Equals( Vector3Cm? other ) => x == other?.x && y == other?.y && z == other?.z;
|
||||
|
||||
public override int GetHashCode() => x.GetHashCode() * 10000019 + z.GetHashCode() * 50000047 + y.GetHashCode();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a fixed-point value in centimeters, stored as an integer.
|
||||
/// Implements INumber<Cm> for full generic math support.
|
||||
/// </summary>
|
||||
sealed public record Cm(int value) : INumber<Cm>
|
||||
{
|
||||
// --- Constants and Identities ---
|
||||
|
||||
/// <summary>
|
||||
/// Represents the multiplicative identity (1.0).
|
||||
/// The underlying value is 100 because 1.0 meter = 100 centimeters.
|
||||
/// </summary>
|
||||
public static Cm One => new Cm(100);
|
||||
public static Cm Zero => new Cm(0);
|
||||
public static int Radix => 10;
|
||||
public static Cm AdditiveIdentity => Zero;
|
||||
public static Cm MultiplicativeIdentity => One;
|
||||
|
||||
|
||||
public float Float => ((float)value) * 0.01f;
|
||||
public double Double => ((double)value) * 0.01;
|
||||
|
||||
// --- Static Conversion Methods ---
|
||||
|
||||
public static Cm From(float v) => new Cm((int)(v * 100.0f + 0.5f));
|
||||
public static Cm From(double v) => new Cm((int)(v * 100.0 + 0.5));
|
||||
|
||||
|
||||
// --- Standard Functions ---
|
||||
|
||||
public static Cm Abs(Cm c) => new Cm(Math.Abs(c.value));
|
||||
public static Cm MaxMagnitude(Cm x, Cm y) => Abs(x) > Abs(y) ? x : y;
|
||||
public static Cm MaxMagnitudeNumber(Cm x, Cm y) => MaxMagnitude(x, y); // Same for this type
|
||||
public static Cm MinMagnitude(Cm x, Cm y) => Abs(x) < Abs(y) ? x : y;
|
||||
public static Cm MinMagnitudeNumber(Cm x, Cm y) => MinMagnitude(x, y); // Same for this type
|
||||
|
||||
// --- Type Property Checks ---
|
||||
|
||||
public static bool IsCanonical(Cm c) => true;
|
||||
public static bool IsComplexNumber(Cm c) => false;
|
||||
public static bool IsEvenInteger(Cm c) => (c.value % 100 == 0) && (c.value / 100 % 2 == 0);
|
||||
public static bool IsFinite(Cm c) => true;
|
||||
public static bool IsImaginaryNumber(Cm c) => false;
|
||||
public static bool IsInfinity(Cm c) => false;
|
||||
public static bool IsInteger(Cm c) => c.value % 100 == 0;
|
||||
public static bool IsNaN(Cm c) => false;
|
||||
public static bool IsNegative(Cm c) => c.value < 0;
|
||||
public static bool IsNegativeInfinity(Cm c) => false;
|
||||
public static bool IsNormal(Cm c) => c.value != 0;
|
||||
public static bool IsOddInteger(Cm c) => (c.value % 100 == 0) && (c.value / 100 % 2 != 0);
|
||||
public static bool IsPositive(Cm c) => c.value > 0;
|
||||
public static bool IsPositiveInfinity(Cm c) => false;
|
||||
public static bool IsRealNumber(Cm c) => true; // It is a real number
|
||||
public static bool IsSubnormal(Cm c) => false;
|
||||
public static bool IsZero(Cm c) => c.value == 0;
|
||||
|
||||
// --- Parsing ---
|
||||
|
||||
public static Cm Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Number, provider);
|
||||
public static Cm Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => Parse(s, NumberStyles.Number, provider);
|
||||
public static Cm Parse(string s, NumberStyles style, IFormatProvider? provider)
|
||||
{
|
||||
if (TryParse(s, style, provider, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
throw new FormatException($"Input string '{s}' was not in a correct format.");
|
||||
}
|
||||
public static Cm Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider)
|
||||
{
|
||||
if (TryParse(s, style, provider, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
throw new FormatException($"Input string was not in a correct format.");
|
||||
}
|
||||
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Cm result) => TryParse(s, NumberStyles.Number, provider, out result);
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, [MaybeNullWhen(false)] out Cm result) => TryParse(s, NumberStyles.Number, provider, out result);
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Cm result)
|
||||
{
|
||||
if (decimal.TryParse(s, style, provider, out decimal decValue))
|
||||
{
|
||||
result = new Cm((int)(decValue * 100m));
|
||||
return true;
|
||||
}
|
||||
result = Cm.Zero;
|
||||
return false;
|
||||
}
|
||||
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Cm result)
|
||||
{
|
||||
if (decimal.TryParse(s, style, provider, out decimal decValue))
|
||||
{
|
||||
result = new Cm((int)(decValue * 100m));
|
||||
return true;
|
||||
}
|
||||
result = Cm.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- Generic Type Conversion ---
|
||||
|
||||
public static bool TryConvertFromChecked<TOther>(TOther value, out Cm result) where TOther : INumberBase<TOther>
|
||||
{
|
||||
// For integer types, scale up. For floating point, convert.
|
||||
if (TOther.IsInteger(value))
|
||||
{
|
||||
try
|
||||
{
|
||||
checked
|
||||
{
|
||||
result = new Cm(int.CreateChecked(value) * 100);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
result = Cm.Zero;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert floating point types
|
||||
if (typeof(TOther) == typeof(double))
|
||||
{
|
||||
double d = double.CreateChecked(value);
|
||||
result = From(d);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(float))
|
||||
{
|
||||
float f = float.CreateChecked(value);
|
||||
result = From(f);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(decimal))
|
||||
{
|
||||
decimal m = decimal.CreateChecked(value);
|
||||
result = new Cm((int)(m * 100m));
|
||||
return true;
|
||||
}
|
||||
|
||||
result = Cm.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryConvertFromSaturating<TOther>(TOther value, out Cm result) where TOther : INumberBase<TOther>
|
||||
{
|
||||
if (TOther.IsInteger(value))
|
||||
{
|
||||
result = new Cm(int.CreateSaturating(value) * 100);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(double))
|
||||
{
|
||||
double d = double.CreateSaturating(value);
|
||||
result = From(d);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(float))
|
||||
{
|
||||
float f = float.CreateSaturating(value);
|
||||
result = From(f);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(decimal))
|
||||
{
|
||||
decimal m = decimal.CreateSaturating(value);
|
||||
result = new Cm((int)(m * 100m));
|
||||
return true;
|
||||
}
|
||||
result = Cm.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryConvertFromTruncating<TOther>(TOther value, out Cm result) where TOther : INumberBase<TOther>
|
||||
{
|
||||
if (TOther.IsInteger(value))
|
||||
{
|
||||
result = new Cm(int.CreateTruncating(value) * 100);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(double))
|
||||
{
|
||||
double d = double.CreateTruncating(value);
|
||||
result = From(d);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(float))
|
||||
{
|
||||
float f = float.CreateTruncating(value);
|
||||
result = From(f);
|
||||
return true;
|
||||
}
|
||||
if (typeof(TOther) == typeof(decimal))
|
||||
{
|
||||
decimal m = decimal.CreateTruncating(value);
|
||||
result = new Cm((int)(m * 100m));
|
||||
return true;
|
||||
}
|
||||
result = Cm.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryConvertToChecked<TOther>(Cm value, out TOther result) where TOther : INumberBase<TOther>
|
||||
{
|
||||
// Convert our value (a count of centimeters) to another type.
|
||||
// This typically involves scaling down by 100.
|
||||
try
|
||||
{
|
||||
checked
|
||||
{
|
||||
if (TOther.IsInteger(TOther.Zero))
|
||||
{
|
||||
result = TOther.CreateChecked(value.value / 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
// For floating points, perform floating point division
|
||||
result = TOther.CreateChecked(value.value) / TOther.CreateChecked(100);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
result = default!;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryConvertToSaturating<TOther>(Cm value, out TOther result) where TOther : INumberBase<TOther>
|
||||
{
|
||||
if (TOther.IsInteger(TOther.Zero))
|
||||
{
|
||||
result = TOther.CreateSaturating(value.value / 100);
|
||||
return true;
|
||||
}
|
||||
result = TOther.CreateSaturating(value.value) / TOther.CreateSaturating(100);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryConvertToTruncating<TOther>(Cm value, out TOther result) where TOther : INumberBase<TOther>
|
||||
{
|
||||
if (TOther.IsInteger(TOther.Zero))
|
||||
{
|
||||
result = TOther.CreateTruncating(value.value / 100);
|
||||
return true;
|
||||
}
|
||||
result = TOther.CreateTruncating(value.value) / TOther.CreateTruncating(100);
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Comparison ---
|
||||
|
||||
public int CompareTo(object? obj)
|
||||
{
|
||||
if (obj is Cm other)
|
||||
{
|
||||
return CompareTo(other);
|
||||
}
|
||||
return obj is null ? 1 : throw new ArgumentException("Object must be of type Cm.", nameof(obj));
|
||||
}
|
||||
|
||||
public int CompareTo(Cm? other) => value.CompareTo(other?.value);
|
||||
|
||||
public bool Equals(Cm? other) => value == other?.value;
|
||||
|
||||
public override int GetHashCode() => value.GetHashCode();
|
||||
|
||||
// --- Formatting ---
|
||||
|
||||
public override string ToString() => (value / 100.0).ToString("F2", CultureInfo.InvariantCulture);
|
||||
|
||||
public string ToString(string? format, IFormatProvider? formatProvider)
|
||||
{
|
||||
// Format as a floating point number
|
||||
return (value / 100.0).ToString(format, formatProvider);
|
||||
}
|
||||
|
||||
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
|
||||
{
|
||||
return (value / 100.0).TryFormat(destination, out charsWritten, format, provider);
|
||||
}
|
||||
|
||||
// --- Operators ---
|
||||
|
||||
public static Cm operator +(Cm c) => c;
|
||||
public static Cm operator +(Cm left, Cm right) => new Cm(left.value + right.value);
|
||||
public static Cm operator -(Cm c) => new Cm(-c.value);
|
||||
public static Cm operator -(Cm left, Cm right) => new Cm(left.value - right.value);
|
||||
public static Cm operator ++(Cm c) => new Cm(c.value + 1);
|
||||
public static Cm operator --(Cm c) => new Cm(c.value - 1);
|
||||
|
||||
// For fixed-point, multiplication/division require scaling
|
||||
public static Cm operator *(Cm left, Cm right)
|
||||
{
|
||||
// (a/100) * (b/100) = (a*b)/10000. To get back to our format, multiply by 100.
|
||||
// So, (a*b)/100. Use long to prevent intermediate overflow.
|
||||
return new Cm((int)(((long)left.value * right.value) / 100));
|
||||
}
|
||||
|
||||
public static Cm operator /(Cm left, Cm right)
|
||||
{
|
||||
// (a/100) / (b/100) = a/b. To get back to our format, multiply by 100.
|
||||
// So, (a*100)/b. Use long to prevent intermediate overflow.
|
||||
return new Cm((int)(((long)left.value * 100) / right.value));
|
||||
}
|
||||
|
||||
public static Cm operator %(Cm left, Cm right) => new Cm(left.value % right.value);
|
||||
|
||||
// --- Comparison Operators ---
|
||||
public static bool operator <(Cm left, Cm right) => left.value < right.value;
|
||||
public static bool operator >(Cm left, Cm right) => left.value > right.value;
|
||||
public static bool operator <=(Cm left, Cm right) => left.value <= right.value;
|
||||
public static bool operator >=(Cm left, Cm right) => left.value >= right.value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for easy conversion to the Cm type.
|
||||
/// </summary>
|
||||
public static class CentEx
|
||||
{
|
||||
|
||||
// --- Static Conversion Methods ---
|
||||
|
||||
public static Cm From(float v) => new Cm((int)(v * 100.0f + 0.5f));
|
||||
public static Cm From(double v) => new Cm((int)(v * 100.0 + 0.5));
|
||||
|
||||
|
||||
//public static Cm Cm(this float r) => CentEx.From(r);
|
||||
//public static Cm Cm(this double r) => CentEx.From(r);
|
||||
|
||||
|
||||
extension(float r)
|
||||
{
|
||||
public Cm Cm => CentEx.From( r );
|
||||
}
|
||||
|
||||
extension(double r)
|
||||
{
|
||||
public Cm Cm => CentEx.From( r );
|
||||
}
|
||||
|
||||
}
|
||||
@ -651,12 +651,25 @@ public class ObjectHandler : ITypeHandler
|
||||
// If POD-Attribute, write attribute
|
||||
if( memberMeta.IsPodAttribute )
|
||||
{
|
||||
writer.WriteAttributeString( memberMeta.XmlName, value.ToString() );
|
||||
try
|
||||
{
|
||||
writer.WriteAttributeString( memberMeta.XmlName, value.ToString() );
|
||||
}
|
||||
catch( Exception ex )
|
||||
{
|
||||
log.error( $"Writing Att {memberMeta.XmlName} = [{value}]" );
|
||||
}
|
||||
}
|
||||
else // Else, write element
|
||||
{
|
||||
xml.WriteNode( writer, value, memberMeta.XmlName, memberMeta.Type, false );
|
||||
}
|
||||
try
|
||||
{
|
||||
xml.WriteNode( writer, value, memberMeta.XmlName, memberMeta.Type, false );
|
||||
}
|
||||
catch( Exception ex )
|
||||
{
|
||||
log.error( $"Writing Node {memberMeta.XmlName} = [{value}]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
util/Guid.cs
23
util/Guid.cs
@ -3,10 +3,15 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace lib;
|
||||
//namespace lib;
|
||||
|
||||
public static class Guid
|
||||
public static class GuidExt
|
||||
{
|
||||
extension(Guid g)
|
||||
{
|
||||
public string Log => $"{g.LastByte():X}";
|
||||
}
|
||||
|
||||
public static System.Guid GuidFromLongs( long a, long b )
|
||||
{
|
||||
byte[] guidData = new byte[16];
|
||||
@ -59,6 +64,14 @@ public static class Guid
|
||||
return (a, b, c, d);
|
||||
}
|
||||
|
||||
|
||||
public static uint LastUInt( this System.Guid guid )
|
||||
{
|
||||
var bytes = guid.ToByteArray();
|
||||
var d = BitConverter.ToUInt32( bytes, 12 );
|
||||
return d;
|
||||
}
|
||||
|
||||
public static System.Guid GuidFromUInts( uint a, uint b, uint c, uint d )
|
||||
{
|
||||
byte[] guidData = new byte[16];
|
||||
@ -78,4 +91,10 @@ public static class Guid
|
||||
var d = BitConverter.ToUInt32( bytes, 12 );
|
||||
return (a, b, c, d);
|
||||
}
|
||||
|
||||
public static byte LastByte( this System.Guid guid )
|
||||
{
|
||||
var bytes = guid.ToByteArray();
|
||||
return bytes[7];
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user