diff options
author | Tavian Barnes <tavianator@gmail.com> | 2009-07-11 16:54:58 +0000 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2009-07-11 16:54:58 +0000 |
commit | 249203127d1ae989785978024ef0ad25bc994384 (patch) | |
tree | df20ef109ae5435b0fa6ccd6219fa03ab2ef1a86 /libdimensionxx/dimensionxx/array.hpp | |
parent | ca84516fa80cfca35da7df71ea04423780028212 (diff) | |
download | dimension-249203127d1ae989785978024ef0ad25bc994384.tar.xz |
Allow Array's of non-POD types through specialized Array_Element class.
Diffstat (limited to 'libdimensionxx/dimensionxx/array.hpp')
-rw-r--r-- | libdimensionxx/dimensionxx/array.hpp | 212 |
1 files changed, 194 insertions, 18 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(); |