| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef _DECAF_LANG_ARRAYPOINTER_H_ |
| #define _DECAF_LANG_ARRAYPOINTER_H_ |
| |
| #include <decaf/util/Config.h> |
| #include <decaf/lang/System.h> |
| #include <decaf/lang/exceptions/NullPointerException.h> |
| #include <decaf/lang/exceptions/IndexOutOfBoundsException.h> |
| #include <decaf/lang/exceptions/IllegalArgumentException.h> |
| #include <decaf/util/concurrent/atomic/AtomicInteger.h> |
| #include <decaf/util/Comparator.h> |
| #include <decaf/util/Arrays.h> |
| #include <memory> |
| #include <typeinfo> |
| #include <algorithm> |
| |
| namespace decaf { |
| namespace lang { |
| |
| /** |
| * Decaf's implementation of a Smart Pointer that is a template on a Type |
| * and is Thread Safe if the default Reference Counter is used. This Pointer |
| * type allows for the substitution of different Reference Counter implementations |
| * which provide a means of using invasive reference counting if desired using |
| * a custom implementation of <code>ReferenceCounter</code>. |
| * <p> |
| * The Decaf smart pointer provide comparison operators for comparing Pointer |
| * instances in the same manner as normal pointer, except that it does not provide |
| * an overload of operators ( <, <=, >, >= ). To allow use of a Pointer in a STL |
| * container that requires it, Pointer provides an implementation of std::less. |
| * |
| * @since 1.0 |
| */ |
| template< typename T > |
| class ArrayPointer { |
| private: |
| |
| struct ArrayData { |
| private: |
| |
| ArrayData(const ArrayData&); |
| ArrayData& operator= (const ArrayData&); |
| |
| public: |
| |
| T* value; |
| int length; |
| decaf::util::concurrent::atomic::AtomicInteger refs; |
| |
| ArrayData() : value(NULL), length(0), refs(1) {} |
| ArrayData(T* value, int length) : value(value), length(length), refs(1) { |
| if( value != NULL && length <= 0 ) { |
| throw decaf::lang::exceptions::IllegalArgumentException( |
| __FILE__, __LINE__, "Non-NULL array pointer cannot have a size <= zero" ); |
| } |
| |
| if( value == NULL && length > 0 ) { |
| throw decaf::lang::exceptions::IllegalArgumentException( |
| __FILE__, __LINE__, "NULL array pointer cannot have a size > zero" ); |
| } |
| } |
| |
| bool release() { |
| if (this->refs.decrementAndGet() < 1) { |
| return true; |
| } |
| return false; |
| } |
| }; |
| |
| typedef void (*deletionFuncPtr)(ArrayData* p); |
| |
| private: |
| |
| ArrayData* array; |
| |
| // Pointer to our internal delete function, allows incompletes. |
| deletionFuncPtr onDelete; |
| |
| public: |
| |
| typedef T* PointerType; // type returned by operator-> |
| typedef T& ReferenceType; // type returned by operator* |
| typedef const T& ConstReferenceType; // type returned by const operator* |
| |
| public: |
| |
| /** |
| * Default Constructor |
| * |
| * Initialized the contained array pointer to NULL, using the subscript operator |
| * results in an exception unless reset to contain a real value. |
| */ |
| ArrayPointer() : array(new ArrayData()), onDelete(onDeleteFunc) {} |
| |
| /** |
| * Create a new ArrayPointer instance and allocates an internal array that is sized |
| * using the passed in size value. |
| * |
| * @param size |
| * The size of the array to allocate for this ArrayPointer instance. |
| */ |
| ArrayPointer(int size) : array(NULL), onDelete(onDeleteFunc) { |
| |
| if (size == 0) { |
| return; |
| } |
| |
| try { |
| T* value = new T[size]; |
| this->array = new ArrayData(value, size); |
| decaf::util::Arrays::fill(value, size, 0, size, T()); |
| } catch (std::exception& ex) { |
| throw ex; |
| } catch (...) { |
| throw std::bad_alloc(); |
| } |
| } |
| |
| /** |
| * Create a new ArrayPointer instance and allocates an internal array that is sized |
| * using the passed in size value. The array elements are initialized with the given |
| * value. |
| * |
| * @param size |
| * The size of the array to allocate for this ArrayPointer instance. |
| * @param fillWith |
| * The value to initialize each element of the newly allocated array with. |
| */ |
| ArrayPointer(int size, const T& fillWith) : array(NULL), onDelete(onDeleteFunc) { |
| |
| if (size == 0) { |
| return; |
| } |
| |
| try { |
| T* value = new T[size]; |
| decaf::util::Arrays::fill(value, size, 0, size, fillWith); |
| this->array = new ArrayData(value, size); |
| } catch (std::exception& ex) { |
| throw ex; |
| } catch (...) { |
| throw std::bad_alloc(); |
| } |
| } |
| |
| /** |
| * Explicit Constructor, creates an ArrayPointer that contains value with a |
| * single reference. This object now has ownership until a call to release. |
| * |
| * @param value |
| * The pointer to the instance of the array we are taking ownership of. |
| * @param size |
| * The size of the array this object is taking ownership of. |
| */ |
| explicit ArrayPointer(const PointerType value, int size) : array(NULL), onDelete(onDeleteFunc) { |
| |
| try { |
| this->array = new ArrayData(value, size); |
| } catch (std::exception& ex) { |
| throw ex; |
| } catch (...) { |
| throw std::bad_alloc(); |
| } |
| } |
| |
| /** |
| * Copy constructor. Copies the value contained in the ArrayPointer to the new |
| * instance and increments the reference counter. |
| */ |
| ArrayPointer(const ArrayPointer& value) : array(value.array), onDelete(onDeleteFunc) { |
| this->array->refs.incrementAndGet(); |
| } |
| |
| virtual ~ArrayPointer() { |
| if (this->array->release() == true) { |
| onDelete(this->array); |
| } |
| } |
| |
| /** |
| * Resets the ArrayPointer to hold the new value. Before the new value is stored |
| * reset checks if the old value should be destroyed and if so calls delete. |
| * Call reset with a value of NULL is supported and acts to set this Pointer |
| * to a NULL pointer. |
| * |
| * @param value |
| * The new array pointer value to contain. |
| * @param size |
| * The size of the new array value this object now contains. |
| */ |
| void reset(T* value, int size = 0) { |
| ArrayPointer(value, size).swap(*this); |
| } |
| |
| /** |
| * Releases the Pointer held and resets the internal pointer value to Null. This method |
| * is not guaranteed to be safe if the Pointer is held by more than one object or this |
| * method is called from more than one thread. |
| * |
| * @param value - The new value to contain. |
| * |
| * @return The pointer instance that was held by this Pointer object, the pointer is |
| * no longer owned by this Pointer and won't be freed when this Pointer goes |
| * out of scope. |
| */ |
| T* release() { |
| T* temp = this->array->value; |
| this->array->value = NULL; |
| this->array->length = 0; |
| this->array->refs.set(1); |
| return temp; |
| } |
| |
| /** |
| * Gets the real array pointer that is contained within this Pointer. This |
| * is not really safe since the caller could delete or alter the pointer but |
| * it mimics the STL auto_ptr and gives access in cases where the caller |
| * absolutely needs the real Pointer. Use at your own risk. |
| * |
| * @return the contained pointer. |
| */ |
| PointerType get() const { |
| return this->array->value; |
| } |
| |
| /** |
| * Returns the current size of the contained array or zero if the array is |
| * NULL. |
| * |
| * @return the size of the array or zero if the array is NULL |
| */ |
| int length() const { |
| return this->array->length; |
| } |
| |
| /** |
| * Exception Safe Swap Function |
| * @param value - the value to swap with this. |
| */ |
| void swap(ArrayPointer& value) { |
| std::swap(this->array, value.array); |
| } |
| |
| /** |
| * Creates a new ArrayPointer instance that is a clone of the value contained in this |
| * ArrayPointer. |
| * |
| * @return an ArrayPointer that contains a copy of the data in this ArrayPointer. |
| */ |
| ArrayPointer clone() const { |
| |
| if (this->array->length == 0) { |
| return ArrayPointer(); |
| } |
| |
| ArrayPointer copy(this->array->length); |
| decaf::lang::System::arraycopy(this->array->value, 0, copy.get(), 0, this->array->length); |
| return copy; |
| } |
| |
| /** |
| * Assigns the value of right to this Pointer and increments the reference Count. |
| * @param right - Pointer on the right hand side of an operator= call to this. |
| */ |
| ArrayPointer& operator=(const ArrayPointer& right) { |
| if (this == (void*) &right) { |
| return *this; |
| } |
| |
| ArrayPointer temp(right); |
| temp.swap(*this); |
| return *this; |
| } |
| template< typename T1> |
| ArrayPointer& operator=(const ArrayPointer<T1>& right) { |
| if (this == (void*) &right) { |
| return *this; |
| } |
| |
| ArrayPointer temp(right); |
| temp.swap(*this); |
| return *this; |
| } |
| |
| /** |
| * Dereference Operator, returns a reference to the Contained value. This |
| * method throws an NullPointerException if the contained value is NULL. |
| * |
| * @return reference to the contained pointer. |
| * |
| * @throws NullPointerException if the contained value is Null |
| */ |
| ReferenceType operator[](int index) { |
| if (this->array->value == NULL) { |
| throw decaf::lang::exceptions::NullPointerException( |
| __FILE__, __LINE__, "ArrayPointer operator& - Pointee is NULL." ); |
| } |
| |
| if (index < 0 || this->array->length <= index) { |
| throw decaf::lang::exceptions::IndexOutOfBoundsException( |
| __FILE__, __LINE__, "Array Index %d is out of bounds for this array.", this->array->length ); |
| } |
| |
| return this->array->value[index]; |
| } |
| ConstReferenceType operator[](int index) const { |
| if( this->array->value == NULL ) { |
| throw decaf::lang::exceptions::NullPointerException( |
| __FILE__, __LINE__, "ArrayPointer operator& - Pointee is NULL." ); |
| } |
| |
| if( index < 0 || this->array->length <= index ) { |
| throw decaf::lang::exceptions::IndexOutOfBoundsException( |
| __FILE__, __LINE__, "Array Index %d is out of bounds for this array.", this->array->length ); |
| } |
| |
| return this->array->value[index]; |
| } |
| |
| bool operator!() const { |
| return this->array->value == NULL; |
| } |
| |
| inline friend bool operator==(const ArrayPointer& left, const T* right) { |
| return left.get() == right; |
| } |
| |
| inline friend bool operator==(const T* left, const ArrayPointer& right) { |
| return left == right.get(); |
| } |
| |
| inline friend bool operator!=(const ArrayPointer& left, const T* right) { |
| return left.get() != right; |
| } |
| |
| inline friend bool operator!=(const T* left, const ArrayPointer& right) { |
| return left != right.get(); |
| } |
| |
| template<typename T1> |
| bool operator==(const ArrayPointer<T1>& right) const { |
| return this->array->value == right.get(); |
| } |
| |
| template<typename T1> |
| bool operator!=(const ArrayPointer<T1>& right) const { |
| return this->array->value != right.get(); |
| } |
| |
| private: |
| |
| // Internal Static deletion function. |
| static void onDeleteFunc(ArrayData* value) { |
| delete [] value->value; |
| delete value; |
| } |
| |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////// |
| template<typename T, typename U> |
| inline bool operator==(const ArrayPointer<T>& left, const U* right) { |
| return left.get() == right; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| template<typename T, typename U> |
| inline bool operator==(const U* left, const ArrayPointer<T>& right) { |
| return right.get() == left; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| template<typename T, typename U> |
| inline bool operator!=(const ArrayPointer<T>& left, const U* right) { |
| return !(left.get() == right); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| template<typename T, typename U> |
| inline bool operator!=(const U* left, const ArrayPointer<T>& right) { |
| return right.get() != left; |
| } |
| |
| /** |
| * This implementation of Comparator is designed to allows objects in a Collection |
| * to be sorted or tested for equality based on the value of the value of the actual |
| * pointer to the array being contained in this ArrayPointer. This allows for a basic |
| * ordering to be acheived in Decaf containers. |
| * |
| * Custom implementations are possible where an array of some type has a logical natural |
| * ordering such as array of integers where the sum of all ints in the array is used. |
| */ |
| template< typename T > |
| class ArrayPointerComparator : public decaf::util::Comparator< ArrayPointer<T> > { |
| public: |
| |
| virtual ~ArrayPointerComparator() {} |
| |
| // Allows for operator less on types that implement Comparable or provide |
| // a workable operator < |
| virtual bool operator() ( const ArrayPointer<T>& left, const ArrayPointer<T>& right ) const { |
| return left.get() < right.get(); |
| } |
| |
| // Requires that the type in the pointer is an instance of a Comparable. |
| virtual int compare(const ArrayPointer<T>& left, const ArrayPointer<T>& right) const { |
| return left.get() < right.get() ? -1 : right.get() < left.get() ? 1 : 0; |
| } |
| |
| }; |
| |
| }} |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| namespace std{ |
| |
| /** |
| * An override of the less function object so that the Pointer objects |
| * can be stored in STL Maps, etc. |
| */ |
| template< typename T > |
| struct less< decaf::lang::ArrayPointer<T> > { |
| |
| typedef decaf::lang::ArrayPointer<T> first_argument_type; |
| typedef decaf::lang::ArrayPointer<T> second_argument_type; |
| typedef bool result_type; |
| |
| bool operator()(const decaf::lang::ArrayPointer<T>& left, |
| const decaf::lang::ArrayPointer<T>& right) const { |
| return less<T*>()(left.get(), right.get()); |
| } |
| }; |
| } |
| |
| #endif /*_DECAF_LANG_ARRAYPOINTER_H_*/ |