blob: bbe2783a2c30c333741201ed354a84ebe5a36b56 [file] [log] [blame]
/**************************************************************************
*
* rw_allocator.h - user-defined allocator type
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2006 Rogue Wave Software.
*
**************************************************************************/
#ifndef RW_ALLOCATOR_INCLUDED
#define RW_ALLOCATOR_INCLUDED
#include <testdefs.h>
_RWSTD_NAMESPACE (std) {
// declare to avoid dragging in all of <memory>
// (yes, it is undefined for programs to do that)
template <class T>
class allocator;
} // namespace std
struct _TEST_EXPORT SharedAlloc
{
// identifies each member function of a standard allocator class
enum MemFun {
m_ctor, // ordinary constructor
m_cpy_ctor, // copy constructor
m_cvt_ctor, // converting (template) constructor
m_cpy_assign, // ordinary assignment operator
m_cvt_assign, // converting (template) assignment operator
m_dtor, // destructor
m_allocate, m_deallocate,
m_construct, m_destroy,
m_address, m_max_size,
n_funs
};
// constructs an allocator object managing a memory pool
// of the specified size (bytes and blocks)
SharedAlloc (_RWSTD_SIZE_T /* max_bytes */ = _RWSTD_SIZE_MAX,
_RWSTD_SIZE_T /* max_blocks */ = _RWSTD_SIZE_MAX);
virtual ~SharedAlloc ();
// attempts to allocate storage for nelems objects of elemsize
// bytes each and returns a pointer to the allocated storage
// on success; throws std::bad_alloc on failure
virtual void*
allocate (_RWSTD_SIZE_T /* nelems */,
_RWSTD_SIZE_T /* elemsize */,
const void* /* hint */);
// deallocates storage at ptr allocated by a call to allocate
// for nelems objects of elemsize bytes each
virtual void
deallocate (void* /* ptr */,
_RWSTD_SIZE_T /* nelems */,
_RWSTD_SIZE_T /* elemsize */);
// returns the maximum number of objects of elemsize each
// that can be allocated from the pool managed by *this
virtual _RWSTD_SIZE_T
max_size (_RWSTD_SIZE_T /* elemsize */ = 1);
// records a call to the allocator member function fun and
// throws an exception derived from std::bad_alloc if the
// number of calls to the member function reaches the limit
// specified by throw_at_calls_
virtual void
funcall (MemFun /* fun */, const SharedAlloc* = 0);
// gets or sets a pointer to the global allocator object
static SharedAlloc*
instance (SharedAlloc* = 0);
// returns a unique id of this allocator object
int id () const { return id_; }
// resets the n_calls_ array to all zeros
void reset_call_counters ();
// returns the name of the member function
static const char* func_name (MemFun);
_RWSTD_SIZE_T max_bytes_; // memory pool size in bytes
_RWSTD_SIZE_T max_blocks_; // memory pool size in blocks
_RWSTD_SIZE_T n_bytes_; // number of allocated bytes
_RWSTD_SIZE_T n_blocks_; // number of allocated blocks
_RWSTD_SIZE_T n_refs_; // number of references
// counter of the number of calls to each allocator member function
// made throughout the lifetime of this object
_RWSTD_SIZE_T n_calls_ [n_funs];
// counter of the number of exceptions thrown by each member function
// throughout the lifetime of this object
_RWSTD_SIZE_T n_throws_ [n_funs];
// member function counter value that, when reached, will cause
// an exception derived from std::bad_alloc to be thrown
_RWSTD_SIZE_T throw_at_calls_ [n_funs];
private:
int id_;
};
// allocator types for easy specialization
template <class T>
struct AllocTypes
{
typedef _RWSTD_SIZE_T size_type;
typedef _RWSTD_PTRDIFF_T difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
};
template <class T, class Types = AllocTypes<T> >
struct UserAlloc
{
// private:
SharedAlloc* pal_;
public:
typedef T value_type;
typedef typename Types::size_type size_type;
typedef typename Types::difference_type difference_type;
typedef typename Types::pointer pointer;
typedef typename Types::const_pointer const_pointer;
typedef typename Types::reference reference;
typedef typename Types::const_reference const_reference;
UserAlloc (SharedAlloc *pal = 0) _THROWS (())
: pal_ (pal ? pal : SharedAlloc::instance ()) {
RW_ASSERT (0 != pal_);
pal_->funcall (pal_->m_ctor);
}
UserAlloc (const UserAlloc &rhs) _THROWS (())
: pal_ (rhs.pal_) {
RW_ASSERT (0 != pal_);
pal_->funcall (pal_->m_cpy_ctor);
}
template <class U>
UserAlloc (const UserAlloc<U> &rhs) _THROWS (())
: pal_ (rhs.pal_) {
RW_ASSERT (0 != pal_);
pal_->funcall (pal_->m_cvt_ctor);
}
template <class U>
void operator= (const UserAlloc<U> &rhs) {
pal_->funcall (pal_->m_cvt_assign, rhs.pal_);
pal_ = rhs.pal_;
}
template <class U>
struct rebind { typedef UserAlloc<U> other; };
void operator= (const UserAlloc &rhs) {
pal_->funcall (pal_->m_cpy_assign, rhs.pal_);
pal_ = rhs.pal_;
}
~UserAlloc () {
pal_->funcall (pal_->m_dtor);
}
pointer allocate (size_type nelems, const void *hint = 0) {
void* const ptr = pal_->allocate (nelems, sizeof (value_type), hint);
return _RWSTD_STATIC_CAST (pointer, ptr);
}
void deallocate (pointer ptr, size_type nelems) {
pal_->deallocate (ptr, nelems, sizeof (value_type));
}
void construct (pointer ptr, const_reference val) {
pal_->funcall (pal_->m_construct);
new (ptr) value_type (val);
}
void destroy (pointer ptr) {
pal_->funcall (pal_->m_destroy);
ptr->~T ();
}
pointer address (reference ref) const {
pal_->funcall (pal_->m_address);
return &ref;
}
const_pointer address (const_reference ref) const {
pal_->funcall (pal_->m_address);
return &ref;
}
size_type max_size () const _THROWS (()) {
return pal_->max_size (sizeof (value_type));
}
bool operator== (const UserAlloc &rhs) const {
return pal_->id () == rhs.pal_->id ();
}
bool operator!= (const UserAlloc &rhs) const {
return !operator== (rhs);
}
};
// when (line <= 0) establishes a new check point for memory leaks
// by storing the number and size of blocks of storage currently
// allocated by operator new and by the SharedAlloc object pointed
// to by palloc (when non-zero)
// when (line > 0) reports the difference between the the number
// and size of blocks of storage allocated at the last checkpoint
// and the values specified by expect_blocks and expect_bytes
_TEST_EXPORT void
rw_check_leaks (const SharedAlloc* /* palloc */ = 0,
int /* line */ = 0,
_RWSTD_SIZE_T /* expect_blocks */ = 0,
_RWSTD_SIZE_T /* expect_bytes */ = _RWSTD_SIZE_MAX);
// when (line <= 0) establishes a new check point for memory leaks
// by storing the number and size of blocks of storage currently
// allocated by operator new
// when (line > 0) reports the difference between the the number
// and size of blocks of storage allocated at the last checkpoint
// and the values specified by expect_blocks and expect_bytes
template <class charT>
inline void
rw_check_leaks (const std::allocator<charT>& /* unused */,
int line = 0,
_RWSTD_SIZE_T expect_blocks = 0,
_RWSTD_SIZE_T expect_bytes = _RWSTD_SIZE_MAX)
{
// can't track memory leaks here
rw_check_leaks ((SharedAlloc*)0, line, expect_blocks, expect_bytes);
}
// when (line <= 0) establishes a new check point for memory leaks
// by storing the number and size of blocks of storage currently
// allocated by operator new and by the user-defined allocator
// specified by the first argument
// when (line > 0) reports the difference between the the number
// and size of blocks of storage allocated at the last checkpoint
// and the values specified by expect_blocks and expect_bytes
template <class charT, class Types>
inline void
rw_check_leaks (const UserAlloc<charT, Types> &alloc,
int line = 0,
_RWSTD_SIZE_T expect_blocks = 0,
_RWSTD_SIZE_T expect_bytes = _RWSTD_SIZE_MAX)
{
// track memory leaks via SharedAlloc
rw_check_leaks (alloc.pal_, line, expect_blocks, expect_bytes);
}
#endif // RW_ALLOCATOR_INCLUDED