gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gnash-commit] gnash ChangeLog server/array.cpp server/array.h...


From: zou lunkai
Subject: Re: [Gnash-commit] gnash ChangeLog server/array.cpp server/array.h...
Date: Mon, 13 Aug 2007 10:53:07 +0800

>+       unsigned int optnum = props->size();
>+       as_cmp_fn cmp[optnum];
>+       as_cmp_fn eq[optnum];

>+       uint8_t flgs[optnum];

A question, is it good practice to rely on VLA(variable length array)?
 Note that even VC8 compiler does not support this feature.

I guess we should not rely on it, which is compiler dependent(based on
google search) and only occurs in array.cpp.  What about replace it
with some STL containers?



On 7/29/07, Sandro Santilli <address@hidden> wrote:
> 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
> +
>
>
> _______________________________________________
> Gnash-commit mailing list
> address@hidden
> http://lists.gnu.org/mailman/listinfo/gnash-commit
>




reply via email to

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