* Corrects behaviour of llListSort() * Thanks DoranZemlja!0.6.3-post-fixes
parent
8b513beefa
commit
9dadf7adfd
|
@ -46,6 +46,7 @@ Patches
|
||||||
* ChrisDown
|
* ChrisDown
|
||||||
* Chris Yeoh
|
* Chris Yeoh
|
||||||
* Daedius
|
* Daedius
|
||||||
|
* DoranZemlja
|
||||||
* daTwitch
|
* daTwitch
|
||||||
* devalnor-#708
|
* devalnor-#708
|
||||||
* dmiles (Daxtron Labs)
|
* dmiles (Daxtron Labs)
|
||||||
|
|
|
@ -372,6 +372,11 @@ namespace OpenSim.Region.ScriptEngine.Shared
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double Mag(Quaternion q)
|
||||||
|
{
|
||||||
|
return Math.Sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.s * q.s);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static Quaternion operator +(Quaternion a, Quaternion b)
|
public static Quaternion operator +(Quaternion a, Quaternion b)
|
||||||
|
@ -742,95 +747,72 @@ namespace OpenSim.Region.ScriptEngine.Shared
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AlphanumComparatorFast : IComparer
|
private static int compare(object left, object right, int ascending)
|
||||||
{
|
{
|
||||||
public int Compare(object x, object y)
|
if (!left.GetType().Equals(right.GetType()))
|
||||||
{
|
{
|
||||||
string s1 = x as string;
|
// unequal types are always "equal" for comparison purposes.
|
||||||
if (s1 == null)
|
// this way, the bubble sort will never swap them, and we'll
|
||||||
{
|
// get that feathered effect we're looking for
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
string s2 = y as string;
|
|
||||||
if (s2 == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len1 = s1.Length;
|
int ret = 0;
|
||||||
int len2 = s2.Length;
|
|
||||||
int marker1 = 0;
|
|
||||||
int marker2 = 0;
|
|
||||||
|
|
||||||
// Walk through two the strings with two markers.
|
if (left is key)
|
||||||
while (marker1 < len1 && marker2 < len2)
|
{
|
||||||
{
|
key l = (key)left;
|
||||||
char ch1 = s1[marker1];
|
key r = (key)right;
|
||||||
char ch2 = s2[marker2];
|
ret = String.CompareOrdinal(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 LSLInteger)
|
||||||
|
{
|
||||||
|
LSLInteger l = (LSLInteger)left;
|
||||||
|
LSLInteger r = (LSLInteger)right;
|
||||||
|
ret = Math.Sign(l.value - r.value);
|
||||||
|
}
|
||||||
|
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.Mag(l) - Vector3.Mag(r));
|
||||||
|
}
|
||||||
|
else if (left is Quaternion)
|
||||||
|
{
|
||||||
|
Quaternion l = (Quaternion)left;
|
||||||
|
Quaternion r = (Quaternion)right;
|
||||||
|
ret = Math.Sign(Quaternion.Mag(l) - Quaternion.Mag(r));
|
||||||
|
}
|
||||||
|
|
||||||
// Some buffers we can build up characters in for each chunk.
|
if (ascending == 0)
|
||||||
char[] space1 = new char[len1];
|
{
|
||||||
int loc1 = 0;
|
ret = 0 - ret;
|
||||||
char[] space2 = new char[len2];
|
}
|
||||||
int loc2 = 0;
|
|
||||||
|
|
||||||
// Walk through all following characters that are digits or
|
return ret;
|
||||||
// characters in BOTH strings starting at the appropriate marker.
|
}
|
||||||
// Collect char arrays.
|
|
||||||
do
|
|
||||||
{
|
|
||||||
space1[loc1++] = ch1;
|
|
||||||
marker1++;
|
|
||||||
|
|
||||||
if (marker1 < len1)
|
class HomogeneousComparer : IComparer
|
||||||
{
|
{
|
||||||
ch1 = s1[marker1];
|
public HomogeneousComparer()
|
||||||
}
|
{
|
||||||
else
|
}
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
|
|
||||||
|
|
||||||
do
|
public int Compare(object lhs, object rhs)
|
||||||
{
|
{
|
||||||
space2[loc2++] = ch2;
|
return compare(lhs, rhs, 1);
|
||||||
marker2++;
|
|
||||||
|
|
||||||
if (marker2 < len2)
|
|
||||||
{
|
|
||||||
ch2 = s2[marker2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
|
|
||||||
|
|
||||||
// If we have collected numbers, compare them numerically.
|
|
||||||
// Otherwise, if we have strings, compare them alphabetically.
|
|
||||||
string str1 = new string(space1);
|
|
||||||
string str2 = new string(space2);
|
|
||||||
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
|
|
||||||
{
|
|
||||||
int thisNumericChunk = int.Parse(str1);
|
|
||||||
int thatNumericChunk = int.Parse(str2);
|
|
||||||
result = thisNumericChunk.CompareTo(thatNumericChunk);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = str1.CompareTo(str2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len1 - len2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,68 +821,70 @@ namespace OpenSim.Region.ScriptEngine.Shared
|
||||||
if (Data.Length == 0)
|
if (Data.Length == 0)
|
||||||
return new list(); // Don't even bother
|
return new list(); // Don't even bother
|
||||||
|
|
||||||
string[] keys;
|
object[] ret = new object[Data.Length];
|
||||||
|
Array.Copy(Data, 0, ret, 0, Data.Length);
|
||||||
|
|
||||||
if (stride == 1) // The simple case
|
if (stride <= 0)
|
||||||
{
|
{
|
||||||
Object[] ret=new Object[Data.Length];
|
stride = 1;
|
||||||
|
|
||||||
Array.Copy(Data, 0, ret, 0, Data.Length);
|
|
||||||
|
|
||||||
keys=new string[Data.Length];
|
|
||||||
|
|
||||||
for (int k = 0; k < Data.Length; k++)
|
|
||||||
keys[k] = Data[k].ToString();
|
|
||||||
|
|
||||||
Array.Sort( keys, ret, new AlphanumComparatorFast() );
|
|
||||||
|
|
||||||
if (ascending == 0)
|
|
||||||
Array.Reverse(ret);
|
|
||||||
return new list(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int src=0;
|
// we can optimize here in the case where stride == 1 and the list
|
||||||
|
// consists of homogeneous types
|
||||||
|
|
||||||
int len=(Data.Length+stride-1)/stride;
|
if (stride == 1)
|
||||||
|
|
||||||
keys=new string[len];
|
|
||||||
Object[][] vals=new Object[len][];
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
while (src < Data.Length)
|
|
||||||
{
|
{
|
||||||
Object[] o=new Object[stride];
|
bool homogeneous = true;
|
||||||
|
int index;
|
||||||
for (i = 0; i < stride; i++)
|
for (index = 1; index < Data.Length; index++)
|
||||||
{
|
{
|
||||||
if (src < Data.Length)
|
if (!Data[0].GetType().Equals(Data[index].GetType()))
|
||||||
o[i]=Data[src++];
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
o[i]=new Object();
|
homogeneous = false;
|
||||||
src++;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx=src/stride-1;
|
if (homogeneous)
|
||||||
keys[idx]=o[0].ToString();
|
{
|
||||||
vals[idx]=o;
|
Array.Sort(ret, new HomogeneousComparer());
|
||||||
|
if (ascending == 0)
|
||||||
|
{
|
||||||
|
Array.Reverse(ret);
|
||||||
|
}
|
||||||
|
return new list(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.Sort(keys, vals, new AlphanumComparatorFast());
|
// Because of the desired type specific feathered sorting behavior
|
||||||
if (ascending == 0)
|
// requried by the spec, we MUST use a non-optimized bubble sort here.
|
||||||
|
// Anything else will give you the incorrect behavior.
|
||||||
|
|
||||||
|
// begin bubble sort...
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
int k;
|
||||||
|
int n = Data.Length;
|
||||||
|
|
||||||
|
for (i = 0; i < (n-stride); i += stride)
|
||||||
{
|
{
|
||||||
Array.Reverse(vals);
|
for (j = i + stride; j < n; j += stride)
|
||||||
|
{
|
||||||
|
if (compare(ret[i], ret[j], ascending) > 0)
|
||||||
|
{
|
||||||
|
for (k = 0; k < stride; k++)
|
||||||
|
{
|
||||||
|
object tmp = ret[i + k];
|
||||||
|
ret[i + k] = ret[j + k];
|
||||||
|
ret[j + k] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object[] sorted=new Object[stride*vals.Length];
|
// end bubble sort
|
||||||
|
|
||||||
for (i = 0; i < vals.Length; i++)
|
return new list(ret);
|
||||||
for (int j = 0; j < stride; j++)
|
|
||||||
sorted[i*stride+j] = vals[i][j];
|
|
||||||
|
|
||||||
return new list(sorted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region CSV Methods
|
#region CSV Methods
|
||||||
|
|
Loading…
Reference in New Issue