Chris@16: #ifndef BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED Chris@16: #define BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED Chris@16: Chris@16: // MS compatible compilers support #pragma once Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1020) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: // Chris@16: // detail/quick_allocator.hpp Chris@16: // Chris@16: // Copyright (c) 2003 David Abrahams Chris@16: // Copyright (c) 2003 Peter Dimov Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include // ::operator new, ::operator delete Chris@16: #include // std::size_t Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: Chris@16: template union freeblock Chris@16: { Chris@16: typedef typename boost::type_with_alignment::type aligner_type; Chris@16: aligner_type aligner; Chris@16: char bytes[size]; Chris@16: freeblock * next; Chris@16: }; Chris@16: Chris@16: template struct allocator_impl Chris@16: { Chris@16: typedef freeblock block; Chris@16: Chris@16: // It may seem odd to use such small pages. Chris@16: // Chris@16: // However, on a typical Windows implementation that uses Chris@16: // the OS allocator, "normal size" pages interact with the Chris@16: // "ordinary" operator new, slowing it down dramatically. Chris@16: // Chris@16: // 512 byte pages are handled by the small object allocator, Chris@16: // and don't interfere with ::new. Chris@16: // Chris@16: // The other alternative is to use much bigger pages (1M.) Chris@16: // Chris@16: // It is surprisingly easy to hit pathological behavior by Chris@16: // varying the page size. g++ 2.96 on Red Hat Linux 7.2, Chris@16: // for example, passionately dislikes 496. 512 seems OK. Chris@16: Chris@16: #if defined(BOOST_QA_PAGE_SIZE) Chris@16: Chris@16: enum { items_per_page = BOOST_QA_PAGE_SIZE / size }; Chris@16: Chris@16: #else Chris@16: Chris@16: enum { items_per_page = 512 / size }; // 1048560 / size Chris@16: Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: Chris@16: static lightweight_mutex & mutex() Chris@16: { Chris@16: static freeblock< sizeof( lightweight_mutex ), boost::alignment_of< lightweight_mutex >::value > fbm; Chris@16: static lightweight_mutex * pm = new( &fbm ) lightweight_mutex; Chris@16: return *pm; Chris@16: } Chris@16: Chris@16: static lightweight_mutex * mutex_init; Chris@16: Chris@16: #endif Chris@16: Chris@16: static block * free; Chris@16: static block * page; Chris@16: static unsigned last; Chris@16: Chris@16: static inline void * alloc() Chris@16: { Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: lightweight_mutex::scoped_lock lock( mutex() ); Chris@16: #endif Chris@16: if(block * x = free) Chris@16: { Chris@16: free = x->next; Chris@16: return x; Chris@16: } Chris@16: else Chris@16: { Chris@16: if(last == items_per_page) Chris@16: { Chris@16: // "Listen to me carefully: there is no memory leak" Chris@16: // -- Scott Meyers, Eff C++ 2nd Ed Item 10 Chris@16: page = ::new block[items_per_page]; Chris@16: last = 0; Chris@16: } Chris@16: Chris@16: return &page[last++]; Chris@16: } Chris@16: } Chris@16: Chris@16: static inline void * alloc(std::size_t n) Chris@16: { Chris@16: if(n != size) // class-specific new called for a derived object Chris@16: { Chris@16: return ::operator new(n); Chris@16: } Chris@16: else Chris@16: { Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: lightweight_mutex::scoped_lock lock( mutex() ); Chris@16: #endif Chris@16: if(block * x = free) Chris@16: { Chris@16: free = x->next; Chris@16: return x; Chris@16: } Chris@16: else Chris@16: { Chris@16: if(last == items_per_page) Chris@16: { Chris@16: page = ::new block[items_per_page]; Chris@16: last = 0; Chris@16: } Chris@16: Chris@16: return &page[last++]; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: static inline void dealloc(void * pv) Chris@16: { Chris@16: if(pv != 0) // 18.4.1.1/13 Chris@16: { Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: lightweight_mutex::scoped_lock lock( mutex() ); Chris@16: #endif Chris@16: block * pb = static_cast(pv); Chris@16: pb->next = free; Chris@16: free = pb; Chris@16: } Chris@16: } Chris@16: Chris@16: static inline void dealloc(void * pv, std::size_t n) Chris@16: { Chris@16: if(n != size) // class-specific delete called for a derived object Chris@16: { Chris@16: ::operator delete(pv); Chris@16: } Chris@16: else if(pv != 0) // 18.4.1.1/13 Chris@16: { Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: lightweight_mutex::scoped_lock lock( mutex() ); Chris@16: #endif Chris@16: block * pb = static_cast(pv); Chris@16: pb->next = free; Chris@16: free = pb; Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: Chris@16: template Chris@16: lightweight_mutex * allocator_impl::mutex_init = &allocator_impl::mutex(); Chris@16: Chris@16: #endif Chris@16: Chris@16: template Chris@16: freeblock * allocator_impl::free = 0; Chris@16: Chris@16: template Chris@16: freeblock * allocator_impl::page = 0; Chris@16: Chris@16: template Chris@16: unsigned allocator_impl::last = allocator_impl::items_per_page; Chris@16: Chris@16: template Chris@16: struct quick_allocator: public allocator_impl< sizeof(T), boost::alignment_of::value > Chris@16: { Chris@16: }; Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #endif // #ifndef BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED