[Top][All Lists]
[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
>