/*****************************************************************
|
| Neptune - References
|
| Copyright (c) 2002-2008, Axiomatic Systems, LLC.
| 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 Axiomatic Systems 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 AXIOMATIC SYSTEMS ''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 AXIOMATIC SYSTEMS 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 _NPT_REFERENCES_H_
#define _NPT_REFERENCES_H_
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
#include "NptConstants.h"
#include "NptThreads.h"
/*----------------------------------------------------------------------
| NPT_Reference
+---------------------------------------------------------------------*/
template <typename T>
class NPT_Reference
{
public:
// constructors and destructor
NPT_Reference() : m_Object(NULL), m_Counter(NULL), m_Mutex(NULL), m_ThreadSafe(true) {}
explicit NPT_Reference(T* object, bool thread_safe = true) :
m_Object(object),
m_Counter(object?new NPT_Cardinal(1):NULL),
m_Mutex((object && thread_safe)?new NPT_Mutex():NULL),
m_ThreadSafe(thread_safe) {}
NPT_Reference(const NPT_Reference<T>& ref) :
m_Object(ref.m_Object), m_Counter(ref.m_Counter), m_Mutex(ref.m_Mutex), m_ThreadSafe(ref.m_ThreadSafe) {
if (m_Mutex) m_Mutex->Lock();
if (m_Counter) ++(*m_Counter);
if (m_Mutex) m_Mutex->Unlock();
}
// this methods should be private, but this causes a problem on some
// compilers, because we need this function in order to implement
// the cast operator operator NPT_Reference<U>() below, which would
// have to be marked as a friend, and friend declarations with the
// same class name confuses some compilers
NPT_Reference(T* object, NPT_Cardinal* counter, NPT_Mutex* mutex, bool thread_safe) :
m_Object(object), m_Counter(counter), m_Mutex(mutex), m_ThreadSafe(thread_safe) {
if (m_Mutex) m_Mutex->Lock();
if (m_Counter) ++(*m_Counter);
if (m_Mutex) m_Mutex->Unlock();
}
~NPT_Reference() {
Release();
}
// overloaded operators
NPT_Reference<T>& operator=(const NPT_Reference<T>& ref) {
if (this != &ref) {
Release();
m_Object = ref.m_Object;
m_Counter = ref.m_Counter;
m_Mutex = ref.m_Mutex;
m_ThreadSafe = ref.m_ThreadSafe;
if (m_Mutex) m_Mutex->Lock();
if (m_Counter) ++(*m_Counter);
if (m_Mutex) m_Mutex->Unlock();
}
return *this;
}
NPT_Reference<T>& operator=(T* object) {
Release();
m_Object = object;
m_Counter = object?new NPT_Cardinal(1):NULL;
m_Mutex = (object && m_ThreadSafe)?new NPT_Mutex():NULL;
return *this;
}
T& operator*() const { return *m_Object; }
T* operator->() const { return m_Object; }
bool operator==(const NPT_Reference<T>& ref) const {
return m_Object == ref.m_Object;
}
bool operator!=(const NPT_Reference<T>& ref) const {
return m_Object != ref.m_Object;
}
// overloaded cast operators
template <typename U> operator NPT_Reference<U>() {
return NPT_Reference<U>(m_Object, m_Counter, m_Mutex, m_ThreadSafe);
}
// methods
/**
* Returns the naked pointer value.
*/
T* AsPointer() const { return m_Object; }
/**
* Returns the reference counter value.
*/
NPT_Cardinal GetCounter() const { return *m_Counter; }
/**
* Returns whether this references a NULL object.
*/
bool IsNull() const { return m_Object == NULL; }
/**
* Detach the reference from the shared object.
* The reference count is decremented, but the object is not deleted if the
* reference count becomes 0.
* After the method returns, this reference does not point to any shared object.
*/
void Detach() {
Release(true);
}
private:
// methods
void Release(bool detach_only = false) {
bool last_reference = false;
if (m_Mutex) m_Mutex->Lock();
if (m_Counter && --(*m_Counter) == 0) {
delete m_Counter;
if (!detach_only) delete m_Object;
last_reference = true;
}
m_Counter = NULL;
m_Object = NULL;
if (m_Mutex) {
NPT_Mutex* mutex = m_Mutex;
m_Mutex = NULL;
mutex->Unlock();
if (last_reference) delete mutex;
}
}
// members
T* m_Object;
NPT_Cardinal* m_Counter;
NPT_Mutex* m_Mutex;
bool m_ThreadSafe;
};
#endif // _NPT_REFERENCES_H_