[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