blob: 593a6499c8a33b52d710b4e39f74feeb8e846c59 [file] [log] [blame]
/*
* 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_POINTER_H_
#define _DECAF_LANG_POINTER_H_
#include <decaf/util/Config.h>
#include <decaf/lang/exceptions/NullPointerException.h>
#include <decaf/lang/exceptions/ClassCastException.h>
#include <decaf/util/concurrent/atomic/AtomicRefCounter.h>
#include <decaf/util/Comparator.h>
#include <memory>
#include <typeinfo>
#include <algorithm>
#include <functional>
namespace decaf {
namespace lang {
// Used internally in Pointer.
struct STATIC_CAST_TOKEN {};
struct DYNAMIC_CAST_TOKEN {};
/**
* 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, typename REFCOUNTER = decaf::util::concurrent::atomic::AtomicRefCounter>
class Pointer : public REFCOUNTER {
private:
typedef void (*deletionFuncPtr)(T* p);
private:
T* value;
// Pointer to our internal delete function.
deletionFuncPtr onDelete;
public:
typedef T* PointerType; // type returned by operator->
typedef T& ReferenceType; // type returned by operator*
typedef REFCOUNTER CounterType; // Type of the Reference Counter
public:
/**
* Default Constructor
*
* Initialized the contained pointer to NULL, using the -> operator
* results in an exception unless reset to contain a real value.
*/
Pointer() : REFCOUNTER(), value(NULL), onDelete(onDeleteFunc) {}
/**
* Explicit Constructor, creates a Pointer that contains value with a
* single reference. This object now has ownership until a call to release.
*
* @param value -
* The instance of the type we are containing here.
*/
explicit Pointer(const PointerType value) : REFCOUNTER(), value(value), onDelete(onDeleteFunc) {}
/**
* Copy constructor. Copies the value contained in the pointer to the new
* instance and increments the reference counter.
*
* @param value
* Another instance of a Pointer<T> that this Pointer will copy.
*/
Pointer(const Pointer& value) : REFCOUNTER(value), value(value.value), onDelete(onDeleteFunc) {}
/**
* Copy constructor. Copies the value contained in the pointer to the new
* instance and increments the reference counter.
*
* @param value
* A different but compatible Pointer instance that this Pointer will copy.
*/
template<typename T1, typename R1>
Pointer(const Pointer<T1, R1>& value) : REFCOUNTER(value), value(value.get()), onDelete(onDeleteFunc) {}
/**
* Static Cast constructor. Copies the value contained in the pointer to the new
* instance and increments the reference counter performing a static cast on the
* value contained in the source Pointer object.
*
* @param value
* Pointer instance to cast to this type using a static_cast.
*/
template<typename T1, typename R1>
Pointer(const Pointer<T1, R1>& value, const STATIC_CAST_TOKEN&) :
REFCOUNTER(value), value(static_cast<T*> (value.get())), onDelete(onDeleteFunc) {}
/**
* Dynamic Cast constructor. Copies the value contained in the pointer to the new
* instance and increments the reference counter performing a dynamic cast on the
* value contained in the source Pointer object. If the cast fails and return NULL
* then this method throws a ClassCastException.
*
* @param value
* Pointer instance to cast to this type using a dynamic_cast.
*
* @throw ClassCastException if the dynamic cast returns NULL
*/
template<typename T1, typename R1>
Pointer(const Pointer<T1, R1>& value, const DYNAMIC_CAST_TOKEN&) :
REFCOUNTER(value), value(dynamic_cast<T*> (value.get())), onDelete(onDeleteFunc) {
if (this->value == NULL) {
// Remove the reference we took in the Reference Counter's ctor since we
// didn't actually create one as the dynamic cast failed.
REFCOUNTER::release();
throw decaf::lang::exceptions::ClassCastException(
__FILE__, __LINE__, "Failed to cast source pointer of type %s to this type: %s.",
typeid(T1).name(), typeid(T).name());
}
}
virtual ~Pointer() {
if (REFCOUNTER::release() == true) {
onDelete(this->value);
}
}
/**
* Resets the Pointer 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 value to contain or NULL to empty the pointer (default NULL if not set).
*/
void reset(T* value = NULL) {
Pointer(value).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.
*
* @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->value;
this->value = NULL;
return temp;
}
/**
* Gets the real 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->value;
}
/**
* Exception Safe Swap Function
*
* @param value
* The value to swap with this Pointer.
*/
void swap(Pointer& value) {
std::swap(this->value, value.value);
REFCOUNTER::swap(value);
}
/**
* 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.
*/
Pointer& operator=(const Pointer& right) {
if (this == (void*) &right) {
return *this;
}
Pointer temp(right);
temp.swap(*this);
return *this;
}
template<typename T1, typename R1>
Pointer& operator=(const Pointer<T1, R1>& right) {
if (this == (void*) &right) {
return *this;
}
Pointer 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*() {
if (this->value == NULL) {
throw decaf::lang::exceptions::NullPointerException(
__FILE__, __LINE__, "Pointer operator& - Pointee is NULL.");
}
return *(this->value);
}
ReferenceType operator*() const {
if (this->value == NULL) {
throw decaf::lang::exceptions::NullPointerException(
__FILE__, __LINE__, "Pointer operator& - Pointee is NULL.");
}
return *(this->value);
}
/**
* Indirection Operator, returns a pointer 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
*/
PointerType operator->() {
if (this->value == NULL) {
throw decaf::lang::exceptions::NullPointerException(
__FILE__, __LINE__, "Pointer operator-> - Pointee is NULL.");
}
return this->value;
}
PointerType operator->() const {
if (this->value == NULL) {
throw decaf::lang::exceptions::NullPointerException(
__FILE__, __LINE__, "Pointer operator-> - Pointee is NULL.");
}
return this->value;
}
bool operator!() const {
return this->value == NULL;
}
inline friend bool operator==(const Pointer& left, const T* right) {
return left.get() == right;
}
inline friend bool operator==(const T* left, const Pointer& right) {
return left == right.get();
}
inline friend bool operator!=(const Pointer& left, const T* right) {
return left.get() != right;
}
inline friend bool operator!=(const T* left, const Pointer& right) {
return left != right.get();
}
template<typename T1, typename R1>
bool operator==(const Pointer<T1, R1>& right) const {
return this->value == right.get();
}
template<typename T1, typename R1>
bool operator!=(const Pointer<T1, R1>& right) const {
return !(this->value == right.get());
}
template<typename T1>
Pointer<T1, CounterType> dynamicCast() const {
return Pointer<T1, CounterType> (*this, DYNAMIC_CAST_TOKEN());
}
template<typename T1>
Pointer<T1, CounterType> staticCast() const {
return Pointer<T1, CounterType> (*this, STATIC_CAST_TOKEN());
}
private:
// Internal Static deletion function.
static void onDeleteFunc(T* value) {
delete value;
}
};
////////////////////////////////////////////////////////////////////////////
template<typename T, typename R, typename U>
inline bool operator==(const Pointer<T, R>& left, const U* right) {
return left.get() == right;
}
////////////////////////////////////////////////////////////////////////////
template<typename T, typename R, typename U>
inline bool operator==(const U* left, const Pointer<T, R>& right) {
return right.get() == left;
}
////////////////////////////////////////////////////////////////////////////
template<typename T, typename R, typename U>
inline bool operator!=(const Pointer<T, R>& left, const U* right) {
return !(left.get() == right);
}
////////////////////////////////////////////////////////////////////////////
template<typename T, typename R, typename U>
inline bool operator!=(const U* left, const Pointer<T, R>& right) {
return right.get() != left;
}
////////////////////////////////////////////////////////////////////////////
template<typename T, typename R>
std::ostream& operator<<(std::ostream &out, const Pointer<T, R>& pointer) {
out << pointer.get();
return out;
}
/**
* 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 Object being Pointed
* to and not the value of the contained pointer in the Pointer instance. This can
* be useful in the case where a series of values in a Collection is more efficiently
* accessed in the Objects Natural Order and not the underlying pointers location in
* memory.
* <p>
* Also this allows Pointer objects that Point to different instances of the same type
* to be compared based on the comparison of the object itself and not just the value of
* the pointer.
*/
template<typename T, typename R = decaf::util::concurrent::atomic::AtomicRefCounter>
class PointerComparator: public decaf::util::Comparator<Pointer<T, R> > {
public:
virtual ~PointerComparator() {}
// Allows for operator less on types that implement Comparable or provide
// a workable operator <
virtual bool operator()(const Pointer<T, R>& left, const Pointer<T, R>& right) const {
return *left < *right;
}
// Requires that the type in the pointer is an instance of a Comparable.
virtual int compare(const Pointer<T, R>& left, const Pointer<T, R>& right) const {
return *left < *right ? -1 : *right < *left ? 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::Pointer<T> > { //: public binary_function<decaf::lang::Pointer<T>, decaf::lang::Pointer<T>, bool> {
typedef decaf::lang::Pointer<T> first_argument_type;
typedef decaf::lang::Pointer<T> second_argument_type;
typedef bool result_type;
bool operator()(const decaf::lang::Pointer<T>& left, const decaf::lang::Pointer<T>& right) const {
return less<T*> ()(left.get(), right.get());
}
};
}
#endif /*_DECAF_LANG_POINTER_H_*/