sharplib/res/Resource.cs
Marc Hernandez 738fd19cf3 Title: Commented out deferredLoader related code in Resource.cs
x) The changes involve commenting out the `deferredLoader` related code in the `Resource.cs` file.
x) Specifically, the instantiation of `ImmDefLoad s_deferredLoad`, the creation and start of a new thread for `m_deferredLoader`, and the entire method `deferredLoader()` have been commented out.
x) This might be due to debugging or refactoring efforts where these parts are temporarily disabled. Further context is needed to understand why these specific lines were commented out.
2024-08-02 20:34:26 -07:00

445 lines
9.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Diagnostics;
using System.Reflection;
using System.Collections.Immutable;
using System.Threading;
using System.IO;
using Microsoft.CodeAnalysis;
using System.Runtime.CompilerServices;
#nullable enable
namespace res;
using ImmDefLoad = ImmutableQueue<(string name, Ref)>;
public interface Res_old
{
}
[DebuggerDisplay("Path = {path}")]
abstract public class Ref : lib.I_Serialize
{
static public bool s_verboseLogging = false;
public string Filename =>path;
public Ref( string filename = "{empty_filename}",
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
)
{
path = filename;
if( s_verboseLogging ) log.info( $"Ref: {GetType().Name} {path}" );
_reason = reason;
_dbgName = dbgName;
_dbgPath = dbgPath;
_dbgLine = dbgLine;
}
abstract public object lookup(
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
);
virtual public void OnChange()
{
}
virtual internal void load()
{
}
private string path = "{set_from_inline_cons}";
protected string _reason = "";
protected string _dbgName = "";
protected string _dbgPath = "";
protected int _dbgLine = 0;
protected string _dbgExp = "";
}
[Serializable]
[DebuggerDisplay("Path = {path} / Res = {res}")]
public class Ref<T> : Ref where T : class, new()
{
public T res => m_res != null ? m_res : lookup();
override public T lookup(
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
)
{
m_res = Mgr.load<T>( Filename, $"Ref lookup", dbgName, dbgPath, dbgLine );
if( s_verboseLogging ) log.info( $"Ref.lookup {GetType().Name} {GetType().GenericTypeArguments[0]} path {Filename}" );
return m_res;
}
//For serialization
/*
public Ref()
:
base( "{set_from_ref<>_default_cons}" )
{
if( s_verboseLogging ) log.info( $"Ref {GetType().Name} {GetType().GenericTypeArguments[0]} path {Filename}" );
}
*/
public Ref( string filename = "",
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
)
:
base( !string.IsNullOrWhiteSpace(filename) ? filename : $"{{{dbgName}_{log.whatFile(dbgPath)}}}" , reason, dbgName, dbgPath, dbgLine )
{
if( s_verboseLogging ) log.info( $"Ref {GetType().Name} {GetType().GenericTypeArguments[0]} path {Filename}" );
m_res = default;
}
override internal void load()
{
m_res = Mgr.load<T>( Filename, _reason, _dbgName, _dbgPath, _dbgLine );
if( s_verboseLogging ) log.info( $"Ref.load {GetType().Name} {GetType().GenericTypeArguments[0]} path {Filename}" );
}
public object OnDeserialize( object enclosing )
{
return enclosing;
}
static public Ref<T> createAsset( T v, string path,
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
)
{
if( File.Exists( path ) )
{
log.warn( $"For {typeof(T).Name}, saving asset to {path}, but it already exists" );
var newPath = $"{path}_{DateTime.Now.ToShortDateString()}_{DateTime.Now.ToShortTimeString()}";
System.IO.File.Move(path, newPath );
log.warn( $"For {typeof(T).Name}, renamed to {newPath}" );
}
var createReason = $"Type {v.GetType().Name}";
if( v is imm.Imm imm )
{
createReason = $"{imm?.Meta}";
}
var newRef = new Ref<T>( path, $"createAsset {createReason} bcs {reason}", dbgName, dbgPath, dbgLine );
return newRef;
}
[NonSerialized]
protected T? m_res;
}
public class Resource
{
static public Mgr mgr = new();
}
public delegate T Load<out T>( string filename );
abstract class LoadHolder
{
public abstract object load();
}
class LoadHolder<T> : LoadHolder
{
public LoadHolder( Load<T> fnLoad )
{
_fnLoad = fnLoad;
}
public Load<T> _fnLoad;
public override object load()
{
return load();
}
}
public record class ResourceHolder<T>( WeakReference<T> weak, string Name, DateTime captured ) : imm.Recorded<ResourceHolder<T>>
where T : class
{
}
//generic classes make a new static per generic type
class ResCache<T> where T : class, new()
{
public static T s_default = new();
public static ImmutableDictionary<string, ResourceHolder<T>> s_cache = ImmutableDictionary<string, ResourceHolder<T>>.Empty;
}
public class Mgr
{
static public void startup()
{
}
static public void register<T>( Load<T> loader )
{
Debug.Assert( !Resource.mgr.m_loaders.ContainsKey( typeof( T ) ) );
var lh = new LoadHolder<T>( loader );
ImmutableInterlocked.TryAdd( ref Resource.mgr.m_loaders, typeof( T ), lh );
}
//Register all subclasses of a particular type
//???? Should we just always do this?
static public void registerSub<T>()
{
registerSub( typeof(T) );
}
static public void registerSub( Type baseType )
{
log.info( $"Registering loader for {baseType.Name}" );
Type[] typeParams = new Type[1];
foreach( var mi in baseType.GetMethods() )
{
if( mi.Name == "res_load" && mi.IsGenericMethod )
{
foreach( var ass in AppDomain.CurrentDomain.GetAssemblies() )
{
foreach( var t in ass.GetTypes() )
{
if( !baseType.IsAssignableFrom( t ) )
continue;
log.debug( $"Making a loader for {t.Name}" );
typeParams[0] = t;
var mi_ng = mi.MakeGenericMethod( typeParams );
var loadGenType = typeof( Load<> );
var loadType = loadGenType.MakeGenericType( t );
var loader = Delegate.CreateDelegate( loadType, mi_ng );
var lhGenType = typeof( LoadHolder<> );
var lhType = lhGenType.MakeGenericType( t );
var lh = Activator.CreateInstance( lhType, loader ) as LoadHolder;
ImmutableInterlocked.TryAdd( ref Resource.mgr.m_loaders!, t, lh );
}
}
return;
}
}
}
static public Ref<T> lookup<T>( string filename,
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
) where T : class, new()
{
return new Ref<T>( filename, reason, dbgName, dbgPath, dbgLine );
}
/*
static public Ref lookup( string filename, Type t,
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
)
{
return new Ref( filename, reason, dbgName, dbgPath, dbgLine );
}
// @@@ TODO Pass information through here
static public T? load<T>( string filename ) where T : class
{
if( ResCache<T>.s_cache.TryGetValue( filename, out var holder ) )
{
if( holder.weak.TryGetTarget( out var v ) )
{
return v;
}
log.info( $"{filename} was in cache, but its been dropped, reloading." );
}
log.warn( $"Block Loading {filename}." );
var newV = actualLoad<T>( filename );
return newV;
}
*/
static public T load<T>( string filename,
string reason = "",
[CallerMemberName] string dbgName = "",
[CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0
) where T : class, new()
{
if( ResCache<T>.s_cache.TryGetValue( filename, out var holder ) )
{
if( holder.weak.TryGetTarget( out var v ) )
{
return v;
}
log.info( $"{filename} was in cache, but its been dropped, reloading." );
}
log.warn( $"Block Loading {filename}." );
var newV = actualLoad<T>( filename );
if( newV is imm.Imm imm )
{
newV = (T)imm.Record( $"Loading because {reason}", dbgName, dbgPath, dbgLine );
}
return newV;
}
static public T actualLoad<T>( string filename ) where T : class, new()
{
lock(s_loadingLock)
{
if( s_loading.TryGetValue( filename, out var evt ) )
{
if( ResCache<T>.s_cache.TryGetValue( filename, out var holder ) )
{
if( holder.weak.TryGetTarget( out var v ) )
{
log.trace( $"{typeof(T).Name} loading {filename}" );
return v;
}
log.error( $"{filename} was in cache, but its been dropped, reloading." );
}
}
{
if( Resource.mgr.m_loaders.TryGetValue( typeof( T ), out var loaderGen ) )
{
var loader = loaderGen as LoadHolder<T>;
var v = loader!._fnLoad( filename );
var weak = new WeakReference<T>( v );
var holder = new ResourceHolder<T>( weak, $"", DateTime.Now ).Record();
log.info( $"To {typeof(T).Name} add {filename}" );
var alreadyAdded = !ImmutableInterlocked.TryAdd( ref ResCache<T>.s_cache, filename, holder );
if( alreadyAdded )
{
log.error( $"Key {filename} already existed, though it shouldnt." );
}
return v;
}
else
{
log.error( $"Loader could not be found for type {typeof( T )}" );
return ResCache<T>.s_default;
}
}
}
return actualLoad<T>( filename );
}
static object s_loadingLock = new object();
static ImmutableDictionary<string, AutoResetEvent> s_loading = ImmutableDictionary<string, AutoResetEvent>.Empty;
//static ImmDefLoad s_deferredLoad = ImmDefLoad.Empty;
public Mgr()
{
log.info( $"Creating Res.Mgr" );
/*
var ts = new ThreadStart( deferredLoader );
m_deferredLoader = new Thread( ts );
*/
LogGC.RegisterObjectId( s_loadingLock );
//m_deferredLoader.Start();
}
/*
void deferredLoader()
{
while( true )
{
Thread.Sleep( 1 );
if( ImmutableInterlocked.TryDequeue( ref s_deferredLoad, out var v ) )
{
v.Item2.load();
}
}
}
//*/
ImmutableDictionary<Type, LoadHolder> m_loaders = ImmutableDictionary<Type, LoadHolder>.Empty;
//Thread m_deferredLoader;
}