summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-07-11 16:54:58 +0000
committerTavian Barnes <tavianator@gmail.com>2009-07-11 16:54:58 +0000
commit249203127d1ae989785978024ef0ad25bc994384 (patch)
treedf20ef109ae5435b0fa6ccd6219fa03ab2ef1a86
parentca84516fa80cfca35da7df71ea04423780028212 (diff)
downloaddimension-249203127d1ae989785978024ef0ad25bc994384.tar.xz
Allow Array's of non-POD types through specialized Array_Element class.
-rw-r--r--libdimensionxx/dimensionxx/array.hpp212
-rw-r--r--libdimensionxx/dimensionxx/camera.hpp19
-rw-r--r--libdimensionxx/dimensionxx/canvas.hpp19
-rw-r--r--libdimensionxx/dimensionxx/color.hpp20
-rw-r--r--libdimensionxx/dimensionxx/geometry.hpp59
-rw-r--r--libdimensionxx/dimensionxx/object.hpp19
-rw-r--r--libdimensionxx/dimensionxx/scene.hpp56
-rw-r--r--libdimensionxx/scene.cpp43
-rw-r--r--tests/testsxx.cpp8
9 files changed, 351 insertions, 104 deletions
diff --git a/libdimensionxx/dimensionxx/array.hpp b/libdimensionxx/dimensionxx/array.hpp
index 84bc06b..aa1f805 100644
--- a/libdimensionxx/dimensionxx/array.hpp
+++ b/libdimensionxx/dimensionxx/array.hpp
@@ -25,9 +25,38 @@
#include <tr1/memory> // For tr1::shared_ptr
#include <cstdlib> // For size_t
+#include <vector>
namespace Dimension
{
+ // Class to store POD types, and wrapped dmnsn_* types, including polymorphic
+ // types. The non-specialized version will only handle POD types; specialize
+ // it to allow storage of classes in Array's.
+ template <typename T>
+ class Array_Element
+ {
+ public:
+ typedef T C_Type;
+
+ inline Array_Element();
+ inline Array_Element(T t);
+
+ // Specializations should implement this constructor if C_Type differs from
+ // T - but it should throw if T is a polymorphic type
+ // Array_Element(C_Type c);
+
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+
+ C_Type dmnsn() const { return m_t; }
+ T& object(C_Type* c) const { return *c; }
+
+ private:
+ T m_t;
+ };
+
// Array template class, wraps a dmnsn_array*. Copying is possible, but
// copies refer to the same object, which is reference counted. T must be
// a POD type.
@@ -35,32 +64,95 @@ namespace Dimension
class Array
{
public:
- Array();
- explicit Array(dmnsn_array* array);
+ inline Array();
+ explicit inline Array(dmnsn_array* array);
// Array(const Array& a);
~Array()
- { if (m_array && m_array.unique()) { dmnsn_delete_array(dmnsn()); } }
+ { if (m_array && m_array.unique()) { dmnsn_delete_array(dmnsn()); } }
// Array& operator=(const Array& a);
- T& operator[](std::size_t i)
- { return *reinterpret_cast<T*>(dmnsn_array_at(dmnsn(), i)); }
- const T& operator[](std::size_t i) const
- { return *reinterpret_cast<const T*>(dmnsn_array_at(dmnsn(), i)); }
+ inline T& operator[](std::size_t i);
+ inline const T& operator[](std::size_t i) const;
std::size_t size() const { return dmnsn_array_size(dmnsn()); }
- void resize(std::size_t size) { dmnsn_array_resize(dmnsn(), size); }
+ inline void resize(std::size_t size);
+
+ inline void push(T& object);
+ inline void push(const T& object); // Not valid for polymorphic types
+ inline void pop();
// Access the wrapped C object.
- dmnsn_array* dmnsn();
- const dmnsn_array* dmnsn() const;
+ inline dmnsn_array* dmnsn();
+ inline const dmnsn_array* dmnsn() const;
// Release ownership of the dmnsn_array*, needed for returning a
// dmnsn_array* from a function.
- dmnsn_array* release();
+ inline dmnsn_array* release();
private:
+ typedef typename Array_Element<T>::C_Type C_Type;
+
std::tr1::shared_ptr<dmnsn_array*> m_array;
+ std::vector<Array_Element<T> > m_elements;
+ };
+
+ // Base class for non-polymorphic wrappers
+ template <typename T, typename C>
+ class DMNSN_Array_Element
+ {
+ public:
+ typedef C C_Type;
+
+ DMNSN_Array_Element() {
+ throw Dimension_Error("Couldn't default-construct an array element.");
+ }
+
+ DMNSN_Array_Element(const T& object) : m_object(new T(object)) { }
+ DMNSN_Array_Element(C_Type c) : m_object(new T(c)) { }
+ // DMNSN_Array_Element(const DMNSN_Array_Element& ae);
+ // ~DMNSN_Array_Element();
+
+ // DMNSN_Array_Element& operator=(const DMNSN_Array_Element& ae);
+
+ C_Type dmnsn() const { return m_object->dmnsn(); }
+ T& object(C_Type* c) const { return *m_object; }
+
+ private:
+ std::tr1::shared_ptr<T> m_object;
+ };
+
+ // Base class for polymorphic wrappers
+ template <typename T, typename C>
+ class Polymorphic_Array_Element
+ {
+ public:
+ typedef C C_Type;
+
+ Polymorphic_Array_Element()
+ {
+ throw Dimension_Error("Cannot default-construct a polymorphic array"
+ " object.");
+ }
+
+ Polymorphic_Array_Element(T& object) : m_object(object.copy()) { }
+
+ Polymorphic_Array_Element(C_Type c)
+ {
+ throw Dimension_Error("Cannot wrap existing dmnsn_array* elements in"
+ " polymorphic class.");
+ }
+
+ // Polymorphic_Array_Element(const Polymorphic_Array_Element& ae);
+ // ~Polymorphic_Array_Element();
+
+ // Polymorphic_Array_Element& operator=(const Polymorphic_Array_Element& e);
+
+ C_Type dmnsn() const { return m_object->dmnsn(); }
+ T& object(C_Type* c) const { return *m_object; }
+
+ private:
+ std::tr1::shared_ptr<T> m_object;
};
// A constraint enforcing that T is a POD type by making it part of a union.
@@ -77,26 +169,110 @@ namespace Dimension
static_cast<void>(constraint); // Silence unused variable warning
}
+ // Array_Element
+
template <typename T>
- Array<T>::Array()
- : m_array(new dmnsn_array*(dmnsn_new_array(sizeof(T))))
+ inline
+ Array_Element<T>::Array_Element()
{
void (*constraint)() = &POD_constraint<T>;
static_cast<void>(constraint); // Silence unused variable warning
}
template <typename T>
- Array<T>::Array(dmnsn_array* array)
- : m_array(new dmnsn_array*(array))
+ inline
+ Array_Element<T>::Array_Element(T t)
+ : m_t(t)
{
void (*constraint)() = &POD_constraint<T>;
static_cast<void>(constraint); // Silence unused variable warning
}
+ // Array constructors
+
+ template <typename T>
+ inline
+ Array<T>::Array()
+ : m_array(new dmnsn_array*(dmnsn_new_array(sizeof(T)))) { }
+
+ template <typename T>
+ inline
+ Array<T>::Array(dmnsn_array* array)
+ : m_array(new dmnsn_array*(array))
+ {
+ m_elements.reserve(dmnsn_array_size(dmnsn()));
+ for (std::size_t i = 0; i < dmnsn_array_size(dmnsn()); ++i) {
+ C_Type* c = reinterpret_cast<C_Type*>(dmnsn_array_at(dmnsn(), i));
+ m_elements.push_back(Array_Element<T>(*c));
+ }
+ }
+
+ // Array element access
+
+ template <typename T>
+ inline T&
+ Array<T>::operator[](std::size_t i)
+ {
+ if (i >= m_elements.size()) {
+ m_elements.resize(i + 1);
+ }
+ C_Type* c = reinterpret_cast<C_Type*>(dmnsn_array_at(dmnsn(), i));
+ return m_elements[i].object(c);
+ }
+
+ template <typename T>
+ inline const T&
+ Array<T>::operator[](std::size_t i) const
+ {
+ if (i >= m_elements.size()) {
+ m_elements.resize(i + 1);
+ }
+ C_Type* c = reinterpret_cast<C_Type*>(dmnsn_array_at(dmnsn(), i));
+ return m_elements[i].object(c);
+ }
+
+ template <typename T>
+ inline void
+ Array<T>::resize(std::size_t size)
+ {
+ m_elements.resize(size);
+ dmnsn_array_resize(dmnsn(), size);
+ }
+
+ template <typename T>
+ inline void
+ Array<T>::push(T& object)
+ {
+ Array_Element<T> ae(object);
+ m_elements.push_back(ae);
+
+ C_Type c = ae.dmnsn();
+ dmnsn_array_push(dmnsn(), &c);
+ }
+
+ template <typename T>
+ inline void
+ Array<T>::push(const T& object)
+ {
+ Array_Element<T> ae(object);
+ m_elements.push_back(ae);
+
+ C_Type c = ae.dmnsn();
+ dmnsn_array_push(dmnsn(), &c);
+ }
+
+ template <typename T>
+ inline void
+ Array<T>::pop()
+ {
+ m_elements.pop();
+ dmnsn_array_resize(dmnsn_array_size(dmnsn()) - 1);
+ }
+
// Access the underlying dmnsn_array*
template <typename T>
- dmnsn_array*
+ inline dmnsn_array*
Array<T>::dmnsn()
{
if (!m_array) {
@@ -107,7 +283,7 @@ namespace Dimension
}
template <typename T>
- const dmnsn_array*
+ inline const dmnsn_array*
Array<T>::dmnsn() const
{
if (!m_array) {
@@ -119,7 +295,7 @@ namespace Dimension
// Release the dmnsn_array*, if we are the only Array holding it
template <typename T>
- dmnsn_array*
+ inline dmnsn_array*
Array<T>::release()
{
dmnsn_array* array = dmnsn();
diff --git a/libdimensionxx/dimensionxx/camera.hpp b/libdimensionxx/dimensionxx/camera.hpp
index 9b717ff..d8743ce 100644
--- a/libdimensionxx/dimensionxx/camera.hpp
+++ b/libdimensionxx/dimensionxx/camera.hpp
@@ -72,6 +72,25 @@ namespace Dimension
virtual Line ray(const Canvas& canvas, unsigned int x, unsigned int y) = 0;
};
+
+ // Array_Element specialization
+ template <>
+ class Array_Element<Camera>
+ : public Polymorphic_Array_Element<Camera, dmnsn_camera*>
+ {
+ public:
+ typedef dmnsn_camera* C_Type;
+
+ Array_Element() { }
+ Array_Element(Camera& camera)
+ : Polymorphic_Array_Element<Camera, dmnsn_camera*>(camera) { }
+ Array_Element(C_Type c)
+ : Polymorphic_Array_Element<Camera, dmnsn_camera*>(c) { }
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+ };
}
#endif /* DIMENSIONXX_CAMERA_HPP */
diff --git a/libdimensionxx/dimensionxx/canvas.hpp b/libdimensionxx/dimensionxx/canvas.hpp
index c75b100..321e1c7 100644
--- a/libdimensionxx/dimensionxx/canvas.hpp
+++ b/libdimensionxx/dimensionxx/canvas.hpp
@@ -60,6 +60,25 @@ namespace Dimension
std::tr1::shared_ptr<dmnsn_canvas*> m_canvas;
};
+
+ // Array_Element specialization
+ template <>
+ class Array_Element<Canvas>
+ : public DMNSN_Array_Element<Canvas, dmnsn_canvas*>
+ {
+ public:
+ typedef dmnsn_canvas* C_Type;
+
+ Array_Element() { }
+ Array_Element(Canvas& canvas)
+ : DMNSN_Array_Element<Canvas, dmnsn_canvas*>(canvas) { }
+ Array_Element(C_Type c)
+ : DMNSN_Array_Element<Canvas, dmnsn_canvas*>(c) { }
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+ };
}
#endif /* DIMENSIONXX_CANVAS_HPP */
diff --git a/libdimensionxx/dimensionxx/color.hpp b/libdimensionxx/dimensionxx/color.hpp
index 635e141..7d804f5 100644
--- a/libdimensionxx/dimensionxx/color.hpp
+++ b/libdimensionxx/dimensionxx/color.hpp
@@ -200,6 +200,26 @@ namespace Dimension
dmnsn_sRGB m_RGB;
};
+ // Array_Element specialization
+ template <>
+ class Array_Element<Color>
+ : public DMNSN_Array_Element<Color, dmnsn_color>
+ {
+ public:
+ typedef dmnsn_color C_Type;
+
+ Array_Element()
+ : DMNSN_Array_Element<Color, dmnsn_color>(Color()) { }
+ Array_Element(Color& color)
+ : DMNSN_Array_Element<Color, dmnsn_color>(color) { }
+ Array_Element(C_Type c)
+ : DMNSN_Array_Element<Color, dmnsn_color>(c) { }
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+ };
+
// Color inline constructors
inline Color::Color(const CIE_XYZ& XYZ)
diff --git a/libdimensionxx/dimensionxx/geometry.hpp b/libdimensionxx/dimensionxx/geometry.hpp
index fdeccf0..4da6f47 100644
--- a/libdimensionxx/dimensionxx/geometry.hpp
+++ b/libdimensionxx/dimensionxx/geometry.hpp
@@ -134,6 +134,65 @@ namespace Dimension
dmnsn_line m_line;
};
+ // Array_Element specializations
+
+ template <>
+ class Array_Element<Matrix>
+ : public DMNSN_Array_Element<Matrix, dmnsn_matrix>
+ {
+ public:
+ typedef dmnsn_matrix C_Type;
+
+ Array_Element()
+ : DMNSN_Array_Element<Matrix, dmnsn_matrix>(Matrix()) { }
+ Array_Element(Matrix& matrix)
+ : DMNSN_Array_Element<Matrix, dmnsn_matrix>(matrix) { }
+ Array_Element(C_Type c)
+ : DMNSN_Array_Element<Matrix, dmnsn_matrix>(c) { }
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+ };
+
+ template <>
+ class Array_Element<Vector>
+ : public DMNSN_Array_Element<Vector, dmnsn_vector>
+ {
+ public:
+ typedef dmnsn_vector C_Type;
+
+ Array_Element()
+ : DMNSN_Array_Element<Vector, dmnsn_vector>(Vector()) { }
+ Array_Element(Vector& vector)
+ : DMNSN_Array_Element<Vector, dmnsn_vector>(vector) { }
+ Array_Element(C_Type c)
+ : DMNSN_Array_Element<Vector, dmnsn_vector>(c) { }
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+ };
+
+ template <>
+ class Array_Element<Line>
+ : public DMNSN_Array_Element<Line, dmnsn_line>
+ {
+ public:
+ typedef dmnsn_line C_Type;
+
+ Array_Element()
+ : DMNSN_Array_Element<Line, dmnsn_line>(Line()) { }
+ Array_Element(Line& line)
+ : DMNSN_Array_Element<Line, dmnsn_line>(line) { }
+ Array_Element(C_Type c)
+ : DMNSN_Array_Element<Line, dmnsn_line>(c) { }
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+ };
+
// Matrix operators
inline Matrix
diff --git a/libdimensionxx/dimensionxx/object.hpp b/libdimensionxx/dimensionxx/object.hpp
index 8283c9c..30dadf8 100644
--- a/libdimensionxx/dimensionxx/object.hpp
+++ b/libdimensionxx/dimensionxx/object.hpp
@@ -78,6 +78,25 @@ namespace Dimension
virtual Array<double> intersections(const Line& l) = 0;
virtual bool inside(const Vector& point) = 0;
};
+
+ // Array_Element specialization
+ template <>
+ class Array_Element<Object>
+ : public Polymorphic_Array_Element<Object, dmnsn_object*>
+ {
+ public:
+ typedef dmnsn_object* C_Type;
+
+ Array_Element() { }
+ Array_Element(Object& object)
+ : Polymorphic_Array_Element<Object, dmnsn_object*>(object) { }
+ Array_Element(C_Type c)
+ : Polymorphic_Array_Element<Object, dmnsn_object*>(c) { }
+ // Array_Element(const Array_Element& ae);
+ // ~Array_Element();
+
+ // Array_Element& operator=(const Array_Element& ae);
+ };
}
#endif /* DIMENSIONXX_OBJECT_HPP */
diff --git a/libdimensionxx/dimensionxx/scene.hpp b/libdimensionxx/dimensionxx/scene.hpp
index acb2cb1..8b5270c 100644
--- a/libdimensionxx/dimensionxx/scene.hpp
+++ b/libdimensionxx/dimensionxx/scene.hpp
@@ -25,15 +25,10 @@
namespace Dimension
{
- // Iterator class for scene objects - never invalidated unless removed
- class Scene_Iterator;
-
// Base scene class. Wraps a dmnsn_scene*.
class Scene
{
public:
- typedef Scene_Iterator Iterator;
-
// Allocate a dmnsn_scene*
Scene(const Color& background, Camera& camera, Canvas& canvas);
@@ -43,19 +38,13 @@ namespace Dimension
~Scene();
// Element access
- Color background() const;
- Camera& camera();
- const Camera& camera() const;
- Canvas& canvas();
- const Canvas& canvas() const;
-
- // Object access
-
- Iterator begin();
- Iterator end();
-
- void push_object(Object& object);
- void remove_object(Iterator i);
+ Color background() const;
+ Camera& camera();
+ const Camera& camera() const;
+ Canvas& canvas();
+ const Canvas& canvas() const;
+ Array<Object>& objects();
+ const Array<Object>& objects() const;
// Access the wrapped C object.
dmnsn_scene* dmnsn();
@@ -68,36 +57,7 @@ namespace Dimension
std::tr1::shared_ptr<dmnsn_scene*> m_scene;
std::tr1::shared_ptr<Camera> m_camera;
std::tr1::shared_ptr<Canvas> m_canvas;
- std::list<std::tr1::shared_ptr<Object> > m_objects;
- };
-
- class Scene_Iterator
- {
- typedef std::list<std::tr1::shared_ptr<Object> >::iterator Iterator;
-
- public:
- Scene_Iterator(Iterator i)
- : m_i(i) { }
- // Scene_Iterator(const Scene_Iterator& i);
- // ~Scene_Iterator();
-
- // Scene_Iterator& operator=(const Scene_Iterator& i);
-
- Object& operator*() const { return **m_i; }
- Object* operator->() const { return &**m_i; }
-
- bool operator==(Scene_Iterator i) const { return m_i == i.m_i; }
- bool operator!=(Scene_Iterator i) const { return m_i != i.m_i; }
-
- Scene_Iterator& operator++() { ++m_i; return *this; }
- Scene_Iterator operator++(int) { return Scene_Iterator(m_i++); }
- Scene_Iterator& operator--() { --m_i; return *this; }
- Scene_Iterator operator--(int) { return Scene_Iterator(m_i--); }
-
- Iterator iterator() const { return m_i; }
-
- private:
- Iterator m_i;
+ Array<Object> m_objects;
};
}
diff --git a/libdimensionxx/scene.cpp b/libdimensionxx/scene.cpp
index 1bff351..f41f3b5 100644
--- a/libdimensionxx/scene.cpp
+++ b/libdimensionxx/scene.cpp
@@ -25,7 +25,7 @@ namespace Dimension
// Allocate a dmnsn_scene
Scene::Scene(const Color& background, Camera& camera, Canvas& canvas)
: m_scene(new dmnsn_scene*(dmnsn_new_scene())), m_camera(camera.copy()),
- m_canvas(new Canvas(canvas))
+ m_canvas(new Canvas(canvas)), m_objects(dmnsn()->objects)
{
if (!dmnsn()) {
throw Dimension_Error("Couldn't allocate scene.");
@@ -40,6 +40,7 @@ namespace Dimension
Scene::~Scene()
{
if (m_scene.unique()) {
+ m_objects.release();
dmnsn_delete_scene(dmnsn());
}
}
@@ -76,44 +77,16 @@ namespace Dimension
return *m_canvas;
}
- // An iterator to the beginning of the object list
- Scene::Iterator
- Scene::begin()
+ Array<Object>&
+ Scene::objects()
{
- return Iterator(m_objects.begin());
+ return m_objects;
}
- // An iterator one past the end of the object list
- Scene::Iterator
- Scene::end()
+ const Array<Object>&
+ Scene::objects() const
{
- return Iterator(m_objects.end());
- }
-
- // Add an object
- void
- Scene::push_object(Object& object)
- {
- m_objects.push_back(std::tr1::shared_ptr<Object>(object.copy()));
- dmnsn_object* cobject = object.dmnsn();
- dmnsn_array_push(dmnsn()->objects, &cobject);
- }
-
- // Remove an object
- void
- Scene::remove_object(Iterator i)
- {
- // Find it in the dmnsn_array* of objects and remove it
- for (unsigned int j = 0; j < dmnsn_array_size(dmnsn()->objects); ++j) {
- dmnsn_object* cobject;
- dmnsn_array_get(dmnsn()->objects, j, &cobject);
- if (cobject == i->dmnsn()) {
- dmnsn_array_remove(dmnsn()->objects, j);
- break;
- }
- }
- // Remove it from the std::list
- m_objects.erase(i.iterator());
+ return m_objects;
}
// Access the wrapped C object.
diff --git a/tests/testsxx.cpp b/tests/testsxx.cpp
index aaeb546..b4c28d9 100644
--- a/tests/testsxx.cpp
+++ b/tests/testsxx.cpp
@@ -38,7 +38,9 @@ namespace Dimension
Matrix::rotation(Vector(0.0, 1.0, 0.0))
* Matrix::translation(Vector(0.0, 0.0, -4.0))
* Matrix::scale(
- Vector(static_cast<double>(canvas.width())/canvas.height(), 1.0, 1.0)
+ Vector(static_cast<double>(canvas.width())/canvas.height(),
+ 1.0,
+ 1.0)
)
);
@@ -49,11 +51,11 @@ namespace Dimension
Sphere sphere;
sphere.trans(inverse(Matrix::scale(Vector(1.25, 1.25, 1.25))));
- scene.push_object(sphere);
+ scene.objects().push(sphere);
Cube cube;
cube.trans(inverse(Matrix::rotation(Vector(0.75, 0.0, 0.0))));
- scene.push_object(cube);
+ scene.objects().push(cube);
return scene;
}