From 35962d8c3987d989d323feef7be0b21045ec1e2e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 29 Apr 2023 11:06:35 +0100 Subject: [PATCH] add llListFindStrided; llListFindList change to be more as spec --- .../Shared/Api/Implementation/LSL_Api.cs | 209 +++++++++++++++--- .../Shared/Api/Interface/ILSL_Api.cs | 1 + .../Shared/Api/Runtime/LSL_Stub.cs | 6 + .../Region/ScriptEngine/Shared/LSL_Types.cs | 99 ++++++--- 4 files changed, 249 insertions(+), 66 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c90a30d5f5..dc21473b9c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -5596,6 +5596,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 0; object o = src.Data[index]; + if (o is null) + return 0; if (o is LSL_Integer || o is Int32) return 1; if (o is LSL_Float || o is Single || o is Double) @@ -5611,9 +5613,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (o is LSL_List) return 7; return 0; - } + /// /// Process the supplied list and return the /// content of the list formatted as a comma @@ -6021,6 +6023,105 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } + private bool ListFind_areEqual(object l, object r) + { + if (l is null || r is null) + return false; + + if (l is LSL_Integer lli) + { + if (r is LSL_Integer rli) + return lli.value == rli.value; + if (r is int ri) + return lli.value == ri; + return false; + } + + if (l is int li) + { + if (r is LSL_Integer rli) + return li == rli.value; + if (r is int ri) + return li == ri; + return false; + } + + if (l is LSL_Float llf) + { + if (r is LSL_Float rlf) + return llf.value == rlf.value; + if (r is float rf) + return llf.value == (double)rf; + if (r is double rd) + return llf.value == rd; + return false; + } + if (l is double ld) + { + if (r is LSL_Float rlf) + return ld == rlf.value; + if (r is float rf) + return ld == (double)rf; + if (r is double rd) + return ld == rd; + return false; + } + if (l is float lf) + { + if (r is LSL_Float rlf) + return lf == (float)rlf.value; + if (r is float rf) + return lf == rf; + if (r is double rd) + return lf == (float)rd; + return false; + } + + if (l is LSL_String lls) + { + if (r is LSL_String rls) + return lls.m_string.Equals(rls.m_string, StringComparison.Ordinal); + if (r is string rs) + return lls.m_string.Equals(rs, StringComparison.Ordinal); + return false; + } + + if (l is string ls) + { + if (r is LSL_String rls) + return ls.Equals(rls.m_string, StringComparison.Ordinal); + if (r is string rs) + return ls.Equals(rs, StringComparison.Ordinal); + if (r is LSL_Key rlk) + return ls.Equals(rlk.m_string, StringComparison.OrdinalIgnoreCase); + return false; + } + + if(l is LSL_Key llk) + { + if (r is LSL_Key rlk) + return llk.m_string.Equals(rlk.m_string, StringComparison.OrdinalIgnoreCase); + if (r is string rk) + return llk.m_string.Equals(rk, StringComparison.OrdinalIgnoreCase); + } + + if (l is LSL_Vector llv) + { + if(r is LSL_Vector rlv) + return llv.Equals(rlv); + return false; + } + + if (l is LSL_Rotation llr) + { + if(r is LSL_Rotation rlr) + return llr.Equals(rlr); + return false; + } + + return false; + } + /// /// Returns the index of the first occurrence of test /// in src. @@ -6033,45 +6134,89 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Integer llListFindList(LSL_List src, LSL_List test) { - int index = -1; - int length = src.Length - test.Length + 1; + if (src.Length == 0) + return -1; + if (test.Length == 0) + return 0; + if (test.Length > src.Length) + return -1; - - // If either list is empty, do not match - if (src.Length != 0 && test.Length != 0) + object test0 = test[0]; + for (int i = 0; i <= src.Length - test.Length; i++) { - for (int i = 0; i < length; i++) + if (ListFind_areEqual(test0, src[i])) { - int needle = llGetListEntryType(test, 0).value; - int haystack = llGetListEntryType(src, i).value; - - // Why this piece of insanity? This is because most script constants are C# value types (e.g. int) - // rather than wrapped LSL types. Such a script constant does not have int.Equal(LSL_Integer) code - // and so the comparison fails even if the LSL_Integer conceptually has the same value. - // Therefore, here we test Equals on both the source and destination objects. - // However, a future better approach may be use LSL struct script constants (e.g. LSL_Integer(1)). - if ((needle == haystack) && (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i]))) + int k = i + 1; + int j = 1; + while(j < test.Length) { - int j; - for (j = 1; j < test.Length; j++) - { - needle = llGetListEntryType(test, j).value; - haystack = llGetListEntryType(src, i+j).value; - - if ((needle != haystack) || (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j])))) - break; - } - - if (j == test.Length) - { - index = i; + if (!ListFind_areEqual(test[j], src[k])) break; - } + ++j; + ++k; } + + if (j == test.Length) + return i; + } + } + return -1; + } + + public LSL_Integer llListFindStrided(LSL_List src, LSL_List test, LSL_Integer lstart, LSL_Integer lend, LSL_Integer lstride) + { + if (src.Length == 0) + return -1; + if (test.Length == 0) + return 0; + if (test.Length > src.Length) + return -1; + + int start = lstart.value; + if (start < 0) + { + start += src.Length; + if (start < 0) + return -1; + } + else if (start >= src.Length) + return -1; + + int end = lend.value; + if (end < 0) + { + end += src.Length; + if (end < 0) + return -1; + end -= test.Length - 1; + } + else if (end >= src.Length) + end = src.Length - test.Length; + + int stride = lstride.value; + if (stride < 1) + stride = 1; + + object test0 = test[0]; + for (int i = start; i <= end; i += stride) + { + if (ListFind_areEqual(test0, src[i])) + { + int k = i + 1; + int j = 1; + while (j < test.Length) + { + if (!ListFind_areEqual(test[j], src[k])) + break; + ++j; + ++k; + } + + if (j == test.Length) + return i; } } - - return index; + return -1; } public LSL_String llGetObjectName() diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index f5488ec489..87c13b04db 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -256,6 +256,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llListenControl(int number, int active); void llListenRemove(int number); LSL_Integer llListFindList(LSL_List src, LSL_List test); + LSL_Integer llListFindStrided(LSL_List src, LSL_List test, LSL_Integer lstart, LSL_Integer lend, LSL_Integer lstride); LSL_List llListInsertList(LSL_List dest, LSL_List src, int start); LSL_List llListRandomize(LSL_List src, int stride); LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 332b13c145..6e424c6500 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -1262,6 +1262,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llListFindList(src, test); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_Integer llListFindStrided(LSL_List src, LSL_List test, LSL_Integer lstart, LSL_Integer lend, LSL_Integer lstride) + { + return m_LSL_Functions.llListFindStrided(src, test, lstart, lend, lstride); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public LSL_List llListInsertList(LSL_List dest, LSL_List src, int start) { diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index fc58716ef2..f2783c814c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -824,32 +824,35 @@ namespace OpenSim.Region.ScriptEngine.Shared foreach (object o in m_data) { - if (o is LSL_Types.LSLInteger) - size += 4; - else if (o is LSL_Types.LSLFloat) - size += 8; - else if (o is LSL_Types.LSLString lso) - size += lso.m_string is null ? 0 : lso.m_string.Length * sizeof(char); - else if (o is LSL_Types.key ko) - size += ko.value.Length; - else if (o is LSL_Types.Vector3) - size += 32; - else if (o is LSL_Types.Quaternion) - size += 64; - else if (o is int) - size += 4; - else if (o is uint) - size += 4; - else if (o is string so) - size += so.Length * sizeof(char); - else if (o is float) - size += 8; - else if (o is double) - size += 16; - else if (o is list lo) - size += lo.Size; - else - throw new Exception("Unknown type in List.Size: " + o.GetType().ToString()); + // here modern sugar alternatives with switch or switch statement generate crap code on dotnet6 + if (o is null) // this explicit test does improve release jit code, otherwise it is present on ALL its + throw new Exception("null entry in List.Size"); + else if (o is LSL_Types.LSLInteger) + size += sizeof(int); + else if (o is LSL_Types.LSLFloat) + size += sizeof(double); + else if (o is LSL_Types.LSLString lso) + size += lso.m_string is null ? 0 : lso.m_string.Length * sizeof(char); + else if (o is LSL_Types.key ko) + size += ko.value.Length; + else if (o is LSL_Types.Vector3) + size += 3 * sizeof(double); + else if (o is LSL_Types.Quaternion) + size += 4 * sizeof(double); + else if (o is int) + size += sizeof(int); + else if (o is uint) + size += sizeof(uint); + else if (o is string so) + size += so.Length * sizeof(char); + else if (o is float) + size += sizeof(float); + else if (o is double) + size += sizeof(double); + else if (o is list lo) + size += lo.Size; + else + throw new Exception("Unknown type in List.Size: " + o.GetType().ToString()); } return size; } @@ -1133,6 +1136,22 @@ namespace OpenSim.Region.ScriptEngine.Shared m_data = tmp; } + public object this[int i] + { + get + { + if(m_data is null || i >= m_data.Length) + return null; + return m_data[i]; + } + set + { + if (m_data is null || i >= m_data.Length) + return; + m_data[i] = value; + } + } + public static implicit operator Boolean(list l) { return l.Length != 0; @@ -1358,6 +1377,9 @@ namespace OpenSim.Region.ScriptEngine.Shared private static int compare(object left, object right, bool ascending) { + if(left is null) + return 0; + if (!left.GetType().Equals(right.GetType())) { // unequal types are always "equal" for comparison purposes. @@ -1415,6 +1437,9 @@ namespace OpenSim.Region.ScriptEngine.Shared public int Compare(object left, object right) { + if (left is null) + return 0; + int ret; if (left is LSLInteger il) { @@ -1455,27 +1480,30 @@ namespace OpenSim.Region.ScriptEngine.Shared private static bool needSwapAscending(object left, object right) { + if (left is null) + return false; + if (left is LSLInteger li) { LSLInteger r = (LSLInteger)right; return li.value > r.value; } - else if (left is LSLString lsl) + if (left is LSLString lsl) { LSLString r = (LSLString)right; return string.CompareOrdinal(lsl.m_string, r.m_string) > 0; } - else if (left is LSLFloat lf) + if (left is LSLFloat lf) { LSLFloat r = (LSLFloat)right; return lf.value > r.value; } - else if (left is Vector3 lv) + if (left is Vector3 lv) { Vector3 r = (Vector3)right; return Vector3.MagSquare(lv) > Vector3.MagSquare(r); } - else if (left is key lk) + if (left is key lk) { key r = (key)right; return string.CompareOrdinal(lk.value, r.value) > 0; @@ -1485,27 +1513,30 @@ namespace OpenSim.Region.ScriptEngine.Shared private static bool needSwapDescending(object left, object right) { + if (left is null) + return false; + if (left is LSLInteger li) { LSLInteger r = (LSLInteger)right; return li.value < r.value; } - else if (left is LSLString lsl) + if (left is LSLString lsl) { LSLString r = (LSLString)right; return string.CompareOrdinal(lsl.m_string, r.m_string) < 0; } - else if (left is LSLFloat lf) + if (left is LSLFloat lf) { LSLFloat r = (LSLFloat)right; return lf.value < r.value; } - else if (left is Vector3 lv) + if (left is Vector3 lv) { Vector3 r = (Vector3)right; return Vector3.MagSquare(lv) < Vector3.MagSquare(r); } - else if (left is key lk) + if (left is key lk) { key r = (key)right; return string.CompareOrdinal(lk.value, r.value) < 0;