mirror of
https://github.com/beefytech/Beef.git
synced 2025-07-02 22:36:00 +02:00
Lazy<T>
, LazyTLS<T>
, thread dtors
This commit is contained in:
parent
cf269db0eb
commit
a27ef9beda
17 changed files with 437 additions and 30 deletions
288
BeefLibs/corlib/src/Lazy.bf
Normal file
288
BeefLibs/corlib/src/Lazy.bf
Normal file
|
@ -0,0 +1,288 @@
|
|||
using System.Threading;
|
||||
|
||||
namespace System
|
||||
{
|
||||
enum LazyThreadMode
|
||||
{
|
||||
None,
|
||||
Lock,
|
||||
Lockless
|
||||
}
|
||||
|
||||
class Lazy<T>
|
||||
{
|
||||
protected struct Entry
|
||||
{
|
||||
public SelfOuter mSingleton;
|
||||
public T mValue;
|
||||
}
|
||||
|
||||
protected Monitor mMonitor ~ delete _;
|
||||
protected LazyThreadMode mThreadMode;
|
||||
protected volatile int mInitId;
|
||||
protected T mValue;
|
||||
delegate T() mCreateDlg ~ delete _;
|
||||
delegate void(T value) mReleaseDlg ~ delete _;
|
||||
|
||||
public this()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public this(LazyThreadMode threadMode)
|
||||
{
|
||||
mThreadMode = threadMode;
|
||||
Init();
|
||||
}
|
||||
|
||||
public this(LazyThreadMode threadMode, delegate T() createDlg = null, delegate void(T value) releaseDlg = null)
|
||||
{
|
||||
mThreadMode = threadMode;
|
||||
mCreateDlg = createDlg;
|
||||
mReleaseDlg = releaseDlg;
|
||||
Init();
|
||||
}
|
||||
|
||||
public this(delegate void(T value) releaseDlg) : this()
|
||||
{
|
||||
mReleaseDlg = releaseDlg;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
switch (mThreadMode)
|
||||
{
|
||||
case .None:
|
||||
case .Lock:
|
||||
mMonitor = new Monitor();
|
||||
case .Lockless:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
ReleaseValue(mut mValue);
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue() where T : struct, new
|
||||
{
|
||||
return T();
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue() where T : class
|
||||
{
|
||||
Runtime.FatalError("No create delegate specified and no public default constructor is available");
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue() where T : class, new
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
|
||||
protected virtual T CreateValue()
|
||||
{
|
||||
return DefaultCreateValue();
|
||||
}
|
||||
|
||||
protected void DefaultReleaseValue(mut T val)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void DefaultReleaseValue(mut T val) where T : struct, IDisposable
|
||||
{
|
||||
val.Dispose();
|
||||
}
|
||||
|
||||
protected void DefaultReleaseValue(mut T val) where T : class
|
||||
{
|
||||
delete (Object)val;
|
||||
}
|
||||
|
||||
protected virtual void ReleaseValue(mut T val)
|
||||
{
|
||||
DefaultReleaseValue(mut val);
|
||||
}
|
||||
|
||||
public ref T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mInitId == -1)
|
||||
return ref mValue;
|
||||
|
||||
switch (mThreadMode)
|
||||
{
|
||||
case .None:
|
||||
mValue = CreateValue();
|
||||
case .Lock:
|
||||
using (mMonitor.Enter())
|
||||
{
|
||||
if (mInitId != -1)
|
||||
{
|
||||
mValue = CreateValue();
|
||||
Interlocked.Fence();
|
||||
mInitId = -1;
|
||||
}
|
||||
}
|
||||
case .Lockless:
|
||||
int threadId = Thread.CurrentThreadId;
|
||||
while (true)
|
||||
{
|
||||
int initId = Interlocked.CompareExchange(ref mInitId, 0, threadId);
|
||||
if (initId == -1)
|
||||
break;
|
||||
|
||||
if (initId == 0)
|
||||
{
|
||||
Interlocked.Fence();
|
||||
mValue = CreateValue();
|
||||
Interlocked.Fence();
|
||||
mInitId = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ref mValue;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValueCreated => mInitId != 0;
|
||||
|
||||
public static ref T operator->(Self self) => ref self.[Inline]Value;
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
if (IsValueCreated)
|
||||
strBuffer.AppendF($"Value: {Value}");
|
||||
else
|
||||
strBuffer.AppendF($"No Value");
|
||||
}
|
||||
}
|
||||
|
||||
class LazyTLS<T>
|
||||
{
|
||||
protected struct Entry
|
||||
{
|
||||
public SelfOuter mSingleton;
|
||||
public T mValue;
|
||||
}
|
||||
|
||||
void* mData;
|
||||
delegate T() mCreateDlg ~ delete _;
|
||||
delegate void(T value) mReleaseDlg ~ delete _;
|
||||
|
||||
public this()
|
||||
{
|
||||
InitTLS();
|
||||
}
|
||||
|
||||
public this(delegate T() createDlg = null, delegate void(T value) releaseDlg = null)
|
||||
{
|
||||
mCreateDlg = createDlg;
|
||||
mReleaseDlg = releaseDlg;
|
||||
InitTLS();
|
||||
}
|
||||
|
||||
void InitTLS()
|
||||
{
|
||||
mData = Platform.BfpTLS_Create((ptr) =>
|
||||
{
|
||||
var entry = (Entry*)ptr;
|
||||
if (entry.mSingleton.mReleaseDlg != null)
|
||||
entry.mSingleton.mReleaseDlg(entry.mValue);
|
||||
else
|
||||
entry.mSingleton.ReleaseValue(mut entry.mValue);
|
||||
delete entry;
|
||||
});
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
Platform.BfpTLS_Release((.)mData);
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue() where T : struct, new
|
||||
{
|
||||
return T();
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue() where T : class
|
||||
{
|
||||
Runtime.FatalError("No create delegate specified and no public default constructor is available");
|
||||
}
|
||||
|
||||
protected T DefaultCreateValue() where T : class, new
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
|
||||
protected virtual T CreateValue()
|
||||
{
|
||||
return DefaultCreateValue();
|
||||
}
|
||||
|
||||
protected void DefaultReleaseValue(mut T val)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void DefaultReleaseValue(mut T val) where T : struct, IDisposable
|
||||
{
|
||||
val.Dispose();
|
||||
}
|
||||
|
||||
|
||||
protected void DefaultReleaseValue(mut T val) where T : class
|
||||
{
|
||||
delete (Object)val;
|
||||
}
|
||||
|
||||
protected virtual void ReleaseValue(mut T val)
|
||||
{
|
||||
DefaultReleaseValue(mut val);
|
||||
}
|
||||
|
||||
public ref T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
void* ptr = Platform.BfpTLS_GetValue((.)mData);
|
||||
if (ptr != null)
|
||||
return ref ((Entry*)ptr).mValue;
|
||||
|
||||
Entry* entry = new Entry();
|
||||
entry.mSingleton = this;
|
||||
if (mCreateDlg != null)
|
||||
entry.mValue = mCreateDlg();
|
||||
else
|
||||
entry.mValue = CreateValue();
|
||||
Platform.BfpTLS_SetValue((.)mData, entry);
|
||||
return ref entry.mValue;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValueCreated => Platform.BfpTLS_GetValue((.)mData) != null;
|
||||
|
||||
public static ref T operator->(Self self) => ref self.[Inline]Value;
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
if (IsValueCreated)
|
||||
strBuffer.AppendF($"Value: {Value}");
|
||||
else
|
||||
strBuffer.AppendF($"No Value");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue