first commit
This commit is contained in:
244
include/QxMemLeak/bool_array.h
Normal file
244
include/QxMemLeak/bool_array.h
Normal file
@@ -0,0 +1,244 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file bool_array.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Header file for class bool_array (packed boolean array).
|
||||
*
|
||||
* \version 3.1, 2005/08/25
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _BOOL_ARRAY_H
|
||||
#define _BOOL_ARRAY_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <assert.h> // assert
|
||||
#include <stdlib.h> // exit, free, and NULL
|
||||
#include <new> // std::bad_alloc
|
||||
#include <stdexcept> // std::out_of_range
|
||||
#include <string> // for exception constructors
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
#ifndef _BYTE_DEFINED
|
||||
#define _BYTE_DEFINED
|
||||
typedef unsigned char BYTE;
|
||||
#endif // !_BYTE_DEFINED
|
||||
|
||||
/**
|
||||
* Class to represent a packed boolean array.
|
||||
*
|
||||
* This was first written in April 1995, before I knew of any existing
|
||||
* implementation of this kind of classes. Of course, the C++ Standard
|
||||
* Template Library now demands an implementation of packed boolean
|
||||
* array as `vector<bool>', but the code here should still be useful
|
||||
* for the following three reasons: (1) STL support of MSVC 6 did not
|
||||
* implement this specialization (nor did it have a `bit_vector'); (2) I
|
||||
* incorporated some useful member functions from the STL bitset into
|
||||
* this `bool_array', including `reset', `set', `flip', and `count';
|
||||
* (3) In my tests under MSVC 6 and GCC 2.95.3/3.2.3 my code is really
|
||||
* FASTER than vector<bool> or the normal boolean array.
|
||||
*/
|
||||
class QX_DLL_EXPORT bool_array
|
||||
{
|
||||
/** Class to represent a reference to an array element. */
|
||||
class QX_DLL_EXPORT _Element
|
||||
{
|
||||
public:
|
||||
_Element(BYTE* __ptr, unsigned long __idx);
|
||||
bool operator=(bool ___value);
|
||||
operator bool() const;
|
||||
private:
|
||||
BYTE* _M_byte_ptr;
|
||||
size_t _M_byte_idx;
|
||||
size_t _M_bit_idx;
|
||||
};
|
||||
|
||||
public:
|
||||
bool_array() : _M_byte_ptr(NULL), _M_length(0) {}
|
||||
explicit bool_array(unsigned long __size);
|
||||
~bool_array() { if (_M_byte_ptr != NULL) free(_M_byte_ptr); }
|
||||
|
||||
bool create(unsigned long __size);
|
||||
void initialize(bool ___value);
|
||||
|
||||
// Using unsigned type here can increase performance!
|
||||
_Element operator[](unsigned long __idx);
|
||||
bool at(unsigned long __idx) const;
|
||||
void reset(unsigned long __idx);
|
||||
void set(unsigned long __idx);
|
||||
|
||||
unsigned long size() const { return _M_length; }
|
||||
unsigned long count() const;
|
||||
unsigned long count(unsigned long __beg, unsigned long __end) const;
|
||||
void flip();
|
||||
|
||||
private:
|
||||
BYTE* _M_byte_ptr;
|
||||
unsigned long _M_length;
|
||||
static BYTE _S_bit_count[256];
|
||||
};
|
||||
|
||||
|
||||
/* Inline functions */
|
||||
|
||||
/**
|
||||
* Constructs a reference to an array element.
|
||||
*
|
||||
* @param __ptr pointer to the interal boolean data
|
||||
* @param __idx index of the array element to access
|
||||
*/
|
||||
inline bool_array::_Element::_Element(BYTE* __ptr, unsigned long __idx)
|
||||
{
|
||||
_M_byte_ptr = __ptr;
|
||||
_M_byte_idx = (size_t)(__idx / 8);
|
||||
_M_bit_idx = (size_t)(__idx % 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a new boolean value to an array element.
|
||||
*
|
||||
* @param ___value the new boolean value
|
||||
* @return the assigned boolean value
|
||||
*/
|
||||
inline bool bool_array::_Element::operator=(bool ___value)
|
||||
{
|
||||
if (___value)
|
||||
*(_M_byte_ptr + _M_byte_idx) |= 1 << _M_bit_idx;
|
||||
else
|
||||
*(_M_byte_ptr + _M_byte_idx) &= ~(1 << _M_bit_idx);
|
||||
return ___value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the boolean value from an array element.
|
||||
*
|
||||
* @return the boolean value of the accessed array element
|
||||
*/
|
||||
inline bool_array::_Element::operator bool() const
|
||||
{
|
||||
return *(_M_byte_ptr + _M_byte_idx) & (1 << _M_bit_idx) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the packed boolean array with a specific size.
|
||||
*
|
||||
* @param __size size of the array
|
||||
* @throw std::out_of_range if \a __size equals \c 0
|
||||
* @throw std::bad_alloc if memory is insufficient
|
||||
*/
|
||||
inline bool_array::bool_array(unsigned long __size)
|
||||
: _M_byte_ptr(NULL), _M_length(0)
|
||||
{
|
||||
if (__size == 0)
|
||||
throw std::out_of_range("invalid bool_array size");
|
||||
|
||||
if (!create(__size))
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reference to an array element.
|
||||
*
|
||||
* @param __idx index of the array element to access
|
||||
*/
|
||||
inline bool_array::_Element bool_array::operator[](unsigned long __idx)
|
||||
{
|
||||
assert(_M_byte_ptr);
|
||||
assert(__idx < _M_length);
|
||||
return _Element(_M_byte_ptr, __idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the boolean value of an array element via an index.
|
||||
*
|
||||
* @param __idx index of the array element to access
|
||||
* @return the boolean value of the accessed array element
|
||||
* @throw std::out_of_range when the index is too big
|
||||
*/
|
||||
inline bool bool_array::at(unsigned long __idx) const
|
||||
{
|
||||
size_t __byte_idx, __bit_idx;
|
||||
if (__idx >= _M_length)
|
||||
throw std::out_of_range("invalid bool_array subscript");
|
||||
__byte_idx = (size_t)(__idx / 8);
|
||||
__bit_idx = (size_t)(__idx % 8);
|
||||
return *(_M_byte_ptr + __byte_idx) & (1 << __bit_idx) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets an array element to \c false via an index.
|
||||
*
|
||||
* @param __idx index of the array element to access
|
||||
* @throw std::out_of_range when the index is too big
|
||||
*/
|
||||
inline void bool_array::reset(unsigned long __idx)
|
||||
{
|
||||
size_t __byte_idx, __bit_idx;
|
||||
if (__idx >= _M_length)
|
||||
throw std::out_of_range("invalid bool_array subscript");
|
||||
__byte_idx = (size_t)(__idx / 8);
|
||||
__bit_idx = (size_t)(__idx % 8);
|
||||
*(_M_byte_ptr + __byte_idx) &= ~(1 << __bit_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an array element to \c true via an index.
|
||||
*
|
||||
* @param __idx index of the array element to access
|
||||
* @throw std::out_of_range when the index is too big
|
||||
*/
|
||||
inline void bool_array::set(unsigned long __idx)
|
||||
{
|
||||
size_t __byte_idx, __bit_idx;
|
||||
if (__idx >= _M_length)
|
||||
throw std::out_of_range("invalid bool_array subscript");
|
||||
__byte_idx = (size_t)(__idx / 8);
|
||||
__bit_idx = (size_t)(__idx % 8);
|
||||
*(_M_byte_ptr + __byte_idx) |= 1 << __bit_idx;
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _BOOL_ARRAY_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
139
include/QxMemLeak/class_level_lock.h
Normal file
139
include/QxMemLeak/class_level_lock.h
Normal file
@@ -0,0 +1,139 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file class_level_lock.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* In essence Loki ClassLevelLockable re-engineered to use a fast_mutex class.
|
||||
*
|
||||
* \version 1.13, 2007/12/30
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _CLASS_LEVEL_LOCK_H
|
||||
#define _CLASS_LEVEL_LOCK_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "fast_mutex.h"
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
#ifdef _NOTHREADS
|
||||
/**
|
||||
* Helper class for class-level locking. This is the
|
||||
* single-threaded implementation.
|
||||
*/
|
||||
template <class _Host, bool _RealLock = false>
|
||||
class class_level_lock
|
||||
{
|
||||
public:
|
||||
/** Type that provides locking/unlocking semantics. */
|
||||
class lock
|
||||
{
|
||||
public:
|
||||
lock() {}
|
||||
};
|
||||
|
||||
typedef _Host volatile_type;
|
||||
};
|
||||
#else
|
||||
/**
|
||||
* Helper class for class-level locking. This is the multi-threaded
|
||||
* implementation. The main departure from Loki ClassLevelLockable
|
||||
* is that there is an additional template parameter which can make
|
||||
* the lock not lock at all even in multi-threaded environments.
|
||||
* See static_mem_pool.h for real usage.
|
||||
*/
|
||||
template <class _Host, bool _RealLock = true>
|
||||
class class_level_lock
|
||||
{
|
||||
static fast_mutex _S_mtx;
|
||||
|
||||
public:
|
||||
class lock;
|
||||
friend class lock;
|
||||
|
||||
/** Type that provides locking/unlocking semantics. */
|
||||
class lock
|
||||
{
|
||||
lock(const lock&);
|
||||
lock& operator=(const lock&);
|
||||
public:
|
||||
lock()
|
||||
{
|
||||
if (_RealLock)
|
||||
_S_mtx.lock();
|
||||
}
|
||||
~lock()
|
||||
{
|
||||
if (_RealLock)
|
||||
_S_mtx.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
typedef volatile _Host volatile_type;
|
||||
};
|
||||
|
||||
#if HAVE_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
/** Partial specialization that makes null locking. */
|
||||
template <class _Host>
|
||||
class class_level_lock<_Host, false>
|
||||
{
|
||||
public:
|
||||
/** Type that provides locking/unlocking semantics. */
|
||||
class lock
|
||||
{
|
||||
public:
|
||||
lock() {}
|
||||
};
|
||||
|
||||
typedef _Host volatile_type;
|
||||
};
|
||||
#endif // HAVE_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
|
||||
template <class _Host, bool _RealLock>
|
||||
fast_mutex class_level_lock<_Host, _RealLock>::_S_mtx;
|
||||
#endif // _NOTHREADS
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _CLASS_LEVEL_LOCK_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
151
include/QxMemLeak/cont_ptr_utils.h
Normal file
151
include/QxMemLeak/cont_ptr_utils.h
Normal file
@@ -0,0 +1,151 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file cont_ptr_utils.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Utility functors for containers of pointers (adapted from Scott
|
||||
* Meyers' <em>Effective STL</em>).
|
||||
*
|
||||
* \version 1.4, 2007/09/12
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _CONT_PTR_UTILS_H
|
||||
#define _CONT_PTR_UTILS_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
/**
|
||||
* Functor to return objects pointed by a container of pointers.
|
||||
*
|
||||
* A typical usage might be like:
|
||||
* @code
|
||||
* vector<Object*> v;
|
||||
* ...
|
||||
* transform(v.begin(), v.end(),
|
||||
* ostream_iterator<Object>(cout, " "),
|
||||
* dereference());
|
||||
* @endcode
|
||||
*/
|
||||
struct QX_DLL_EXPORT dereference
|
||||
{
|
||||
template <typename _Tp>
|
||||
const _Tp& operator()(const _Tp* __ptr) const
|
||||
{
|
||||
return *__ptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functor to compare objects pointed by a container of pointers.
|
||||
*
|
||||
* @code
|
||||
* vector<Object*> v;
|
||||
* ...
|
||||
* sort(v.begin(), v.end(), dereference_less());
|
||||
* @endcode
|
||||
* or
|
||||
* @code
|
||||
* set<Object*, dereference_less> s;
|
||||
* @endcode
|
||||
*/
|
||||
struct QX_DLL_EXPORT dereference_less
|
||||
{
|
||||
template <typename _Pointer>
|
||||
bool operator()(_Pointer __ptr1, _Pointer __ptr2) const
|
||||
{
|
||||
return *__ptr1 < *__ptr2;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functor to delete objects pointed by a container of pointers.
|
||||
*
|
||||
* A typical usage might be like:
|
||||
* @code
|
||||
* list<Object*> l;
|
||||
* ...
|
||||
* for_each(l.begin(), l.end(), delete_object());
|
||||
* @endcode
|
||||
*/
|
||||
struct QX_DLL_EXPORT delete_object
|
||||
{
|
||||
template <typename _Pointer>
|
||||
void operator()(_Pointer __ptr) const
|
||||
{
|
||||
delete __ptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functor to output objects pointed by a container of pointers.
|
||||
*
|
||||
* A typical usage might be like:
|
||||
* @code
|
||||
* list<Object*> l;
|
||||
* ...
|
||||
* for_each(l.begin(), l.end(), output_object<ostream>(cout, " "));
|
||||
* @endcode
|
||||
*/
|
||||
template <typename _OutputStrm, typename _StringType = const char*>
|
||||
struct output_object
|
||||
{
|
||||
output_object(_OutputStrm& __outs, const _StringType& __sep)
|
||||
: _M_outs(__outs), _M_sep(__sep)
|
||||
{}
|
||||
|
||||
template <typename _Tp>
|
||||
void operator()(const _Tp* __ptr) const
|
||||
{
|
||||
_M_outs << *__ptr << _M_sep;
|
||||
}
|
||||
|
||||
private:
|
||||
_OutputStrm& _M_outs;
|
||||
_StringType _M_sep;
|
||||
};
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _CONT_PTR_UTILS_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
220
include/QxMemLeak/debug_new.h
Normal file
220
include/QxMemLeak/debug_new.h
Normal file
@@ -0,0 +1,220 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file debug_new.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Header file for checking leaks caused by unmatched new/delete.
|
||||
*
|
||||
* \version 4.4, 2007/12/31
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _DEBUG_NEW_H
|
||||
#define _DEBUG_NEW_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QxCommon/QxMacro.h>
|
||||
|
||||
/**
|
||||
* @def HAVE_PLACEMENT_DELETE
|
||||
*
|
||||
* Macro to indicate whether placement delete operators are supported on
|
||||
* a certain compiler. Some compilers, like Borland C++ Compiler 5.5.1
|
||||
* and Digital Mars Compiler 8.42, do not support them, and the user
|
||||
* must define this macro to \c 0 to make the program compile. Also
|
||||
* note that in that case memory leakage will occur if an exception is
|
||||
* thrown in the initialization (constructor) of a dynamically created
|
||||
* object.
|
||||
*/
|
||||
#ifndef HAVE_PLACEMENT_DELETE
|
||||
#define HAVE_PLACEMENT_DELETE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def _DEBUG_NEW_REDEFINE_NEW
|
||||
*
|
||||
* Macro to indicate whether redefinition of \c new is wanted. If one
|
||||
* wants to define one's own <code>operator new</code>, to call
|
||||
* <code>operator new</code> directly, or to call placement \c new, it
|
||||
* should be defined to \c 0 to alter the default behaviour. Unless, of
|
||||
* course, one is willing to take the trouble to write something like:
|
||||
* @code
|
||||
* # ifdef new
|
||||
* # define _NEW_REDEFINED
|
||||
* # undef new
|
||||
* # endif
|
||||
*
|
||||
* // Code that uses new is here
|
||||
*
|
||||
* # ifdef _NEW_REDEFINED
|
||||
* # ifdef DEBUG_NEW
|
||||
* # define new DEBUG_NEW
|
||||
* # endif
|
||||
* # undef _NEW_REDEFINED
|
||||
* # endif
|
||||
* @endcode
|
||||
*/
|
||||
#ifndef _DEBUG_NEW_REDEFINE_NEW
|
||||
#define _DEBUG_NEW_REDEFINE_NEW 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def _DEBUG_NEW_CALLER_ADDRESS
|
||||
*
|
||||
* The expression to return the caller address. print_position will
|
||||
* later on use this address to print the position information of memory
|
||||
* operation points.
|
||||
*/
|
||||
#ifndef _DEBUG_NEW_CALLER_ADDRESS
|
||||
#ifdef __GNUC__
|
||||
#define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0)
|
||||
#else
|
||||
#define _DEBUG_NEW_CALLER_ADDRESS NULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def DEBUG_NEW
|
||||
*
|
||||
* Macro to catch file/line information on allocation. If
|
||||
* #_DEBUG_NEW_REDEFINE_NEW is \c 0, one can use this macro directly;
|
||||
* otherwise \c new will be defined to it, and one must use \c new
|
||||
* instead.
|
||||
*/
|
||||
#define DEBUG_NEW qx::memory::__debug_new_recorder(__FILE__, __LINE__, __FUNCTION__) ->* new
|
||||
|
||||
#if _DEBUG_NEW_REDEFINE_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif // _DEBUG_NEW_REDEFINE_NEW
|
||||
|
||||
#ifdef _DEBUG_NEW_EMULATE_MALLOC
|
||||
#include <stdlib.h>
|
||||
#ifdef new
|
||||
#define malloc(s) ((void*)(new char[s]))
|
||||
#else // new
|
||||
#define malloc(s) ((void*)(DEBUG_NEW char[s]))
|
||||
#endif // new
|
||||
#define free(p) delete[] (char*)(p)
|
||||
#endif // _DEBUG_NEW_EMULATE_MALLOC
|
||||
|
||||
QX_DLL_EXPORT void * operator new(size_t size, const char * file, int line);
|
||||
QX_DLL_EXPORT void * operator new[](size_t size, const char * file, int line);
|
||||
|
||||
#if HAVE_PLACEMENT_DELETE
|
||||
QX_DLL_EXPORT void operator delete(void * pointer, const char * file, int line) throw();
|
||||
QX_DLL_EXPORT void operator delete[](void * pointer, const char * file, int line) throw();
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1300
|
||||
// MSVC 6 requires the following declarations; or the non-placement
|
||||
// new[]/delete[] will not compile.
|
||||
QX_DLL_EXPORT void * operator new[](size_t) throw(std::bad_alloc);
|
||||
QX_DLL_EXPORT void operator delete[](void *) throw();
|
||||
#endif
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
/* Prototypes */
|
||||
QX_DLL_EXPORT int check_leaks();
|
||||
QX_DLL_EXPORT int check_mem_corruption();
|
||||
|
||||
/* Control variables */
|
||||
extern bool new_autocheck_flag; // default to true: call check_leaks() on exit
|
||||
extern bool new_verbose_flag; // default to false: no verbose information
|
||||
extern FILE* new_output_fp; // default to stderr: output to console
|
||||
extern const char* new_progname;// default to NULL; should be assigned argv[0]
|
||||
|
||||
/**
|
||||
* Recorder class to remember the call context.
|
||||
*
|
||||
* The idea comes from <a href="http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/7089382e3bc1c489/85f9107a1dc79ee9?#85f9107a1dc79ee9">Greg Herlihy's post</a> in comp.lang.c++.moderated.
|
||||
*/
|
||||
class QX_DLL_EXPORT __debug_new_recorder
|
||||
{
|
||||
const char* _M_file;
|
||||
const int _M_line;
|
||||
const char* _M_fct;
|
||||
void _M_process(void* pointer);
|
||||
public:
|
||||
/**
|
||||
* Constructor to remember the call context. The information will
|
||||
* be used in __debug_new_recorder::operator->*.
|
||||
*/
|
||||
__debug_new_recorder(const char* file, int line, const char* fct)
|
||||
: _M_file(file), _M_line(line), _M_fct(fct) {}
|
||||
/**
|
||||
* Operator to write the context information to memory.
|
||||
* <code>operator->*</code> is chosen because it has the right
|
||||
* precedence, it is rarely used, and it looks good: so people can
|
||||
* tell the special usage more quickly.
|
||||
*/
|
||||
template <class _Tp> _Tp* operator->*(_Tp* pointer) { _M_process(pointer); return pointer; };
|
||||
static void free_pointer(void* pointer, void* addr, bool is_array);
|
||||
private:
|
||||
__debug_new_recorder(const __debug_new_recorder&);
|
||||
__debug_new_recorder& operator=(const __debug_new_recorder&);
|
||||
};
|
||||
|
||||
/**
|
||||
* Counter class for on-exit leakage check.
|
||||
*
|
||||
* This technique is learnt from <em>The C++ Programming Language</em> by
|
||||
* Bjarne Stroustup.
|
||||
*/
|
||||
class QX_DLL_EXPORT __debug_new_counter
|
||||
{
|
||||
static int _S_count;
|
||||
public:
|
||||
__debug_new_counter();
|
||||
~__debug_new_counter();
|
||||
};
|
||||
|
||||
/** Counting object for each file including debug_new.h. */
|
||||
static __debug_new_counter __debug_new_count;
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _DEBUG_NEW_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
367
include/QxMemLeak/fast_mutex.h
Normal file
367
include/QxMemLeak/fast_mutex.h
Normal file
@@ -0,0 +1,367 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file fast_mutex.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* A fast mutex implementation for POSIX and Win32.
|
||||
*
|
||||
* \version 1.18, 2005/05/06
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _FAST_MUTEX_H
|
||||
#define _FAST_MUTEX_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
# if !defined(_NOTHREADS)
|
||||
# if !defined(_WIN32THREADS) && \
|
||||
(defined(_WIN32) && defined(_MT))
|
||||
// Automatically use _WIN32THREADS when specifying -MT/-MD in MSVC,
|
||||
// or -mthreads in MinGW GCC.
|
||||
# define _WIN32THREADS
|
||||
# elif !defined(_PTHREADS) && \
|
||||
defined(_REENTRANT)
|
||||
// Automatically use _PTHREADS when specifying -pthread in GCC.
|
||||
// N.B. I do not detect on _PTHREAD_H since libstdc++-v3 under
|
||||
// Linux will silently include <pthread.h> anyway.
|
||||
# define _PTHREADS
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_PTHREADS) && !defined(_WIN32THREADS) && !defined(_NOTHREADS)
|
||||
# define _NOTHREADS
|
||||
# endif
|
||||
|
||||
# if defined(_NOTHREADS)
|
||||
# if defined(_PTHREADS) || defined(_WIN32THREADS)
|
||||
# undef _NOTHREADS
|
||||
# error "Cannot define multi-threaded mode with -D_NOTHREADS"
|
||||
# if defined(__MINGW32__) && defined(_WIN32THREADS) && !defined(_MT)
|
||||
# error "Be sure to specify -mthreads with -D_WIN32THREADS"
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
/**
|
||||
* Macro to control whether to check for initialization status for each
|
||||
* lock/unlock operation. Defining it to a non-zero value will enable
|
||||
* the check, so that the construction/destruction of a static object
|
||||
* using a static fast_mutex not yet constructed or already destroyed
|
||||
* will work (with lock/unlock operations ignored). Defining it to zero
|
||||
* will disable to check.
|
||||
*/
|
||||
# define _FAST_MUTEX_CHECK_INITIALIZATION 1
|
||||
# endif
|
||||
|
||||
# if defined(_PTHREADS) && defined(_WIN32THREADS)
|
||||
// Some C++ libraries have _PTHREADS defined even on Win32 platforms.
|
||||
// Thus this hack.
|
||||
# undef _PTHREADS
|
||||
# endif
|
||||
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
/** Macro for fast_mutex assertions. Real version (for debug mode). */
|
||||
# define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
|
||||
if (!(_Expr)) { \
|
||||
fprintf(stderr, "fast_mutex::%s\n", _Msg); \
|
||||
abort(); \
|
||||
}
|
||||
#else
|
||||
/** Macro for fast_mutex assertions. Fake version (for release mode). */
|
||||
# define _FAST_MUTEX_ASSERT(_Expr, _Msg) \
|
||||
((void)0)
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
|
||||
# ifdef _PTHREADS
|
||||
# include <pthread.h>
|
||||
/**
|
||||
* Macro alias to `volatile' semantics. Here it is truly volatile since
|
||||
* it is in a multi-threaded (POSIX threads) environment.
|
||||
*/
|
||||
# define __VOLATILE volatile
|
||||
/**
|
||||
* Class for non-reentrant fast mutexes. This is the implementation
|
||||
* for POSIX threads.
|
||||
*/
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
class fast_mutex
|
||||
{
|
||||
pthread_mutex_t _M_mtx_impl;
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
bool _M_initialized;
|
||||
# endif
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
bool _M_locked;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
public:
|
||||
fast_mutex()
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
: _M_locked(false)
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
{
|
||||
::pthread_mutex_init(&_M_mtx_impl, NULL);
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
_M_initialized = true;
|
||||
# endif
|
||||
}
|
||||
~fast_mutex()
|
||||
{
|
||||
_FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
_M_initialized = false;
|
||||
# endif
|
||||
::pthread_mutex_destroy(&_M_mtx_impl);
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
if (!_M_initialized)
|
||||
return;
|
||||
# endif
|
||||
::pthread_mutex_lock(&_M_mtx_impl);
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
// The following assertion should _always_ be true for a
|
||||
// real `fast' pthread_mutex. However, this assertion can
|
||||
// help sometimes, when people forget to use `-lpthread' and
|
||||
// glibc provides an empty implementation. Having this
|
||||
// assertion is also more consistent.
|
||||
_FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
|
||||
_M_locked = true;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
if (!_M_initialized)
|
||||
return;
|
||||
# endif
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
_FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
|
||||
_M_locked = false;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
::pthread_mutex_unlock(&_M_mtx_impl);
|
||||
}
|
||||
private:
|
||||
fast_mutex(const fast_mutex&);
|
||||
fast_mutex& operator=(const fast_mutex&);
|
||||
};
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
# endif // _PTHREADS
|
||||
|
||||
# ifdef _WIN32THREADS
|
||||
# include <windows.h>
|
||||
/**
|
||||
* Macro alias to `volatile' semantics. Here it is truly volatile since
|
||||
* it is in a multi-threaded (Win32 threads) environment.
|
||||
*/
|
||||
# define __VOLATILE volatile
|
||||
/**
|
||||
* Class for non-reentrant fast mutexes. This is the implementation
|
||||
* for Win32 threads.
|
||||
*/
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
class fast_mutex
|
||||
{
|
||||
CRITICAL_SECTION _M_mtx_impl;
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
bool _M_initialized;
|
||||
# endif
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
bool _M_locked;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
public:
|
||||
fast_mutex()
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
: _M_locked(false)
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
{
|
||||
::InitializeCriticalSection(&_M_mtx_impl);
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
_M_initialized = true;
|
||||
# endif
|
||||
}
|
||||
~fast_mutex()
|
||||
{
|
||||
_FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
_M_initialized = false;
|
||||
# endif
|
||||
::DeleteCriticalSection(&_M_mtx_impl);
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
if (!_M_initialized)
|
||||
return;
|
||||
# endif
|
||||
::EnterCriticalSection(&_M_mtx_impl);
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
_FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
|
||||
_M_locked = true;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
# if _FAST_MUTEX_CHECK_INITIALIZATION
|
||||
if (!_M_initialized)
|
||||
return;
|
||||
# endif
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
_FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
|
||||
_M_locked = false;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
::LeaveCriticalSection(&_M_mtx_impl);
|
||||
}
|
||||
private:
|
||||
fast_mutex(const fast_mutex&);
|
||||
fast_mutex& operator=(const fast_mutex&);
|
||||
};
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
# endif // _WIN32THREADS
|
||||
|
||||
# ifdef _NOTHREADS
|
||||
/**
|
||||
* Macro alias to `volatile' semantics. Here it is not truly volatile
|
||||
* since it is in a single-threaded environment.
|
||||
*/
|
||||
# define __VOLATILE
|
||||
/**
|
||||
* Class for non-reentrant fast mutexes. This is the null
|
||||
* implementation for single-threaded environments.
|
||||
*/
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
class fast_mutex
|
||||
{
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
bool _M_locked;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
public:
|
||||
fast_mutex()
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
: _M_locked(false)
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
{
|
||||
}
|
||||
~fast_mutex()
|
||||
{
|
||||
_FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked");
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
_FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked");
|
||||
_M_locked = true;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
_FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked");
|
||||
_M_locked = false;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
}
|
||||
private:
|
||||
fast_mutex(const fast_mutex&);
|
||||
fast_mutex& operator=(const fast_mutex&);
|
||||
};
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
# endif // _NOTHREADS
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
/** An acquistion-on-initialization lock class based on fast_mutex. */
|
||||
class QX_DLL_EXPORT fast_mutex_autolock
|
||||
{
|
||||
fast_mutex& _M_mtx;
|
||||
public:
|
||||
explicit fast_mutex_autolock(fast_mutex& __mtx) : _M_mtx(__mtx)
|
||||
{
|
||||
_M_mtx.lock();
|
||||
}
|
||||
~fast_mutex_autolock()
|
||||
{
|
||||
_M_mtx.unlock();
|
||||
}
|
||||
private:
|
||||
fast_mutex_autolock(const fast_mutex_autolock&);
|
||||
fast_mutex_autolock& operator=(const fast_mutex_autolock&);
|
||||
};
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _FAST_MUTEX_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
330
include/QxMemLeak/fixed_mem_pool.h
Normal file
330
include/QxMemLeak/fixed_mem_pool.h
Normal file
@@ -0,0 +1,330 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file fixed_mem_pool.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Definition of a fixed-size memory pool template for structs/classes.
|
||||
* This is a easy-to-use class template for pre-allocated memory pools.
|
||||
* The client side needs to do the following things:
|
||||
* - Use one of the macros #DECLARE_FIXED_MEM_POOL,
|
||||
* #DECLARE_FIXED_MEM_POOL__NOTHROW, and
|
||||
* #DECLARE_FIXED_MEM_POOL__THROW_NOCHECK at the end of the class
|
||||
* (say, \c class \e _Cls) definitions
|
||||
* - Call fixed_mem_pool<_Cls>::initialize at the beginning of the
|
||||
* program
|
||||
* - Optionally, specialize fixed_mem_pool<_Cls>::bad_alloc_handler to
|
||||
* change the behaviour when all memory blocks are allocated
|
||||
* - Optionally, call fixed_mem_pool<_Cls>::deinitialize at exit of the
|
||||
* program to check for memory leaks
|
||||
* - Optionally, call fixed_mem_pool<_Cls>::get_alloc_count to check
|
||||
* memory usage when the program is running
|
||||
*
|
||||
* \version 1.14, 2005/09/19
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _FIXED_MEM_POOL_H
|
||||
#define _FIXED_MEM_POOL_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "class_level_lock.h"
|
||||
#include "mem_pool_base.h"
|
||||
|
||||
/**
|
||||
* Defines the alignment of memory blocks.
|
||||
*/
|
||||
#ifndef MEM_POOL_ALIGNMENT
|
||||
#define MEM_POOL_ALIGNMENT 4
|
||||
#endif
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
/**
|
||||
* Class template to manipulate a fixed-size memory pool. Please notice
|
||||
* that only allocate and deallocate are protected by a lock.
|
||||
*
|
||||
* @param _Tp class to use the fixed_mem_pool
|
||||
*/
|
||||
template <class _Tp>
|
||||
class fixed_mem_pool
|
||||
{
|
||||
public:
|
||||
typedef typename class_level_lock<fixed_mem_pool<_Tp> >::lock lock;
|
||||
static void* allocate();
|
||||
static void deallocate(void*);
|
||||
static bool initialize(size_t __size);
|
||||
static int deinitialize();
|
||||
static int get_alloc_count();
|
||||
static bool is_initialized();
|
||||
protected:
|
||||
static bool bad_alloc_handler();
|
||||
private:
|
||||
static size_t _S_align(size_t __size);
|
||||
static void* _S_mem_pool_ptr;
|
||||
static void* _S_first_avail_ptr;
|
||||
static int _S_alloc_cnt;
|
||||
};
|
||||
|
||||
/** Pointer to the allocated chunk of memory. */
|
||||
template <class _Tp>
|
||||
void* fixed_mem_pool<_Tp>::_S_mem_pool_ptr = NULL;
|
||||
|
||||
/** Pointer to the first available memory block. */
|
||||
template <class _Tp>
|
||||
void* fixed_mem_pool<_Tp>::_S_first_avail_ptr = NULL;
|
||||
|
||||
/** Count of allocations. */
|
||||
template <class _Tp>
|
||||
int fixed_mem_pool<_Tp>::_S_alloc_cnt = 0;
|
||||
|
||||
/**
|
||||
* Allocates a memory block from the memory pool.
|
||||
*
|
||||
* @return pointer to the allocated memory block
|
||||
*/
|
||||
template <class _Tp>
|
||||
inline void* fixed_mem_pool<_Tp>::allocate()
|
||||
{
|
||||
lock __guard;
|
||||
for (;;)
|
||||
{
|
||||
if (void* __result = _S_first_avail_ptr)
|
||||
{
|
||||
_S_first_avail_ptr = *(void**)_S_first_avail_ptr;
|
||||
++_S_alloc_cnt;
|
||||
return __result;
|
||||
}
|
||||
else
|
||||
if (!bad_alloc_handler())
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates a memory block and returns it to the memory pool.
|
||||
*
|
||||
* @param __block_ptr pointer to the memory block to return
|
||||
*/
|
||||
template <class _Tp>
|
||||
inline void fixed_mem_pool<_Tp>::deallocate(void* __block_ptr)
|
||||
{
|
||||
if (__block_ptr == NULL)
|
||||
return;
|
||||
lock __guard;
|
||||
assert(_S_alloc_cnt != 0);
|
||||
--_S_alloc_cnt;
|
||||
*(void**)__block_ptr = _S_first_avail_ptr;
|
||||
_S_first_avail_ptr = __block_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the memory pool.
|
||||
*
|
||||
* @param __size number of memory blocks to put in the memory pool
|
||||
* @return \c true if successful; \c false if memory insufficient
|
||||
*/
|
||||
template <class _Tp>
|
||||
bool fixed_mem_pool<_Tp>::initialize(size_t __size)
|
||||
{
|
||||
size_t __block_size = _S_align(sizeof(_Tp));
|
||||
assert(!is_initialized());
|
||||
assert(__size > 0 && __block_size >= sizeof(void*));
|
||||
_S_mem_pool_ptr = mem_pool_base::alloc_sys(__size * __block_size);
|
||||
_S_first_avail_ptr = _S_mem_pool_ptr;
|
||||
if (_S_mem_pool_ptr == NULL)
|
||||
return false;
|
||||
char* __block_ = (char*)_S_mem_pool_ptr;
|
||||
while (--__size != 0)
|
||||
{
|
||||
char* __next_ = __block_ + __block_size;
|
||||
*(void**)__block_ = __next_;
|
||||
__block_ = __next_;
|
||||
}
|
||||
*(void**)__block_ = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitializes the memory pool.
|
||||
*
|
||||
* @return \c 0 if all memory blocks are returned and the memory pool
|
||||
* successfully freed; or a non-zero value indicating number of
|
||||
* memory blocks still in allocation
|
||||
*/
|
||||
template <class _Tp>
|
||||
int fixed_mem_pool<_Tp>::deinitialize()
|
||||
{
|
||||
if (_S_alloc_cnt != 0)
|
||||
return _S_alloc_cnt;
|
||||
assert(is_initialized());
|
||||
mem_pool_base::dealloc_sys(_S_mem_pool_ptr);
|
||||
_S_mem_pool_ptr = NULL;
|
||||
_S_first_avail_ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the allocation count.
|
||||
*
|
||||
* @return the number of memory blocks still in allocation
|
||||
*/
|
||||
template <class _Tp>
|
||||
inline int fixed_mem_pool<_Tp>::get_alloc_count()
|
||||
{
|
||||
return _S_alloc_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the memory pool initialized?
|
||||
*
|
||||
* @return \c true if it is successfully initialized; \c false otherwise
|
||||
*/
|
||||
template <class _Tp>
|
||||
inline bool fixed_mem_pool<_Tp>::is_initialized()
|
||||
{
|
||||
return _S_mem_pool_ptr != NULL;;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bad allocation handler. Called when there are no memory blocks
|
||||
* available in the memory pool. If this function returns \c false
|
||||
* (default behaviour if not explicitly specialized), it indicates that
|
||||
* it can do nothing and allocate() should return \c NULL; if this
|
||||
* function returns \c true, it indicates that it has freed some memory
|
||||
* blocks and allocate() should try allocating again.
|
||||
*/
|
||||
template <class _Tp>
|
||||
bool fixed_mem_pool<_Tp>::bad_alloc_handler()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aligns the memory block size.
|
||||
*
|
||||
* @param __size size to be aligned
|
||||
* @return aligned value of \a __size
|
||||
*/
|
||||
template <class _Tp>
|
||||
inline size_t fixed_mem_pool<_Tp>::_S_align(size_t __size)
|
||||
{
|
||||
return (__size + MEM_POOL_ALIGNMENT - 1)
|
||||
/ MEM_POOL_ALIGNMENT * MEM_POOL_ALIGNMENT;
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
/**
|
||||
* Declares the normal (exceptionable) overload of <b>operator new</b>
|
||||
* and <b>operator delete</b>.
|
||||
*
|
||||
* @param _Cls class to use the fixed_mem_pool
|
||||
* @see DECLARE_FIXED_MEM_POOL__THROW_NOCHECK, which, too,
|
||||
* defines an <b>operator new</b> that will never return
|
||||
* \c NULL, but requires more discipline on the
|
||||
* programmer's side.
|
||||
*/
|
||||
#define DECLARE_FIXED_MEM_POOL(_Cls) \
|
||||
public: \
|
||||
static void* operator new(size_t __size) \
|
||||
{ \
|
||||
assert(__size == sizeof(_Cls)); \
|
||||
if (void* __ptr = fixed_mem_pool<_Cls>::allocate()) \
|
||||
return __ptr; \
|
||||
else \
|
||||
throw std::bad_alloc(); \
|
||||
} \
|
||||
static void operator delete(void* __ptr) \
|
||||
{ \
|
||||
if (__ptr != NULL) \
|
||||
fixed_mem_pool<_Cls>::deallocate(__ptr); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares the non-exceptionable overload of <b>operator new</b> and
|
||||
* <b>operator delete</b>.
|
||||
*
|
||||
* @param _Cls class to use the fixed_mem_pool
|
||||
*/
|
||||
#define DECLARE_FIXED_MEM_POOL__NOTHROW(_Cls) \
|
||||
public: \
|
||||
static void* operator new(size_t __size) throw() \
|
||||
{ \
|
||||
assert(__size == sizeof(_Cls)); \
|
||||
return fixed_mem_pool<_Cls>::allocate(); \
|
||||
} \
|
||||
static void operator delete(void* __ptr) \
|
||||
{ \
|
||||
if (__ptr != NULL) \
|
||||
fixed_mem_pool<_Cls>::deallocate(__ptr); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares the exceptionable, non-checking overload of <b>operator
|
||||
* new</b> and <b>operator delete</b>.
|
||||
*
|
||||
* N.B. Using this macro \e requires users to explicitly specialize
|
||||
* fixed_mem_pool::bad_alloc_handler so that it shall never return
|
||||
* \c false (it may throw exceptions, say, \c std::bad_alloc, or simply
|
||||
* abort). Otherwise a segmentation fault might occur (instead of
|
||||
* returning a \c NULL pointer).
|
||||
*
|
||||
* @param _Cls class to use the fixed_mem_pool
|
||||
*/
|
||||
#define DECLARE_FIXED_MEM_POOL__THROW_NOCHECK(_Cls) \
|
||||
public: \
|
||||
static void* operator new(size_t __size) \
|
||||
{ \
|
||||
assert(__size == sizeof(_Cls)); \
|
||||
return fixed_mem_pool<_Cls>::allocate(); \
|
||||
} \
|
||||
static void operator delete(void* __ptr) \
|
||||
{ \
|
||||
if (__ptr != NULL) \
|
||||
fixed_mem_pool<_Cls>::deallocate(__ptr); \
|
||||
}
|
||||
|
||||
#endif // _FIXED_MEM_POOL_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
82
include/QxMemLeak/mem_leak.h
Normal file
82
include/QxMemLeak/mem_leak.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** https://www.qxorm.com/
|
||||
** Copyright (C) 2013 XDL Team (ic-east.com)
|
||||
**
|
||||
** This file is part of the QxOrm library
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any
|
||||
** damages arising from the use of this software
|
||||
**
|
||||
** Commercial Usage
|
||||
** Licensees holding valid commercial QxOrm licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and XDL Team
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file 'license.gpl3.txt' included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met : http://www.gnu.org/copyleft/gpl.html
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, or
|
||||
** if you have questions regarding the use of this file, please contact :
|
||||
** ic-east.com
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*** http://wyw.dcweb.cn/leakage.htm ***/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#define _DEBUG_NEW_REDEFINE_NEW 0
|
||||
#include "debug_new.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4290) // C++ exception specification ignored
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifndef QX_MEM_LEAK_STATIC_OR_INLINE
|
||||
#ifdef _MSC_VER
|
||||
#define QX_MEM_LEAK_STATIC_OR_INLINE static
|
||||
#else
|
||||
#define QX_MEM_LEAK_STATIC_OR_INLINE inline
|
||||
#endif // _MSC_VER
|
||||
#endif // QX_MEM_LEAK_STATIC_OR_INLINE
|
||||
|
||||
QX_MEM_LEAK_STATIC_OR_INLINE void *operator new(size_t size) throw(std::bad_alloc) { return operator new(size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); };
|
||||
QX_MEM_LEAK_STATIC_OR_INLINE void *operator new[](size_t size) throw(std::bad_alloc) { return operator new[](size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); };
|
||||
QX_MEM_LEAK_STATIC_OR_INLINE void operator delete(void *pointer) throw() { qx::memory::__debug_new_recorder::free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, false); };
|
||||
QX_MEM_LEAK_STATIC_OR_INLINE void operator delete[](void *pointer) throw() { qx::memory::__debug_new_recorder::free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, true); };
|
||||
|
||||
#if HAVE_PLACEMENT_DELETE
|
||||
QX_MEM_LEAK_STATIC_OR_INLINE void operator delete(void *pointer, const std::nothrow_t &) throw() { operator delete(pointer, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); };
|
||||
QX_MEM_LEAK_STATIC_OR_INLINE void operator delete[](void *pointer, const std::nothrow_t &) throw() { operator delete[](pointer, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); };
|
||||
#endif // HAVE_PLACEMENT_DELETE
|
||||
|
||||
#ifdef new
|
||||
#undef new
|
||||
#endif // new
|
||||
#define new DEBUG_NEW
|
||||
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#if (!_QX_USE_MEM_LEAK_DETECTION)
|
||||
#ifndef DEBUG_NEW
|
||||
#define DEBUG_NEW new
|
||||
#endif // DEBUG_NEW
|
||||
#endif // (! _QX_USE_MEM_LEAK_DETECTION)
|
||||
|
||||
#ifdef _QX_MODE_RELEASE
|
||||
#ifndef DEBUG_NEW
|
||||
#define DEBUG_NEW new
|
||||
#endif // DEBUG_NEW
|
||||
#endif // _QX_MODE_RELEASE
|
||||
77
include/QxMemLeak/mem_pool_base.h
Normal file
77
include/QxMemLeak/mem_pool_base.h
Normal file
@@ -0,0 +1,77 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file mem_pool_base.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Header file for the memory pool base.
|
||||
*
|
||||
* \version 1.1, 2004/07/26
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _MEM_POOL_BASE_H
|
||||
#define _MEM_POOL_BASE_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
/**
|
||||
* Base class for memory pools.
|
||||
*/
|
||||
class QX_DLL_EXPORT mem_pool_base
|
||||
{
|
||||
public:
|
||||
virtual ~mem_pool_base();
|
||||
virtual void recycle() = 0;
|
||||
static void* alloc_sys(size_t __size);
|
||||
static void dealloc_sys(void* __ptr);
|
||||
|
||||
/** Structure to store the next available memory block. */
|
||||
struct _Block_list { _Block_list* _M_next; };
|
||||
};
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _MEM_POOL_BASE_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
156
include/QxMemLeak/object_level_lock.h
Normal file
156
include/QxMemLeak/object_level_lock.h
Normal file
@@ -0,0 +1,156 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file object_level_lock.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* In essence Loki ObjectLevelLockable re-engineered to use a fast_mutex
|
||||
* class. Check also Andrei Alexandrescu's article <a
|
||||
* href="http://www.awprofessional.com/articles/article.asp?p=25298">
|
||||
* "Multithreading and the C++ Type System"</a> for the ideas behind.
|
||||
*
|
||||
* \version 1.4, 2004/05/09
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _OBJECT_LEVEL_LOCK_H
|
||||
#define _OBJECT_LEVEL_LOCK_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "fast_mutex.h"
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
# ifdef _NOTHREADS
|
||||
/**
|
||||
* Helper class for object-level locking. This is the
|
||||
* single-threaded implementation.
|
||||
*/
|
||||
template <class _Host>
|
||||
class object_level_lock
|
||||
{
|
||||
public:
|
||||
/** Type that provides locking/unlocking semantics. */
|
||||
class lock
|
||||
{
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
const object_level_lock& _M_host;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
lock(const lock&);
|
||||
lock& operator=(const lock&);
|
||||
public:
|
||||
explicit lock(const object_level_lock& __host)
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
: _M_host(__host)
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
{}
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
// The purpose of this method is allow one to write code
|
||||
// like "assert(guard.get_locked_object() == this)" to
|
||||
// ensure that the locked object is exactly the object being
|
||||
// accessed.
|
||||
const object_level_lock* get_locked_object() const
|
||||
{
|
||||
return &_M_host;
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
};
|
||||
|
||||
typedef _Host volatile_type;
|
||||
};
|
||||
# else
|
||||
/**
|
||||
* Helper class for class-level locking. This is the multi-threaded
|
||||
* implementation.
|
||||
*/
|
||||
template <class _Host>
|
||||
class object_level_lock
|
||||
{
|
||||
mutable fast_mutex _M_mtx;
|
||||
|
||||
public:
|
||||
class lock;
|
||||
friend class lock;
|
||||
|
||||
/** Type that provides locking/unlocking semantics. */
|
||||
class lock
|
||||
{
|
||||
const object_level_lock& _M_host;
|
||||
|
||||
lock(const lock&);
|
||||
lock& operator=(const lock&);
|
||||
public:
|
||||
explicit lock(const object_level_lock& __host) : _M_host(__host)
|
||||
{
|
||||
_M_host._M_mtx.lock();
|
||||
}
|
||||
~lock()
|
||||
{
|
||||
_M_host._M_mtx.unlock();
|
||||
}
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
// The purpose of this method is allow one to write code
|
||||
// like "assert(guard.get_locked_object() == this)" to
|
||||
// ensure that the locked object is exactly the object being
|
||||
// accessed.
|
||||
const object_level_lock* get_locked_object() const
|
||||
{
|
||||
return &_M_host;
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
};
|
||||
|
||||
typedef volatile _Host volatile_type;
|
||||
};
|
||||
# endif // _NOTHREADS
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _OBJECT_LEVEL_LOCK_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
112
include/QxMemLeak/pctimer.h
Normal file
112
include/QxMemLeak/pctimer.h
Normal file
@@ -0,0 +1,112 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file pctimer.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Function to get a high-resolution timer for Win32/Cygwin/Unix.
|
||||
*
|
||||
* \version 1.6, 2004/08/02
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
#ifndef _PCTIMER_H
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
typedef double pctimer_t;
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
|
||||
#ifndef _WIN32
|
||||
#define _PCTIMER_NO_WIN32
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif /* WIN32_LEAN_AND_MEAN */
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef _PCTIMER_NO_WIN32
|
||||
#undef _PCTIMER_NO_WIN32
|
||||
#undef _WIN32
|
||||
#endif /* _PCTIMER_NO_WIN32 */
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
__inline pctimer_t pctimer(void)
|
||||
{
|
||||
static LARGE_INTEGER __pcount, __pcfreq;
|
||||
static int __initflag;
|
||||
|
||||
if (!__initflag)
|
||||
{
|
||||
QueryPerformanceFrequency(&__pcfreq);
|
||||
__initflag++;
|
||||
}
|
||||
|
||||
QueryPerformanceCounter(&__pcount);
|
||||
return (double)__pcount.QuadPart / (double)__pcfreq.QuadPart;
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#else /* Not Win32/Cygwin */
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
__inline pctimer_t pctimer(void)
|
||||
{
|
||||
struct timeval __tv;
|
||||
gettimeofday(&__tv, NULL);
|
||||
return (double)__tv.tv_sec + (double)__tv.tv_usec / 1000000;
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif /* Win32/Cygwin */
|
||||
|
||||
#endif /* _PCTIMER_H */
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
162
include/QxMemLeak/set_assign.h
Normal file
162
include/QxMemLeak/set_assign.h
Normal file
@@ -0,0 +1,162 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file set_assign.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Definition of template functions set_assign_union and set_assign_difference.
|
||||
*
|
||||
* \version 1.5, 2004/07/26
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _SET_ASSIGN_H
|
||||
#define _SET_ASSIGN_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
template <class _Container, class _InputIter>
|
||||
_Container& set_assign_union(_Container& __dest,
|
||||
_InputIter __first,
|
||||
_InputIter __last)
|
||||
{
|
||||
typename _Container::iterator __first_dest = __dest.begin();
|
||||
typename _Container::iterator __last_dest = __dest.end();
|
||||
while (__first_dest != __last_dest && __first != __last)
|
||||
{
|
||||
if (*__first_dest < *__first)
|
||||
++__first_dest;
|
||||
else if (*__first < *__first_dest)
|
||||
{
|
||||
__dest.insert(__first_dest, *__first);
|
||||
++__first;
|
||||
}
|
||||
else // *__first_dest == *__first
|
||||
{
|
||||
++__first_dest;
|
||||
++__first;
|
||||
}
|
||||
}
|
||||
if (__first != __last)
|
||||
std::copy(__first, __last, inserter(__dest, __last_dest));
|
||||
return __dest;
|
||||
}
|
||||
|
||||
template <class _Container, class _InputIter, class _Compare>
|
||||
_Container& set_assign_union(_Container& __dest,
|
||||
_InputIter __first,
|
||||
_InputIter __last,
|
||||
_Compare __comp)
|
||||
{
|
||||
typename _Container::iterator __first_dest = __dest.begin();
|
||||
typename _Container::iterator __last_dest = __dest.end();
|
||||
while (__first_dest != __last_dest && __first != __last)
|
||||
{
|
||||
if (__comp(*__first_dest, *__first))
|
||||
++__first_dest;
|
||||
else if (__comp(*__first, *__first_dest))
|
||||
{
|
||||
__dest.insert(__first_dest, *__first);
|
||||
++__first;
|
||||
}
|
||||
else // *__first_dest is equivalent to *__first
|
||||
{
|
||||
++__first_dest;
|
||||
++__first;
|
||||
}
|
||||
}
|
||||
if (__first != __last)
|
||||
std::copy(__first, __last, inserter(__dest, __last_dest));
|
||||
return __dest;
|
||||
}
|
||||
|
||||
template <class _Container, class _InputIter>
|
||||
_Container& set_assign_difference(_Container& __dest,
|
||||
_InputIter __first,
|
||||
_InputIter __last)
|
||||
{
|
||||
typename _Container::iterator __first_dest = __dest.begin();
|
||||
typename _Container::iterator __last_dest = __dest.end();
|
||||
while (__first_dest != __last_dest && __first != __last)
|
||||
{
|
||||
if (*__first_dest < *__first)
|
||||
++__first_dest;
|
||||
else if (*__first < *__first_dest)
|
||||
++__first;
|
||||
else // *__first_dest == *__first
|
||||
{
|
||||
__dest.erase(__first_dest++);
|
||||
++__first;
|
||||
}
|
||||
}
|
||||
return __dest;
|
||||
}
|
||||
|
||||
template <class _Container, class _InputIter, class _Compare>
|
||||
_Container& set_assign_difference(_Container& __dest,
|
||||
_InputIter __first,
|
||||
_InputIter __last,
|
||||
_Compare __comp)
|
||||
{
|
||||
typename _Container::iterator __first_dest = __dest.begin();
|
||||
typename _Container::iterator __last_dest = __dest.end();
|
||||
while (__first_dest != __last_dest && __first != __last)
|
||||
{
|
||||
if (__comp(*__first_dest, *__first))
|
||||
++__first_dest;
|
||||
else if (__comp(*__first, *__first_dest))
|
||||
++__first;
|
||||
else // *__first_dest is equivalent to *__first
|
||||
{
|
||||
__dest.erase(__first_dest++);
|
||||
++__first;
|
||||
}
|
||||
}
|
||||
return __dest;
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#endif // _SET_ASSIGN_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
63
include/QxMemLeak/static_assert.h
Normal file
63
include/QxMemLeak/static_assert.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file static_assert.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Template class to check validity duing compile time (adapted from Loki).
|
||||
*
|
||||
* \version 1.2, 2005/11/22
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
#ifndef STATIC_ASSERT
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
template <bool> struct __nvwa_compile_time_error;
|
||||
template <> struct __nvwa_compile_time_error<true> {};
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#define STATIC_ASSERT(_Expr, _Msg) \
|
||||
{ \
|
||||
__nvwa_compile_time_error<((_Expr) != 0)> ERROR_##_Msg; \
|
||||
(void)ERROR_##_Msg; \
|
||||
}
|
||||
|
||||
#endif // STATIC_ASSERT
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
395
include/QxMemLeak/static_mem_pool.h
Normal file
395
include/QxMemLeak/static_mem_pool.h
Normal file
@@ -0,0 +1,395 @@
|
||||
// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
// vim:tabstop=4:shiftwidth=4:expandtab:
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute
|
||||
* it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must
|
||||
* not claim that you wrote the original software. If you use this
|
||||
* software in a product, an acknowledgement in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must
|
||||
* not be misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* This file is part of Stones of Nvwa:
|
||||
* http://sourceforge.net/projects/nvwa
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file static_mem_pool.h
|
||||
* \ingroup QxMemLeak
|
||||
*
|
||||
* Header file for the `static' memory pool.
|
||||
*
|
||||
* \version 1.20, 2007/10/20
|
||||
* \author Wu Yongwei
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#if _QX_USE_MEM_LEAK_DETECTION
|
||||
|
||||
#ifndef _STATIC_MEM_POOL_H
|
||||
#define _STATIC_MEM_POOL_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include "class_level_lock.h"
|
||||
#include "mem_pool_base.h"
|
||||
|
||||
/* Defines Work-around for Microsoft Visual C++ 6.0 and Borland C++ 5.5.1 */
|
||||
# if (defined(_MSC_VER) && _MSC_VER < 1300) \
|
||||
|| (defined(__BORLANDC__) && __BORLANDC__ < 0x600)
|
||||
# define __PRIVATE public
|
||||
# else
|
||||
# define __PRIVATE private
|
||||
# endif
|
||||
|
||||
/* Defines the macro for debugging output */
|
||||
# ifdef _STATIC_MEM_POOL_DEBUG
|
||||
# include <iostream>
|
||||
# define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \
|
||||
{ \
|
||||
if (_Lck) { \
|
||||
static_mem_pool_set::lock __guard; \
|
||||
std::cerr << "static_mem_pool: " << _Msg << std::endl; \
|
||||
} else { \
|
||||
std::cerr << "static_mem_pool: " << _Msg << std::endl; \
|
||||
} \
|
||||
}
|
||||
# else
|
||||
# define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \
|
||||
((void)0)
|
||||
# endif
|
||||
|
||||
namespace qx {
|
||||
namespace memory {
|
||||
|
||||
/**
|
||||
* Singleton class to maintain a set of existing instantiations of
|
||||
* static_mem_pool.
|
||||
*/
|
||||
class QX_DLL_EXPORT static_mem_pool_set
|
||||
{
|
||||
public:
|
||||
typedef class_level_lock<static_mem_pool_set>::lock lock;
|
||||
static static_mem_pool_set& instance();
|
||||
void recycle();
|
||||
void add(mem_pool_base* __memory_pool_p);
|
||||
|
||||
__PRIVATE:
|
||||
~static_mem_pool_set();
|
||||
private:
|
||||
static_mem_pool_set();
|
||||
|
||||
typedef std::vector<mem_pool_base*> container_type;
|
||||
container_type _M_memory_pool_set;
|
||||
|
||||
/* Forbid their use */
|
||||
static_mem_pool_set(const static_mem_pool_set&);
|
||||
const static_mem_pool_set& operator=(const static_mem_pool_set&);
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton class template to manage the allocation/deallocation of
|
||||
* memory blocks of one specific size.
|
||||
*
|
||||
* @param _Sz size of elements in the static_mem_pool
|
||||
* @param _Gid group id of a static_mem_pool: if it is negative,
|
||||
* simultaneous accesses to this static_mem_pool will be
|
||||
* protected from each other; otherwise no protection is
|
||||
* given
|
||||
*/
|
||||
template <size_t _Sz, int _Gid = -1>
|
||||
class static_mem_pool : public mem_pool_base
|
||||
{
|
||||
typedef typename class_level_lock<static_mem_pool<_Sz, _Gid>, (_Gid < 0)>
|
||||
::lock lock;
|
||||
public:
|
||||
/**
|
||||
* Gets the instance of the static memory pool. It will create the
|
||||
* instance if it does not already exist. Generally this function
|
||||
* is now not needed.
|
||||
*
|
||||
* @return reference to the instance of the static memory pool
|
||||
* @see instance_known
|
||||
*/
|
||||
static static_mem_pool& instance()
|
||||
{
|
||||
lock __guard;
|
||||
if (!_S_instance_p)
|
||||
{
|
||||
_S_instance_p = _S_create_instance();
|
||||
}
|
||||
return *_S_instance_p;
|
||||
}
|
||||
/**
|
||||
* Gets the known instance of the static memory pool. The instance
|
||||
* must already exist. Generally the static initializer of the
|
||||
* template guarantees it.
|
||||
*
|
||||
* @return reference to the instance of the static memory pool
|
||||
*/
|
||||
static static_mem_pool& instance_known()
|
||||
{
|
||||
assert(_S_instance_p != NULL);
|
||||
return *_S_instance_p;
|
||||
}
|
||||
/**
|
||||
* Allocates memory and returns its pointer. The template will try
|
||||
* to get it from the memory pool first, and request memory from the
|
||||
* system if there is no free memory in the pool.
|
||||
*
|
||||
* @return pointer to allocated memory if successful; \c NULL
|
||||
* otherwise
|
||||
*/
|
||||
void* allocate()
|
||||
{
|
||||
{
|
||||
lock __guard;
|
||||
if (_S_memory_block_p)
|
||||
{
|
||||
void* __result = _S_memory_block_p;
|
||||
_S_memory_block_p = _S_memory_block_p->_M_next;
|
||||
return __result;
|
||||
}
|
||||
}
|
||||
return _S_alloc_sys(_S_align(_Sz));
|
||||
}
|
||||
/**
|
||||
* Deallocates memory by putting the memory block into the pool.
|
||||
*
|
||||
* @param __ptr pointer to memory to be deallocated
|
||||
*/
|
||||
void deallocate(void* __ptr)
|
||||
{
|
||||
assert(__ptr != NULL);
|
||||
lock __guard;
|
||||
_Block_list* __block_ = reinterpret_cast<_Block_list*>(__ptr);
|
||||
__block_->_M_next = _S_memory_block_p;
|
||||
_S_memory_block_p = __block_;
|
||||
}
|
||||
virtual void recycle();
|
||||
|
||||
private:
|
||||
static_mem_pool()
|
||||
{
|
||||
_STATIC_MEM_POOL_TRACE(true, "static_mem_pool<" << _Sz << ','
|
||||
<< _Gid << "> is created");
|
||||
}
|
||||
~static_mem_pool()
|
||||
{
|
||||
#ifndef _QX_MODE_RELEASE
|
||||
#ifndef QT_NO_DEBUG
|
||||
// Empty the pool to avoid false memory leakage alarms. This is
|
||||
// generally not necessary for release binaries.
|
||||
_Block_list* __block_ = _S_memory_block_p;
|
||||
while (__block_)
|
||||
{
|
||||
_Block_list* __next_ = __block_->_M_next;
|
||||
dealloc_sys(__block_);
|
||||
__block_ = __next_;
|
||||
}
|
||||
_S_memory_block_p = NULL;
|
||||
#endif // QT_NO_DEBUG
|
||||
#endif // _QX_MODE_RELEASE
|
||||
_S_instance_p = NULL;
|
||||
_S_destroyed = true;
|
||||
_STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ','
|
||||
<< _Gid << "> is destroyed");
|
||||
}
|
||||
static size_t _S_align(size_t __size)
|
||||
{
|
||||
return __size >= sizeof(_Block_list) ? __size : sizeof(_Block_list);
|
||||
}
|
||||
static void* _S_alloc_sys(size_t __size);
|
||||
static static_mem_pool* _S_create_instance();
|
||||
|
||||
static bool _S_destroyed;
|
||||
static static_mem_pool* _S_instance_p;
|
||||
static mem_pool_base::_Block_list* _S_memory_block_p;
|
||||
|
||||
/* Forbid their use */
|
||||
static_mem_pool(const static_mem_pool&);
|
||||
const static_mem_pool& operator=(const static_mem_pool&);
|
||||
};
|
||||
|
||||
template <size_t _Sz, int _Gid> bool
|
||||
static_mem_pool<_Sz, _Gid>::_S_destroyed = false;
|
||||
template <size_t _Sz, int _Gid> mem_pool_base::_Block_list*
|
||||
static_mem_pool<_Sz, _Gid>::_S_memory_block_p = NULL;
|
||||
template <size_t _Sz, int _Gid> static_mem_pool<_Sz, _Gid>*
|
||||
static_mem_pool<_Sz, _Gid>::_S_instance_p = _S_create_instance();
|
||||
|
||||
/**
|
||||
* Recycles half of the free memory blocks in the memory pool to the
|
||||
* system. It is called when a memory request to the system (in other
|
||||
* instances of the static memory pool) fails.
|
||||
*/
|
||||
template <size_t _Sz, int _Gid>
|
||||
void static_mem_pool<_Sz, _Gid>::recycle()
|
||||
{
|
||||
// Only here the global lock in static_mem_pool_set is obtained
|
||||
// before the pool-specific lock. However, no race conditions are
|
||||
// found so far.
|
||||
lock __guard;
|
||||
_Block_list* __block_ = _S_memory_block_p;
|
||||
while (__block_)
|
||||
{
|
||||
if (_Block_list* __temp_ = __block_->_M_next)
|
||||
{
|
||||
_Block_list* __next_ = __temp_->_M_next;
|
||||
__block_->_M_next = __next_;
|
||||
dealloc_sys(__temp_);
|
||||
__block_ = __next_;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
_STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ','
|
||||
<< _Gid << "> is recycled");
|
||||
}
|
||||
|
||||
template <size_t _Sz, int _Gid>
|
||||
void* static_mem_pool<_Sz, _Gid>::_S_alloc_sys(size_t __size)
|
||||
{
|
||||
static_mem_pool_set::lock __guard;
|
||||
void* __result = mem_pool_base::alloc_sys(__size);
|
||||
if (!__result)
|
||||
{
|
||||
static_mem_pool_set::instance().recycle();
|
||||
__result = mem_pool_base::alloc_sys(__size);
|
||||
}
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <size_t _Sz, int _Gid>
|
||||
static_mem_pool<_Sz, _Gid>* static_mem_pool<_Sz, _Gid>::_S_create_instance()
|
||||
{
|
||||
if (_S_destroyed)
|
||||
throw std::runtime_error("dead reference detected");
|
||||
|
||||
static_mem_pool_set::instance(); // Force its creation
|
||||
static_mem_pool* __inst_p = new static_mem_pool();
|
||||
try
|
||||
{
|
||||
static_mem_pool_set::instance().add(__inst_p);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_STATIC_MEM_POOL_TRACE(true,
|
||||
"Exception occurs in static_mem_pool_set::add");
|
||||
// The strange cast below is to work around a bug in GCC 2.95.3
|
||||
delete static_cast<mem_pool_base*>(__inst_p);
|
||||
throw;
|
||||
}
|
||||
return __inst_p;
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
} // namespace qx
|
||||
|
||||
#define DECLARE_STATIC_MEM_POOL(_Cls) \
|
||||
public: \
|
||||
static void* operator new(size_t __size) \
|
||||
{ \
|
||||
assert(__size == sizeof(_Cls)); \
|
||||
void* __ptr; \
|
||||
__ptr = static_mem_pool<sizeof(_Cls)>:: \
|
||||
instance_known().allocate(); \
|
||||
if (__ptr == NULL) \
|
||||
throw std::bad_alloc(); \
|
||||
return __ptr; \
|
||||
} \
|
||||
static void operator delete(void* __ptr) \
|
||||
{ \
|
||||
if (__ptr) \
|
||||
static_mem_pool<sizeof(_Cls)>:: \
|
||||
instance_known().deallocate(__ptr); \
|
||||
}
|
||||
|
||||
#define DECLARE_STATIC_MEM_POOL__NOTHROW(_Cls) \
|
||||
public: \
|
||||
static void* operator new(size_t __size) throw() \
|
||||
{ \
|
||||
assert(__size == sizeof(_Cls)); \
|
||||
return static_mem_pool<sizeof(_Cls)>:: \
|
||||
instance_known().allocate(); \
|
||||
} \
|
||||
static void operator delete(void* __ptr) \
|
||||
{ \
|
||||
if (__ptr) \
|
||||
static_mem_pool<sizeof(_Cls)>:: \
|
||||
instance_known().deallocate(__ptr); \
|
||||
}
|
||||
|
||||
#define DECLARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \
|
||||
public: \
|
||||
static void* operator new(size_t __size) \
|
||||
{ \
|
||||
assert(__size == sizeof(_Cls)); \
|
||||
void* __ptr; \
|
||||
__ptr = static_mem_pool<sizeof(_Cls), (_Gid)>:: \
|
||||
instance_known().allocate(); \
|
||||
if (__ptr == NULL) \
|
||||
throw std::bad_alloc(); \
|
||||
return __ptr; \
|
||||
} \
|
||||
static void operator delete(void* __ptr) \
|
||||
{ \
|
||||
if (__ptr) \
|
||||
static_mem_pool<sizeof(_Cls), (_Gid)>:: \
|
||||
instance_known().deallocate(__ptr); \
|
||||
}
|
||||
|
||||
#define DECLARE_STATIC_MEM_POOL_GROUPED__NOTHROW(_Cls, _Gid) \
|
||||
public: \
|
||||
static void* operator new(size_t __size) throw() \
|
||||
{ \
|
||||
assert(__size == sizeof(_Cls)); \
|
||||
return static_mem_pool<sizeof(_Cls), (_Gid)>:: \
|
||||
instance_known().allocate(); \
|
||||
} \
|
||||
static void operator delete(void* __ptr) \
|
||||
{ \
|
||||
if (__ptr) \
|
||||
static_mem_pool<sizeof(_Cls), (_Gid)>:: \
|
||||
instance_known().deallocate(__ptr); \
|
||||
}
|
||||
|
||||
// OBSOLETE: no longer needed
|
||||
#define PREPARE_STATIC_MEM_POOL(_Cls) \
|
||||
std::cerr << "PREPARE_STATIC_MEM_POOL is obsolete!\n";
|
||||
|
||||
// OBSOLETE: no longer needed
|
||||
#define PREPARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \
|
||||
std::cerr << "PREPARE_STATIC_MEM_POOL_GROUPED is obsolete!\n";
|
||||
|
||||
#undef __PRIVATE
|
||||
|
||||
#endif // _STATIC_MEM_POOL_H
|
||||
#endif // _QX_USE_MEM_LEAK_DETECTION
|
||||
#endif // _QX_MODE_RELEASE
|
||||
#endif // QT_NO_DEBUG
|
||||
Reference in New Issue
Block a user