[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog server/array.cpp server/array.h...
From: |
Sandro Santilli |
Subject: |
[Gnash-commit] gnash ChangeLog server/array.cpp server/array.h... |
Date: |
Sun, 29 Jul 2007 12:57:01 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Sandro Santilli <strk> 07/07/29 12:57:01
Modified files:
. : ChangeLog
server : array.cpp array.h
testsuite/actionscript.all: array.as
Log message:
Patch #6124 by address@hidden:
* server/array.{cpp,h}: implement remaining array.sort(..)
functionality
(flags UNIQUE and RETURNINDEXEDARRAY) all of array.sortOn(...)
* testsuite/actionscript.all/array.as: test for Array.sort and
Array.sortOn
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.3858&r2=1.3859
http://cvs.savannah.gnu.org/viewcvs/gnash/server/array.cpp?cvsroot=gnash&r1=1.66&r2=1.67
http://cvs.savannah.gnu.org/viewcvs/gnash/server/array.h?cvsroot=gnash&r1=1.30&r2=1.31
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/array.as?cvsroot=gnash&r1=1.21&r2=1.22
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.3858
retrieving revision 1.3859
diff -u -b -r1.3858 -r1.3859
--- ChangeLog 29 Jul 2007 12:45:24 -0000 1.3858
+++ ChangeLog 29 Jul 2007 12:57:00 -0000 1.3859
@@ -1,5 +1,12 @@
2007-07-29 <address@hidden>
+ * server/array.{cpp,h}: implement remaining array.sort(..) functionality
+ (flags UNIQUE and RETURNINDEXEDARRAY) all of array.sortOn(...)
+ * testsuite/actionscript.all/array.as: test for Array.sort and
+ Array.sortOn
+
+2007-07-29 <address@hidden>
+
* server/array.cpp: Fix bug in the array.splice(index) method to
prevent an incorrect number of elements being spliced; fix bug
in the array.slice(startindex, endindex) method for certain
Index: server/array.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/array.cpp,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -b -r1.66 -r1.67
--- server/array.cpp 29 Jul 2007 12:45:25 -0000 1.66
+++ server/array.cpp 29 Jul 2007 12:57:01 -0000 1.67
@@ -29,6 +29,7 @@
#include "fn_call.h"
#include "GnashException.h"
#include "action.h" // for call_method
+#include "VM.h" // for PROPNAME macro to work
#include <string>
#include <algorithm>
@@ -40,91 +41,239 @@
namespace gnash {
+typedef bool (* as_cmp_fn) (const as_value&, const as_value&);
+
static as_object* getArrayInterface();
static void attachArrayProperties(as_object& proto);
static void attachArrayInterface(as_object& proto);
-// Default as_value strict weak comparator (string based)
-class AsValueLessThen
+inline static bool int_lt_or_eq (int a)
+{
+ return a <= 0;
+}
+
+inline static bool int_gt (int a)
+{
+ return a > 0;
+}
+
+// simple as_value strict-weak-ordering comparison functions:
+inline static bool
+as_value_lt (const as_value& a, const as_value& b)
{
-public:
- bool operator() (const as_value& a, const as_value& b)
- {
return a.to_string().compare(b.to_string()) < 0;
- }
-};
+}
-// Default descending as_value strict weak comparator (string based)
-class AsValueLessThenDesc
+inline static bool
+as_value_gt (const as_value& a, const as_value& b)
{
-public:
- bool operator() (const as_value& a, const as_value& b)
- {
return a.to_string().compare(b.to_string()) > 0;
- }
-};
+}
-// Case-insensitive as_value strict weak comparator (string)
-class AsValueLessThenNoCase
+inline static bool
+as_value_eq (const as_value& a, const as_value& b)
+{
+ return a.to_string().compare(b.to_string()) == 0;
+}
+
+inline static int
+as_value_StrNoCaseCmp (const as_value& a, const as_value& b)
{
-public:
- bool operator() (const as_value& a, const as_value& b)
- {
using namespace boost::algorithm;
std::string strA = to_upper_copy(a.to_string());
std::string strB = to_upper_copy(b.to_string());
- return strA.compare(strB) < 0;
- }
-};
+ return strA.compare(strB);
+}
-// Descending Case-insensitive as_value strict weak comparator (string)
-class AsValueLessThenDescNoCase
+inline static bool
+as_value_nocase_lt (const as_value& a, const as_value& b)
{
-public:
- bool operator() (const as_value& a, const as_value& b)
- {
- using namespace boost::algorithm;
+ return as_value_StrNoCaseCmp(a, b) < 0;
+}
- std::string strA = to_upper_copy(a.to_string());
- std::string strB = to_upper_copy(b.to_string());
+inline static bool
+as_value_nocase_gt (const as_value& a, const as_value& b)
+{
+ return as_value_StrNoCaseCmp(a, b) > 0;
+}
- return strA.compare(strB) > 0;
- }
-};
+inline static bool
+as_value_nocase_eq (const as_value& a, const as_value& b)
+{
+ return as_value_StrNoCaseCmp(a, b) == 0;
+}
-// Numeric as_value strict weak comparator
-class AsValueLessThenNumeric
+inline static bool
+as_value_numLT (const as_value& a, const as_value& b)
{
-public:
- bool operator() (const as_value& a, const as_value& b)
+ if (a.is_undefined()) return false;
+ if (b.is_undefined()) return true;
+ if (a.is_null()) return false;
+ if (b.is_null()) return true;
+ double aval = a.to_number();
+ double bval = b.to_number();
+ if (isnan(aval)) return false;
+ if (isnan(bval)) return true;
+ return aval < bval;
+}
+
+inline static bool
+as_value_numGT (const as_value& a, const as_value& b)
+{
+ if (b.is_undefined()) return false;
+ if (a.is_undefined()) return true;
+ if (b.is_null()) return false;
+ if (a.is_null()) return true;
+ double aval = a.to_number();
+ double bval = b.to_number();
+ if (isnan(bval)) return false;
+ if (isnan(aval)) return true;
+ return aval > bval;
+}
+
+inline static bool
+as_value_numEQ (const as_value& a, const as_value& b)
+{
+ if (a.is_undefined() && b.is_undefined()) return true;
+ if (a.is_null() && b.is_null()) return true;
+ double aval = a.to_number();
+ double bval = b.to_number();
+ if (isnan(aval) && isnan(bval)) return true;
+ return aval == bval;
+}
+
+inline static bool
+as_value_num_lt (const as_value& a, const as_value& b)
+{
+ if (a.is_string() || b.is_string())
+ return as_value_lt(a, b);
+ return as_value_numLT(a, b);
+}
+
+inline static bool
+as_value_num_gt (const as_value& a, const as_value& b)
+{
+ if (a.is_string() || b.is_string())
+ return as_value_gt(a, b);
+ return as_value_numGT(a, b);
+}
+
+inline static bool
+as_value_num_eq (const as_value& a, const as_value& b)
+{
+ if (a.is_string() || b.is_string())
+ return as_value_eq(a, b);
+ return as_value_numEQ(a, b);
+}
+
+inline static bool
+as_value_num_nocase_lt (const as_value& a, const as_value& b)
+{
+ if (a.is_string() || b.is_string())
+ return as_value_nocase_lt(a, b);
+ return as_value_numLT(a, b);
+}
+
+inline static bool
+as_value_num_nocase_gt (const as_value& a, const as_value& b)
+{
+ if (a.is_string() || b.is_string())
+ return as_value_nocase_gt(a, b);
+ return as_value_numGT(a, b);
+}
+
+inline static bool
+as_value_num_nocase_eq (const as_value& a, const as_value& b)
+{
+ if (a.is_string() || b.is_string())
+ return as_value_nocase_eq(a, b);
+ return as_value_numEQ(a, b);
+}
+
+// Return basic as_value comparison function for corresponding sort flag
+// Note:
+// fUniqueSort and fReturnIndexedArray must first be stripped from the flag
+static as_cmp_fn
+get_basic_cmp(uint8_t flags)
+{
+ switch ( flags )
{
- return ( a.to_number() < b.to_number() );
+ case 0:
+ return &as_value_lt;
+
+ case as_array_object::fDescending:
+ return &as_value_gt;
+
+ case as_array_object::fCaseInsensitive:
+ return &as_value_nocase_lt;
+
+ case as_array_object::fCaseInsensitive |
+ as_array_object::fDescending:
+ return &as_value_nocase_gt;
+
+ case as_array_object::fNumeric:
+ return &as_value_num_lt;
+
+ case as_array_object::fNumeric | as_array_object::fDescending:
+ return &as_value_num_gt;
+
+ case as_array_object::fCaseInsensitive |
+ as_array_object::fNumeric:
+ return &as_value_num_nocase_lt;
+
+ case as_array_object::fCaseInsensitive |
+ as_array_object::fNumeric |
+ as_array_object::fDescending:
+ return &as_value_num_nocase_gt;
+
+ default:
+ log_error(_("Unhandled sort flags: %d (0x%X)"), flags,
flags);
+ return &as_value_lt;
}
-};
+}
-// Descending Numeric as_value strict weak comparator
-class AsValueLessThenDescNumeric
+// Return basic as_value equality function for corresponding sort flag
+// Note:
+// fUniqueSort and fReturnIndexedArray must first be stripped from the flag
+static as_cmp_fn
+get_basic_eq(uint8_t flags)
{
-public:
- bool operator() (const as_value& a, const as_value& b)
+ flags &= ~(as_array_object::fDescending);
+ switch ( flags )
{
- return ( a.to_number() > b.to_number() );
- }
-};
+ case 0: // default string comparison
+ return &as_value_eq;
+
+ case as_array_object::fCaseInsensitive:
+ return &as_value_nocase_eq;
+
+ case as_array_object::fNumeric:
+ return &as_value_num_eq;
+
+ case as_array_object::fCaseInsensitive |
+ as_array_object::fNumeric:
+ return &as_value_num_nocase_eq;
+ default:
+ return &as_value_eq;
+ }
+}
// Custom (ActionScript) comparator
-class AsValueFuncComparator
+class as_value_custom
{
public:
as_function& _comp;
as_object* _object;
+ bool (*_zeroCmp)(const int);
- AsValueFuncComparator(as_function& comparator,
boost::intrusive_ptr<as_object> this_ptr)
+ as_value_custom(as_function& comparator, bool (*zc)(const int),
+ boost::intrusive_ptr<as_object> this_ptr)
:
- _comp(comparator)
+ _comp(comparator),
+ _zeroCmp(zc)
{
_object = this_ptr.get();
}
@@ -134,18 +283,152 @@
as_value cmp_method(&_comp);
as_environment env;
as_value ret(0);
- int retval;
env.push(a);
env.push(b);
ret = call_method(cmp_method, &env, _object, 2, 1);
- retval = (int)ret.to_number();
- if (retval > 0) return true;
+ return (*_zeroCmp)((int)ret.to_number());
+ }
+};
+
+// Comparator for sorting on a single array property
+class as_value_prop
+{
+public:
+ as_cmp_fn _comp;
+ const std::string& _prop;
+
+ // Note: cmpfn must implement a strict weak ordering
+ as_value_prop(const std::string& name,
+ as_cmp_fn cmpfn)
+ :
+ _comp(cmpfn),
+ _prop(name)
+ {
+ }
+
+ bool operator() (const as_value& a, const as_value& b)
+ {
+ as_value av, bv;
+ boost::intrusive_ptr<as_object> ao = a.to_object();
+ boost::intrusive_ptr<as_object> bo = b.to_object();
+
+ ao->get_member(_prop, &av);
+ bo->get_member(_prop, &bv);
+ return (*_comp)(av, bv);
+ }
+};
+
+
+// Comparator for sorting on multiple array properties
+class as_value_multiprop
+{
+public:
+ const as_cmp_fn* _cmps;
+ std::deque<std::string>::const_iterator _pBegin, _pEnd, pit;
+
+ // Note: all as_cmp_fns in *cmps must implement strict weak ordering
+ as_value_multiprop(std::deque<std::string>::const_iterator pBegin,
+ std::deque<std::string>::const_iterator pEnd,
+ as_cmp_fn* cmps)
+ :
+ _pBegin(pBegin), _pEnd(pEnd)
+ {
+ _cmps = cmps;
+ }
+
+ bool operator() (const as_value& a, const as_value& b)
+ {
+ const as_cmp_fn* cmp = _cmps;
+
+ for (pit = _pBegin; pit != _pEnd; ++pit, ++cmp)
+ {
+ as_value av, bv;
+ boost::intrusive_ptr<as_object> ao = a.to_object();
+ boost::intrusive_ptr<as_object> bo = b.to_object();
+ ao->get_member(*pit, &av);
+ bo->get_member(*pit, &bv);
+
+ if ( (*cmp)(av, bv) ) return true;
+ if ( (*cmp)(bv, av) ) return false;
+ // Note: for loop finishes only if a == b for
+ // each requested comparison
+ // (since *cmp(av,bv) == *cmp(bv,av) == false)
+ }
+
return false;
}
};
-// @@ TODO : implement as_array_object's unimplemented functions
+class as_value_multiprop_eq : public as_value_multiprop
+{
+public:
+ as_value_multiprop_eq(std::deque<std::string>::const_iterator pBegin,
+ std::deque<std::string>::const_iterator pEnd,
+ as_cmp_fn* eq)
+ : as_value_multiprop(pBegin, pEnd, eq)
+ {
+ }
+
+ bool operator() (const as_value& a, const as_value& b)
+ {
+ const as_cmp_fn* cmp = _cmps;
+
+ for (pit = _pBegin; pit != _pEnd; ++pit, ++cmp)
+ {
+ as_value av, bv;
+ boost::intrusive_ptr<as_object> ao = a.to_object();
+ boost::intrusive_ptr<as_object> bo = b.to_object();
+ ao->get_member(*pit, &av);
+ bo->get_member(*pit, &bv);
+
+ if ( !(*cmp)(av, bv) ) return false;
+ }
+
+ return true;
+ }
+};
+
+// Convenience function to strip fUniqueSort and fReturnIndexedArray from sort
+// flag. Presence of flags recorded in douniq and doindex.
+static inline uint8_t
+flag_preprocess(uint8_t flgs, bool* douniq, bool* doindex)
+{
+ *douniq = (flgs & as_array_object::fUniqueSort);
+ *doindex = (flgs & as_array_object::fReturnIndexedArray);
+ flgs &= ~(as_array_object::fReturnIndexedArray);
+ flgs &= ~(as_array_object::fUniqueSort);
+ return flgs;
+}
+
+// Convenience function to process and extract flags from an as_value array
+// of flags (as passed to sortOn when sorting on multiple properties)
+static void
+get_multi_flags(std::deque<as_value>::const_iterator itBegin,
+ std::deque<as_value>::const_iterator itEnd,
+ uint8_t* flgs, bool* uniq, bool* index)
+{
+ std::deque<as_value>::const_iterator it = itBegin;
+ int i = 0;
+
+ // extract fUniqueSort and fReturnIndexedArray from first flag
+ if (it != itEnd)
+ {
+ uint8_t flag = static_cast<uint8_t>((*it).to_number());
+ flag = flag_preprocess(flag, uniq, index);
+ flgs[i++] = flag;
+ ++it;
+ }
+
+ while (it != itEnd)
+ {
+ uint8_t flag = static_cast<uint8_t>((*it).to_number());
+ flag &= ~(as_array_object::fReturnIndexedArray);
+ flag &= ~(as_array_object::fUniqueSort);
+ flgs[i++] = flag;
+ ++it;
+ }
+}
as_array_object::as_array_object()
:
@@ -172,6 +455,32 @@
{
}
+std::deque<indexed_as_value>
+as_array_object::get_indexed_elements()
+{
+ std::deque<indexed_as_value> indexed_elements;
+ int i = 0;
+
+ for (std::deque<as_value>::const_iterator it = elements.begin();
+ it != elements.end(); ++it)
+ {
+ indexed_elements.push_back(indexed_as_value(*it, i++));
+ }
+ return indexed_elements;
+}
+
+std::deque<as_value>::const_iterator
+as_array_object::begin()
+{
+ return elements.begin();
+}
+
+std::deque<as_value>::const_iterator
+as_array_object::end()
+{
+ return elements.end();
+}
+
int
as_array_object::index_requested(const std::string& name)
{
@@ -422,91 +731,17 @@
as_object::set_member_default(name,val);
}
-std::auto_ptr<as_array_object>
-as_array_object::sorted_indexes(uint8_t flags)
-{
- assert(flags & as_array_object::fReturnIndexedArray);
- log_unimpl("Array.sorted_index");
- return std::auto_ptr<as_array_object>(NULL);
-}
-
-void
-as_array_object::sort(uint8_t flags)
+as_array_object*
+as_array_object::get_indices(std::deque<indexed_as_value> elems)
{
+ as_array_object* intIndexes = new as_array_object();
- // use sorted_index to use this flag
- assert( ! (flags & as_array_object::fReturnIndexedArray) );
-
- bool do_unique = (flags & as_array_object::fUniqueSort);
-
- // strip the UniqueSort flag, we'll use the do_unique later
- flags &= ~(as_array_object::fUniqueSort);
-
- switch ( flags )
+ for (std::deque<indexed_as_value>::const_iterator it = elems.begin();
+ it != elems.end(); ++it)
{
- case 0: // default sorting
- //log_msg(_("Default sorting"));
- std::sort(elements.begin(), elements.end(),
- AsValueLessThen());
- break;
-
- case as_array_object::fDescending:
- //log_msg(_("Default descending"));
- std::sort(elements.begin(), elements.end(),
- AsValueLessThenDesc());
- break;
-
- case as_array_object::fCaseInsensitive:
- //log_msg(_("case insensitive"));
- std::sort(elements.begin(), elements.end(),
- AsValueLessThenNoCase());
- break;
-
- case as_array_object::fCaseInsensitive |
as_array_object::fDescending:
- //log_msg(_("case insensitive descending"));
- std::sort(elements.begin(), elements.end(),
- AsValueLessThenDescNoCase());
- break;
-
- case as_array_object::fNumeric:
- //log_msg(_("numeric"));
- std::sort(elements.begin(), elements.end(),
- AsValueLessThenNumeric());
- break;
-
- case as_array_object::fNumeric | as_array_object::fDescending:
- //log_msg(_("numeric descending"));
- std::sort(elements.begin(), elements.end(),
- AsValueLessThenDescNumeric());
- break;
-
- default:
- log_error(_("Unhandled sort flags: %d (0x%X)"), flags,
flags);
- break;
+ intIndexes->push(as_value(it->vec_index));
}
-
- // do the unique step afterwards to simplify code
- // (altought it's slower, but we can take care of this later)
- // TODO: use the do_unique variable inside the switch cases
- // to either use std::sort or std::uniq or similar
- if ( do_unique )
- {
- log_unimpl(_("array.sort with unique flag"));
- }
-}
-
-void
-as_array_object::sort(as_function& comparator, boost::intrusive_ptr<as_object>
this_ptr, uint8_t flags)
-{
-
- // use sorted_index to use this flag
- assert( ! (flags & as_array_object::fReturnIndexedArray) );
-
- // Other flags are simply NOT used
- // (or are them ? the descending one could be!)
- std::sort(elements.begin(), elements.end(),
- AsValueFuncComparator(comparator, this_ptr));
-
+ return intIndexes;
}
static as_value
@@ -579,47 +814,198 @@
static as_value
array_sort(const fn_call& fn)
{
- boost::intrusive_ptr<as_array_object> array =
ensureType<as_array_object>(fn.this_ptr);
-
+ boost::intrusive_ptr<as_array_object> array =
+ ensureType<as_array_object>(fn.this_ptr);
uint8_t flags = 0;
if ( fn.nargs == 0 )
{
- array->sort(flags);
+ array->sort(&as_value_lt);
+ return as_value((boost::intrusive_ptr<as_object>)array);
}
else if ( fn.nargs == 1 && fn.arg(0).is_number() )
{
flags=static_cast<uint8_t>(fn.arg(0).to_number());
- array->sort(flags);
}
else if ( fn.arg(0).is_as_function() )
{
// Get comparison function
as_function* as_func = fn.arg(0).to_as_function();
+ bool (*icmp)(int);
if ( fn.nargs == 2 && fn.arg(1).is_number() )
- {
flags=static_cast<uint8_t>(fn.arg(1).to_number());
- }
- array->sort(*as_func, fn.this_ptr, flags);
+
+ if (flags & as_array_object::fDescending) icmp = &int_lt_or_eq;
+ else icmp = &int_gt;
+
+ as_value_custom avc =
+ as_value_custom(*as_func, icmp, fn.this_ptr);
+
+ if ( (flags & as_array_object::fReturnIndexedArray) )
+ return as_value(array->sort_indexed(&avc));
+ array->sort(&avc);
+ return as_value((boost::intrusive_ptr<as_object>)array);
+ // note: custom AS function sorting apparently ignores the
+ // UniqueSort flag which is why it is also ignored here
}
else
{
IF_VERBOSE_ASCODING_ERRORS(
log_aserror(_("Sort called with invalid arguments."));
)
+ return as_value();
}
-
- return as_value(); // returns void
+ bool do_unique, do_index;
+ flags = flag_preprocess(flags, &do_unique, &do_index);
+ as_cmp_fn comp = get_basic_cmp(flags);
+
+ if (do_unique)
+ {
+ as_cmp_fn eq =
+ get_basic_eq(flags);
+ if (do_index) return array->sort_indexed(comp, eq);
+ return array->sort(comp, eq);
+ }
+ if (do_index) return as_value(array->sort_indexed(comp));
+ array->sort(comp);
+ return as_value((boost::intrusive_ptr<as_object>)array);
}
static as_value
array_sortOn(const fn_call& fn)
{
- boost::intrusive_ptr<as_array_object> array =
ensureType<as_array_object>(fn.this_ptr);
- UNUSED(array);
+ boost::intrusive_ptr<as_array_object> array =
+ ensureType<as_array_object>(fn.this_ptr);
+
+ // case: sortOn("prop")
+ if ( fn.nargs == 1 && fn.arg(0).is_string() )
+ {
+ std::string propField = PROPNAME(fn.arg(0).to_string());
+ as_value_prop avc = as_value_prop(propField, &as_value_lt);
+ array->sort(&avc);
+ return as_value((boost::intrusive_ptr<as_object>)array);
+ }
+
+ // case: sortOn("prop", Array.FLAG)
+ bool do_unique = false, do_index = false;
+ if ( fn.nargs == 2 && fn.arg(0).is_string() )
+ {
+ std::string propField = PROPNAME(fn.arg(0).to_string());
+ if ( fn.arg(1).is_number() )
+ {
+ uint8_t flags =
+ static_cast<uint8_t>(fn.arg(1).to_number());
+ flags = flag_preprocess(flags, &do_unique, &do_index);
+ as_value_prop avc = as_value_prop(propField,
+ get_basic_cmp(flags));
+ if (do_unique)
+ {
+ as_value_prop ave = as_value_prop(propField,
+ get_basic_eq(flags));
+ if (do_index)
+ return array->sort_indexed(&avc, &ave);
+ return array->sort(&avc, &ave);
+ }
+ if (do_index)
+ return as_value(array->sort_indexed(&avc));
+ array->sort(&avc);
+ return as_value((boost::intrusive_ptr<as_object>)array);
+ }
+ }
+
+ // case: sortOn(["prop1", "prop2"] ...)
+ if (fn.nargs > 0 && fn.arg(0).is_object() )
+ {
+ boost::intrusive_ptr<as_array_object> props =
+ ensureType<as_array_object>(fn.arg(0).to_object());
+ std::deque<std::string> prp;
+ unsigned int optnum = props->size();
+ as_cmp_fn cmp[optnum];
+ as_cmp_fn eq[optnum];
- log_unimpl("Array.sortOn()");
+ for (std::deque<as_value>::const_iterator it = props->begin();
+ it != props->end(); ++it)
+ {
+ std::string s = PROPNAME((*it).to_string());
+ prp.push_back(s);
+ }
+
+ // case: sortOn(["prop1", "prop2"])
+ if (fn.nargs == 1)
+ { // assign each cmp function to the standard cmp fn
+ for (unsigned int i = 0; i < optnum; i++)
+ cmp[i] = &as_value_lt;
+ }
+ // case: sortOn(["prop1", "prop2"], [Array.FLAG1, Array.FLAG2])
+ else if ( fn.arg(1).is_object() )
+ {
+ boost::intrusive_ptr<as_array_object> farray =
+
ensureType<as_array_object>(fn.arg(1).to_object());
+ if (farray->size() == optnum)
+ {
+ uint8_t flgs[optnum];
+ std::deque<as_value>::const_iterator
+ fBegin = farray->begin(),
+ fEnd = farray->end();
+
+ get_multi_flags(fBegin, fEnd, flgs,
+ &do_unique, &do_index);
+
+ for (unsigned int i = 0; i < optnum; i++)
+ cmp[i] = get_basic_cmp(flgs[i]);
+
+ if (do_unique)
+ {
+ for (unsigned int i = 0; i < optnum;
i++)
+ eq[i] = get_basic_eq(flgs[i]);
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < optnum; i++)
+ cmp[i] = &as_value_lt;
+ }
+ }
+ // case: sortOn(["prop1", "prop2"], Array.FLAG)
+ else if ( fn.arg(1).is_number() )
+ {
+ uint8_t flags =
+ static_cast<uint8_t>(fn.arg(1).to_number());
+ flag_preprocess(flags, &do_unique, &do_index);
+ as_cmp_fn c = get_basic_cmp(flags);
+
+ for (unsigned int i = 0; i < optnum; i++)
+ cmp[i] = c;
+
+ if (do_unique)
+ {
+ as_cmp_fn e = get_basic_eq(flags);
+ for (unsigned int i = 0; i < optnum; i++)
+ eq[i] = e;
+ }
+ }
+
+ as_value_multiprop avc =
+ as_value_multiprop(prp.begin(), prp.end(), cmp);
+
+ if (do_unique)
+ {
+ as_value_multiprop_eq ave =
+ as_value_multiprop_eq(prp.begin(), prp.end(),
eq);
+ if (do_index)
+ return array->sort_indexed(&avc, &ave);
+ return array->sort(&avc, &ave);
+ }
+ if (do_index)
+ return as_value(array->sort_indexed(&avc));
+ array->sort(&avc);
+ return as_value((boost::intrusive_ptr<as_object>)array);
+
+ }
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror(_("SortOn called with invalid arguments."));
+ )
return as_value();
}
Index: server/array.h
===================================================================
RCS file: /sources/gnash/gnash/server/array.h,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -b -r1.30 -r1.31
--- server/array.h 13 Jul 2007 01:13:46 -0000 1.30
+++ server/array.h 29 Jul 2007 12:57:01 -0000 1.31
@@ -38,6 +38,17 @@
namespace gnash {
+struct indexed_as_value : public as_value
+{
+ int vec_index;
+
+ indexed_as_value(const as_value& val, int index)
+ : as_value(val)
+ {
+ vec_index = index;
+ }
+};
+
/// The Array ActionScript object
class as_array_object : public as_object
{
@@ -53,7 +64,10 @@
/// Descending order (b precedes a)
fDescending = (1<<1), // 2
- /// Remove consecutive equal elements
+ /// If two or more elements in the array
+ /// have identical sort fields, return 0
+ /// and don't modify the array.
+ /// Otherwise proceed to sort the array.
fUniqueSort = (1<<2), // 4
/// Don't modify the array, rather return
@@ -71,6 +85,12 @@
~as_array_object();
+ std::deque<indexed_as_value> get_indexed_elements();
+
+ std::deque<as_value>::const_iterator begin();
+
+ std::deque<as_value>::const_iterator end();
+
void push(const as_value& val);
void unshift(const as_value& val);
@@ -81,6 +101,8 @@
as_value at(unsigned int index);
+ as_array_object* get_indices(std::deque<indexed_as_value> origElems);
+
void reverse();
/// @param env
@@ -152,17 +174,84 @@
std::auto_ptr<as_array_object> splice(unsigned start, unsigned len,
const std::vector<as_value>& replacement);
+ /// \brief
/// Sort the array, using given values comparator
- void sort(as_function& comparator, boost::intrusive_ptr<as_object>
this_ptr, uint8_t flags=0);
+ ///
+ /// @param avc
+ /// boolean functor or function comparing two as_value& objects
+ ///
+ template <class AVCMP>
+ void sort(AVCMP* avc)
+ {
+ std::sort(elements.begin(), elements.end(), *avc);
+ }
+
+ /// \brief
+ /// Attempt to sort the array using given values comparator, avc.
+ /// If two or more elements in the array are equal, as determined
+ /// by the equality comparator ave, then the array is not sorted
+ /// and 0 is returned. Otherwise the array is sorted and returned.
+ ///
+ /// @param avc
+ /// boolean functor or function comparing two as_value& objects
+ /// used to determine sort-order
+ ///
+ /// @param ave
+ /// boolean functor or function comparing two as_value& objects
+ /// used to determine equality
+ ///
+ template <class AVCMP, class AVEQ>
+ as_value sort(AVCMP* avc, AVEQ* ave)
+ {
+ std::deque<as_value> nelem = std::deque<as_value>(elements);
- void sort(uint8_t flags=0);
+ std::sort(nelem.begin(), nelem.end(), *avc);
+ if (adjacent_find(nelem.begin(), nelem.end(), *ave) !=
nelem.end() )
+ return as_value(0);
+ elements = nelem;
+ return as_value(this);
+ }
+
+ /// \brief
/// Return a new array containing sorted index of this array
- //
- /// NOTE: assert(flags & Array::fReturnIndexedArray)
- std::auto_ptr<as_array_object> sorted_indexes(uint8_t flags);
+ ///
+ /// @param avc
+ /// boolean functor or function comparing two as_value& objects
+ ///
+ template <class AVCMP>
+ as_array_object* sort_indexed(AVCMP* avc)
+ {
+ std::deque<indexed_as_value> ielem = get_indexed_elements();
+ std::sort(ielem.begin(), ielem.end(), *avc);
+ return get_indices(ielem);
+ }
+
+ /// \brief
+ /// Return a new array containing sorted index of this array.
+ /// If two or more elements in the array are equal, as determined
+ /// by the equality comparator ave, then 0 is returned instead.
+ ///
+ /// @param avc
+ /// boolean functor or function comparing two as_value& objects
+ /// used to determine sort-order
+ ///
+ /// @param ave
+ /// boolean functor or function comparing two as_value& objects
+ /// used to determine equality
+ ///
+ template <class AVCMP, class AVEQ>
+ as_value sort_indexed(AVCMP* avc, AVEQ* ave)
+ {
+ std::deque<indexed_as_value> ielem = get_indexed_elements();
+
+ std::sort(ielem.begin(), ielem.end(), *avc);
- std::auto_ptr<as_array_object> sorted_indexes(as_function& comparator,
uint8_t flags);
+ if (adjacent_find(ielem.begin(), ielem.end(), *ave) !=
ielem.end() )
+ return as_value(0);
+
+ return get_indices(ielem);
+ }
/// Overridden to provide 'length' member
//
Index: testsuite/actionscript.all/array.as
===================================================================
RCS file: /sources/gnash/gnash/testsuite/actionscript.all/array.as,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22
--- testsuite/actionscript.all/array.as 29 Jul 2007 12:45:25 -0000 1.21
+++ testsuite/actionscript.all/array.as 29 Jul 2007 12:57:01 -0000 1.22
@@ -5,7 +5,7 @@
// Updated with sort functions, and to use check() macro
// by Mike Carlson Feb. 14th, 2006
-rcsid="$Id: array.as,v 1.21 2007/07/29 12:45:25 strk Exp $";
+rcsid="$Id: array.as,v 1.22 2007/07/29 12:57:01 strk Exp $";
#include "check.as"
@@ -348,3 +348,430 @@
xcheck(c.hasOwnProperty('2'));
#endif
+//-------------------------------
+// Test sort
+//-------------------------------
+
+function cmp_fn(x,y)
+{
+ if (x.length < y.length) { return -1; }
+ if (x.length > y.length) { return 1; }
+ return 0;
+}
+
+function tolen(x)
+{
+ var i;
+ str = "[";
+ for (i = 0; i < x.length; i++)
+ {
+ str += String(x[i].length);
+ if (i != x.length - 1) str += ", ";
+ }
+ str += "]";
+ return str;
+}
+
+a = ["ed", "emacs", "", "vi", "nano", "Jedit"];
+b = [8, 1, -2, 5, -7, -9, 3, 0];
+c = [7.2, 2.0, -0.5, 3/0, 0.0, 8.35, 0.001, -3.7];
+d = [];
+e = ["singleton"];
+
+trace(" -- Basic Sort Tests -- ");
+
+r = a.sort( Array.NUMERIC );
+check_equals( r.toString(), ",Jedit,ed,emacs,nano,vi" );
+check_equals( a.toString(), ",Jedit,ed,emacs,nano,vi" );
+a.sort( Array.NUMERIC | Array.CASEINSENSITIVE );
+check_equals( a.toString(), ",ed,emacs,Jedit,nano,vi" );
+a.sort();
+check_equals( a.toString(), ",Jedit,ed,emacs,nano,vi" );
+a.sort( Array.CASEINSENSITIVE );
+check_equals( a.toString(), ",ed,emacs,Jedit,nano,vi" );
+a.sort( Array.UNIQUESORT );
+check_equals( a.toString(), ",Jedit,ed,emacs,nano,vi" );
+r = a.sort( Array.DESCENDING );
+check_equals( r.toString(), "vi,nano,emacs,ed,Jedit," );
+check_equals( a.toString(), "vi,nano,emacs,ed,Jedit," );
+
+r = b.sort();
+check_equals( r.toString(), "-2,-7,-9,0,1,3,5,8" );
+check_equals( b.toString(), "-2,-7,-9,0,1,3,5,8" );
+b.sort( Array.NUMERIC );
+check_equals( b.toString(), "-9,-7,-2,0,1,3,5,8" );
+b.sort( Array.UNIQUESORT );
+check_equals( b.toString(), "-2,-7,-9,0,1,3,5,8" );
+b.sort( Array.DESCENDING );
+check_equals( b.toString(), "8,5,3,1,0,-9,-7,-2" );
+r = b.sort( Array.DESCENDING | Array.NUMERIC );
+check_equals( r.toString(), "8,5,3,1,0,-2,-7,-9" );
+check_equals( b.toString(), "8,5,3,1,0,-2,-7,-9" );
+
+r = c.sort();
+check_equals( r.toString(), "-0.5,-3.7,0,0.001,2,7.2,8.35,Infinity" );
+check_equals( c.toString(), "-0.5,-3.7,0,0.001,2,7.2,8.35,Infinity" );
+c.sort( Array.CASEINSENSITIVE );
+check_equals( c.toString(), "-0.5,-3.7,0,0.001,2,7.2,8.35,Infinity" );
+c.sort( Array.NUMERIC );
+check_equals( c.toString(), "-3.7,-0.5,0,0.001,2,7.2,8.35,Infinity" );
+r = c.sort( Array.UNIQUESORT );
+check_equals( c.toString(), "-0.5,-3.7,0,0.001,2,7.2,8.35,Infinity" );
+r = c.sort( Array.DESCENDING | Array.NUMERIC );
+check_equals( c.toString(), "Infinity,8.35,7.2,2,0.001,0,-0.5,-3.7" );
+
+r = d.sort();
+check_equals( r.toString(), "" );
+check_equals( d.toString(), "" );
+d.sort( Array.UNIQUESORT );
+check_equals( d.toString(), "" );
+d.sort( Array.DESCENDING | Array.NUMERIC );
+check_equals( d.toString(), "" );
+
+r = e.sort();
+check_equals( r.toString(), "singleton" );
+check_equals( e.toString(), "singleton" );
+e.sort( Array.UNIQUESORT );
+check_equals( e.toString(), "singleton" );
+e.sort( Array.DESCENDING | Array.CASEINSENSITIVE );
+check_equals( e.toString(), "singleton" );
+
+trace(" -- Return Indexed Array Tests -- ");
+
+r = a.sort( Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "5,4,3,2,1,0" );
+check_equals( a.toString(), "vi,nano,emacs,ed,Jedit," );
+r = a.sort( Array.RETURNINDEXEDARRAY | Array.DESCENDING |
Array.CASEINSENSITIVE );
+check_equals( r.toString(), "0,1,4,2,3,5" );
+check_equals( a.toString(), "vi,nano,emacs,ed,Jedit," );
+r = b.sort( Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "5,6,7,4,3,2,1,0" );
+r = b.sort( Array.RETURNINDEXEDARRAY | Array.NUMERIC );
+check_equals( r.toString(), "7,6,5,4,3,2,1,0" );
+r = b.sort( Array.RETURNINDEXEDARRAY | Array.DESCENDING |
Array.CASEINSENSITIVE );
+check_equals( r.toString(), "0,1,2,3,4,7,6,5" );
+r = c.sort( Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "6,7,5,4,3,2,1,0" );
+r = c.sort( Array.RETURNINDEXEDARRAY | Array.NUMERIC );
+check_equals( r.toString(), "7,6,5,4,3,2,1,0" );
+r = c.sort( Array.RETURNINDEXEDARRAY | Array.DESCENDING |
Array.CASEINSENSITIVE );
+check_equals( r.toString(), "0,1,2,3,4,5,7,6" );
+r = d.sort( Array.RETURNINDEXEDARRAY | Array.DESCENDING );
+check_equals( r.toString(), "" );
+check_equals( d.toString(), "" );
+r = d.sort( Array.NUMERIC | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "" );
+check_equals( d.toString(), "" );
+r = e.sort( Array.CASEINSENSITIVE | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+check_equals( e.toString(), "singleton" );
+r = e.sort( Array.NUMERIC | Array.RETURNINDEXEDARRAY | Array.DESCENDING );
+check_equals( r.toString(), "0" );
+
+trace(" -- Custom AS function tests -- ");
+r = a.sort( cmp_fn, Array.UNIQUE );
+check_equals( r.toString(), ",vi,ed,nano,emacs,Jedit" );
+check_equals( a.toString(), ",vi,ed,nano,emacs,Jedit" );
+r = a.sort( something_undefined );
+check_equals(typeof(r), 'undefined');
+r = a.sort( cmp_fn, Array.DESCENDING );
+check_equals( tolen(r), "[5, 5, 4, 2, 2, 0]" );
+check_equals( tolen(a), "[5, 5, 4, 2, 2, 0]" );
+a.sort( cmp_fn, Array.CASEINSENSITIVE | Array.NUMERIC );
+check_equals( tolen(a), "[0, 2, 2, 4, 5, 5]" );
+r = a.sort( cmp_fn, Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0,1,2,3,4,5" );
+r = a.sort( cmp_fn, Array.RETURNINDEXEDARRAY | Array.DESCENDING );
+check_equals( r.toString(), "5,4,3,2,1,0" );
+r = d.sort( cmp_fn );
+check_equals( r.toString(), "" );
+check_equals( d.toString(), "" );
+r = d.sort( cmp_fn, Array.UNIQUESORT | Array.CASEINSENSITIVE );
+check_equals( r.toString(), "" );
+check_equals( d.toString(), "" );
+r = e.sort( cmp_fn, Array.UNIQUESORT | Array.CASEINSENSITIVE );
+check_equals( r.toString(), "singleton" );
+check_equals( e.toString(), "singleton" );
+
+a.push("ED");
+b.push(3.0);
+c.push(9/0);
+
+trace(" -- UNIQUESORT tests -- ");
+
+r = a.sort( Array.UNIQUESORT );
+check_equals( r.toString(), ",ED,Jedit,ed,emacs,nano,vi" );
+check_equals( a.toString(), ",ED,Jedit,ed,emacs,nano,vi" );
+r = a.sort( Array.UNIQUESORT | Array.CASEINSENSITIVE );
+check_equals( r.toString(), "0" );
+check_equals( a.toString(), ",ED,Jedit,ed,emacs,nano,vi" );
+r = a.sort( Array.UNIQUESORT | Array.CASEINSENSITIVE | Array.DESCENDING );
+check_equals( r.toString(), "0" );
+check_equals( a.toString(), ",ED,Jedit,ed,emacs,nano,vi" );
+r = a.sort( Array.UNIQUESORT | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0,1,2,3,4,5,6" );
+r = a.sort( Array.UNIQUESORT | Array.CASEINSENSITIVE | Array.DESCENDING |
Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+
+r = b.sort( Array.UNIQUESORT );
+check_equals( r.toString(), "0" );
+check_equals( b.toString(), "8,5,3,1,0,-2,-7,-9,3" );
+r = b.sort( Array.UNIQUESORT | Array.NUMERIC );
+check_equals( r.toString(), "0" );
+r = b.sort( Array.UNIQUESORT | Array.NUMERIC | Array.DESCENDING );
+check_equals( r.toString(), "0" );
+r = b.sort( Array.UNIQUESORT | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+r = b.sort( Array.UNIQUESORT | Array.NUMERIC | Array.DESCENDING |
Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+
+r = c.sort( Array.UNIQUESORT );
+check_equals( r.toString(), "0" );
+check_equals( c.toString(), "Infinity,8.35,7.2,2,0.001,0,-0.5,-3.7,Infinity" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC | Array.DESCENDING );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC | Array.DESCENDING |
Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+r = a.sort( cmp_fn, Array.UNIQUE | Array.CASEINSENSITIVE );
+check_equals( tolen(r), "[0, 2, 2, 2, 4, 5, 5]" );
+check_equals( tolen(a), "[0, 2, 2, 2, 4, 5, 5]" );
+r = a.sort( cmp_fn, Array.UNIQUE | Array.CASEINSENSITIVE |
Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0,1,2,3,4,5,6" );
+r = a.sort( cmp_fn, Array.UNIQUE | Array.CASEINSENSITIVE |
Array.RETURNINDEXEDARRAY | Array.DESCENDING );
+check_equals( r.toString(), "6,5,4,3,2,1,0" );
+
+trace(" -- Array with null value -- ");
+c.push(null);
+
+r = c.sort();
+check_equals( r.toString(),
"-0.5,-3.7,0,0.001,2,7.2,8.35,Infinity,Infinity,null" );
+check_equals( c.toString(),
"-0.5,-3.7,0,0.001,2,7.2,8.35,Infinity,Infinity,null" );
+c.sort( Array.NUMERIC );
+check_equals( c.toString(),
"-3.7,-0.5,0,0.001,2,7.2,8.35,Infinity,Infinity,null" );
+c.sort( Array.DESCENDING | Array.NUMERIC );
+check_equals( c.toString(),
"null,Infinity,Infinity,8.35,7.2,2,0.001,0,-0.5,-3.7" );
+r = c.sort( Array.RETURNINDEXEDARRAY | Array.NUMERIC );
+check_equals( r.toString(), "9,8,7,6,5,4,3,1,2,0" );
+r = c.sort( Array.RETURNINDEXEDARRAY | Array.DESCENDING |
Array.CASEINSENSITIVE );
+check_equals( r.toString(), "0,1,2,3,4,5,6,7,9,8" );
+r = c.sort( Array.UNIQUESORT );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC | Array.DESCENDING |
Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+
+trace(" -- Array with 2 null values -- ");
+c = [7.2, 2.0, null, -0.5, 3/0, 0.0, null, 8.35, 0.001, -3.7];
+c.sort( Array.NUMERIC );
+check_equals( c.toString(), "-3.7,-0.5,0,0.001,2,7.2,8.35,Infinity,null,null"
);
+c.sort( Array.DESCENDING | Array.NUMERIC );
+check_equals( c.toString(), "null,null,Infinity,8.35,7.2,2,0.001,0,-0.5,-3.7"
);
+r = c.sort( Array.RETURNINDEXEDARRAY | Array.NUMERIC );
+check_equals( r.toString(), "9,8,7,6,5,4,3,2,0,1" );
+check_equals( c.toString(), "null,null,Infinity,8.35,7.2,2,0.001,0,-0.5,-3.7"
);
+r = c.sort( Array.UNIQUESORT );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC );
+check_equals( r.toString(), "0" );
+
+trace(" -- Array with 2 undefined values -- ");
+c = [7.2, 2.0, undefined, -0.5, 3/0, 0.0, undefined, 8.35, 0.001, -3.7];
+r = c.sort( Array.UNIQUESORT );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC );
+check_equals( r.toString(), "0" );
+
+trace(" -- Array with 2 NaN values -- ");
+c = [7.2, 2.0, NaN, -0.5, 3/0, 0.0, NaN, 8.35, 0.001, -3.7];
+r = c.sort( Array.UNIQUESORT );
+check_equals( r.toString(), "0" );
+r = c.sort( Array.UNIQUESORT | Array.NUMERIC );
+check_equals( r.toString(), "0" );
+
+//-------------------------------
+// Test sortOn
+//-------------------------------
+
+a = [];
+a.push({Name: "Zuse Z3", Year: 1941, Electronic: false});
+a.push({Name: "Colossus", Year: 1943, Electronic: true});
+a.push({Name: "ENIAC", Year: 1944, Electronic: true});
+
+function tostr(x)
+{
+ var i;
+ str = "";
+ for(i = 0; i < x.length; i++)
+ {
+ y = a[i];
+ str += (y.Name + "," + y.Year + "," + y.Electronic );
+ if (i != x.length - 1) str += " | ";
+ }
+ return str;
+}
+
+trace("sortOn a single property ");
+r = a.sortOn( "Name" );
+check_equals( tostr(r), "Colossus,1943,true | ENIAC,1944,true | Zuse
Z3,1941,false" );
+check_equals( tostr(a), "Colossus,1943,true | ENIAC,1944,true | Zuse
Z3,1941,false" );
+
+r = a.sortOn( "Year" );
+check_equals( tostr(r), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true" );
+check_equals( tostr(a), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true" );
+
+a.sortOn( "Electronic" );
+check_equals( tostr(a), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true" );
+
+a.sortOn("Year", Array.NUMERIC );
+check_equals( tostr(a), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true" );
+
+a.sortOn("Year", Array.NUMERIC | Array.DESCENDING );
+check_equals ( tostr(a), "ENIAC,1944,true | Colossus,1943,true | Zuse
Z3,1941,false" );
+
+r = a.sortOn("Year", Array.UNIQUESORT | Array.NUMERIC );
+check_equals ( tostr(r), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true" );
+check_equals ( tostr(a), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true" );
+
+r = a.sortOn("Year", Array.RETURNINDEXEDARRAY | Array.NUMERIC );
+check_equals( r.toString(), "0,1,2" );
+check_equals ( tostr(a), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true" );
+
+r = a.sortOn("Name", Array.UNIQUESORT );
+check_equals( tostr(r), "Colossus,1943,true | ENIAC,1944,true | Zuse
Z3,1941,false" );
+check_equals( tostr(a), "Colossus,1943,true | ENIAC,1944,true | Zuse
Z3,1941,false" );
+
+r = a.sortOn("Name", Array.UNIQUESORT | Array.DESCENDING );
+check_equals( tostr(r), "Zuse Z3,1941,false | ENIAC,1944,true |
Colossus,1943,true" );
+
+r = a.sortOn("Name", Array.UNIQUESORT | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "2,1,0" );
+
+r = a.sortOn("Electronic", Array.UNIQUESORT | Array.RETURNINDEXEDARRAY );
+check_equals( r.toString(), "0" );
+check_equals( tostr(a), "Zuse Z3,1941,false | ENIAC,1944,true |
Colossus,1943,true");
+
+trace("sortOn multiple properties");
+a.push({Name: "Atanasoff-Berry", Year: 1941, Electronic: true, Mass: 320});
+
+r = a.sortOn( ["Name", "Year"] );
+check_equals( tostr(r), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+a.sortOn( ["Electronic", "Year"] );
+check_equals( tostr(a), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+
+a.sortOn( ["Electronic", "Year"], [Array.DESCENDING, Array.NUMERIC] );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+r = a.sortOn( ["Name", "Year"], [Array.UNIQUESORT, Array.NUMERIC] );
+check_equals( tostr(r), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+r = a.sortOn( ["Electronic", "Name"], [Array.UNIQUESORT, Array.NUMERIC] );
+check_equals( tostr(r), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+
+
+trace("sortOn missing properties" );
+r = a.sortOn(["Megaflops"] );
+check_equals( tostr(r), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+check_equals( tostr(a), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+
+a.sortOn(["Binary", "Turing complete"] );
+check_equals( tostr(a), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+
+a.sortOn(["Inventor", "Cost"], [Array.DESCENDING, 0] );
+check_equals( tostr(a), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+
+r = a.sortOn(["Name", "Year", "Cost"], [Array.DESCENDING, Array.NUMERIC, 0] );
+check_equals( tostr(a), "Zuse Z3,1941,false | ENIAC,1944,true |
Colossus,1943,true | Atanasoff-Berry,1941,true" );
+
+r = a.sortOn(["Name", "Cost", "Year"], [0, 0, Array.NUMERIC] );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+r = a.sortOn(["Electronic", "Year", "Cost"], [Array.UNIQUESORT, Array.NUMERIC,
Array.NUMERIC] );
+check_equals( tostr(r), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+check_equals( tostr(a), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true" );
+
+r = a.sortOn(["Electronic", "Cost" ], [Array.UNIQUESORT, Array.NUMERIC] );
+check_equals( r.toString(), "0" );
+
+trace("sortOn with mismatching array lengths");
+r = a.sortOn( ["Name", "Year"], [0] );
+check_equals( tostr(r), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+r = a.sortOn( ["Name", "Year"], [Array.DESCENDING] );
+check_equals( tostr(r), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+a.sortOn(["Name", "Electronic"], [Array.DESCENDING] );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+r = a.sortOn(["Name", "Year"], [Array.RETURNINDEXEDARRAY] );
+check_equals( tostr(r), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+trace("sortOn, undocumented invocation");
+r = a.sortOn( ["Name", "Year"], Array.DESCENDING );
+check_equals( tostr(r), "Zuse Z3,1941,false | ENIAC,1944,true |
Colossus,1943,true | Atanasoff-Berry,1941,true" );
+check_equals( tostr(a), "Zuse Z3,1941,false | ENIAC,1944,true |
Colossus,1943,true | Atanasoff-Berry,1941,true" );
+
+a.sortOn( ["Year", "Name"], Array.NUMERIC );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Zuse Z3,1941,false |
Colossus,1943,true | ENIAC,1944,true" );
+
+a.sortOn( ["Electronic", "Year", "Name"], Array.NUMERIC | Array.DESCENDING );
+check_equals( tostr(a), "ENIAC,1944,true | Colossus,1943,true |
Atanasoff-Berry,1941,true | Zuse Z3,1941,false" );
+
+#if OUTPUT_VERSION > 6
+trace("sortOn partially missing properties");
+
+r = a.sortOn(["Name", "Electronic"], [Array.DESCENDING] );
+check_equals( tostr(r), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+r = a.sortOn(["Name", "Year"], [Array.RETURNINDEXEDARRAY]);
+check_equals( tostr(r), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+
+trace("sortOn partially missing properties");
+a.push({Name: "Harvard Mark I", Year: 1944, Mass: 4500});
+
+a.sortOn(["Electronic", "Year"], Array.DESCENDING | Array.IGNORECASE );
+check_equals( tostr(a), "Harvard Mark I,1944,undefined | ENIAC,1944,true |
Colossus,1943,true | Atanasoff-Berry,1941,true | Zuse Z3,1941,false" );
+
+a.sortOn( ["Electronic", "Name"], [Array.NUMERIC, Array.DESCENDING] );
+check_equals( tostr(a), "Zuse Z3,1941,false | ENIAC,1944,true |
Colossus,1943,true | Atanasoff-Berry,1941,true | Harvard Mark I,1944,undefined"
);
+
+r = a.sortOn( ["Electronic", "Name"], [Array.UNIQUESORT, Array.NUMERIC] );
+check_equals( tostr(r), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true | Harvard Mark I,1944,undefined" );
+check_equals( tostr(a), "Zuse Z3,1941,false | Atanasoff-Berry,1941,true |
Colossus,1943,true | ENIAC,1944,true | Harvard Mark I,1944,undefined" );
+
+a.sortOn( ["Mass", "Name"], [0, 0] );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Harvard Mark
I,1944,undefined | Colossus,1943,true | ENIAC,1944,true | Zuse Z3,1941,false" );
+
+a.sortOn( ["Mass", "Year", "Name"], [Array.NUMERIC | Array.DESCENDING,
Array.NUMERIC | Array.DESCENDING | 0] );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Harvard Mark
I,1944,undefined | Zuse Z3,1941,false | Colossus,1943,true | ENIAC,1944,true" );
+
+a.sortOn( ["Mass", "Name"], [Array.UNIQUE, Array.DESCENDING] );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Harvard Mark
I,1944,undefined | Zuse Z3,1941,false | ENIAC,1944,true | Colossus,1943,true" );
+
+a.sortOn( ["Electronic", "Mass", "Name"], [0, Array.NUMERIC |
Array.DESCENDING, 0] );
+check_equals( tostr(a), "Zuse Z3,1941,false | Colossus,1943,true |
ENIAC,1944,true | Atanasoff-Berry,1941,true | Harvard Mark I,1944,undefined" );
+
+r = a.sortOn( ["Electronic", "Mass", "Year", "Name"],
[Array.RETURNINDEXEDARRAY, Array.NUMERIC, Array.NUMERIC, Array.DESCENDING] );
+check_equals( r.toString(), "0,3,1,2,4");
+#endif // OUTPUT_VERSION > 6
+
+#if OUTPUT_VERSION < 7
+trace("sortOn property name case-mismatch");
+a.sortOn( ["name"] );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Colossus,1943,true |
ENIAC,1944,true | Zuse Z3,1941,false" );
+a.sortOn( ["year", "name"], Array.NUMERIC );
+check_equals( tostr(a), "Atanasoff-Berry,1941,true | Zuse Z3,1941,false |
Colossus,1943,true | ENIAC,1944,true" );
+#endif // OUTPUT_VERSION < 7
+