| /************************************************************************** |
| * |
| * 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 <rw_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 |