422 lines
13 KiB
C
422 lines
13 KiB
C
|
/*
|
||
|
*
|
||
|
* Copyright (C) 2012-2014, OFFIS e.V.
|
||
|
* All rights reserved. See COPYRIGHT file for details.
|
||
|
*
|
||
|
* This software and supporting documentation were developed by
|
||
|
*
|
||
|
* OFFIS e.V.
|
||
|
* R&D Division Health
|
||
|
* Escherweg 2
|
||
|
* D-26121 Oldenburg, Germany
|
||
|
*
|
||
|
*
|
||
|
* Module: ofstd
|
||
|
*
|
||
|
* Author: Jan Schlamelcher
|
||
|
*
|
||
|
* Purpose: Implement fallback support for modern memory management
|
||
|
* approaches (e.g. smart pointers) for older compilers.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef OFMEM_H
|
||
|
#define OFMEM_H
|
||
|
|
||
|
#include "dcmtk/config/osconfig.h" // make sure OS specific configuration is included first
|
||
|
#include "dcmtk/ofstd/ofutil.h"
|
||
|
|
||
|
// use native classes when c++11 is supported
|
||
|
#ifdef DCMTK_USE_CXX11_STL
|
||
|
|
||
|
#include <memory>
|
||
|
template<typename... ARGS>
|
||
|
using OFshared_ptr = std::shared_ptr<ARGS...>;
|
||
|
template<typename... ARGS>
|
||
|
using OFunique_ptr = std::unique_ptr<ARGS...>;
|
||
|
|
||
|
#else //fallback implementations
|
||
|
|
||
|
#if defined HAVE_SYNC_ADD_AND_FETCH && defined HAVE_SYNC_SUB_AND_FETCH
|
||
|
#define OF_SHARED_PTR_COUNTER_TYPE size_t
|
||
|
#elif defined HAVE_INTERLOCKED_INCREMENT && defined HAVE_INTERLOCKED_DECREMENT
|
||
|
#if _MSC_VER <= 1200
|
||
|
#define OF_SHARED_PTR_COUNTER_TYPE LONG
|
||
|
#else
|
||
|
#define OF_SHARED_PTR_COUNTER_TYPE volatile LONG
|
||
|
#endif
|
||
|
#else
|
||
|
#define OF_SHARED_PTR_COUNTER_TYPE size_t
|
||
|
#define OF_SHARED_PTR_NEED_MUTEX 1
|
||
|
#include "dcmtk/ofstd/ofthread.h"
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_WINDOWS_H
|
||
|
#define WIN32_LEAN_AND_MEAN
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
/** OFshared_ptr is a smart pointer that retains shared ownership of an object through a pointer.
|
||
|
* Several OFshared_ptr objects may own the same object; the object is destroyed when the last remaining
|
||
|
* OFshared_ptr referring to it is destroyed or reset.
|
||
|
*
|
||
|
* An OFshared_ptr may also own no objects, in which case it is called empty.
|
||
|
*
|
||
|
* OFshared_ptr meets the requirements of CopyConstructible and CopyAssignable.
|
||
|
* @tparam T the type of the managed object, e.g. int for an OFshared_ptr behaving like an int*.
|
||
|
* @note this implementation is meant to be a subset of the c++11's std::shared_ptr that lacks the
|
||
|
* following features: swap support, support for weak references, atomic access to the managed object,
|
||
|
* custom deleters and some functions like comparing OFshared_ptrs or read access
|
||
|
* to the reference counter.
|
||
|
* see http://en.cppreference.com/w/cpp/memory/shared_ptr to compare OFshared_ptr against std::shared_ptr.
|
||
|
*/
|
||
|
template<typename T>
|
||
|
class OFshared_ptr
|
||
|
{
|
||
|
public:
|
||
|
/** Constructs a shared_ptr with pt as the managed object.
|
||
|
* @param pt the managed object that this shared_ptr takes
|
||
|
* the ownership to.
|
||
|
*/
|
||
|
OFshared_ptr( T* const pt = OFnullptr )
|
||
|
: m_pData( new Data( pt ) )
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
/** Constructs a shared_ptr which shares ownership of the object managed by other.
|
||
|
* If other manages no object, *this manages no object too.
|
||
|
* @param other another shared_ptr that this one will be copy constructed from.
|
||
|
*/
|
||
|
OFshared_ptr( const OFshared_ptr& other )
|
||
|
: m_pData( other.m_pData )
|
||
|
{
|
||
|
m_pData->increment_count();
|
||
|
}
|
||
|
|
||
|
/** Replaces the managed object with the one managed by other.
|
||
|
* @param other another shared_ptr that this one will be copy assigned from.
|
||
|
*/
|
||
|
OFshared_ptr& operator=( const OFshared_ptr& other )
|
||
|
{
|
||
|
if( this != &other )
|
||
|
{
|
||
|
destroy();
|
||
|
m_pData = other.m_pData;
|
||
|
m_pData->increment_count();
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/** If *this owns an object and it is the last shared_ptr owning it,
|
||
|
* the object is destroyed. Otherwise does nothing.
|
||
|
*/
|
||
|
~OFshared_ptr()
|
||
|
{
|
||
|
destroy();
|
||
|
}
|
||
|
|
||
|
/** Checks if *this manages an object, i.e. whether get() != 0.
|
||
|
* @return OFTrue if *this manages an object, OFFalse otherwise.
|
||
|
*/
|
||
|
operator OFBool() const
|
||
|
{
|
||
|
return m_pData->pointer() != OFnullptr;
|
||
|
}
|
||
|
|
||
|
/** Checks if *this does not manage an object, i.e. whether get() == 0.
|
||
|
* @return OFFalse if *this manages an object, OFTrue otherwise.
|
||
|
*/
|
||
|
OFBool operator!() const
|
||
|
{
|
||
|
return !m_pData->pointer();
|
||
|
}
|
||
|
|
||
|
/** Dereferences pointer to the managed object.
|
||
|
* @return a reference to the managed object.
|
||
|
*/
|
||
|
T& operator*() const
|
||
|
{
|
||
|
return *m_pData->pointer();
|
||
|
}
|
||
|
|
||
|
/** Dereferences pointer to the managed object.
|
||
|
* @return a pointer to the managed object.
|
||
|
*/
|
||
|
T* operator->() const
|
||
|
{
|
||
|
return m_pData->pointer();
|
||
|
}
|
||
|
|
||
|
/** Returns a pointer to the managed object.
|
||
|
* @return a pointer to the managed object.
|
||
|
*/
|
||
|
T* get() const
|
||
|
{
|
||
|
return m_pData->pointer();
|
||
|
}
|
||
|
|
||
|
/** Replaces the managed object with an object pointed to by pt.
|
||
|
* @param pt pointer to an object to acquire ownership of.
|
||
|
*/
|
||
|
void reset( T* const pt = OFnullptr )
|
||
|
{
|
||
|
destroy();
|
||
|
m_pData = new Data( pt );
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
/** Helper class containing the reference to the
|
||
|
* managed object and the reference counter.
|
||
|
*/
|
||
|
class Data
|
||
|
{
|
||
|
public:
|
||
|
/** Construct reference and counter from a raw pointer.
|
||
|
* @param pt the raw pointer that becomes the managed object.
|
||
|
*/
|
||
|
Data( T* const pt )
|
||
|
: m_Count( 1 )
|
||
|
, m_pT( pt )
|
||
|
#ifdef OF_SHARED_PTR_NEED_MUTEX
|
||
|
, m_Mutex()
|
||
|
#endif
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
/** Delete the managed object.
|
||
|
* We are deleted only if the reference counter reached zero,
|
||
|
* so we now have to delete the managed object.
|
||
|
*/
|
||
|
~Data()
|
||
|
{
|
||
|
delete m_pT;
|
||
|
}
|
||
|
|
||
|
/** Increment the reference counter in a thread-safe and (if possible)
|
||
|
* lock-free fashion.
|
||
|
*/
|
||
|
void increment_count()
|
||
|
{
|
||
|
#ifdef HAVE_SYNC_ADD_AND_FETCH
|
||
|
__sync_add_and_fetch( &m_Count, 1 );
|
||
|
#elif defined HAVE_INTERLOCKED_INCREMENT
|
||
|
InterlockedIncrement( &m_Count );
|
||
|
#else
|
||
|
m_Mutex.lock();
|
||
|
++m_Count;
|
||
|
m_Mutex.unlock();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/** Decrement the reference counter in a thread-safe and (if possible)
|
||
|
* lock-free fashion.
|
||
|
* @return OFTrue if the reference counter reached zero, OFFalse otherwise.
|
||
|
*/
|
||
|
OFBool decrement_count()
|
||
|
{
|
||
|
#ifdef HAVE_SYNC_SUB_AND_FETCH
|
||
|
return !__sync_sub_and_fetch( &m_Count, 1 );
|
||
|
#elif defined HAVE_INTERLOCKED_DECREMENT
|
||
|
return !InterlockedDecrement( &m_Count );
|
||
|
#else
|
||
|
m_Mutex.lock();
|
||
|
const OFBool result = !--m_Count;
|
||
|
m_Mutex.unlock();
|
||
|
return result;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/** Get the managed object.
|
||
|
* @return a pointer to the managed object.
|
||
|
*/
|
||
|
T* pointer() const
|
||
|
{
|
||
|
return m_pT;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Just to silence some warnings.
|
||
|
Data(const Data&);
|
||
|
Data& operator=(const Data&);
|
||
|
|
||
|
/// The counter.
|
||
|
OF_SHARED_PTR_COUNTER_TYPE m_Count;
|
||
|
/// The pointer to the managed object.
|
||
|
T* const m_pT;
|
||
|
#ifdef OF_SHARED_PTR_NEED_MUTEX
|
||
|
/// A mutex for platforms that don't support lock-free counters.
|
||
|
OFMutex m_Mutex;
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
/** decrement the reference counter, destroy the managed
|
||
|
* object and the counter if the counter reached zero.
|
||
|
*/
|
||
|
void destroy()
|
||
|
{
|
||
|
if( m_pData->decrement_count() )
|
||
|
delete m_pData;
|
||
|
}
|
||
|
|
||
|
/** A pointer to the management data structure containing the actual
|
||
|
* reference to the managed object and the reference counter.
|
||
|
*/
|
||
|
Data* m_pData;
|
||
|
};
|
||
|
|
||
|
/** OFunique_ptr is a smart pointer that retains sole ownership of an object through a pointer and destroys
|
||
|
* that object when the unique_ptr goes out of scope. No two unique_ptr instances can manage the same object.
|
||
|
*
|
||
|
* The object is destroyed and its memory deallocated when either of the following happens:
|
||
|
* - unique_ptr managing the object is destroyed
|
||
|
* - unique_ptr managing the object is assigned another pointer via reset().
|
||
|
*
|
||
|
* A unique_ptr may also own no objects, in which case it is called empty.
|
||
|
*
|
||
|
* OFunique_ptr is NOT CopyConstructible or CopyAssignable.
|
||
|
* @tparam T the type of the managed object, e.g. int for an OFunique_ptr behaving like an int*.
|
||
|
* @note this implementation is meant to be a subset of the c++11's std::unique_ptr that lacks the
|
||
|
* following features: swap support, custom deleters, specialized handling of pointers to
|
||
|
* arrays and some functions like comparing OFunique_ptrs or creating a hash key.
|
||
|
* see http://en.cppreference.com/w/cpp/memory/unique_ptr to compare OFunique_ptr against std::unique_ptr.
|
||
|
*/
|
||
|
template<typename T>
|
||
|
class OFunique_ptr
|
||
|
{
|
||
|
public:
|
||
|
/** typedef of pointer type T* for template programmers.
|
||
|
*/
|
||
|
typedef T* pointer;
|
||
|
/** T, the type of the object managed by this unique_ptr.
|
||
|
*/
|
||
|
typedef T element_type;
|
||
|
|
||
|
/** Constructs an empty OFunique_ptr
|
||
|
*/
|
||
|
OFunique_ptr() : m_pData( OFnullptr ) {}
|
||
|
|
||
|
/** Constructs a OFunique_ptr which owns p.
|
||
|
* @param p the pointer that's going to be owned by this unique_ptr.
|
||
|
*/
|
||
|
explicit OFunique_ptr( pointer p ) : m_pData( p ) {}
|
||
|
|
||
|
/** Move constructor.
|
||
|
* The move constructor <i>moves</i> the ownership of the managed
|
||
|
* object from its parameter to the newly created OFunique_ptr
|
||
|
* object, effectively emptying the former OFunique_ptr
|
||
|
* object.
|
||
|
* @param rhs an <i>rvalue reference</i> to another OFunique_ptr
|
||
|
* object, e.g. obtained via OFmove.
|
||
|
* @details
|
||
|
* <h3>Example</h3>
|
||
|
* This example shows how to move the ownership of a managed
|
||
|
* object from one OFunique_ptr to another. Note that the
|
||
|
* ownership always remains unique in this example, even
|
||
|
* if an error occurred while reading the Dataset.
|
||
|
* Therefore no memory leaks are possible!
|
||
|
* @code
|
||
|
* void consumeDataset( OFunique_ptr<DcmDataset> pDataset )
|
||
|
* . . .
|
||
|
* OFunique_ptr<DcmDataset> pDataset( new DcmDataset );
|
||
|
* if( pDataset && pDataset->read( ... ).good() )
|
||
|
* {
|
||
|
* // Error: copy constructor not available, as it would
|
||
|
* // compromise the unique ownership principle
|
||
|
* // consumeDataset( pDataset );
|
||
|
*
|
||
|
* // OFmove allows us to 'tell' OFunique_ptr we want
|
||
|
* // to give away the ownership.
|
||
|
* consumeDataset( OFmove( pDataset ) );
|
||
|
* }
|
||
|
* @endcode
|
||
|
*/
|
||
|
OFunique_ptr( OFrvalue_ref(OFunique_ptr) rhs )
|
||
|
#ifndef DOXYGEN
|
||
|
: m_pData( rhs.m_pData )
|
||
|
{
|
||
|
OFrvalue_access(rhs).m_pData = OFnullptr;
|
||
|
}
|
||
|
#else
|
||
|
;
|
||
|
#endif
|
||
|
|
||
|
/** Move assignment operator.
|
||
|
* The move assignment operator <i>moves</i> the ownership of the
|
||
|
* managed object from its parameter to itself, effectively emptying
|
||
|
* the other OFunique_ptr object. See OFunique_ptr's <i>move constructor</i>
|
||
|
* for more information.
|
||
|
* @param rhs an <i>rvalue reference</i> to another OFunique_ptr
|
||
|
* object, e.g. obtained via OFmove.
|
||
|
*/
|
||
|
OFunique_ptr& operator=( OFrvalue_ref(OFunique_ptr) rhs )
|
||
|
#ifndef DOXYGEN
|
||
|
{
|
||
|
OFunique_ptr& other = OFrvalue_access(rhs);
|
||
|
if( &other != this )
|
||
|
{
|
||
|
reset( other.m_pData );
|
||
|
other.m_pData = OFnullptr;
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
#else
|
||
|
;
|
||
|
#endif
|
||
|
|
||
|
/** If get() == OFnullptr there are no effects -- otherwise, the owned object is destroyed.
|
||
|
*/
|
||
|
~OFunique_ptr() { delete m_pData; }
|
||
|
|
||
|
/** Replaces the managed object. The previously owned object is deleted if the unique_ptr
|
||
|
* was not empty.
|
||
|
* @param p the new pointer to be owned, defaults to OFnullptr.
|
||
|
*/
|
||
|
void reset( pointer p = OFnullptr ) { delete m_pData; m_pData = p; }
|
||
|
|
||
|
/** Releases the ownership of the managed object if any.
|
||
|
* Retrieves the owned object (if any) and lets the unique_ptr become empty.
|
||
|
* @return same as get().
|
||
|
*/
|
||
|
pointer release() { pointer const p = m_pData; m_pData = OFnullptr; return p; }
|
||
|
|
||
|
/** Returns a pointer to the managed object or OFnullptr if no object is owned.
|
||
|
* @return Pointer to the managed object or OFnullptr if no object is owned.
|
||
|
*/
|
||
|
pointer get() const { return m_pData; }
|
||
|
|
||
|
/** Checks whether *this owns an object, i.e. whether get() != OFnullptr.
|
||
|
* @return get() != OFnullptr.
|
||
|
*/
|
||
|
operator bool() const { return m_pData != OFnullptr; }
|
||
|
|
||
|
/** Checks whether *this does NOT own an object, i.e. whether get() == OFnullptr.
|
||
|
* @return get() == OFnullptr.
|
||
|
*/
|
||
|
bool operator!() const { return m_pData == OFnullptr; }
|
||
|
|
||
|
/** Access the object owned by *this.
|
||
|
* @return the object owned by *this, i.e. *get().
|
||
|
*/
|
||
|
T& operator*() const { return *m_pData; }
|
||
|
|
||
|
/** Access the object owned by *this.
|
||
|
* @return same as get().
|
||
|
*/
|
||
|
pointer operator->() const { return m_pData; }
|
||
|
|
||
|
private:
|
||
|
/// Disable copy construction.
|
||
|
OFunique_ptr(const OFunique_ptr&);
|
||
|
/// Disable copy assignment.
|
||
|
OFunique_ptr& operator=(const OFunique_ptr&);
|
||
|
|
||
|
/// The underlying (raw) pointer.
|
||
|
pointer m_pData;
|
||
|
};
|
||
|
|
||
|
#endif //c++11
|
||
|
|
||
|
#endif //OFMEM_H
|