mirror of
				https://github.com/boostorg/smart_ptr.git
				synced 2025-11-04 09:41:43 +01:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			feature/de
			...
			feature/qu
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					82e80c7175 | ||
| 
						 | 
					81318213a6 | ||
| 
						 | 
					85c2a6ea74 | ||
| 
						 | 
					9723621128 | 
@@ -1,198 +1,63 @@
 | 
			
		||||
#ifndef BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED
 | 
			
		||||
#define BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED
 | 
			
		||||
 | 
			
		||||
// MS compatible compilers support #pragma once
 | 
			
		||||
// Copyright 2003 David Abrahams
 | 
			
		||||
// Copyright 2003, 2025 Peter Dimov
 | 
			
		||||
// Distributed under the Boost Software License, Version 1.0.
 | 
			
		||||
// https://www.boost.org/LICENSE_1_0.txt
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
 | 
			
		||||
# pragma once
 | 
			
		||||
#endif
 | 
			
		||||
#include <boost/config/header_deprecated.hpp>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
//  detail/quick_allocator.hpp
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2003 David Abrahams
 | 
			
		||||
//  Copyright (c) 2003 Peter Dimov
 | 
			
		||||
//
 | 
			
		||||
// Distributed under the Boost Software License, Version 1.0. (See
 | 
			
		||||
// accompanying file LICENSE_1_0.txt or copy at
 | 
			
		||||
// http://www.boost.org/LICENSE_1_0.txt)
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
 | 
			
		||||
#include <boost/smart_ptr/detail/lightweight_mutex.hpp>
 | 
			
		||||
#include <boost/smart_ptr/detail/sp_type_traits.hpp>
 | 
			
		||||
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <new>              // ::operator new, ::operator delete
 | 
			
		||||
#include <cstddef>          // std::size_t
 | 
			
		||||
BOOST_HEADER_DEPRECATED("std::allocator or std::pmr::synchronized_pool_resource")
 | 
			
		||||
 | 
			
		||||
