From 249203127d1ae989785978024ef0ad25bc994384 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 11 Jul 2009 16:54:58 +0000 Subject: Allow Array's of non-POD types through specialized Array_Element class. --- libdimensionxx/dimensionxx/array.hpp | 212 +++++++++++++++++++++++++++++--- libdimensionxx/dimensionxx/camera.hpp | 19 +++ libdimensionxx/dimensionxx/canvas.hpp | 19 +++ libdimensionxx/dimensionxx/color.hpp | 20 +++ libdimensionxx/dimensionxx/geometry.hpp | 59 +++++++++ libdimensionxx/dimensionxx/object.hpp | 19 +++ libdimensionxx/dimensionxx/scene.hpp | 56 ++------- libdimensionxx/scene.cpp | 43 ++----- tests/testsxx.cpp | 8 +- 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 // For tr1::shared_ptr #include // For size_t +#include 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 + 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(dmnsn_array_at(dmnsn(), i)); } - const T& operator[](std::size_t i) const - { return *reinterpret_cast(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::C_Type C_Type; + std::tr1::shared_ptr m_array; + std::vector > m_elements; + }; + + // Base class for non-polymorphic wrappers + template + 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 m_object; + }; + + // Base class for polymorphic wrappers + template + 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 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(constraint); // Silence unused variable warning } + // Array_Element + template - Array::Array() - : m_array(new dmnsn_array*(dmnsn_new_array(sizeof(T)))) + inline + Array_Element::Array_Element() { void (*constraint)() = &POD_constraint; static_cast(constraint); // Silence unused variable warning } template - Array::Array(dmnsn_array* array) - : m_array(new dmnsn_array*(array)) + inline + Array_Element::Array_Element(T t) + : m_t(t) { void (*constraint)() = &POD_constraint; static_cast(constraint); // Silence unused variable warning } + // Array constructors + + template + inline + Array::Array() + : m_array(new dmnsn_array*(dmnsn_new_array(sizeof(T)))) { } + + template + inline + Array::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(dmnsn_array_at(dmnsn(), i)); + m_elements.push_back(Array_Element(*c)); + } + } + + // Array element access + + template + inline T& + Array::operator[](std::size_t i) + { + if (i >= m_elements.size()) { + m_elements.resize(i + 1); + } + C_Type* c = reinterpret_cast(dmnsn_array_at(dmnsn(), i)); + return m_elements[i].object(c); + } + + template + inline const T& + Array::operator[](std::size_t i) const + { + if (i >= m_elements.size()) { + m_elements.resize(i + 1); + } + C_Type* c = reinterpret_cast(dmnsn_array_at(dmnsn(), i)); + return m_elements[i].object(c); + } + + template + inline void + Array::resize(std::size_t size) + { + m_elements.resize(size); + dmnsn_array_resize(dmnsn(), size); + } + + template + inline void + Array::push(T& object) + { + Array_Element ae(object); + m_elements.push_back(ae); + + C_Type c = ae.dmnsn(); + dmnsn_array_push(dmnsn(), &c); + } + + template + inline void + Array::push(const T& object) + { + Array_Element ae(object); + m_elements.push_back(ae); + + C_Type c = ae.dmnsn(); + dmnsn_array_push(dmnsn(), &c); + } + + template + inline void + Array::pop() + { + m_elements.pop(); + dmnsn_array_resize(dmnsn_array_size(dmnsn()) - 1); + } + // Access the underlying dmnsn_array* template - dmnsn_array* + inline dmnsn_array* Array::dmnsn() { if (!m_array) { @@ -107,7 +283,7 @@ namespace Dimension } template - const dmnsn_array* + inline const dmnsn_array* Array::dmnsn() const { if (!m_array) { @@ -119,7 +295,7 @@ namespace Dimension // Release the dmnsn_array*, if we are the only Array holding it template - dmnsn_array* + inline dmnsn_array* Array::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 + : public Polymorphic_Array_Element + { + public: + typedef dmnsn_camera* C_Type; + + Array_Element() { } + Array_Element(Camera& camera) + : Polymorphic_Array_Element(camera) { } + Array_Element(C_Type c) + : Polymorphic_Array_Element(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 m_canvas; }; + + // Array_Element specialization + template <> + class Array_Element + : public DMNSN_Array_Element + { + public: + typedef dmnsn_canvas* C_Type; + + Array_Element() { } + Array_Element(Canvas& canvas) + : DMNSN_Array_Element(canvas) { } + Array_Element(C_Type c) + : DMNSN_Array_Element(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 + : public DMNSN_Array_Element + { + public: + typedef dmnsn_color C_Type; + + Array_Element() + : DMNSN_Array_Element(Color()) { } + Array_Element(Color& color) + : DMNSN_Array_Element(color) { } + Array_Element(C_Type c) + : DMNSN_Array_Element(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 + : public DMNSN_Array_Element + { + public: + typedef dmnsn_matrix C_Type; + + Array_Element() + : DMNSN_Array_Element(Matrix()) { } + Array_Element(Matrix& matrix) + : DMNSN_Array_Element(matrix) { } + Array_Element(C_Type c) + : DMNSN_Array_Element(c) { } + // Array_Element(const Array_Element& ae); + // ~Array_Element(); + + // Array_Element& operator=(const Array_Element& ae); + }; + + template <> + class Array_Element + : public DMNSN_Array_Element + { + public: + typedef dmnsn_vector C_Type; + + Array_Element() + : DMNSN_Array_Element(Vector()) { } + Array_Element(Vector& vector) + : DMNSN_Array_Element(vector) { } + Array_Element(C_Type c) + : DMNSN_Array_Element(c) { } + // Array_Element(const Array_Element& ae); + // ~Array_Element(); + + // Array_Element& operator=(const Array_Element& ae); + }; + + template <> + class Array_Element + : public DMNSN_Array_Element + { + public: + typedef dmnsn_line C_Type; + + Array_Element() + : DMNSN_Array_Element(Line()) { } + Array_Element(Line& line) + : DMNSN_Array_Element(line) { } + Array_Element(C_Type c) + : DMNSN_Array_Element(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 intersections(const Line& l) = 0; virtual bool inside(const Vector& point) = 0; }; + + // Array_Element specialization + template <> + class Array_Element + : public Polymorphic_Array_Element + { + public: + typedef dmnsn_object* C_Type; + + Array_Element() { } + Array_Element(Object& object) + : Polymorphic_Array_Element(object) { } + Array_Element(C_Type c) + : Polymorphic_Array_Element(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& objects(); + const Array& objects() const; // Access the wrapped C object. dmnsn_scene* dmnsn(); @@ -68,36 +57,7 @@ namespace Dimension std::tr1::shared_ptr m_scene; std::tr1::shared_ptr m_camera; std::tr1::shared_ptr m_canvas; - std::list > m_objects; - }; - - class Scene_Iterator - { - typedef std::list >::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 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& + 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& + 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.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(canvas.width())/canvas.height(), 1.0, 1.0) + Vector(static_cast(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; } -- cgit v1.2.3