diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 6230788692..f8b5165cbc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -679,7 +679,7 @@ namespace OpenSim.Region.ScriptEngine.Shared get { if (m_data == null) - m_data=new Object[0]; + m_data=new object[0]; return m_data.Length; } } @@ -689,11 +689,11 @@ namespace OpenSim.Region.ScriptEngine.Shared get { if (m_data == null) - m_data=new Object[0]; + return 0; int size = 0; - foreach (Object o in m_data) + foreach (object o in m_data) { if (o is LSL_Types.LSLInteger) size += 4; @@ -730,7 +730,7 @@ namespace OpenSim.Region.ScriptEngine.Shared { get { if (m_data == null) - m_data=new Object[0]; + m_data=new object[0]; return m_data; } @@ -765,131 +765,106 @@ namespace OpenSim.Region.ScriptEngine.Shared /// public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) { - if (Data[itemIndex] is LSL_Types.LSLInteger) - { - return (LSL_Types.LSLInteger)Data[itemIndex]; - } - else if (Data[itemIndex] is Int32) - { - return new LSL_Types.LSLFloat((int)Data[itemIndex]); - } - else if (Data[itemIndex] is float) - { - return new LSL_Types.LSLFloat((float)Data[itemIndex]); - } - else if (Data[itemIndex] is Double) - { - return new LSL_Types.LSLFloat((Double)Data[itemIndex]); - } - else if (Data[itemIndex] is LSL_Types.LSLString) - { - return new LSL_Types.LSLFloat(Data[itemIndex].ToString()); - } - else - { - return (LSL_Types.LSLFloat)Data[itemIndex]; - } + object o = Data[itemIndex]; + if (o is LSL_Types.LSLInteger) + return (LSL_Types.LSLInteger)o; + if (o is Int32) + return new LSL_Types.LSLFloat((int)o); + if (o is float) + return new LSL_Types.LSLFloat((float)o); + if (o is Double) + return new LSL_Types.LSLFloat((Double)o); + if (o is LSL_Types.LSLString) + return new LSL_Types.LSLFloat(o.ToString()); + return (LSL_Types.LSLFloat)o; } public LSL_Types.LSLString GetLSLStringItem(int itemIndex) { - if (Data[itemIndex] is LSL_Types.key) - { - return (LSL_Types.key)Data[itemIndex]; - } - else - { - return new LSL_Types.LSLString(Data[itemIndex].ToString()); - } + object o = Data[itemIndex]; + if (o is LSL_Types.key) + return (LSL_Types.key)o; + return new LSL_Types.LSLString(o.ToString()); } public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) { - if (Data[itemIndex] is LSL_Types.LSLInteger) - return (LSL_Types.LSLInteger)Data[itemIndex]; - if (Data[itemIndex] is LSL_Types.LSLFloat) - return new LSLInteger((int)Data[itemIndex]); - else if (Data[itemIndex] is Int32) - return new LSLInteger((int)Data[itemIndex]); - else if (Data[itemIndex] is LSL_Types.LSLString) - return new LSLInteger(Data[itemIndex].ToString()); - else - throw new InvalidCastException(string.Format( - "{0} expected but {1} given", - typeof(LSL_Types.LSLInteger).Name, - Data[itemIndex] != null ? - Data[itemIndex].GetType().Name : "null")); + object o = Data[itemIndex]; + if (o is LSL_Types.LSLInteger) + return (LSL_Types.LSLInteger)o; + if (o is LSL_Types.LSLFloat) + return new LSLInteger((int)o); + if (o is Int32) + return new LSLInteger((int)o); + if (o is LSL_Types.LSLString) + return new LSLInteger(o.ToString()); + + throw new InvalidCastException(string.Format( + "{0} expected but {1} given", + typeof(LSL_Types.LSLInteger).Name, + o != null ? + o.GetType().Name : "null")); } public LSL_Types.Vector3 GetVector3Item(int itemIndex) { - if (Data[itemIndex] is LSL_Types.Vector3) - { - return (LSL_Types.Vector3)Data[itemIndex]; - } - else if(Data[itemIndex] is OpenMetaverse.Vector3) - { - return new LSL_Types.Vector3( - (OpenMetaverse.Vector3)Data[itemIndex]); - } - else - { - throw new InvalidCastException(string.Format( - "{0} expected but {1} given", - typeof(LSL_Types.Vector3).Name, - Data[itemIndex] != null ? - Data[itemIndex].GetType().Name : "null")); - } + object o = Data[itemIndex]; + if (o is LSL_Types.Vector3) + return (LSL_Types.Vector3)o; + if(o is OpenMetaverse.Vector3) + return new LSL_Types.Vector3((OpenMetaverse.Vector3)o); + + throw new InvalidCastException(string.Format( + "{0} expected but {1} given", + typeof(LSL_Types.Vector3).Name, + o != null ? + o.GetType().Name : "null")); } // use LSL_Types.Quaternion to parse and store a vector4 for lightShare public LSL_Types.Quaternion GetVector4Item(int itemIndex) { - if (Data[itemIndex] is LSL_Types.Quaternion) + object o = Data[itemIndex]; + if (o is LSL_Types.Quaternion) { - LSL_Types.Quaternion q = (LSL_Types.Quaternion)Data[itemIndex]; + LSL_Types.Quaternion q = (LSL_Types.Quaternion)o; return q; } - else if(Data[itemIndex] is OpenMetaverse.Quaternion) + if(o is OpenMetaverse.Quaternion) { - LSL_Types.Quaternion q = new LSL_Types.Quaternion( - (OpenMetaverse.Quaternion)Data[itemIndex]); + LSL_Types.Quaternion q = new LSL_Types.Quaternion((OpenMetaverse.Quaternion)o); q.Normalize(); return q; } - else - { - throw new InvalidCastException(string.Format( - "{0} expected but {1} given", - typeof(LSL_Types.Quaternion).Name, - Data[itemIndex] != null ? - Data[itemIndex].GetType().Name : "null")); - } + + throw new InvalidCastException(string.Format( + "{0} expected but {1} given", + typeof(LSL_Types.Quaternion).Name, + o != null ? + o.GetType().Name : "null")); } public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) { - if (Data[itemIndex] is LSL_Types.Quaternion) + object o = Data[itemIndex]; + if (o is LSL_Types.Quaternion) { - LSL_Types.Quaternion q = (LSL_Types.Quaternion)Data[itemIndex]; + LSL_Types.Quaternion q = (LSL_Types.Quaternion)o; q.Normalize(); return q; } - else if(Data[itemIndex] is OpenMetaverse.Quaternion) + if(o is OpenMetaverse.Quaternion) { - LSL_Types.Quaternion q = new LSL_Types.Quaternion( - (OpenMetaverse.Quaternion)Data[itemIndex]); + LSL_Types.Quaternion q = new LSL_Types.Quaternion((OpenMetaverse.Quaternion)o); q.Normalize(); return q; } - else - { - throw new InvalidCastException(string.Format( + + throw new InvalidCastException(string.Format( "{0} expected but {1} given", typeof(LSL_Types.Quaternion).Name, Data[itemIndex] != null ? Data[itemIndex].GetType().Name : "null")); - } } public LSL_Types.key GetKeyItem(int itemIndex) @@ -909,10 +884,18 @@ namespace OpenSim.Region.ScriptEngine.Shared private void ExtendAndAdd(object o) { object[] tmp; - tmp = new object[Data.Length + 1]; - Data.CopyTo(tmp, 0); - tmp.SetValue(o, tmp.Length - 1); - Data = tmp; + if(m_data == null || m_data.Length == 0) + { + tmp = new object[1]; + tmp.SetValue(o, 0); + } + else + { + tmp = new object[m_data.Length + 1]; + m_data.CopyTo(tmp, 0); + tmp.SetValue(o, tmp.Length - 1); + } + m_data = tmp; } public static implicit operator Boolean(list l) @@ -965,24 +948,30 @@ namespace OpenSim.Region.ScriptEngine.Shared public void Add(object o) { object[] tmp; - tmp = new object[Data.Length + 1]; - Data.CopyTo(tmp, 0); - tmp[Data.Length] = o; // Since this is tmp.Length - 1 - Data = tmp; + if(m_data == null || m_data.Length == 0) + { + tmp = new object[1]; + tmp[0] = o; + } + else + { + tmp = new object[m_data.Length + 1]; + m_data.CopyTo(tmp, 0); + tmp[m_data.Length] = o; // Since this is tmp.Length - 1 + } + m_data = tmp; } public bool Contains(object o) { - bool ret = false; - foreach (object i in Data) + if (m_data == null) + return false; + foreach (object i in m_data) { if (i == o) - { - ret = true; - break; - } + return true; } - return ret; + return false; } public list DeleteSublist(int start, int end) @@ -991,67 +980,69 @@ namespace OpenSim.Region.ScriptEngine.Shared // If start <= end, remove that part // if either is negative, count from the end of the array // if the resulting start > end, keep [end + 1, start - 1] + if(m_data == null || m_data.Length == 0) + return new list(new object[0]); + int len = m_data.Length; object[] ret; if (start < 0) - start=Data.Length + start; - + start= len + start; if (start < 0) start=0; if (end < 0) - end=Data.Length + end; + end= len + end; if (end < 0) end=0; if (start > end) { end++; - if (end >= Data.Length) + if (end >= len) return new list(new object[0]); start--; - if (start >= Data.Length) - start = Data.Length - 1; + if (start >= len) + start = len - 1; int num = start - end + 1; if(num <= 0) return new list(new object[0]); ret = new object[num]; - Array.Copy(Data, end, ret, 0, num); + Array.Copy(m_data, end, ret, 0, num); return new list(ret); } // start >= 0 && end >= 0 here - if (start >= Data.Length) + if (start >= len) { - ret = new object[Data.Length]; - Array.Copy(Data, 0, ret, 0, Data.Length); + ret = new object[len]; + Array.Copy(m_data, 0, ret, 0, len); return new list(ret); } - if (end >= Data.Length) - end = Data.Length-1; + if (end >= len) + end = len - 1; end++; // now, this makes the math easier int remove = end - start; - if(remove >= Data.Length) + if(remove >= len) return new list(new object[0]); - ret = new object[Data.Length - remove]; + ret = new object[len - remove]; if (start > 0) - Array.Copy(Data, 0, ret, 0, start); + Array.Copy(m_data, 0, ret, 0, start); - if(end >= Data.Length) + if(end >= len) return new list(ret); - Array.Copy(Data, end, ret, start, Data.Length - end); + Array.Copy(m_data, end, ret, start, len - end); return new list(ret); } @@ -1132,7 +1123,6 @@ namespace OpenSim.Region.ScriptEngine.Shared { return this; } - } else { @@ -1206,42 +1196,155 @@ namespace OpenSim.Region.ScriptEngine.Shared class HomogeneousComparer : IComparer { + //both sides known to be of same type private readonly bool ascending; public HomogeneousComparer(bool ascend) { ascending = ascend; } - public int Compare(object lhs, object rhs) + public int Compare(object left, object right) { - return compare(lhs, rhs, ascending); + int ret = 0; + if (left is LSLInteger) + { + LSLInteger l = (LSLInteger)left; + LSLInteger r = (LSLInteger)right; + ret = Math.Sign(l.value - r.value); + } + else if (left is LSLString) + { + LSLString l = (LSLString)left; + LSLString r = (LSLString)right; + ret = string.CompareOrdinal(l.m_string, r.m_string); + } + else if (left is LSLFloat) + { + LSLFloat l = (LSLFloat)left; + LSLFloat r = (LSLFloat)right; + ret = Math.Sign(l.value - r.value); + } + else if (left is Vector3) + { + Vector3 l = (Vector3)left; + Vector3 r = (Vector3)right; + ret = Math.Sign(Vector3.MagSquare(l) - Vector3.MagSquare(r)); + } + else if (left is key) + { + key l = (key)left; + key r = (key)right; + ret = string.CompareOrdinal(l.value, r.value); + } + else //if (left is Quaternion) and unknown types + { + return 0; + } + + if (ascending) + return ret; + + return -ret; } } + private static bool needSwapAscending(object left, object right) + { + if (left is LSLInteger) + { + LSLInteger l = (LSLInteger)left; + LSLInteger r = (LSLInteger)right; + return l.value > r.value; + } + else if (left is LSLString) + { + LSLString l = (LSLString)left; + LSLString r = (LSLString)right; + return string.CompareOrdinal(l.m_string, r.m_string) > 0; + } + else if (left is LSLFloat) + { + LSLFloat l = (LSLFloat)left; + LSLFloat r = (LSLFloat)right; + return l.value > r.value; + } + else if (left is Vector3) + { + Vector3 l = (Vector3)left; + Vector3 r = (Vector3)right; + return Vector3.MagSquare(l) > Vector3.Mag(r); + } + else if (left is key) + { + key l = (key)left; + key r = (key)right; + return string.CompareOrdinal(l.value, r.value) > 0; + } + return false; + } + + private static bool needSwapDescending(object left, object right) + { + if (left is LSLInteger) + { + LSLInteger l = (LSLInteger)left; + LSLInteger r = (LSLInteger)right; + return l.value < r.value; + } + else if (left is LSLString) + { + LSLString l = (LSLString)left; + LSLString r = (LSLString)right; + return string.CompareOrdinal(l.m_string, r.m_string) < 0; + } + else if (left is LSLFloat) + { + LSLFloat l = (LSLFloat)left; + LSLFloat r = (LSLFloat)right; + return l.value < r.value; + } + else if (left is Vector3) + { + Vector3 l = (Vector3)left; + Vector3 r = (Vector3)right; + return Vector3.MagSquare(l) < Vector3.MagSquare(r); + } + else if (left is key) + { + key l = (key)left; + key r = (key)right; + return string.CompareOrdinal(l.value, r.value) < 0; + } + return false; + } + public list Sort(int stride, bool ascending) { - if (Data.Length == 0) + if (m_data == null || m_data.Length == 0) return new list(); // Don't even bother - object[] ret = new object[Data.Length]; - Array.Copy(Data, 0, ret, 0, Data.Length); + object[] ret = new object[m_data.Length]; + Array.Copy(m_data, 0, ret, 0, m_data.Length); if (stride <= 0) stride = 1; - if ((ret.Length % stride) != 0) + if ((ret.Length <= stride) || (ret.Length % stride) != 0) return new list(ret); - // we can optimize here in the case where stride == 1 and the list - // consists of homogeneous types + // if list does not consists of homogeneous types + // and because of the desired type specific feathered sorting behavior + // requeried by the spec, we MUST use a non-optimized bubble sort + // Anything else will give you the incorrect behavior. + // we can optimize the case where stride == 1 if (stride == 1) { bool homogeneous = true; Type firstType = ret[0].GetType(); - for (int index = 1; index < ret.Length; index++) + for (int i = 1; i < ret.Length; ++i) { - if (!firstType.Equals(ret[index].GetType())) + if (!firstType.Equals(ret[i].GetType())) { homogeneous = false; break; @@ -1249,36 +1352,105 @@ namespace OpenSim.Region.ScriptEngine.Shared } if (homogeneous) - { + // big boost using native Sort with its faster sorting methods. Array.Sort(ret, new HomogeneousComparer(ascending)); - return new list(ret); + else + { + if (ascending) + { + for (int i = 0; i < ret.Length - 1; ++i) + { + object pivot = ret[i]; + Type pivotType = pivot.GetType(); + for (int j = i + 1; j < ret.Length; ++j) + { + object tmp = ret[j]; + if (tmp.GetType() == pivotType && needSwapAscending(pivot, tmp)) + { + ret[j] = pivot; + ret[i] = tmp; + pivot = tmp; + } + } + } + } + else + { + for (int i = 0; i < ret.Length - 1; ++i) + { + object pivot = ret[i]; + Type pivotType = pivot.GetType(); + for (int j = i + 1; j < ret.Length; ++j) + { + object tmp = ret[j]; + if (tmp.GetType() == pivotType && needSwapDescending(pivot, tmp)) + { + ret[j] = pivot; + ret[i] = tmp; + pivot = tmp; + for (int k = 1; k < stride; k++) + { + tmp = ret[i + k]; + ret[i + k] = ret[j + k]; + ret[j + k] = tmp; + } + } + } + } + } } + return new list(ret); } - // Because of the desired type specific feathered sorting behavior - // requried by the spec, we MUST use a non-optimized bubble sort here. - // Anything else will give you the incorrect behavior. - for (int i = 0; i < ret.Length - stride; i += stride) + if (ascending) { - object o = ret[i]; - for (int j = i + stride; j < ret.Length; j += stride) + for (int i = 0; i < ret.Length - stride; i += stride) { - if (compare(o, ret[j], ascending) > 0) + object pivot = ret[i]; + Type pivotType = pivot.GetType(); + for (int j = i + stride; j < ret.Length; j += stride) { - ret[i] = ret[j]; - ret[j] = o; - o = ret[i]; - for (int k = 1; k < stride; k++) + object tmp = ret[j]; + if (tmp.GetType() == pivotType && needSwapAscending(pivot, tmp)) { - object tmp = ret[i + k]; - ret[i + k] = ret[j + k]; - ret[j + k] = tmp; + ret[j] = pivot; + ret[i] = tmp; + pivot = tmp; + for (int k = 1; k < stride; k++) + { + tmp = ret[i + k]; + ret[i + k] = ret[j + k]; + ret[j + k] = tmp; + } + } + } + } + } + else + { + for (int i = 0; i < ret.Length - stride; i += stride) + { + object pivot = ret[i]; + Type pivotType = pivot.GetType(); + for (int j = i + stride; j < ret.Length; j += stride) + { + object tmp = ret[j]; + if (tmp.GetType() == pivotType && needSwapDescending(pivot, tmp)) + { + ret[j] = pivot; + ret[i] = tmp; + pivot = tmp; + for (int k = 1; k < stride; k++) + { + tmp = ret[i + k]; + ret[i + k] = ret[j + k]; + ret[j + k] = tmp; + } } } } } - // end bubble sort return new list(ret); } @@ -1348,7 +1520,7 @@ namespace OpenSim.Region.ScriptEngine.Shared double entry; for (int i = 0; i < Data.Length; i++) { - if (double.TryParse(Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) + if (double.TryParse(m_data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) { if (entry < minimum) minimum = entry; } @@ -1362,7 +1534,7 @@ namespace OpenSim.Region.ScriptEngine.Shared double entry; for (int i = 0; i < Data.Length; i++) { - if (double.TryParse(Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) + if (double.TryParse(m_data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) { if (entry > maximum) maximum = entry; } @@ -1381,7 +1553,7 @@ namespace OpenSim.Region.ScriptEngine.Shared double entry; for (int i = 0; i < Data.Length; i++) { - if (double.TryParse(Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) + if (double.TryParse(m_data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) { count++; } @@ -1395,7 +1567,7 @@ namespace OpenSim.Region.ScriptEngine.Shared double entry; for (int i = 0; i < src.Data.Length; i++) { - if (double.TryParse(src.Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) + if (double.TryParse(src.m_data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) { ret.Add(entry); } @@ -1409,7 +1581,7 @@ namespace OpenSim.Region.ScriptEngine.Shared double entry; for (int i = 0; i < Data.Length; i++) { - if (double.TryParse(Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) + if (double.TryParse(m_data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) { sum = sum + entry; } @@ -1423,7 +1595,7 @@ namespace OpenSim.Region.ScriptEngine.Shared double entry; for (int i = 0; i < Data.Length; i++) { - if (double.TryParse(Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) + if (double.TryParse(m_data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) { sum = sum + Math.Pow(entry, 2); }