/* * Copyright (c) 2005-2006, David Fahlander * 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. Neither the name of slurk.org nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * 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 OWNER 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 IFR_V1_ARRAY_HPP_ #define IFR_V1_ARRAY_HPP_ #include // assert #include // size_t, malloc #include // memset, memcpy, memcmp #include // bad_alloc #include // auto_ptr #include "p.hpp" #include "colltraits.hpp" /* */ namespace ifr { namespace v1 { using std::size_t; using std::malloc; using std::memset; using std::bad_alloc; using std::memcpy; using std::memcmp; using std::auto_ptr; /* Base of refcounted array types. Defines it's own new and delete operators that allocated memory on heap both for the class itself and for the number of items in the array. */ template class RCArrayBase : public refcounted { protected: size_t size_; private: // Hide the normal new and delete operators. void* operator new (size_t); void* operator new[] (size_t); void operator delete[] (void*); public: // Allocate space for both this class and the array that it holds. void* operator new (size_t object_size, size_t array_size) throw (bad_alloc) { assert (object_size == sizeof(C)); (void) object_size; // Remove warning about unreferenced variable C* p = reinterpret_cast ( malloc (sizeof(C) + (array_size * sizeof(ItemType)))); if (p == NULL) { throw bad_alloc (); } // This is kind of a pre-constructor that sets the size value since // it is not accessable in constructor. p->size_ = array_size; return p; } void operator delete (void* p, size_t) { free (p); } void operator delete (void* p) { operator delete (p, 0); } virtual void destroy() { delete static_cast (this); } protected: // Make impossible for end-users to create an instance of us except through create() or // clone() methods on our subclasses. RCArrayBase(){} private: // Make non-copyable since we have a dynamic operator new. // Instead, our subclasses can be cloneable through their clone() method. RCArrayBase(const RCArrayBase& other); RCArrayBase& operator = (const RCArrayBase& other); public: ItemType* c_array() { assert (this != NULL); return reinterpret_cast (reinterpret_cast (this) + sizeof(C)); } const ItemType* c_array() const { assert (this != NULL); return reinterpret_cast (reinterpret_cast (this) + sizeof(C)); } ItemType& at (size_t pos) { assert (this != NULL); return c_array()[pos]; } const ItemType& at (size_t pos) const { assert (this != NULL); return c_array()[pos]; } size_t size() const { assert (this != NULL); return size_; } }; /* Reference counted array template. Used by the Array and array class templates. This general template class is for arrays items of non-primitive types. A specialization exists for array items of primitive types. */ template < typename T, typename ItemType = typename colltraits::ItemType, bool value_based = is_primitive::value > class RCArray : public RCArrayBase, ItemType> { public: RCArray() { // Zero fill (instead of calling default constuctor of all items (p)) // size_ member was initialized by new operator. memset ( this->c_array(), 0, this->size_ * sizeof(ItemType)); } ~RCArray() { if (this->size_) { // Call destructor of the smart pointers for (size_t i=0; isize_; ++i) { this->c_array()[i].ItemType::~ItemType(); } } } static RCArray* create (size_t size) { return new (size) RCArray(); } RCArray* clone() const { assert (this != NULL); auto_ptr retval (new (this->size_) RCArray ()); ItemType* retarray = retval->c_array(); const ItemType* thisarray = this->c_array(); // Copy the smart pointers only for (size_t i=0; isize_; ++i) { retarray[i] = thisarray[i]; } return retval.release(); } int compare (const RCArray& other) const { // Compare the smart pointers only for (size_t i=0; i < this->size(); ++i) { if (this->at(i) == other.at(i)) { continue; } else if (this->at(i) < other.at(1)) { return -1; } else { return 1; } } return 0; } }; /** */ enum SecureMode { NOT_SECURE, SECURE }; /* Reference counted array template specialization for primitive types. Used by the Array and array class templates. */ template class RCArray : public RCArrayBase, ItemType> { private: SecureMode secmode_; public: RCArray(SecureMode secmode = NOT_SECURE) : secmode_(secmode) {} static RCArray* create (size_t size) { return new (size) RCArray(); } static RCArray* create (size_t size, SecureMode secmode) { return new (size) RCArray(secmode); } ~RCArray() { if (secmode_ && this->size_) { // Zero memory const void* p = this->c_array(); memset ( const_cast(p), 0, this->size_ * sizeof(T)); // Force no compiler optimization: *(volatile char*)p = *(volatile char*)p; } } RCArray* clone() const { assert (this != NULL); auto_ptr retval (new (this->size_) RCArray (secmode_)); memcpy ( const_cast(retval->c_array()), this->c_array(), this->size_ * sizeof(ItemType)); return retval.release(); } bool isSecure() const { assert (this != NULL); return (secmode_ == SECURE); } int compare (const RCArray& other) const { for (size_t i=0; i < this->size(); ++i) { if (this->at(i) == other.at(i)) { continue; } else if (this->at(i) < other.at(1)) { return -1; } else { return 1; } } return 0; } }; /* Forward declaration of the array template. Needed for the clone() methods. */ template < typename T, typename ItemType = typename colltraits::ItemType, bool is_primitive = is_primitive::value> class array; /* Specialization of colltraits for array. Needed for collections where the item type is array, for example array >. This specialization states that collections of array<> will store each item as a array<> and not as a p< array<> >. */ template struct colltraits, false> { typedef array ItemType; typedef const array& InArgType; }; /* Friend class helping to access the private a_ member in array. I want the a_ member to be private so that no one uses it by accident. Still, when people know what the're doing, it should be possible to access the member using this help class. */ struct array_help { template inline static const p >& get_array ( const array& arr) { return arr.a_; } template inline static p >& get_array ( array& arr) { return arr.a_; } template inline static int get_ptrdiff (const array& arr) { return arr.ptrdiff_; } template inline static void set_ptrdiff ( array& arr, int ptrdiff) { arr.ptrdiff_ = ptrdiff; } }; /* Base help class for the array template. The class is here to define the common interface between array and array. */ template class array_base { friend struct array_help; public: typedef RCArray ArrayClass; protected: // The only member - a smart pointer to an array instance. p a_; public: // Constructors inline array_base (){} inline array_base (const p& other) : a_ (other) {} // Methods inline size_t size() const { return a_->size(); } inline int compare (const array_base& other) const { return a_->compare (*other.a_); } // Operators inline bool operator == (const ArrayClass* arrayClass) const { return a_ == arrayClass; } inline bool operator != (const ArrayClass* arrayClass) const { return a_ != arrayClass; } inline bool operator < (const array_base& other) const { return a_->compare (*other.a_) < 0; } inline bool operator > (const array_base& other) const { return a_->compare (*other.a_) > 0; } inline bool operator == (const array_base& other) const { return a_->compare (*other.a_) == 0; } inline bool operator != (const array_base& other) const { return a_->compare (*other.a_) != 0; } }; /* The array template. This is the generic array class where all items are p. Note that a specialization exists for primitive types. */ template class array : public array_base { friend struct array_help; public: typedef RCArray ArrayClass; typedef array_base Base; private: int ptrdiff_; public: // Constructors inline array () : ptrdiff_(0) {} inline explicit array (size_t size) : Base ((size ? ArrayClass::create(size) : NULL)), ptrdiff_(0) {} inline array (const NullClass*) : Base (NULL), ptrdiff_(0) {} //inline array (const p& other) : Base (other), ptrdiff_(0) {} inline array (const array& other) : Base (other), ptrdiff_(other.ptrdiff_) {} // Template based Copy Constructor template inline array (const array, false>& other) : Base (reinterpret_cast (other)) { // Check compile time that DerivedItem is derived from T T* tmp = reinterpret_cast(NULL); // Check compile-time that T and DerivedItem are compatible smartptr_assert_type_compatibility (tmp, tmp, (DerivedItem*)NULL); // Set ptrdiff_ according to the cast made ptrdiff_ = reinterpret_cast(other).ptrdiff_ + ptr_diff::value(); } inline array (const p& other, int ptrdiff) : Base (other), ptrdiff_(ptrdiff) {} public: // Template based operator = template inline array& operator = (const array, false>& other) { // Check compile time that DerivedItem is derived from T T* tmp = reinterpret_cast(NULL); // Check compile-time that T and DerivedItem are compatible smartptr_assert_type_compatibility (tmp, tmp, (DerivedItem*)NULL); // Set ptrdiff_ according to the cast made ptrdiff_ = reinterpret_cast(other).ptrdiff_ + ptr_diff::value(); this->a_ = reinterpret_cast(other).a_; return *this; } inline array& operator = (const NullClass* nullclass) { assert (nullclass == NULL); this->a_ = NULL; return *this; } inline CollItemRef operator [] (size_t pos) const { return CollItemRef (getptr(this->a_), this->a_->c_array() + pos, ptrdiff_); } // Methods inline CollItemRef at (size_t pos) const { return CollItemRef (getptr(this->a_), this->a_->c_array() + pos, ptrdiff_); } inline array clone() const { return array (this->a_->clone(), ptrdiff_); } }; /* The array template specialized for primitive types. */ template class array : public array_base { public: typedef RCArray ArrayClass; typedef array_base Base; public: // Ordinary Constructors inline array () {} inline explicit array (size_t size) : Base ((size ? ArrayClass::create (size) : NULL)) {} inline array (size_t size, SecureMode secmode) : Base (ArrayClass::create(size, secmode)) {} inline array (const NullClass*) : Base (NULL) {} inline array (const p& other) : Base (other) {} inline array (const array& other) : Base (other) {} // Constructor that copies content from supplied C array. array (const ItemType* initialData, size_t size, SecureMode secmode = NOT_SECURE) : Base ((size ? ArrayClass::create (size, secmode) : NULL)) { if (size) { memcpy (const_cast::Type*> (c_array()), initialData, size * sizeof(ItemType)); } } inline array& operator = (const NullClass* nullclass) { assert (nullclass == NULL); this->a_ = NULL; return *this; } inline ItemType& operator [] (size_t pos) { return this->a_->at(pos); } inline const ItemType& operator [] (size_t pos) const { return this->a_->at(pos); } // Methods inline ItemType& at (size_t pos) { return this->a_->at (pos); } inline const ItemType& at (size_t pos) const { return this->a_->at (pos); } inline array clone() const { return this->a_->clone(); } inline ItemType* c_array() { return this->a_->c_array(); } inline const ItemType* c_array() const { return this->a_->c_array(); } }; /** */ template long getrefcount (const array& parray) { return getrefcount (array_help::get_array (parray)); } /** */ template void addref (array& parray) { addref (array_help::get_array (parray)); } /** */ template void release (array& parray) { release (array_help::get_array (parray)); } /** array_cast. Similar to static_cast but for arrays. Usage: array b; array d = array_cast (b); */ template inline array, false> array_cast (const array, false>& baseArray) { // Check compile-time that T and Base are compatible // Also check that the cast is valid using static_cast but allowing casting between const/non-const. smartptr_assert_type_compatibility ( (Base*)NULL, (Base*)NULL, static_cast ((Base*)(0))) // <-- Checks that cast is valid using static_cast + const_cast ; // Cast and adjust ptrdiff in returned array (making our own static_cast<>-similar implementaion) return array ( reinterpret_cast >&> (array_help::get_array (baseArray)), array_help::get_ptrdiff (baseArray) - ptr_diff::value()); } /** array_cast for arrays of primitive types. Usage: array a; array b = array_cast (a); */ template inline array& array_cast (const array& otherArray) { ERROR_CANNOT_CAST_PRIMITIVE_ARRAYS(otherArray); // Not implemented. } /** */ template const T* getptr (const array& a) { return (a != NULL ? a.c_array() : NULL); } /** */ template T* getptr (array& a) { return (a != NULL ? a.c_array() : NULL); } } } #endif // IFR_V1_ARRAY_HPP_