gnash-commit
[Top][All Lists]
Advanced

[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
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]