mirror of
https://github.com/beefytech/Beef.git
synced 2025-07-15 12:43:52 +02:00
Merge branch 'master' into BookmarkPanel
This commit is contained in:
commit
6884b9fc21
267 changed files with 26197 additions and 17792 deletions
|
@ -792,9 +792,23 @@ namespace Beefy
|
|||
BFApp_SetCursor((int32)cursor);
|
||||
}
|
||||
|
||||
public virtual void* GetClipboardData(String format, out int32 size)
|
||||
public virtual void* GetClipboardData(String format, out int32 size, int waitTime = 500)
|
||||
{
|
||||
return BFApp_GetClipboardData(format, out size);
|
||||
Stopwatch sw = null;
|
||||
repeat
|
||||
{
|
||||
if (sw != null)
|
||||
Thread.Sleep(1);
|
||||
void* result = BFApp_GetClipboardData(format, out size);
|
||||
if (size != -1)
|
||||
return result;
|
||||
if (waitTime == 0)
|
||||
return null;
|
||||
if (sw == null)
|
||||
sw = scope:: .()..Start();
|
||||
}
|
||||
while (waitTime < sw.ElapsedMilliseconds);
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void ReleaseClipboardData(void* ptr)
|
||||
|
@ -802,9 +816,9 @@ namespace Beefy
|
|||
BFApp_ReleaseClipboardData(ptr);
|
||||
}
|
||||
|
||||
public virtual bool GetClipboardText(String outStr)
|
||||
public virtual bool GetClipboardText(String outStr, int waitTime = 500)
|
||||
{
|
||||
return GetClipboardTextData("text", outStr);
|
||||
return GetClipboardTextData("text", outStr, waitTime);
|
||||
}
|
||||
|
||||
public virtual bool GetClipboardText(String outStr, String extra)
|
||||
|
@ -813,10 +827,10 @@ namespace Beefy
|
|||
return GetClipboardTextData("text", outStr);
|
||||
}
|
||||
|
||||
public bool GetClipboardTextData(String format, String outStr)
|
||||
public bool GetClipboardTextData(String format, String outStr, int waitTime = 500)
|
||||
{
|
||||
int32 aSize;
|
||||
void* clipboardData = GetClipboardData(format, out aSize);
|
||||
void* clipboardData = GetClipboardData(format, out aSize, waitTime);
|
||||
if (clipboardData == null)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace Beefy
|
|||
if (autoRetry)
|
||||
{
|
||||
if (fileOpenErr == .SharingViolation)
|
||||
retry = true;
|
||||
retry = i != 99;
|
||||
}
|
||||
if (!retry)
|
||||
return .Err(.OpenError(fileOpenErr));
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace Beefy.theme.dark
|
|||
|
||||
}
|
||||
|
||||
public virtual void MouseDown(float x, float y, int btn, int btnCount)
|
||||
public virtual void MouseDown(Rect rect, float x, float y, int btn, int btnCount)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ namespace Beefy.theme.dark
|
|||
public bool mScrollToStartOnLostFocus;
|
||||
public bool mHiliteCurrentLine;
|
||||
public Dictionary<int32, Embed> mEmbeds = new .() ~ DeleteDictionaryAndValues!(_);
|
||||
public Embed mEmbedSelected;
|
||||
public Range? mLineRange;
|
||||
|
||||
protected static uint32[] sDefaultColors = new uint32[] ( Color.White ) ~ delete _;
|
||||
|
@ -457,6 +458,12 @@ namespace Beefy.theme.dark
|
|||
LineStartsChanged();
|
||||
}
|
||||
|
||||
public override void ClearText()
|
||||
{
|
||||
mLineRange = null;
|
||||
base.ClearText();
|
||||
}
|
||||
|
||||
public virtual float DrawText(Graphics g, String str, float x, float y, uint16 typeIdAndFlags)
|
||||
{
|
||||
using (g.PushColor(mTextColors[typeIdAndFlags & 0xFF]))
|
||||
|
|
|
@ -2781,6 +2781,11 @@ namespace MiniZ
|
|||
array_ptr.m_element_size = element_size;
|
||||
}
|
||||
|
||||
static mixin ZIP_ARRAY_ELEMENT_PTR<T>(var array_ptr, int index)
|
||||
{
|
||||
&((T*)(array_ptr.m_p))[index]
|
||||
}
|
||||
|
||||
static mixin ZIP_ARRAY_ELEMENT<T>(var array_ptr, int index)
|
||||
{
|
||||
((T*)(array_ptr.m_p))[index]
|
||||
|
@ -2929,9 +2934,9 @@ namespace MiniZ
|
|||
|
||||
static bool zip_reader_filename_less(ZipArray* pCentral_dir_array, ZipArray* pCentral_dir_offsets, uint32 l_index, uint32 r_index)
|
||||
{
|
||||
uint8* pL = &ZIP_ARRAY_ELEMENT!<uint8>(pCentral_dir_array, ZIP_ARRAY_ELEMENT!<uint32>(pCentral_dir_offsets, l_index));
|
||||
uint8* pL = ZIP_ARRAY_ELEMENT_PTR!<uint8>(pCentral_dir_array, ZIP_ARRAY_ELEMENT!<uint32>(pCentral_dir_offsets, l_index));
|
||||
uint8* pE;
|
||||
uint8* pR = &ZIP_ARRAY_ELEMENT!<uint8>(pCentral_dir_array, ZIP_ARRAY_ELEMENT!<uint32>(pCentral_dir_offsets, r_index));
|
||||
uint8* pR = ZIP_ARRAY_ELEMENT_PTR!<uint8>(pCentral_dir_array, ZIP_ARRAY_ELEMENT!<uint32>(pCentral_dir_offsets, r_index));
|
||||
uint32 l_len = ReadLE16!(pL + ZIP_CDH_FILENAME_LEN_OFS), r_len = ReadLE16!(pR + ZIP_CDH_FILENAME_LEN_OFS);
|
||||
char8 l = 0, r = 0;
|
||||
pL += ZIP_CENTRAL_DIR_HEADER_SIZE; pR += ZIP_CENTRAL_DIR_HEADER_SIZE;
|
||||
|
@ -2951,7 +2956,7 @@ namespace MiniZ
|
|||
ZipInternalState* pState = pZip.m_pState;
|
||||
ZipArray* pCentral_dir_offsets = &pState.m_central_dir_offsets;
|
||||
ZipArray* pCentral_dir = &pState.m_central_dir;
|
||||
uint32* pIndices = &ZIP_ARRAY_ELEMENT!<uint32>(&pState.m_sorted_central_dir_offsets, 0);
|
||||
uint32* pIndices = ZIP_ARRAY_ELEMENT_PTR!<uint32>(&pState.m_sorted_central_dir_offsets, 0);
|
||||
int size = (int)pZip.m_total_files;
|
||||
int start = (size - 2) >> 1, end;
|
||||
while (start >= 0)
|
||||
|
@ -3063,9 +3068,9 @@ namespace MiniZ
|
|||
int32 total_header_size, comp_size, decomp_size, disk_index;
|
||||
if ((n < ZIP_CENTRAL_DIR_HEADER_SIZE) || (ReadLE32!(p) != ZIP_CENTRAL_DIR_HEADER_SIG))
|
||||
return false;
|
||||
ZIP_ARRAY_ELEMENT!<uint32>(&pZip.m_pState.m_central_dir_offsets, i) = (uint32)(p - (uint8*)pZip.m_pState.m_central_dir.m_p);
|
||||
*ZIP_ARRAY_ELEMENT_PTR!<uint32>(&pZip.m_pState.m_central_dir_offsets, i) = (uint32)(p - (uint8*)pZip.m_pState.m_central_dir.m_p);
|
||||
if (sort_central_dir)
|
||||
ZIP_ARRAY_ELEMENT!<uint32>(&pZip.m_pState.m_sorted_central_dir_offsets, i) = (uint32)i;
|
||||
*ZIP_ARRAY_ELEMENT_PTR!<uint32>(&pZip.m_pState.m_sorted_central_dir_offsets, i) = (uint32)i;
|
||||
comp_size = (int32)ReadLE32!(p + ZIP_CDH_COMPRESSED_SIZE_OFS);
|
||||
decomp_size = (int32)ReadLE32!(p + ZIP_CDH_DECOMPRESSED_SIZE_OFS);
|
||||
if (((ReadLE32!(p + ZIP_CDH_METHOD_OFS) == 0) && (decomp_size != comp_size)) || ((decomp_size != 0) && (comp_size == 0)) || (decomp_size == -1) || (comp_size == -1))
|
||||
|
@ -3210,7 +3215,7 @@ namespace MiniZ
|
|||
{
|
||||
if ((pZip == null) || (pZip.m_pState == null) || (file_index >= pZip.m_total_files) || (pZip.m_zip_mode != .Reading))
|
||||
return null;
|
||||
return &ZIP_ARRAY_ELEMENT!<uint8>(&pZip.m_pState.m_central_dir, ZIP_ARRAY_ELEMENT!<uint32>(&pZip.m_pState.m_central_dir_offsets, file_index));
|
||||
return ZIP_ARRAY_ELEMENT_PTR!<uint8>(&pZip.m_pState.m_central_dir, ZIP_ARRAY_ELEMENT!<uint32>(&pZip.m_pState.m_central_dir_offsets, file_index));
|
||||
}
|
||||
|
||||
static bool zip_reader_is_file_encrypted(ZipArchive* pZip, int32 file_index)
|
||||
|
@ -3313,7 +3318,7 @@ namespace MiniZ
|
|||
{
|
||||
char8* pR = pR_in;
|
||||
|
||||
uint8* pL = &ZIP_ARRAY_ELEMENT!<uint8>(pCentral_dir_array, ZIP_ARRAY_ELEMENT!<uint32>(pCentral_dir_offsets, l_index));
|
||||
uint8* pL = ZIP_ARRAY_ELEMENT_PTR!<uint8>(pCentral_dir_array, ZIP_ARRAY_ELEMENT!<uint32>(pCentral_dir_offsets, l_index));
|
||||
uint8* pE;
|
||||
int32 l_len = ReadLE16!(pL + ZIP_CDH_FILENAME_LEN_OFS);
|
||||
char8 l = 0, r = 0;
|
||||
|
@ -3334,7 +3339,7 @@ namespace MiniZ
|
|||
ZipInternalState* pState = pZip.m_pState;
|
||||
ZipArray* pCentral_dir_offsets = &pState.m_central_dir_offsets;
|
||||
ZipArray* pCentral_dir = &pState.m_central_dir;
|
||||
uint32* pIndices = &ZIP_ARRAY_ELEMENT!<uint32>(&pState.m_sorted_central_dir_offsets, 0);
|
||||
uint32* pIndices = ZIP_ARRAY_ELEMENT_PTR!<uint32>(&pState.m_sorted_central_dir_offsets, 0);
|
||||
int32 size = pZip.m_total_files;
|
||||
int32 filename_len = (int32)Internal.CStrLen(pFilename);
|
||||
int32 l = 0, h = size - 1;
|
||||
|
@ -3363,7 +3368,7 @@ namespace MiniZ
|
|||
comment_len = (pComment != null) ? Internal.CStrLen(pComment) : 0; if (comment_len > 0xFFFF) return -1;
|
||||
for (file_index = 0; file_index < pZip.m_total_files; file_index++)
|
||||
{
|
||||
uint8* pHeader = &ZIP_ARRAY_ELEMENT!<uint8>(&pZip.m_pState.m_central_dir, ZIP_ARRAY_ELEMENT!<uint32>(&pZip.m_pState.m_central_dir_offsets, file_index));
|
||||
uint8* pHeader = ZIP_ARRAY_ELEMENT_PTR!<uint8>(&pZip.m_pState.m_central_dir, ZIP_ARRAY_ELEMENT!<uint32>(&pZip.m_pState.m_central_dir_offsets, file_index));
|
||||
int32 filename_len = ReadLE16!(pHeader + ZIP_CDH_FILENAME_LEN_OFS);
|
||||
char8* pFilename = (char8*)pHeader + ZIP_CENTRAL_DIR_HEADER_SIZE;
|
||||
if (filename_len < name_len)
|
||||
|
|
|
@ -5,8 +5,13 @@ namespace System
|
|||
{
|
||||
interface IRawAllocator
|
||||
{
|
||||
void* Alloc(int size, int align);
|
||||
void Free(void* ptr);
|
||||
void* Alloc(int size, int align) mut;
|
||||
void Free(void* ptr) mut;
|
||||
}
|
||||
|
||||
interface ITypedAllocator : IRawAllocator
|
||||
{
|
||||
void* AllocTyped(Type type, int size, int align) mut;
|
||||
}
|
||||
|
||||
struct StdAllocator : IRawAllocator
|
||||
|
@ -22,6 +27,76 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
class SingleAllocator : ITypedAllocator
|
||||
{
|
||||
void* mPtr;
|
||||
int mSize;
|
||||
Type mType;
|
||||
|
||||
[AllowAppend]
|
||||
public this(int size)
|
||||
{
|
||||
void* ptr = append uint8[size]*(?);
|
||||
mPtr = ptr;
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
if ((mType != null) && (mType.IsObject))
|
||||
{
|
||||
Object obj = Internal.UnsafeCastToObject(mPtr);
|
||||
delete:null obj;
|
||||
}
|
||||
|
||||
if (mSize < 0)
|
||||
delete mPtr;
|
||||
}
|
||||
|
||||
protected virtual void* AllocLarge(int size, int align)
|
||||
{
|
||||
return new uint8[size]*;
|
||||
}
|
||||
|
||||
protected virtual void FreeLarge(void* ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
public void* Alloc(int size, int align)
|
||||
{
|
||||
return AllocTyped(typeof(void), size, align);
|
||||
}
|
||||
|
||||
public void Free(void* ptr)
|
||||
{
|
||||
Runtime.Assert(ptr == mPtr);
|
||||
mType = typeof(void);
|
||||
}
|
||||
|
||||
[Optimize]
|
||||
public void* AllocTyped(Type type, int size, int align)
|
||||
{
|
||||
Runtime.Assert(mType == null, "SingleAllocator has been used for multiple allocations");
|
||||
|
||||
mType = type;
|
||||
do
|
||||
{
|
||||
if (size > size)
|
||||
break;
|
||||
void* usePtr = (void*)(int)Math.Align((int)mPtr, align);
|
||||
if ((uint8*)usePtr + size > (uint8*)mPtr + mSize)
|
||||
break;
|
||||
mPtr = usePtr;
|
||||
mSize = 0;
|
||||
return mPtr;
|
||||
}
|
||||
mSize = -1;
|
||||
mPtr = AllocLarge(size, align);
|
||||
return mPtr;
|
||||
}
|
||||
}
|
||||
|
||||
struct AllocWrapper<T> where T : new, delete
|
||||
{
|
||||
alloctype(T) mVal;
|
||||
|
|
|
@ -425,10 +425,18 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Field | .StaticField | .Method | .Property /*2*/)]
|
||||
[AttributeUsage(.Field | .StaticField | .Method | .Property | .Types)]
|
||||
public struct NoShowAttribute : Attribute
|
||||
{
|
||||
public this()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public this(bool allowDirect)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Parameter)]
|
||||
|
|
|
@ -71,6 +71,12 @@ namespace System.Collections
|
|||
Add(item);
|
||||
}
|
||||
|
||||
[AllowAppend]
|
||||
public this(Span<T> span) : this(span.Length)
|
||||
{
|
||||
AddRange(span);
|
||||
}
|
||||
|
||||
[AllowAppend]
|
||||
public this(int capacity)
|
||||
{
|
||||
|
|
626
BeefLibs/corlib/src/Collections/SplitList.bf
Normal file
626
BeefLibs/corlib/src/Collections/SplitList.bf
Normal file
|
@ -0,0 +1,626 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Collections
|
||||
{
|
||||
class SplitList<T> : IEnumerable<Entry>, IList, ICollection<T> where T : struct
|
||||
{
|
||||
private const int_cosize cDefaultCapacity = 4;
|
||||
|
||||
private void* mItems;
|
||||
private int_cosize mSize;
|
||||
private int_cosize mAllocSize;
|
||||
#if VERSION_LIST
|
||||
private int32 mVersion;
|
||||
const String cVersionError = "List changed during enumeration";
|
||||
#endif
|
||||
|
||||
[Inline] public int AllocSize => mAllocSize;
|
||||
|
||||
static void GetFields(List<FieldInfo> fieldList)
|
||||
{
|
||||
if (typeof(T).IsUnion)
|
||||
return;
|
||||
for (var field in typeof(T).GetFields())
|
||||
{
|
||||
if (field.IsStatic)
|
||||
continue;
|
||||
fieldList.Add(field);
|
||||
}
|
||||
}
|
||||
|
||||
[Comptime, OnCompile(.TypeInit)]
|
||||
static void Init()
|
||||
{
|
||||
var fields = GetFields(.. scope .());
|
||||
String code = scope $"""
|
||||
int_cosize[{Math.Max(0, fields.Count - 1)}] mOffsets;
|
||||
""";
|
||||
Compiler.EmitTypeBody(typeof(Self), code);
|
||||
|
||||
if (typeof(T).IsUnion)
|
||||
Runtime.FatalError("Cannot use SplitList on a union");
|
||||
}
|
||||
|
||||
public struct Data
|
||||
{
|
||||
SelfOuter mList;
|
||||
|
||||
public this(SelfOuter list)
|
||||
{
|
||||
mList = list;
|
||||
}
|
||||
|
||||
[Comptime, OnCompile(.TypeInit)]
|
||||
static void Init()
|
||||
{
|
||||
var fields = GetFields(.. scope .());
|
||||
String code = scope .();
|
||||
for (var field in fields)
|
||||
{
|
||||
code.AppendF($"[Inline] public Span<{field.FieldType}> {field.Name} => .((.)((uint8*)mList.mItems");
|
||||
if (@field.Index > 0)
|
||||
code.AppendF($" + mList.mOffsets[{@field.Index - 1}]");
|
||||
code.AppendF($"), mList.mSize);\n");
|
||||
}
|
||||
Compiler.EmitTypeBody(typeof(Self), code);
|
||||
}
|
||||
}
|
||||
|
||||
[Comptime]
|
||||
static void Emit_Get(String prefix, String idx, String item)
|
||||
{
|
||||
var fields = GetFields(.. scope .());
|
||||
String code = scope .();
|
||||
for (var field in fields)
|
||||
{
|
||||
code.AppendF($"{item}.[Friend]{field.Name} = (({field.FieldType}*)((uint8*){prefix}mItems");
|
||||
if (@field.Index > 0)
|
||||
code.AppendF($" + {prefix}mOffsets[{@field.Index - 1}]");
|
||||
code.AppendF($"))[{idx}];\n");
|
||||
}
|
||||
|
||||
Compiler.MixinRoot(code);
|
||||
}
|
||||
|
||||
[Comptime]
|
||||
static void Emit_Set(String prefix, String idx, String item)
|
||||
{
|
||||
String code = scope .();
|
||||
var fields = GetFields(.. scope .());
|
||||
for (var field in fields)
|
||||
{
|
||||
if (field.IsStatic)
|
||||
continue;
|
||||
code.AppendF($"(({field.FieldType}*)((uint8*){prefix}mItems");
|
||||
if (@field.Index > 0)
|
||||
code.AppendF($" + {prefix}mOffsets[{@field.Index - 1}]");
|
||||
code.AppendF($"))[{idx}] = {item}.[Friend]{field.Name};\n");
|
||||
}
|
||||
|
||||
Compiler.MixinRoot(code);
|
||||
}
|
||||
|
||||
[Comptime]
|
||||
static void Emit_Copy(String destOfs, String srcOfs, String length)
|
||||
{
|
||||
var fields = GetFields(.. scope .());
|
||||
String code = scope .();
|
||||
for (var field in fields)
|
||||
{
|
||||
if (@field.Index > 0)
|
||||
code.AppendF($"Internal.MemMove((uint8*)mItems + mOffsets[{@field.Index - 1}] + {destOfs} * {field.FieldType.Stride}, (uint8*)mItems + mOffsets[{@field.Index - 1}] + {srcOfs} * {field.FieldType.Stride}, mSize * {field.FieldType.Stride});\n");
|
||||
else
|
||||
code.AppendF($"Internal.MemMove((uint8*)mItems + {destOfs} * {field.FieldType.Stride}, (uint8*)mItems + {srcOfs} * {field.FieldType.Stride}, {length} * {field.FieldType.Stride});\n");
|
||||
}
|
||||
Compiler.MixinRoot(code);
|
||||
}
|
||||
|
||||
public struct Entry
|
||||
{
|
||||
SelfOuter mList;
|
||||
int_cosize mIdx;
|
||||
|
||||
[Inline]
|
||||
public this(SelfOuter list, int idx)
|
||||
{
|
||||
mList = list;
|
||||
mIdx = (.)idx;
|
||||
}
|
||||
|
||||
[Comptime, OnCompile(.TypeInit)]
|
||||
static void Init()
|
||||
{
|
||||
var fields = GetFields(.. scope .());
|
||||
String code = scope .();
|
||||
for (var field in fields)
|
||||
{
|
||||
code.AppendF($"[Inline] public ref {field.FieldType} {field.Name} => ref (({field.FieldType}*)((uint8*)mList.mItems");
|
||||
if (@field.Index > 0)
|
||||
code.AppendF($" + mList.mOffsets[{@field.Index - 1}]");
|
||||
code.AppendF($"))[mIdx];\n");
|
||||
}
|
||||
|
||||
Compiler.EmitTypeBody(typeof(Self), code);
|
||||
}
|
||||
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
T value = ?;
|
||||
Emit_Get("mList.", "mIdx", "value");
|
||||
return value;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
Emit_Set("mList.", "mIdx", "value");
|
||||
}
|
||||
}
|
||||
|
||||
public static T operator implicit(Self self) => self.[Inline]Value;
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
Free(mItems);
|
||||
}
|
||||
|
||||
public Entry this[int index]
|
||||
{
|
||||
[Checked]
|
||||
get
|
||||
{
|
||||
Runtime.Assert((uint)index < (uint)mSize);
|
||||
return .(this, index);
|
||||
}
|
||||
|
||||
[Unchecked, Inline]
|
||||
get
|
||||
{
|
||||
return .(this, index);
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => mSize;
|
||||
|
||||
[Inline] public Data Data => .(this);
|
||||
|
||||
protected virtual void* Alloc(int byteSize)
|
||||
{
|
||||
return new uint8[byteSize]*;
|
||||
}
|
||||
|
||||
protected virtual void Free(void* val)
|
||||
{
|
||||
delete val;
|
||||
}
|
||||
|
||||
void* Realloc(int newSize, bool autoFree)
|
||||
{
|
||||
[Comptime]
|
||||
void Emit_Start()
|
||||
{
|
||||
var fields = GetFields(.. scope .());
|
||||
String code = scope $"int_cosize[{Math.Max(0, fields.Count - 1)}] newOffsets;\n";
|
||||
FieldInfo prevFieldInfo = default;
|
||||
for (var field in fields)
|
||||
{
|
||||
if (@field.Index > 0)
|
||||
{
|
||||
code.AppendF($"newOffsets[{@field.Index - 1}] = (.)Math.Align(");
|
||||
if (@field.Index > 1)
|
||||
code.AppendF($"newOffsets[{@field.Index - 2}] + ");
|
||||
code.AppendF($"newSize * {prevFieldInfo.FieldType.Stride}, {field.FieldType.Align});\n");
|
||||
}
|
||||
prevFieldInfo = field;
|
||||
}
|
||||
|
||||
if (fields.Count == 0)
|
||||
code.AppendF("int newSizeBytes = 0;\n");
|
||||
else if (fields.Count == 1)
|
||||
code.AppendF($"int newSizeBytes = newSize * {typeof(T).Stride};\n");
|
||||
else
|
||||
code.AppendF($"int newSizeBytes = newOffsets[{fields.Count - 2}] + newSize * {fields[fields.Count - 1].FieldType.Stride};\n");
|
||||
|
||||
Compiler.MixinRoot(code);
|
||||
}
|
||||
|
||||
[Comptime]
|
||||
void Emit_Copy()
|
||||
{
|
||||
var fields = GetFields(.. scope .());
|
||||
String code = scope .();
|
||||
for (var field in fields)
|
||||
{
|
||||
if (@field.Index > 0)
|
||||
code.AppendF($"Internal.MemCpy((uint8*)newItems + newOffsets[{@field.Index - 1}], (uint8*)mItems + mOffsets[{@field.Index - 1}], mSize * {field.FieldType.Stride});\n");
|
||||
else
|
||||
code.AppendF($"Internal.MemCpy(newItems, mItems, mSize * {field.FieldType.Stride});\n");
|
||||
}
|
||||
Compiler.MixinRoot(code);
|
||||
}
|
||||
|
||||
void* oldAlloc = null;
|
||||
if (newSize > 0)
|
||||
{
|
||||
Emit_Start();
|
||||
void* newItems = Alloc(newSizeBytes);
|
||||
if (mSize > 0)
|
||||
{
|
||||
Emit_Copy();
|
||||
}
|
||||
oldAlloc = mItems;
|
||||
mItems = newItems;
|
||||
mOffsets = newOffsets;
|
||||
mAllocSize = (.)newSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldAlloc = mItems;
|
||||
mItems = null;
|
||||
mAllocSize = 0;
|
||||
}
|
||||
|
||||
if ((autoFree) && (oldAlloc != null))
|
||||
{
|
||||
Free(oldAlloc);
|
||||
return null;
|
||||
}
|
||||
|
||||
return oldAlloc;
|
||||
}
|
||||
|
||||
public void* EnsureCapacity(int min, bool autoFree)
|
||||
{
|
||||
int allocSize = AllocSize;
|
||||
if (allocSize >= min)
|
||||
return null;
|
||||
|
||||
int_cosize newCapacity = (int_cosize)(allocSize == 0 ? cDefaultCapacity : allocSize * 2);
|
||||
// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
|
||||
// Note that this check works even when mItems.Length overflowed thanks to the (uint) cast
|
||||
//if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
|
||||
if (newCapacity < min) newCapacity = (int_cosize)min;
|
||||
return Realloc(newCapacity, autoFree);
|
||||
}
|
||||
|
||||
public void Reserve(int size)
|
||||
{
|
||||
EnsureCapacity(size, true);
|
||||
}
|
||||
|
||||
/// Adds an item to the back of the list.
|
||||
public void Add(T item)
|
||||
{
|
||||
if (mSize == AllocSize)
|
||||
{
|
||||
// We free after the insert to allow for inserting a ref to another list element
|
||||
let oldPtr = EnsureCapacity(mSize + 1, false);
|
||||
Emit_Set("", "mSize", "item");
|
||||
mSize++;
|
||||
Free(oldPtr);
|
||||
return;
|
||||
}
|
||||
|
||||
Emit_Set("", "mSize", "item");
|
||||
mSize++;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void GCMarkMembers()
|
||||
{
|
||||
[Comptime]
|
||||
void Emit()
|
||||
{
|
||||
String code = scope .();
|
||||
var fields = GetFields(.. scope .());
|
||||
for (var field in fields)
|
||||
{
|
||||
if (!field.FieldType.WantsMark)
|
||||
continue;
|
||||
code.AppendF($"for (int i < mSize) {{ GC.Mark!((({field.FieldType}*)((uint8*)mItems");
|
||||
if (@field.Index > 0)
|
||||
code.AppendF($" + mOffsets[{@field.Index - 1}]");
|
||||
code.Append("))[i]); }\n");
|
||||
}
|
||||
Compiler.MixinRoot(code);
|
||||
}
|
||||
|
||||
if (mItems == null)
|
||||
return;
|
||||
let type = typeof(T);
|
||||
if ((type.[Friend]mTypeFlags & .WantsMark) == 0)
|
||||
return;
|
||||
Emit();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (mSize > 0)
|
||||
{
|
||||
mSize = 0;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
for (int i < mSize)
|
||||
if (this[i].Value == item)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(Span<T> span)
|
||||
{
|
||||
for (int i < span.Length)
|
||||
span[i] = this[i].Value;
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
int index = IndexOf(item);
|
||||
if (index >= 0)
|
||||
{
|
||||
RemoveAt(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
Debug.Assert((uint)index < (uint)mSize);
|
||||
if (index < mSize - 1)
|
||||
{
|
||||
int copySize = mSize - index - 1;
|
||||
(void)copySize;
|
||||
Emit_Copy("index", "(index + 1)", "copySize");
|
||||
}
|
||||
mSize--;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void RemoveRange(int index, int count)
|
||||
{
|
||||
Debug.Assert((uint)index + (uint)count <= (uint)mSize);
|
||||
if (index + count <= mSize - 1)
|
||||
{
|
||||
for (int i = index; i < mSize - count; i++)
|
||||
mItems[i] = mItems[i + count];
|
||||
}
|
||||
mSize -= (.)count;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Will change the order of items in the list
|
||||
public void RemoveAtFast(int index)
|
||||
{
|
||||
Debug.Assert((uint32)index < (uint32)mSize);
|
||||
if (mSize > 1)
|
||||
this[index].Value = this[mSize - 1].Value;
|
||||
mSize--;
|
||||
#if VERSION_LIST
|
||||
mVersion++;
|
||||
#endif
|
||||
}
|
||||
|
||||
Variant IList.this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return [Unbound]Variant.Create(this[index]);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
ThrowUnimplemented();
|
||||
}
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return .(this);
|
||||
}
|
||||
|
||||
public int FindIndex(Predicate<T> match)
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
if (match(this[i].Value))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
if (this[i].Value == item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int IndexOf(T item, int index)
|
||||
{
|
||||
for (int i = index; i < mSize; i++)
|
||||
if (this[i].Value == item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int IndexOf(T item, int index, int count)
|
||||
{
|
||||
for (int i = index; i < index + count; i++)
|
||||
if (this[i].Value == item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int IndexOfStrict(T item)
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
if (this[i].Value === item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int IndexOfStrict(T item, int index)
|
||||
{
|
||||
for (int i = index; i < mSize; i++)
|
||||
if (this[i].Value === item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int IndexOfStrict(T item, int index, int count)
|
||||
{
|
||||
for (int i = index; i < index + count; i++)
|
||||
if (this[i].Value === item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int IndexOfAlt<TAlt>(TAlt item) where TAlt : IHashable where bool : operator T == TAlt
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
if (this[i].Value == item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int LastIndexOf(T item)
|
||||
{
|
||||
for (int i = mSize - 1; i >= 0; i--)
|
||||
if (this[i].Value == item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int LastIndexOfStrict(T item)
|
||||
{
|
||||
for (int i = mSize - 1; i >= 0; i--)
|
||||
if (this[i].Value === item)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<Entry>, IResettable
|
||||
{
|
||||
private SplitList<T> mList;
|
||||
private int mIndex;
|
||||
#if VERSION_LIST
|
||||
private int32 mVersion;
|
||||
#endif
|
||||
public this(SplitList<T> list)
|
||||
{
|
||||
mList = list;
|
||||
mIndex = 0;
|
||||
#if VERSION_LIST
|
||||
mVersion = list.mVersion;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VERSION_LIST
|
||||
void CheckVersion()
|
||||
{
|
||||
if (mVersion != mList.mVersion)
|
||||
Runtime.FatalError(cVersionError);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
var localList = mList;
|
||||
if ((uint(mIndex) < uint(localList.mSize)))
|
||||
{
|
||||
mIndex++;
|
||||
return true;
|
||||
}
|
||||
return MoveNextRare();
|
||||
}
|
||||
|
||||
private bool MoveNextRare() mut
|
||||
{
|
||||
#if VERSION_LIST
|
||||
CheckVersion();
|
||||
#endif
|
||||
mIndex = mList.mSize + 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
public Entry Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return mList[mIndex - 1];
|
||||
}
|
||||
}
|
||||
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
return mIndex - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return mList.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove() mut
|
||||
{
|
||||
int curIdx = mIndex - 1;
|
||||
mList.RemoveAt(curIdx);
|
||||
#if VERSION_LIST
|
||||
mVersion = mList.mVersion;
|
||||
#endif
|
||||
mIndex = curIdx;
|
||||
}
|
||||
|
||||
public void RemoveFast() mut
|
||||
{
|
||||
int curIdx = mIndex - 1;
|
||||
int lastIdx = mList.Count - 1;
|
||||
if (curIdx < lastIdx)
|
||||
mList[curIdx].Value = mList[lastIdx].Value;
|
||||
mList.RemoveAt(lastIdx);
|
||||
#if VERSION_LIST
|
||||
mVersion = mList.mVersion;
|
||||
#endif
|
||||
mIndex = curIdx;
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
mIndex = 0;
|
||||
}
|
||||
|
||||
public Result<Entry> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -259,6 +259,9 @@ namespace System
|
|||
[LinkName("#CallerExpression")]
|
||||
public static extern String[0x00FFFFFF] CallerExpression;
|
||||
|
||||
[LinkName("#OrigCalleeType")]
|
||||
public static extern Type OrigCalleeType;
|
||||
|
||||
[LinkName("#ProjectName")]
|
||||
public static extern String ProjectName;
|
||||
|
||||
|
@ -280,6 +283,9 @@ namespace System
|
|||
[LinkName("#CompileRev")]
|
||||
public static extern int32 CompileRev;
|
||||
|
||||
[LinkName("#NextId")]
|
||||
public static extern int64 NextId;
|
||||
|
||||
[Comptime(ConstEval=true)]
|
||||
public static void Assert(bool cond)
|
||||
{
|
||||
|
@ -287,6 +293,7 @@ namespace System
|
|||
Runtime.FatalError("Assert failed");
|
||||
}
|
||||
|
||||
static extern void Comptime_SetReturnType(int32 typeId);
|
||||
static extern void* Comptime_MethodBuilder_EmitStr(void* native, StringView str);
|
||||
static extern void* Comptime_CreateMethod(int32 typeId, StringView methodName, Type returnType, MethodFlags methodFlags);
|
||||
static extern void Comptime_EmitTypeBody(int32 typeId, StringView text);
|
||||
|
@ -309,6 +316,12 @@ namespace System
|
|||
Comptime_EmitTypeBody((.)owner.TypeId, text);
|
||||
}
|
||||
|
||||
[Comptime(OnlyFromComptime=true)]
|
||||
public static void SetReturnType(Type type)
|
||||
{
|
||||
Comptime_SetReturnType((.)type.TypeId);
|
||||
}
|
||||
|
||||
[Comptime(OnlyFromComptime=true)]
|
||||
public static void EmitAddInterface(Type owner, Type iface)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,62 @@ namespace System
|
|||
{
|
||||
struct Enum
|
||||
{
|
||||
[NoShow(true)]
|
||||
[Comptime(ConstEval=true)]
|
||||
public static int GetCount<T>() where T : Enum
|
||||
{
|
||||
int count = 0;
|
||||
for (var field in typeof(T).GetFields())
|
||||
{
|
||||
if (field.IsEnumCase)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
[Comptime(ConstEval=true)]
|
||||
public static var GetMinValue<T>() where T : Enum
|
||||
{
|
||||
Compiler.SetReturnType(typeof(T));
|
||||
|
||||
int? minValue = null;
|
||||
for (var field in typeof(T).GetFields())
|
||||
{
|
||||
if (field.IsEnumCase)
|
||||
{
|
||||
if (minValue == null)
|
||||
minValue = field.[Friend]mFieldData.mData;
|
||||
else
|
||||
minValue = Math.Min(minValue.Value, field.[Friend]mFieldData.mData);
|
||||
}
|
||||
}
|
||||
return minValue.ValueOrDefault;
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
[Comptime(ConstEval=true)]
|
||||
public static var GetMaxValue<T>() where T : Enum
|
||||
{
|
||||
Compiler.SetReturnType(typeof(T));
|
||||
|
||||
int? maxValue = null;
|
||||
for (var field in typeof(T).GetFields())
|
||||
{
|
||||
if (field.IsEnumCase)
|
||||
{
|
||||
if (maxValue == null)
|
||||
maxValue = field.[Friend]mFieldData.mData;
|
||||
else
|
||||
maxValue = Math.Max(maxValue.Value, field.[Friend]mFieldData.mData);
|
||||
}
|
||||
}
|
||||
if (maxValue == null)
|
||||
return -1;
|
||||
return maxValue.ValueOrDefault;
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
public static void EnumToString(Type type, String strBuffer, int64 iVal)
|
||||
{
|
||||
for (var field in type.GetFields())
|
||||
|
@ -19,6 +75,7 @@ namespace System
|
|||
iVal.ToString(strBuffer);
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
public static Result<T> Parse<T>(StringView str, bool ignoreCase = false) where T : enum
|
||||
{
|
||||
for (var (name, data) in GetEnumerator<T>())
|
||||
|
@ -32,7 +89,8 @@ namespace System
|
|||
return .Err;
|
||||
}
|
||||
|
||||
public static bool IsDefined<T>(T value)
|
||||
[NoShow(true)]
|
||||
public static bool IsDefined<T>(T value) where T : Enum
|
||||
where T : enum
|
||||
{
|
||||
for (var data in GetValues<T>())
|
||||
|
@ -44,24 +102,28 @@ namespace System
|
|||
return false;
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
public static EnumEnumerator<TEnum> GetEnumerator<TEnum>()
|
||||
where TEnum : enum
|
||||
{
|
||||
return .();
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
public static EnumValuesEnumerator<TEnum> GetValues<TEnum>()
|
||||
where TEnum : enum
|
||||
{
|
||||
return .();
|
||||
}
|
||||
|
||||
|
||||
[NoShow(true)]
|
||||
public static EnumNamesEnumerator<TEnum> GetNames<TEnum>()
|
||||
where TEnum : enum
|
||||
{
|
||||
return .();
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
private struct EnumFieldsEnumerator<TEnum>
|
||||
where TEnum : enum
|
||||
{
|
||||
|
@ -127,6 +189,7 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
public struct EnumEnumerator<TEnum> : EnumFieldsEnumerator<TEnum>, IEnumerator<(StringView name, TEnum value)>
|
||||
where TEnum : enum
|
||||
{
|
||||
|
@ -146,6 +209,7 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
public struct EnumValuesEnumerator<TEnum> : EnumFieldsEnumerator<TEnum>, IEnumerator<TEnum>
|
||||
where TEnum : enum
|
||||
{
|
||||
|
@ -165,6 +229,7 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
[NoShow(true)]
|
||||
public struct EnumNamesEnumerator<TEnum> : EnumFieldsEnumerator<TEnum>, IEnumerator<StringView>
|
||||
where TEnum : enum
|
||||
{
|
||||
|
|
|
@ -13,10 +13,17 @@ namespace System
|
|||
// If we are enumerating then mData points to the enumerator.
|
||||
int mData;
|
||||
|
||||
#if BF_64_BIT
|
||||
const int sIsEnumerating = (.)0x8000'0000'0000'0000;
|
||||
const int sHadEnumRemoves = 0x4000'0000'0000'0000;
|
||||
const int sFlagsMask = (.)0xC000'0000'0000'0000;
|
||||
const int sDataMask = ~sFlagsMask;
|
||||
#else
|
||||
const int sIsEnumerating = 1;
|
||||
const int sHadEnumRemoves = 2;
|
||||
const int sFlagsMask = 3;
|
||||
const int sDataMask = ~sFlagsMask;
|
||||
#endif
|
||||
|
||||
public bool HasListeners
|
||||
{
|
||||
|
|
|
@ -149,6 +149,22 @@ namespace System
|
|||
public static void ExcludeThreadId(int thereadId) {}
|
||||
#endif
|
||||
|
||||
[DisableObjectAccessChecks]
|
||||
static void MarkAppendedObject(Object obj)
|
||||
{
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
|
||||
ClassVData* maskedVData = (ClassVData*)(void*)(obj.[Friend]mClassVData & ~(int)0xFF);
|
||||
if (maskedVData == null)
|
||||
return;
|
||||
#else
|
||||
if (obj.[Friend]mClassVData == null)
|
||||
return;
|
||||
#endif
|
||||
obj.[Friend]GCMarkMembers();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void MarkDerefedObject(Object* obj)
|
||||
{
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace System.IO
|
|||
public static Result<void, FileError> ReadAll(StringView path, List<uint8> outData)
|
||||
{
|
||||
FileStream fs = scope FileStream();
|
||||
var result = fs.Open(path, .Open, .Read);
|
||||
var result = fs.Open(path, .Open, .Read, .ReadWrite);
|
||||
if (result case .Err(let err))
|
||||
return .Err(.OpenError(err));
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ namespace System.IO
|
|||
Windows.SHCreateItemFromParsingName(mSelectedPath.ToScopedNativeWChar!(), null, Windows.COM_IShellItem.sIID, (void**)&folderShellItem);
|
||||
if (folderShellItem != null)
|
||||
{
|
||||
fileDialog.VT.SetDefaultFolder(fileDialog, folderShellItem);
|
||||
fileDialog.VT.SetFolder(fileDialog, folderShellItem);
|
||||
folderShellItem.VT.Release(folderShellItem);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ namespace System.IO
|
|||
{
|
||||
class MemoryStream : Stream
|
||||
{
|
||||
List<uint8> mMemory ~ delete _;
|
||||
bool mOwns;
|
||||
List<uint8> mMemory ~ { if (mOwns) delete _; }
|
||||
int mPosition = 0;
|
||||
|
||||
public override int64 Position
|
||||
|
@ -46,14 +47,18 @@ namespace System.IO
|
|||
|
||||
public this()
|
||||
{
|
||||
mOwns = true;
|
||||
mMemory = new List<uint8>();
|
||||
}
|
||||
|
||||
public this(List<uint8> memory)
|
||||
public this(List<uint8> memory, bool owns = true)
|
||||
{
|
||||
mOwns = owns;
|
||||
mMemory = memory;
|
||||
}
|
||||
|
||||
public List<uint8> Memory => mMemory;
|
||||
|
||||
public override Result<int> TryRead(Span<uint8> data)
|
||||
{
|
||||
let count = data.Length;
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace System
|
|||
interface IRefCounted
|
||||
{
|
||||
void AddRef();
|
||||
void ReleaseRef();
|
||||
void Release();
|
||||
}
|
||||
|
||||
class RefCounted : IRefCounted
|
||||
|
@ -63,5 +63,167 @@ namespace System
|
|||
Debug.Assert(refCount >= 0);
|
||||
return refCount;
|
||||
}
|
||||
|
||||
void IRefCounted.Release()
|
||||
{
|
||||
ReleaseRef();
|
||||
}
|
||||
|
||||
struct Alloc
|
||||
{
|
||||
public void* Alloc(Type type, int size, int align)
|
||||
{
|
||||
int sizeAdd = size + Math.Max(align, sizeof(int));
|
||||
|
||||
void* data = Internal.Malloc(sizeAdd);
|
||||
return (uint8*)data + sizeAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RefCounted<T> : IRefCounted where T : class, delete
|
||||
{
|
||||
public T mVal;
|
||||
public int mRefCount = 1;
|
||||
|
||||
public int RefCount => mRefCount;
|
||||
public T Value => mVal;
|
||||
|
||||
protected this()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected ~this()
|
||||
{
|
||||
Debug.Assert(mRefCount == 0);
|
||||
delete mVal;
|
||||
}
|
||||
|
||||
[OnCompile(.TypeInit), Comptime]
|
||||
static void Init()
|
||||
{
|
||||
String emitStr = scope .();
|
||||
|
||||
for (var methodInfo in typeof(T).GetMethods(.Public))
|
||||
{
|
||||
if (methodInfo.IsStatic)
|
||||
continue;
|
||||
if (!methodInfo.IsConstructor)
|
||||
continue;
|
||||
|
||||
emitStr.AppendF("public static RefCounted<T> Create(");
|
||||
methodInfo.GetParamsDecl(emitStr);
|
||||
emitStr.AppendF(")\n");
|
||||
emitStr.AppendF("{{\n");
|
||||
emitStr.AppendF("\treturn new [Friend] RefCountedAppend<T>(");
|
||||
methodInfo.GetArgsList(emitStr);
|
||||
emitStr.AppendF(");\n}}\n");
|
||||
}
|
||||
|
||||
Compiler.EmitTypeBody(typeof(Self), emitStr);
|
||||
}
|
||||
|
||||
public static RefCounted<T> Attach(T val)
|
||||
{
|
||||
return new Self() { mVal = val };
|
||||
}
|
||||
|
||||
public virtual void DeleteSelf()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
public void DeleteUnchecked()
|
||||
{
|
||||
mRefCount = 0;
|
||||
DeleteSelf();
|
||||
}
|
||||
|
||||
public void AddRef()
|
||||
{
|
||||
Interlocked.Increment(ref mRefCount);
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
int refCount = Interlocked.Decrement(ref mRefCount);
|
||||
Debug.Assert(refCount >= 0);
|
||||
if (refCount == 0)
|
||||
DeleteSelf();
|
||||
}
|
||||
|
||||
public void ReleaseLastRef()
|
||||
{
|
||||
int refCount = Interlocked.Decrement(ref mRefCount);
|
||||
Debug.Assert(refCount == 0);
|
||||
if (refCount == 0)
|
||||
DeleteSelf();
|
||||
}
|
||||
|
||||
public int ReleaseRefNoDelete()
|
||||
{
|
||||
int refCount = Interlocked.Decrement(ref mRefCount);
|
||||
Debug.Assert(refCount >= 0);
|
||||
return refCount;
|
||||
}
|
||||
|
||||
public virtual T Detach()
|
||||
{
|
||||
var val = mVal;
|
||||
mVal = null;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static T operator->(Self self)
|
||||
{
|
||||
return self.mVal;
|
||||
}
|
||||
|
||||
public static T operator implicit(Self self)
|
||||
{
|
||||
return self.mVal;
|
||||
}
|
||||
}
|
||||
|
||||
class RefCountedAppend<T> : RefCounted<T> where T : class, new, delete
|
||||
{
|
||||
protected ~this()
|
||||
{
|
||||
Debug.Assert(mRefCount == 0);
|
||||
delete:append mVal;
|
||||
mVal = null;
|
||||
}
|
||||
|
||||
[OnCompile(.TypeInit), Comptime]
|
||||
static void Init()
|
||||
{
|
||||
String emitStr = scope .();
|
||||
|
||||
for (var methodInfo in typeof(T).GetMethods(.Public))
|
||||
{
|
||||
if (methodInfo.IsStatic)
|
||||
continue;
|
||||
if (!methodInfo.IsConstructor)
|
||||
continue;
|
||||
|
||||
emitStr.AppendF("[AllowAppend]\nprotected this(");
|
||||
methodInfo.GetParamsDecl(emitStr);
|
||||
emitStr.AppendF(")\n");
|
||||
emitStr.AppendF("{{\n");
|
||||
emitStr.AppendF("\tvar val = append T(");
|
||||
methodInfo.GetArgsList(emitStr);
|
||||
emitStr.AppendF(");\n");
|
||||
emitStr.AppendF("\tmVal = val;\n");
|
||||
emitStr.AppendF("}}\n");
|
||||
}
|
||||
|
||||
Compiler.EmitTypeBody(typeof(Self), emitStr);
|
||||
}
|
||||
|
||||
public override T Detach()
|
||||
{
|
||||
Runtime.FatalError("Can only detach from objects created via RefCounted<T>.Attach");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,11 +72,6 @@ namespace System
|
|||
return &mVAList;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void* ToVAListPtr() mut
|
||||
{
|
||||
return &mVAList;
|
||||
}
|
||||
}
|
||||
|
||||
[AlwaysInclude]
|
||||
|
@ -89,6 +84,8 @@ namespace System
|
|||
[CallingConvention(.Cdecl), NoReturn]
|
||||
public static extern void ThrowIndexOutOfRange(int stackOffset = 0);
|
||||
[CallingConvention(.Cdecl), NoReturn]
|
||||
public static extern void ThrowObjectNotInitialized(int stackOffset = 0);
|
||||
[CallingConvention(.Cdecl), NoReturn]
|
||||
public static extern void FatalError(String error, int stackOffset = 0);
|
||||
[Intrinsic("memcpy")]
|
||||
public static extern void MemCpy(void* dest, void* src, int length, int32 align = 1, bool isVolatile = false);
|
||||
|
|
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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -192,8 +192,18 @@ namespace System
|
|||
|
||||
[CLink]
|
||||
private static extern double modf(double x, out double intpart);
|
||||
|
||||
#if BF_PLATFORM_WINDOWS && BF_64_BIT
|
||||
[CLink]
|
||||
private static extern float modff(float x, out float intpart);
|
||||
#else
|
||||
private static float modff(float x, out float intpart)
|
||||
{
|
||||
var f = modf(x, var i);
|
||||
intpart = (.)i;
|
||||
return (.)f;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static float Truncate(float f)
|
||||
{
|
||||
|
|
|
@ -35,6 +35,15 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
public T ValueOrDefault
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
}
|
||||
|
||||
public ref T ValueRef
|
||||
{
|
||||
[Inline]
|
||||
|
@ -96,9 +105,19 @@ namespace System
|
|||
[Inline]
|
||||
public static explicit operator T(Nullable<T> value)
|
||||
{
|
||||
if (!value.mHasValue)
|
||||
Debug.FatalError("Value requested for null nullable.");
|
||||
return value.mValue;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public static ref T operator->(ref Nullable<T> value)
|
||||
{
|
||||
if (!value.mHasValue)
|
||||
Debug.FatalError("Value requested for null nullable.");
|
||||
return ref value.mValue;
|
||||
}
|
||||
|
||||
[Inline, Commutable]
|
||||
public static bool operator==(Nullable<T> lhs, T rhs)
|
||||
{
|
||||
|
@ -401,31 +420,6 @@ namespace System
|
|||
return Nullable<TResult>(lhs.mValue | rhs.mValue);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public static T operator??(Nullable<T> lhs, T rhs)
|
||||
{
|
||||
return (lhs.mHasValue) ? lhs.mValue : rhs;
|
||||
}
|
||||
|
||||
public static TResult? operator??<TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult : operator TOther ?? T where TResult : struct
|
||||
{
|
||||
if (!rhs.mHasValue) return null;
|
||||
return Nullable<TResult>(lhs ?? rhs.mValue);
|
||||
}
|
||||
|
||||
public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, TOther rhs) where TResult : operator T ?? TOther where TResult : struct
|
||||
{
|
||||
if (!lhs.mHasValue) return null;
|
||||
return Nullable<TResult>(lhs.mValue ?? rhs);
|
||||
}
|
||||
|
||||
public static TResult? operator??<TOther, TResult>(Nullable<T> lhs, Nullable<TOther> rhs) where TOther : struct where TResult : operator T ?? TOther where TResult : struct
|
||||
{
|
||||
if ((!lhs.mHasValue) || (!rhs.mHasValue)) return null;
|
||||
return Nullable<TResult>(lhs.mValue ?? rhs.mValue);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public static TResult? operator<< <TOther, TResult>(TOther lhs, Nullable<T> rhs) where TResult : operator TOther << T where TResult : struct
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace System
|
|||
public struct BfpEvent {};
|
||||
public struct BfpFileWatcher {}
|
||||
public struct BfpProcess {}
|
||||
public struct BfpTLS;
|
||||
|
||||
public enum BfpSystemResult : int32
|
||||
{
|
||||
|
@ -95,6 +96,18 @@ namespace System
|
|||
[CallingConvention(.Stdcall), CLink]
|
||||
public static extern void BfpSystem_GetComputerName(char8* outStr, int32* inOutStrSize, BfpSystemResult* outResult);
|
||||
|
||||
[CallingConvention(.Stdcall), CLink]
|
||||
public static extern int BfpThread_GetCurrentId();
|
||||
|
||||
[CallingConvention(.Stdcall), CLink]
|
||||
public static extern BfpTLS* BfpTLS_Create(function [CallingConvention(.Stdcall)] void(void*) exitProc);
|
||||
[CallingConvention(.Stdcall), CLink]
|
||||
public static extern void BfpTLS_Release(BfpTLS* tls);
|
||||
[CallingConvention(.Stdcall), CLink]
|
||||
public static extern void BfpTLS_SetValue(BfpTLS* tls, void* value);
|
||||
[CallingConvention(.Stdcall), CLink]
|
||||
public static extern void* BfpTLS_GetValue(BfpTLS* tls);
|
||||
|
||||
public enum BfpFileWatcherFlags : int32
|
||||
{
|
||||
None = 0,
|
||||
|
|
|
@ -225,6 +225,187 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
struct Range<T> where T : operator T + int where int : operator T - T where bool : operator T >= T
|
||||
{
|
||||
protected T mStart;
|
||||
protected T mEnd;
|
||||
|
||||
public this()
|
||||
{
|
||||
mStart = default;
|
||||
mEnd = default;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public this(T start, T end)
|
||||
{
|
||||
Debug.Assert(end >= start);
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd - mStart;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
mEnd = mStart + value;
|
||||
}
|
||||
}
|
||||
|
||||
public T Start
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mStart;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
mStart = value;
|
||||
}
|
||||
}
|
||||
|
||||
public T End
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
set mut
|
||||
{
|
||||
mEnd = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return mEnd == mStart;
|
||||
}
|
||||
}
|
||||
|
||||
public ReverseEnumerator Reversed
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
return ReverseEnumerator(mEnd + -1, mStart);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(T idx)
|
||||
{
|
||||
return (idx >= mStart) && !(idx >= mEnd);
|
||||
}
|
||||
|
||||
public bool Contains(Range<T> val)
|
||||
{
|
||||
return (val.[Friend]mStart >= mStart) && (val.[Friend]mEnd <= mEnd);
|
||||
}
|
||||
|
||||
public void Clear() mut
|
||||
{
|
||||
mStart = default;
|
||||
mEnd = default;
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return Enumerator(this);
|
||||
}
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
strBuffer.AppendF($"{mStart}..<{mEnd}");
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
private T mEnd;
|
||||
private T mIndex;
|
||||
|
||||
[Inline]
|
||||
public this(Range<T> range)
|
||||
{
|
||||
mIndex = range.mStart + -1;
|
||||
mEnd = range.mEnd;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public ref T Index
|
||||
{
|
||||
get mut
|
||||
{
|
||||
return ref mIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public T End => mEnd;
|
||||
|
||||
[Inline]
|
||||
public Result<T> GetNext() mut
|
||||
{
|
||||
if (mIndex + 1 >= mEnd)
|
||||
return .Err;
|
||||
mIndex += 1;
|
||||
return mIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReverseEnumerator : IEnumerator<T>
|
||||
{
|
||||
private T mEnd;
|
||||
private T mIndex;
|
||||
|
||||
[Inline]
|
||||
public this(T start, T end)
|
||||
{
|
||||
mIndex = start + 1;
|
||||
mEnd = end;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public ref T Index
|
||||
{
|
||||
get mut
|
||||
{
|
||||
return ref mIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public T End => mEnd;
|
||||
|
||||
[Inline]
|
||||
public Result<T> GetNext() mut
|
||||
{
|
||||
if (mIndex <= mEnd)
|
||||
return .Err;
|
||||
mIndex += -1;
|
||||
return mIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IndexRange : RangeExpression
|
||||
{
|
||||
protected Index mStart;
|
||||
|
|
|
@ -8,7 +8,8 @@ namespace System.Reflection
|
|||
public enum Error
|
||||
{
|
||||
InvalidTargetType,
|
||||
InvalidValueType
|
||||
InvalidValueType,
|
||||
AppendedField
|
||||
}
|
||||
|
||||
TypeInstance mTypeInstance;
|
||||
|
@ -24,6 +25,8 @@ namespace System.Reflection
|
|||
public int32 MemberOffset => (int32)mFieldData.mData;
|
||||
public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
||||
public bool IsConst => mFieldData.mFlags.HasFlag(.Const);
|
||||
public bool IsAppended => mFieldData.mFlags.HasFlag(.Appended);
|
||||
public bool IsEnumCase => mFieldData.mFlags.HasFlag(.EnumCase);
|
||||
public bool IsReadOnly => mFieldData.mFlags.HasFlag(.ReadOnly);
|
||||
public bool IsStatic => mFieldData.mFlags.HasFlag(.Static);
|
||||
public bool IsPublic => (mFieldData.mFlags & .FieldAccessMask) == .Public;
|
||||
|
@ -85,7 +88,12 @@ namespace System.Reflection
|
|||
if (valueType == fieldType)
|
||||
{
|
||||
if (valueType.IsObject)
|
||||
{
|
||||
if (mFieldData.mFlags.HasFlag(.Appended))
|
||||
return .Err(.AppendedField);
|
||||
|
||||
*((void**)dataAddr) = Internal.UnsafeCastToPtr(value);
|
||||
}
|
||||
else
|
||||
Internal.MemCpy(dataAddr, valueDataAddr, fieldType.[Friend]mSize);
|
||||
}
|
||||
|
@ -384,7 +392,10 @@ namespace System.Reflection
|
|||
if (typeCode == TypeCode.Object)
|
||||
{
|
||||
value.[Friend]mStructType = 0;
|
||||
value.[Friend]mData = *(int*)targetDataAddr;
|
||||
if (mFieldData.mFlags.HasFlag(.Appended))
|
||||
value.[Friend]mData = (int)targetDataAddr;
|
||||
else
|
||||
value.[Friend]mData = *(int*)targetDataAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -50,6 +50,9 @@ namespace System.Reflection
|
|||
public bool IsReadOnly => Compiler.IsComptime ?
|
||||
Type.[Friend]Comptime_Method_GetInfo(mData.mComptimeMethodInstance).mMethodFlags.HasFlag(.ReadOnly) :
|
||||
mData.mMethodData.[Friend]mFlags.HasFlag(.ReadOnly);
|
||||
public bool IsStatic => Compiler.IsComptime ?
|
||||
Type.[Friend]Comptime_Method_GetInfo(mData.mComptimeMethodInstance).mMethodFlags.HasFlag(.Static) :
|
||||
mData.mMethodData.[Friend]mFlags.HasFlag(.Static);
|
||||
|
||||
public StringView Name => Compiler.IsComptime ?
|
||||
Type.[Friend]Comptime_Method_GetName(mData.mComptimeMethodInstance) :
|
||||
|
@ -112,6 +115,19 @@ namespace System.Reflection
|
|||
}
|
||||
}
|
||||
|
||||
public TypeInstance.ParamFlags GetParamFlags(int paramIdx)
|
||||
{
|
||||
if (Compiler.IsComptime)
|
||||
{
|
||||
return Type.[Friend]Comptime_Method_GetParamInfo(mData.mComptimeMethodInstance, (.)paramIdx).mParamFlags;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert((uint)paramIdx < (uint)mData.mMethodData.mParamCount);
|
||||
return mData.mMethodData.mParamData[paramIdx].mParamFlags;
|
||||
}
|
||||
}
|
||||
|
||||
public Result<T> GetParamCustomAttribute<T>(int paramIdx) where T : Attribute
|
||||
{
|
||||
if (Compiler.IsComptime)
|
||||
|
@ -967,19 +983,60 @@ namespace System.Reflection
|
|||
strBuffer.Append(' ');
|
||||
strBuffer.Append(mData.mMethodData.mName);
|
||||
strBuffer.Append('(');
|
||||
|
||||
int useParamIdx = 0;
|
||||
for (int paramIdx < mData.mMethodData.mParamCount)
|
||||
{
|
||||
if (paramIdx > 0)
|
||||
strBuffer.Append(", ");
|
||||
let paramData = mData.mMethodData.mParamData[paramIdx];
|
||||
let paramType = Type.[Friend]GetType(paramData.mType);
|
||||
if (paramData.mParamFlags.HasFlag(.Implicit))
|
||||
continue;
|
||||
if (useParamIdx > 0)
|
||||
strBuffer.Append(", ");
|
||||
paramType.ToString(strBuffer);
|
||||
strBuffer.Append(' ');
|
||||
strBuffer.Append(paramData.mName);
|
||||
useParamIdx++;
|
||||
}
|
||||
strBuffer.Append(')');
|
||||
}
|
||||
|
||||
public void GetParamsDecl(String strBuffer)
|
||||
{
|
||||
int useParamIdx = 0;
|
||||
for (int paramIdx < ParamCount)
|
||||
{
|
||||
var flag = GetParamFlags(paramIdx);
|
||||
if (flag.HasFlag(.Implicit))
|
||||
continue;
|
||||
if (useParamIdx > 0)
|
||||
strBuffer.Append(", ");
|
||||
if (flag.HasFlag(.Params))
|
||||
strBuffer.Append("params ");
|
||||
strBuffer.Append(GetParamType(paramIdx));
|
||||
strBuffer.Append(" ");
|
||||
strBuffer.Append(GetParamName(paramIdx));
|
||||
useParamIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetArgsList(String strBuffer)
|
||||
{
|
||||
int useParamIdx = 0;
|
||||
for (int paramIdx < ParamCount)
|
||||
{
|
||||
var flag = GetParamFlags(paramIdx);
|
||||
if (flag.HasFlag(.Implicit))
|
||||
continue;
|
||||
if (useParamIdx > 0)
|
||||
strBuffer.Append(", ");
|
||||
if (flag.HasFlag(.Params))
|
||||
strBuffer.Append("params ");
|
||||
strBuffer.Append(GetParamName(paramIdx));
|
||||
useParamIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<MethodInfo>
|
||||
{
|
||||
BindingFlags mBindingFlags;
|
||||
|
|
|
@ -27,6 +27,22 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
public ref T ValueRef
|
||||
{
|
||||
[Inline]
|
||||
get mut
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case .Ok(var ref val): return ref val;
|
||||
case .Err:
|
||||
{
|
||||
Internal.FatalError("Unhandled error in result", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public static implicit operator Result<T>(T value)
|
||||
{
|
||||
|
@ -39,6 +55,19 @@ namespace System
|
|||
return result.Unwrap();
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public static mut T operator->(ref Result<T> result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case .Ok(var mut val): return mut val;
|
||||
case .Err:
|
||||
{
|
||||
Internal.FatalError("Unhandled error in result", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public void IgnoreError()
|
||||
{
|
||||
|
@ -99,7 +128,7 @@ namespace System
|
|||
|
||||
extension Result<T> where T : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
public new void Dispose()
|
||||
{
|
||||
if (this case .Ok(var val))
|
||||
val.Dispose();
|
||||
|
@ -116,9 +145,9 @@ namespace System
|
|||
switch (this)
|
||||
{
|
||||
case .Ok(var val): return val;
|
||||
case .Err(var err):
|
||||
case .Err:
|
||||
{
|
||||
Internal.FatalError(scope String()..AppendF("Unhandled error in result:\n {}", err), 2);
|
||||
Internal.FatalError("Unhandled error in result", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,16 +160,47 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
public ref T ValueRef
|
||||
{
|
||||
[Inline]
|
||||
get mut
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case .Ok(var ref val): return ref val;
|
||||
case .Err:
|
||||
{
|
||||
Internal.FatalError("Unhandled error in result", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public static implicit operator Result<T, TErr>(T value)
|
||||
{
|
||||
return .Ok(value);
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public static implicit operator T(Result<T, TErr> result)
|
||||
{
|
||||
return result.Unwrap();
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public static mut T operator->(ref Result<T, TErr> result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case .Ok(var mut val): return mut val;
|
||||
case .Err:
|
||||
{
|
||||
Internal.FatalError("Unhandled error in result", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void IgnoreError()
|
||||
{
|
||||
}
|
||||
|
@ -203,7 +263,7 @@ namespace System
|
|||
|
||||
extension Result<T, TErr> where T : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
public new void Dispose()
|
||||
{
|
||||
if (this case .Ok(var val))
|
||||
val.Dispose();
|
||||
|
@ -212,7 +272,7 @@ namespace System
|
|||
|
||||
extension Result<T, TErr> where TErr : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
public new void Dispose()
|
||||
{
|
||||
if (this case .Err(var err))
|
||||
err.Dispose();
|
||||
|
@ -221,7 +281,7 @@ namespace System
|
|||
|
||||
extension Result<T, TErr> where T : IDisposable where TErr : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
public new void Dispose()
|
||||
{
|
||||
if (this case .Ok(var val))
|
||||
val.Dispose();
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace System
|
|||
[StaticInitPriority(101)]
|
||||
static class Runtime
|
||||
{
|
||||
const int32 cVersion = 9;
|
||||
const int32 cVersion = 10;
|
||||
|
||||
[CRepr, AlwaysInclude]
|
||||
struct BfDebugMessageData
|
||||
|
@ -118,6 +118,7 @@ namespace System
|
|||
function bool (Object thread) mThread_IsAutoDelete;
|
||||
function void (Object thread) mThread_AutoDelete;
|
||||
function int32 (Object thread) mThread_GetMaxStackSize;
|
||||
function void () mThread_Exiting;
|
||||
function void () mGC_MarkAllStaticMembers;
|
||||
function bool () mGC_CallRootCallbacks;
|
||||
function void () mGC_Shutdown;
|
||||
|
@ -146,7 +147,7 @@ namespace System
|
|||
static Type Object_GetType(Object obj)
|
||||
{
|
||||
#if BF_DBG_RUNTIME
|
||||
return obj.[Friend]RawGetType();
|
||||
return obj.[Friend, DisableObjectAccessChecks]RawGetType();
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
|
|
|
@ -276,6 +276,7 @@ namespace System
|
|||
|
||||
public void RemoveFromEnd(int length) mut
|
||||
{
|
||||
Debug.Assert((uint)length <= (uint)mLength);
|
||||
mLength -= length;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace System
|
|||
[Ordered]
|
||||
class String : IHashable, IFormattable, IPrintable
|
||||
{
|
||||
enum CreateFlags
|
||||
public enum CreateFlags
|
||||
{
|
||||
None = 0,
|
||||
NullTerminate = 1
|
||||
|
@ -48,7 +48,7 @@ namespace System
|
|||
|
||||
int_strsize mLength;
|
||||
uint_strsize mAllocSizeAndFlags;
|
||||
char8* mPtr = null;
|
||||
char8* mPtrOrBuffer = null;
|
||||
|
||||
extern const String* sStringLiterals;
|
||||
extern const String* sIdStringLiterals;
|
||||
|
@ -210,8 +210,8 @@ namespace System
|
|||
[AllowAppend]
|
||||
public this(StringView strView)
|
||||
{
|
||||
let tryBufferSize = strView.Length - sizeof(char8*);
|
||||
let bufferSize = (tryBufferSize >= 0) ? tryBufferSize : 0;
|
||||
let count = strView.Length;
|
||||
int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1);
|
||||
#unwarn
|
||||
char8* addlPtr = append char8[bufferSize]*(?);
|
||||
Init(bufferSize);
|
||||
|
@ -326,7 +326,7 @@ namespace System
|
|||
public ~this()
|
||||
{
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
delete:this mPtrOrBuffer;
|
||||
}
|
||||
|
||||
void FakeMethod ()
|
||||
|
@ -390,7 +390,7 @@ namespace System
|
|||
//[Optimize]
|
||||
get
|
||||
{
|
||||
return ((mAllocSizeAndFlags & cStrPtrFlag) != 0) ? mPtr : (char8*)&mPtr;
|
||||
return ((mAllocSizeAndFlags & cStrPtrFlag) != 0) ? mPtrOrBuffer : (char8*)&mPtrOrBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -660,10 +660,10 @@ namespace System
|
|||
{
|
||||
if (str.IsDynAlloc)
|
||||
{
|
||||
delete str.mPtr;
|
||||
delete str.mPtrOrBuffer;
|
||||
}
|
||||
|
||||
str.mPtr = mPtr;
|
||||
str.mPtrOrBuffer = mPtrOrBuffer;
|
||||
str.mAllocSizeAndFlags = mAllocSizeAndFlags;
|
||||
str.mLength = mLength;
|
||||
|
||||
|
@ -673,7 +673,7 @@ namespace System
|
|||
}
|
||||
else
|
||||
{
|
||||
mPtr = null;
|
||||
mPtrOrBuffer = null;
|
||||
mAllocSizeAndFlags = (int_strsize)sizeof(char8*);
|
||||
mLength = 0;
|
||||
}
|
||||
|
@ -689,8 +689,8 @@ namespace System
|
|||
public void Reference(String str)
|
||||
{
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
mPtr = str.Ptr;
|
||||
delete:this mPtrOrBuffer;
|
||||
mPtrOrBuffer = str.Ptr;
|
||||
mLength = str.mLength;
|
||||
mAllocSizeAndFlags = cStrPtrFlag;
|
||||
}
|
||||
|
@ -698,8 +698,8 @@ namespace System
|
|||
public void Reference(char8* ptr, int length, int allocSize)
|
||||
{
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
mPtr = ptr;
|
||||
delete:this mPtrOrBuffer;
|
||||
mPtrOrBuffer = ptr;
|
||||
mLength = (int_strsize)length;
|
||||
mAllocSizeAndFlags = cStrPtrFlag;
|
||||
}
|
||||
|
@ -707,8 +707,8 @@ namespace System
|
|||
public void Reference(char8* ptr, int length)
|
||||
{
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
mPtr = ptr;
|
||||
delete:this mPtrOrBuffer;
|
||||
mPtrOrBuffer = ptr;
|
||||
mLength = (int_strsize)length;
|
||||
mAllocSizeAndFlags = cStrPtrFlag;
|
||||
}
|
||||
|
@ -721,8 +721,8 @@ namespace System
|
|||
public void Reference(char8* ptr)
|
||||
{
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
mPtr = ptr;
|
||||
delete:this mPtrOrBuffer;
|
||||
mPtrOrBuffer = ptr;
|
||||
mLength = StrLen(ptr);
|
||||
mAllocSizeAndFlags = cStrPtrFlag;
|
||||
}
|
||||
|
@ -734,7 +734,7 @@ namespace System
|
|||
Debug.Assert(!IsDynAlloc);
|
||||
Debug.Assert(AllocSize == 0); // Assert is reference
|
||||
Debug.Assert((uint)mLength >= (uint)adjBytes);
|
||||
mPtr += adjBytes;
|
||||
mPtrOrBuffer += adjBytes;
|
||||
mLength -= (int_strsize)adjBytes;
|
||||
}
|
||||
|
||||
|
@ -763,8 +763,8 @@ namespace System
|
|||
Internal.MemSet(newPtr + mLength, 0, newSize - mLength);
|
||||
#endif
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
mPtr = newPtr;
|
||||
delete:this mPtrOrBuffer;
|
||||
mPtrOrBuffer = newPtr;
|
||||
mAllocSizeAndFlags = (uint_strsize)newSize | cDynAllocFlag | cStrPtrFlag;
|
||||
}
|
||||
|
||||
|
@ -780,8 +780,8 @@ namespace System
|
|||
Debug.Assert((uint)newSize <= cSizeFlags);
|
||||
Internal.MemCpy(newPtr, Ptr, mLength);
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
mPtr = newPtr;
|
||||
delete:this mPtrOrBuffer;
|
||||
mPtrOrBuffer = newPtr;
|
||||
mAllocSizeAndFlags = (uint_strsize)newSize | cDynAllocFlag | cStrPtrFlag;
|
||||
}
|
||||
|
||||
|
@ -1313,7 +1313,7 @@ namespace System
|
|||
if (pos == len || (ch = format[pos]) < '0' || ch > '9')
|
||||
{
|
||||
if ((pos < len) &&
|
||||
((ch == '}') || (ch == ':')))
|
||||
((ch == '}') || (ch == ':') || (ch == ',')))
|
||||
index = autoArgIdx++;
|
||||
else
|
||||
return FormatError();
|
||||
|
@ -1603,8 +1603,8 @@ namespace System
|
|||
newPtr[outIdx] = '\0';
|
||||
|
||||
if (IsDynAlloc)
|
||||
delete mPtr;
|
||||
mPtr = newPtr;
|
||||
delete mPtrOrBuffer;
|
||||
mPtrOrBuffer = newPtr;
|
||||
mAllocSizeAndFlags = (uint_strsize)newSize | cDynAllocFlag | cStrPtrFlag;
|
||||
}
|
||||
}
|
||||
|
@ -1633,8 +1633,8 @@ namespace System
|
|||
int newLen = UTF8Map(Ptr, mLength, newStr, allocSize, (int32)unicodeNormalizationOptions);
|
||||
|
||||
if (IsDynAlloc)
|
||||
delete:this mPtr;
|
||||
mPtr = newStr;
|
||||
delete:this mPtrOrBuffer;
|
||||
mPtrOrBuffer = newStr;
|
||||
mLength = (int_strsize)newLen;
|
||||
mAllocSizeAndFlags = (uint32)(allocSize) | cDynAllocFlag | cStrPtrFlag;
|
||||
return .Ok;
|
||||
|
@ -1656,8 +1656,8 @@ namespace System
|
|||
int newLen = UTF8Map(Ptr, mLength, newStr, allocSize, (int32)unicodeNormalizationOptions);
|
||||
|
||||
if (destStr.IsDynAlloc)
|
||||
delete:destStr destStr.mPtr;
|
||||
destStr.mPtr = newStr;
|
||||
delete:destStr destStr.mPtrOrBuffer;
|
||||
destStr.mPtrOrBuffer = newStr;
|
||||
destStr.mLength = (int_strsize)newLen;
|
||||
destStr.mAllocSizeAndFlags = (uint_strsize)(newLen + 1) | cDynAllocFlag | cStrPtrFlag;
|
||||
return .Ok;
|
||||
|
@ -2059,7 +2059,7 @@ namespace System
|
|||
{
|
||||
if (mLength != str.[Friend]mLength)
|
||||
return false;
|
||||
return EqualsHelper(str.Ptr, mPtr, mLength);
|
||||
return EqualsHelper(str.Ptr, Ptr, mLength);
|
||||
}
|
||||
|
||||
public bool Equals(StringView str, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
|
@ -2067,8 +2067,8 @@ namespace System
|
|||
if (mLength != str.[Friend]mLength)
|
||||
return false;
|
||||
if (comparisonType == StringComparison.OrdinalIgnoreCase)
|
||||
return EqualsIgnoreCaseHelper(str.Ptr, mPtr, mLength);
|
||||
return EqualsHelper(str.Ptr, mPtr, mLength);
|
||||
return EqualsIgnoreCaseHelper(str.Ptr, Ptr, mLength);
|
||||
return EqualsHelper(str.Ptr, Ptr, mLength);
|
||||
}
|
||||
|
||||
public bool StartsWith(StringView b, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
|
@ -2488,6 +2488,56 @@ namespace System
|
|||
return StringSplitEnumerator(Ptr, Length, separators, count, options);
|
||||
}
|
||||
|
||||
public StringSplitEnumerator Split(char8[] separators, StringSplitOptions options)
|
||||
{
|
||||
return StringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView sv)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, sv, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView separator, int count)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separator, count, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView separator, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separator, Int32.MaxValue, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView separator, int count, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separator, count, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(params StringView[] separators)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators, int count)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, count, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators, int count, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, count, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, options);
|
||||
}
|
||||
|
||||
public static mixin NewOrSet(var target, var source)
|
||||
{
|
||||
if (target == null)
|
||||
|
@ -2914,11 +2964,11 @@ namespace System
|
|||
RemoveEmptyEntries = 1
|
||||
}
|
||||
|
||||
struct StringSplitEnumerator : IEnumerator<StringView>
|
||||
public struct StringSplitEnumerator : IEnumerator<StringView>
|
||||
{
|
||||
StringSplitOptions mSplitOptions;
|
||||
char8 mSplitChar0;
|
||||
char8[] mSplitChars;
|
||||
char8 mFirstSeparator;
|
||||
char8[] mSeparators;
|
||||
char8* mPtr;
|
||||
int_strsize mStrLen;
|
||||
int32 mCurCount;
|
||||
|
@ -2926,15 +2976,15 @@ namespace System
|
|||
int_strsize mPos;
|
||||
int_strsize mMatchPos;
|
||||
|
||||
public this(char8* ptr, int strLength, char8[] splitChars, int count, StringSplitOptions splitOptions)
|
||||
public this(char8* ptr, int strLength, char8[] separators, int count, StringSplitOptions splitOptions)
|
||||
{
|
||||
mPtr = ptr;
|
||||
mStrLen = (int_strsize)strLength;
|
||||
if (splitChars.Count > 0)
|
||||
mSplitChar0 = splitChars[0];
|
||||
if (separators?.Count > 0)
|
||||
mFirstSeparator = separators[0];
|
||||
else
|
||||
mSplitChar0 = '\0';
|
||||
mSplitChars = splitChars;
|
||||
mFirstSeparator = '\0';
|
||||
mSeparators = separators;
|
||||
mCurCount = 0;
|
||||
mMaxCount = (int32)count;
|
||||
mPos = 0;
|
||||
|
@ -2942,12 +2992,12 @@ namespace System
|
|||
mSplitOptions = splitOptions;
|
||||
}
|
||||
|
||||
public this(char8* ptr, int strLength, char8 splitChar, int count, StringSplitOptions splitOptions)
|
||||
public this(char8* ptr, int strLength, char8 separator, int count, StringSplitOptions splitOptions)
|
||||
{
|
||||
mPtr = ptr;
|
||||
mStrLen = (int_strsize)strLength;
|
||||
mSplitChar0 = splitChar;
|
||||
mSplitChars = null;
|
||||
mFirstSeparator = separator;
|
||||
mSeparators = null;
|
||||
mCurCount = 0;
|
||||
mMaxCount = (int32)count;
|
||||
mPos = 0;
|
||||
|
@ -3028,14 +3078,18 @@ namespace System
|
|||
else
|
||||
{
|
||||
char8 c = mPtr[mMatchPos];
|
||||
if (c == mSplitChar0)
|
||||
if (c.IsWhiteSpace && mFirstSeparator == '\0' && (mSeparators == null || mSeparators.IsEmpty))
|
||||
{
|
||||
foundMatch = true;
|
||||
}
|
||||
else if (mSplitChars != null)
|
||||
else if (c == mFirstSeparator)
|
||||
{
|
||||
for (int i = 1; i < mSplitChars.Count; i++)
|
||||
if (c == mSplitChars[i])
|
||||
foundMatch = true;
|
||||
}
|
||||
else if (mSeparators != null)
|
||||
{
|
||||
for (int i = 1; i < mSeparators.Count; i++)
|
||||
if (c == mSeparators[i])
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
|
@ -3070,6 +3124,179 @@ namespace System
|
|||
}
|
||||
}
|
||||
|
||||
public struct StringStringSplitEnumerator : IEnumerator<StringView>
|
||||
{
|
||||
StringSplitOptions mSplitOptions;
|
||||
StringView mFirstSeparator;
|
||||
StringView[] mSeparators;
|
||||
char8* mPtr;
|
||||
int_strsize mStrLen;
|
||||
int32 mCurCount;
|
||||
int32 mMaxCount;
|
||||
int_strsize mPos;
|
||||
int_strsize mMatchPos;
|
||||
int_strsize mMatchLen;
|
||||
|
||||
public this(char8* ptr, int strLength, StringView[] separators, int count, StringSplitOptions splitOptions)
|
||||
{
|
||||
mPtr = ptr;
|
||||
mStrLen = (int_strsize)strLength;
|
||||
if (separators?.Count > 0)
|
||||
mFirstSeparator = separators[0];
|
||||
else
|
||||
mFirstSeparator = .();
|
||||
mSeparators = separators;
|
||||
mCurCount = 0;
|
||||
mMaxCount = (int32)count;
|
||||
mPos = 0;
|
||||
mMatchPos = -1;
|
||||
mMatchLen = 1;
|
||||
mSplitOptions = splitOptions;
|
||||
}
|
||||
|
||||
public this(char8* ptr, int strLength, StringView separator, int count, StringSplitOptions splitOptions)
|
||||
{
|
||||
mPtr = ptr;
|
||||
mStrLen = (int_strsize)strLength;
|
||||
mFirstSeparator = separator;
|
||||
mSeparators = null;
|
||||
mCurCount = 0;
|
||||
mMaxCount = (int32)count;
|
||||
mPos = 0;
|
||||
mMatchPos = -1;
|
||||
mMatchLen = 1;
|
||||
mSplitOptions = splitOptions;
|
||||
}
|
||||
|
||||
public StringView Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return StringView(mPtr + mPos, mMatchPos - mPos);
|
||||
}
|
||||
}
|
||||
|
||||
public int_strsize Pos
|
||||
{
|
||||
get
|
||||
{
|
||||
return mPos;
|
||||
}
|
||||
}
|
||||
|
||||
public int_strsize MatchPos
|
||||
{
|
||||
get
|
||||
{
|
||||
return mMatchPos;
|
||||
}
|
||||
}
|
||||
|
||||
public int32 MatchIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return mCurCount - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasMore
|
||||
{
|
||||
get
|
||||
{
|
||||
return mMatchPos < mStrLen;
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext() mut
|
||||
{
|
||||
if (mCurCount >= mMaxCount)
|
||||
return false;
|
||||
|
||||
mPos = mMatchPos + mMatchLen;
|
||||
|
||||
mCurCount++;
|
||||
if (mCurCount == mMaxCount)
|
||||
{
|
||||
mMatchPos = (int_strsize)mStrLen;
|
||||
if (mPos > mMatchPos)
|
||||
return false;
|
||||
if ((mMatchPos == mPos) && (mSplitOptions.HasFlag(.RemoveEmptyEntries)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int endDiff = mStrLen - mMatchPos;
|
||||
if (endDiff == 0)
|
||||
return false;
|
||||
while (true)
|
||||
{
|
||||
mMatchPos++;
|
||||
endDiff--;
|
||||
bool foundMatch = false;
|
||||
if (endDiff == 0)
|
||||
{
|
||||
foundMatch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mFirstSeparator.IsNull && (mSeparators == null || mSeparators.IsEmpty) && mPtr[mMatchPos].IsWhiteSpace)
|
||||
{
|
||||
foundMatch = true;
|
||||
mMatchLen = 1;
|
||||
}
|
||||
else if (mFirstSeparator.Length <= mStrLen - mMatchPos && StringView(&mPtr[mMatchPos], mFirstSeparator.Length) == mFirstSeparator)
|
||||
{
|
||||
foundMatch = true;
|
||||
mMatchLen = (int_strsize)mFirstSeparator.Length;
|
||||
}
|
||||
else if (mSeparators != null)
|
||||
{
|
||||
for (int i = 1; i < mSeparators.Count; i++)
|
||||
{
|
||||
if (mSeparators[i].Length <= mStrLen - mMatchPos && StringView(&mPtr[mMatchPos], mSeparators[i].Length) == mSeparators[i])
|
||||
{
|
||||
foundMatch = true;
|
||||
mMatchLen = (int_strsize)mSeparators[i].Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundMatch)
|
||||
{
|
||||
if ((mMatchPos >= mPos + 1) || (!mSplitOptions.HasFlag(StringSplitOptions.RemoveEmptyEntries)))
|
||||
return true;
|
||||
mPos = mMatchPos + mMatchLen;
|
||||
if (mPos >= mStrLen)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMatchLen = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
mPos = 0;
|
||||
mMatchPos = -1;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Result<StringView> GetNext() mut
|
||||
{
|
||||
if (!MoveNext())
|
||||
return .Err;
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public struct StringView : Span<char8>, IFormattable, IPrintable, IHashable
|
||||
{
|
||||
public this()
|
||||
|
@ -3080,12 +3307,23 @@ namespace System
|
|||
|
||||
public this(String string)
|
||||
{
|
||||
if (string == null)
|
||||
{
|
||||
this = default;
|
||||
return;
|
||||
}
|
||||
mPtr = string.Ptr;
|
||||
mLength = string.Length;
|
||||
}
|
||||
|
||||
public this(String string, int offset)
|
||||
{
|
||||
if (string == null)
|
||||
{
|
||||
Debug.Assert(offset == 0);
|
||||
this = default;
|
||||
return;
|
||||
}
|
||||
Debug.Assert((uint)offset <= (uint)string.Length);
|
||||
mPtr = string.Ptr + offset;
|
||||
mLength = string.Length - offset;
|
||||
|
@ -3093,6 +3331,12 @@ namespace System
|
|||
|
||||
public this(String string, int offset, int length)
|
||||
{
|
||||
if (string == null)
|
||||
{
|
||||
Debug.Assert(offset == 0 && length == 0);
|
||||
this = default;
|
||||
return;
|
||||
}
|
||||
Debug.Assert((uint)offset + (uint)length <= (uint)string.Length);
|
||||
mPtr = string.Ptr + offset;
|
||||
mLength = length;
|
||||
|
@ -3120,6 +3364,12 @@ namespace System
|
|||
|
||||
public this(char8[] arr, int offset, int length)
|
||||
{
|
||||
if (arr == null)
|
||||
{
|
||||
Debug.Assert(offset == 0 && length == 0);
|
||||
this = default;
|
||||
return;
|
||||
}
|
||||
Debug.Assert((uint)offset + (uint)length <= (uint)arr.Count);
|
||||
mPtr = arr.CArray() + offset;
|
||||
mLength = length;
|
||||
|
@ -3127,13 +3377,23 @@ namespace System
|
|||
|
||||
public this(char8* ptr)
|
||||
{
|
||||
if (ptr == null)
|
||||
{
|
||||
this = default;
|
||||
return;
|
||||
}
|
||||
mPtr = ptr;
|
||||
mLength = String.StrLen(ptr);
|
||||
}
|
||||
|
||||
public this(char8* ptr, int length)
|
||||
|
||||
{
|
||||
if (ptr == null)
|
||||
{
|
||||
Debug.Assert(length == 0);
|
||||
this = default;
|
||||
return;
|
||||
}
|
||||
mPtr = ptr;
|
||||
mLength = length;
|
||||
}
|
||||
|
@ -3749,11 +4009,71 @@ namespace System
|
|||
return StringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringSplitEnumerator Split(char8[] separators, int count = Int32.MaxValue, StringSplitOptions options = .None)
|
||||
public StringSplitEnumerator Split(char8[] separators)
|
||||
{
|
||||
return StringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringSplitEnumerator Split(char8[] separators, int count)
|
||||
{
|
||||
return StringSplitEnumerator(Ptr, Length, separators, count, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringSplitEnumerator Split(char8[] separators, int count, StringSplitOptions options)
|
||||
{
|
||||
return StringSplitEnumerator(Ptr, Length, separators, count, options);
|
||||
}
|
||||
|
||||
public StringSplitEnumerator Split(char8[] separators, StringSplitOptions options)
|
||||
{
|
||||
return StringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView c)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, c, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView separator, int count)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separator, count, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView separator, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separator, Int32.MaxValue, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView separator, int count, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separator, count, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(params StringView[] separators)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators, int count)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, count, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators, int count, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, count, options);
|
||||
}
|
||||
|
||||
public StringStringSplitEnumerator Split(StringView[] separators, StringSplitOptions options)
|
||||
{
|
||||
return StringStringSplitEnumerator(Ptr, Length, separators, Int32.MaxValue, options);
|
||||
}
|
||||
|
||||
public String Intern()
|
||||
{
|
||||
using (String.[Friend]sMonitor.Enter())
|
||||
|
@ -3820,18 +4140,21 @@ namespace System
|
|||
public mixin ToScopedNativeWChar()
|
||||
{
|
||||
int encodedLen = UTF16.GetEncodedLen(this);
|
||||
char16* buf;
|
||||
c_wchar* buf;
|
||||
if (encodedLen < 128)
|
||||
{
|
||||
buf = scope:mixin char16[encodedLen+1]* ( ? );
|
||||
buf = scope:mixin c_wchar[encodedLen+1]* ( ? );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = new char16[encodedLen+1]* ( ? );
|
||||
buf = new c_wchar[encodedLen+1]* ( ? );
|
||||
defer:mixin delete buf;
|
||||
}
|
||||
|
||||
UTF16.Encode(this, buf, encodedLen);
|
||||
if (sizeof(c_wchar) == 2)
|
||||
UTF16.Encode(this, (.)buf, encodedLen);
|
||||
else
|
||||
UTF32.Encode(this, (.)buf, encodedLen);
|
||||
buf[encodedLen] = 0;
|
||||
buf
|
||||
}
|
||||
|
|
|
@ -20,8 +20,13 @@ namespace System.Threading
|
|||
private Object mThreadStartArg;
|
||||
|
||||
bool mAutoDelete;
|
||||
public static Thread sMainThread = new Thread() ~ delete _;
|
||||
|
||||
|
||||
static Monitor sMonitor = new .() ~ delete _;
|
||||
static Event<delegate void()> sOnExit ~ _.Dispose();
|
||||
Event<delegate void()> mOnExit ~ _.Dispose();
|
||||
|
||||
public static Thread sMainThread = new Thread() ~ delete _;
|
||||
|
||||
[StaticInitPriority(102)]
|
||||
struct RuntimeThreadInit
|
||||
{
|
||||
|
@ -62,6 +67,14 @@ namespace System.Threading
|
|||
return ((Thread)thread).mMaxStackSize;
|
||||
}
|
||||
|
||||
static void Thread_Exiting()
|
||||
{
|
||||
using (sMonitor.Enter())
|
||||
{
|
||||
sOnExit();
|
||||
}
|
||||
}
|
||||
|
||||
static void Thread_StartProc(Object threadObj)
|
||||
{
|
||||
Thread thread = (Thread)threadObj;
|
||||
|
@ -103,6 +116,7 @@ namespace System.Threading
|
|||
cb.[Friend]mThread_IsAutoDelete = => Thread_IsAutoDelete;
|
||||
cb.[Friend]mThread_AutoDelete = => Thread_AutoDelete;
|
||||
cb.[Friend]mThread_GetMaxStackSize = => Thread_GetMaxStackSize;
|
||||
cb.[Friend]mThread_Exiting = => Thread_Exiting;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,6 +192,38 @@ namespace System.Threading
|
|||
}
|
||||
}
|
||||
|
||||
public void AddExitNotify(delegate void() dlg)
|
||||
{
|
||||
using (sMonitor.Enter())
|
||||
{
|
||||
mOnExit.Add(dlg);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<void> RemovedExitNotify(delegate void() dlg, bool delegateDelegate = false)
|
||||
{
|
||||
using (sMonitor.Enter())
|
||||
{
|
||||
return mOnExit.Remove(dlg, delegateDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddGlobalExitNotify(delegate void() dlg)
|
||||
{
|
||||
using (sMonitor.Enter())
|
||||
{
|
||||
sOnExit.Add(dlg);
|
||||
}
|
||||
}
|
||||
|
||||
public static Result<void> RemoveGlobalExitNotify(delegate void() dlg, bool delegateDelegate = false)
|
||||
{
|
||||
using (sMonitor.Enter())
|
||||
{
|
||||
return sOnExit.Remove(dlg, delegateDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
extern void ManualThreadInit();
|
||||
extern void StartInternal();
|
||||
extern void SetStackStart(void* ptr);
|
||||
|
@ -217,6 +263,7 @@ namespace System.Threading
|
|||
}
|
||||
}
|
||||
|
||||
public static extern void RequestExitNotify();
|
||||
public extern void Suspend();
|
||||
public extern void Resume();
|
||||
|
||||
|
@ -316,9 +363,10 @@ namespace System.Threading
|
|||
}
|
||||
}
|
||||
|
||||
extern int32 GetThreadId();
|
||||
[CallingConvention(.Cdecl)]
|
||||
extern int GetThreadId();
|
||||
|
||||
public int32 Id
|
||||
public int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -326,6 +374,8 @@ namespace System.Threading
|
|||
}
|
||||
}
|
||||
|
||||
public static int CurrentThreadId => Platform.BfpThread_GetCurrentId();
|
||||
|
||||
[CallingConvention(.Cdecl)]
|
||||
private static extern Thread GetCurrentThreadNative();
|
||||
|
||||
|
@ -337,6 +387,12 @@ namespace System.Threading
|
|||
|
||||
public ~this()
|
||||
{
|
||||
using (sMonitor.Enter())
|
||||
{
|
||||
mOnExit();
|
||||
sOnExit();
|
||||
}
|
||||
|
||||
// Make sure we're not deleting manually if mAutoDelete is set
|
||||
Debug.Assert((!mAutoDelete) || (CurrentThread == this));
|
||||
// Delegate to the unmanaged portion.
|
||||
|
|
|
@ -196,5 +196,7 @@ namespace System
|
|||
{
|
||||
TimeSpanFormat.[Friend]Format(this, format, formatProvider, outStr);
|
||||
}
|
||||
|
||||
public static TimeSpan operator-(Self lhs, Self rhs) => .((int64)lhs - (int64)rhs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1942,7 +1942,8 @@ namespace System {
|
|||
}
|
||||
// the data returned from the PAL is completely bogus; return a dummy entry
|
||||
return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId);*/
|
||||
Runtime.NotImplemented();
|
||||
// TODO: Not implemented.
|
||||
return Utc;
|
||||
}
|
||||
#endif // !FEATURE_WIN32_REGISTRY
|
||||
|
||||
|
|
|
@ -852,7 +852,8 @@ namespace System.Reflection
|
|||
None = 0,
|
||||
Splat = 1,
|
||||
Implicit = 2,
|
||||
AppendIdx = 4
|
||||
AppendIdx = 4,
|
||||
Params = 8
|
||||
}
|
||||
|
||||
[CRepr, AlwaysInclude]
|
||||
|
@ -1479,6 +1480,7 @@ namespace System.Reflection
|
|||
EnumDiscriminator = 0x0200,
|
||||
EnumCase = 0x0400,
|
||||
ReadOnly = 0x0800,
|
||||
Appended = 0x1000,
|
||||
}
|
||||
|
||||
public enum MethodFlags : uint16
|
||||
|
|
|
@ -2,6 +2,7 @@ namespace System
|
|||
{
|
||||
struct ValueType
|
||||
{
|
||||
[NoShow(true)]
|
||||
public static extern bool Equals<T>(T val1, T val2);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue