[libset-intervaltree-perl] 01/07: Import original source of Set-IntervalTree 0.10
Vincent Danjean
vdanjean at debian.org
Sun Oct 1 19:48:35 UTC 2017
This is an automated email from the git hooks/post-receive script.
vdanjean pushed a commit to branch master
in repository libset-intervaltree-perl.
commit 66eb463b890a21e7a7c8ced741d5525f81ad8ada
Author: Vincent Danjean <Vincent.Danjean at ens-lyon.org>
Date: Thu Sep 29 22:33:42 2016 +0200
Import original source of Set-IntervalTree 0.10
---
Changes | 10 +
IntervalTree.xs | 281 +++++++++++
MANIFEST | 15 +
META.json | 39 ++
META.yml | 21 +
Makefile.PL | 26 ++
README | 22 +
lib/Set/IntervalTree.pm | 191 ++++++++
perlobject.map | 106 +++++
src/Makefile | 2 +
src/interval_tree.h | 1195 +++++++++++++++++++++++++++++++++++++++++++++++
src/test_main.cc | 46 ++
t/Set-IntervalTree.t | 66 +++
t/fetch-nearest.t | 21 +
typemap | 20 +
15 files changed, 2061 insertions(+)
diff --git a/Changes b/Changes
new file mode 100644
index 0000000..d2a8016
--- /dev/null
+++ b/Changes
@@ -0,0 +1,10 @@
+Revision history for Perl extension Set::IntervalTree.
+
+0.01 Mon Jul 12 15:58:33 2010
+ - original version; created by h2xs 1.23 with options
+ -n Set::IntervalTree -F -I. interval_tree.h
+
+0.02 Mon Apr 29 11:03:00 2011
+ - change to half-closed intervals
+ - add remove, remove_window, fetch_window methods
+
diff --git a/IntervalTree.xs b/IntervalTree.xs
new file mode 100644
index 0000000..bad6988
--- /dev/null
+++ b/IntervalTree.xs
@@ -0,0 +1,281 @@
+extern "C" {
+ #include "EXTERN.h"
+ #include "perl.h"
+ #include "XSUB.h"
+ #undef seed
+ #undef do_open
+ #undef do_close
+}
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <sstream>
+
+#include <interval_tree.h>
+
+#define do_open Perl_do_open
+#define do_close Perl_do_close
+
+class SV_ptr {
+ SV *sv;
+ public:
+ SV_ptr() : sv(0) {}
+ SV_ptr(SV *sv) : sv(sv) {
+ if (sv) SvREFCNT_inc(sv);
+ }
+ SV_ptr(const SV_ptr &ptr) : sv(ptr.get()) {
+ if (sv) SvREFCNT_inc(sv);
+ }
+ virtual ~SV_ptr() {
+ if (sv) SvREFCNT_dec(sv);
+ }
+ SV_ptr& operator=(SV_ptr ptr) {
+ if (sv) SvREFCNT_dec(sv);
+ sv = ptr.get();
+ if (sv) SvREFCNT_inc(sv);
+ return *this;
+ }
+ bool operator!=(SV_ptr &ptr) {
+ return sv != ptr.get();
+ }
+ bool defined() {
+ return sv != 0;
+ }
+ SV * get() {
+ return sv;
+ }
+ SV * get() const {
+ return sv;
+ }
+};
+
+std::ostream& operator<<(std::ostream &out, SV_ptr value) {
+ out << "Node:" << value.get();
+ return out;
+}
+
+class RemoveFunctor {
+ SV *callback;
+ public:
+ RemoveFunctor(SV *callback_) : callback(callback_) {}
+ bool operator()(SV_ptr value, long low, long high) const {
+ // pass args into callback
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(value.get());
+ XPUSHs(sv_2mortal(newSViv(low)));
+ XPUSHs(sv_2mortal(newSViv(high+1)));
+ PUTBACK;
+
+ // get result from callback and return
+ I32 count = call_sv(callback, G_SCALAR);
+
+ SPAGAIN;
+
+ if (count < 1) {
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ return false;
+ }
+
+ SV *retval_sv = POPs;
+ bool retval = SvTRUE(retval_sv);
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ return retval;
+ }
+};
+
+typedef IntervalTree<SV_ptr,long> PerlIntervalTree;
+typedef IntervalTree<SV_ptr,long>::Node PerlIntervalTree_Node;
+
+MODULE = Set::IntervalTree PACKAGE = Set::IntervalTree
+
+PerlIntervalTree *
+PerlIntervalTree::new()
+
+SV *
+PerlIntervalTree::str()
+ CODE:
+ std::string str = THIS->str();
+ const char *tree = str.c_str();
+ RETVAL = newSVpv(tree, 0);
+ OUTPUT:
+ RETVAL
+
+SV *
+PerlIntervalTree::fetch_nearest_up(long value)
+ CODE:
+ SV_ptr ptr = THIS->fetch_nearest_up(value);
+ SV *ret = ptr.get();
+ SvREFCNT_inc(ret);
+ RETVAL = ret;
+ if (RETVAL == 0)
+ XSRETURN_UNDEF;
+ OUTPUT:
+ RETVAL
+
+SV *
+PerlIntervalTree::fetch_nearest_down(long value)
+ CODE:
+ SV_ptr ptr = THIS->fetch_nearest_down(value-1);
+ SV *ret = ptr.get();
+ SvREFCNT_inc(ret);
+ RETVAL = ret;
+ if (RETVAL == 0)
+ XSRETURN_UNDEF;
+ OUTPUT:
+ RETVAL
+
+void
+PerlIntervalTree::insert(SV *value, long low, long high)
+ PROTOTYPE: $;$;$
+ CODE:
+ if (high <= low) Perl_croak(aTHX_ "Intervals must have positive width");
+ SV_ptr ptr(value);
+ THIS->insert(ptr, low, high-1);
+
+AV *
+PerlIntervalTree::remove(long low, long high, ...)
+ CODE:
+ if (high <= low) Perl_croak(aTHX_ "Intervals must have positive width");
+ RETVAL = newAV();
+ sv_2mortal((SV*)RETVAL);
+
+ if (items > 3) {
+ SV *callback = ST(3);
+ RemoveFunctor remove_functor(callback);
+ std::vector<SV_ptr> removed;
+ THIS->remove(low, high-1, remove_functor, removed);
+
+ for (std::vector<SV_ptr>::iterator
+ i=removed.begin(); i!=removed.end(); ++i)
+ {
+ SV *value = i->get();
+ SvREFCNT_inc(value);
+ av_push(RETVAL, value);
+ }
+ }
+ else {
+ std::vector<SV_ptr> removed;
+ THIS->remove(low, high-1, removed);
+
+ for (std::vector<SV_ptr>::iterator
+ i=removed.begin(); i!=removed.end(); ++i)
+ {
+ SV *value = i->get();
+ SvREFCNT_inc(value);
+ av_push(RETVAL, value);
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+AV *
+PerlIntervalTree::remove_window(long low, long high, ...)
+ CODE:
+ if (high <= low) Perl_croak(aTHX_ "Intervals must have positive width");
+ RETVAL = newAV();
+ sv_2mortal((SV*)RETVAL);
+
+ if (items > 3) {
+ SV *callback = ST(3);
+ RemoveFunctor remove_functor(callback);
+ std::vector<SV_ptr> removed;
+ THIS->remove_window(low, high-1, remove_functor, removed);
+
+ for (std::vector<SV_ptr>::iterator
+ i=removed.begin(); i!=removed.end(); ++i)
+ {
+ SV *value = i->get();
+ SvREFCNT_inc(value);
+ av_push(RETVAL, value);
+ }
+ }
+ else {
+ std::vector<SV_ptr> removed;
+ THIS->remove_window(low, high-1, removed);
+
+ for (std::vector<SV_ptr>::iterator
+ i=removed.begin(); i!=removed.end(); ++i)
+ {
+ SV *value = i->get();
+ SvREFCNT_inc(value);
+ av_push(RETVAL, value);
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+AV *
+PerlIntervalTree::fetch(long low, long high)
+ PROTOTYPE: $;$
+ CODE:
+ if (high <= low) Perl_croak(aTHX_ "Intervals must have positive width");
+ RETVAL = newAV();
+ sv_2mortal((SV*)RETVAL);
+ std::vector<SV_ptr> intervals;
+ THIS->fetch(low, high-1, intervals);
+ for (size_t i=0; i<intervals.size(); i++) {
+ SV *value = intervals[i].get();
+ SvREFCNT_inc(value);
+ av_push(RETVAL, value);
+ }
+ OUTPUT:
+ RETVAL
+
+AV *
+PerlIntervalTree::fetch_window(long low, long high)
+ PROTOTYPE: $;$
+ CODE:
+ if (high <= low) Perl_croak(aTHX_ "Intervals must have positive width");
+ RETVAL = newAV();
+ sv_2mortal((SV*)RETVAL);
+ std::vector<SV_ptr> intervals;
+ THIS->fetch_window(low, high-1, intervals);
+ for (size_t i=0; i<intervals.size(); i++) {
+ SV *value = intervals[i].get();
+ SvREFCNT_inc(value);
+ av_push(RETVAL, value);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+PerlIntervalTree::DESTROY()
+
+MODULE = Set::IntervalTree PACKAGE = Set::IntervalTree::Node
+
+PerlIntervalTree_Node *
+PerlIntervalTree_Node::new()
+
+int
+PerlIntervalTree_Node::low()
+ CODE:
+ RETVAL = THIS->low();
+ OUTPUT:
+ RETVAL
+
+int
+PerlIntervalTree_Node::high()
+ CODE:
+ RETVAL = THIS->high()+1;
+ OUTPUT:
+ RETVAL
+
+SV *
+PerlIntervalTree_Node::value()
+ CODE:
+ RETVAL = THIS->value().get();
+ OUTPUT:
+ RETVAL
+
+void
+PerlIntervalTree_Node::DESTROY()
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..fa82037
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,15 @@
+Changes
+IntervalTree.xs
+Makefile.PL
+MANIFEST
+README
+typemap
+perlobject.map
+src/interval_tree.h
+src/test_main.cc
+src/Makefile
+t/Set-IntervalTree.t
+t/fetch-nearest.t
+lib/Set/IntervalTree.pm
+META.yml Module YAML meta-data (added by MakeMaker)
+META.json Module JSON meta-data (added by MakeMaker)
diff --git a/META.json b/META.json
new file mode 100644
index 0000000..ed7eabd
--- /dev/null
+++ b/META.json
@@ -0,0 +1,39 @@
+{
+ "abstract" : "Perform range-based lookups on sets of ranges.",
+ "author" : [
+ "Ben Booth <benbooth at gmail.com>"
+ ],
+ "dynamic_config" : 1,
+ "generated_by" : "ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921",
+ "license" : [
+ "unknown"
+ ],
+ "meta-spec" : {
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ "version" : "2"
+ },
+ "name" : "Set-IntervalTree",
+ "no_index" : {
+ "directory" : [
+ "t",
+ "inc"
+ ]
+ },
+ "prereqs" : {
+ "build" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0"
+ }
+ },
+ "configure" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0"
+ }
+ },
+ "runtime" : {
+ "requires" : {}
+ }
+ },
+ "release_status" : "stable",
+ "version" : "0.10"
+}
diff --git a/META.yml b/META.yml
new file mode 100644
index 0000000..947f29d
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,21 @@
+---
+abstract: 'Perform range-based lookups on sets of ranges.'
+author:
+ - 'Ben Booth <benbooth at gmail.com>'
+build_requires:
+ ExtUtils::MakeMaker: 0
+configure_requires:
+ ExtUtils::MakeMaker: 0
+dynamic_config: 1
+generated_by: 'ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921'
+license: unknown
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: Set-IntervalTree
+no_index:
+ directory:
+ - t
+ - inc
+requires: {}
+version: 0.10
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..4fc8084
--- /dev/null
+++ b/Makefile.PL
@@ -0,0 +1,26 @@
+use 5.006001;
+use ExtUtils::MakeMaker;
+
+$CC = 'c++';
+
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ NAME => 'Set::IntervalTree',
+ VERSION_FROM => 'lib/Set/IntervalTree.pm', # finds $VERSION
+ PREREQ_PM => {}, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'lib/Set/IntervalTree.pm', # retrieve abstract from module
+ AUTHOR => 'Ben Booth <benbooth at gmail.com>') : ()),
+ LIBS => [''], # e.g., '-lm'
+ DEFINE => '-Isrc', # e.g., '-DHAVE_SOMETHING'
+ CC => $CC,
+ LD => '$(CC)',
+ OPTIMIZE => '-g -O2',
+ XSOPT => '-C++',
+ TYPEMAPS => ['perlobject.map'],
+ INC => '-Isrc', # e.g., '-I. -I/usr/include/other'
+ # Un-comment this if you add C files to link with later:
+ # OBJECT => '$(O_FILES)', # link all the C files too
+);
+
diff --git a/README b/README
new file mode 100644
index 0000000..78616ba
--- /dev/null
+++ b/README
@@ -0,0 +1,22 @@
+Set-IntervalTree version 0.03
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires no external CPAN module dependencies.
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2010 by Ben Booth
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.10.1 or,
+at your option, any later version of Perl 5 you may have available.
diff --git a/lib/Set/IntervalTree.pm b/lib/Set/IntervalTree.pm
new file mode 100644
index 0000000..9ed9a04
--- /dev/null
+++ b/lib/Set/IntervalTree.pm
@@ -0,0 +1,191 @@
+package Set::IntervalTree;
+
+use 5.006001;
+use strict;
+use warnings;
+use Carp;
+
+require Exporter;
+use AutoLoader;
+
+our @ISA = qw(Exporter);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use Set::IntervalTree ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+our %EXPORT_TAGS = ( 'all' => [ qw(
+
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+
+);
+
+our $VERSION = '0.10';
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function.
+
+ my $constname;
+ our $AUTOLOAD;
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ croak "&Set::IntervalTree::constant not defined!" if $constname eq 'constant';
+ my ($error, $val) = constant($constname);
+ if ($error) { croak $error; }
+ {
+ no strict 'refs';
+ # Fixed between 5.005_53 and 5.005_61
+#XXX if ($] >= 5.00561) {
+#XXX *$AUTOLOAD = sub () { $val };
+#XXX }
+#XXX else {
+ *$AUTOLOAD = sub { $val };
+#XXX }
+ }
+ goto &$AUTOLOAD;
+}
+
+require XSLoader;
+XSLoader::load('Set::IntervalTree', $VERSION);
+
+# Preloaded methods go here.
+
+# Autoload methods go after =cut, and are processed by the autosplit program.
+
+1;
+__END__
+# Below is stub documentation for your module. You'd better edit it!
+
+=head1 NAME
+
+Set::IntervalTree - Perform range-based lookups on sets of ranges.
+
+=head1 SYNOPSIS
+
+ use Set::IntervalTree;
+ my $tree = Set::IntervalTree->new;
+ $tree->insert("ID1",100,200);
+ $tree->insert(2,50,100);
+ $tree->insert({id=>3},520,700);
+ $tree->insert($some_obj,1000,1100);
+
+ my $results = $tree->fetch(400,800);
+ my $window = $tree->fetch_window(100,200);
+ print scalar(@$results)." intervals found.\n";
+
+ # remove only items overlapping location 100..200 with values
+ # less than 100;
+ my $removed = $tree->remove(100,200 sub {
+ my ($item, $low, $high) = @_;
+ return $item < 100;
+ });
+
+=head1 DESCRIPTION
+
+Set::IntervalTree uses Interval Trees to store and efficiently
+look up ranges using a range-based lookup.
+
+All intervals are half-open, i.e. [1,3), [2,6), etc.
+
+=head1 EXPORTS
+
+Nothing.
+
+=head1 METHODS
+
+my $tree = Set::IntervalTree->new;
+
+ Creates a new interval tree object.
+
+$tree->insert($object, $low, $high);
+
+ Insert a range into the interval tree and associate it with a
+ perl scalar.
+
+ $object can be any perl scalar. This is what will be returned by fetch().
+ $low is the lower bound of the range.
+ $high is the upper bound of the range.
+
+ Ranges are represented as half-closed integer intervals.
+
+my $results = $tree->fetch($low, $high)
+
+ Return an arrayref of perl objects whose ranges overlap
+ the specified range.
+
+ $low is the lower bound of the region to query.
+ $high is the upper bound of the region to query.
+
+my $results = $tree->fetch_window($low, $high)
+
+ Return an arrayref of perl objects whose ranges are completely contained
+ witin the specified range.
+
+ $low is the lower bound of the region to query.
+ $high is the upper bound of the region to query.
+
+my $nearest_up = $tree->fetch_nearest_up($query)
+
+ Search for the closest interval in upstream that does not contain the query
+ and returns the perl object associated with it.
+
+ $query is the position to use for the search
+
+my $nearest_down = $tree->fetch_nearest_down($query)
+
+ Search for the closest interval in downstream that does not contain the query
+ and returns the perl object associated with it.
+
+ $query is the position to use for the search
+
+my $removed = $tree->remove($low, $high [, optional \&coderef]);
+
+ Remove items in the tree that overlap the region from $low to $high.
+ A coderef can be passed in as an optional third argument for filtering
+ what is removed. The coderef receives the stored item, the low point,
+ and the high point as its arguments. If the result value of the coderef
+ is true, the item is removed, otherwise the item remains in the tree.
+
+ Returns the list of removed items.
+
+my $removed = $tree->remove_window($low, $high [, optional \&coderef]);
+
+ Remove items in the tree that are contained within the region from $low
+ to $high. A coderef can be passed in as an optional third argument
+ for filtering what is removed. The coderef receives the stored item,
+ the low point, and the high point as its arguments. If the result
+ value of the coderef is true, the item is removed, otherwise the item
+ remains in the tree.
+
+ Returns the list of removed items.
+
+=head1 LIMITATIONS
+
+A $tree->print() serialization method might be useful for debugging.
+
+=head1 SEE ALSO
+
+The source code for this module contains a reusable template-based
+C++ header for Interval trees that might be useful.
+
+=head1 AUTHOR
+
+Ben Booth, E<lt>benbooth at cpan.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2012 by Ben Booth
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.10.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/perlobject.map b/perlobject.map
new file mode 100644
index 0000000..4795c47
--- /dev/null
+++ b/perlobject.map
@@ -0,0 +1,106 @@
+# "perlobject.map" Dean Roehrich, version 19960302
+#
+# TYPEMAPs
+#
+# HV * -> unblessed Perl HV object.
+# AV * -> unblessed Perl AV object.
+#
+# INPUT/OUTPUT maps
+#
+# O_* -> opaque blessed objects
+# T_* -> opaque blessed or unblessed objects
+#
+# O_OBJECT -> link an opaque C or C++ object to a blessed Perl object.
+# T_OBJECT -> link an opaque C or C++ object to an unblessed Perl object.
+# O_HvRV -> a blessed Perl HV object.
+# T_HvRV -> an unblessed Perl HV object.
+# O_AvRV -> a blessed Perl AV object.
+# T_AvRV -> an unblessed Perl AV object.
+
+TYPEMAP
+
+HV * T_HvRV
+AV * T_AvRV
+
+
+######################################################################
+OUTPUT
+
+# The Perl object is blessed into 'CLASS', which should be a
+# char* having the name of the package for the blessing.
+O_OBJECT
+ sv_setref_pv( $arg, CLASS, (void*)$var );
+
+T_OBJECT
+ sv_setref_pv( $arg, Nullch, (void*)$var );
+
+# Cannot use sv_setref_pv() because that will destroy
+# the HV-ness of the object. Remember that newRV() will increment
+# the refcount.
+O_HvRV
+ $arg = sv_bless( newRV((SV*)$var), gv_stashpv(CLASS,1) );
+
+T_HvRV
+ $arg = newRV((SV*)$var);
+
+# Cannot use sv_setref_pv() because that will destroy
+# the AV-ness of the object. Remember that newRV() will increment
+# the refcount.
+O_AvRV
+ $arg = sv_bless( newRV((SV*)$var), gv_stashpv(CLASS,1) );
+
+T_AvRV
+ $arg = newRV((SV*)$var);
+
+
+######################################################################
+INPUT
+
+O_OBJECT
+ if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
+ $var = ($type)SvIV((SV*)SvRV( $arg ));
+ else{
+ warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+T_OBJECT
+ if( SvROK($arg) )
+ $var = ($type)SvIV((SV*)SvRV( $arg ));
+ else{
+ warn( \"${Package}::$func_name() -- $var is not an SV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+O_HvRV
+ if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV) )
+ $var = (HV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not a blessed HV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+T_HvRV
+ if( SvROK($arg) && (SvTYPE(SvRV($arg)) == SVt_PVHV) )
+ $var = (HV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not an HV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+O_AvRV
+ if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVAV) )
+ $var = (AV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not a blessed AV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+T_AvRV
+ if( SvROK($arg) && (SvTYPE(SvRV($arg)) == SVt_PVAV) )
+ $var = (AV*)SvRV( $arg );
+ else {
+ warn( \"${Package}::$func_name() -- $var is not an AV reference\" );
+ XSRETURN_UNDEF;
+ }
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..485b7c3
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,2 @@
+test: test_main.cc interval_tree.h
+ g++ -g -O0 -o test_main test_main.cc
diff --git a/src/interval_tree.h b/src/interval_tree.h
new file mode 100644
index 0000000..31d527a
--- /dev/null
+++ b/src/interval_tree.h
@@ -0,0 +1,1195 @@
+#ifndef INTERVALTREE_H_
+#define INTERVALTREE_H_
+
+#include <cmath>
+#include <cstdlib>
+#include <cassert>
+#include <limits>
+#include <algorithm>
+#include <sstream>
+#include <vector>
+#include <string>
+
+// The interval_tree.h file contains code for
+// interval trees implemented using red-black-trees as described in
+// the book _Introduction_To_Algorithms_ by Cormen, Leisserson,
+// and Rivest.
+
+// The low should return the lowest point of the interval and
+// the high should return the highest point of the interval.
+
+template<typename T, typename N=long>
+class IntervalTree {
+public:
+ enum color_t {BLACK, RED};
+
+ class Node {
+ friend class IntervalTree<T,N>;
+ public:
+ std::string str(Node *, Node *) const;
+ Node();
+ Node(const T&, N, N);
+ virtual ~Node();
+ N low() const;
+ N high() const;
+ T value() const;
+ protected:
+ T value_;
+ N key;
+ N high_;
+ N maxHigh;
+ color_t color;
+ Node * left;
+ Node * right;
+ Node * parent;
+ };
+
+ struct it_recursion_node {
+ /* this structure stores the information needed when we take the */
+ /* right branch in searching for intervals but possibly come back */
+ /* and check the left branch as well. */
+ it_recursion_node(Node *start_node_=NULL,
+ size_t parentIndex_=0,
+ bool tryRightBranch_=false)
+ : start_node (start_node_),
+ parentIndex (parentIndex_),
+ tryRightBranch (tryRightBranch_) {}
+
+ Node * start_node;
+ size_t parentIndex;
+ bool tryRightBranch;
+ } ;
+
+ IntervalTree();
+ ~IntervalTree();
+ std::string str() const;
+ void remove(N, N, std::vector<T>&);
+ template <class F> void remove(N, N, const F&, std::vector<T>&);
+ void remove_window(N, N, std::vector<T>&);
+ template <class F> void remove_window(N, N, const F&, std::vector<T>&);
+ Node * insert(const T&, N, N);
+ void fetch(N, N, std::vector<T>&);
+ void fetch_window(N, N, std::vector<T>&);
+ T fetch_nearest_up(IntervalTree<T,N>::Node* x, N value);
+ T fetch_nearest_up(N value);
+ IntervalTree<T,N>::Node* fetch_nearest_down(IntervalTree<T,N>::Node* x, N value);
+ T fetch_nearest_down(N value);
+protected:
+ void fetch_node(N, N, std::vector<Node*>&);
+ void fetch_window_node(N, N, std::vector<Node*>&);
+ T remove(Node *);
+ Node * GetPredecessorOf(Node *) const;
+ Node * GetSuccessorOf(Node *) const;
+ void check() const;
+
+ /* A sentinel is used for root and for nil. These sentinels are */
+ /* created when ITTreeCreate is caled. root->left should always */
+ /* point to the node which is the root of the tree. nil points to a */
+ /* node which should always be black but has aribtrary children and */
+ /* parent and no key or info. The point of using these sentinels is so */
+ /* that the root and nil nodes do not require special cases in the code */
+ Node * root;
+ Node * nil;
+
+ N Overlap(N a1, N a2, N b1, N b2);
+ N Contain(N a1, N a2, N b1, N b2);
+ void LeftRotate(Node *);
+ void RightRotate(Node *);
+ void TreeInsertHelp(Node *);
+ void TreePrintHelper(Node *, std::stringstream&) const;
+ void FixUpMaxHigh(Node *);
+ void DeleteFixUp(Node *);
+ void CheckMaxHighFields(Node *) const;
+ bool CheckMaxHighFieldsHelper(Node * y,
+ const N currentHigh,
+ bool match) const;
+private:
+ std::vector<it_recursion_node> recursionNodeStack;
+ size_t currentParent;
+};
+
+// If the symbol CHECK_INTERVAL_TREE_ASSUMPTIONS is defined then the
+// code does a lot of extra checking to make sure certain assumptions
+// are satisfied. This only needs to be done if you suspect bugs are
+// present or if you make significant changes and want to make sure
+// your changes didn't mess anything up.
+// #define CHECK_INTERVAL_TREE_ASSUMPTIONS 1
+
+template<typename T, typename N> IntervalTree<T,N>::Node::Node() {
+}
+
+template<typename T, typename N>
+IntervalTree<T,N>::Node::Node(const T& value__, N lowPoint, N highPoint)
+ : value_ (value__),
+ key(lowPoint),
+ high_(highPoint),
+ maxHigh(highPoint)
+{
+}
+
+template<typename T, typename N>
+IntervalTree<T,N>::Node::~Node()
+{
+}
+
+template<typename T, typename N>
+IntervalTree<T,N>::IntervalTree()
+{
+ nil = new typename IntervalTree<T,N>::Node();
+ nil->left = nil->right = nil->parent = nil;
+ nil->color = BLACK;
+ nil->key = nil->high_ = nil->maxHigh = std::numeric_limits<N>::min();
+
+ root = new typename IntervalTree<T,N>::Node();
+ root->parent = root->left = root->right = nil;
+ root->key = root->high_ = root->maxHigh = std::numeric_limits<N>::max();
+ root->color=BLACK;
+
+ /* the following are used for the fetch function */
+ recursionNodeStack.push_back(it_recursion_node());
+}
+
+template<typename T, typename N>
+N IntervalTree<T,N>::Node::low() const {
+ return key;
+}
+
+template<typename T, typename N>
+N IntervalTree<T,N>::Node::high() const {
+ return high_;
+}
+
+template<typename T, typename N>
+T IntervalTree<T,N>::Node::value() const {
+ return value_;
+}
+
+/***********************************************************************/
+/* FUNCTION: LeftRotate */
+/**/
+/* INPUTS: the node to rotate on */
+/**/
+/* OUTPUT: None */
+/**/
+/* Modifies Input: this, x */
+/**/
+/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
+/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
+/* makes the parent of x be to the left of x, x the parent of */
+/* its parent before the rotation and fixes other pointers */
+/* accordingly. Also updates the maxHigh fields of x and y */
+/* after rotation. */
+/***********************************************************************/
+
+template<typename T, typename N>
+void IntervalTree<T,N>::LeftRotate(IntervalTree<T,N>::Node* x) {
+ typename IntervalTree<T,N>::Node* y;
+
+ /* I originally wrote this function to use the sentinel for */
+ /* nil to avoid checking for nil. However this introduces a */
+ /* very subtle bug because sometimes this function modifies */
+ /* the parent pointer of nil. This can be a problem if a */
+ /* function which calls LeftRotate also uses the nil sentinel */
+ /* and expects the nil sentinel's parent pointer to be unchanged */
+ /* after calling this function. For example, when DeleteFixUP */
+ /* calls LeftRotate it expects the parent pointer of nil to be */
+ /* unchanged. */
+
+ y=x->right;
+ x->right=y->left;
+
+ if (y->left != nil) y->left->parent=x; /* used to use sentinel here */
+ /* and do an unconditional assignment instead of testing for nil */
+
+ y->parent=x->parent;
+
+ /* instead of checking if x->parent is the root as in the book, we */
+ /* count on the root sentinel to implicitly take care of this case */
+ if( x == x->parent->left) {
+ x->parent->left=y;
+ } else {
+ x->parent->right=y;
+ }
+ y->left=x;
+ x->parent=y;
+
+ x->maxHigh=std::max(x->left->maxHigh,std::max(x->right->maxHigh,x->high_));
+ y->maxHigh=std::max(x->maxHigh,std::max(y->right->maxHigh,y->high_));
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ check();
+#elif defined(DEBUG_ASSERT)
+ assert(nil->color != RED || !"nil not red in ITLeftRotate");
+ assert((nil->maxHigh!=std::numeric_limits<N>::min())
+ || !"nil->maxHigh != std::numeric_limits<N>::min() in ITLeftRotate");
+#endif
+}
+
+
+/***********************************************************************/
+/* FUNCTION: RighttRotate */
+/**/
+/* INPUTS: node to rotate on */
+/**/
+/* OUTPUT: None */
+/**/
+/* Modifies Input?: this, y */
+/**/
+/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */
+/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */
+/* makes the parent of x be to the left of x, x the parent of */
+/* its parent before the rotation and fixes other pointers */
+/* accordingly. Also updates the maxHigh fields of x and y */
+/* after rotation. */
+/***********************************************************************/
+
+
+template<typename T, typename N>
+void IntervalTree<T,N>::RightRotate(IntervalTree<T,N>::Node* y) {
+ typename IntervalTree<T,N>::Node* x;
+
+ /* I originally wrote this function to use the sentinel for */
+ /* nil to avoid checking for nil. However this introduces a */
+ /* very subtle bug because sometimes this function modifies */
+ /* the parent pointer of nil. This can be a problem if a */
+ /* function which calls LeftRotate also uses the nil sentinel */
+ /* and expects the nil sentinel's parent pointer to be unchanged */
+ /* after calling this function. For example, when DeleteFixUP */
+ /* calls LeftRotate it expects the parent pointer of nil to be */
+ /* unchanged. */
+
+ x=y->left;
+ y->left=x->right;
+
+ if (nil != x->right) x->right->parent=y; /*used to use sentinel here */
+ /* and do an unconditional assignment instead of testing for nil */
+
+ /* instead of checking if x->parent is the root as in the book, we */
+ /* count on the root sentinel to implicitly take care of this case */
+ x->parent=y->parent;
+ if( y == y->parent->left) {
+ y->parent->left=x;
+ } else {
+ y->parent->right=x;
+ }
+ x->right=y;
+ y->parent=x;
+
+ y->maxHigh=std::max(y->left->maxHigh,std::max(y->right->maxHigh,y->high_));
+ x->maxHigh=std::max(x->left->maxHigh,std::max(y->maxHigh,x->high_));
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ check();
+#elif defined(DEBUG_ASSERT)
+ assert(nil->color != RED || !"nil not red in ITRightRotate");
+ assert((nil->maxHigh!=std::numeric_limits<N>::min())
+ || !"nil->maxHigh != std::numeric_limits<N>::min() in ITRightRotate");
+#endif
+}
+
+/***********************************************************************/
+/* FUNCTION: TreeInsertHelp */
+/**/
+/* INPUTS: z is the node to insert */
+/**/
+/* OUTPUT: none */
+/**/
+/* Modifies Input: this, z */
+/**/
+/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */
+/* using the algorithm described in _Introduction_To_Algorithms_ */
+/* by Cormen et al. This funciton is only intended to be called */
+/* by the InsertTree function and not by the user */
+/***********************************************************************/
+
+template<typename T, typename N>
+void IntervalTree<T,N>::TreeInsertHelp(IntervalTree<T,N>::Node* z) {
+ /* This function should only be called by InsertITTree (see above) */
+ typename IntervalTree<T,N>::Node* x;
+ typename IntervalTree<T,N>::Node* y;
+
+ z->left=z->right=nil;
+ y=root;
+ x=root->left;
+ while( x != nil) {
+ y=x;
+ if ( x->key > z->key) {
+ x=x->left;
+ } else { /* x->key <= z->key */
+ x=x->right;
+ }
+ }
+ z->parent=y;
+ if ( (y == root) ||
+ (y->key > z->key) ) {
+ y->left=z;
+ } else {
+ y->right=z;
+ }
+
+
+#if defined(DEBUG_ASSERT)
+ assert(nil->color != RED || !"nil not red in ITTreeInsertHelp");
+ assert((nil->maxHigh!=std::numeric_limits<N>::min())
+ || !"nil->maxHigh != std::numeric_limits<N>::min() in ITTreeInsertHelp");
+#endif
+}
+
+
+/***********************************************************************/
+/* FUNCTION: FixUpMaxHigh */
+/**/
+/* INPUTS: x is the node to start from*/
+/**/
+/* OUTPUT: none */
+/**/
+/* Modifies Input: this */
+/**/
+/* EFFECTS: Travels up to the root fixing the maxHigh fields after */
+/* an insertion or deletion */
+/***********************************************************************/
+
+template<typename T, typename N>
+void IntervalTree<T,N>::FixUpMaxHigh(IntervalTree<T,N>::Node * x) {
+ while(x != root) {
+ x->maxHigh=std::max(x->high_,std::max(x->left->maxHigh,x->right->maxHigh));
+ x=x->parent;
+ }
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ check();
+#endif
+}
+
+/* Before calling InsertNode the node x should have its key set */
+
+/***********************************************************************/
+/* FUNCTION: InsertNode */
+/**/
+/* INPUTS: newInterval is the interval to insert*/
+/**/
+/* OUTPUT: This function returns a pointer to the newly inserted node */
+/* which is guarunteed to be valid until this node is deleted. */
+/* What this means is if another data structure stores this */
+/* pointer then the tree does not need to be searched when this */
+/* is to be deleted. */
+/**/
+/* Modifies Input: tree */
+/**/
+/* EFFECTS: Creates a node node which contains the appropriate key and */
+/* info pointers and inserts it into the tree. */
+/***********************************************************************/
+
+template <typename T, typename N>
+typename IntervalTree<T,N>::Node* IntervalTree<T,N>::insert(const T& newInterval, N low, N high)
+{
+ typename IntervalTree<T,N>::Node * y;
+ typename IntervalTree<T,N>::Node * x;
+ typename IntervalTree<T,N>::Node * newNode;
+
+ x = new typename IntervalTree<T,N>::Node(newInterval, low, high);
+ TreeInsertHelp(x);
+ FixUpMaxHigh(x->parent);
+ newNode = x;
+ x->color=RED;
+ while(x->parent->color == RED) { /* use sentinel instead of checking for root */
+ if (x->parent == x->parent->parent->left) {
+ y=x->parent->parent->right;
+ if (y->color == RED) {
+ x->parent->color=BLACK;
+ y->color=BLACK;
+ x->parent->parent->color=RED;
+ x=x->parent->parent;
+ } else {
+ if (x == x->parent->right) {
+ x=x->parent;
+ LeftRotate(x);
+ }
+ x->parent->color=BLACK;
+ x->parent->parent->color=RED;
+ RightRotate(x->parent->parent);
+ }
+ } else { /* case for x->parent == x->parent->parent->right */
+ /* this part is just like the section above with */
+ /* left and right interchanged */
+ y=x->parent->parent->left;
+ if (y->color == RED) {
+ x->parent->color=BLACK;
+ y->color=BLACK;
+ x->parent->parent->color=RED;
+ x=x->parent->parent;
+ } else {
+ if (x == x->parent->left) {
+ x=x->parent;
+ RightRotate(x);
+ }
+ x->parent->color=BLACK;
+ x->parent->parent->color=RED;
+ LeftRotate(x->parent->parent);
+ }
+ }
+ }
+ root->left->color=BLACK;
+ return(newNode);
+
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ check();
+#elif defined(DEBUG_ASSERT)
+ assert(nil->color != RED || !"nil not red in ITTreeInsert");
+ assert(root->color != RED || !"root not red in ITTreeInsert");
+ assert((nil->maxHigh!=std::numeric_limits<N>::min())
+ || !"nil->maxHigh != std::numeric_limits<N>::min() in ITTreeInsert");
+#endif
+}
+
+/***********************************************************************/
+/* FUNCTION: GetSuccessorOf */
+/**/
+/* INPUTS: x is the node we want the succesor of */
+/**/
+/* OUTPUT: This function returns the successor of x or NULL if no */
+/* successor exists. */
+/**/
+/* Modifies Input: none */
+/**/
+/* Note: uses the algorithm in _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+template<typename T, typename N>
+typename IntervalTree<T,N>::Node * IntervalTree<T,N>::GetSuccessorOf(IntervalTree<T,N>::Node * x) const
+{
+ typename IntervalTree<T,N>::Node* y;
+
+ if (nil != (y = x->right)) { /* assignment to y is intentional */
+ while(y->left != nil) { /* returns the minium of the right subtree of x */
+ y=y->left;
+ }
+ return(y);
+ } else {
+ y=x->parent;
+ while(x == y->right) { /* sentinel used instead of checking for nil */
+ x=y;
+ y=y->parent;
+ }
+ if (y == root) return(nil);
+ return(y);
+ }
+}
+
+/***********************************************************************/
+/* FUNCTION: GetPredecessorOf */
+/**/
+/* INPUTS: x is the node to get predecessor of */
+/**/
+/* OUTPUT: This function returns the predecessor of x or NULL if no */
+/* predecessor exists. */
+/**/
+/* Modifies Input: none */
+/**/
+/* Note: uses the algorithm in _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+template<typename T, typename N>
+typename IntervalTree<T,N>::Node * IntervalTree<T,N>::GetPredecessorOf(IntervalTree<T,N>::Node * x) const {
+ typename IntervalTree<T,N>::Node* y;
+
+ if (nil != (y = x->left)) { /* assignment to y is intentional */
+ while(y->right != nil) { /* returns the maximum of the left subtree of x */
+ y=y->right;
+ }
+ return(y);
+ } else {
+ y=x->parent;
+ while(x == y->left) {
+ if (y == root) return(nil);
+ x=y;
+ y=y->parent;
+ }
+ return(y);
+ }
+}
+
+/***********************************************************************/
+/* FUNCTION: str */
+/**/
+/* INPUTS: none */
+/**/
+/* OUTPUT: none */
+/**/
+/* EFFECTS: This function recursively prints the nodes of the tree */
+/* inorder. */
+/**/
+/* Modifies Input: none */
+/**/
+/* Note: This function should only be called from ITTreePrint */
+/***********************************************************************/
+
+template<typename T, typename N>
+std::string IntervalTree<T,N>::Node::str(IntervalTree<T,N>::Node * nil,
+ IntervalTree<T,N>::Node * root) const {
+ std::stringstream s;
+
+ s << value_;
+ s << ", k=" << key << ", h=" << high_ << ", mH=" << maxHigh;
+ s << " l->key=";
+ if( left == nil) s << "NULL"; else s << left->key;
+ s << " r->key=";
+ if( right == nil) s << "NULL"; else s << right->key;
+ s << " p->key=";
+ if( parent == root) s << "NULL"; else s << parent->key;
+ s << " color=" << (color == RED ? "RED" : "BLACK") << std::endl;
+ return s.str();
+}
+
+template<typename T, typename N>
+void IntervalTree<T,N>::TreePrintHelper(IntervalTree<T,N>::Node* x, std::stringstream &s) const {
+ if (x != nil) {
+ TreePrintHelper(x->left, s);
+ s << x->str(nil,root);
+ TreePrintHelper(x->right, s);
+ }
+}
+
+template<typename T, typename N>
+IntervalTree<T,N>::~IntervalTree() {
+
+ typename IntervalTree<T,N>::Node * x = root->left;
+ typename std::vector<typename IntervalTree<T,N>::Node *> stuffToFree;
+
+ if (x != nil) {
+ if (x->left != nil) {
+ stuffToFree.push_back(x->left);
+ }
+ if (x->right != nil) {
+ stuffToFree.push_back(x->right);
+ }
+ delete x;
+ while( !stuffToFree.empty() ) {
+ x = stuffToFree.back();
+ stuffToFree.pop_back();
+ if (x->left != nil) {
+ stuffToFree.push_back(x->left);
+ }
+ if (x->right != nil) {
+ stuffToFree.push_back(x->right);
+ }
+ delete x;
+ }
+ }
+ delete nil;
+ delete root;
+}
+
+
+/***********************************************************************/
+/* FUNCTION: str */
+/**/
+/* INPUTS: none */
+/**/
+/* OUTPUT: none */
+/**/
+/* EFFECT: This function recursively prints the nodes of the tree */
+/* inorder. */
+/**/
+/* Modifies Input: none */
+/**/
+/***********************************************************************/
+
+template<typename T, typename N>
+std::string IntervalTree<T,N>::str() const {
+ std::stringstream s;
+ TreePrintHelper(root->left, s);
+ return s.str();
+}
+
+/***********************************************************************/
+/* FUNCTION: DeleteFixUp */
+/**/
+/* INPUTS: x is the child of the spliced */
+/* out node in remove. */
+/**/
+/* OUTPUT: none */
+/**/
+/* EFFECT: Performs rotations and changes colors to restore red-black */
+/* properties after a node is deleted */
+/**/
+/* Modifies Input: this, x */
+/**/
+/* The algorithm from this function is from _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+template<typename T,typename N>
+void IntervalTree<T,N>::DeleteFixUp(IntervalTree<T,N>::Node* x) {
+ typename IntervalTree<T,N>::Node * w;
+ typename IntervalTree<T,N>::Node * rootLeft = root->left;
+
+ while( (x->color == BLACK) && (rootLeft != x)) {
+ if (x == x->parent->left) {
+ w=x->parent->right;
+ if (w->color == RED) {
+ w->color=BLACK;
+ x->parent->color=RED;
+ LeftRotate(x->parent);
+ w=x->parent->right;
+ }
+ if ( (w->right->color == BLACK) && (w->left->color == BLACK) ) {
+ w->color=RED;
+ x=x->parent;
+ } else {
+ if (w->right->color == BLACK) {
+ w->left->color=BLACK;
+ w->color=RED;
+ RightRotate(w);
+ w=x->parent->right;
+ }
+ w->color=x->parent->color;
+ x->parent->color=BLACK;
+ w->right->color=BLACK;
+ LeftRotate(x->parent);
+ x=rootLeft; /* this is to exit while loop */
+ }
+ } else { /* the code below is has left and right switched from above */
+ w=x->parent->left;
+ if (w->color == RED) {
+ w->color=BLACK;
+ x->parent->color=RED;
+ RightRotate(x->parent);
+ w=x->parent->left;
+ }
+ if ( (w->right->color == BLACK) && (w->left->color == BLACK) ) {
+ w->color=RED;
+ x=x->parent;
+ } else {
+ if (w->left->color == BLACK) {
+ w->right->color=BLACK;
+ w->color=RED;
+ LeftRotate(w);
+ w=x->parent->left;
+ }
+ w->color=x->parent->color;
+ x->parent->color=BLACK;
+ w->left->color=BLACK;
+ RightRotate(x->parent);
+ x=rootLeft; /* this is to exit while loop */
+ }
+ }
+ }
+ x->color=BLACK;
+
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ check();
+#elif defined(DEBUG_ASSERT)
+ assert(nil->color != BLACK || !"nil not black in ITDeleteFixUp");
+ assert((nil->maxHigh!=std::numeric_limits<N>::min())
+ || !"nil->maxHigh != std::numeric_limits<N>::min() in ITDeleteFixUp");
+#endif
+}
+
+
+/***********************************************************************/
+/* FUNCTION: remove */
+/**/
+/* INPUTS: tree is the tree to delete node z from */
+/**/
+/* OUTPUT: returns the Interval stored at deleted node */
+/**/
+/* EFFECT: Deletes z from tree and but don't call destructor */
+/* Then calls FixUpMaxHigh to fix maxHigh fields then calls */
+/* ITDeleteFixUp to restore red-black properties */
+/**/
+/* Modifies Input: z */
+/**/
+/* The algorithm from this function is from _Introduction_To_Algorithms_ */
+/***********************************************************************/
+
+template<typename T, typename N>
+T IntervalTree<T,N>::remove(IntervalTree<T,N>::Node * z){
+ typename IntervalTree<T,N>::Node* y;
+ typename IntervalTree<T,N>::Node* x;
+ T returnValue = z->value();
+
+ y= ((z->left == nil) || (z->right == nil)) ? z : GetSuccessorOf(z);
+ x= (y->left == nil) ? y->right : y->left;
+ if (root == (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */
+ root->left=x;
+ } else {
+ if (y == y->parent->left) {
+ y->parent->left=x;
+ } else {
+ y->parent->right=x;
+ }
+ }
+ if (y != z) { /* y should not be nil in this case */
+
+#ifdef DEBUG_ASSERT
+ assert( (y!=nil) || !"y is nil in remove");
+#endif
+ /* y is the node to splice out and x is its child */
+
+ y->maxHigh = std::numeric_limits<N>::min();
+ y->left=z->left;
+ y->right=z->right;
+ y->parent=z->parent;
+ z->left->parent=z->right->parent=y;
+ if (z == z->parent->left) {
+ z->parent->left=y;
+ } else {
+ z->parent->right=y;
+ }
+ FixUpMaxHigh(x->parent);
+ if (y->color == BLACK) {
+ y->color = z->color;
+ DeleteFixUp(x);
+ } else
+ y->color = z->color;
+ delete z;
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ check();
+#elif defined(DEBUG_ASSERT)
+ assert(nil->color != BLACK || !"nil not black in ITDelete");
+ assert((nil->maxHigh!=std::numeric_limits<N>::min())
+ && !"nil->maxHigh != std::numeric_limits<N>::min() in ITDelete");
+#endif
+ } else {
+ FixUpMaxHigh(x->parent);
+ if (y->color == BLACK) DeleteFixUp(x);
+ delete y;
+#ifdef CHECK_INTERVAL_TREE_ASSUMPTIONS
+ check();
+#elif defined(DEBUG_ASSERT)
+ assert(nil->color != BLACK || !"nil not black in ITDelete");
+ assert((nil->maxHigh!=std::numeric_limits<N>::min())
+ || !"nil->maxHigh != std::numeric_limits<N>::min() in ITDelete");
+#endif
+ }
+ return returnValue;
+}
+
+template <typename T, typename N>
+void IntervalTree<T,N>::remove(N low, N high, std::vector<T> &removed)
+{
+ typename std::vector<typename IntervalTree<T,N>::Node*> got;
+ fetch_node(low, high, got);
+ for (typename std::vector<typename IntervalTree<T,N>::Node*>::const_iterator
+ i=got.begin(); i!=got.end(); ++i)
+ {
+ removed.push_back((*i)->value());
+ remove(*i);
+ }
+}
+
+template <typename T, typename N> template <typename F>
+void IntervalTree<T,N>::remove(N low, N high, const F &removeFunctor, std::vector<T> &removed)
+{
+ typename std::vector<typename IntervalTree<T,N>::Node*> got;
+ fetch_node(low, high, got);
+ for (typename std::vector<typename IntervalTree<T,N>::Node*>::const_iterator
+ i=got.begin(); i!=got.end(); ++i)
+ {
+ if (removeFunctor((*i)->value(), (*i)->low(), (*i)->high())) {
+ removed.push_back((*i)->value());
+ remove(*i);
+ }
+ }
+}
+
+template <typename T, typename N>
+void IntervalTree<T,N>::remove_window(N low, N high, std::vector<T> &removed)
+{
+ typename std::vector<typename IntervalTree<T,N>::Node*> got;
+ fetch_window_node(low, high, got);
+ for (typename std::vector<typename IntervalTree<T,N>::Node*>::const_iterator
+ i=got.begin(); i!=got.end(); ++i)
+ {
+ removed.push_back((*i)->value());
+ remove(*i);
+ }
+}
+
+template <typename T, typename N> template <typename F>
+void IntervalTree<T,N>::remove_window(
+ N low,
+ N high,
+ const F& removeFunctor,
+ std::vector<T> &removed)
+{
+ typename std::vector<typename IntervalTree<T,N>::Node*> got;
+ fetch_window_node(low, high, got);
+ for (typename std::vector<typename IntervalTree<T,N>::Node*>::const_iterator
+ i=got.begin(); i!=got.end(); ++i)
+ {
+ if (removeFunctor((*i)->value(), (*i)->low(), (*i)->high())) {
+ removed.push_back((*i)->value());
+ remove(*i);
+ }
+ }
+}
+
+/***********************************************************************/
+/* FUNCTION: Overlap */
+/**/
+/* INPUTS: [a1,a2) and [b1,b2) are the low and high endpoints of two */
+/* intervals. */
+/**/
+/* OUTPUT: stack containing pointers to the nodes between [low,high) */
+/**/
+/* Modifies Input: none */
+/**/
+/* EFFECT: returns 1 if the intervals overlap, and 0 otherwise */
+/***********************************************************************/
+
+template<typename T, typename N>
+N IntervalTree<T,N>::Overlap(N a1, N a2, N b1, N b2) {
+ return a1 <= b2 && b1 <= a2;
+}
+
+
+template<typename T, typename N>
+N IntervalTree<T,N>::Contain(N a1, N a2, N b1, N b2) {
+ return a1 <= b1 && b2 <= a2;
+}
+
+/***********************************************************************/
+/* FUNCTION: fetch */
+/**/
+/* INPUTS: tree is the tree to look for intervals overlapping the */
+/* interval [low,high) */
+/**/
+/* OUTPUT: stack containing pointers to the nodes overlapping */
+/* [low,high) */
+/**/
+/* Modifies Input: none */
+/**/
+/* EFFECT: Returns a stack containing pointers to nodes containing */
+/* intervals which overlap [low,high) in O(max(N,k*log(N))) */
+/* where N is the number of intervals in the tree and k is */
+/* the number of overlapping intervals */
+/**/
+/* Note: This basic idea for this function comes from the */
+/* _Introduction_To_Algorithms_ book by Cormen et al, but */
+/* modifications were made to return all overlapping intervals */
+/* instead of just the first overlapping interval as in the */
+/* book. The natural way to do this would require recursive */
+/* calls of a basic search function. I translated the */
+/* recursive version into an interative version with a stack */
+/* as described below. */
+/***********************************************************************/
+
+
+
+/* The basic idea for the function below is to take the IntervalSearch */
+/* function from the book and modify to find all overlapping intervals */
+/* instead of just one. This means that any time we take the left */
+/* branch down the tree we must also check the right branch if and only if */
+/* we find an overlapping interval in that left branch. Note this is a */
+/* recursive condition because if we go left at the root then go left */
+/* again at the first left child and find an overlap in the left subtree */
+/* of the left child of root we must recursively check the right subtree */
+/* of the left child of root as well as the right child of root. */
+
+template<typename T, typename N>
+void IntervalTree<T,N>::fetch(N low, N high, std::vector<T> &enumResultStack) {
+ typename IntervalTree<T,N>::Node* x=root->left;
+ bool stuffToDo = (x != nil);
+
+ // Possible speed up: add min field to prune right searches //
+
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when entering IntervalTree::fetch");
+#endif
+ currentParent = 0;
+
+ while(stuffToDo) {
+ if (Overlap(low,high,x->key,x->high_) ) {
+ enumResultStack.push_back(x->value());
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ }
+ if(x->left->maxHigh >= low) { // implies x != nil
+ recursionNodeStack.push_back(it_recursion_node());
+ recursionNodeStack.back().start_node = x;
+ recursionNodeStack.back().tryRightBranch = false;
+ recursionNodeStack.back().parentIndex = currentParent;
+ currentParent = recursionNodeStack.size()-1;
+ x = x->left;
+ } else {
+ x = x->right;
+ }
+ stuffToDo = (x != nil);
+ while( (!stuffToDo) && (recursionNodeStack.size() > 1) ) {
+ it_recursion_node back = recursionNodeStack.back();
+ recursionNodeStack.pop_back();
+
+ if(back.tryRightBranch) {
+ x=back.start_node->right;
+ currentParent=back.parentIndex;
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ stuffToDo = ( x != nil);
+ }
+ }
+ }
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when exiting IntervalTree::fetch");
+#endif
+}
+
+template<typename T, typename N>
+T IntervalTree<T,N>::fetch_nearest_up(IntervalTree<T,N>::Node* x, N value) {
+
+ if(x == nil)
+ return T();
+
+ if(x->key > value) {
+ // Maybe there is a better interval candidate in the left subtree
+ if(x->left != nil) {
+ T best_left_value = fetch_nearest_up(x->left,value);
+ if (best_left_value.defined())
+ return best_left_value;
+ }
+ return x->value();
+ } else {
+ return fetch_nearest_up(x->right,value);
+ }
+}
+
+template<typename T, typename N>
+T IntervalTree<T,N>::fetch_nearest_up(N value) {
+ return fetch_nearest_up(root->left,value);
+}
+
+template<typename T, typename N>
+typename IntervalTree<T,N>::Node* IntervalTree<T,N>::fetch_nearest_down(IntervalTree<T,N>::Node* x, N value) {
+
+ if (x == nil)
+ return NULL;
+
+ if(x->key > value) {
+ return fetch_nearest_down(x->left,value);
+ } else {
+ // There is not a better interval in the subtrees
+ if(x->high_ == x->maxHigh && x->high_ <= value) {
+ return x;
+ } else {
+ typename IntervalTree<T,N>::Node* best_node = NULL;
+ if(x->high_ <= value) {
+ best_node = x;
+ }
+ // Is there a closer interval in the left subtree
+ if(x->left != nil) {
+ typename IntervalTree<T,N>::Node* best_node_left = fetch_nearest_down(x->left,value);
+ if(best_node == NULL) {
+ best_node = best_node_left;
+ } else if(best_node_left != NULL && best_node_left->high_ > best_node->high_) {
+ best_node = best_node_left;
+ }
+ }
+ // Is there a closer interval in the right subtree
+ if(x->right != nil) {
+ typename IntervalTree<T,N>::Node* best_node_right = fetch_nearest_down(x->right,value);
+ if(best_node == NULL) {
+ best_node = best_node_right;
+ } else if(best_node_right != NULL && best_node_right->high_ > best_node->high_) {
+ best_node = best_node_right;
+ }
+ }
+ return best_node;
+ }
+ }
+}
+
+template<typename T, typename N>
+T IntervalTree<T,N>::fetch_nearest_down(N value) {
+ typename IntervalTree<T,N>::Node* best_node = fetch_nearest_down(root->left,value);
+ if(best_node)
+ return best_node->value();
+ else
+ return T();
+}
+
+
+template<typename T, typename N>
+void IntervalTree<T,N>::fetch_node(
+ N low,
+ N high,
+ std::vector<typename IntervalTree<T,N>::Node*> &enumResultStack)
+{
+ typename IntervalTree<T,N>::Node* x=root->left;
+ bool stuffToDo = (x != nil);
+
+ // Possible speed up: add min field to prune right searches //
+
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when entering IntervalTree::fetch");
+#endif
+ currentParent = 0;
+
+ while(stuffToDo) {
+ if (Overlap(low,high,x->key,x->high_) ) {
+ enumResultStack.push_back(x);
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ }
+ if(x->left->maxHigh >= low) { // implies x != nil
+ recursionNodeStack.push_back(it_recursion_node());
+ recursionNodeStack.back().start_node = x;
+ recursionNodeStack.back().tryRightBranch = false;
+ recursionNodeStack.back().parentIndex = currentParent;
+ currentParent = recursionNodeStack.size()-1;
+ x = x->left;
+ } else {
+ x = x->right;
+ }
+ stuffToDo = (x != nil);
+ while( (!stuffToDo) && (recursionNodeStack.size() > 1) ) {
+ it_recursion_node back = recursionNodeStack.back();
+ recursionNodeStack.pop_back();
+
+ if(back.tryRightBranch) {
+ x=back.start_node->right;
+ currentParent=back.parentIndex;
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ stuffToDo = ( x != nil);
+ }
+ }
+ }
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when exiting IntervalTree::fetch");
+#endif
+}
+
+template<typename T, typename N>
+void IntervalTree<T,N>::fetch_window(N low, N high, std::vector<T> &enumResultStack)
+{
+ typename IntervalTree<T,N>::Node* x=root->left;
+ bool stuffToDo = (x != nil);
+
+ // Possible speed up: add min field to prune right searches //
+
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when entering IntervalTree::fetch_window");
+#endif
+ currentParent = 0;
+
+ while(stuffToDo) {
+ if (Contain(low,high,x->key,x->high_) ) {
+ enumResultStack.push_back(x->value());
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ }
+ if(x->left->maxHigh >= low) { // implies x != nil
+ recursionNodeStack.push_back(it_recursion_node());
+ recursionNodeStack.back().start_node = x;
+ recursionNodeStack.back().tryRightBranch = false;
+ recursionNodeStack.back().parentIndex = currentParent;
+ currentParent = recursionNodeStack.size()-1;
+ x = x->left;
+ } else {
+ x = x->right;
+ }
+ stuffToDo = (x != nil);
+ while( (!stuffToDo) && (recursionNodeStack.size() > 1) ) {
+ it_recursion_node back = recursionNodeStack.back();
+ recursionNodeStack.pop_back();
+
+ if(back.tryRightBranch) {
+ x=back.start_node->right;
+ currentParent=back.parentIndex;
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ stuffToDo = ( x != nil);
+ }
+ }
+ }
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when exiting IntervalTree::fetch");
+#endif
+}
+
+template<typename T, typename N>
+void IntervalTree<T,N>::fetch_window_node(
+ N low,
+ N high,
+ std::vector<typename IntervalTree<T,N>::Node*> &enumResultStack)
+{
+ typename IntervalTree<T,N>::Node* x=root->left;
+ bool stuffToDo = (x != nil);
+
+ // Possible speed up: add min field to prune right searches //
+
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when entering IntervalTree::fetch_window_node");
+#endif
+ currentParent = 0;
+
+ while(stuffToDo) {
+ if (Contain(low,high,x->key,x->high_) ) {
+ enumResultStack.push_back(x);
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ }
+ if(x->left->maxHigh >= low) { // implies x != nil
+ recursionNodeStack.push_back(it_recursion_node());
+ recursionNodeStack.back().start_node = x;
+ recursionNodeStack.back().tryRightBranch = false;
+ recursionNodeStack.back().parentIndex = currentParent;
+ currentParent = recursionNodeStack.size()-1;
+ x = x->left;
+ } else {
+ x = x->right;
+ }
+ stuffToDo = (x != nil);
+ while( (!stuffToDo) && (recursionNodeStack.size() > 1) ) {
+ it_recursion_node back = recursionNodeStack.back();
+ recursionNodeStack.pop_back();
+
+ if(back.tryRightBranch) {
+ x=back.start_node->right;
+ currentParent=back.parentIndex;
+ recursionNodeStack[currentParent].tryRightBranch=true;
+ stuffToDo = ( x != nil);
+ }
+ }
+ }
+#ifdef DEBUG_ASSERT
+ assert((recursionNodeStack.size() == 1)
+ || !"recursionStack not empty when exiting IntervalTree::fetch");
+#endif
+}
+
+template<typename T, typename N>
+bool IntervalTree<T,N>::CheckMaxHighFieldsHelper(IntervalTree<T,N>::Node * y,
+ const N currentHigh,
+ bool match) const
+{
+ if (y != nil) {
+ match = CheckMaxHighFieldsHelper(y->left,currentHigh,match) ?
+ true : match;
+ if (y->high_ == currentHigh)
+ match = true;
+ match = CheckMaxHighFieldsHelper(y->right,currentHigh,match) ?
+ true : match;
+ }
+ return match;
+}
+
+
+
+/* Make sure the maxHigh fields for everything makes sense. *
+ * If something is wrong, print a warning and exit */
+template<typename T, typename N>
+void IntervalTree<T,N>::CheckMaxHighFields(IntervalTree<T,N>::Node * x) const {
+ if (x != nil) {
+ CheckMaxHighFields(x->left);
+ if(!(CheckMaxHighFieldsHelper(x,x->maxHigh,false) > 0)) {
+ assert(0);
+ }
+ CheckMaxHighFields(x->right);
+ }
+}
+
+template<typename T, typename N>
+void IntervalTree<T,N>::check() const {
+ CheckMaxHighFields(root->left);
+}
+
+#endif
+
diff --git a/src/test_main.cc b/src/test_main.cc
new file mode 100644
index 0000000..101dca5
--- /dev/null
+++ b/src/test_main.cc
@@ -0,0 +1,46 @@
+#include <cstdio>
+#include <cmath>
+#include <ctime>
+#include <cstdlib>
+#include <vector>
+#include <string>
+#include <iostream>
+
+#include "interval_tree.h"
+
+int main(int argc, char *argv[])
+{
+ int low;
+ int high;
+
+ IntervalTree<int> intervalTree;
+ int count = 1000;
+ int domain = 1000;
+ std::cout << "Inserting " << count <<
+ " nodes into [0," << domain << "]." << std::endl;
+
+ srand(time(NULL));
+ for(int i=0; i<count; i++) {
+ low = rand() % domain;
+ high = (rand() % (domain-low)) + low;
+
+ intervalTree.insert(i, low, high);
+ // std::cout << "Added: [" << low << "," << high << "]" << std::endl;
+ if(!(i%25000)){std::cout << "*";fflush(0);}
+ }
+ std::cout << std::endl;
+
+ low = domain * 0.4f;
+ high = domain * 0.5f;//10% of the domain is being tested
+ std::cout << "Enumerating intervals between " << low
+ << " and " << high << std::endl;
+ std::vector<int> results = intervalTree.fetch(low,high);
+ std::cout << results.size() << " intervals found." << std::endl;
+
+ for(int i=0; i<results.size(); i++) {
+ std::cout << results[i] << ",";
+ }
+ std::cout << std::endl;
+ return 0;
+}
+
diff --git a/t/Set-IntervalTree.t b/t/Set-IntervalTree.t
new file mode 100644
index 0000000..6a84262
--- /dev/null
+++ b/t/Set-IntervalTree.t
@@ -0,0 +1,66 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl Set-IntervalTree.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test::More tests => 4;
+BEGIN { use_ok('Set::IntervalTree') };
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
+use strict;
+use warnings;
+$|=1;
+
+my $tree = Set::IntervalTree->new;
+ok($tree);
+
+my $count = 1000;
+my $domain = 1000;
+print "Inserting $count nodes into [0,$domain].\n";
+srand(time);
+
+my $i;
+for $i (0..$count-1) {
+ my $low = int(rand() * $domain);
+ my $high = int((rand() * ($domain-$low))+$low)+1;
+ $tree->insert($i,$low,$high);
+# print "Added: [$low,$high]\n";
+ print "*" if !($i%25000);
+}
+print "\n";
+# print "Tree: ".$tree->str;
+
+my $low = int($domain * 0.4);
+my $high = int($domain * 0.5);
+print "Enumerating intervals between $low and $high\n";
+my $results = $tree->fetch($low,$high);
+ok($results);
+print scalar(@$results)." intervals found.\n";
+
+# for my $i (0..$#$results) {
+# print $results->[$i].",";
+# }
+
+print "Removing all values greater than 500\n";
+my $r=0;
+my $removed = $tree->remove(0, $domain, sub {
+ my ($i, $low, $high) = @_;
+ if ($i > 500) {
+ print "\$i=$i, \$low=$low, \$high=$high\n";
+ $r++;
+ }
+ return $i > 500;
+ });
+ok($removed && @$removed == $r);
+print "Successfully removed ".scalar(@$removed)." items\n";
+
+print "\n";
+
+exit 0;
+
diff --git a/t/fetch-nearest.t b/t/fetch-nearest.t
new file mode 100644
index 0000000..6210507
--- /dev/null
+++ b/t/fetch-nearest.t
@@ -0,0 +1,21 @@
+
+use Test::More tests => 9;
+BEGIN { use_ok('Set::IntervalTree') };
+
+use strict;
+use warnings;
+
+my $tree = Set::IntervalTree->new;
+$tree->insert("A",1,2);
+$tree->insert("B",2,3);
+$tree->insert("C",6,10);
+$tree->insert("D",4,12);
+
+is($tree->fetch_nearest_up(2), "D");
+is($tree->fetch_nearest_up(5), "C");
+is($tree->fetch_nearest_up(1), "B");
+is($tree->fetch_nearest_up(7), undef);
+is($tree->fetch_nearest_down(7), "B");
+is($tree->fetch_nearest_down(3), "B");
+is($tree->fetch_nearest_down(11), "C");
+is($tree->fetch_nearest_down(1), undef);
diff --git a/typemap b/typemap
new file mode 100644
index 0000000..2b1e595
--- /dev/null
+++ b/typemap
@@ -0,0 +1,20 @@
+TYPEMAP
+
+PerlIntervalTree * O_OBJECT
+PerlIntervalTree_Node * PERLINTERVALTREE_NODE
+
+OUTPUT
+
+PERLINTERVALTREE_NODE
+ sv_setref_pv( $arg, \"Set::IntervalTree::Node\", (void*)$var );
+
+INPUT
+
+PERLINTERVALTREE_NODE
+ if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
+ $var = ($type)SvIV((SV*)SvRV( $arg ));
+ else{
+ warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
+ XSRETURN_UNDEF;
+ }
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libset-intervaltree-perl.git
More information about the Pkg-perl-cvs-commits
mailing list