initial working frustum culling implementation
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Fri, 21 Aug 2009 06:13:20 +0000 (00:13 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Fri, 21 Aug 2009 06:13:20 +0000 (00:13 -0600)
46 files changed:
configure.ac
data/scenes/Test.json
src/Makefile.am
src/Moof/Aabb.cc
src/Moof/Aabb.hh
src/Moof/Camera.cc
src/Moof/Camera.hh
src/Moof/Engine.cc
src/Moof/Engine.hh
src/Moof/Entity.hh
src/Moof/Frustum.cc [new file with mode: 0644]
src/Moof/Frustum.hh
src/Moof/Hash.cc [new file with mode: 0644]
src/Moof/Hash.hh [new file with mode: 0644]
src/Moof/Math.hh
src/Moof/Mippleton.hh
src/Moof/Octree.hh
src/Moof/Plane.cc [new file with mode: 0644]
src/Moof/Plane.hh
src/Moof/Scene.cc
src/Moof/Scene.hh
src/Moof/Sphere.cc [new file with mode: 0644]
src/Moof/Sphere.hh [new file with mode: 0644]
src/Moof/Texture.cc
src/Moof/Texture.hh
src/Moof/Tree.hh
src/Moof/stlplus/containers.hpp [new file with mode: 0755]
src/Moof/stlplus/containers_fixes.hpp [new file with mode: 0755]
src/Moof/stlplus/digraph.hpp [new file with mode: 0755]
src/Moof/stlplus/digraph.tpp [new file with mode: 0755]
src/Moof/stlplus/exceptions.hpp [new file with mode: 0755]
src/Moof/stlplus/foursome.hpp [new file with mode: 0755]
src/Moof/stlplus/foursome.tpp [new file with mode: 0755]
src/Moof/stlplus/hash.hpp [new file with mode: 0755]
src/Moof/stlplus/hash.tpp [new file with mode: 0755]
src/Moof/stlplus/matrix.hpp [new file with mode: 0755]
src/Moof/stlplus/matrix.tpp [new file with mode: 0755]
src/Moof/stlplus/ntree.hpp [new file with mode: 0755]
src/Moof/stlplus/ntree.tpp [new file with mode: 0755]
src/Moof/stlplus/safe_iterator.hpp [new file with mode: 0755]
src/Moof/stlplus/safe_iterator.tpp [new file with mode: 0755]
src/Moof/stlplus/smart_ptr.hpp [new file with mode: 0755]
src/Moof/stlplus/smart_ptr.tpp [new file with mode: 0755]
src/Moof/stlplus/triple.hpp [new file with mode: 0755]
src/Moof/stlplus/triple.tpp [new file with mode: 0755]
src/YoinkApp.cc

index 7884e484f7338cfc8bc62a1499f7da772133ac1e..e8d8d9b090eddaa5ff27e84f0ee3ef205c81a86c 100644 (file)
@@ -39,8 +39,8 @@ AC_ARG_ENABLE([debug],
                          [debug=$enableval
                           if test x$debug = xyes
                           then
-                                  CFLAGS="-Wall -Werror -g -O0 -DDEBUG"
-                                  CXXFLAGS="-Wall -Werror -g -O0 -DDEBUG"
+                                  CFLAGS="-Wall -Werror -gstabs+ -O0 -DDEBUG"
+                                  CXXFLAGS="-Wall -Werror -gstabs+ -O0 -DDEBUG"
                           else
                                   CFLAGS="-O2 -DNDEBUG"
                                   CXXFLAGS="-O2 -DNDEBUG"
index 562a3befec0cb3224423f30392716e4c6b2c8c54..db9ba5d1e626cc147b8fd17fd6a0a567373ab2b1 100644 (file)
@@ -1,6 +1,6 @@
 {
        "playfield_bounds": [0, 0, -100, 1280, 500, 100],
-       "maximum_bounds": [-160, 0, -192, 1440, 512, 224],
+       "maximum_bounds": [-165, -5, -197, 1445, 517, 229],
        "instructions":
        [
 
index 62c10cafa3d2fe5ca81a7730c7dd49235efd6e1a..1d320e691cbbd2a87a753e02555722f21258f6a7 100644 (file)
@@ -20,13 +20,17 @@ libmoof_la_SOURCES = \
                                   Moof/Engine.hh \
                                   Moof/Entity.hh \
                                   Moof/Event.hh \
+                                  Moof/Frustum.cc \
                                   Moof/Frustum.hh \
+                                  Moof/Hash.cc \
+                                  Moof/Hash.hh \
                                   Moof/Interpolator.hh \
                                   Moof/Math.hh \
                                   Moof/Mippleton.hh \
                                   Moof/Octree.hh \
                                   Moof/OpenGL.cc \
                                   Moof/OpenGL.hh \
+                                  Moof/Plane.cc \
                                   Moof/Plane.hh \
                                   Moof/Profiler.hh \
                                   Moof/Random.cc \
@@ -42,6 +46,8 @@ libmoof_la_SOURCES = \
                                   Moof/Settings.cc \
                                   Moof/Settings.hh \
                                   Moof/Singleton.hh \
+                                  Moof/Sphere.cc \
+                                  Moof/Sphere.hh \
                                   Moof/StringTools.cc \
                                   Moof/StringTools.hh \
                                   Moof/Texture.cc \
index d81c971f78947d61a0df5d5b0de4344c46f93b16..c844251b1d0551b2fcf9c94a8ddf2929c11baf6e 100644 (file)
 
 #include <Moof/Aabb.hh>
 #include <Moof/Camera.hh>
+#include <Moof/OpenGL.hh>
+#include <Moof/Texture.hh>
 
 
 namespace Mf {
 
 
+void Aabb::getOctant(Aabb& octant, int num) const
+{
+       Vector3 mid = getCenter();
+
+       switch (num)
+       {
+               case 0:
+                       octant.init(Vector3(min[0], min[1], mid[2]),
+                                               Vector3(mid[0], mid[1], max[2]));
+                       break;
+               case 1:
+                       octant.init(Vector3(mid[0], min[1], mid[2]),
+                                               Vector3(max[0], mid[1], max[2]));
+                       break;
+               case 2:
+                       octant.init(mid, max);
+                       break;
+               case 3:
+                       octant.init(Vector3(min[0], mid[1], mid[2]),
+                                               Vector3(mid[0], max[1], max[2]));
+                       break;
+               case 4:
+                       octant.init(min, mid);
+                       break;
+               case 5:
+                       octant.init(Vector3(mid[0], min[1], min[2]),
+                                               Vector3(max[0], mid[1], mid[2]));
+                       break;
+               case 6:
+                       octant.init(Vector3(mid[0], mid[1], min[2]),
+                                               Vector3(max[0], max[1], mid[2]));
+                       break;
+               case 7:
+                       octant.init(Vector3(min[0], mid[1], min[2]),
+                                               Vector3(mid[0], max[1], mid[2]));
+                       break;
+       }
+}
+
+
+void Aabb::getCorners(Vector3 corners[8]) const
+{
+       corners[0][0] = min[0]; corners[0][1] = min[1]; corners[0][2] = max[2];
+       corners[1][0] = max[0]; corners[1][1] = min[1]; corners[1][2] = max[2];
+       corners[2][0] = max[0]; corners[2][1] = max[1]; corners[2][2] = max[2];
+       corners[3][0] = min[0]; corners[3][1] = max[1]; corners[3][2] = max[2];
+       corners[4][0] = min[0]; corners[4][1] = min[1]; corners[4][2] = min[2];
+       corners[5][0] = max[0]; corners[5][1] = min[1]; corners[5][2] = min[2];
+       corners[6][0] = max[0]; corners[6][1] = max[1]; corners[6][2] = min[2];
+       corners[7][0] = min[0]; corners[7][1] = max[1]; corners[7][2] = min[2];
+}
+
+
+void Aabb::encloseVertices(const Vector3 vertices[], unsigned count)
+{
+       min = vertices[0];
+       max = vertices[0];
+
+       for (unsigned i = 1; i < count; ++i)
+       {
+               if (vertices[i][0] < min[0]) min[0] = vertices[i][0];
+               if (vertices[i][0] > max[0]) max[0] = vertices[i][0];
+               if (vertices[i][1] < min[1]) min[1] = vertices[i][1];
+               if (vertices[i][1] > max[1]) max[1] = vertices[i][1];
+               if (vertices[i][2] < min[2]) min[2] = vertices[i][2];
+               if (vertices[i][2] > max[2]) max[2] = vertices[i][2];
+       }
+}
+
+
 void Aabb::draw(Scalar alpha) const
 {
        Scalar vertices[] = {min[0], min[1], min[2],
@@ -52,14 +124,23 @@ void Aabb::draw(Scalar alpha) const
                                                 4, 5, 6, 7};
 
        glEnableClientState(GL_VERTEX_ARRAY);
+       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glVertexPointer(3, GL_SCALAR, 0, vertices);
 
+       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+       Texture::resetBind();
+
        glDrawElements(GL_QUADS, sizeof(indices), GL_UNSIGNED_BYTE, indices);
+
+       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+       //glDisableClientState(GL_VERTEX_ARRAY);
+
+       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
 
 bool Aabb::isVisible(const Camera& cam) const
 {
-       return cam.getFrustum().checkAabb(*this);
+       return cam.getFrustum().containsAabb(*this);
 }
 
 
index f51531a49d49db13e1fd3f87b77510c59ed747c4..457d198495e9a358fd40e304b3236730e501af57 100644 (file)
@@ -32,6 +32,7 @@
 #include <Moof/Cullable.hh>
 #include <Moof/Drawable.hh>
 #include <Moof/Math.hh>
+#include <Moof/Plane.hh>
 
 
 namespace Mf {
@@ -104,6 +105,36 @@ struct Aabb : public Cullable, public Drawable
                                           (min[2] + max[2]) / 2.0);
        }
 
+       void getOctant(Aabb& octant, int num) const;
+
+       inline Plane getPlaneXY() const
+       {
+               Plane plane;
+               plane.normal = Vector3(0.0, 0.0, 1.0);
+               plane.d = cml::dot(-plane.normal, getCenter());
+               return plane;
+       }
+
+       inline Plane getPlaneXZ() const
+       {
+               Plane plane;
+               plane.normal = Vector3(0.0, 1.0, 0.0);
+               plane.d = cml::dot(-plane.normal, getCenter());
+               return plane;
+       }
+
+       inline Plane getPlaneYZ() const
+       {
+               Plane plane;
+               plane.normal = Vector3(1.0, 0.0, 0.0);
+               plane.d = cml::dot(-plane.normal, getCenter());
+               return plane;
+       }
+
+       void getCorners(Vector3 corners[8]) const;
+
+       void encloseVertices(const Vector3 vertices[], unsigned count);
+
        void draw(Scalar alpha = 0.0) const;
        bool isVisible(const Camera& cam) const;
 };
index 26e24ba358fbfd7494517a66409e75c5150f8b59..cdebc7a7b735b7e681e3b28f041f576aa9166d7f 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <iostream>
 #include <Moof/Camera.hh>
+#include <Moof/OpenGL.hh>
 
 
 namespace Mf {
@@ -35,31 +36,47 @@ namespace Mf {
 
 void Camera::setPosition(const Vector3& point)
 {
-       //position_ = point;
-       Vector3 coeff[2] = {position_, point};
-       pInterp_.init(coeff, 0.1);
+       position_ = point;
+       //Vector3 coeff[2] = {position_, point};
+       //pInterp_.init(coeff, 0.1);
 }
 void Camera::setRotation(const Quaternion& rotation)
 {
        rotation_ = rotation;
-       //srcRotation_ = rotation_;
-       //dstRotation_ = rotation;
-       //tInterp_ = 0.0;
 }
 
-void Camera::update(Scalar t, Scalar dt)
+
+void Camera::setProjection(const Matrix4& projection)
 {
-       pInterp_.update(dt);
-       position_ = pInterp_.getState(0.0);
+       projection_ = projection;
+}
 
-       //tInterp_ += dt * 10.0;
-       //rotation_ = cml::slerp(srcRotation_, dstRotation_, cml::clamp(tInterp_, 0.0, 1.0));
-       //rotation_.normalize();
+void Camera::setProjection(Scalar fovy, Scalar aspect, Scalar near, Scalar far)
+{
+       cml::matrix_perspective_yfov_RH(projection_, fovy, aspect, near, far,
+                       cml::z_clip_neg_one);
 
        calculateSecondary();
 }
 
 
+void Camera::uploadProjectionToGL() const
+{
+       glMatrixMode(GL_PROJECTION);
+       glLoadMatrix(projection_.data());
+
+       glMatrixMode(GL_MODELVIEW);
+}
+
+void Camera::update(Scalar t, Scalar dt)
+{
+       //pInterp_.update(dt);
+       //position_ = pInterp_.getState(0.0);
+
+       //calculateSecondary();
+}
+
+
 void Camera::lookAt(const Vector3& point)
 {
        quaternion_rotation_aim_at(rotation_, position_, point);
@@ -150,13 +167,15 @@ void Camera::adjustFromInput(const Event& event)
 
 void Camera::calculateSecondary()
 {
-       matrix_rotation_quaternion(transformation_, rotation_);
+       matrix_rotation_quaternion(modelview_, rotation_);
 
        Matrix4 translate;
        matrix_translation(translate, position_);
 
-       //transformation_ = translate * transformation_;
-       transformation_ *= translate;
+       //modelview_ = translate * modelview_;
+       modelview_ *= translate;
+
+       frustum_.init(modelview_, projection_);
 }
 
 
index 0aa5dc9990cf5c3f97f23b0db1b76467e91fc143..63d00749555a13c2052027dc8b0bb069e4856ecc 100644 (file)
@@ -47,19 +47,22 @@ public:
                position_(0.0, 0.0, 0.0)
        {
                quaternion_rotation_world_y(rotation_, 0.0);
-               srcRotation_ = rotation_;
-               dstRotation_ = rotation_;
                calculateSecondary();
        }
 
        void setPosition(const Vector3& point);
        void setRotation(const Quaternion& rotation);
 
+       void setProjection(const Matrix4& projection);
+       void setProjection(Scalar fovy, Scalar aspect, Scalar near, Scalar far);
+
+       void uploadProjectionToGL() const;
+
        void lookAt(const Vector3& point);
 
-       const Matrix4& getTransformation() const
+       const Matrix4& getModelviewMatrix() const
        {
-               return transformation_;
+               return modelview_;
        }
 
        const Frustum& getFrustum() const
@@ -73,15 +76,12 @@ public:
 private:
        Vector3         position_;
        Quaternion      rotation_;
+       Matrix4         projection_;
 
-       Matrix4         transformation_;
+       Matrix4         modelview_;
        Frustum         frustum_;
 
        Lerpv3          pInterp_;
-
-       Quaternion      srcRotation_;
-       Quaternion      dstRotation_;
-       Scalar          tInterp_;
 };
 
 
index be8ca5fac61e184f0b54a0da244355e5b33e89a2..53fca73e9e883cfab1d18aced70cd125391f26d1 100644 (file)
@@ -103,7 +103,7 @@ public:
         * The main loop.  This just calls dispatchEvents(), update(), and draw()
         * over and over again.  The timing of the update and draw are decoupled.
         * The actual frame rate is also calculated here.  This function will return
-        * with a value of 0 if the member variable running becomes true.
+        * the exit code used to stop the loop.
         */
 
        int run()
@@ -141,6 +141,10 @@ public:
 
                                nextStep += timestep;
                        }
+                       if (ticksNow >= nextStep)
+                       {
+                               nextStep = ticksNow + timestep;
+                       }
 
                        if (ticksNow >= nextDraw)
                        {
@@ -179,7 +183,7 @@ public:
                }
                while (running);
 
-               return 0;
+               return exitCode;
        }
 
 
@@ -216,6 +220,7 @@ public:
        VideoPtr        video;
 
        bool            running;
+       int                     exitCode;
 
        Scalar          timestep;
        Scalar          drawRate;
@@ -238,9 +243,10 @@ int Engine::run()
        return impl_->run();
 }
 
-void Engine::stop()
+void Engine::stop(int exitCode)
 {
        impl_->running = false;
+       impl_->exitCode = exitCode;
 }
 
 
index 2d7dfd6aa77b9ee56ebb591f7e7954c15b69875a..76120c49c890b45bba4beb618504f3ea76403df2 100644 (file)
@@ -53,7 +53,7 @@ public:
        virtual ~Engine();
 
        int run();
-       void stop();
+       void stop(int exitCode = 0);
 
        void setTimestep(Scalar ts);
        Scalar getTimestep();
index 7595054e68e8aa534b7c58966c6687cb22f5f487..f593d0cd316d872468e44b11b290750c4ffcc8fe 100644 (file)
 #include <Moof/Aabb.hh>
 #include <Moof/Cullable.hh>
 #include <Moof/Drawable.hh>
+#include <Moof/Sphere.hh>
 
 
 namespace Mf {
 
 
+class Camera;
+
 /**
- * Interface for game objects that can be drawn to the screen and half a
+ * Interface for game objects that can be drawn to the screen and have a
  * specified size.
  */
 
 class Entity : public Drawable, public Cullable
 {
 public:
+       inline virtual ~Entity() {}
+
        const Aabb& getAabb() const
        {
                return aabb_;
        }
 
+       const Sphere& getSphere() const
+       {
+               return sphere_;
+       }
+
+       virtual void drawIfVisible(Scalar alpha, const Camera& cam) const
+       {
+               if (isVisible(cam)) draw(alpha);
+       }
+
 protected:
-       Aabb aabb_;
+       Aabb    aabb_;
+       Sphere  sphere_;
 };
 
 typedef boost::shared_ptr<Entity> EntityPtr;
diff --git a/src/Moof/Frustum.cc b/src/Moof/Frustum.cc
new file mode 100644 (file)
index 0000000..4dc6340
--- /dev/null
@@ -0,0 +1,109 @@
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+ Redistribution   and   use  in  source  and  binary  forms,  with  or  without
+ modification, are permitted provided that the following conditions are met:
+   * Redistributions  of  source  code  must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions  in binary form must reproduce the above copyright notice,
+     this  list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+ THIS  SOFTWARE  IS  PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND  ANY  EXPRESS  OR  IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.  IN  NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES  (INCLUDING,  BUT  NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES;  LOSS  OF  USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Moof/Aabb.hh>
+#include <Moof/Frustum.hh>
+#include <Moof/Sphere.hh>
+
+
+namespace Mf {
+
+
+void Frustum::init(const Matrix4& modelview, const Matrix4& projection)
+{
+       Scalar planes[6][4];
+
+       cml::extract_frustum_planes(modelview, projection, planes,
+                       cml::z_clip_neg_one);
+
+       planes_[0] = Plane(planes[0][0], planes[0][1], planes[0][2], planes[0][3]);
+       planes_[1] = Plane(planes[1][0], planes[1][1], planes[1][2], planes[1][3]);
+       planes_[2] = Plane(planes[2][0], planes[2][1], planes[2][2], planes[2][3]);
+       planes_[3] = Plane(planes[3][0], planes[3][1], planes[3][2], planes[3][3]);
+       planes_[4] = Plane(planes[4][0], planes[4][1], planes[4][2], planes[4][3]);
+       planes_[5] = Plane(planes[5][0], planes[5][1], planes[5][2], planes[5][3]);
+}
+
+void Frustum::init(const Matrix4& modelview, Scalar fovy, Scalar aspect,
+               Scalar near, Scalar far)
+{
+       Matrix4 projection;
+
+       cml::matrix_perspective_yfov_RH(projection, fovy, aspect, near, far,
+                       cml::z_clip_neg_one);
+
+       init(modelview, projection);
+}
+
+Frustum::Collision Frustum::containsAabb(const Aabb& aabb) const
+{
+       Vector3 corners[8];
+       int nTotalInside = 0;
+
+       aabb.getCorners(corners);
+
+       for (int i = 0; i < 6; ++i)
+       {
+               int nInside = 8;
+
+               for (int j = 0; j < 8; ++j)
+               {
+                       if (planes_[i].intersectsPoint(corners[j]) ==
+                                       Plane::NEGATIVE)
+                       {
+                               --nInside;
+                       }
+               }
+
+               if (nInside == 0)      return OUTSIDE;
+               else if (nInside == 8) ++nTotalInside;
+       }
+
+       if (nTotalInside == 6) return INSIDE;
+       else                   return INTERSECT;
+}
+
+
+Frustum::Collision Frustum::containsSphere(const Sphere& sphere) const
+{
+       for (int i = 0; i < 6; ++i)
+       {
+               Plane::Halfspace halfspace = planes_[i].intersectsSphere(sphere);
+               
+               if (halfspace == Plane::NEGATIVE)       return OUTSIDE;
+               else if (halfspace == Plane::INTERSECT) return INTERSECT;
+       }
+
+       return INSIDE;
+}
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
index ac2b353e263409f1be648a60854f249fc263ff9b..a50dc8338d0a10206bce3ebc900f93037b640e23 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef _MOOF_FRUSTUM_HH_
 #define _MOOF_FRUSTUM_HH_
        
+#include <Moof/Math.hh>
 #include <Moof/Plane.hh>
 
 
@@ -36,11 +37,11 @@ namespace Mf {
 
 
 class Aabb;
+class Sphere;
 
 class Frustum
 {
-       //Matrix4 projection;
-       Plane left, right, bottom, top, near, far;
+       Plane   planes_[6]; // left, right, bottom, top, near, far
 
 public:
        typedef enum
@@ -50,16 +51,23 @@ public:
                INTERSECT       = 2
        } Collision;
 
-       //Frustum() {}
-       //Frustum(Scalar l, Scalar r, Scalar b, Scalar t, Scalar n, Scalar f);
-       //Frustum(Scalar fovy, Scalar aspect, Scalar near, Scalar far);
-
-       inline Collision checkAabb(const Aabb& aabb) const
+       Frustum() {}
+       inline Frustum(const Matrix4& modelview, const Matrix4& projection)
+       {
+               init(modelview, projection);
+       }
+       inline Frustum(const Matrix4& modelview, Scalar fovy, Scalar aspect,
+                       Scalar near, Scalar far)
        {
-               return INSIDE;
+               init(modelview, fovy, aspect, near, far);
        }
+       
+       void init(const Matrix4& modelview, const Matrix4& projection);
+       void init(const Matrix4& modelview, Scalar fovy, Scalar aspect, Scalar near,
+                       Scalar far);
 
-       //const Matrix4& getMatrix() const;
+       Collision containsAabb(const Aabb& aabb) const;
+       Collision containsSphere(const Sphere& sphere) const;
 };
 
 
diff --git a/src/Moof/Hash.cc b/src/Moof/Hash.cc
new file mode 100644 (file)
index 0000000..457c353
--- /dev/null
@@ -0,0 +1,104 @@
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+ Redistribution   and   use  in  source  and  binary  forms,  with  or  without
+ modification, are permitted provided that the following conditions are met:
+   * Redistributions  of  source  code  must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions  in binary form must reproduce the above copyright notice,
+     this  list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+ THIS  SOFTWARE  IS  PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND  ANY  EXPRESS  OR  IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.  IN  NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES  (INCLUDING,  BUT  NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES;  LOSS  OF  USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "Hash.hh"
+
+
+namespace Mf {
+
+
+//-----------------------------------------------------------------------------
+// MurmurHash2, by Austin Appleby
+
+// Note - This code makes a few assumptions about how your machine behaves -
+
+// 1. We can read a 4-byte value from any address without crashing
+// 2. sizeof(int) == 4
+
+// And it has a few limitations -
+
+// 1. It will not work incrementally.
+// 2. It will not produce the same results on little-endian and big-endian
+//    machines.
+
+unsigned int MurmurHash2_(const void* key, int len, unsigned int seed)
+{
+       // 'm' and 'r' are mixing constants generated offline.
+       // They're not really 'magic', they just happen to work well.
+
+       const unsigned int m = 0x5bd1e995;
+       const int r = 24;
+
+       // Initialize the hash to a 'random' value
+
+       unsigned int h = seed ^ len;
+
+       // Mix 4 bytes at a time into the hash
+
+       const unsigned char* data = (const unsigned char*)key;
+
+       while (len >= 4)
+       {
+               unsigned int k = *(unsigned int*)data;
+
+               k *= m; 
+               k ^= k >> r; 
+               k *= m; 
+               
+               h *= m; 
+               h ^= k;
+
+               data += 4;
+               len -= 4;
+       }
+       
+       // Handle the last few bytes of the input array
+
+       switch (len)
+       {
+       case 3: h ^= data[2] << 16;
+       case 2: h ^= data[1] << 8;
+       case 1: h ^= data[0];
+               h *= m;
+       };
+
+       // Do a few final mixes of the hash to ensure the last few
+       // bytes are well-incorporated.
+
+       h ^= h >> 13;
+       h *= m;
+       h ^= h >> 15;
+
+       return h;
+} 
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
diff --git a/src/Moof/Hash.hh b/src/Moof/Hash.hh
new file mode 100644 (file)
index 0000000..c069544
--- /dev/null
@@ -0,0 +1,56 @@
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+ Redistribution   and   use  in  source  and  binary  forms,  with  or  without
+ modification, are permitted provided that the following conditions are met:
+   * Redistributions  of  source  code  must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions  in binary form must reproduce the above copyright notice,
+     this  list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+ THIS  SOFTWARE  IS  PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND  ANY  EXPRESS  OR  IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.  IN  NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES  (INCLUDING,  BUT  NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES;  LOSS  OF  USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef _MOOF_HASH_HH_
+#define _MOOF_HASH_HH_
+
+#include <string>
+
+#include <stlplus/hash.hpp>
+
+
+namespace Mf {
+
+
+unsigned MurmurHash2_(const void* key, int len, unsigned seed);
+
+struct hash_string
+{
+       inline unsigned operator()(const std::string& val) const
+       {
+               return MurmurHash2_(val.data(), val.length(), -1);
+       }
+};
+
+
+} // namespace Mf
+
+#endif // _MOOF_HASH_HH_
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
index 4e1cda8c1a25f3a4f57cffe616a56564040f45f6..26c4b5180dc61395c97752bd133b606de9285b10 100644 (file)
@@ -85,7 +85,7 @@ const Scalar EPSILON = 0.000001;
  * Check the equality of scalars with a certain degree of error allowed.
  */
 
-inline bool checkEquality(Scalar a, Scalar b, Scalar epsilon = EPSILON)
+inline bool isEqual(Scalar a, Scalar b, Scalar epsilon = EPSILON)
 {
        return std::abs(a - b) < epsilon;
 }
index 95d3f21577e6e9d444e56cf6a4fb33f50e421b73..7058eccf76214911933a61a7d3fca5a07de4fcf9 100644 (file)
  * after the last interested code releases its hold on the object.
  */
 
-#include <map>
+#include <Moof/Hash.hh>
 #include <string>
 
-
 namespace Mf {
 
 
 template <class T>
 class Mippleton
 {
-       typedef std::pair<unsigned,T*>                          ptr_value_t;
-       typedef std::pair<std::string,ptr_value_t>      ptr_map_pair_t;
-       typedef std::map<std::string,ptr_value_t>       ptr_map_t;
+       typedef std::pair<unsigned,T*>                                                          ptr_value_t;
+       typedef std::pair<std::string,ptr_value_t>                                      ptr_map_pair_t;
+       typedef stlplus::hash<std::string,ptr_value_t,hash_string>      ptr_map_t;
+       //typedef std::map<std::string,ptr_value_t>     ptr_map_t;
 
-       static ptr_map_t ptrs_;
-       std::string name_;
+       static ptr_map_t        ptrs_;
+       std::string                     name_;
 
 public:
-       explicit Mippleton(const std::string& name) : name_(name) {}
+       explicit Mippleton(const std::string& name) :
+               name_(name) {}
 
        inline const std::string& getName() const
        {
@@ -65,11 +66,11 @@ public:
 
        inline static T* retain(const std::string& name)
        {
-               typename ptr_map_t::iterator it;
+               typename ptr_map_t::iterator it = ptrs_.find(name);
 
-               if ((it = ptrs_.find(name)) != ptrs_.end())
+               if (it != ptrs_.end())
                {
-                       (*it).second.first++;
+                       ++((*it).second.first);
                        return (*it).second.second;
                }
                else
@@ -84,10 +85,10 @@ public:
        {
                typename ptr_map_t::iterator it;
 
-               if ((it = ptrs_.find(name)) != ptrs_.end() && -(*it).second.first == 0)
+               if ((it = ptrs_.find(name)) != ptrs_.end() && --(*it).second.first == 0)
                {
                        delete (*it).second.second;
-                       ptrs_.erase(it);
+                       ptrs_.erase((*it).first);
                }
        }
 
@@ -98,7 +99,9 @@ public:
 };
 
 template <class T>
-std::map<std::string,std::pair<unsigned,T*> > Mippleton<T>::ptrs_;
+stlplus::hash< std::string,std::pair<unsigned,T*>,hash_string >
+//std::map< std::string,std::pair<unsigned,T*> >
+       Mippleton<T>::ptrs_;
 
 
 } // namespace Mf
index 2ee617f3744f0baa6155c15df3a767617cb35c56..78d3aa875706cd61f4558740c7b90a8cf4f82cd3 100644 (file)
 
 #include <boost/shared_ptr.hpp>
 
+#include <Moof/Aabb.hh>
+#include <Moof/Drawable.hh>
+#include <Moof/Entity.hh>
 #include <Moof/Math.hh>
+#include <Moof/Sphere.hh>
 #include <Moof/Tree.hh>
        
 
 namespace Mf {
 
 
-class Entity;
+struct OctreeNode : public Entity
+{
+       std::list<EntityPtr> objects;
+
+       OctreeNode()
+       {
+               aabb_.min = Vector3(-1.0, -1.0, -1.0);
+               aabb_.max = Vector3(1.0, 1.0, 1.0);
+               sphere_.init(Vector3(0.0, 0.0, 0.0), 1.41421);
+       }
+
+       OctreeNode(const Aabb& aabb)
+       {
+               aabb_ = aabb;
+               sphere_.point = aabb.getCenter();
+               sphere_.radius = (aabb.min - sphere_.point).length();
+       }
+
+       void draw(Scalar alpha) const
+       {
+               std::list<EntityPtr>::const_iterator it;
+
+               for (it = objects.begin(); it != objects.end(); ++it)
+               {
+                       (*it)->draw(alpha);
+               }
+               if (!objects.empty())
+                       aabb_.draw(); // temporary
+       }
+
+       void drawIfVisible(Scalar alpha, const Camera& cam) const
+       {
+               std::list<EntityPtr>::const_iterator it;
+
+               for (it = objects.begin(); it != objects.end(); ++it)
+               {
+                       (*it)->drawIfVisible(alpha, cam);
+               }
+               if (!objects.empty())
+                       aabb_.draw();
+       }
+
 
+       bool isVisible(const Camera& cam) const
+       {
+               if (sphere_.isVisible(cam))
+               {
+                       return aabb_.isVisible(cam);
+               }
+
+               return false;
+       }
+};
 
-class Octree
+
+class Octree;
+typedef boost::shared_ptr<Octree> OctreePtr;
+
+class Octree : public Tree<OctreeNode>
 {
+
+       Octree() {}
+
+       explicit Octree(const OctreeNode& initNode) :
+               Tree<OctreeNode>(initNode) {}
+
 public:
 
-       class Node
+       inline static OctreePtr createNewNode(const OctreeNode& item)
+       {
+               OctreePtr newNode = OctreePtr(new Octree(item));
+               init(newNode);
+               return newNode;
+       }
+
+
+       static Tree<OctreeNode>::WeakPtr add(Ptr node, EntityPtr entity)
        {
-               Aabb    aabb_;
-               Vector3 center_;
+               Plane::Halfspace halfspace;
+               int octantNum = -1;
+
+               Plane xy = node->node.getAabb().getPlaneXY();
+               halfspace = xy.intersectsSphere(entity->getSphere());
 
-               std::list<boost::shared_ptr<Entity> > objects_;
+               if (halfspace == Plane::POSITIVE)
+               {
+                       Plane xz = node->node.getAabb().getPlaneXZ();
+                       halfspace = xz.intersectsSphere(entity->getSphere());
 
-       public:
+                       if (halfspace == Plane::POSITIVE)
+                       {
+                               Plane yz = node->node.getAabb().getPlaneYZ();
+                               halfspace = yz.intersectsSphere(entity->getSphere());
 
-               Node() :
-                       aabb_(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0),
-                       center_(0.0, 0.0, 0.0) {}
+                               if (halfspace == Plane::POSITIVE)
+                               {
+                                       octantNum = 2;
+                               }
+                               else if (halfspace == Plane::NEGATIVE)
+                               {
+                                       octantNum = 3;
+                               }
+                       }
+                       else if (halfspace == Plane::NEGATIVE)
+                       {
+                               Plane yz = node->node.getAabb().getPlaneYZ();
+                               halfspace = yz.intersectsSphere(entity->getSphere());
 
-               Node(const Aabb& aabb) :
-                       aabb_(aabb),
-                       center_(aabb.getCenter()) {}
-       };
+                               if (halfspace == Plane::POSITIVE)
+                               {
+                                       octantNum = 1;
+                               }
+                               else if (halfspace == Plane::NEGATIVE)
+                               {
+                                       octantNum = 0;
+                               }
+                       }
+               }
+               else if (halfspace == Plane::NEGATIVE)
+               {
+                       Plane xz = node->node.getAabb().getPlaneXZ();
+                       halfspace = xz.intersectsSphere(entity->getSphere());
 
-       Octree() :
-               root_(new Tree<Node>()) {}
+                       if (halfspace == Plane::POSITIVE)
+                       {
+                               Plane yz = node->node.getAabb().getPlaneYZ();
+                               halfspace = yz.intersectsSphere(entity->getSphere());
 
-       Octree(const Aabb& aabb) :
-               root_(new Tree<Node>(Node(aabb))) {}
+                               if (halfspace == Plane::POSITIVE)
+                               {
+                                       octantNum = 6;
+                               }
+                               else if (halfspace == Plane::NEGATIVE)
+                               {
+                                       octantNum = 7;
+                               }
+                       }
+                       else if (halfspace == Plane::NEGATIVE)
+                       {
+                               Plane yz = node->node.getAabb().getPlaneYZ();
+                               halfspace = yz.intersectsSphere(entity->getSphere());
 
+                               if (halfspace == Plane::POSITIVE)
+                               {
+                                       octantNum = 5;
+                               }
+                               else if (halfspace == Plane::NEGATIVE)
+                               {
+                                       octantNum = 4;
+                               }
+                       }
+               }
 
-       Tree<Node>::WeakPtr add(EntityPtr object);
+               if (octantNum == -1)
+               {
+                       node->node.objects.push_front(entity);
+                       return node;
+               }
+               else
+               {
+                       if (node->isLeaf())
+                       {
+                               addChildren(node);
+                       }
+
+                       Ptr child = node->getChild(octantNum);
+                       if (child)
+                       {
+                               return add(child, entity);
+                       }
+                       else
+                       {
+                               std::cerr << "no child at index " << octantNum << std::endl;
+                               return Ptr();
+                       }
+                       //return WeakPtr();
+               }
+       }
+
+       static void addChildren(Ptr node)
+       {
+               Aabb octant;
+
+               for (int i = 0; i < 8; ++i)
+               {
+                       node->node.getAabb().getOctant(octant, i);
+                       //OctreeNode octantNode(octant);
+
+                       Ptr newChild = createNewNode(octant);
+                       node->addChild(newChild);
+               }
+       }
+
+       void draw(Ptr node, Scalar alpha)
+       {
+               if (!node)
+               {
+                       std::cerr << "null child :-(" << std::endl;
+                       return;
+               }
+
+               node->node.draw(alpha);
+
+               if (!node->isLeaf())
+               {
+                       Ptr firstChild = node->getFirstChild();
+                       Ptr temp = firstChild;
+
+                       if (!firstChild)
+                       {
+                               std::cerr << "node is not a leaf, but has no first child :-(" << std::endl;
+                               return;
+                       }
+
+                       do
+                       {
+                               draw(temp, alpha);
+                               temp = temp->getNextSibling();
+                       }
+                       while (temp && temp != firstChild);
+               }
+       }
+
+       void drawIfVisible(Ptr node, Scalar alpha, const Camera& cam)
+       {
+               //node.drawIfVisible(alpha, cam);
+               
+               if (!node)
+               {
+                       std::cerr << "null child :-(" << std::endl;
+                       return;
+               }
+
+               Frustum::Collision collision =
+                       cam.getFrustum().containsSphere(node->node.getSphere());
+               if (collision == Frustum::OUTSIDE) return;
+
+               collision = cam.getFrustum().containsAabb(node->node.getAabb());
+               if (collision == Frustum::OUTSIDE) return;
+
+
+               if (collision == Frustum::INSIDE)
+               {
+                       node->node.draw(alpha);
+               }
+               else // collision == Frustum::INTERSECT
+               {
+                       node->node.drawIfVisible(alpha, cam);
+               }
+
+               if (!node->isLeaf())
+               {
+                       Ptr firstChild = node->getFirstChild();
+                       Ptr temp = firstChild;
+
+                       if (!firstChild)
+                       {
+                               std::cerr << "node is not a leaf, but has no first child :-(" << std::endl;
+                               return;
+                       }
+
+                       if (collision == Frustum::INSIDE)
+                       {
+                               do
+                               {
+                                       draw(temp, alpha);
+                                       temp = temp->getNextSibling();
+                               }
+                               while (temp && temp != firstChild);
+                       }
+                       else // collision == Frustum::INTERSECT
+                       {
+                               do
+                               {
+                                       drawIfVisible(temp, alpha, cam);
+                                       temp = temp->getNextSibling();
+                               }
+                               while (temp && temp != firstChild);
+                       }
+               }
+       }
+
+       void drawIfVisible(Scalar alpha, const Camera& cam)
+       {
+               drawIfVisible(getThis(), alpha, cam);
+       }
 
-private:
-       Tree<Node>::Ptr root_;
 };
 
 
+
 } // namespace Mf
 
 #endif // _MOOF_OCTREE_HH_
diff --git a/src/Moof/Plane.cc b/src/Moof/Plane.cc
new file mode 100644 (file)
index 0000000..975ef13
--- /dev/null
@@ -0,0 +1,70 @@
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+ Redistribution   and   use  in  source  and  binary  forms,  with  or  without
+ modification, are permitted provided that the following conditions are met:
+   * Redistributions  of  source  code  must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions  in binary form must reproduce the above copyright notice,
+     this  list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+ THIS  SOFTWARE  IS  PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND  ANY  EXPRESS  OR  IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.  IN  NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES  (INCLUDING,  BUT  NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES;  LOSS  OF  USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "Aabb.hh"
+#include "Plane.hh"
+#include "Sphere.hh"
+
+
+namespace Mf {
+
+
+Plane::Halfspace Plane::intersectsAabb(const Aabb& aabb) const
+{
+       Vector3 corners[8];
+       int nPositive = 8;
+
+       aabb.getCorners(corners);
+
+       for (int i = 0; i < 8; ++i)
+       {
+               if (intersectsPoint(corners[i]) == NEGATIVE)
+               {
+                       --nPositive;
+               }
+       }
+
+       if (nPositive == 0)      return NEGATIVE;
+       else if (nPositive == 8) return POSITIVE;
+       else                     return INTERSECT;
+}
+
+Plane::Halfspace Plane::intersectsSphere(const Sphere& sphere) const
+{
+       Scalar distance = getDistanceToPoint(sphere.point);
+
+       if (distance < -sphere.radius)     return NEGATIVE;
+       else if (distance < sphere.radius) return INTERSECT;
+       else                               return POSITIVE;
+}
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
index 797edc05c39fe13283c4a52088502fcb6e2f132c..248a3128161afe0cadbdde10fa781d6b3e89c405 100644 (file)
 namespace Mf {
 
 
-class Plane
+class Aabb;
+class Sphere;
+
+
+struct Plane
 {
-       Vector4 components;
+       Vector3 normal;
+       Scalar  d;
+
+       typedef enum
+       {
+               NEGATIVE        = -1,
+               INTERSECT       =  0,
+               POSITIVE        =  1
+       } Halfspace;
+
+       Plane() {}
+       Plane(const Vector3& vector, Scalar scalar) :
+               normal(vector),
+               d(scalar) {}
+       Plane(Scalar a, Scalar b, Scalar c, Scalar scalar) :
+               normal(a, b, c),
+               d(scalar) {}
+
+
+       void normalize()
+       {
+               Scalar mag = normal.length();
+
+               normal /= mag;
+               d /= mag;
+       }
+
+       inline Scalar getDistanceToPoint(const Vector3& point) const
+       {
+               return cml::dot(point, normal) + d;
+       }
+
+       inline Halfspace intersectsPoint(const Vector3& point) const
+       {
+               Scalar distance = getDistanceToPoint(point);
+
+               if (isEqual(distance, 0.0)) return INTERSECT;
+               else if (distance < 0.0)    return NEGATIVE;
+               else                        return POSITIVE;
+       }
 
-public:
+       Halfspace intersectsAabb(const Aabb& aabb) const;
+       Halfspace intersectsSphere(const Sphere& sphere) const;
 };
 
 
index adec6ec42ccbfa1a38c6f63647c8e24001fceb9c..85e5be75d9697a315e5aded091589e6ab3c8da58 100644 (file)
@@ -70,6 +70,10 @@ class Scene::SceneImpl : public Mippleton<SceneImpl>
                        {
                                std::cerr << "no coords for tile's texture" << std::endl;
                        }
+
+                       aabb_.encloseVertices(vertices, 4);
+                       sphere_.point = aabb_.getCenter();
+                       sphere_.radius = (aabb_.min - sphere_.point).length();
                }
 
                void setDetail(long detail)
@@ -98,34 +102,17 @@ class Scene::SceneImpl : public Mippleton<SceneImpl>
                        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
                        tilemap_.bind();
 
-                       //glEnableClientState(GL_VERTEX_ARRAY);
-                       //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-                       //glVertexPointer(3, GL_SCALAR, 0, vertices_);
-                       //glTexCoordPointer(2, GL_SCALAR, 0, texCoords_);
-
-                       //glDrawArrays(GL_TRIANGLE_FAN, 0, sizeof(vertices_));
+                       glVertexPointer(3, GL_SCALAR, 0, vertices_);
+                       glTexCoordPointer(2, GL_SCALAR, 0, texCoords_);
 
-                       //glDisableClientState(GL_VERTEX_ARRAY);
-                       //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-                       glBegin(GL_TRIANGLE_FAN);
-                               glTexCoord2f(texCoords_[0], texCoords_[1]);
-                               glVertex3v(vertices_);
-                               glTexCoord2f(texCoords_[2], texCoords_[3]);
-                               glVertex3v(vertices_+3);
-                               glTexCoord2f(texCoords_[4], texCoords_[5]);
-                               glVertex3v(vertices_+6);
-                               glTexCoord2f(texCoords_[6], texCoords_[7]);
-                               glVertex3v(vertices_+9);
-                       glEnd();
+                       glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
                        glDisable(GL_BLEND);
                }
 
                bool isVisible(const Camera& cam) const
                {
-                       return aabb_.isVisible(cam);
+                       return sphere_.isVisible(cam);
                }
 
        private:
@@ -393,7 +380,8 @@ public:
                                Quad* quad = new Quad(quadVertices, texture, indices[h][w]);
                                boost::shared_ptr<Quad> quadPtr(quad);
 
-                               objects.push_back(quadPtr);
+                               //objects.push_back(quadPtr);
+                               Octree::add(octree, quadPtr);
                        }
                }
        }
@@ -473,7 +461,8 @@ public:
 
                        boost::shared_ptr<Quad> quadPtr(quad);
 
-                       objects.push_back(quadPtr);
+                       //objects.push_back(quad_Ptr);
+                       Octree::add(octree, quadPtr);
                }
        }
 
@@ -502,6 +491,15 @@ public:
                {
                        loadBox(maximumBounds, (*it).second);
                }
+               else
+               {
+                       std::cerr << "maximum bounds required in scene" << std::endl;
+                       return;
+               }
+
+               //OctreeNode rootNode(maximumBounds);
+               octree = Octree::createNewNode(maximumBounds);
+
                if ((it = rootObj.find("instructions")) != rootObj.end())
                {
                        loadInstructions((*it).second);
@@ -509,19 +507,36 @@ public:
        }
 
 
-       void draw(Scalar alpha)
+       void draw(Scalar alpha, const Camera& cam) const
        {
-               QuadVector::iterator it;
+               //QuadVector::const_iterator it;
 
-               for (it = objects.begin(); it != objects.end(); ++it)
-               {
-                       //std::cout << "draw object";
-                       (*it)->draw(alpha);
-               }
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+               octree->drawIfVisible(alpha, cam);
+
+               //int objectsDrawn = 0;
+
+               //for (it = objects.begin(); it != objects.end(); ++it)
+               //{
+                       //if ((*it)->isVisible(cam))
+                       //{
+                               ////std::cout << "draw object";
+                               //(*it)->draw();
+
+                               //objectsDrawn++;
+                       //}
+               //}
+
+               //std::cout << objectsDrawn << std::endl;
+
+               glDisableClientState(GL_VERTEX_ARRAY);
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
-               glBindTexture(GL_TEXTURE_2D, 0);
+               Texture::resetBind();
                glColor3f(0.0f, 1.0f, 0.0f);
                playfieldBounds.draw();
                glColor3f(0.0f, 0.0f, 1.0f);
@@ -534,8 +549,9 @@ public:
        Aabb playfieldBounds;
        Aabb maximumBounds;
 
-       typedef std::vector< boost::shared_ptr<Quad> > QuadVector;
-       QuadVector objects;
+       //typedef std::vector< boost::shared_ptr<Quad> > QuadVector;
+       //QuadVector objects;
+       OctreePtr octree;
 };
 
 
@@ -544,15 +560,15 @@ Scene::Scene(const std::string& name) :
        impl_(Scene::SceneImpl::retain(name), &Scene::SceneImpl::release) {}
 
 
-void Scene::draw(Scalar alpha) const
+void Scene::draw(Scalar alpha, const Camera& cam) const
 {
        // pass through
-       impl_->draw(alpha);
+       impl_->draw(alpha, cam);
 }
 
 void Scene::refresh()
 {
-       impl_->objects.clear();
+       //impl_->objects.clear();
        impl_->loadFromFile();
 }
 
index db25db7a42ea096c0e017e6b008ba5695fc039b0..08ab6cc2441c7f58497fa01bffbe42853fb80e4c 100644 (file)
 namespace Mf {
 
 
-class Scene : public Resource, public Drawable
+class Camera;
+
+class Scene : public Resource
 {
 public:
        Scene(const std::string& name);
 
-       void draw(Scalar alpha) const;
+       void draw(Scalar alpha, const Camera& cam) const;
        void refresh();
 
        static std::string getPathToResource(const std::string& name);
diff --git a/src/Moof/Sphere.cc b/src/Moof/Sphere.cc
new file mode 100644 (file)
index 0000000..352d58d
--- /dev/null
@@ -0,0 +1,55 @@
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+ Redistribution   and   use  in  source  and  binary  forms,  with  or  without
+ modification, are permitted provided that the following conditions are met:
+   * Redistributions  of  source  code  must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions  in binary form must reproduce the above copyright notice,
+     this  list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+ THIS  SOFTWARE  IS  PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND  ANY  EXPRESS  OR  IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.  IN  NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES  (INCLUDING,  BUT  NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES;  LOSS  OF  USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Moof/Camera.hh>
+#include <Moof/OpenGL.hh>
+#include <Moof/Sphere.hh>
+
+
+namespace Mf {
+
+
+void Sphere::encloseVertices(const Vector3 vertices[], unsigned count)
+{
+}
+
+void Sphere::draw(Scalar alpha) const
+{
+
+}
+
+bool Sphere::isVisible(const Camera& cam) const
+{
+       return cam.getFrustum().containsSphere(*this);
+}
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
diff --git a/src/Moof/Sphere.hh b/src/Moof/Sphere.hh
new file mode 100644 (file)
index 0000000..b20ca74
--- /dev/null
@@ -0,0 +1,77 @@
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+ Redistribution   and   use  in  source  and  binary  forms,  with  or  without
+ modification, are permitted provided that the following conditions are met:
+   * Redistributions  of  source  code  must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions  in binary form must reproduce the above copyright notice,
+     this  list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+ THIS  SOFTWARE  IS  PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND  ANY  EXPRESS  OR  IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.  IN  NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES  (INCLUDING,  BUT  NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES;  LOSS  OF  USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#ifndef _MOOF_SPHERE_HH_
+#define _MOOF_SPHERE_HH_
+
+#include <Moof/Cullable.hh>
+#include <Moof/Drawable.hh>
+#include <Moof/Math.hh>
+
+
+namespace Mf {
+
+
+/**
+ * Axis-aligned Bounding Box
+ */
+
+struct Sphere : public Cullable, public Drawable
+{
+       Vector3 point;
+       Scalar  radius;
+
+       Sphere() {}
+
+       Sphere(const Vector3& p, Scalar r) :
+               point(p),
+               radius(r) {}
+
+       Sphere(Scalar x, Scalar y, Scalar z, Scalar r) :
+               point(x, y, z),
+               radius(r) {}
+
+       inline void init(const Vector3& p, Scalar r)
+       {
+               point = p;
+               radius = r;
+       }
+
+       void encloseVertices(const Vector3 vertices[], unsigned count);
+
+       void draw(Scalar alpha = 0.0) const;
+       bool isVisible(const Camera& cam) const;
+};
+
+
+} // namespace Mf
+
+#endif // _MOOF_SPHERE_HH_
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
index 128d54f3d7c8750b2087859a22b81aa6c5f18dc6..dc9407afc9da1af082ed577da1ab99a6b27bc1e6 100644 (file)
@@ -414,6 +414,13 @@ GLuint Texture::getObject() const
 }
 
 
+void Texture::resetBind()
+{
+       glBindTexture(GL_TEXTURE_2D, 0);
+       TextureImpl::globalObject_ = 0;
+}
+
+
 unsigned Texture::getWidth() const
 {
        // pass through
@@ -454,7 +461,7 @@ void Texture::setWrapT(GLuint wrap)
 
 std::string Texture::getPathToResource(const std::string& name)
 {
-       // TODO named resources must be png for now
+       // TODO named texture resources must be png for now
        return Resource::getPathToResource("textures/" + name + ".png");
 }
 
index d2b2359f0eb4e28d09194cac40816e66dd0536a0..9d17eb8f66254dee136d41647eb76263c0d4ed40 100644 (file)
@@ -53,6 +53,8 @@ public:
        void bind() const;
        GLuint getObject() const;
 
+       static void resetBind();
+
        unsigned getWidth() const;
        unsigned getHeight() const;
 
index 2b5fdb8baf769bcebba4460bdd67e3e4e7d40e01..b3f6a97c22dadf125c1efd79efaaef48883ad2a4 100644 (file)
@@ -40,50 +40,81 @@ template <typename T>
 class Tree
 {
 public:
-       typedef boost::shared_ptr<Tree> Ptr;
-       typedef boost::weak_ptr<Tree> WeakPtr;
+       typedef boost::shared_ptr<Tree> Ptr;
+       typedef boost::weak_ptr<Tree>   WeakPtr;
 
-private:
+       T               node;
+
+protected:
        WeakPtr parent_;
        WeakPtr prevSibling_;
        Ptr             next_;
        WeakPtr lastDescendant_;
 
+       inline static void init(Ptr itself)
+       {
+               itself->prevSibling_ = itself;
+               itself->lastDescendant_ = itself;
+       }
+
+       Tree() {}
+
+       explicit Tree(const T& item) :
+               node(item) {}
+
 public:
 
-       T               data;
+       inline void print() const
+       {
+               std::cout << "==================" << std::endl;
+               std::cout << "    Node: " << getThis() << std::endl;
+               std::cout << "  Parent: " << parent_.lock() << std::endl;
+               std::cout << " PrevSib: " << prevSibling_.lock() << std::endl;
+               std::cout << "    Next: " << next_ << std::endl;
+               std::cout << "LastDesc: " << lastDescendant_.lock() << std::endl;
+               //std::cout << "   Value: " << node << std::endl;
+               std::cout << "==================" << std::endl;
+       }
 
-       Tree() {}
-       Tree(const T& item) :
-               data(item) {}
+       inline static Ptr createNewNode()
+       {
+               Ptr newNode = Ptr(new Tree<T>());
+       }
 
-       inline Ptr next() const
+       inline static Ptr createNewNode(const T& item)
+       {
+               Ptr newNode = Ptr(new Tree<T>(item));
+               init(newNode);
+               return newNode;
+       }
+
+       inline Ptr getNext() const
        {
                return next_;
        }
 
-       inline Ptr prev() const
+       inline Ptr getPrevious() const
        {
-               Ptr parent = parent_.lock();
+               Ptr parent = getParent();
 
                if (parent)
                {
-                       if (parent->next_.get() == this)
+                       if (parent->getNext().get() == this)
                        {
                                return parent;
                        }
                        else
                        {
-                               return prevSibling_.lock()->lastDescendant_.lock();
+                               return prevSibling_.lock()->getLastDescendant();
                        }
                }
 
                return Ptr();
        }
 
-       inline Ptr firstChild() const
+       inline Ptr getFirstChild() const
        {
-               if (next_ && next_->parent_.lock().get() == this)
+               if (next_ && next_->getParent().get() == this)
                {
                        return next_;
                }
@@ -91,9 +122,9 @@ public:
                return Ptr();
        }
 
-       inline Ptr lastChild() const
+       inline Ptr getLastChild() const
        {
-               Ptr child = firstChild();
+               Ptr child = getFirstChild();
 
                if (child)
                {
@@ -103,11 +134,23 @@ public:
                return child;
        }
 
-       inline Ptr nextSibling() const
+       inline Ptr getChild(int index) const
+       {
+               Ptr child = getFirstChild();
+
+               for (int i = 0; child && i < index; ++i)
+               {
+                       child = child->getNextSibling();
+               }
+
+               return child;
+       }
+
+       inline Ptr getNextSibling() const
        {
-               Ptr sibling = lastDescendant_.lock()->next_;
+               Ptr sibling = getLastDescendant()->getNext();
 
-               if (sibling && sibling->parent_.lock() != parent_.lock())
+               if (sibling && sibling->getParent() != getParent())
                {
                        return Ptr();
                }
@@ -115,11 +158,11 @@ public:
                return sibling;
        }
 
-       inline Ptr prevSibling() const
+       inline Ptr getPreviousSibling() const
        {
-               Ptr parent = parent_.lock();
+               Ptr parent = getParent();
 
-               if (parent && parent->next_.get() != this)
+               if (parent && parent->getNext().get() != this)
                {
                        return prevSibling_.lock();
                }
@@ -127,6 +170,50 @@ public:
                return Ptr();
        }
 
+       inline Ptr getParent() const
+       {
+               return parent_.lock();
+       }
+
+       inline Ptr getLastDescendant() const
+       {
+               return lastDescendant_.lock();
+       }
+
+       inline Ptr getThis() const
+       {
+               if (next_)
+               {
+                       return next_->getPrevious();
+               }
+
+               return getLastDescendant();
+       }
+
+       inline bool isRoot() const
+       {
+               return getParent().get() == 0;
+       }
+
+       inline bool isLeaf() const
+       {
+               return getLastDescendant().get() == this;
+       }
+
+       inline bool isDescendantOf(Ptr ancestor) const
+       {
+               Ptr temp = getParent();
+
+               while (temp)
+               {
+                       if (temp.get() == this) return true;
+
+                       temp = temp->getParent();
+               }
+
+               return false;
+       }
+
 
        class Iterator
        {
@@ -137,12 +224,110 @@ public:
        };
 
 
-       void insert()
+       void addChild(Ptr subtree)
        {
+       //WeakPtr       parent_;
+       //WeakPtr       prevSibling_;
+       //Ptr           next_;
+       //WeakPtr       lastDescendant_;
+       
+               subtree->remove();
+               
+               Ptr firstChild = getFirstChild();
+               Ptr lastChild = getLastChild();
+               Ptr nextSibling = getNextSibling();
+               Ptr lastDescendant = getLastDescendant();
+               Ptr newLastDescendant = subtree->getLastDescendant();
+               Ptr parent = getThis();
+
+               // 1. If parent is leaf, set parent.next to subtree.
+
+               if (isLeaf())
+               {
+                       next_ = subtree;
+               }
+
+               // 2. Set parent.last_descendant to subtree.last_descendant.
+
+               Ptr temp = parent;
+               while (temp && temp->getLastDescendant() == lastDescendant)
+               {
+                       temp->lastDescendant_ = newLastDescendant;
+                       temp = temp->getParent();
+               }
+
+               // 3. Set subtree.parent to parent.
+
+               subtree->parent_ = parent;
+
+               // 4. Set parent.first_child.prev_sibling to subtree.
+
+               if (firstChild)
+               {
+                       firstChild->prevSibling_ = subtree;
+               }
+
+               // 5. Set subtree.prev_sibling to parent.last_child.
+               // 6. Set parent.last_child.last_descendant.next to subtree.
+               
+               if (lastChild)
+               {
+                       subtree->prevSibling_ = lastChild;
+                       lastChild->getLastDescendant()->next_ = subtree;
+               }
+               else
+               {
+                       subtree->prevSibling_ = subtree;
+               }
+
+               // 7. Set subtree.last_descendant.next to parent.next_sibling.
+
+               if (nextSibling)
+               {
+                       subtree->getLastDescendant()->next_ = nextSibling;
+               }
        }
 
        void remove()
        {
+               Ptr parent = getParent();
+               Ptr prevSibling = getPreviousSibling();
+               Ptr nextSibling = getNextSibling();
+               Ptr lastDescendant = getLastDescendant();
+               Ptr previous = getPrevious();
+
+               Ptr newLastDescendant;
+
+               // 1. Fix last descendant of each direct ancestor.
+
+               if (prevSibling) newLastDescendant = prevSibling->getLastDescendant();
+               else             newLastDescendant = parent;
+
+               Ptr temp = parent;
+               while (temp && temp->getLastDescendant() == lastDescendant)
+               {
+                       temp->lastDescendant_ = newLastDescendant;
+                       temp = temp->getParent();
+               }
+
+               // 2. Fix next of previous.
+
+               if (previous)
+               {
+                       previous->next_ = nextSibling;
+               }
+
+               // 3. Fix the previous sibling of next sibling.
+
+               if (nextSibling)
+               {
+                       nextSibling->prevSibling_ = prevSibling;
+               }
+               
+               // 4. Once detached, the subtree root has no parent or siblings.
+
+               parent_.reset();
+               prevSibling_ = getThis();
        }
 
 };
diff --git a/src/Moof/stlplus/containers.hpp b/src/Moof/stlplus/containers.hpp
new file mode 100755 (executable)
index 0000000..5863758
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef STLPLUS_CONTAINERS\r
+#define STLPLUS_CONTAINERS\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   Allows all the STLplus containers to be included in one go\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "digraph.hpp"\r
+#include "foursome.hpp"\r
+#include "hash.hpp"\r
+#include "matrix.hpp"\r
+#include "ntree.hpp"\r
+#include "smart_ptr.hpp"\r
+#include "triple.hpp"\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif\r
diff --git a/src/Moof/stlplus/containers_fixes.hpp b/src/Moof/stlplus/containers_fixes.hpp
new file mode 100755 (executable)
index 0000000..618ef84
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef STLPLUS_CONTAINERS_FIXES\r
+#define STLPLUS_CONTAINERS_FIXES\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   Contains work arounds for OS or Compiler specific problems with container\r
+//   templates\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Unnecessary compiler warnings\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+// Microsoft Visual Studio\r
+// shut up the following irritating warnings\r
+//   4275 - VC6, exported class was derived from a class that was not exported\r
+//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)\r
+//   4305 - VC6, identifier type was converted to a smaller type\r
+//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)\r
+//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it\r
+//   4290 - VC6, C++ exception specification ignored\r
+//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)\r
+//   4355 - VC6, 'this' : used in base member initializer list\r
+//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program\r
+//   4996 - VC8, 'xxxx' was declared deprecated\r
+#pragma warning(disable: 4275 4786 4305 4503 4309 4290 4800 4355 4675 4996)\r
+#endif\r
+\r
+#ifdef __BORLANDC__\r
+// Borland\r
+// Shut up the following irritating warnings\r
+//   8008 - Condition is always true.\r
+//          Whenever the compiler encounters a constant comparison that (due to\r
+//          the nature of the value being compared) is always true or false, it\r
+//          issues this warning and evaluates the condition at compile time.\r
+//   8026 - Functions with exception specifications are not expanded inline\r
+//   8027 - Functions with xxx are not expanded inline\r
+//   8060 - Possibly incorrect assignment.\r
+//          This warning is generated when the compiler encounters an assignment\r
+//          operator as the main operator of a conditional expression (part of\r
+//          an if, while, or do-while statement). This is usually a\r
+//          typographical error for the equality operator.\r
+//   8066 - Unreachable code.\r
+//          A break, continue, goto, or return statement was not followed by a\r
+//          label or the end of a loop or function. The compiler checks while,\r
+//          do, and for loops with a constant test condition, and attempts to\r
+//          recognize loops that can't fall through.\r
+#pragma warn -8008\r
+#pragma warn -8026\r
+#pragma warn -8027\r
+#pragma warn -8060\r
+#pragma warn -8066\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Problems with the typename keyword\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+// There are problems with using the 'typename' keyword. Technically, if you\r
+// use a type member of a template class (i.e. a type declared within the\r
+// template class by a local typedef), you need to tell the compiler that it\r
+// is a type name. This is because the compiler cannot work out whether a\r
+// member is a type, a method or a data field at compile time. However,\r
+// support for the typename keyword has traditionally been incomplete in both\r
+// gcc and Visual Studio. I have used macros to try to resolve this issue. The\r
+// macros add the keyword for compiler versions that require it and omit it\r
+// for compiler versions that do not support it\r
+\r
+// There are five places where typename keywords cause problems:\r
+//\r
+//   1) in a typedef where a template class's member type is being mapped onto\r
+//      a type definition within another template class or function \r
+//      e.g. template<typename T> fn () {\r
+//             typedef typename someclass<T>::member_type local_type;\r
+//                     ^^^^^^^^\r
+//   2) in a function parameter declaration, with similar rules to the above\r
+//      e.g. template<typename T> fn (typename someclass<T>::member_type)\r
+//                                    ^^^^^^^^\r
+//   3) in instantiating a template, the parameter to the template, with similar rules to the above\r
+//      e.g. template_class<typename someclass<T>::member_type>\r
+//                          ^^^^^^^^\r
+//   4) Return expressions\r
+//      e.g. return typename ntree<T>::const_iterator(this,m_root);\r
+//                  ^^^^^^^^\r
+//   5) Creating temporary objects when passing arguments to a function or constructor\r
+//      e.g. return typename ntree<T>::const_prefix_iterator(typename ntree<T>::const_iterator(this,m_root));\r
+//                                                           ^^^^^^^^\r
+// Note that the typename keyword is only required when the type being referred to is a member of a template class\r
+//\r
+// So far it *seems* as if all compilers either require all of them or none of\r
+// them, so this set of situations can be handled by a single macro\r
+\r
+// default values, overridden for individual problem cases below\r
+#define TYPENAME typename\r
+\r
+// GCC \r
+//   - pre-version 3 didn't handle typename in any of these cases\r
+//   - version 3 onwards, typename is required for all three cases as per default\r
+#ifdef __GNUC__\r
+#if __GNUC__ < 3\r
+#undef TYPENAME\r
+#define TYPENAME\r
+#endif\r
+#endif\r
+\r
+// Visual Studio\r
+//   - version 6 (compiler v.12) cannot handle typename in any of these cases\r
+//   - version 7 (.NET) (compiler v.13) requires a typename in a parameter specification but supports all\r
+//   - version 8 (2005) (compiler v.14) requires parameters and templates, supports all\r
+#ifdef _MSC_VER\r
+#if _MSC_VER < 1300\r
+#undef TYPENAME\r
+#define TYPENAME\r
+#endif\r
+#endif\r
+\r
+// Borland \r
+//   - doesn't handle typename in 5.5, does in 5.82, not sure about other cases\r
+#ifdef __BORLANDC__\r
+#if __BORLANDC__ <= 0x550\r
+#undef TYPENAME\r
+#define TYPENAME\r
+#endif\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif\r
diff --git a/src/Moof/stlplus/digraph.hpp b/src/Moof/stlplus/digraph.hpp
new file mode 100755 (executable)
index 0000000..8281998
--- /dev/null
@@ -0,0 +1,507 @@
+#ifndef STLPLUS_DIGRAPH\r
+#define STLPLUS_DIGRAPH\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   STL-style Directed graph template component\r
+//   Digraph stands for directed-graph, i.e. all arcs have a direction\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+#include "safe_iterator.hpp"\r
+#include "exceptions.hpp"\r
+#include <vector>\r
+#include <map>\r
+#include <set>\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Internals\r
+\r
+  template<typename NT, typename AT> class digraph_node;\r
+  template<typename NT, typename AT> class digraph_arc;\r
+  template<typename NT, typename AT> class digraph;\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // The Digraph iterator classes\r
+  // a digraph_iterator points to a node whilst a digraph_arc_iterator points to an arc\r
+  // Note that these are redefined as:\r
+  //   digraph<NT,AT>::iterator           - points to a non-const node\r
+  //   digraph<NT,AT>::const_iterator     - points to a const node\r
+  //   digraph<NT,AT>::arc_iterator       - points to a non-const arc\r
+  //   digraph<NT,AT>::const_arc_iterator - points to a const arc\r
+  // and this is the form in which they should be used\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  class digraph_iterator : public safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >\r
+  {\r
+  public:\r
+    friend class digraph<NT,AT>;\r
+\r
+    // local type definitions\r
+    // an iterator points to an object whilst a const_iterator points to a const object\r
+    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;\r
+    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;\r
+    typedef digraph_iterator<NT,AT,NRef,NPtr> this_iterator;\r
+    typedef NRef reference;\r
+    typedef NPtr pointer;\r
+\r
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
+    digraph_iterator(void);\r
+    ~digraph_iterator(void);\r
+\r
+    // Type conversion methods allow const_iterator and iterator to be converted\r
+    // convert an iterator/const_iterator to a const_iterator\r
+    const_iterator constify(void) const;\r
+    // convert an iterator/const_iterator to an iterator\r
+    iterator deconstify(void) const;\r
+\r
+    // increment/decrement operators used to step through the set of all nodes in a graph\r
+    // it is only legal to increment a valid iterator\r
+    // pre-increment\r
+    this_iterator& operator ++ (void)\r
+      throw(null_dereference,end_dereference);\r
+    // post-increment\r
+    this_iterator operator ++ (int)\r
+      throw(null_dereference,end_dereference);\r
+    // pre-decrement\r
+    this_iterator& operator -- (void)\r
+      throw(null_dereference,end_dereference);\r
+    // post-decrement\r
+    this_iterator operator -- (int)\r
+      throw(null_dereference,end_dereference);\r
+\r
+    // test useful for testing whether iteration has completed and for inclusion in other containers\r
+    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()\r
+    bool operator == (const this_iterator& r) const;\r
+    bool operator != (const this_iterator& r) const;\r
+    bool operator < (const this_iterator& r) const;\r
+\r
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
+    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
+    reference operator*(void) const\r
+      throw(null_dereference,end_dereference);\r
+    pointer operator->(void) const\r
+      throw(null_dereference,end_dereference);\r
+\r
+  public:\r
+    // constructor used by digraph to create a non-null iterator\r
+    explicit digraph_iterator(digraph_node<NT,AT>* node);\r
+    // constructor used by digraph to create an end iterator\r
+    explicit digraph_iterator(const digraph<NT,AT>* owner);\r
+    // used to create an alias of an iterator\r
+    explicit digraph_iterator(const safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >& iterator);\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  class digraph_arc_iterator : public safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >\r
+  {\r
+  public:\r
+    friend class digraph<NT,AT>;\r
+\r
+    // local type definitions\r
+    // an iterator points to an object whilst a const_iterator points to a const object\r
+    typedef digraph_arc_iterator<NT,AT,AT&,AT*> iterator;\r
+    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_iterator;\r
+    typedef digraph_arc_iterator<NT,AT,ARef,APtr> this_iterator;\r
+    typedef ARef reference;\r
+    typedef APtr pointer;\r
+\r
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
+    digraph_arc_iterator(void);\r
+    ~digraph_arc_iterator(void);\r
+\r
+    // Type conversion methods allow const_iterator and iterator to be converted\r
+    // convert an iterator/const_iterator to a const_iterator\r
+    const_iterator constify(void) const;\r
+    // convert an iterator/const_iterator to an iterator\r
+    iterator deconstify(void) const;\r
+\r
+    // increment/decrement operators used to step through the set of all nodes in a graph\r
+    // it is only legal to increment a valid iterator\r
+    // pre-increment\r
+    this_iterator& operator ++ (void)\r
+      throw(null_dereference,end_dereference);\r
+    // post-increment\r
+    this_iterator operator ++ (int)\r
+      throw(null_dereference,end_dereference);\r
+    // pre-decrement\r
+    this_iterator& operator -- (void)\r
+      throw(null_dereference,end_dereference);\r
+    // post-decrement\r
+    this_iterator operator -- (int)\r
+      throw(null_dereference,end_dereference);\r
+\r
+    // test useful for testing whether iteration has completed and for inclusion in other containers\r
+    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()\r
+    bool operator == (const this_iterator&) const;\r
+    bool operator != (const this_iterator&) const;\r
+    bool operator < (const this_iterator&) const;\r
+\r
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
+    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
+    reference operator*(void) const\r
+      throw(null_dereference,end_dereference);\r
+    pointer operator->(void) const\r
+      throw(null_dereference,end_dereference);\r
+\r
+  public:\r
+    // constructor used by digraph to create a non-null iterator\r
+    explicit digraph_arc_iterator(digraph_arc<NT,AT>* arc);\r
+    // constructor used by digraph to create an end iterator\r
+    explicit digraph_arc_iterator(const digraph<NT,AT>* owner);\r
+    // used to create an alias of an iterator\r
+    explicit digraph_arc_iterator(const safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >& iterator);\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // The Graph class\r
+  // NT is the Node type and AT is the Arc type\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename NT, typename AT>\r
+  class digraph\r
+  {\r
+  public:\r
+    // STL-like typedefs for the types and iterators\r
+    typedef NT node_type;\r
+    typedef AT arc_type;\r
+    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;\r
+    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;\r
+    typedef digraph_arc_iterator<NT,AT,AT&,AT*> arc_iterator;\r
+    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_arc_iterator;\r
+\r
+    // supplementary types used throughout\r
+\r
+    // a path is represented as a vector of arcs so the forward traversal is\r
+    // done by going from begin() to end() or 0 to size-1 - of course a backward\r
+    // traversal can be done by traversing the vector backwards\r
+    typedef std::vector<arc_iterator> arc_vector;\r
+    typedef std::vector<const_arc_iterator> const_arc_vector;\r
+    const_arc_vector constify_arcs(const arc_vector&) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    arc_vector deconstify_arcs(const const_arc_vector&) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // a path vector is a vector of paths used to represent all the paths from one node to another\r
+    // there is no particular ordering to the paths in the vector\r
+    typedef std::vector<arc_vector> path_vector;\r
+    typedef std::vector<const_arc_vector> const_path_vector;\r
+    const_path_vector constify_paths(const path_vector&) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    path_vector deconstify_paths(const const_path_vector&) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // a node vector is a simple vector of nodes used to represent the reachable sets\r
+    // there is no particular ordering to the nodes in the vector\r
+    typedef std::vector<iterator> node_vector;\r
+    typedef std::vector<const_iterator> const_node_vector;\r
+    const_node_vector constify_nodes(const node_vector&) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    node_vector deconstify_nodes(const const_node_vector&) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // callback used in the path algorithms to select which arcs to consider\r
+    typedef bool (*arc_select_fn) (const digraph<NT,AT>&, const_arc_iterator);\r
+\r
+    // a value representing an unknown offset\r
+    // Note that it's static so use in the form digraph<NT,AT>::npos()\r
+    static unsigned npos(void);\r
+\r
+    //////////////////////////////////////////////////////////////////////////\r
+    // Constructors, destructors and copies\r
+\r
+    digraph(void);\r
+    ~digraph(void);\r
+\r
+    // copy constructor and assignment both copy the graph\r
+    digraph(const digraph<NT,AT>&);\r
+    digraph<NT,AT>& operator=(const digraph<NT,AT>&);\r
+\r
+    //////////////////////////////////////////////////////////////////////////\r
+    // Basic Node functions\r
+    // Nodes are referred to by iterators created when the node is inserted.\r
+    // Iterators remain valid unless the node is erased (they are list iterators, so no resize problems)\r
+    // It is also possible to walk through all the nodes using a list-like start() to end() loop\r
+    // Each node has a set of input arcs and output arcs. These are indexed by an unsigned i.e. they form a vector.\r
+    // The total number of inputs is the fanin and the total number of outputs is the fanout.\r
+    // The contents of the node (type NT) are accessed, of course, by dereferencing the node iterator.\r
+\r
+    // tests for the number of nodes and the special test for zero nodes\r
+    bool empty(void) const;\r
+    unsigned size(void) const;\r
+\r
+    // add a new node and return its iterator\r
+    iterator insert(const NT& node_data);\r
+\r
+    // remove a node and return the iterator to the next node\r
+    // erasing a node erases its arcs\r
+    iterator erase(iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    // remove all nodes\r
+    void clear(void);\r
+\r
+    // traverse all the nodes in no particular order using STL-style iteration\r
+    const_iterator begin(void) const;\r
+    iterator begin(void);\r
+    const_iterator end(void) const;\r
+    iterator end(void);\r
+\r
+    // access the inputs of this node\r
+    // the fanin is the number of inputs and the inputs are accessed using an index from 0..fanin-1\r
+    unsigned fanin(const_iterator) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    unsigned fanin(iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    const_arc_iterator input(const_iterator, unsigned) const\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+    arc_iterator input(iterator, unsigned)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+\r
+    // access the outputs of this node\r
+    // the fanout is the number of outputs and the outputs are accessed using an index from 0..fanout-1\r
+    unsigned fanout(const_iterator) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    unsigned fanout(iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    const_arc_iterator output(const_iterator, unsigned) const\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+    arc_iterator output(iterator, unsigned)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+\r
+    // convenience routines for getting the set of all inputs or all outputs as vectors\r
+    const_arc_vector inputs(const_iterator) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    arc_vector inputs(iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    const_arc_vector outputs(const_iterator) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    arc_vector outputs(iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // find the output index of an arc which goes from this node\r
+    // returns digraph<NT,AT>::npos if the arc is not an output of from\r
+    unsigned output_offset(const_iterator from, const_arc_iterator arc) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    unsigned output_offset(iterator from, arc_iterator arc)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    // ditto for an input arc\r
+    unsigned input_offset(const_iterator to, const_arc_iterator arc) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    unsigned input_offset(iterator to, arc_iterator arc)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    //////////////////////////////////////////////////////////////////////////\r
+    // Basic Arc functions\r
+    // to avoid name conflicts, arc functions have the arc_ prefix \r
+    // Arcs, like nodes, are referred to by a list iterator which is returned by the arc_insert function\r
+    // They may also be visited from arc_begin() to arc_end()\r
+    // Each arc has a from field and a to field which contain the node iterators of the endpoints of the arc\r
+    // Of course, the arc data can be accessed by simply dereferencing the iterator\r
+\r
+    // tests for the number of arcs and the special test for zero arcs\r
+    bool arc_empty (void) const;\r
+    unsigned arc_size(void) const;\r
+\r
+    // add a new arc and return its iterator\r
+    arc_iterator arc_insert(iterator from, iterator to, const AT& arc_data = AT())\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // remove an arc and return the iterator to the next arc\r
+    arc_iterator arc_erase(arc_iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    // remove all arcs\r
+    void arc_clear(void);\r
+\r
+    // traverse all the arcs in no particular order using STL-style iteration\r
+    const_arc_iterator arc_begin(void) const;\r
+    arc_iterator arc_begin(void);\r
+    const_arc_iterator arc_end(void) const;\r
+    arc_iterator arc_end(void);\r
+\r
+    // find the node that an arc points from or to\r
+    const_iterator arc_from(const_arc_iterator) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    iterator arc_from(arc_iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    const_iterator arc_to(const_arc_iterator) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    iterator arc_to(arc_iterator)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // reconnect an arc to a different from and to node\r
+    void arc_move(arc_iterator arc, iterator from, iterator to)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    // reconnect just the from node\r
+    void arc_move_from(arc_iterator arc, iterator from)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    // reconnect just the to node\r
+    void arc_move_to(arc_iterator arc, iterator to)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    // reverse the arc direction so that to becomes from and vice-versa\r
+    void arc_flip(arc_iterator arc)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    ////////////////////////////////////////////////////////////////////////////////\r
+    // Adjacency algorithms\r
+\r
+    // test whether the nodes are adjacent i.e. whether there is an arc going from from to to\r
+    bool adjacent(const_iterator from, const_iterator to) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    bool adjacent(iterator from, iterator to)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // as above, but returns the arc that makes the nodes adjacent\r
+    // returns the first arc if there's more than one, returns arc_end() if there are none\r
+    const_arc_iterator adjacent_arc(const_iterator from, const_iterator to) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    arc_iterator adjacent_arc(iterator from, iterator to)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // as above, but returns the set of all arcs that make two nodes adjacent (there may be more than one)\r
+    // returns an empty vector if there are none\r
+    const_arc_vector adjacent_arcs(const_iterator from, const_iterator to) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    arc_vector adjacent_arcs(iterator from, iterator to)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // return the adjacency sets for the node inputs or outputs, i.e. the set of nodes adjacent to this node\r
+    // each adjacent node will only be entered once even if there are multiple arcs between the nodes\r
+    const_node_vector input_adjacencies(const_iterator to) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    node_vector input_adjacencies(iterator to)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    const_node_vector output_adjacencies(const_iterator from) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    node_vector output_adjacencies(iterator from)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    ////////////////////////////////////////////////////////////////////////////////\r
+    // Topographical Sort Algorithm\r
+    // This generates a node ordering such that each node is visited after its fanin nodes.\r
+\r
+    // This only generates a valid ordering for a DAG. \r
+\r
+    // The return value is a pair : \r
+    //  - the node vector which is a set of iterators to the nodes in sorted order\r
+    //  - the arc vector is the set of backward ards that were broken to achieve the sort\r
+    // If the arc vector is empty then the graph formed a DAG.\r
+\r
+    // The arc selection callback can be used to ignore arcs that are not part\r
+    // of the ordering, i.e. arcs that are meant to be backwards arcs\r
+\r
+    std::pair<const_node_vector,const_arc_vector> sort(arc_select_fn = 0) const;\r
+    std::pair<node_vector,arc_vector> sort(arc_select_fn = 0);\r
+\r
+    // Simplified variant of above for graphs that are known to be DAGs.\r
+    // If the sort fails due to backward arcs, the\r
+    // return vector is empty. Note that this will also be empty if the graph\r
+    // has no nodes in it, so use the empty() method to differentiate.\r
+\r
+    const_node_vector dag_sort(arc_select_fn = 0) const;\r
+    node_vector dag_sort(arc_select_fn = 0);\r
+\r
+    ////////////////////////////////////////////////////////////////////////////////\r
+    // Basic Path Algorithms\r
+    // A path is a series of arcs - you can use arc_from and arc_to to convert\r
+    // that into a series of nodes. All the path algorithms take an arc_select\r
+    // which allows arcs to be selected or rejected for consideration in a path.\r
+\r
+    // A selection callback function is applied to each arc in the traversal and\r
+    // returns true if the arc is to be selected and false if the arc is to be\r
+    // rejected. If no function is provided the arc is selected. If you want to\r
+    // use arc selection you should create a function with the type profile given\r
+    // by the arc_select_fn type. The select function is passed both the graph and\r
+    // the arc iterator so that it is possible to select an arc on the basis of\r
+    // the nodes it is connected to.\r
+\r
+    // Note: I used a callback because the STL-like predicate idea wasn't working for me...\r
+\r
+    // test for the existence of a path from from to to\r
+    bool path_exists(const_iterator from, const_iterator to, arc_select_fn = 0) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    bool path_exists(iterator from, iterator to, arc_select_fn = 0)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // get the set of all paths from from to to\r
+    const_path_vector all_paths(const_iterator from, const_iterator to, arc_select_fn = 0) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    path_vector all_paths(iterator from, iterator to, arc_select_fn = 0)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // get the set of all nodes that can be reached by any path from from\r
+    const_node_vector reachable_nodes(const_iterator from, arc_select_fn = 0) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    node_vector reachable_nodes(iterator from, arc_select_fn = 0)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // get the set of all nodes that can reach to to by any path\r
+    const_node_vector reaching_nodes(const_iterator to, arc_select_fn = 0) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    node_vector reaching_nodes(iterator to, arc_select_fn = 0)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    ////////////////////////////////////////////////////////////////////////////////\r
+    // Unweighted Shortest path algorithms\r
+\r
+    // find the shortest path from from to to\r
+    // This is an unweighted shortest path algorithm, i.e. the weight of each\r
+    // arc is assumed to be 1, so just counts the number of arcs\r
+    // if there is more than one shortest path it returns the first one\r
+    // If there are no paths, returns an empty path\r
+    const_arc_vector shortest_path(const_iterator from, const_iterator to, arc_select_fn = 0) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    arc_vector shortest_path(iterator from, iterator to, arc_select_fn = 0)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // find the set of shortest paths from from to any other node in the graph\r
+    // that is reachable (i.e. for which path_exists() is true)\r
+    // This is an unweighted shortest path, so just counts the number of arcs\r
+    // if there is more than one shortest path to a node it returns the first one\r
+    // If there are no paths, returns an empty list\r
+    const_path_vector shortest_paths(const_iterator from, arc_select_fn = 0) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    path_vector shortest_paths(iterator from, arc_select_fn = 0)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+  private:\r
+    friend class digraph_iterator<NT,AT,NT&,NT*>;\r
+    friend class digraph_iterator<NT,AT,const NT&,const NT*>;\r
+    friend class digraph_arc_iterator<NT,AT,AT&,AT*>;\r
+    friend class digraph_arc_iterator<NT,AT,const AT&, const AT*>;\r
+\r
+    typedef std::set<const_iterator> const_iterator_set;\r
+    typedef TYPENAME const_iterator_set::iterator const_iterator_set_iterator;\r
+\r
+    bool path_exists_r(const_iterator from, const_iterator to, const_iterator_set& visited, arc_select_fn) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    void all_paths_r(const_iterator from, const_iterator to, const_arc_vector& so_far, const_path_vector& result, arc_select_fn) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    void reachable_nodes_r(const_iterator from, const_iterator_set& visited, arc_select_fn) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    void reaching_nodes_r(const_iterator to, const_iterator_set& visited, arc_select_fn) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    digraph_node<NT,AT>* m_nodes_begin;\r
+    digraph_node<NT,AT>* m_nodes_end;\r
+    digraph_arc<NT,AT>* m_arcs_begin;\r
+    digraph_arc<NT,AT>* m_arcs_end;\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#include "digraph.tpp"\r
+#endif\r
diff --git a/src/Moof/stlplus/digraph.tpp b/src/Moof/stlplus/digraph.tpp
new file mode 100755 (executable)
index 0000000..c10586b
--- /dev/null
@@ -0,0 +1,1483 @@
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   Note: I tried to write this using STL lists for the node and arc lists, but\r
+//   it got far too hairy. The specific problem is that I wanted a digraph\r
+//   iterator to contain a list::iterator so I needed to be able to generate a\r
+//   list::iterator from a node or arc and STL list iterators don't give you that\r
+//   functionality. I tried burgling the data structures, but that was\r
+//   non-portable between different STL implementations so needed lots of #ifdefs\r
+//   and so was mind-bogglingly awful and unreadable - in other words a\r
+//   maintenance nightmare. I gave up and impemented my own lists - not difficult.\r
+\r
+//   I use circular double-linked lists. The circular design means that both\r
+//   ends of the list are equally accessible in unit time. An empty list\r
+//   contains no objects. There is no end node in the list - unlike the STL\r
+//   lists which have a dummy node for end iterators to point to -\r
+//   conceptually the end iterator points one element beyond the end of the\r
+//   list. However, I implement the end iterator concept in the iterator\r
+//   itself, so do not need the dummy end node.\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include <algorithm>\r
+#include <deque>\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Internals\r
+\r
+namespace stlplus\r
+{\r
+\r
+  template<typename NT, typename AT>\r
+  class digraph_node\r
+  {\r
+  public:\r
+    master_iterator<digraph<NT,AT>, digraph_node<NT,AT> > m_master;\r
+    NT m_data;\r
+    digraph_node<NT,AT>* m_prev;\r
+    digraph_node<NT,AT>* m_next;\r
+    std::vector<digraph_arc<NT,AT>*> m_inputs;\r
+    std::vector<digraph_arc<NT,AT>*> m_outputs;\r
+  public:\r
+    digraph_node(const digraph<NT,AT>* owner, const NT& d = NT()) :\r
+      m_master(owner,this), m_data(d), m_prev(0), m_next(0)\r
+      {\r
+      }\r
+    ~digraph_node(void)\r
+      {\r
+      }\r
+  };\r
+\r
+  template<typename NT, typename AT>\r
+  class digraph_arc\r
+  {\r
+  public:\r
+    master_iterator<digraph<NT,AT>, digraph_arc<NT,AT> > m_master;\r
+    AT m_data;\r
+    digraph_arc<NT,AT>* m_prev;\r
+    digraph_arc<NT,AT>* m_next;\r
+    digraph_node<NT,AT>* m_from;\r
+    digraph_node<NT,AT>* m_to;\r
+    digraph_arc(const digraph<NT,AT>* owner, digraph_node<NT,AT>* from = 0, digraph_node<NT,AT>* to = 0, const AT& d = AT()) : \r
+      m_master(owner,this), m_data(d), m_prev(0), m_next(0), m_from(from), m_to(to)\r
+      {\r
+      }\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Iterators\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Node iterator\r
+\r
+  // construct a null iterator\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(void)\r
+  {\r
+  }\r
+\r
+  // valid iterator\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(digraph_node<NT,AT>* node) :\r
+    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(node->m_master)\r
+  {\r
+  }\r
+\r
+  // end iterator\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(const digraph<NT,AT>* owner) :\r
+    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(owner)\r
+  {\r
+  }\r
+\r
+  // alias an iterator\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(const safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >& iterator) : \r
+    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(iterator)\r
+  {\r
+  }\r
+\r
+  // destructor\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_iterator<NT,AT,NRef,NPtr>::~digraph_iterator(void)\r
+  {\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::const_iterator digraph_iterator<NT,AT,NRef,NPtr>::constify (void) const\r
+  {\r
+    return digraph_iterator<NT,AT,const NT&,const NT*>(*this);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::iterator digraph_iterator<NT,AT,NRef,NPtr>::deconstify (void) const\r
+  {\r
+    return digraph_iterator<NT,AT,NT&,NT*>(*this);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& digraph_iterator<NT,AT,NRef,NPtr>::operator ++ (void)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    if (this->node()->m_next)\r
+      this->set(this->node()->m_next->m_master);\r
+    else\r
+      this->set_end();\r
+    return *this;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator digraph_iterator<NT,AT,NRef,NPtr>::operator ++ (int)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // post-increment is defined in terms of the pre-increment\r
+    digraph_iterator<NT,AT,NRef,NPtr> result(*this);\r
+    ++(*this);\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& digraph_iterator<NT,AT,NRef,NPtr>::operator -- (void)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    if (this->node()->m_prev)\r
+      this->set(this->node()->m_prev->m_master);\r
+    else\r
+      this->set_end();\r
+    return *this;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator digraph_iterator<NT,AT,NRef,NPtr>::operator -- (int)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // post-decrement is defined in terms of the pre-decrement\r
+    digraph_iterator<NT,AT,NRef,NPtr> result(*this);\r
+    --(*this);\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  bool digraph_iterator<NT,AT,NRef,NPtr>::operator == (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const\r
+  {\r
+    return equal(r);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  bool digraph_iterator<NT,AT,NRef,NPtr>::operator != (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const\r
+  {\r
+    return !operator==(r);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  bool digraph_iterator<NT,AT,NRef,NPtr>::operator < (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const\r
+  {\r
+    return compare(r) < 0;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::reference digraph_iterator<NT,AT,NRef,NPtr>::operator*(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    return this->node()->m_data;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::pointer digraph_iterator<NT,AT,NRef,NPtr>::operator->(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return &(operator*());\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Arc Iterator\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  digraph_arc_iterator<NT,AT,ARef,APtr>::digraph_arc_iterator(void)\r
+  {\r
+  }\r
+\r
+  // valid iterator\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(digraph_arc<NT,AT>* arc) :\r
+    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(arc->m_master)\r
+  {\r
+  }\r
+\r
+  // end iterator\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(const digraph<NT,AT>* owner) :\r
+    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(owner)\r
+  {\r
+  }\r
+\r
+  // alias an iterator\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(const safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >& iterator) : \r
+    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(iterator)\r
+  {\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  digraph_arc_iterator<NT,AT,ARef,APtr>::~digraph_arc_iterator(void)\r
+  {\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,NRef,NPtr>::const_iterator digraph_arc_iterator<NT,AT,NRef,NPtr>::constify (void) const\r
+  {\r
+    return digraph_arc_iterator<NT,AT,const AT&,const AT*>(*this);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename NRef, typename NPtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,NRef,NPtr>::iterator digraph_arc_iterator<NT,AT,NRef,NPtr>::deconstify (void) const\r
+  {\r
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(*this);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& digraph_arc_iterator<NT,AT,ARef,APtr>::operator ++ (void)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    if (this->node()->m_next)\r
+      this->set(this->node()->m_next->m_master);\r
+    else\r
+      this->set_end();\r
+    return *this;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator digraph_arc_iterator<NT,AT,ARef,APtr>::operator ++ (int)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // post-increment is defined in terms of the pre-increment\r
+    digraph_arc_iterator<NT,AT,ARef,APtr> result(*this);\r
+    ++(*this);\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& digraph_arc_iterator<NT,AT,ARef,APtr>::operator -- (void)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    if (this->node()->m_prev)\r
+      this->set(this->node()->m_prev->m_master);\r
+    else\r
+      this->set_end();\r
+    return *this;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator digraph_arc_iterator<NT,AT,ARef,APtr>::operator -- (int)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // post-decrement is defined in terms of the pre-decrement\r
+    digraph_arc_iterator<NT,AT,ARef,APtr> result(*this);\r
+    --(*this);\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator == (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const\r
+  {\r
+    return equal(r);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator != (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const\r
+  {\r
+    return !operator==(r);\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator < (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const\r
+  {\r
+    return compare(r) < 0;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::reference digraph_arc_iterator<NT,AT,ARef,APtr>::operator*(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    return this->node()->m_data;\r
+  }\r
+\r
+  template<typename NT, typename AT, typename ARef, typename APtr>\r
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::pointer digraph_arc_iterator<NT,AT,ARef,APtr>::operator->(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return &(operator*());\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // subtype utilities\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::constify_arcs(const TYPENAME digraph<NT,AT>::arc_vector& arcs) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > result;\r
+    for (unsigned i = 0; i < arcs.size(); i++)\r
+    {\r
+      arcs[i].assert_valid(this);\r
+      result.push_back(arcs[i].constify());\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::deconstify_arcs(const TYPENAME digraph<NT,AT>::const_arc_vector& arcs) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;\r
+    for (unsigned i = 0; i < arcs.size(); i++)\r
+    {\r
+      arcs[i].assert_valid(this);\r
+      result.push_back(arcs[i].deconstify());\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_path_vector digraph<NT,AT>::constify_paths(const TYPENAME digraph<NT,AT>::path_vector& paths) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;\r
+    for (unsigned i = 0; i < paths.size(); i++)\r
+      result.push_back(constify_arcs(paths[i]));\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::path_vector digraph<NT,AT>::deconstify_paths(const TYPENAME digraph<NT,AT>::const_path_vector& paths) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > > result;\r
+    for (unsigned i = 0; i < paths.size(); i++)\r
+      result.push_back(deconstify_arcs(paths[i]));\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::constify_nodes(const TYPENAME digraph<NT,AT>::node_vector& nodes) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
+    for (unsigned i = 0; i < nodes.size(); i++)\r
+    {\r
+      nodes[i].assert_valid(this);\r
+      result.push_back(nodes[i].constify());\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::deconstify_nodes(const TYPENAME digraph<NT,AT>::const_node_vector& nodes) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<digraph_iterator<NT,AT,NT&,NT*> > result;\r
+    for (unsigned i = 0; i < nodes.size(); i++)\r
+    {\r
+      nodes[i].assert_valid(this);\r
+      result.push_back(nodes[i].deconstify());\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::npos(void)\r
+  {\r
+    return(unsigned)-1;\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Constructors etc.\r
+\r
+  template<typename NT, typename AT>\r
+  digraph<NT,AT>::digraph(void) :\r
+    m_nodes_begin(0), m_nodes_end(0), m_arcs_begin(0), m_arcs_end(0)\r
+  {\r
+    // node and arc lists are circular double-linked lists\r
+    // they start out empty (no dummy end node)\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  digraph<NT,AT>::~digraph(void)\r
+  {\r
+    clear();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  digraph<NT,AT>::digraph(const digraph<NT,AT>& r) :\r
+    m_nodes_begin(0), m_nodes_end(0), m_arcs_begin(0), m_arcs_end(0)\r
+  {\r
+    *this = r;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  digraph<NT,AT>& digraph<NT,AT>::operator=(const digraph<NT,AT>& r)\r
+  {\r
+    // make it self-copy safe i.e. a=a; is a valid instruction\r
+    if (this == &r) return *this;\r
+    clear();\r
+    // first phase is to copy the nodes, creating a map of cross references from the old nodes to their new equivalents\r
+    std::map<digraph_iterator<NT,AT,const NT&,const NT*>, digraph_iterator<NT,AT,NT&,NT*> > xref;\r
+    for (digraph_iterator<NT,AT,const NT&,const NT*> n = r.begin(); n != r.end(); n++)\r
+      xref[n] = insert(*n);\r
+    // second phase is to copy the arcs, using the map to convert the old to and from nodes to the new nodes\r
+    for (digraph_arc_iterator<NT,AT, const AT&,const AT*> a = r.arc_begin(); a != r.arc_end(); a++)\r
+      arc_insert(xref[r.arc_from(a)],xref[r.arc_to(a)],*a);\r
+    return *this;\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Basic Node functions\r
+\r
+  template<typename NT, typename AT>\r
+  bool digraph<NT,AT>::empty(void) const\r
+  {\r
+    return m_nodes_begin == 0;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::size(void) const\r
+  {\r
+    unsigned count = 0;\r
+    for (digraph_iterator<NT,AT,const NT&,const NT*> i = begin(); i != end(); i++)\r
+      count++;\r
+    return count;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::insert(const NT& node_data)\r
+  {\r
+    digraph_node<NT,AT>* new_node = new digraph_node<NT,AT>(this,node_data);\r
+    if (!m_nodes_end)\r
+    {\r
+      // insert into an empty list\r
+      m_nodes_begin = new_node;\r
+      m_nodes_end = new_node;\r
+    }\r
+    else\r
+    {\r
+      // insert at the end of the list\r
+      new_node->m_prev = m_nodes_end;\r
+      m_nodes_end->m_next = new_node;\r
+      m_nodes_end = new_node;\r
+    }\r
+    return digraph_iterator<NT,AT,NT&,NT*>(new_node);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::erase(TYPENAME digraph<NT,AT>::iterator iter)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    // remove all arcs connected to this node first\r
+    // use arc_erase rather than arcs.erase because that tidies up the node at the other end of the arc too\r
+    for (unsigned i = fanin(iter); i--; )\r
+      arc_erase(input(iter,i));\r
+    for (unsigned j = fanout(iter); j--; )\r
+      arc_erase(output(iter,j));\r
+    // now unlink the node from the list and delete it\r
+    if (iter.node()->m_next)\r
+      iter.node()->m_next->m_prev = iter.node()->m_prev;\r
+    if (iter.node()->m_prev)\r
+      iter.node()->m_prev->m_next = iter.node()->m_next;\r
+    digraph_node<NT,AT>* next = iter.node()->m_next;\r
+    delete iter.node();\r
+    // return the next node in the list\r
+    if (next)\r
+      return digraph_iterator<NT,AT,NT&,NT*>(next);\r
+    else\r
+      return digraph_iterator<NT,AT,NT&,NT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::clear(void)\r
+  {\r
+    // clearing the nodes also clears the arcs\r
+    for (digraph_iterator<NT,AT,NT&,NT*> i = begin(); i != end(); )\r
+      i = erase(i);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::begin(void) const\r
+  {\r
+    if (m_nodes_begin)\r
+      return digraph_iterator<NT,AT,const NT&,const NT*>(m_nodes_begin);\r
+    else\r
+      return digraph_iterator<NT,AT,const NT&,const NT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::begin(void)\r
+  {\r
+    if (m_nodes_begin)\r
+      return digraph_iterator<NT,AT,NT&,NT*>(m_nodes_begin);\r
+    else\r
+      return digraph_iterator<NT,AT,NT&,NT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::end(void) const\r
+  {\r
+    return digraph_iterator<NT,AT,const NT&,const NT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::end(void)\r
+  {\r
+    return digraph_iterator<NT,AT,NT&,NT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::fanin(TYPENAME digraph<NT,AT>::const_iterator iter) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return iter.node()->m_inputs.size();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::fanin(TYPENAME digraph<NT,AT>::iterator iter)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return iter.node()->m_inputs.size();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::input(TYPENAME digraph<NT,AT>::const_iterator iter, unsigned i) const\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    iter.assert_valid(this);\r
+    if (i >= iter.node()->m_inputs.size()) throw std::out_of_range("digraph::input");\r
+    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(iter.node()->m_inputs[i]);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::input(TYPENAME digraph<NT,AT>::iterator iter, unsigned i)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    iter.assert_valid(this);\r
+    if (i >= iter.node()->m_inputs.size()) throw std::out_of_range("digraph::input");\r
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(iter.node()->m_inputs[i]);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::fanout(TYPENAME digraph<NT,AT>::const_iterator iter) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return iter.node()->m_outputs.size();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::fanout(TYPENAME digraph<NT,AT>::iterator iter)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return iter.node()->m_outputs.size();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::output(TYPENAME digraph<NT,AT>::const_iterator iter, unsigned i) const\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    iter.assert_valid(this);\r
+    if (i >= iter.node()->m_outputs.size()) throw std::out_of_range("digraph::output");\r
+    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(iter.node()->m_outputs[i]);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::output(TYPENAME digraph<NT,AT>::iterator iter, unsigned i)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    iter.assert_valid(this);\r
+    if (i >= iter.node()->m_outputs.size()) throw std::out_of_range("digraph::output");\r
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(iter.node()->m_outputs[i]);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::inputs(TYPENAME digraph<NT,AT>::const_iterator node) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    node.assert_valid(this);\r
+    std::vector<digraph_arc_iterator<NT,AT,const AT&, const AT*> > result;\r
+    for (unsigned i = 0; i < fanin(node); i++)\r
+      result.push_back(input(node,i));\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::inputs(TYPENAME digraph<NT,AT>::iterator node)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    node.assert_valid(this);\r
+    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;\r
+    for (unsigned i = 0; i < fanin(node); i++)\r
+      result.push_back(input(node,i));\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::outputs(TYPENAME digraph<NT,AT>::const_iterator node) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    node.assert_valid(this);\r
+    std::vector<digraph_arc_iterator<NT,AT,const AT&, const AT*> > result;\r
+    for (unsigned i = 0; i < fanout(node); i++)\r
+      result.push_back(output(node,i));\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::outputs(TYPENAME digraph<NT,AT>::iterator node)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    node.assert_valid(this);\r
+    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;\r
+    for (unsigned i = 0; i < fanout(node); i++)\r
+      result.push_back(output(node,i));\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::output_offset(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                         TYPENAME digraph<NT,AT>::const_arc_iterator arc) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    from.assert_valid(this);\r
+    arc.assert_valid(this);\r
+    for (unsigned i = 0; i < fanout(from); i++)\r
+    {\r
+      if (output(from,i) == arc)\r
+        return i;\r
+    }\r
+    return digraph<NT,AT>::npos();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::output_offset(TYPENAME digraph<NT,AT>::iterator from,\r
+                                         TYPENAME digraph<NT,AT>::arc_iterator arc)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    from.assert_valid(this);\r
+    arc.assert_valid(this);\r
+    for (unsigned i = 0; i < fanout(from); i++)\r
+    {\r
+      if (output(from,i) == arc)\r
+        return i;\r
+    }\r
+    return digraph<NT,AT>::npos();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::input_offset(TYPENAME digraph<NT,AT>::const_iterator to,\r
+                                        TYPENAME digraph<NT,AT>::const_arc_iterator arc) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    to.assert_valid(this);\r
+    arc.assert_valid(this);\r
+    for (unsigned i = 0; i < fanin(to); i++)\r
+    {\r
+      if (input(to,i) == arc)\r
+        return i;\r
+    }\r
+    return digraph<NT,AT>::npos();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::input_offset(TYPENAME digraph<NT,AT>::iterator to,\r
+                                        TYPENAME digraph<NT,AT>::arc_iterator arc)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    to.assert_valid(this);\r
+    arc.assert_valid(this);\r
+    for (unsigned i = 0; i < fanin(to); i++)\r
+    {\r
+      if (input(to,i) == arc)\r
+        return i;\r
+    }\r
+    return digraph<NT,AT>::npos();\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Basic Arc functions\r
+\r
+  template<typename NT, typename AT>\r
+  bool digraph<NT,AT>::arc_empty(void) const\r
+  {\r
+    return m_arcs_end == 0;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  unsigned digraph<NT,AT>::arc_size(void) const\r
+  {\r
+    unsigned count = 0;\r
+    for (digraph_arc_iterator<NT,AT, const AT&,const AT*> i = arc_begin(); i != arc_end(); i++)\r
+      count++;\r
+    return count;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_insert(TYPENAME digraph<NT,AT>::iterator from,\r
+                                                                   TYPENAME digraph<NT,AT>::iterator to,\r
+                                                                   const AT& arc_data)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    from.assert_valid(this);\r
+    to.assert_valid(this);\r
+    // create the new arc and link it in to the arc list\r
+    digraph_arc<NT,AT>* new_arc = new digraph_arc<NT,AT>(this, from.node(), to.node(), arc_data);\r
+    if (!m_arcs_end)\r
+    {\r
+      // insert into an empty list\r
+      m_arcs_begin = new_arc;\r
+      m_arcs_end = new_arc;\r
+    }\r
+    else\r
+    {\r
+      // insert at the end of the list\r
+      new_arc->m_prev = m_arcs_end;\r
+      m_arcs_end->m_next = new_arc;\r
+      m_arcs_end = new_arc;\r
+    }\r
+    // add this arc to the inputs and outputs of the end nodes\r
+    from.node()->m_outputs.push_back(new_arc);\r
+    to.node()->m_inputs.push_back(new_arc);\r
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(new_arc);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_erase(TYPENAME digraph<NT,AT>::arc_iterator iter)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    // first remove this arc's pointers from the from/to nodes\r
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator i = iter.node()->m_to->m_inputs.begin(); i != iter.node()->m_to->m_inputs.end(); )\r
+    {\r
+      if (*i == iter.node())\r
+        i = iter.node()->m_to->m_inputs.erase(i);\r
+      else\r
+        i++;\r
+    }\r
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator o = iter.node()->m_from->m_outputs.begin(); o != iter.node()->m_from->m_outputs.end(); )\r
+    {\r
+      if (*o == iter.node())\r
+        o = iter.node()->m_from->m_outputs.erase(o);\r
+      else\r
+        o++;\r
+    }\r
+    // now unlink the arc from the list and delete it\r
+    if (iter.node()->m_next)\r
+      iter.node()->m_next->m_prev = iter.node()->m_prev;\r
+    if (iter.node()->m_prev)\r
+      iter.node()->m_prev->m_next = iter.node()->m_next;\r
+    digraph_arc<NT,AT>* next = iter.node()->m_next;\r
+    delete iter.node();\r
+    if (next)\r
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(next);\r
+    else\r
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::arc_clear(void)\r
+  {\r
+    for (digraph_arc_iterator<NT,AT,AT&,AT*> a = arc_begin(); a != arc_end(); )\r
+      a = arc_erase(a);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::arc_begin(void) const\r
+  {\r
+    if (m_arcs_begin)\r
+      return digraph_arc_iterator<NT,AT, const AT&,const AT*>(m_arcs_begin);\r
+    else\r
+      return digraph_arc_iterator<NT,AT, const AT&,const AT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_begin(void)\r
+  {\r
+    if (m_arcs_begin)\r
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(m_arcs_begin);\r
+    else\r
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::arc_end(void) const\r
+  {\r
+    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_end(void)\r
+  {\r
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(this);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::arc_from(TYPENAME digraph<NT,AT>::const_arc_iterator iter) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return digraph_iterator<NT,AT,const NT&,const NT*>(iter.node()->m_from);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::arc_from(TYPENAME digraph<NT,AT>::arc_iterator iter)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return digraph_iterator<NT,AT,NT&,NT*>(iter.node()->m_from);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::arc_to(TYPENAME digraph<NT,AT>::const_arc_iterator iter) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return digraph_iterator<NT,AT,const NT&,const NT*>(iter.node()->m_to);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::arc_to(TYPENAME digraph<NT,AT>::arc_iterator iter)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    iter.assert_valid(this);\r
+    return digraph_iterator<NT,AT,NT&,NT*>(iter.node()->m_to);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::arc_move(TYPENAME digraph<NT,AT>::arc_iterator arc,\r
+                                TYPENAME digraph<NT,AT>::iterator from,\r
+                                TYPENAME digraph<NT,AT>::iterator to)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    arc_move_to(arc,to);\r
+    arc_move_from(arc,from);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::arc_move_from(TYPENAME digraph<NT,AT>::arc_iterator arc,\r
+                                     TYPENAME digraph<NT,AT>::iterator from)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    arc.assert_valid(this);\r
+    from.assert_valid(this);\r
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator o = arc.node()->m_from->m_outputs.begin(); o != arc.node()->m_from->m_outputs.end(); )\r
+    {\r
+      if (*o == arc.node())\r
+        o = arc.node()->m_from->m_outputs.erase(o);\r
+      else\r
+        o++;\r
+    }\r
+    from.node()->m_outputs.push_back(arc.node());\r
+    arc.node()->m_from = from.node();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::arc_move_to(TYPENAME digraph<NT,AT>::arc_iterator arc,\r
+                                   TYPENAME digraph<NT,AT>::iterator to)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    arc.assert_valid(this);\r
+    to.assert_valid(this);\r
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator i = arc.node()->m_to->m_inputs.begin(); i != arc.node()->m_to->m_inputs.end(); )\r
+    {\r
+      if (*i == arc.node())\r
+        i = arc.node()->m_to->m_inputs.erase(i);\r
+      else\r
+        i++;\r
+    }\r
+    to.node()->m_inputs.push_back(arc.node());\r
+    arc.node()->m_to = to.node();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::arc_flip(TYPENAME digraph<NT,AT>::arc_iterator arc)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    arc_move(arc,arc_to(arc),arc_from(arc));\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Adjacency Algorithms\r
+\r
+  template<typename NT, typename AT>\r
+  bool digraph<NT,AT>::adjacent(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                TYPENAME digraph<NT,AT>::const_iterator to) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return adjacent_arc(from,to) != arc_end();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  bool digraph<NT,AT>::adjacent(TYPENAME digraph<NT,AT>::iterator from,\r
+                                TYPENAME digraph<NT,AT>::iterator to)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return adjacent_arc(from,to) != arc_end();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::adjacent_arc(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                                                           TYPENAME digraph<NT,AT>::const_iterator to) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    from.assert_valid(this);\r
+    to.assert_valid(this);\r
+    for (unsigned arc = 0; arc < fanout(from); arc++)\r
+    {\r
+      if (arc_to(output(from, arc)) == to)\r
+        return output(from,arc);\r
+    }\r
+    return arc_end();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::adjacent_arc(TYPENAME digraph<NT,AT>::iterator from,\r
+                                                                     TYPENAME digraph<NT,AT>::iterator to)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return adjacent_arc(from.constify(), to.constify()).deconstify();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::adjacent_arcs(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                                                          TYPENAME digraph<NT,AT>::const_iterator to) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    from.assert_valid(this);\r
+    to.assert_valid(this);\r
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > result;\r
+    for (unsigned arc = 0; arc < fanout(from); arc++)\r
+    {\r
+      if (arc_to(output(from, arc)) == to)\r
+        result.push_back(output(from,arc));\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::adjacent_arcs(TYPENAME digraph<NT,AT>::iterator from,\r
+                                                                    TYPENAME digraph<NT,AT>::iterator to)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_arcs(adjacent_arcs(from.constify(), to.constify()));\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::input_adjacencies(TYPENAME digraph<NT,AT>::const_iterator to) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
+    for (unsigned arc = 0; arc < fanin(to); arc++)\r
+    {\r
+      digraph_iterator<NT,AT,const NT&,const NT*> from = arc_from(input(to, arc));\r
+      if (std::find(result.begin(), result.end(), from) == result.end())\r
+        result.push_back(from);\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::input_adjacencies(TYPENAME digraph<NT,AT>::iterator to)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_nodes(input_adjacencies(to.constify()));\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::output_adjacencies(TYPENAME digraph<NT,AT>::const_iterator from) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
+    for (unsigned arc = 0; arc < fanout(from); arc++)\r
+    {\r
+      digraph_iterator<NT,AT,const NT&,const NT*> to = arc_to(output(from, arc));\r
+      if (find(result.begin(), result.end(), to) == result.end())\r
+        result.push_back(to);\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::output_adjacencies(TYPENAME digraph<NT,AT>::iterator from)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_nodes(output_adjacencies(from.constify()));\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Topographical Sort Algorithms\r
+\r
+  template<typename NT, typename AT>\r
+  std::pair<TYPENAME digraph<NT,AT>::const_node_vector, TYPENAME digraph<NT,AT>::const_arc_vector>\r
+  digraph<NT,AT>::sort(TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+  {\r
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > errors;\r
+    // build a map containing the number of fanins to each node that must be visited before this one\r
+    std::map<digraph_iterator<NT,AT,const NT&,const NT*>,unsigned> fanin_map;\r
+    for (digraph_iterator<NT,AT,const NT&,const NT*> n = begin(); n != end(); n++)\r
+    {\r
+      unsigned predecessors = 0;\r
+      // only count predecessors connected by selected arcs\r
+      for (unsigned f = 0; f < fanin(n); f++)\r
+      {\r
+        digraph_arc_iterator<NT,AT, const AT&,const AT*> input_arc = input(n,f);\r
+        digraph_iterator<NT,AT,const NT&,const NT*> predecessor = arc_from(input_arc);\r
+        if (!select || select(*this,input_arc))\r
+          predecessors++;\r
+      }\r
+      if (predecessors == 0)\r
+      {\r
+        result.push_back(n);\r
+      }\r
+      else\r
+      {\r
+        fanin_map[n] = predecessors;\r
+      }\r
+    }\r
+    // main algorithm applies the topographical sort repeatedly. For a DAG, it\r
+    // will complete first time. However, with backward arcs, the first\r
+    // iteration will fail. The algorithm then tries breaking random arcs to try\r
+    // to get an ordering.\r
+    for(unsigned i = 0; !fanin_map.empty(); )\r
+    {\r
+      // now visit each node in traversal order, decrementing the fanin count of\r
+      // all successors. As each successor's fanin count goes to zero, it is\r
+      // appended to the result.\r
+      for (; i < result.size(); i++)\r
+      {\r
+        // Note: dereferencing gives us a node iterator\r
+        digraph_iterator<NT,AT,const NT&,const NT*> current = result[i];\r
+        for (unsigned f = 0; f < fanout(current); f++)\r
+        {\r
+          // only consider successors connected by selected arcs\r
+          digraph_arc_iterator<NT,AT, const AT&,const AT*> output_arc = output(current, f);\r
+          digraph_iterator<NT,AT,const NT&,const NT*> successor = arc_to(output_arc);\r
+          if (!select || select(*this,output_arc))\r
+          {\r
+            // don't consider arcs that have been eliminated to break a loop\r
+            if (fanin_map.find(successor) != fanin_map.end())\r
+            {\r
+              --fanin_map[successor];\r
+              if ((fanin_map[successor]) == 0)\r
+              {\r
+                result.push_back(successor);\r
+                fanin_map.erase(fanin_map.find(successor));\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+      if (!fanin_map.empty())\r
+      {\r
+        // there must be backward arcs preventing completion\r
+        // try removing arcs from the sort to get a partial ordering containing all the nodes\r
+\r
+        // select an arc that is still relevant to the sort and break it\r
+        // first select a node that has non-zero fanin and its predecessor that has non-zero fanin\r
+        digraph_iterator<NT,AT,const NT&,const NT*> stuck_node = fanin_map.begin()->first;\r
+        for (unsigned f = 0; f < fanin(stuck_node); f++)\r
+        {\r
+          // now successively remove input arcs that are still part of the sort until the fanin reduces to zero\r
+          // first find a relevant arc - this must be a selected arc that has not yet been traversed by the first half of the algorithm\r
+          digraph_arc_iterator<NT,AT, const AT&,const AT*> input_arc = input(stuck_node, f);\r
+          if (!select || select(*this,input_arc))\r
+          {\r
+            digraph_iterator<NT,AT,const NT&,const NT*> predecessor = arc_from(input_arc);\r
+            if (fanin_map.find(predecessor) != fanin_map.end())\r
+            {\r
+              // found the right combination - remove this arc and then drop out of the fanin loop to restart the outer sort loop\r
+              errors.push_back(input_arc);\r
+              --fanin_map[stuck_node];\r
+              if ((fanin_map[stuck_node]) == 0)\r
+              {\r
+                result.push_back(stuck_node);\r
+                fanin_map.erase(fanin_map.find(stuck_node));\r
+                break;\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    return std::make_pair(result,errors);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  std::pair<TYPENAME digraph<NT,AT>::node_vector, TYPENAME digraph<NT,AT>::arc_vector>\r
+  digraph<NT,AT>::sort(TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+  {\r
+    std::pair<std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >,\r
+              std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > const_result =\r
+      const_cast<const digraph<NT,AT>*>(this)->sort(select);\r
+\r
+    std::pair<std::vector<digraph_iterator<NT,AT,NT&,NT*> >,\r
+              std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > > result =\r
+      std::make_pair(deconstify_nodes(const_result.first),deconstify_arcs(const_result.second));\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::dag_sort(TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+  {\r
+    std::pair<std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >,\r
+              std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result = sort(select);\r
+    if (result.second.empty()) return result.first;\r
+    return std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >();\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::dag_sort(TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+  {\r
+    return deconstify_nodes(const_cast<const digraph<NT,AT>*>(this)->dag_sort(select));\r
+  }\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Path Algorithms\r
+\r
+  template<typename NT, typename AT>\r
+  bool digraph<NT,AT>::path_exists_r(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                     TYPENAME digraph<NT,AT>::const_iterator to,\r
+                                     TYPENAME digraph<NT,AT>::const_iterator_set& visited,\r
+                                     TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // Recursive part of the digraph::path_exists function. This is based on a\r
+    // depth first search algorithm and stops the moment it finds a path\r
+    // regardless of its length. Simply traverse every output and recurse on that\r
+    // node until we find the to node or run out of things to recurse on. However,\r
+    // to avoid infinite recursion due to cycles in the graph, I need to maintain\r
+    // a set of visited nodes. The visited set is updated when a candidate is\r
+    // found but tested before the recursion on the candidate so that the number of\r
+    // function calls is minimised.\r
+    for (unsigned i = 0; i < fanout(from); i++)\r
+    {\r
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = output(from,i);\r
+      if (!select || select(*this, arc))\r
+      {\r
+        digraph_iterator<NT,AT,const NT&,const NT*> node = arc_to(arc);\r
+        // if the node is the target, return immediately\r
+        if (node == to) return true;\r
+        // update the visited set and give up if the insert fails, which indicates that the node has already been visited\r
+        if (!(visited.insert(node).second)) return false;\r
+        // now recurse - a path exists from from to to if a path exists from an adjacent node to to\r
+        if (path_exists_r(node,to,visited,select)) return true;\r
+      }\r
+    }\r
+    return false;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  bool digraph<NT,AT>::path_exists(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                   TYPENAME digraph<NT,AT>::const_iterator to, \r
+                                   TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // set up the recursion with its initial visited set and then recurse\r
+    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;\r
+    visited.insert(from);\r
+    return path_exists_r(from, to, visited, select);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  bool digraph<NT,AT>::path_exists(TYPENAME digraph<NT,AT>::iterator from,\r
+                                   TYPENAME digraph<NT,AT>::iterator to,\r
+                                   TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return path_exists(from.constify(), to.constify(), select);\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::all_paths_r(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                   TYPENAME digraph<NT,AT>::const_iterator to,\r
+                                   TYPENAME digraph<NT,AT>::const_arc_vector& so_far,\r
+                                   TYPENAME digraph<NT,AT>::const_path_vector& result,\r
+                                   TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // This is the recursive part of the all_paths function. The field so_far\r
+    // contains the path so far so that when 'to' is reached, the path is\r
+    // complete. It serves the same purpose as the visited set in the path_exists\r
+    // function except that it also preserves the path order. It also serves the\r
+    // purpose of detecting cycles and thus stopping infinite recursion. Every\r
+    // time the recursion reaches the to node, a copy of so_far is appended to the\r
+    // path set.\r
+    for (unsigned i = 0; i < fanout(from); i++)\r
+    {\r
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> candidate = output(from,i);\r
+      // assert_valid that the arc is selected and then assert_valid that the candidate has not\r
+      // been visited on this path and only allow further recursion if it hasn't\r
+      if ((!select || select(*this, candidate)) && std::find(so_far.begin(), so_far.end(), candidate) == so_far.end())\r
+      {\r
+        // extend the path tracing the route to this arc\r
+        so_far.push_back(candidate);\r
+        // if the candidate arc points to the target, update the result set and prevent further recursion, otherwise recurse\r
+        if (arc_to(candidate) == to)\r
+          result.push_back(so_far);\r
+        else\r
+          all_paths_r(arc_to(candidate),to,so_far,result,select);\r
+        so_far.pop_back();\r
+      }\r
+    }\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_path_vector \r
+  digraph<NT,AT>::all_paths(TYPENAME digraph<NT,AT>::const_iterator from, \r
+                            TYPENAME digraph<NT,AT>::const_iterator to,\r
+                            TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // set up the recursion with empty data fields and then recurse\r
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;\r
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > so_far;\r
+    all_paths_r(from, to, so_far, result, select);\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::path_vector\r
+  digraph<NT,AT>::all_paths(TYPENAME digraph<NT,AT>::iterator from, \r
+                            TYPENAME digraph<NT,AT>::iterator to,\r
+                            TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_paths(all_paths(from.constify(), to.constify(), select));\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::reachable_nodes_r(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                         TYPENAME digraph<NT,AT>::const_iterator_set& visited,\r
+                                         TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // The recursive part of the reachable_nodes function.\r
+    // This is a depth-first traversal again but this time it carries on to find all the reachable nodes\r
+    // Just keep recursing on all the adjacent nodes of each node, skipping already visited nodes to avoid cycles\r
+    for (unsigned i = 0; i < fanout(from); i++)\r
+    {\r
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = output(from,i);\r
+      if (!select || select(*this,arc))\r
+      {\r
+        digraph_iterator<NT,AT,const NT&,const NT*> candidate = arc_to(arc);\r
+        if (visited.insert(candidate).second)\r
+          reachable_nodes_r(candidate,visited,select);\r
+      }\r
+    }\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_node_vector\r
+  digraph<NT,AT>::reachable_nodes(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                  TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // seed the recursion, marking the starting node as already visited\r
+    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;\r
+    visited.insert(from);\r
+    reachable_nodes_r(from, visited, select);\r
+    // convert the visited set into the required output form\r
+    // exclude the starting node\r
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
+    for (TYPENAME std::set<digraph_iterator<NT,AT,const NT&,const NT*> >::iterator i = visited.begin(); i != visited.end(); i++)\r
+      if (*i != from)\r
+        result.push_back(*i);\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::node_vector\r
+  digraph<NT,AT>::reachable_nodes(TYPENAME digraph<NT,AT>::iterator from,\r
+                                  TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_nodes(reachable_nodes(from.constify(), select));\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  void digraph<NT,AT>::reaching_nodes_r(TYPENAME digraph<NT,AT>::const_iterator to,\r
+                                        TYPENAME digraph<NT,AT>::const_iterator_set& visited,\r
+                                        TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // The recursive part of the reaching_nodes function.\r
+    // Just like the reachable_nodes_r function but it goes backwards\r
+    for (unsigned i = 0; i < fanin(to); i++)\r
+    {\r
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = input(to,i);\r
+      if (!select || select(*this,arc))\r
+      {\r
+        digraph_iterator<NT,AT,const NT&,const NT*> candidate = arc_from(input(to,i));\r
+        if (visited.insert(candidate).second)\r
+          reaching_nodes_r(candidate,visited,select);\r
+      }\r
+    }\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_node_vector\r
+  digraph<NT,AT>::reaching_nodes(TYPENAME digraph<NT,AT>::const_iterator to,\r
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // seed the recursion, marking the starting node as already visited\r
+    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;\r
+    visited.insert(to);\r
+    reaching_nodes_r(to,visited,select);\r
+    // convert the visited set into the required output form\r
+    // exclude the end node\r
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
+    for (TYPENAME std::set<digraph_iterator<NT,AT,const NT&,const NT*> >::iterator i = visited.begin(); i != visited.end(); i++)\r
+      if (*i != to)\r
+        result.push_back(*i);\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::node_vector\r
+  digraph<NT,AT>::reaching_nodes(TYPENAME digraph<NT,AT>::iterator to,\r
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_nodes(reaching_nodes(to.constify(),select));\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Shortest Path Algorithms\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_arc_vector\r
+  digraph<NT,AT>::shortest_path(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                TYPENAME digraph<NT,AT>::const_iterator to,\r
+                                TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > paths = all_paths(from,to,select);\r
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > shortest;\r
+    for (TYPENAME std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > >::iterator i = paths.begin(); i != paths.end(); i++)\r
+      if (shortest.empty() || i->size() < shortest.size())\r
+        shortest = *i;\r
+    return shortest;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::arc_vector\r
+  digraph<NT,AT>::shortest_path(TYPENAME digraph<NT,AT>::iterator from, \r
+                                TYPENAME digraph<NT,AT>::iterator to,\r
+                                TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_arcs(shortest_path(from.constify(),to.constify(),select));\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::const_path_vector\r
+  digraph<NT,AT>::shortest_paths(TYPENAME digraph<NT,AT>::const_iterator from,\r
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    from.assert_valid(this);\r
+    // This is an unweighted shortest path algorithm based on the algorithm from\r
+    // Weiss's book. This is essentially a breadth-first traversal or graph\r
+    // colouring algorithm. It is an iterative algorithm, so no recursion here! It\r
+    // works by creating a node queue initialised with the starting node. It then\r
+    // consumes the queue from front to back. For each node, it finds the\r
+    // successors and appends them to the queue. If a node is already 'known' it\r
+    // is not added - this avoids cycles. Thus the queue insert ordering\r
+    // represents the breadth-first ordering. On the way it creates a map of\r
+    // visited nodes. This is a map not a set because it also stores the arc that\r
+    // nominated this node as a shortest path. The full path can then be recreated\r
+    // from the map by just walking back through the predecessors. The depth (or\r
+    // colour) can be determined by the path length.\r
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;\r
+    // initialise the iteration by creating a queue and adding the start node\r
+    std::deque<digraph_iterator<NT,AT,const NT&,const NT*> > nodes;\r
+    nodes.push_back(from);\r
+    // Create a map to store the set of known nodes mapped to their predecessor\r
+    // arcs. Initialise it with the current node, which has no predecessor. Note\r
+    // that the algorithm uses the feature of digraph iterators that they can be\r
+    // null iterators and that all null iterators are equal.\r
+    typedef std::map<digraph_iterator<NT,AT,const NT&,const NT*>,\r
+                     digraph_arc_iterator<NT,AT,const AT&,const AT*> > known_map;\r
+    known_map known;\r
+    known.insert(std::make_pair(from,digraph_arc_iterator<NT,AT, const AT&,const AT*>()));\r
+    // now the iterative part of the algorithm\r
+    while(!nodes.empty())\r
+    {\r
+      // pop the queue to get the next node to process - unfortunately the STL\r
+      // deque::pop does not return the popped value\r
+      digraph_iterator<NT,AT,const NT&,const NT*> current = nodes.front();\r
+      nodes.pop_front();\r
+      // now visit all the successors\r
+      for (unsigned i = 0; i < fanout(current); i++)\r
+      {\r
+        digraph_arc_iterator<NT,AT, const AT&,const AT*> next_arc = output(current,i);\r
+        // assert_valid whether the successor arc is a selected arc and can be part of a path\r
+        if (!select || select(*this,next_arc))\r
+        {\r
+          digraph_iterator<NT,AT,const NT&,const NT*> next = arc_to(next_arc);\r
+          // Discard any successors that are known because to be known already they\r
+          // must have another shorter path. Otherwise add the successor node to the\r
+          // queue to be visited later. To minimise the overhead of map lookup I use\r
+          // the usual trick of trying to insert the node and determining whether\r
+          // the node was known by the success or failure of the insertion - this is\r
+          // a Good STL Trick (TM).\r
+          if (known.insert(std::make_pair(next,next_arc)).second)\r
+            nodes.push_back(next);\r
+        }\r
+      }\r
+    }\r
+    // The map contains the results as an unordered set of nodes, mapped to their\r
+    // predecessor arcs and weight. This now needs to be converted into a set of\r
+    // paths. This is done by starting with a node from the map, finding its\r
+    // predecessor arc and therefore its predecessor node, looking that up in the\r
+    // map to find its predecessor and so on until the start node is reached (it\r
+    // has a null predecessor). Note that the known set includes the from node\r
+    // which does not generate a path.\r
+    for (TYPENAME known_map::iterator i = known.begin(); i != known.end(); i++)\r
+    {\r
+      if (i->first != from)\r
+      {\r
+        const_arc_vector this_path;\r
+        for (TYPENAME known_map::iterator node = i; \r
+             node->second.valid(); \r
+             node = known.find(arc_from(node->second)))\r
+          this_path.insert(this_path.begin(),node->second);\r
+        result.push_back(this_path);\r
+      }\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename NT, typename AT>\r
+  TYPENAME digraph<NT,AT>::path_vector\r
+  digraph<NT,AT>::shortest_paths(TYPENAME digraph<NT,AT>::iterator from,\r
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return deconstify_paths(shortest_paths(from.constify(),select));\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
diff --git a/src/Moof/stlplus/exceptions.hpp b/src/Moof/stlplus/exceptions.hpp
new file mode 100755 (executable)
index 0000000..3549ff4
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef STLPLUS_EXCEPTIONS\r
+#define STLPLUS_EXCEPTIONS\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author: Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   The set of general exceptions thrown by STLplus components\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+#include <stdexcept>\r
+#include <string>\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Thrown if a pointer or an iterator is dereferenced when it is null\r
+\r
+  class null_dereference : public std::logic_error\r
+  {\r
+  public:\r
+    null_dereference(const std::string& description) throw() :\r
+      std::logic_error(std::string("stlplus::null_dereference: ") + description) {}\r
+    ~null_dereference(void) throw() {}\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Thrown if an iterator is dereferenced when it is pointing to the end element\r
+\r
+  class end_dereference : public std::logic_error\r
+  {\r
+  public:\r
+    end_dereference(const std::string& description) throw() :\r
+      std::logic_error("stlplus::end_dereference: " + description) {}\r
+    ~end_dereference(void) throw() {}\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Thrown if an iterator is used with the wrong container. In other words, an\r
+  // iterator is created as a pointer to a sub-object within a container. If\r
+  // that iterator is then used with a different container, this exception is\r
+  // thrown.\r
+\r
+  class wrong_object : public std::logic_error\r
+  {\r
+  public:\r
+    wrong_object(const std::string& description) throw() :\r
+      std::logic_error("stlplus::wrong_object: " + description) {}\r
+    ~wrong_object(void) throw() {}\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Thrown if an attempt is made to copy an object that is uncopyable\r
+\r
+  class illegal_copy : public std::logic_error\r
+  {\r
+  public:\r
+    illegal_copy(const std::string& description) throw() :\r
+      std::logic_error("stlplus::illegal_copy: " + description) {}\r
+    ~illegal_copy(void) throw() {}\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#endif\r
diff --git a/src/Moof/stlplus/foursome.hpp b/src/Moof/stlplus/foursome.hpp
new file mode 100755 (executable)
index 0000000..36437f1
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef STLPLUS_FOURSOME\r
+#define STLPLUS_FOURSOME\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton, from an original by Dan Milton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   The next in the series pair->triple->foursome\r
+\r
+//   Originally called quadruple but that clashed (as did quad) with system\r
+//   libraries on some operating systems\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // the foursome class\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  struct foursome\r
+  {\r
+    typedef T1 first_type;\r
+    typedef T2 second_type;\r
+    typedef T3 third_type;\r
+    typedef T4 fourth_type;\r
+\r
+    T1 first;\r
+    T2 second;\r
+    T3 third;\r
+    T4 fourth;\r
+\r
+    foursome(void);\r
+    foursome(const T1& p1, const T2& p2, const T3& p3, const T4& p4);\r
+    foursome(const foursome<T1,T2,T3,T4>& t2);\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // creation\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  foursome<T1,T2,T3,T4> make_foursome(const T1& first, const T2& second, const T3& third, const T4& fourth);\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // comparison\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  bool operator == (const foursome<T1,T2,T3,T4>& left, const foursome<T1,T2,T3,T4>& right);\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#include "foursome.tpp"\r
+#endif\r
diff --git a/src/Moof/stlplus/foursome.tpp b/src/Moof/stlplus/foursome.tpp
new file mode 100755 (executable)
index 0000000..f1dd9b3
--- /dev/null
@@ -0,0 +1,59 @@
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton, from an original by Dan Milton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // the foursome class\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  foursome<T1,T2,T3,T4>::foursome(void) :\r
+    first(), second(), third(), fourth()\r
+  {\r
+  }\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  foursome<T1,T2,T3,T4>::foursome(const T1& p1, const T2& p2, const T3& p3, const T4& p4) :\r
+    first(p1), second(p2), third(p3), fourth(p4)\r
+  {\r
+  }\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  foursome<T1,T2,T3,T4>::foursome(const foursome<T1,T2,T3,T4>& t2) :\r
+    first(t2.first), second(t2.second), third(t2.third), fourth(t2.fourth)\r
+  {\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // creation\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  foursome<T1,T2,T3,T4> make_foursome(const T1& first, const T2& second, const T3& third, const T4& fourth)\r
+  {\r
+    return foursome<T1,T2,T3,T4>(first,second,third,fourth);\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // comparison\r
+\r
+  template<typename T1, typename T2, typename T3, typename T4>\r
+  bool operator == (const foursome<T1,T2,T3,T4>& left, const foursome<T1,T2,T3,T4>& right)\r
+  {\r
+    // foursomes are equal if all elements are equal\r
+    return \r
+      left.first == right.first && \r
+      left.second == right.second && \r
+      left.third == right.third &&\r
+      left.fourth == right.fourth;\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
diff --git a/src/Moof/stlplus/hash.hpp b/src/Moof/stlplus/hash.hpp
new file mode 100755 (executable)
index 0000000..05d3b7d
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef STLPLUS_HASH\r
+#define STLPLUS_HASH\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   A chained hash table using STL semantics\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+#include "exceptions.hpp"\r
+#include "safe_iterator.hpp"\r
+#include <map>\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // internals\r
+\r
+  template<typename K, typename T, class H, class E> class hash;\r
+  template<typename K, typename T, class H, class E> class hash_element;\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // iterator class\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  class hash_iterator : public safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >\r
+  {\r
+  public:\r
+    friend class hash<K,T,H,E>;\r
+\r
+    // local type definitions\r
+    // an iterator points to a value whilst a const_iterator points to a const value\r
+    typedef V                                                  value_type;\r
+    typedef hash_iterator<K,T,H,E,std::pair<const K,T> >       iterator;\r
+    typedef hash_iterator<K,T,H,E,const std::pair<const K,T> > const_iterator;\r
+    typedef hash_iterator<K,T,H,E,V>                           this_iterator;\r
+    typedef V&                                                 reference;\r
+    typedef V*                                                 pointer;\r
+\r
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
+    // any attempt to dereference or use a null iterator is an error\r
+    // the only valid thing you can do is assign an iterator to it\r
+    hash_iterator(void);\r
+    ~hash_iterator(void);\r
+\r
+    // Type conversion methods allow const_iterator and iterator to be converted\r
+    // convert an iterator/const_iterator to a const_iterator\r
+    const_iterator constify(void) const;\r
+    // convert an iterator/const_iterator to an iterator\r
+    iterator deconstify(void) const;\r
+\r
+    // increment operators used to step through the set of all values in a hash\r
+    // it is only legal to increment a valid iterator\r
+    // there's no decrement - I've only implemented this as a unidirectional iterator\r
+    // pre-increment\r
+    this_iterator& operator ++ (void)\r
+      throw(null_dereference,end_dereference);\r
+    // post-increment\r
+    this_iterator operator ++ (int)\r
+      throw(null_dereference,end_dereference);\r
+\r
+    // test useful for testing whether iteration has completed\r
+    bool operator == (const this_iterator& r) const;\r
+    bool operator != (const this_iterator& r) const;\r
+    bool operator < (const this_iterator& r) const;\r
+\r
+    // access the value - a const_iterator gives you a const value, an iterator a non-const value\r
+    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
+    reference operator*(void) const\r
+      throw(null_dereference,end_dereference);\r
+    pointer operator->(void) const\r
+      throw(null_dereference,end_dereference);\r
+\r
+  private:\r
+    friend class hash_element<K,T,H,E>;\r
+\r
+    // constructor used by hash to create a non-null iterator\r
+    // you cannot create a valid iterator except by calling a hash method that returns one\r
+    explicit hash_iterator(hash_element<K,T,H,E>* element);\r
+    // constructor used to create an end iterator\r
+    explicit hash_iterator(const hash<K,T,H,E>* owner);\r
+    // used to create an alias of an iterator\r
+    explicit hash_iterator(const safe_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> >& iterator);\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Hash class\r
+  // K = key type\r
+  // T = value type\r
+  // H = hash function object with the profile 'unsigned H(const K&)'\r
+  // E = equal function object with profile 'bool E(const K&, const K&)' defaults to equal_to which in turn calls '=='\r
+\r
+  template<typename K, typename T, class H, class E = std::equal_to<K> >\r
+  class hash\r
+  {\r
+  public:\r
+    typedef unsigned                                size_type;\r
+    typedef K                                       key_type;\r
+    typedef T                                       data_type;\r
+    typedef T                                       mapped_type;\r
+    typedef std::pair<const K, T>                   value_type;\r
+    typedef hash_iterator<K,T,H,E,value_type>       iterator;\r
+    typedef hash_iterator<K,T,H,E,const value_type> const_iterator;\r
+\r
+    // construct a hash table with specified number of bins\r
+    // the default 0 bins means leave it to the table to decide\r
+    // specifying 0 bins also enables auto-rehashing, otherwise auto-rehashing defaults off\r
+    hash(unsigned bins = 0);\r
+    ~hash(void);\r
+\r
+    // copy and equality copy the data elements but not the size of the copied table\r
+    hash(const hash&);\r
+    hash& operator = (const hash&);\r
+\r
+    // test for an empty table and for the size of a table\r
+    // efficient because the size is stored separately from the table contents\r
+    bool empty(void) const;\r
+    unsigned size(void) const;\r
+\r
+    // test for equality - two hashes are equal if they contain equal values\r
+    bool operator == (const hash&) const;\r
+    bool operator != (const hash&) const;\r
+\r
+    // switch auto-rehash on\r
+    void auto_rehash(void);\r
+    // switch auto-rehash off\r
+    void manual_rehash(void);\r
+    // force a rehash now\r
+    // default of 0 means implement built-in size calculation for rehashing (recommended - it doubles the number of bins)\r
+    void rehash(unsigned bins = 0);\r
+    // test the loading ratio, which is the size divided by the number of bins\r
+    // use this if you are doing your own rehashing\r
+    // the recommendation is to double the bins when the loading exceeds 0.5 which is what auto-rehashing does\r
+    float loading(void) const;\r
+\r
+    // test for the presence of a key\r
+    bool present(const K& key) const;\r
+    // provide map equivalent key count function (0 or 1, as not a multimap)\r
+    size_type count(const K& key) const;\r
+\r
+    // insert a new key/data pair - replaces any previous value for this key\r
+    iterator insert(const K& key, const T& data);\r
+    // insert a copy of the pair into the table (std::map compatible)\r
+    std::pair<iterator, bool> insert(const value_type& value);\r
+    // insert a new key and return the iterator so that the data can be filled in\r
+    iterator insert(const K& key);\r
+\r
+    // remove a key/data pair from the hash table\r
+    bool erase(const K& key);\r
+    // remove all elements from the hash table\r
+    void erase(void);\r
+    // provide the std::map equivalent clear function\r
+    void clear(void);\r
+\r
+    // find a key and return an iterator to it\r
+    // The iterator is like a pointer to a pair<const K,T>\r
+    // end() is returned if the find fails\r
+    const_iterator find(const K& key) const;\r
+    iterator find(const K& key);\r
+\r
+    // returns the data corresponding to the key\r
+    // const version is used for const hashes and cannot change the hash, so failure causes an exception\r
+    // non-const version is for non-const hashes and is like map - it creates a new key/data pair if find fails\r
+    const T& operator[] (const K& key) const throw(std::out_of_range);\r
+    T& operator[] (const K& key);\r
+\r
+    // iterators allow the hash table to be traversed\r
+    // iterators remain valid unless an item is removed or unless a rehash happens\r
+    const_iterator begin(void) const;\r
+    iterator begin(void);\r
+    const_iterator end(void) const;\r
+    iterator end(void);\r
+\r
+    // internals\r
+  private:\r
+    friend class hash_element<K,T,H,E>;\r
+    friend class hash_iterator<K,T,H,E,std::pair<const K,T> >;\r
+    friend class hash_iterator<K,T,H,E,const std::pair<const K,T> >;\r
+\r
+    unsigned m_rehash;\r
+    unsigned m_bins;\r
+    unsigned m_size;\r
+    hash_element<K,T,H,E>** m_values;\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#include "hash.tpp"\r
+#endif\r
diff --git a/src/Moof/stlplus/hash.tpp b/src/Moof/stlplus/hash.tpp
new file mode 100755 (executable)
index 0000000..bcb5bc5
--- /dev/null
@@ -0,0 +1,575 @@
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // the element stored in the hash\r
+\r
+  template<typename K, typename T, typename H, typename E>\r
+  class hash_element\r
+  {\r
+  public:\r
+    master_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> > m_master;\r
+    std::pair<const K, T> m_value;\r
+    hash_element<K,T,H,E>* m_next;\r
+    unsigned m_hash;\r
+\r
+    hash_element(const hash<K,T,H,E>* owner, const K& key, const T& data, unsigned hash) : \r
+      m_master(owner,this), m_value(key,data), m_next(0), m_hash(hash) \r
+      {\r
+      }\r
+\r
+    hash_element(const hash<K,T,H,E>* owner, const std::pair<const K,T>& value, unsigned hash) : \r
+      m_master(owner,this), m_value(value), m_next(0), m_hash(hash) \r
+      {\r
+      }\r
+\r
+    ~hash_element(void)\r
+      {\r
+        m_next = 0;\r
+        m_hash = 0;\r
+      }\r
+\r
+    const hash<K,T,H,E>* owner(void) const\r
+      {\r
+        return m_master.owner();\r
+      }\r
+\r
+    // generate the bin number from the hash value and the owner's number of bins\r
+    unsigned bin(void) const\r
+      {\r
+        return m_hash % (owner()->m_bins);\r
+      }\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // iterator\r
+\r
+  // null constructor\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  hash_iterator<K,T,H,E,V>::hash_iterator(void)\r
+  {\r
+  }\r
+\r
+  // non-null constructor used from within the hash to construct a valid iterator\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  hash_iterator<K,T,H,E,V>::hash_iterator(hash_element<K,T,H,E>* element) :\r
+    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(element->m_master)\r
+  {\r
+  }\r
+\r
+  // constructor used to create an end iterator\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  hash_iterator<K,T,H,E,V>::hash_iterator(const hash<K,T,H,E>* owner) :\r
+    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(owner)\r
+  {\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  hash_iterator<K,T,H,E,V>::hash_iterator(const safe_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> >& iterator) :\r
+    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(iterator)\r
+  {\r
+  }\r
+\r
+  // destructor\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  hash_iterator<K,T,H,E,V>::~hash_iterator(void)\r
+  {\r
+  }\r
+\r
+  // mode conversions\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  TYPENAME hash_iterator<K,T,H,E,V>::const_iterator hash_iterator<K,T,H,E,V>::constify(void) const\r
+  {\r
+    return hash_iterator<K,T,H,E,const std::pair<const K,T> >(*this);\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  TYPENAME hash_iterator<K,T,H,E,V>::iterator hash_iterator<K,T,H,E,V>::deconstify(void) const\r
+  {\r
+    return hash_iterator<K,T,H,E,std::pair<const K,T> >(*this);\r
+  }\r
+\r
+  // increment operator looks for the next element in the table\r
+  // if there isn't one, then this becomes an end() iterator with m_bin = m_bins\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  TYPENAME hash_iterator<K,T,H,E,V>::this_iterator& hash_iterator<K,T,H,E,V>::operator ++ (void)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    if (this->node()->m_next)\r
+      set(this->node()->m_next->m_master);\r
+    else\r
+    {\r
+      // failing that, subsequent hash values are tried until either an element is found or there are no more bins\r
+      // in which case it becomes an end() iterator\r
+      hash_element<K,T,H,E>* element = 0;\r
+      unsigned current_bin = this->node()->bin();\r
+      for(current_bin++; !element && (current_bin < this->owner()->m_bins); current_bin++)\r
+        element = this->owner()->m_values[current_bin];\r
+      if (element)\r
+        set(element->m_master);\r
+      else\r
+        this->set_end();\r
+    }\r
+    return *this;\r
+  }\r
+\r
+  // post-increment is defined in terms of pre-increment\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  TYPENAME hash_iterator<K,T,H,E,V>::this_iterator hash_iterator<K,T,H,E,V>::operator ++ (int)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    hash_iterator<K,T,H,E,V> old(*this);\r
+    ++(*this);\r
+    return old;\r
+  }\r
+\r
+  // two iterators are equal if they point to the same element\r
+  // both iterators must be non-null and belong to the same table\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  bool hash_iterator<K,T,H,E,V>::operator == (const hash_iterator<K,T,H,E,V>& r) const\r
+  {\r
+    return equal(r);\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  bool hash_iterator<K,T,H,E,V>::operator != (const hash_iterator<K,T,H,E,V>& r) const\r
+  {\r
+    return !operator==(r);\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  bool hash_iterator<K,T,H,E,V>::operator < (const hash_iterator<K,T,H,E,V>& r) const\r
+  {\r
+    return compare(r) < 0;\r
+  }\r
+\r
+  // iterator dereferencing is only legal on a non-null iterator\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  V& hash_iterator<K,T,H,E,V>::operator*(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    return this->node()->m_value;\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E, typename V>\r
+  V* hash_iterator<K,T,H,E,V>::operator->(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return &(operator*());\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // hash\r
+\r
+  // totally arbitrary initial size used for auto-rehashed tables\r
+  static unsigned hash_default_bins = 127;\r
+\r
+  // constructor\r
+  // tests whether the user wants auto-rehash\r
+  // sets the rehash point to be a loading of 1.0 by setting it to the number of bins\r
+  // uses the user's size unless this is zero, in which case implement the default\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  hash<K,T,H,E>::hash(unsigned bins) :\r
+    m_rehash(bins), m_bins(bins > 0 ? bins : hash_default_bins), m_size(0), m_values(0)\r
+  {\r
+    m_values = new hash_element<K,T,H,E>*[m_bins];\r
+    for (unsigned i = 0; i < m_bins; i++)\r
+      m_values[i] = 0;\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  hash<K,T,H,E>::~hash(void)\r
+  {\r
+    // delete all the elements\r
+    clear();\r
+    // and delete the data structure\r
+    delete[] m_values;\r
+    m_values = 0;\r
+  }\r
+\r
+  // as usual, implement the copy constructor i.t.o. the assignment operator\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  hash<K,T,H,E>::hash(const hash<K,T,H,E>& right) :\r
+    m_rehash(right.m_rehash), m_bins(right.m_bins), m_size(0), m_values(0)\r
+  {\r
+    m_values = new hash_element<K,T,H,E>*[right.m_bins];\r
+    // copy the rehash behaviour as well as the size\r
+    for (unsigned i = 0; i < m_bins; i++)\r
+      m_values[i] = 0;\r
+    *this = right;\r
+  }\r
+\r
+  // assignment operator\r
+  // this is done by copying the elements\r
+  // the source and target hashes can be different sizes\r
+  // the hash is self-copy safe, i.e. it is legal to say x = x;\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  hash<K,T,H,E>& hash<K,T,H,E>::operator = (const hash<K,T,H,E>& r)\r
+  {\r
+    // make self-copy safe\r
+    if (&r == this) return *this;\r
+    // remove all the existing elements\r
+    clear();\r
+    // copy the elements across - remember that this is rehashing because the two\r
+    // tables can be different sizes so there is no quick way of doing this by\r
+    // copying the lists\r
+    for (hash_iterator<K,T,H,E,const std::pair<const K,T> > i = r.begin(); i != r.end(); ++i)\r
+      insert(i->first, i->second);\r
+    return *this;\r
+  }\r
+\r
+  // number of values in the hash\r
+  template<typename K, typename T, class H, class E>\r
+  bool hash<K,T,H,E>::empty(void) const\r
+  {\r
+    return m_size == 0;\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  unsigned hash<K,T,H,E>::size(void) const\r
+  {\r
+    return m_size;\r
+  }\r
+\r
+  // equality\r
+  template<typename K, typename T, class H, class E>\r
+  bool hash<K,T,H,E>::operator == (const hash<K,T,H,E>& right) const\r
+  {\r
+    // this table is the same as the right table if they are the same table!\r
+    if (&right == this) return true;\r
+    // they must be the same size to be equal\r
+    if (m_size != right.m_size) return false;\r
+    // now every key in this must be in right and have the same data\r
+    for (hash_iterator<K,T,H,E,const std::pair<const K,T> > i = begin(); i != end(); i++)\r
+    {\r
+      hash_iterator<K,T,H,E,const std::pair<const K,T> > found = right.find(i->first);\r
+      if (found == right.end()) return false;\r
+      if (!(i->second == found->second)) return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  // set up the hash to auto-rehash at a specific size\r
+  // setting the rehash size to 0 forces manual rehashing\r
+  template<typename K, typename T, class H, class E>\r
+  void hash<K,T,H,E>::auto_rehash(void)\r
+  {\r
+    m_rehash = m_bins;\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  void hash<K,T,H,E>::manual_rehash(void)\r
+  {\r
+    m_rehash = 0;\r
+  }\r
+\r
+  // the rehash function\r
+  // builds a new hash table and moves the elements (without copying) from the old to the new\r
+  // I store the un-modulused hash value in the element for more efficient rehashing\r
+  // passing 0 to the bins parameter does auto-rehashing\r
+  // passing any other value forces the number of bins\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  void hash<K,T,H,E>::rehash(unsigned bins)\r
+  {\r
+    // user specified size: just take the user's value\r
+    // auto calculate: if the load is high, increase the size; else do nothing\r
+    unsigned new_bins = bins ? bins : m_bins;\r
+    if (bins == 0 && m_size > 0)\r
+    {\r
+      // these numbers are pretty arbitrary\r
+      // TODO - make them user-customisable?\r
+      float load = loading();\r
+      if (load > 2.0)\r
+        new_bins = (unsigned)(m_bins * load);\r
+      else if (load > 1.0)\r
+        new_bins = m_bins * 2;\r
+    }\r
+    if (new_bins == m_bins) return;\r
+    // set the new rehashing point if auto-rehashing is on\r
+    if (m_rehash) m_rehash = new_bins;\r
+    // move aside the old structure\r
+    hash_element<K,T,H,E>** old_values = m_values;\r
+    unsigned old_bins = m_bins;\r
+    // create a replacement structure\r
+    m_values = new hash_element<K,T,H,E>*[new_bins];\r
+    for (unsigned i = 0; i < new_bins; i++)\r
+      m_values[i] = 0;\r
+    m_bins = new_bins;\r
+    // move all the old elements across, rehashing each one\r
+    for (unsigned j = 0; j < old_bins; j++)\r
+    {\r
+      while(old_values[j])\r
+      {\r
+        // unhook from the old structure\r
+        hash_element<K,T,H,E>* current = old_values[j];\r
+        old_values[j] = current->m_next;\r
+        // rehash using the stored hash value\r
+        unsigned bin = current->bin();\r
+        // hook it into the new structure\r
+        current->m_next = m_values[bin];\r
+        m_values[bin] = current;\r
+      }\r
+    }\r
+    // now delete the old structure\r
+    delete[] old_values;\r
+  }\r
+\r
+  // the loading is the average number of elements per bin\r
+  // this simplifies to the total elements divided by the number of bins\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  float hash<K,T,H,E>::loading(void) const\r
+  {\r
+    return (float)m_size / (float)m_bins;\r
+  }\r
+\r
+  // remove all elements from the table\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  void hash<K,T,H,E>::erase(void)\r
+  {\r
+    // unhook the list elements and destroy them\r
+    for (unsigned i = 0; i < m_bins; i++)\r
+    {\r
+      hash_element<K,T,H,E>* current = m_values[i];\r
+      while(current)\r
+      {\r
+        hash_element<K,T,H,E>* next = current->m_next;\r
+        delete current;\r
+        current = next;\r
+      }\r
+      m_values[i] = 0;\r
+    }\r
+    m_size = 0;\r
+  }\r
+\r
+  // test for whether a key is present in the table\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  bool hash<K,T,H,E>::present(const K& key) const\r
+  {\r
+    return find(key) != end();\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::size_type hash<K,T,H,E>::count(const K& key) const\r
+  {\r
+    return present() ? 1 : 0;\r
+  }\r
+\r
+  // add a key and data element to the table - defined in terms of the general-purpose pair insert function\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::insert(const K& key, const T& data)\r
+  {\r
+    return insert(std::pair<const K,T>(key,data)).first;\r
+  }\r
+\r
+  // insert a key/data pair into the table\r
+  // this removes any old value with the same key since there is no multihash functionality\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  std::pair<TYPENAME hash<K,T,H,E>::iterator, bool> hash<K,T,H,E>::insert(const std::pair<const K,T>& value)\r
+  {\r
+    // if auto-rehash is enabled, implement the auto-rehash before inserting the new value\r
+    // the table is rehashed if this insertion makes the loading exceed 1.0\r
+    if (m_rehash && (m_size >= m_rehash)) rehash();\r
+    // calculate the new hash value\r
+    unsigned hash_value_full = H()(value.first);\r
+    unsigned bin = hash_value_full % m_bins;\r
+    bool inserted = true;\r
+    // unhook any previous value with this key\r
+    // this has been inlined from erase(key) so that the hash value is not calculated twice\r
+    hash_element<K,T,H,E>* previous = 0;\r
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)\r
+    {\r
+      // first check the full stored hash value\r
+      if (current->m_hash != hash_value_full) continue;\r
+\r
+      // next try the equality operator\r
+      if (!E()(current->m_value.first, value.first)) continue;\r
+\r
+      // unhook this value and destroy it\r
+      if (previous)\r
+        previous->m_next = current->m_next;\r
+      else\r
+        m_values[bin] = current->m_next;\r
+      delete current;\r
+      m_size--;\r
+\r
+      // we've overwritten a previous value\r
+      inserted = false;\r
+\r
+      // assume there can only be one match so we can give up now\r
+      break;\r
+    }\r
+    // now hook in a new list element at the start of the list for this hash value\r
+    hash_element<K,T,H,E>* new_item = new hash_element<K,T,H,E>(this, value, hash_value_full);\r
+    new_item->m_next = m_values[bin];\r
+    m_values[bin] = new_item;\r
+    // increment the size count\r
+    m_size++;\r
+    // construct an iterator from the list node, and return whether inserted\r
+    return std::make_pair(hash_iterator<K,T,H,E,std::pair<const K,T> >(new_item), inserted);\r
+  }\r
+\r
+  // insert a key with an empty data field ready to be filled in later\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::insert(const K& key)\r
+  {\r
+    return insert(key,T());\r
+  }\r
+\r
+  // remove a key from the table - return true if the key was found and removed, false if it wasn't present\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  bool hash<K,T,H,E>::erase(const K& key)\r
+  {\r
+    unsigned hash_value_full = H()(key);\r
+    unsigned bin = hash_value_full % m_bins;\r
+    // scan the list for an element with this key\r
+    // need to keep a previous pointer because the lists are single-linked\r
+    hash_element<K,T,H,E>* previous = 0;\r
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)\r
+    {\r
+      // first check the full stored hash value\r
+      if (current->m_hash != hash_value_full) continue;\r
+\r
+      // next try the equality operator\r
+      if (!E()(current->m_value.first, key)) continue;\r
+\r
+      // found this key, so unhook the element from the list\r
+      if (previous)\r
+        previous->m_next = current->m_next;\r
+      else\r
+        m_values[bin] = current->m_next;\r
+      // destroy it\r
+      delete current;\r
+      // remember to maintain the size count\r
+      m_size--;\r
+      return true;\r
+    }\r
+    return false;\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  void hash<K,T,H,E>::clear(void)\r
+  {\r
+    erase();\r
+  }\r
+\r
+  // search for a key in the table and return an iterator to it\r
+  // if the search fails, returns an end() iterator\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::find(const K& key) const\r
+  {\r
+    // scan the list for this key's hash value for the element with a matching key\r
+    unsigned hash_value_full = H()(key);\r
+    unsigned bin = hash_value_full % m_bins;\r
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; current = current->m_next)\r
+    {\r
+      if (current->m_hash == hash_value_full && E()(current->m_value.first, key))\r
+        return hash_iterator<K,T,H,E,const std::pair<const K,T> >(current);\r
+    }\r
+    return end();\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::find(const K& key)\r
+  {\r
+    // scan the list for this key's hash value for the element with a matching key\r
+    unsigned hash_value_full = H()(key);\r
+    unsigned bin = hash_value_full % m_bins;\r
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; current = current->m_next)\r
+    {\r
+      if (current->m_hash == hash_value_full && E()(current->m_value.first, key))\r
+        return hash_iterator<K,T,H,E,std::pair<const K,T> >(current);\r
+    }\r
+    return end();\r
+  }\r
+\r
+  // table lookup by key using the index operator[], returning a reference to the data field, not an iterator\r
+  // this is rather like the std::map's [] operator\r
+  // the difference is that I have a const and non-const version\r
+  // the const version will not create the element if not present already, but the non-const version will\r
+  // the non-const version is compatible with the behaviour of the map\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  const T& hash<K,T,H,E>::operator[] (const K& key) const throw(std::out_of_range)\r
+  {\r
+    // this const version cannot change the hash, so has to raise an exception if the key is missing\r
+    hash_iterator<K,T,H,E,const std::pair<const K,T> > found = find(key);\r
+    if (found == end())\r
+      throw std::out_of_range("key not found in stlplus::hash::operator[]");\r
+    return found->second;\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  T& hash<K,T,H,E>::operator[] (const K& key)\r
+  {\r
+    // this non-const version can change the hash, so creates a new element if the key is missing\r
+    hash_iterator<K,T,H,E,std::pair<const K,T> > found = find(key);\r
+    if (found == end())\r
+      found = insert(key);\r
+    return found->second;\r
+  }\r
+\r
+  // iterators\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::begin(void) const\r
+  {\r
+    // find the first element\r
+    for (unsigned bin = 0; bin < m_bins; bin++)\r
+      if (m_values[bin])\r
+        return hash_iterator<K,T,H,E,const std::pair<const K,T> >(m_values[bin]);\r
+    // if the hash is empty, return the end iterator\r
+    return end();\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::begin(void)\r
+  {\r
+    // find the first element\r
+    for (unsigned bin = 0; bin < m_bins; bin++)\r
+      if (m_values[bin])\r
+        return hash_iterator<K,T,H,E,std::pair<const K,T> >(m_values[bin]);\r
+    // if the hash is empty, return the end iterator\r
+    return end();\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::end(void) const\r
+  {\r
+    return hash_iterator<K,T,H,E,const std::pair<const K,T> >(this);\r
+  }\r
+\r
+  template<typename K, typename T, class H, class E>\r
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::end(void)\r
+  {\r
+    return hash_iterator<K,T,H,E,std::pair<const K,T> >(this);\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
diff --git a/src/Moof/stlplus/matrix.hpp b/src/Moof/stlplus/matrix.hpp
new file mode 100755 (executable)
index 0000000..fd0a512
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef STLPLUS_MATRIX\r
+#define STLPLUS_MATRIX\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   General-purpose 2D matrix data structure \r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename T> class matrix\r
+  {\r
+  public:\r
+    matrix(unsigned rows = 0, unsigned cols = 0, const T& fill = T()) throw();\r
+    ~matrix(void) throw();\r
+\r
+    matrix(const matrix&) throw();\r
+    matrix& operator =(const matrix&) throw();\r
+\r
+    void resize(unsigned rows, unsigned cols, const T& fill = T()) throw();\r
+\r
+    unsigned rows(void) const throw();\r
+    unsigned columns(void) const throw();\r
+\r
+    void erase(const T& fill = T()) throw();\r
+    void erase(unsigned row, unsigned col, const T& fill = T()) throw(std::out_of_range);\r
+    void insert(unsigned row, unsigned col, const T&) throw(std::out_of_range);\r
+    const T& item(unsigned row, unsigned col) const throw(std::out_of_range);\r
+    T& item(unsigned row, unsigned col) throw(std::out_of_range);\r
+    const T& operator()(unsigned row, unsigned col) const throw(std::out_of_range);\r
+    T& operator()(unsigned row, unsigned col) throw(std::out_of_range);\r
+\r
+    void fill(const T& item = T()) throw();\r
+    void fill_column(unsigned col, const T& item = T()) throw(std::out_of_range);\r
+    void fill_row(unsigned row, const T& item = T()) throw(std::out_of_range);\r
+    void fill_leading_diagonal(const T& item = T()) throw();\r
+    void fill_trailing_diagonal(const T& item = T()) throw();\r
+    void make_identity(const T& one, const T& zero = T()) throw();\r
+\r
+    void transpose(void) throw();\r
+\r
+  private:\r
+    unsigned m_rows;\r
+    unsigned m_cols;\r
+    T** m_data;\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#include "matrix.tpp"\r
+#endif\r
diff --git a/src/Moof/stlplus/matrix.tpp b/src/Moof/stlplus/matrix.tpp
new file mode 100755 (executable)
index 0000000..65ec779
--- /dev/null
@@ -0,0 +1,215 @@
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename T>\r
+  matrix<T>::matrix(unsigned rows, unsigned cols, const T& fill) throw()\r
+  {\r
+    m_rows = 0;\r
+    m_cols = 0;\r
+    m_data = 0;\r
+    resize(rows,cols,fill);\r
+  }\r
+\r
+  template<typename T>\r
+  matrix<T>::~matrix(void) throw()\r
+  {\r
+    for (unsigned row = 0; row < m_rows; row++)\r
+      delete[] m_data[row];\r
+    delete[] m_data;\r
+  }\r
+\r
+  template<typename T>\r
+  matrix<T>::matrix(const matrix<T>& r) throw()\r
+  {\r
+    m_rows = 0;\r
+    m_cols = 0;\r
+    m_data = 0;\r
+    *this = r;\r
+  }\r
+\r
+  template<typename T>\r
+  matrix<T>& matrix<T>::operator =(const matrix<T>& right) throw()\r
+  {\r
+    // clear the old values\r
+    for (unsigned row = 0; row < m_rows; row++)\r
+      delete[] m_data[row];\r
+    delete[] m_data;\r
+    m_rows = 0;\r
+    m_cols = 0;\r
+    m_data = 0;\r
+    // now reconstruct with the new\r
+    resize(right.m_rows, right.m_cols);\r
+    for (unsigned row = 0; row < m_rows; row++)\r
+      for (unsigned col = 0; col < m_cols; col++)\r
+        m_data[row][col] = right.m_data[row][col];\r
+    return *this;\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::resize(unsigned rows, unsigned cols, const T& fill) throw()\r
+  {\r
+    // a grid is an array of rows, where each row is an array of T\r
+    // a zero-row or zero-column matrix has a null grid\r
+    // TODO - make this exception-safe - new could throw here and that would cause a memory leak\r
+    T** new_grid = 0;\r
+    if (rows && cols)\r
+    {\r
+      new_grid = new T*[rows];\r
+      for (unsigned row = 0; row < rows; row++)\r
+      {\r
+        new_grid[row] = new T[cols];\r
+        // copy old items to the new grid but only within the bounds of the intersection of the old and new grids\r
+        // fill the rest of the grid with the initial value\r
+        for (unsigned col = 0; col < cols; col++)\r
+          if (row < m_rows && col < m_cols)\r
+            new_grid[row][col] = m_data[row][col];\r
+          else\r
+            new_grid[row][col] = fill;\r
+      }\r
+    }\r
+    // destroy the old grid\r
+    for (unsigned row = 0; row < m_rows; row++)\r
+      delete[] m_data[row];\r
+    delete[] m_data;\r
+    // move the new data into the matrix\r
+    m_data = new_grid;\r
+    m_rows = rows;\r
+    m_cols = cols;\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned matrix<T>::rows(void) const throw()\r
+  {\r
+    return m_rows;\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned matrix<T>::columns(void) const throw()\r
+  {\r
+    return m_cols;\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::erase(const T& fill) throw()\r
+  {\r
+    for (unsigned row = 0; row < m_rows; row++)\r
+      for (unsigned col = 0; col < m_cols; col++)\r
+        insert(row,col,fill);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::erase(unsigned row, unsigned col, const T& fill) throw(std::out_of_range)\r
+  {\r
+    insert(row,col,fill);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::insert(unsigned row, unsigned col, const T& element) throw(std::out_of_range)\r
+  {\r
+    if (row >= m_rows) throw std::out_of_range("matrix::insert row");\r
+    if (col >= m_cols) throw std::out_of_range("matrix::insert col");\r
+    m_data[row][col] = element;\r
+  }\r
+\r
+  template<typename T>\r
+  const T& matrix<T>::item(unsigned row, unsigned col) const throw(std::out_of_range)\r
+  {\r
+    if (row >= m_rows) throw std::out_of_range("matrix::item row");\r
+    if (col >= m_cols) throw std::out_of_range("matrix::item col");\r
+    return m_data[row][col];\r
+  }\r
+\r
+  template<typename T>\r
+  T& matrix<T>::item(unsigned row, unsigned col) throw(std::out_of_range)\r
+  {\r
+    if (row >= m_rows) throw std::out_of_range("matrix::item row");\r
+    if (col >= m_cols) throw std::out_of_range("matrix::item col");\r
+    return m_data[row][col];\r
+  }\r
+\r
+  template<typename T>\r
+  const T& matrix<T>::operator()(unsigned row, unsigned col) const throw(std::out_of_range)\r
+  {\r
+    if (row >= m_rows) throw std::out_of_range("matrix::operator() row");\r
+    if (col >= m_cols) throw std::out_of_range("matrix::operator() col");\r
+    return m_data[row][col];\r
+  }\r
+\r
+  template<typename T>\r
+  T& matrix<T>::operator()(unsigned row, unsigned col) throw(std::out_of_range)\r
+  {\r
+    if (row >= m_rows) throw std::out_of_range("matrix::operator() row");\r
+    if (col >= m_cols) throw std::out_of_range("matrix::operator() col");\r
+    return m_data[row][col];\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::fill(const T& item) throw()\r
+  {\r
+    erase(item);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::fill_column(unsigned col, const T& item) throw (std::out_of_range)\r
+  {\r
+    if (col >= m_cols) throw std::out_of_range("matrix::fill_column");\r
+    for (unsigned row = 0; row < m_rows; row++)\r
+      insert(row, col, item);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::fill_row(unsigned row, const T& item) throw (std::out_of_range)\r
+  {\r
+    if (row >= m_rows) throw std::out_of_range("matrix::fill_row");\r
+    for (unsigned col = 0; col < m_cols; col++)\r
+      insert(row, col, item);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::fill_leading_diagonal(const T& item) throw()\r
+  {\r
+    for (unsigned i = 0; i < m_cols && i < m_rows; i++)\r
+      insert(i, i, item);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::fill_trailing_diagonal(const T& item) throw()\r
+  {\r
+    for (unsigned i = 0; i < m_cols && i < m_rows; i++)\r
+      insert(i, m_cols-i-1, item);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::make_identity(const T& one, const T& zero) throw()\r
+  {\r
+    fill(zero);\r
+    fill_leading_diagonal(one);\r
+  }\r
+\r
+  template<typename T>\r
+  void matrix<T>::transpose(void) throw()\r
+  {\r
+    // no gain in manipulating this, since building a new matrix is no less efficient\r
+    matrix<T> transposed(columns(), rows());\r
+    for (unsigned row = 0; row < rows(); row++)\r
+      for (unsigned col = 0; col < columns(); col++)\r
+        transposed.insert(col,row,item(row,col));\r
+    // TODO - avoid an extra copy by swapping the member data here\r
+    *this = transposed;\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
diff --git a/src/Moof/stlplus/ntree.hpp b/src/Moof/stlplus/ntree.hpp
new file mode 100755 (executable)
index 0000000..33817e2
--- /dev/null
@@ -0,0 +1,364 @@
+#ifndef STLPLUS_NTREE\r
+#define STLPLUS_NTREE\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   A templated n-ary tree data structure. STL-like but the definition of\r
+//   iterators is really only applicable to one-dimensional structures. I use\r
+//   iterators to access tree nodes, but there is no increment or decrement\r
+//   operators for them. I also define prefix and postfix traversal iterators\r
+//   which do have increment.\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+#include "exceptions.hpp"\r
+#include "safe_iterator.hpp"\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Internals\r
+\r
+  template<typename T> class ntree_node;\r
+  template<typename T> class ntree;\r
+  template<typename T, typename TRef, typename TPtr> class ntree_iterator;\r
+  template<typename T, typename TRef, typename TPtr> class ntree_prefix_iterator;\r
+  template<typename T, typename TRef, typename TPtr> class ntree_postfix_iterator;\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Iterators\r
+\r
+  // Simple iterators which are just used as pointers to tree nodes. These have\r
+  // no increment or decrement operations defined. An uninitialised iterator is\r
+  // null - similarly, if you ask for the root of an empty tree or the parent of\r
+  // the root node then you get a null iterator.\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  class ntree_iterator : public safe_iterator<ntree<T>,ntree_node<T> >\r
+  {\r
+  public:\r
+    // local type definitions\r
+    // an iterator points to an object whilst a const_iterator points to a const object\r
+    typedef ntree_iterator<T,T&,T*> iterator;\r
+    typedef ntree_iterator<T,const T&,const T*> const_iterator;\r
+    typedef ntree_iterator<T,TRef,TPtr> this_iterator;\r
+    typedef TRef reference;\r
+    typedef TPtr pointer;\r
+\r
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
+    ntree_iterator(void);\r
+    ~ntree_iterator(void);\r
+\r
+    // Type conversion methods allow const_iterator and iterator to be converted\r
+    const_iterator constify(void) const;\r
+    iterator deconstify(void) const;\r
+\r
+    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed\r
+    bool operator == (const this_iterator& r) const;\r
+    bool operator != (const this_iterator& r) const;\r
+    bool operator < (const this_iterator& r) const;\r
+\r
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
+    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
+    reference operator*(void) const\r
+      throw(null_dereference,end_dereference);\r
+    pointer operator->(void) const\r
+      throw(null_dereference,end_dereference);\r
+\r
+    friend class ntree<T>;\r
+    friend class ntree_prefix_iterator<T,TRef,TPtr>;\r
+    friend class ntree_postfix_iterator<T,TRef,TPtr>;\r
+\r
+  public:\r
+    // Note: I had to make this public to get round a compiler problem - it should be private\r
+    // you cannot create a valid iterator except by calling an ntree method that returns one\r
+    // constructor used by ntree to create a non-null iterator\r
+    explicit ntree_iterator(ntree_node<T>* node);\r
+    // constructor used by ntree to create an end iterator\r
+    explicit ntree_iterator(const ntree<T>* owner);\r
+    // used to create an alias of an iterator\r
+    explicit ntree_iterator(const safe_iterator<ntree<T>, ntree_node<T> >& iterator);\r
+  };\r
+\r
+  // Traversal iterators are like iterators but they have increment operators (++)\r
+  // - prefix_iterator visits the nodes of the tree in prefix order\r
+  // - postfix_iterator visits the nodes of the tree in postfix order.\r
+  // There is no such thing as infix order for an n-ary tree and you cannot\r
+  // traverse backwards with these iterators. These follow the STL convention in\r
+  // that you iterate from a begin to an end - in this case ntree exports\r
+  // prefix_begin()/prefix_end() and postfix_begin()/postfix_end(). You can\r
+  // simplify these iterators to the basic iterator above for functions that\r
+  // require a simple iterator.\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  class ntree_prefix_iterator\r
+  {\r
+  public:\r
+    typedef ntree_prefix_iterator<T,T&,T*>             iterator;\r
+    typedef ntree_prefix_iterator<T,const T&,const T*> const_iterator;\r
+    typedef ntree_prefix_iterator<T,TRef,TPtr>         this_iterator;\r
+    typedef ntree_iterator<T,TRef,TPtr>                simple_iterator;\r
+    typedef TRef                                       reference;\r
+    typedef TPtr                                       pointer;\r
+\r
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
+    ntree_prefix_iterator(void);\r
+    ~ntree_prefix_iterator(void);\r
+\r
+    // tests\r
+    // a null iterator is one that has not been initialised with a value yet\r
+    // i.e. you just declared it but didn't assign to it\r
+    bool null(void) const;\r
+    // an end iterator is one that points to the end element of the list of nodes\r
+    // in STL conventions this is one past the last valid element and must not be dereferenced\r
+    bool end(void) const;\r
+    // a valid iterator is one that can be dereferenced\r
+    // i.e. non-null and non-end\r
+    bool valid(void) const;\r
+\r
+    // Type conversion methods allow const_iterator and iterator to be converted\r
+    // convert an iterator/const_iterator to a const_iterator\r
+    const_iterator constify(void) const;\r
+    iterator deconstify(void) const;\r
+\r
+    // generate a simple iterator from a traversal iterator\r
+    ntree_iterator<T,TRef,TPtr> simplify(void) const;\r
+\r
+    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed\r
+    bool operator == (const this_iterator& r) const;\r
+    bool operator != (const this_iterator& r) const;\r
+    bool operator < (const this_iterator& r) const;\r
+\r
+    // increment/decrement operators used to step through the set of all nodes in a graph\r
+    // it is only legal to increment a valid iterator\r
+    // pre-increment\r
+    this_iterator& operator ++ (void)\r
+      throw(null_dereference,end_dereference);\r
+    // post-increment\r
+    this_iterator operator ++ (int)\r
+      throw(null_dereference,end_dereference);\r
+\r
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
+    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
+    reference operator*(void) const\r
+      throw(null_dereference,end_dereference);\r
+    pointer operator->(void) const\r
+      throw(null_dereference,end_dereference);\r
+\r
+    friend class ntree<T>;\r
+    friend class ntree_iterator<T,TRef,TPtr>;\r
+\r
+  private:\r
+    ntree_iterator<T,TRef,TPtr> m_iterator;\r
+\r
+    explicit ntree_prefix_iterator(const ntree_iterator<T,TRef,TPtr>& i);\r
+    const ntree_iterator<T,TRef,TPtr>& get_iterator(void) const;\r
+    ntree_iterator<T,TRef,TPtr>& get_iterator(void);\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  class ntree_postfix_iterator\r
+  {\r
+  public:\r
+    typedef ntree_postfix_iterator<T,T&,T*>             iterator;\r
+    typedef ntree_postfix_iterator<T,const T&,const T*> const_iterator;\r
+    typedef ntree_postfix_iterator<T,TRef,TPtr>         this_iterator;\r
+    typedef ntree_iterator<T,TRef,TPtr>                 simple_iterator;\r
+    typedef TRef                                        reference;\r
+    typedef TPtr                                        pointer;\r
+\r
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
+    ntree_postfix_iterator(void);\r
+    ~ntree_postfix_iterator(void);\r
+\r
+    // tests\r
+    // a null iterator is one that has not been initialised with a value yet\r
+    // i.e. you just declared it but didn't assign to it\r
+    bool null(void) const;\r
+    // an end iterator is one that points to the end element of the list of nodes\r
+    // in STL conventions this is one past the last valid element and must not be dereferenced\r
+    bool end(void) const;\r
+    // a valid iterator is one that can be dereferenced\r
+    // i.e. non-null and non-end\r
+    bool valid(void) const;\r
+\r
+    // Type conversion methods allow const_iterator and iterator to be converted\r
+    // convert an iterator/const_iterator to a const_iterator\r
+    const_iterator constify(void) const;\r
+    iterator deconstify(void) const;\r
+\r
+    // generate a simple iterator from a traversal iterator\r
+    ntree_iterator<T,TRef,TPtr> simplify(void) const;\r
+\r
+    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed\r
+    bool operator == (const this_iterator& r) const;\r
+    bool operator != (const this_iterator& r) const;\r
+    bool operator < (const this_iterator& r) const;\r
+\r
+    // increment/decrement operators used to step through the set of all nodes in a graph\r
+    // it is only legal to increment a valid iterator\r
+    // pre-increment\r
+    this_iterator& operator ++ (void)\r
+      throw(null_dereference,end_dereference);\r
+    // post-increment\r
+    this_iterator operator ++ (int)\r
+      throw(null_dereference,end_dereference);\r
+\r
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
+    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
+    reference operator*(void) const\r
+      throw(null_dereference,end_dereference);\r
+    pointer operator->(void) const\r
+      throw(null_dereference,end_dereference);\r
+\r
+    friend class ntree<T>;\r
+    friend class ntree_iterator<T,TRef,TPtr>;\r
+\r
+  private:\r
+    ntree_iterator<T,TRef,TPtr> m_iterator;\r
+\r
+    explicit ntree_postfix_iterator(const ntree_iterator<T,TRef,TPtr>& i);\r
+    const ntree_iterator<T,TRef,TPtr>& get_iterator(void) const;\r
+    ntree_iterator<T,TRef,TPtr>& get_iterator(void);\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // The Ntree class\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename T>\r
+  class ntree\r
+  {\r
+  public:\r
+    // STL-like typedefs for the types and iterators\r
+    typedef T value_type;\r
+\r
+    typedef ntree_iterator<T,T&,T*> iterator;\r
+    typedef ntree_iterator<T,const T&,const T*> const_iterator;\r
+\r
+    typedef ntree_prefix_iterator<T,T&,T*> prefix_iterator;\r
+    typedef ntree_prefix_iterator<T,const T&,const T*> const_prefix_iterator;\r
+\r
+    typedef ntree_postfix_iterator<T,T&,T*> postfix_iterator;\r
+    typedef ntree_postfix_iterator<T,const T&,const T*> const_postfix_iterator;\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // Constructors, destructors and copies\r
+\r
+    ntree(void);\r
+    ~ntree(void);\r
+\r
+    // copy constructor and assignment both copy the tree\r
+    ntree(const ntree<T>&);\r
+    ntree<T>& operator=(const ntree<T>&);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // size tests\r
+\r
+    // tests on whole tree\r
+    bool empty(void) const;\r
+    unsigned size(void) const;\r
+\r
+    // tests for number of nodes in subtree starting at node\r
+    unsigned size(const const_iterator& node) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    unsigned size(const iterator& node)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    // test for depth of tree from root to node\r
+    unsigned depth(const const_iterator& node) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    unsigned depth(const iterator& node)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // direct traversal\r
+\r
+    const_iterator root(void) const;\r
+    iterator root(void);\r
+\r
+    unsigned children(const const_iterator& node) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    unsigned children(const iterator& node)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    const_iterator child(const const_iterator& node, unsigned child) const\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+    iterator child(const iterator& node, unsigned child)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+\r
+    const_iterator parent(const const_iterator& node) const\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    iterator parent(const iterator& node)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // iterator traversal\r
+\r
+    const_prefix_iterator prefix_begin(void) const;\r
+    prefix_iterator prefix_begin(void);\r
+    const_prefix_iterator prefix_end(void) const;\r
+    prefix_iterator prefix_end(void);\r
+\r
+    const_postfix_iterator postfix_begin(void) const;\r
+    postfix_iterator postfix_begin(void);\r
+    const_postfix_iterator postfix_end(void) const;\r
+    postfix_iterator postfix_end(void);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // modification\r
+\r
+    iterator insert(const T&);\r
+\r
+    iterator insert(const iterator& node, unsigned child, const T&)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+    iterator append(const iterator& node, const T&) \r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    iterator insert(const iterator& node, unsigned child, const ntree<T>&)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+    iterator append(const iterator& node, const ntree<T>&)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    iterator push(const iterator& node, const T&) \r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    void pop(const iterator& node, unsigned child) \r
+      throw(wrong_object,null_dereference,end_dereference);\r
+\r
+    void erase(void);\r
+    void erase(const iterator& node)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    void erase(const iterator& node, unsigned child)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+\r
+    ntree<T> subtree(void);\r
+    ntree<T> subtree(const iterator& node)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    ntree<T> subtree(const iterator& node, unsigned child)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+\r
+    ntree<T> cut(void);\r
+    ntree<T> cut(const iterator& node)\r
+      throw(wrong_object,null_dereference,end_dereference);\r
+    ntree<T> cut(const iterator& node, unsigned child)\r
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+\r
+  private:\r
+    ntree_node<T>* m_root;\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#include "ntree.tpp"\r
+#endif\r
diff --git a/src/Moof/stlplus/ntree.tpp b/src/Moof/stlplus/ntree.tpp
new file mode 100755 (executable)
index 0000000..6fd019d
--- /dev/null
@@ -0,0 +1,913 @@
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include <vector>\r
+#include <algorithm>\r
+\r
+namespace stlplus \r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // ntree_node\r
+\r
+  template<typename T>\r
+  class ntree_node\r
+  {\r
+  public:\r
+    master_iterator<ntree<T>, ntree_node<T> > m_master;\r
+    T m_data;\r
+    ntree_node<T>* m_parent;\r
+    std::vector<ntree_node<T>*> m_children;\r
+\r
+  public:\r
+    ntree_node(const ntree<T>* owner, const T& data = T()) :\r
+      m_master(owner,this), m_data(data), m_parent(0)\r
+      {\r
+      }\r
+\r
+    void change_owner(const ntree<T>* owner)\r
+      {\r
+        m_master.change_owner(owner);\r
+        for (TYPENAME std::vector<ntree_node<T>*>::iterator i = m_children.begin(); i != m_children.end(); i++)\r
+          (*i)->change_owner(owner);\r
+      }\r
+\r
+    ~ntree_node(void)\r
+      {\r
+        m_parent = 0;\r
+        for (TYPENAME std::vector<ntree_node<T>*>::iterator i = m_children.begin(); i != m_children.end(); i++)\r
+          delete *i;\r
+      }\r
+\r
+  };\r
+\r
+  template<typename T>\r
+  static ntree_node<T>* ntree_copy(const ntree<T>* new_owner, ntree_node<T>* root)\r
+  {\r
+    if (!root) return 0;\r
+    ntree_node<T>* new_tree = new ntree_node<T>(new_owner, root->m_data);\r
+    for (TYPENAME std::vector<ntree_node<T>*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++)\r
+    {\r
+      ntree_node<T>* new_child = ntree_copy(new_owner, *i);\r
+      new_tree->m_children.push_back(new_child);\r
+      new_child->m_parent = new_tree;\r
+    }\r
+    return new_tree;\r
+  }\r
+\r
+  template<typename T>\r
+  static unsigned ntree_size(ntree_node<T>* root)\r
+  {\r
+    if (!root) return 0;\r
+    unsigned result = 1;\r
+    for (TYPENAME std::vector<ntree_node<T>*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++)\r
+      result += ntree_size(*i);\r
+    return result;\r
+  }\r
+\r
+  template<typename T>\r
+  static unsigned ntree_depth(ntree_node<T>* root)\r
+  {\r
+    unsigned depth = 0;\r
+    for (ntree_node<T>* i = root; i; i = i->m_parent)\r
+      depth++;\r
+    return depth;\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // ntree_iterator\r
+\r
+  // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(void)\r
+  {\r
+  }\r
+\r
+  // used to create an alias of an iterator\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(const safe_iterator<ntree<T>, ntree_node<T> >& iterator) :\r
+    safe_iterator<ntree<T>,ntree_node<T> >(iterator)\r
+  {\r
+  }\r
+\r
+  // constructor used by ntree to create a non-null iterator\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(ntree_node<T>* node) :\r
+    safe_iterator<ntree<T>,ntree_node<T> >(node->m_master)\r
+  {\r
+  }\r
+\r
+  // constructor used by ntree to create an end iterator\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(const ntree<T>* owner) :\r
+    safe_iterator<ntree<T>,ntree_node<T> >(owner)\r
+  {\r
+  }\r
+\r
+  // destructor\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr>::~ntree_iterator(void)\r
+  {\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_iterator<T,TRef,TPtr>::const_iterator ntree_iterator<T,TRef,TPtr>::constify(void) const\r
+  {\r
+    return ntree_iterator<T,const T&,const T*>(*this);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_iterator<T,TRef,TPtr>::iterator ntree_iterator<T,TRef,TPtr>::deconstify(void) const\r
+  {\r
+    return ntree_iterator<T,T&,T*>(*this);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return equal(r);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return !operator==(r);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return compare(r) < 0;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_iterator<T,TRef,TPtr>::reference ntree_iterator<T,TRef,TPtr>::operator*(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    this->assert_valid();\r
+    return this->node()->m_data;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_iterator<T,TRef,TPtr>::pointer ntree_iterator<T,TRef,TPtr>::operator->(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return &(operator*());\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // ntree_prefix_iterator\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_prefix_iterator<T,TRef,TPtr>::ntree_prefix_iterator(void)\r
+  {\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_prefix_iterator<T,TRef,TPtr>::~ntree_prefix_iterator(void)\r
+  {\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_prefix_iterator<T,TRef,TPtr>::ntree_prefix_iterator(const ntree_iterator<T,TRef,TPtr>& i) :\r
+    m_iterator(i)\r
+  {\r
+    // this is initialised with the root node\r
+    // which is also the first node in prefix traversal order\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_prefix_iterator<T,TRef,TPtr>::null(void) const\r
+  {\r
+    return m_iterator.null();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_prefix_iterator<T,TRef,TPtr>::end(void) const\r
+  {\r
+    return m_iterator.end();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_prefix_iterator<T,TRef,TPtr>::valid(void) const\r
+  {\r
+    return m_iterator.valid();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::const_iterator ntree_prefix_iterator<T,TRef,TPtr>::constify(void) const\r
+  {\r
+    return ntree_prefix_iterator<T,const T&,const T*>(m_iterator);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::iterator ntree_prefix_iterator<T,TRef,TPtr>::deconstify(void) const\r
+  {\r
+    return ntree_prefix_iterator<T,T&,T*>(m_iterator);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr> ntree_prefix_iterator<T,TRef,TPtr>::simplify(void) const\r
+  {\r
+    return m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_prefix_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return m_iterator == r.m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_prefix_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return m_iterator != r.m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_prefix_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return m_iterator < r.m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& ntree_prefix_iterator<T,TRef,TPtr>::operator ++ (void)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // pre-increment operator\r
+    // algorithm: if there are any children, visit child 0, otherwise, go to\r
+    // parent and deduce which child the start node was of that parent - if\r
+    // there are further children, go into the next one. Otherwise, go up the\r
+    // tree and test again for further children. Return null if there are no\r
+    // further nodes\r
+    m_iterator.assert_valid();\r
+    ntree_node<T>* old_node = m_iterator.node();\r
+    if (!old_node->m_children.empty())\r
+    {\r
+      // simply take the first child of this node\r
+      m_iterator.set(old_node->m_children[0]->m_master);\r
+    }\r
+    else\r
+    {\r
+      // this loop walks up the parent pointers\r
+      // either it will walk off the top and exit or a new node will be found and the loop will exit\r
+      for (;;)\r
+      {\r
+        // go up a level\r
+        ntree_node<T>* parent = old_node->m_parent;\r
+        if (!parent)\r
+        {\r
+          // we've walked off the top of the tree, so return end\r
+          m_iterator.set_end();\r
+          break;\r
+        }\r
+        else\r
+        {\r
+          // otherwise walk down the next child - if there is one\r
+          // find which index the old node was relative to this node\r
+          TYPENAME std::vector<ntree_node<T>*>::iterator found = \r
+            std::find(parent->m_children.begin(), parent->m_children.end(), old_node);\r
+          // if this was found, then see if there is another and if so return that\r
+          found++;\r
+          if (found != parent->m_children.end())\r
+          {\r
+            // visit the next child\r
+            m_iterator.set((*found)->m_master);\r
+            break;\r
+          }\r
+          else\r
+          {\r
+            // keep going up\r
+            old_node = parent;\r
+          }\r
+        }\r
+      }\r
+    }\r
+    return *this;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator ntree_prefix_iterator<T,TRef,TPtr>::operator ++ (int)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // post-increment is defined in terms of the pre-increment\r
+    ntree_prefix_iterator<T,TRef,TPtr> result(*this);\r
+    ++(*this);\r
+    return result;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::reference ntree_prefix_iterator<T,TRef,TPtr>::operator*(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return m_iterator.operator*();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::pointer ntree_prefix_iterator<T,TRef,TPtr>::operator->(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return m_iterator.operator->();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  const ntree_iterator<T,TRef,TPtr>& ntree_prefix_iterator<T,TRef,TPtr>::get_iterator(void) const\r
+  {\r
+    return m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr>& ntree_prefix_iterator<T,TRef,TPtr>::get_iterator(void)\r
+  {\r
+    return m_iterator;\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // ntree_postfix_iterator\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_postfix_iterator<T,TRef,TPtr>::ntree_postfix_iterator(void)\r
+  {\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_postfix_iterator<T,TRef,TPtr>::~ntree_postfix_iterator(void)\r
+  {\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_postfix_iterator<T,TRef,TPtr>::ntree_postfix_iterator(const ntree_iterator<T,TRef,TPtr>& i) :\r
+    m_iterator(i)\r
+  {\r
+    // this is initialised with the root node\r
+    // initially traverse to the first node to be visited\r
+    if (m_iterator.valid())\r
+    {\r
+      ntree_node<T>* node = m_iterator.node();\r
+      while (!node->m_children.empty())\r
+        node = node->m_children[0];\r
+      m_iterator.set(node->m_master);\r
+    }\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_postfix_iterator<T,TRef,TPtr>::null(void) const\r
+  {\r
+    return m_iterator.null();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_postfix_iterator<T,TRef,TPtr>::end(void) const\r
+  {\r
+    return m_iterator.end();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_postfix_iterator<T,TRef,TPtr>::valid(void) const\r
+  {\r
+    return m_iterator.valid();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::const_iterator ntree_postfix_iterator<T,TRef,TPtr>::constify(void) const\r
+  {\r
+    return ntree_postfix_iterator<T,const T&,const T*>(m_iterator);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::iterator ntree_postfix_iterator<T,TRef,TPtr>::deconstify(void) const\r
+  {\r
+    return ntree_postfix_iterator<T,T&,T*>(m_iterator);\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr> ntree_postfix_iterator<T,TRef,TPtr>::simplify(void) const\r
+  {\r
+    return m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_postfix_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return m_iterator == r.m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_postfix_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return m_iterator != r.m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  bool ntree_postfix_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
+  {\r
+    return m_iterator < r.m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& ntree_postfix_iterator<T,TRef,TPtr>::operator ++ (void)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // pre-increment operator\r
+    // algorithm: this node has been visited, therefore all children must have\r
+    // already been visited. So go to parent. Return null if the parent is null.\r
+    // Otherwise deduce which child the start node was of that parent - if there\r
+    // are further children, go into the next one and then walk down any\r
+    // subsequent first-child pointers to the bottom. Otherwise, if there are no\r
+    // children then the parent node is the next in the traversal.\r
+    m_iterator.assert_valid();\r
+    // go up a level\r
+    ntree_node<T>* old_node = m_iterator.node();\r
+    ntree_node<T>* parent = old_node->m_parent;\r
+    if (!parent)\r
+    {\r
+      // we've walked off the top of the tree, so return end\r
+      m_iterator.set_end();\r
+    }\r
+    else\r
+    {\r
+      // otherwise find which index the old node was relative to this node\r
+      TYPENAME std::vector<ntree_node<T>*>::iterator found =\r
+        std::find(parent->m_children.begin(), parent->m_children.end(), old_node);\r
+      // if this was found, then see if there is another\r
+      found++;\r
+      if (found != parent->m_children.end())\r
+      {\r
+        // if so traverse to it and walk down the leftmost child pointers to the bottom of the new sub-tree\r
+        ntree_node<T>* new_node = *found;\r
+        while (!new_node->m_children.empty())\r
+          new_node = new_node->m_children[0];\r
+        m_iterator.set(new_node->m_master);\r
+      }\r
+      else\r
+      {\r
+        // the parent's children have all been visited - so the parent is visited\r
+        m_iterator.set(parent->m_master);\r
+      }\r
+    }\r
+    return *this;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator ntree_postfix_iterator<T,TRef,TPtr>::operator ++ (int)\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    // post-increment is defined in terms of the pre-increment\r
+    ntree_postfix_iterator<T,TRef,TPtr> result(*this);\r
+    ++(*this);\r
+    return result;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::reference ntree_postfix_iterator<T,TRef,TPtr>::operator*(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return m_iterator.operator*();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::pointer ntree_postfix_iterator<T,TRef,TPtr>::operator->(void) const\r
+    throw(null_dereference,end_dereference)\r
+  {\r
+    return m_iterator.operator->();\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  const ntree_iterator<T,TRef,TPtr>& ntree_postfix_iterator<T,TRef,TPtr>::get_iterator(void) const\r
+  {\r
+    return m_iterator;\r
+  }\r
+\r
+  template<typename T, typename TRef, typename TPtr>\r
+  ntree_iterator<T,TRef,TPtr>& ntree_postfix_iterator<T,TRef,TPtr>::get_iterator(void)\r
+  {\r
+    return m_iterator;\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // ntree\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename T>\r
+  ntree<T>::ntree(void) : m_root(0)\r
+  {\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T>::~ntree(void)\r
+  {\r
+    if (m_root) delete m_root;\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T>::ntree(const ntree<T>& r) : m_root(0)\r
+  {\r
+    *this = r;\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T>& ntree<T>::operator=(const ntree<T>& r)\r
+  {\r
+    if (m_root) delete m_root;\r
+    m_root = ntree_copy(this, r.m_root);\r
+    return *this;\r
+  }\r
+\r
+  template<typename T>\r
+  bool ntree<T>::empty(void) const\r
+  {\r
+    return m_root == 0;\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned ntree<T>::size(void) const\r
+  {\r
+    return ntree_size(m_root);\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned ntree<T>::size(const TYPENAME ntree<T>::const_iterator& i) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    return ntree_size(i.node());\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned ntree<T>::size(const TYPENAME ntree<T>::iterator& i)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    return ntree_size(i.node());\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned ntree<T>::depth(const TYPENAME ntree<T>::const_iterator& i) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    return ntree_depth(i.node());\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned ntree<T>::depth(const TYPENAME ntree<T>::iterator& i)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    return ntree_depth(i.node());\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::const_iterator ntree<T>::root(void) const\r
+  {\r
+    if (!m_root) return ntree_iterator<T,const T&,const T*>(this);\r
+    return ntree_iterator<T,const T&,const T*>(m_root);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::root(void)\r
+  {\r
+    if (!m_root) return ntree_iterator<T,T&,T*>(this);\r
+    return ntree_iterator<T,T&,T*>(m_root);\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned ntree<T>::children(const TYPENAME ntree<T>::const_iterator& i) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    return i.node()->m_children.size();\r
+  }\r
+\r
+  template<typename T>\r
+  unsigned ntree<T>::children(const ntree_iterator<T,T&,T*>& i)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    return i.node()->m_children.size();\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::const_iterator ntree<T>::child(const TYPENAME ntree<T>::const_iterator& i, unsigned child) const\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    i.assert_valid(this);\r
+    if (child >= children(i)) throw std::out_of_range("stlplus::ntree");\r
+    return ntree_iterator<T,const T&,const T*>(i.node()->m_children[child]);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::child(const TYPENAME ntree<T>::iterator& i, unsigned child)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    i.assert_valid(this);\r
+    if (child >= children(i)) throw std::out_of_range("stlplus::ntree");\r
+    return ntree_iterator<T,T&,T*>(i.node()->m_children[child]);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::const_iterator ntree<T>::parent(const TYPENAME ntree<T>::const_iterator& i) const\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    ntree_node<T>* parent = i.node()->m_parent;\r
+    if (!parent) return ntree_iterator<T,const T&,const T*>(this);\r
+    return ntree_iterator<T,const T&,const T*>(parent);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::parent(const TYPENAME ntree<T>::iterator& i)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    i.assert_valid(this);\r
+    ntree_node<T>* parent = i.node()->m_parent;\r
+    if (!parent) return ntree_iterator<T,T&,T*>(this);\r
+    return ntree_iterator<T,T&,T*>(parent);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::const_prefix_iterator ntree<T>::prefix_begin(void) const\r
+  {\r
+    return ntree_prefix_iterator<T,const T&,const T*>(root());\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::prefix_iterator ntree<T>::prefix_begin(void)\r
+  {\r
+    return ntree_prefix_iterator<T,T&,T*>(root());\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::const_prefix_iterator ntree<T>::prefix_end(void) const\r
+  {\r
+    return ntree_prefix_iterator<T,const T&,const T*>(ntree_iterator<T,const T&,const T*>(this));\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::prefix_iterator ntree<T>::prefix_end(void)\r
+  {\r
+    return ntree_prefix_iterator<T,T&,T*>(ntree_iterator<T,T&,T*>(this));\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::const_postfix_iterator ntree<T>::postfix_begin(void) const\r
+  {\r
+    return ntree_postfix_iterator<T,const T&,const T*>(root());\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::postfix_iterator ntree<T>::postfix_begin(void)\r
+  {\r
+    return ntree_postfix_iterator<T,T&,T*>(root());\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::const_postfix_iterator ntree<T>::postfix_end(void) const\r
+  {\r
+    return ntree_postfix_iterator<T,const T&,const T*>(ntree_iterator<T,const T&,const T*>(this));\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::postfix_iterator ntree<T>::postfix_end(void)\r
+  {\r
+    return ntree_postfix_iterator<T,T&,T*>(ntree_iterator<T,T&,T*>(this));\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::insert(const T& data)\r
+  {\r
+    // insert a new node as the root\r
+    return insert(ntree_iterator<T,T&,T*>(this), 0, data);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::insert(const TYPENAME ntree<T>::iterator& i, unsigned offset, const T& data)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    // if i is the end iterator, this means insert a new root\r
+    if (i.end())\r
+      erase();\r
+    else\r
+    {\r
+      i.assert_valid(this);\r
+      if (offset > children(i)) throw std::out_of_range("stlplus::ntree");\r
+    }\r
+    ntree_node<T>* new_node = new ntree_node<T>(this,data);\r
+    if (i.end())\r
+    {\r
+      m_root = new_node;\r
+    }\r
+    else\r
+    {\r
+      i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node);\r
+      new_node->m_parent = i.node();\r
+    }\r
+    return ntree_iterator<T,T&,T*>(new_node);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::append(const TYPENAME ntree<T>::iterator& i, const T& data)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return insert(i, i.node()->m_children.size(), data);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::insert(const TYPENAME ntree<T>::iterator& i, unsigned offset, const ntree<T>& tree)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    // insert a whole tree as a child of i\r
+    i.assert_valid(this);\r
+    if (offset > children(i)) throw std::out_of_range("stlplus::ntree");\r
+    ntree_node<T>* new_node = ntree_copy(this, tree.m_root);\r
+    i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node);\r
+    new_node->m_parent = i.node();\r
+    return ntree_iterator<T,T&,T*>(new_node);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::append(const TYPENAME ntree<T>::iterator& i, const ntree<T>& tree)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    return insert(i, children(i), tree);\r
+  }\r
+\r
+  template<typename T>\r
+  TYPENAME ntree<T>::iterator ntree<T>::push(const TYPENAME ntree<T>::iterator& node, const T& data)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // insert a new node to replace the existing node in the tree\r
+    // making the original node the child of the new node\r
+    // i.e. (node) becomes (new)->(node)\r
+    // afterwards, the iterator still points to the old node, now the child\r
+    // returns the iterator to the new node\r
+    node.assert_valid(this);\r
+    ntree_node<T>* new_node = new ntree_node<T>(this,data);\r
+    if (node.node() == m_root)\r
+    {\r
+      // pushing the root node\r
+      m_root = new_node;\r
+      new_node->m_parent = 0;\r
+    }\r
+    else\r
+    {\r
+      // pushing a sub-node\r
+      *(std::find(node.node()->m_parent->m_children.begin(), node.node()->m_parent->m_children.end(), node.node())) = new_node;\r
+      new_node->m_parent = node.node()->m_parent;\r
+    }\r
+    // link up the old node as the child of the new node\r
+    new_node->m_children.insert(new_node->m_children.begin(),node.node());\r
+    node.node()->m_parent = new_node;\r
+    return ntree_iterator<T,T&,T*>(new_node);\r
+  }\r
+\r
+  template<typename T>\r
+  void ntree<T>::pop(const TYPENAME ntree<T>::iterator& parent, unsigned offset)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    // inverse of push\r
+    // removes the specified child of the parent node, adding its children to the parent node at the same offset\r
+    parent.assert_valid(this);\r
+    ntree_node<T>* node = parent.node();\r
+    if (offset >= node->m_children.size()) throw std::out_of_range("stlplus::ntree");\r
+    // move the grandchildren first\r
+    ntree_node<T>* child = parent.node()->m_children[offset];\r
+    while (!child->m_children.empty())\r
+    {\r
+      // remove the last grandchild and insert into node just after the child to be removed\r
+      ntree_node<T>* grandchild = child->m_children[child->m_children.size()-1];\r
+      child->m_children.pop_back();\r
+      node->m_children.insert(node->m_children.begin()+offset+1, grandchild);\r
+      grandchild->m_parent = node;\r
+    }\r
+    // now remove the child\r
+    node->m_children.erase(node->m_children.begin()+offset);\r
+    delete child;\r
+  }\r
+\r
+  template<typename T>\r
+  void ntree<T>::erase(void)\r
+  {\r
+    // erase the whole tree\r
+    erase(root());\r
+  }\r
+\r
+  template<typename T>\r
+  void ntree<T>::erase(const TYPENAME ntree<T>::iterator& i)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    if (!i.end())\r
+    {\r
+      // erase this node and its subtree\r
+      // do this by erasing this child of its parent\r
+      // handle the case of erasing the root\r
+      i.assert_valid(this);\r
+      ntree_node<T>* node = i.node();\r
+      if (node == m_root)\r
+      {\r
+        delete m_root;\r
+        m_root = 0;\r
+      }\r
+      else\r
+      {\r
+        ntree_node<T>* parent = node->m_parent;\r
+        // impossible for parent to be null - should assert this\r
+        TYPENAME std::vector<ntree_node<T>*>::iterator found = \r
+          std::find(parent->m_children.begin(), parent->m_children.end(), node);\r
+        // impossible for find to fail - should assert this\r
+        parent->m_children.erase(found);\r
+        delete node;\r
+      }\r
+    }\r
+  }\r
+\r
+  template<typename T>\r
+  void ntree<T>::erase(const TYPENAME ntree<T>::iterator& i, unsigned offset)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    erase(child(i, offset));\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T> ntree<T>::subtree(void)\r
+  {\r
+    return subtree(root());\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T> ntree<T>::subtree(const TYPENAME ntree<T>::iterator& i)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    ntree<T> result;\r
+    if (!i.end())\r
+    {\r
+      i.assert_valid(this);\r
+      result.m_root = ntree_copy(&result, i.node());\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T> ntree<T>::subtree(const TYPENAME ntree<T>::iterator& i, unsigned offset)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    return subtree(child(i, offset));\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T> ntree<T>::cut(void)\r
+  {\r
+    return cut(root());\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T> ntree<T>::cut(const TYPENAME ntree<T>::iterator& i)\r
+    throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    ntree<T> result;\r
+    if (!i.end())\r
+    {\r
+      i.assert_valid(this);\r
+      ntree_node<T>* node = i.node();\r
+      if (node == m_root)\r
+      {\r
+        result.m_root = m_root;\r
+        m_root = 0;\r
+      }\r
+      else\r
+      {\r
+        ntree_node<T>* parent = node->m_parent;\r
+        // impossible for parent to be null - should assert this\r
+        TYPENAME std::vector<ntree_node<T>*>::iterator found = \r
+          std::find(parent->m_children.begin(), parent->m_children.end(), node);\r
+        // impossible for find to fail - should assert this\r
+        result.m_root = *found;\r
+        parent->m_children.erase(found);\r
+      }\r
+      if (result.m_root)\r
+      {\r
+        result.m_root->m_parent = 0;\r
+        result.m_root->set_new_owner(&result);\r
+      }\r
+    }\r
+    return result;\r
+  }\r
+\r
+  template<typename T>\r
+  ntree<T> ntree<T>::cut(const TYPENAME ntree<T>::iterator& i, unsigned offset)\r
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
+  {\r
+    return cut(child(i, offset));\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
diff --git a/src/Moof/stlplus/safe_iterator.hpp b/src/Moof/stlplus/safe_iterator.hpp
new file mode 100755 (executable)
index 0000000..5bf80fb
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef STLPLUS_SAFE_ITERATOR\r
+#define STLPLUS_SAFE_ITERATOR\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   The STLplus safe_iterator superclasses. This implements the STLplus safe\r
+//   iterator principles. Data structures can then be built using subclasses\r
+//   of safe_iterator for their iterator objects and they will inherit the\r
+//   safe iterator behaviour.\r
+\r
+//   The data structure must contain a master iterator for each node in the\r
+//   structure. When an iterator is returned to the user, it must be created\r
+//   by the master iterator. When a node is removed from the data structure,\r
+//   its master iterator is destroyed. This sets all iterators pointing to the\r
+//   master iterator to end iterators.\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+#include "exceptions.hpp"\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // internals\r
+\r
+  template<typename O, typename N>\r
+  class safe_iterator_body;\r
+\r
+  template<typename O, typename N>\r
+  class safe_iterator;\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Master Iterator\r
+  // Create one of these in each node in the data structure\r
+  // Generate iterators by obtaining a safe-iterator object from the master iterator\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename O, typename N>\r
+  class master_iterator\r
+  {\r
+  public:\r
+\r
+    // construct a valid master iterator connected to the node\r
+    master_iterator(const O* owner, N* node) throw();\r
+\r
+    // destructor - disconnects all iterators from the node\r
+    ~master_iterator(void) throw();\r
+\r
+    // dereference\r
+    N* node(void) const throw();\r
+    const O* owner(void) const throw();\r
+\r
+    // when you move a node from one owner to another, call this on the node's master iterator\r
+    // this effectively moves all other iterators to the node so that they are owned by the new owner too\r
+    void change_owner(const O* owner) throw();\r
+\r
+    friend class safe_iterator<O,N>;\r
+  private:\r
+    master_iterator(const master_iterator&) throw();\r
+    master_iterator& operator=(const master_iterator&) throw();\r
+    safe_iterator_body<O,N>* m_body;\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Safe Iterator\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename O, typename N>\r
+  class safe_iterator\r
+  {\r
+  public:\r
+\r
+    // construct a null iterator\r
+    safe_iterator(void) throw();\r
+\r
+    // construct a valid iterator by aliasing from the owner node's master iterator\r
+    safe_iterator(const master_iterator<O,N>&) throw();\r
+\r
+    // copy constructor does aliasing\r
+    safe_iterator(const safe_iterator<O,N>&) throw();\r
+\r
+    // alias an iterator by assignment\r
+    safe_iterator<O,N>& operator=(const safe_iterator<O,N>&) throw();\r
+\r
+    // destructor\r
+    ~safe_iterator(void) throw();\r
+\r
+    // reassignment to another node used in increment/decrement operation\r
+    void set(const master_iterator<O,N>&) throw();\r
+\r
+    // dereference\r
+    N* node(void) const throw();\r
+    const O* owner(void) const throw();\r
+\r
+    // change to a null iterator - i.e. one that does not belong to any object\r
+    // this does not affect any other iterators pointing to the same node\r
+    void set_null(void) throw();\r
+\r
+    ////////////////////////////////////////////////////////////////////////////////\r
+    // operations for clients that do not have a master end iterator\r
+    // alternatively, have a master end iterator as part of the container\r
+    // and call constructor(master_end) or set(master_end)\r
+\r
+    // construct an end iterator\r
+    safe_iterator(const O* owner) throw();\r
+\r
+    // change to an end iterator - e.g. as a result of incrementing off the end\r
+    void set_end(void) throw();\r
+\r
+    ////////////////////////////////////////////////////////////////////////////////\r
+    // tests\r
+\r
+    // comparison\r
+    bool equal(const safe_iterator<O,N>& right) const throw();\r
+    int compare(const safe_iterator<O,N>& right) const throw();\r
+\r
+    // a null iterator is one that has not been initialised with a value yet\r
+    // i.e. you just declared it but didn't assign to it\r
+    bool null(void) const throw();\r
+\r
+    // an end iterator is one that points to the end element of the list of nodes\r
+    // in STL conventions this is one past the last valid element and must not be dereferenced\r
+    bool end(void) const throw();\r
+\r
+    // a valid iterator is one that can be dereferenced\r
+    // i.e. non-null and non-end\r
+    bool valid(void) const throw();\r
+\r
+    // check the rules for a valid iterator that can be dereferenced\r
+    // optionally also check that the iterator is owned by the owner\r
+    void assert_valid(void) const throw(null_dereference,end_dereference);\r
+    void assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference);\r
+    // assert the rules for a non-null iterator - i.e. valid or end, values that occur in increment operations\r
+    void assert_non_null(void) const throw(null_dereference);\r
+    // assert that this iterator is owned by this container\r
+    void assert_owner(const O* owner) const throw(wrong_object);\r
+\r
+    ////////////////////////////////////////////////////////////////////////////////\r
+\r
+    friend class master_iterator<O,N>;\r
+  private:\r
+    safe_iterator_body<O,N>* m_body;\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#include "safe_iterator.tpp"\r
+#endif\r
diff --git a/src/Moof/stlplus/safe_iterator.tpp b/src/Moof/stlplus/safe_iterator.tpp
new file mode 100755 (executable)
index 0000000..14d89b9
--- /dev/null
@@ -0,0 +1,373 @@
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // body class implements the aliasing behaviour\r
+\r
+  template<typename O, typename N>\r
+  class safe_iterator_body\r
+  {\r
+  private:\r
+    const O* m_owner;\r
+    N* m_node;\r
+    unsigned m_count;\r
+\r
+  public:\r
+\r
+    safe_iterator_body(const O* owner, N* node) throw() : \r
+      m_owner(owner), m_node(node), m_count(1)\r
+      {\r
+//         std::cerr << "constructing " \r
+//                   << std::hex << ((unsigned long)this) \r
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
+//                   << ":" << std::dec << m_count << std::endl;\r
+      }\r
+\r
+    ~safe_iterator_body(void) throw()\r
+      {\r
+//         std::cerr << "destroying " \r
+//                   << std::hex << ((unsigned long)this) \r
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
+//                   << ":" << std::dec << m_count << std::endl;\r
+        m_owner = 0;\r
+        m_node = 0;\r
+      }\r
+\r
+    unsigned count(void) const\r
+      {\r
+        return m_count;\r
+      }\r
+\r
+    void increment(void)\r
+      {\r
+        ++m_count;\r
+//         std::cerr << "incremented " \r
+//                   << std::hex << ((unsigned long)this) \r
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
+//                   << ":" << std::dec << m_count << std::endl;\r
+      }\r
+\r
+    bool decrement(void)\r
+      {\r
+        --m_count;\r
+//         std::cerr << "decremented " \r
+//                   << std::hex << ((unsigned long)this) \r
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
+//                   << ":" << std::dec << m_count << std::endl;\r
+        return m_count == 0;\r
+      }\r
+\r
+    N* node(void) const throw()\r
+      {\r
+        return m_node;\r
+      }\r
+\r
+    const O* owner(void) const throw()\r
+      {\r
+        return m_owner;\r
+      }\r
+\r
+    void change_owner(const O* owner)\r
+      {\r
+        m_owner = owner;\r
+      }\r
+\r
+    bool equal(const safe_iterator_body<O,N>* right) const throw()\r
+      {\r
+//        return m_node == right->m_node;\r
+        return compare(right) == 0;\r
+      }\r
+\r
+    int compare(const safe_iterator_body<O,N>* right) const throw()\r
+      {\r
+        return ((long)m_node) - ((long)right->m_node);\r
+      }\r
+\r
+    bool null(void) const throw()\r
+      {\r
+        return m_owner == 0;\r
+      }\r
+\r
+    bool end(void) const throw()\r
+      {\r
+        return m_owner != 0 && m_node == 0;\r
+      }\r
+\r
+    bool valid(void) const throw()\r
+      {\r
+        return m_owner != 0 && m_node != 0;\r
+      }\r
+\r
+    void set_end(void) throw()\r
+      {\r
+        m_node = 0;\r
+      }\r
+\r
+    void set_null(void) throw()\r
+      {\r
+        m_owner = 0;\r
+        m_node = 0;\r
+      }\r
+\r
+    void assert_valid(void) const throw(null_dereference,end_dereference)\r
+      {\r
+        if (null())\r
+          throw null_dereference("stlplus::safe_iterator");\r
+        if (end())\r
+          throw end_dereference("stlplus::safe_iterator");\r
+      }\r
+\r
+    void assert_non_null(void) const throw(null_dereference)\r
+      {\r
+        if (null())\r
+          throw null_dereference("stlplus::safe_iterator");\r
+      }\r
+\r
+    void assert_owner(const O* owner) const throw(wrong_object)\r
+      {\r
+        if (owner != m_owner)\r
+          throw wrong_object("stlplus::safe_iterator");\r
+      }\r
+  };\r
+\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Master Iterator\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  // construct a valid iterator\r
+  template<typename O, typename N>\r
+  master_iterator<O,N>::master_iterator(const O* owner, N* node) throw() :\r
+    m_body(new safe_iterator_body<O,N>(owner,node))\r
+  {\r
+  }\r
+\r
+  // destructor - disconnect all iterators from the node\r
+  // this usually happens when the node is deleted and must invalidate all aliases\r
+  template<typename O, typename N>\r
+  master_iterator<O,N>::~master_iterator(void) throw()\r
+  {\r
+    m_body->set_end();\r
+    if(m_body->decrement())\r
+    {\r
+      delete m_body;\r
+      m_body = 0;\r
+    }\r
+  }\r
+\r
+  // dereference\r
+  template<typename O, typename N>\r
+  N* master_iterator<O,N>::node(void) const throw()\r
+  {\r
+    return m_body->node();\r
+  }\r
+\r
+  template<typename O, typename N>\r
+  const O* master_iterator<O,N>::owner(void) const throw()\r
+  {\r
+    return m_body->owner();\r
+  }\r
+\r
+  // when you move a node from one owner to another, call this on the node's iterator\r
+  // this effectively moves all iterators to the node so that they are owned by the new owner too\r
+  template<typename O, typename N>\r
+  void master_iterator<O,N>::change_owner(const O* owner) throw()\r
+  {\r
+    m_body->change_owner(owner);\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Safe Iterator\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  // construct a null iterator\r
+  // later assignment of a valid iterator to this is done by using step\r
+  template<typename O, typename N>\r
+  safe_iterator<O,N>::safe_iterator(void) throw() : \r
+    m_body(new safe_iterator_body<O,N>(0,0))\r
+  {\r
+  }\r
+\r
+  // construct a valid iterator by aliasing from the owner node's master iterator\r
+  template<typename O, typename N>\r
+  safe_iterator<O,N>::safe_iterator(const master_iterator<O,N>& r) throw() :\r
+    m_body(0)\r
+  {\r
+    m_body = r.m_body;\r
+    m_body->increment();\r
+  }\r
+\r
+  // construct a valid iterator by aliasing from the owner node's master iterator\r
+  template<typename O, typename N>\r
+  safe_iterator<O,N>::safe_iterator(const safe_iterator<O,N>& r) throw() :\r
+    m_body(0)\r
+  {\r
+    m_body = r.m_body;\r
+    m_body->increment();\r
+  }\r
+\r
+  // assignment implements dealiasing followed by aliasing\r
+  template<typename O, typename N>\r
+  safe_iterator<O,N>& safe_iterator<O,N>::operator=(const safe_iterator<O,N>& r) throw()\r
+  {\r
+    if (m_body != r.m_body)\r
+    {\r
+      if (m_body->decrement())\r
+        delete m_body;\r
+      m_body = r.m_body;\r
+      m_body->increment();\r
+    }\r
+    return *this;\r
+  }\r
+\r
+  // destructor - implements dealiasing\r
+  template<typename O, typename N>\r
+  safe_iterator<O,N>::~safe_iterator(void) throw()\r
+  {\r
+    if(m_body->decrement())\r
+    {\r
+      delete m_body;\r
+      m_body = 0;\r
+    }\r
+  }\r
+\r
+\r
+  // increment/decrement operation\r
+  // implements dealiasing followed by aliasing\r
+  template<typename O, typename N>\r
+  void safe_iterator<O,N>::set(const master_iterator<O,N>& r) throw()\r
+  {\r
+    if (m_body != r.m_body)\r
+    {\r
+      if (m_body->decrement())\r
+        delete m_body;\r
+      m_body = r.m_body;\r
+      m_body->increment();\r
+    }\r
+  }\r
+\r
+  // dereference\r
+  template<typename O, typename N>\r
+  N* safe_iterator<O,N>::node(void) const throw()\r
+  {\r
+    return m_body->node();\r
+  }\r
+\r
+  template<typename O, typename N>\r
+  const O* safe_iterator<O,N>::owner(void) const throw()\r
+  {\r
+    return m_body->owner();\r
+  }\r
+\r
+  // change to a null iterator - i.e. one that doees not belong to any object\r
+  // this does not affect any other iterators pointing to the same node\r
+  template<typename O, typename N>\r
+  void safe_iterator<O,N>::set_null(void) throw()\r
+  {\r
+    if (m_body->count() == 1)\r
+    {\r
+      // no aliases, so just make this null\r
+      m_body->set_null();\r
+    }\r
+    else\r
+    {\r
+      // create a new body which is null so as not to affect any other aliases\r
+      m_body->decrement();\r
+      m_body = new safe_iterator_body<O,N>(0,0);\r
+    }\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // operations for clients that do not have a master end iterator\r
+  // alternatively, have a master end iterator as part of the container\r
+  // and call constructor(master_end) or step(master_end)\r
+\r
+  // construct an end iterator\r
+  template<typename O, typename N>\r
+  safe_iterator<O,N>::safe_iterator(const O* owner) throw() :\r
+    m_body(new safe_iterator_body<O,N>(owner,0))\r
+  {\r
+  }\r
+\r
+  // change to an end iterator - e.g. as a result of incrementing off the end\r
+  template<typename O, typename N>\r
+  void safe_iterator<O,N>::set_end(void) throw()\r
+  {\r
+    if (m_body->count() == 1)\r
+    {\r
+      // no aliases, so just make this an end iterator\r
+      m_body->set_end();\r
+    }\r
+    else\r
+    {\r
+      // create a new body which is null so as not to affect any other aliases\r
+      m_body->decrement();\r
+      m_body = new safe_iterator_body<O,N>(owner(),0);\r
+    }\r
+  }\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // tests\r
+\r
+  // comparison\r
+  template<typename O, typename N>\r
+  bool safe_iterator<O,N>::equal(const safe_iterator<O,N>& right) const throw()\r
+  {\r
+    return compare(right) == 0;\r
+  }\r
+\r
+  template<typename O, typename N>\r
+  int safe_iterator<O,N>::compare(const safe_iterator<O,N>& right) const throw()\r
+  {\r
+    if (m_body == right.m_body) return 0;\r
+    return m_body->compare(right.m_body);\r
+  }\r
+\r
+  // a null iterator is one that has not been initialised with a value yet\r
+  template<typename O, typename N>\r
+  bool safe_iterator<O,N>::null(void) const throw()\r
+  {\r
+    return m_body->null();\r
+  }\r
+\r
+  // an end iterator is one that points to the end element of the list of nodes\r
+  template<typename O, typename N>\r
+  bool safe_iterator<O,N>::end(void) const throw()\r
+  {\r
+    return m_body->end();\r
+  }\r
+\r
+  // a valid iterator is one that can be dereferenced\r
+  template<typename O, typename N>\r
+  bool safe_iterator<O,N>::valid(void) const throw()\r
+  {\r
+    return m_body->valid();\r
+  }\r
+\r
+  // check the rules for a valid iterator that can be dereferenced\r
+  template<typename O, typename N>\r
+  void safe_iterator<O,N>::assert_valid(void) const throw(null_dereference,end_dereference)\r
+  {\r
+    m_body->assert_valid();\r
+  }\r
+\r
+  template<typename O, typename N>\r
+  void safe_iterator<O,N>::assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference)\r
+  {\r
+    m_body->assert_valid();\r
+    m_body->assert_owner(owner);\r
+  }\r
+\r
+  template<typename O, typename N>\r
+  void safe_iterator<O,N>::assert_non_null(void) const throw(null_dereference)\r
+  {\r
+    m_body->assert_non_null();\r
+  }\r
+\r
+  template<typename O, typename N>\r
+  void safe_iterator<O,N>::assert_owner(const O* owner) const throw(wrong_object)\r
+  {\r
+    m_body->assert_owner(owner);\r
+  }\r
+\r
+} // end namespace stlplus\r
diff --git a/src/Moof/stlplus/smart_ptr.hpp b/src/Moof/stlplus/smart_ptr.hpp
new file mode 100755 (executable)
index 0000000..d1395f5
--- /dev/null
@@ -0,0 +1,256 @@
+#ifndef STLPLUS_SMART_PTR\r
+#define STLPLUS_SMART_PTR\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+//   A smart pointer is a memory-managing pointer to an object. If you like, it\r
+//   is a zero-dimensional container. \r
+\r
+//   Assignment of smart pointers result in multiple aliases of the same object.\r
+//   The term alias is used to differentiate from conventional pointers because\r
+//   the semantics are different.\r
+\r
+//   Aliases can be turned into copies if the pointed-to class supports copying.\r
+\r
+//   The base class is smart_ptr_base which defines the common interface. Then\r
+//   there are three subclasses which have the same interface but different copy\r
+//   semantics:\r
+\r
+//   - smart_ptr        for simple types and classes which have copy constructors\r
+//   - smart_ptr_clone  for polymorphic class hierarchies which are copied using a clone method\r
+//   - smart_ptr_nocopy for any class that cannot or should not be copied\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include "containers_fixes.hpp"\r
+#include "exceptions.hpp"\r
+#include <map>\r
+#include <string>\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // internals\r
+\r
+  template<typename T> class smart_ptr_holder;\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // Base class\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename T, typename C>\r
+  class smart_ptr_base\r
+  {\r
+  public:\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // member type definitions\r
+\r
+    typedef T value_type;\r
+    typedef T& reference;\r
+    typedef const T& const_reference;\r
+    typedef C value_copy;\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // constructors and destructors\r
+\r
+    // create a null pointer\r
+    smart_ptr_base(void);\r
+\r
+    // create a pointer containing a *copy* of the object using the template parameter C\r
+    // this copy is taken because the pointer class maintains a dynamically allocated object \r
+    // and the T& may not be (usually is not) dynamically allocated\r
+    explicit smart_ptr_base(const T& data) throw(illegal_copy);\r
+\r
+    // create a pointer containing a dynamically created object\r
+    // Note: the object must be allocated *by the user* with new\r
+    // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))\r
+    explicit smart_ptr_base(T* data);\r
+\r
+    // copy constructor implements aliasing so no copy is made\r
+    explicit smart_ptr_base(const smart_ptr_base<T,C>& r);\r
+\r
+    // destructor decrements the reference count and delete only when the last reference is destroyed\r
+    ~smart_ptr_base(void);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // logical tests to see if there is anything contained in the pointer since it can be null\r
+\r
+    // there are two forms:explicit and implicit\r
+    // implicit: if(!r) or if(r)\r
+    // explicit: if(r.null()) or if(r.present())\r
+    operator bool(void) const;\r
+    bool operator!(void) const;\r
+    bool present(void) const;\r
+    bool null(void) const;\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // dereference operators and functions\r
+\r
+    // dereference the smart pointer to get the object - use in the form *p1\r
+    T& operator*(void) throw(null_dereference);\r
+    const T& operator*(void) const throw(null_dereference);\r
+\r
+    // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()\r
+    T* operator->(void) throw(null_dereference);\r
+    const T* operator->(void) const throw(null_dereference);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // explicit function forms of the above assignment and dereference operators\r
+\r
+    // set the value - note that this does a copy using the C template parameter\r
+    void set_value(const T& data) throw(illegal_copy);\r
+    // get the value\r
+    T& value(void) throw(null_dereference);\r
+    const T& value(void) const throw(null_dereference);\r
+\r
+    // set the pointer\r
+    // deletes the previous pointer and adopts the passed pointer instead\r
+    // Note: the object must be allocated *by the user* with new\r
+    // Warning: it is very easy to break the memory management with this operation\r
+    void set(T* data = 0);\r
+    // get the pointer\r
+    T* pointer(void);\r
+    const T* pointer(void) const;\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // functions to manage aliases\r
+\r
+    // make this an alias of the passed object\r
+    void alias(const smart_ptr_base<T,C>&);\r
+\r
+    // test whether two pointers point to the same object(known as aliasing the object)\r
+    // used in the form if(a.aliases(b))\r
+    bool aliases(const smart_ptr_base<T,C>&) const;\r
+\r
+    // find the number of aliases - used when you need to know whether an\r
+    // object is still referred to from elsewhere (rare!)\r
+    unsigned alias_count(void) const;\r
+\r
+    // delete the object and make the pointer null - does not make it unique\r
+    // first, so all other pointers to this will be null too\r
+    void clear(void);\r
+\r
+    // make the pointer unique and null in one step - does not affect other\r
+    // pointers that were pointing to the same object\r
+    void clear_unique(void);\r
+\r
+    //////////////////////////////////////////////////////////////////////////////\r
+    // functions that involve copying\r
+\r
+    // these functions use the copy functor passed as the template parameter C\r
+    // to copy the object with the right copy semantics. If the copy functor\r
+    // is no_copy, an exception will be thrown.\r
+\r
+    // make this pointer unique with respect to any other references to the same object\r
+    // if this pointer is already unique, it does nothing - otherwise it copies the object\r
+    void make_unique(void) throw(illegal_copy);\r
+\r
+    // make this pointer a unique copy of the parameter\r
+    // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2\r
+    void copy(const smart_ptr_base<T,C>&) throw(illegal_copy);\r
+\r
+  protected:\r
+    smart_ptr_holder<T>* m_holder;\r
+\r
+  public:\r
+    // internal use only - had to make them public because they need to be\r
+    // accessed by routines that could not be made friends\r
+    void* handle(void) const;\r
+    void make_alias(void* handle);\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // copy functors implementing the three possible copy semantics\r
+\r
+  // constructor_copy uses the copy constructor of the object - used for simple types\r
+\r
+  template <typename T>\r
+  class constructor_copy\r
+  {\r
+  public:\r
+    T* operator() (const T& from) throw()\r
+      {\r
+        return new T(from);\r
+      }\r
+  };\r
+\r
+  // clone_copy uses the clone method of the object - used for polymorphic types\r
+\r
+  template <typename T>\r
+  class clone_copy\r
+  {\r
+  public:\r
+    T* operator() (const T& from) throw()\r
+      {\r
+        return from.clone();\r
+      }\r
+  };\r
+\r
+  // no_copy throws an exception - used for types that cannot be copied\r
+\r
+  template <typename T>\r
+  class no_copy\r
+  {\r
+  public:\r
+    T* operator() (const T& from) throw(illegal_copy)\r
+      {\r
+        throw illegal_copy("no_copy functor called");\r
+        return 0;\r
+      }\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // smart_ptr        for simple types and classes which have copy constructors\r
+\r
+  template <typename T>\r
+  class smart_ptr : public smart_ptr_base<T, constructor_copy<T> >\r
+  {\r
+  public:\r
+    smart_ptr(void) {}\r
+    explicit smart_ptr(const T& data) : smart_ptr_base<T, constructor_copy<T> >(data) {}\r
+    explicit smart_ptr(T* data) : smart_ptr_base<T, constructor_copy<T> >(data) {}\r
+    smart_ptr<T>& operator=(const T& data) {set_value(data); return *this;}\r
+    smart_ptr<T>& operator=(const smart_ptr<T>& r) {alias(r); return *this;}\r
+    ~smart_ptr(void) {}\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // smart_ptr_clone  for polymorphic class hierarchies which have a clone method\r
+\r
+  template <typename T>\r
+  class smart_ptr_clone : public smart_ptr_base<T, clone_copy<T> >\r
+  {\r
+  public:\r
+    smart_ptr_clone(void) {}\r
+    explicit smart_ptr_clone(const T& data) : smart_ptr_base<T, clone_copy<T> >(data) {}\r
+    explicit smart_ptr_clone(T* data) : smart_ptr_base<T, clone_copy<T> >(data) {}\r
+    smart_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}\r
+    smart_ptr_clone<T>& operator=(const smart_ptr_clone<T>& r) {alias(r); return *this;}\r
+    ~smart_ptr_clone(void) {}\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // smart_ptr_nocopy for any class that cannot or should not be copied\r
+\r
+  template <typename T>\r
+  class smart_ptr_nocopy : public smart_ptr_base<T, no_copy<T> >\r
+  {\r
+  public:\r
+    smart_ptr_nocopy(void) {}\r
+    explicit smart_ptr_nocopy(const T& data) : smart_ptr_base<T, no_copy<T> >(data) {}\r
+    explicit smart_ptr_nocopy(T* data) : smart_ptr_base<T, no_copy<T> >(data) {}\r
+    smart_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}\r
+    smart_ptr_nocopy<T>& operator=(const smart_ptr_nocopy<T>& r) {alias(r); return *this;}\r
+    ~smart_ptr_nocopy(void) {}\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+} // end namespace stlplus\r
+\r
+#include "smart_ptr.tpp"\r
+#endif\r
diff --git a/src/Moof/stlplus/smart_ptr.tpp b/src/Moof/stlplus/smart_ptr.tpp
new file mode 100755 (executable)
index 0000000..cb1b8bb
--- /dev/null
@@ -0,0 +1,343 @@
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//   Author:    Andy Rushton\r
+//   Copyright: (c) Southampton University 1999-2004\r
+//              (c) Andy Rushton           2004-2009\r
+//   License:   BSD License, see ../docs/license.html\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+namespace stlplus\r
+{\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // internal holder data structure\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  template<typename T>\r
+  class smart_ptr_holder\r
+  {\r
+  private:\r
+    unsigned m_count;\r
+    T* m_data;\r
+\r
+    // make these private to disallow copying because the holder doesn't know how to copy\r
+    smart_ptr_holder(const smart_ptr_holder& s) :\r
+      m_count(0), m_data(0)\r
+      {\r
+      }\r
+\r
+    smart_ptr_holder& operator=(const smart_ptr_holder& s)\r
+      {\r
+        return *this;\r
+      }\r
+\r
+  public:\r
+    smart_ptr_holder(T* p = 0) : \r
+      m_count(1), m_data(p)\r
+      {\r
+      }\r
+\r
+    ~smart_ptr_holder(void)\r
+      {\r
+        clear();\r
+      }\r
+\r
+    unsigned count(void) const\r
+      {\r
+        return m_count;\r
+      }\r
+\r
+    void increment(void)\r
+      {\r
+        ++m_count;\r
+      }\r
+\r
+    bool decrement(void)\r
+      {\r
+        --m_count;\r
+        return m_count == 0;\r
+      }\r
+\r
+    bool null(void)\r
+      {\r
+        return m_data == 0;\r
+      }\r
+\r
+    void clear(void)\r
+      {\r
+        if(m_data)\r
+          delete m_data;\r
+        m_data = 0;\r
+      }\r
+\r
+    void set(T* p = 0)\r
+      {\r
+        clear();\r
+        m_data = p;\r
+      }\r
+\r
+    T*& pointer(void)\r
+      {\r
+        return m_data;\r
+      }\r
+\r
+    const T* pointer(void) const\r
+      {\r
+        return m_data;\r
+      }\r
+\r
+    T& value(void)\r
+      {\r
+        return *m_data;\r
+      }\r
+\r
+    const T& value(void) const\r
+      {\r
+        return *m_data;\r
+      }\r
+  };\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // smart_ptr_base class\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+\r
+  ////////////////////////////////////////////////////////////////////////////////\r
+  // constructors, assignments and destructors\r
+\r
+  // create a null pointer\r
+  template <typename T, typename C>\r
+  smart_ptr_base<T,C>::smart_ptr_base(void) :\r
+    m_holder(new smart_ptr_holder<T>)\r
+  {\r
+  }\r
+\r
+  // create a pointer containing a *copy* of the object pointer\r
+  template <typename T, typename C>\r
+  smart_ptr_base<T,C>::smart_ptr_base(const T& data) throw(illegal_copy) :\r
+    m_holder(new smart_ptr_holder<T>)\r
+  {\r