# HG changeset patch # User Jaroslav Hajek # Date 1235110089 -3600 # Node ID 89b95972e17806caadb6d47f05d4487543e43664 # Parent 96d87674b818f72f34da798ca3e19ef569a9aadb fix previously introduced problem in octave_sort, improve design diff -r 96d87674b818 -r 89b95972e178 liboctave/ChangeLog --- a/liboctave/ChangeLog Fri Feb 20 01:00:25 2009 -0500 +++ b/liboctave/ChangeLog Fri Feb 20 07:08:09 2009 +0100 @@ -1,3 +1,15 @@ +2009-02-20 Jaroslav Hajek + + * oct-sort.h (octave_sort::MergeState::MergeState): New + constructor. + (octave_sort::MergeState::~MergeState): New destructor. + (octave_sort::MergeState::reset, + octave_sort::MergeState::getmem, + octave_sort::MergeState::getmemi): New methods. + (octave_sort::sort, + octave_sort::merge_lo, octave_sort::merge_hi + octave_sort::merge_at): Reflect change. + 2009-02-19 Jaroslav Hajek * oct-types.h (sortmode): Move enum here. diff -r 96d87674b818 -r 89b95972e178 liboctave/oct-sort.cc --- a/liboctave/oct-sort.cc Fri Feb 20 01:00:25 2009 -0500 +++ b/liboctave/oct-sort.cc Fri Feb 20 07:08:09 2009 +0100 @@ -37,6 +37,15 @@ * duplicate methods to avoid by-the-way indexed sorting +* add methods for verifying sortedness of array + +* row sorting via breadth-first tree subsorting + +* binary lookup and sequential binary lookup optimized for dense downsampling. + +* NOTE: the memory management routines rely on the fact that delete [] silently + ignores null pointers. Don't gripe about the missing checks - they're there. + The Python license is @@ -120,7 +129,6 @@ template octave_sort::~octave_sort () { - merge_freemem (); delete ms; } @@ -479,37 +487,6 @@ return ofs; } -/* Conceptually a MergeState's constructor. */ -template -void -octave_sort::merge_init (void) -{ - if (! ms) ms = new MergeState; - ms->a = 0; - ms->ia = 0; - ms->alloced = 0; - ms->n = 0; - ms->min_gallop = MIN_GALLOP; -} - -/* Free all the temp memory owned by the MergeState. This must be called - * when you're done with a MergeState, and may be called before then if - * you want to free the temp memory early. - */ -template -void -octave_sort::merge_freemem (void) -{ - if (ms) - { - delete [] ms->a; - delete [] ms->ia; - ms->alloced = 0; - ms->a = 0; - ms->ia = 0; - } -} - static inline octave_idx_type roundupsize (octave_idx_type n) { @@ -551,50 +528,40 @@ * Returns 0 on success and -1 if the memory can't be gotten. */ template -int -octave_sort::merge_getmem (octave_idx_type need) +void +octave_sort::MergeState::getmem (octave_idx_type need) { - if (need <= ms->alloced) - return 0; + if (need <= alloced) + return; need = roundupsize (need); /* Don't realloc! That can cost cycles to copy the old data, but * we don't care what's in the block. */ - merge_freemem (); - ms->a = new T[need]; - if (ms->a) - { - ms->alloced = need; - return 0; - } - merge_freemem (); /* reset to sane state */ + delete [] a; + delete [] ia; // Must do this or fool possible next getmemi. + a = new T[need]; + alloced = need; - return -1; } template -int -octave_sort::merge_getmemi (octave_idx_type need) +void +octave_sort::MergeState::getmemi (octave_idx_type need) { - if (need <= ms->alloced && ms->a && ms->ia) - return 0; + if (ia && need <= alloced) + return; need = roundupsize (need); /* Don't realloc! That can cost cycles to copy the old data, but * we don't care what's in the block. */ - merge_freemem (); - ms->a = new T[need]; - ms->ia = new octave_idx_type[need]; - if (ms->a && ms->ia) - { - ms->alloced = need; - return 0; - } - merge_freemem (); /* reset to sane state */ + delete [] a; + delete [] ia; - return -1; + a = new T[need]; + ia = new octave_idx_type[need]; + alloced = need; } /* Merge the na elements starting at pa with the nb elements starting at pb @@ -615,8 +582,8 @@ int result = -1; /* guilty until proved innocent */ octave_idx_type min_gallop = ms->min_gallop; - if (merge_getmem (na) < 0) - return -1; + ms->getmem (na); + std::copy (pa, pa + na, ms->a); dest = pa; pa = ms->a; @@ -751,8 +718,8 @@ int result = -1; /* guilty until proved innocent */ octave_idx_type min_gallop = ms->min_gallop; - if (merge_getmemi (na) < 0) - return -1; + ms->getmemi (na); + std::copy (pa, pa + na, ms->a); std::copy (ipa, ipa + na, ms->ia); dest = pa; idest = ipa; @@ -898,8 +865,8 @@ T *basea, *baseb; octave_idx_type min_gallop = ms->min_gallop; - if (merge_getmem (nb) < 0) - return -1; + ms->getmem (nb); + dest = pb + nb - 1; std::copy (pb, pb + nb, ms->a); basea = pa; @@ -1037,8 +1004,8 @@ octave_idx_type *ibasea, *ibaseb; octave_idx_type min_gallop = ms->min_gallop; - if (merge_getmemi (nb) < 0) - return -1; + ms->getmemi (nb); + dest = pb + nb - 1; idest = ipb + nb - 1; std::copy (pb, pb + nb, ms->a); @@ -1419,13 +1386,10 @@ octave_sort::sort (T *data, octave_idx_type nel, Comp comp) { /* Re-initialize the Mergestate as this might be the second time called */ - if (ms) - { - ms->n = 0; - ms->min_gallop = MIN_GALLOP; - } - else - merge_init (); + if (! ms) ms = new MergeState; + + ms->reset (); + ms->getmem (1024); if (nel > 1) { @@ -1480,6 +1444,12 @@ octave_sort::sort (T *data, octave_idx_type *idx, octave_idx_type nel, Comp comp) { + /* Re-initialize the Mergestate as this might be the second time called */ + if (! ms) ms = new MergeState; + + ms->reset (); + ms->getmemi (1024); + if (nel > 1) { octave_idx_type nremaining = nel; @@ -1534,17 +1504,6 @@ void octave_sort::sort (T *data, octave_idx_type nel) { - /* Re-initialize the Mergestate as this might be the second time called */ - if (ms) - { - ms->n = 0; - ms->min_gallop = MIN_GALLOP; - } - else - merge_init (); - - merge_getmem (1024); - #ifdef INLINE_ASCENDING_SORT if (compare == ascending_compare) sort (data, nel, std::less ()); @@ -1563,17 +1522,6 @@ void octave_sort::sort (T *data, octave_idx_type *idx, octave_idx_type nel) { - /* Re-initialize the Mergestate as this might be the second time called */ - if (ms) - { - ms->n = 0; - ms->min_gallop = MIN_GALLOP; - } - else - merge_init (); - - merge_getmemi (1024); - #ifdef INLINE_ASCENDING_SORT if (compare == ascending_compare) sort (data, idx, nel, std::less ()); @@ -1686,12 +1634,12 @@ if (comp (lbuf[lst], lbuf[i])) { if (i > lst + 1) - runs.push (run_t (col+1, lst, i - lst)); + runs.push (run_t (col+1, ofs + lst, i - lst)); lst = i; } } if (nel > lst + 1) - runs.push (run_t (col+1, lst, nel - lst)); + runs.push (run_t (col+1, ofs + lst, nel - lst)); } } } @@ -1701,17 +1649,6 @@ octave_sort::sort_rows (const T *data, octave_idx_type *idx, octave_idx_type rows, octave_idx_type cols) { - /* Re-initialize the Mergestate as this might be the second time called */ - if (ms) - { - ms->n = 0; - ms->min_gallop = MIN_GALLOP; - } - else - merge_init (); - - merge_getmemi (1024); - #ifdef INLINE_ASCENDING_SORT if (compare == ascending_compare) sort_rows (data, idx, rows, cols, std::less ()); diff -r 96d87674b818 -r 89b95972e178 liboctave/oct-sort.h --- a/liboctave/oct-sort.h Fri Feb 20 01:00:25 2009 -0500 +++ b/liboctave/oct-sort.h Fri Feb 20 07:08:09 2009 +0100 @@ -171,6 +171,20 @@ struct MergeState { + MergeState (void) + : a (0), ia (0), alloced (0) + { reset (); } + + ~MergeState (void) + { delete [] a; delete [] ia; } + + void reset (void) + { min_gallop = MIN_GALLOP; n = 0; } + + void getmem (octave_idx_type need); + + void getmemi (octave_idx_type need); + // This controls when we get *into* galloping mode. It's // initialized to MIN_GALLOP. merge_lo and merge_hi tend to nudge // it higher for random data, and lower for highly structured @@ -219,14 +233,6 @@ octave_idx_type gallop_right (T key, T *a, octave_idx_type n, octave_idx_type hint, Comp comp); - void merge_init (void); - - void merge_freemem (void); - - int merge_getmem (octave_idx_type need); - - int merge_getmemi (octave_idx_type need); - template int merge_lo (T *pa, octave_idx_type na, T *pb, octave_idx_type nb, diff -r 96d87674b818 -r 89b95972e178 scripts/general/accumarray.m --- a/scripts/general/accumarray.m Fri Feb 20 01:00:25 2009 -0500 +++ b/scripts/general/accumarray.m Fri Feb 20 07:08:09 2009 +0100 @@ -91,6 +91,7 @@ endif [subs, idx] = sortrows (subs); + if (isscalar (val)) val = val * ones (size (idx)); else