Algorithm-RectanglesContainingDot_XS
view release on metacpan or search on metacpan
Revision history for Perl extension Algorithm::RectanglesContainingDot_XS.
0.02 Mar 11, 2007
- updated to work under perl 5.6.x
- docs updated
0.01 Thu Mar 8 10:16:35 2007
- original version; created by h2xs 1.23 with options
-An Algorithm::RectanglesContainingDot_XS
if (\@ARGV && \$ARGV[0] eq '--unstrip') {
eval { require Devel::PPPort };
\$@ and die "Cannot require Devel::PPPort, please install.\\n";
Devel::PPPort::WriteFile(\$0);
exit 0;
}
print <<END;
Sorry, but this is a stripped version of \$0.
To be able to use its original script and doc functionality,
please try to regenerate this file using:
\$^X \$0 --unstrip
END
/ms;
open OUT, ">$0" or die "cannot strip $0: $!\n";
print OUT $self;
#define small xsmall
#endif
#ifndef SMALLSORT
#define SMALLSORT (200)
#endif
/*
* The mergesort implementation is by Peter M. Mcilroy <pmcilroy@lucent.com>.
*
* The original code was written in conjunction with BSD Computer Software
* Research Group at University of California, Berkeley.
*
* See also: "Optimistic Merge Sort" (SODA '92)
*
* The integration to Perl is by John P. Linderman <jpl@research.att.com>.
*
* The code can be distributed under the same terms as Perl itself.
*
*/
b++;
}
q = r;
} while (b < t);
sense = !sense;
}
return runs;
}
/* The original merge sort, in use since 5.7, was as fast as, or faster than,
* qsort on many platforms, but slower than qsort, conspicuously so,
* on others. The most likely explanation was platform-specific
* differences in cache sizes and relative speeds.
*
* The quicksort divide-and-conquer algorithm guarantees that, as the
* problem is subdivided into smaller and smaller parts, the parts
* fit into smaller (and faster) caches. So it doesn't matter how
* many levels of cache exist, quicksort will "find" them, and,
* as long as smaller is faster, take advanatge of them.
*
* By contrast, consider how the original mergesort algorithm worked.
* Suppose we have five runs (each typically of length 2 after dynprep).
*
* pass base aux
* 0 1 2 3 4 5
* 1 12 34 5
* 2 1234 5
* 3 12345
* 4 12345
*
* Adjacent pairs are merged in "grand sweeps" through the input.
* This means, on pass 1, the records in runs 1 and 2 aren't revisited until
* runs 3 and 4 are merged and the runs from run 5 have been copied.
* The only cache that matters is one large enough to hold *all* the input.
* On some platforms, this may be many times slower than smaller caches.
*
* The following pseudo-code uses the same basic merge algorithm,
* but in a divide-and-conquer way.
*
* # merge $runs runs at offset $offset of list $list1 into $list2.
* # all unmerged runs ($runs == 1) originate in list $base.
* sub mgsort2 {
* my ($offset, $runs, $base, $list1, $list2) = @_;
*
* if ($runs == 1) {
* if ($list1 is $base) copy run to $list2
* return offset of end of list (or copy)
* } else {
* $off2 = mgsort2($offset, $runs-($runs/2), $base, $list2, $list1)
* mgsort2($off2, $runs/2, $base, $list2, $list1)
* merge the adjacent runs at $offset of $list1 into $list2
* merge runs 12 and 3 from base to aux
* (runs 4 and 5 are where they belong, no copy needed)
* merge runs 4 and 5 from base to aux
* merge runs 123 and 45 from aux to base
*
* Note that we merge runs 1 and 2 immediately after copying them,
* while they are still likely to be in fast cache. Similarly,
* run 3 is merged with run 12 while it still may be lingering in cache.
* This implementation should therefore enjoy much of the cache-friendly
* behavior that quicksort does. In addition, it does less copying
* than the original mergesort implementation (only runs 1 and 2 are copied)
* and the "balancing" of merges is better (merged runs comprise more nearly
* equal numbers of original runs).
*
* The actual cache-friendly implementation will use a pseudo-stack
* to avoid recursion, and will unroll processing of runs of length 2,
* but it is otherwise similar to the recursive implementation.
*/
typedef struct {
IV offset; /* offset of 1st of 2 runs at this level */
IV runs; /* how many runs must be combined into 1 */
} off_runs; /* pseudo-stack element */
* Stack the second half for later processing,
* and set about producing the first half now.
*/
while (runs > 2) {
++level;
++stackp;
stackp->offset = offset;
runs -= stackp->runs = runs / 2;
}
/* We must construct a single run from 1 or 2 runs.
* All the original runs are in which[0] == base.
* The run we construct must end up in which[level&1].
*/
iwhich = level & 1;
if (runs == 1) {
/* Constructing a single run from a single run.
* If it's where it belongs already, there's nothing to do.
* Otherwise, copy it to where it belongs.
* A run of 1 is either a singleton at level 0,
* or the second half of a split 3. In neither event
* is it necessary to set offset. It will be set by the merge
( run in 0.233 second using v1.01-cache-2.11-cpan-1c8d708658b )