first commit

This commit is contained in:
bing
2026-04-03 11:32:07 +08:00
commit 003be19522
1142 changed files with 185854 additions and 0 deletions

View 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&lt;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&lt;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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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

View 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

View 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