1
0
Fork 0
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:
Simon Lübeß 2022-08-13 18:02:49 +02:00
commit 6884b9fc21
267 changed files with 26197 additions and 17792 deletions

View file

@ -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;

View file

@ -170,7 +170,7 @@ namespace Beefy
if (autoRetry)
{
if (fileOpenErr == .SharingViolation)
retry = true;
retry = i != 99;
}
if (!retry)
return .Err(.OpenError(fileOpenErr));

View file

@ -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]))

View file

@ -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)

View file

@ -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;

View file

@ -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)]

View file

@ -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)
{

View 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;
}
}
}
}

View file

@ -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)
{

View file

@ -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
{

View file

@ -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
{

View file

@ -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

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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");
}
}
}

View file

@ -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
View 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");
}
}
}

View file

@ -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)
{

View file

@ -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

View file

@ -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,

View file

@ -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;

View file

@ -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
{

View file

@ -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;

View file

@ -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();

View file

@ -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

View file

@ -276,6 +276,7 @@ namespace System
public void RemoveFromEnd(int length) mut
{
Debug.Assert((uint)length <= (uint)mLength);
mLength -= length;
}

View file

@ -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
}

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -2,6 +2,7 @@ namespace System
{
struct ValueType
{
[NoShow(true)]
public static extern bool Equals<T>(T val1, T val2);
}
}