namespace boost
 | 
			
		||||
{
 | 
			
		||||
namespace detail
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template<unsigned size, unsigned align_> union freeblock
 | 
			
		||||
template<class T> struct quick_allocator
 | 
			
		||||
{
 | 
			
		||||
    typedef typename sp_type_with_alignment<align_>::type aligner_type;
 | 
			
		||||
    aligner_type aligner;
 | 
			
		||||
    char bytes[size];
 | 
			
		||||
    freeblock * next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<unsigned size, unsigned align_> struct allocator_impl
 | 
			
		||||
{
 | 
			
		||||
    typedef freeblock<size, align_> block;
 | 
			
		||||
 | 
			
		||||
    // It may seem odd to use such small pages.
 | 
			
		||||
    //
 | 
			
		||||
    // However, on a typical Windows implementation that uses
 | 
			
		||||
    // the OS allocator, "normal size" pages interact with the
 | 
			
		||||
    // "ordinary" operator new, slowing it down dramatically.
 | 
			
		||||
    //
 | 
			
		||||
    // 512 byte pages are handled by the small object allocator,
 | 
			
		||||
    // and don't interfere with ::new.
 | 
			
		||||
    //
 | 
			
		||||
    // The other alternative is to use much bigger pages (1M.)
 | 
			
		||||
    //
 | 
			
		||||
    // It is surprisingly easy to hit pathological behavior by
 | 
			
		||||
    // varying the page size. g++ 2.96 on Red Hat Linux 7.2,
 | 
			
		||||
    // for example, passionately dislikes 496. 512 seems OK.
 | 
			
		||||
 | 
			
		||||
#if defined(BOOST_QA_PAGE_SIZE)
 | 
			
		||||
 | 
			
		||||
    enum { items_per_page = BOOST_QA_PAGE_SIZE / size };
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
    enum { items_per_page = 512 / size }; // 1048560 / size
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef BOOST_HAS_THREADS
 | 
			
		||||
 | 
			
		||||
    static lightweight_mutex & mutex()
 | 
			
		||||
    static void* alloc()
 | 
			
		||||
    {
 | 
			
		||||
        static freeblock< sizeof( lightweight_mutex ), std::alignment_of< lightweight_mutex >::value > fbm;
 | 
			
		||||
        static lightweight_mutex * pm = new( &fbm ) lightweight_mutex;
 | 
			
		||||
        return *pm;
 | 
			
		||||
        return std::allocator<T>().allocate( 1 );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static lightweight_mutex * mutex_init;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    static block * free;
 | 
			
		||||
    static block * page;
 | 
			
		||||
    static unsigned last;
 | 
			
		||||
 | 
			
		||||
    static inline void * alloc()
 | 
			
		||||
    static void* alloc( std::size_t n )
 | 
			
		||||
    {
 | 
			
		||||
#ifdef BOOST_HAS_THREADS
 | 
			
		||||
        lightweight_mutex::scoped_lock lock( mutex() );
 | 
			
		||||
#endif
 | 
			
		||||
        if(block * x = free)
 | 
			
		||||
        if( n != sizeof(T) ) // class-specific delete called for a derived object
 | 
			
		||||
        {
 | 
			
		||||
            free = x->next;
 | 
			
		||||
            return x;
 | 
			
		||||
            return ::operator new( n );
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if(last == items_per_page)
 | 
			
		||||
            {
 | 
			
		||||
                // "Listen to me carefully: there is no memory leak"
 | 
			
		||||
                // -- Scott Meyers, Eff C++ 2nd Ed Item 10
 | 
			
		||||
                page = ::new block[items_per_page];
 | 
			
		||||
                last = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return &page[last++];
 | 
			
		||||
            return alloc();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void * alloc(std::size_t n)
 | 
			
		||||
    static void dealloc( void* p )
 | 
			
		||||
    {
 | 
			
		||||
        if(n != size) // class-specific new called for a derived object
 | 
			
		||||
        if( p != 0 ) // 18.4.1.1/13
 | 
			
		||||
        {
 | 
			
		||||
            return ::operator new(n);
 | 
			
		||||
            std::allocator<T>().deallocate( static_cast<T*>( p ), 1 );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void dealloc( void* p, std::size_t n )
 | 
			
		||||
    {
 | 
			
		||||
        if( n != sizeof(T) ) // class-specific delete called for a derived object
 | 
			
		||||
        {
 | 
			
		||||
            ::operator delete( p );
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
#ifdef BOOST_HAS_THREADS
 | 
			
		||||
            lightweight_mutex::scoped_lock lock( mutex() );
 | 
			
		||||
#endif
 | 
			
		||||
            if(block * x = free)
 | 
			
		||||
            {
 | 
			
		||||
                free = x->next;
 | 
			
		||||
                return x;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if(last == items_per_page)
 | 
			
		||||
                {
 | 
			
		||||
                    page = ::new block[items_per_page];
 | 
			
		||||
                    last = 0;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return &page[last++];
 | 
			
		||||
            }
 | 
			
		||||
            dealloc( p );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void dealloc(void * pv)
 | 
			
		||||
    {
 | 
			
		||||
        if(pv != 0) // 18.4.1.1/13
 | 
			
		||||
        {
 | 
			
		||||
#ifdef BOOST_HAS_THREADS
 | 
			
		||||
            lightweight_mutex::scoped_lock lock( mutex() );
 | 
			
		||||
#endif
 | 
			
		||||
            block * pb = static_cast<block *>(pv);
 | 
			
		||||
            pb->next = free;
 | 
			
		||||
            free = pb;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void dealloc(void * pv, std::size_t n)
 | 
			
		||||
    {
 | 
			
		||||
        if(n != size) // class-specific delete called for a derived object
 | 
			
		||||
        {
 | 
			
		||||
            ::operator delete(pv);
 | 
			
		||||
        }
 | 
			
		||||
        else if(pv != 0) // 18.4.1.1/13
 | 
			
		||||
        {
 | 
			
		||||
#ifdef BOOST_HAS_THREADS
 | 
			
		||||
            lightweight_mutex::scoped_lock lock( mutex() );
 | 
			
		||||
#endif
 | 
			
		||||
            block * pb = static_cast<block *>(pv);
 | 
			
		||||
            pb->next = free;
 | 
			
		||||
            free = pb;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef BOOST_HAS_THREADS
 | 
			
		||||
 | 
			
		||||
template<unsigned size, unsigned align_>
 | 
			
		||||
  lightweight_mutex * allocator_impl<size, align_>::mutex_init = &allocator_impl<size, align_>::mutex();
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
template<unsigned size, unsigned align_>
 | 
			
		||||
  freeblock<size, align_> * allocator_impl<size, align_>::free = 0;
 | 
			
		||||
 | 
			
		||||
template<unsigned size, unsigned align_>
 | 
			
		||||
  freeblock<size, align_> * allocator_impl<size, align_>::page = 0;
 | 
			
		||||
 | 
			
		||||
template<unsigned size, unsigned align_>
 | 
			
		||||
  unsigned allocator_impl<size, align_>::last = allocator_impl<size, align_>::items_per_page;
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
struct quick_allocator: public allocator_impl< sizeof(T), std::alignment_of<T>::value >
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace detail
 | 
			
		||||
 | 
			
		||||
} // namespace boost
 | 
			
		||||
 | 
			
		||||
#endif  // #ifndef BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED
 | 
			
		||||
 
 | 
			
		||||
@@ -429,3 +429,6 @@ run sp_type_with_alignment_test.cpp ;
 | 
			
		||||
run sp_ostream_test.cpp ;
 | 
			
		||||
run ip_ostream_test.cpp ;
 | 
			
		||||
run lsp_ostream_test.cpp ;
 | 
			
		||||
 | 
			
		||||
run shared_ptr_alloc_test.cpp ;
 | 
			
		||||
run quick_allocator_test.cpp ;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										99
									
								
								test/quick_allocator_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								test/quick_allocator_test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
// Copyright 2025 Peter Dimov
 | 
			
		||||
// Distributed under the Boost Software License, Version 1.0.
 | 
			
		||||
// https://www.boost.org/LICENSE_1_0.txt
 | 
			
		||||
 | 
			
		||||
#include <boost/smart_ptr/detail/quick_allocator.hpp>
 | 
			
		||||
#include <boost/core/lightweight_test.hpp>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
// The interface of quick_allocator has never been documented,
 | 
			
		||||
// but in can be inferred from the source code to be
 | 
			
		||||
//
 | 
			
		||||
// template<class T> struct quick_allocator
 | 
			
		||||
// {
 | 
			
		||||
//     // allocate memory for an object of type T
 | 
			
		||||
//     static void* alloc();
 | 
			
		||||
//
 | 
			
		||||
//     // deallocate the memory returned from alloc()
 | 
			
		||||
//     // if p == 0, no effect
 | 
			
		||||
//     static void dealloc( void* p );
 | 
			
		||||
//
 | 
			
		||||
//     // if n == sizeof(T), returns alloc()
 | 
			
		||||
//     // otherwise, allocates a memory block of size n
 | 
			
		||||
//     static void* alloc( std::size_t n );
 | 
			
		||||
//
 | 
			
		||||
//     // deallocate the memory returned from alloc( n )
 | 
			
		||||
//     // if p == 0, no effect
 | 
			
		||||
//     static void dealloc( void* p, std::size_t n );
 | 
			
		||||
//  };
 | 
			
		||||
 | 
			
		||||
struct X
 | 
			
		||||
{
 | 
			
		||||
    int data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Y: public X
 | 
			
		||||
{
 | 
			
		||||
    int data2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    using boost::detail::quick_allocator;
 | 
			
		||||
 | 
			
		||||
    void* p = quick_allocator<Y>::alloc();
 | 
			
		||||
    std::memset( p, 0xAA, sizeof(Y) );
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        void* p1 = quick_allocator<X>::alloc();
 | 
			
		||||
        std::memset( p1, 0xCC, sizeof(X) );
 | 
			
		||||
 | 
			
		||||
        void* p2 = quick_allocator<X>::alloc();
 | 
			
		||||
        std::memset( p2, 0xDD, sizeof(X) );
 | 
			
		||||
 | 
			
		||||
        BOOST_TEST_NE( p1, p2 );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p1 ), 0xCC );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p2 ), 0xDD );
 | 
			
		||||
 | 
			
		||||
        quick_allocator<X>::dealloc( 0 );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p1 ), 0xCC );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p2 ), 0xDD );
 | 
			
		||||
 | 
			
		||||
        quick_allocator<X>::dealloc( p1 );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p2 ), 0xDD );
 | 
			
		||||
 | 
			
		||||
        quick_allocator<X>::dealloc( p2 );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        void* p1 = quick_allocator<X>::alloc( sizeof(X) );
 | 
			
		||||
        std::memset( p1, 0xCC, sizeof(X) );
 | 
			
		||||
 | 
			
		||||
        void* p2 = quick_allocator<X>::alloc( sizeof(Y) );
 | 
			
		||||
        std::memset( p2, 0xDD, sizeof(Y) );
 | 
			
		||||
 | 
			
		||||
        BOOST_TEST_NE( p1, p2 );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p1 ), 0xCC );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p2 ), 0xDD );
 | 
			
		||||
 | 
			
		||||
        quick_allocator<X>::dealloc( 0, sizeof(X) );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p1 ), 0xCC );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p2 ), 0xDD );
 | 
			
		||||
 | 
			
		||||
        quick_allocator<X>::dealloc( p1, sizeof(X) );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p2 ), 0xDD );
 | 
			
		||||
 | 
			
		||||
        quick_allocator<X>::dealloc( 0, sizeof(Y) );
 | 
			
		||||
        BOOST_TEST_EQ( *static_cast<unsigned char*>( p2 ), 0xDD );
 | 
			
		||||
 | 
			
		||||
        quick_allocator<X>::dealloc( p2, sizeof(Y) );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BOOST_TEST_EQ( *static_cast<unsigned char*>( p ), 0xAA );
 | 
			
		||||
    quick_allocator<Y>::dealloc( 0 );
 | 
			
		||||
 | 
			
		||||
    BOOST_TEST_EQ( *static_cast<unsigned char*>( p ), 0xAA );
 | 
			
		||||
    quick_allocator<Y>::dealloc( p );
 | 
			
		||||
 | 
			
		||||
    return boost::report_errors();
 | 
			
		||||
}
 | 
			
		||||
@@ -52,7 +52,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    void * operator new(std::size_t)
 | 
			
		||||
    {
 | 
			
		||||
        return std::allocator<X>().allocate(1, static_cast<X*>(0));
 | 
			
		||||
        return std::allocator<X>().allocate(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void operator delete(void * p)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user