MemMan 3 beta

/**************************************************
 *
 * MemMan 3.0.0.0 beta
 *
 * Copyright (C) 2007 - 2008 by Len3d
 * All rights reserved.
 *
 ************************************************
*/


#ifndef __MEM_MAN__
#define __MEM_MAN__

#include 
<vector>
#include 
<algorithm>
#include 
<malloc.h>

#pragma pack(push,
1)

namespace mem {

    
#define mem_inline        __forceinline

    
#define    mem_page_size    ( 1 << 18 )
    
#define mem_align_size    16
    
#define mem_align        __declspec( align( mem_align_size ) )

    typedef unsigned 
int    prior_type;
    typedef unsigned 
long    time_type;
    typedef unsigned 
long    size_type;
    typedef unsigned 
char    byte;

    
#define mem_max( a, b )    ( ( (a) > (b) ) ? (a) : (b) )
    
#define mem_min( a, b )    ( ( (a) < (b) ) ? (a) : (b) )

    
enum {
        ENTRY_PRIORITY 
= 0,
    }
;

    
class heap {
    
public:
        mem_inline heap( size_type max_size )
        
{
            allocated_size 
= 0;
            available_size 
= max_size;
        }


        mem_inline 
~heap()
        
{
        }


        mem_inline 
void *alloc( size_type size )
        
{
            
if( size == 0 )
                
return NULL;

            allocated_size 
+= size;
            available_size 
-= size;

            
return sys_alloc( size );
        }


        mem_inline 
void dealloc( void *ptr, size_type size )
        
{
            
if( ptr && size != 0 )
            
{
                sys_dealloc( ptr );

                allocated_size 
-= size;
                available_size 
+= size;
            }

        }


        mem_inline 
void *aligned_alloc( size_type size )
        
{
            
if( size == 0 )
                
return NULL;

            allocated_size 
+= size;
            available_size 
-= size;

            
return sys_aligned_alloc( size );
        }


        mem_inline 
void aligned_dealloc( void *ptr, size_type size )
        
{
            
if( ptr && size != 0 )
            
{
                sys_aligned_dealloc( ptr );

                allocated_size 
-= size;
                available_size 
+= size;
            }

        }


        mem_inline size_type available()
        
{
            
return available_size;
        }


    
private:
        mem_inline 
void *sys_alloc( size_type size )
        
{
            
return malloc( size );
        }


        mem_inline 
void sys_dealloc( void *ptr )
        
{
            free( ptr );
        }


        mem_inline 
void *sys_aligned_alloc( size_type size )
        
{
            
return _aligned_malloc( size, mem_align_size );
        }


        mem_inline 
void sys_aligned_dealloc( void *ptr )
        
{
            _aligned_free( ptr );
        }


    
private:
        size_type        allocated_size, 
                        available_size;
    }
;

    
extern heap        *g_heap;

    
class allocator {
    
public:
        mem_inline 
void *alloc( size_type size )
        
{
            
return g_heap->alloc( size );
        }


        mem_inline 
void dealloc( void *ptr, size_type size )
        
{
            g_heap
->dealloc( ptr, size );
        }


        mem_inline size_type available()
        
{
            
return g_heap->available();
        }

    }
;

    
class aligned_allocator {
    
public:
        mem_inline 
void *alloc( size_type size )
        
{
            
return g_heap->aligned_alloc( size );
        }


        mem_inline 
void dealloc( void *ptr, size_type size )
        
{
            g_heap
->aligned_dealloc( ptr, size );
        }


        mem_inline size_type available()
        
{
            
return g_heap->available();
        }

    }
;

    template 
< typename ALLOC = allocator > class pool;

    template 
< typename ALLOC = allocator >
    
class entry {
    
public:
        mem_inline entry()
        
{
            priority 
= ENTRY_PRIORITY;
            last_use_time 
= pl.get_current_time();
            locked 
= false;
        }

        
        mem_inline 
virtual ~entry()
        
{
        }


        mem_inline 
void *alloc( size_type size )
        
{
            
return pl.alloc( size, this );
        }


        mem_inline 
void dealloc( void *ptr, size_type size )
        
{
            pl.dealloc( ptr, size, 
this );
        }


        mem_inline 
void stream_begin()
        
{
            locked 
= true;
            stream_in();
            last_use_time 
= pl.get_current_time();
        }


        mem_inline 
void stream_end()
        
{
            locked 
= false;
        }


        mem_inline 
bool is_locked()
        
{
            
return locked;
        }


        mem_inline 
bool operator < ( const entry< ALLOC > & right ) const
        
{
            
if( priority == right.priority )
                
return ( last_use_time < right.last_use_time );
            
else
                
return ( priority < right.priority );
        }


    
public:
#ifdef _DEBUG
        
virtual void stream_in() = 0;
#endif

        
virtual bool stream_out( void * & ptr, size_type size ) = 0;

    
public:
        
static pool< ALLOC >    pl;
        prior_type                priority;
        time_type                last_use_time;
        
bool                    locked;
    }
;

    template 
< typename ALLOC >
    mem_inline 
bool compare_entry( const entry< ALLOC > *left, const entry< ALLOC > *right )
    
{
        
return ( *left < *right );
    }


    template 
< typename ALLOC >
    
class pool {
    
private:
        
class page {
        
public:
            mem_inline page( size_type _size, page 
*old )
            
{
                size 
= _size;
                
base = get_base();
                next 
= old;
                prev 
= NULL;
                
if( next )
                    next
->prev = this;
            }


            mem_inline 
~page()
            
{
            }


            mem_inline 
void recycle( page *old )
            
{
                
void    *ptr = NULL;

                
for( std::vector< entry< ALLOC > * >::iterator i = ents.begin();
                        i 
!= ents.end(); ++i )
                
{
                    (
*i)->stream_out( ptr, 0 );
                }


                ents.clear();

                size 
= get_size();
                
base = get_base();
                next 
= old;
                prev 
= NULL;
                
if( next )
                    next
->prev = this;
            }


            mem_inline 
byte *get_base()
            
{
                
return (byte *this + sizeof(page);
            }


            mem_inline size_type get_size()
            
{
                
return static_cast<size_type>base - get_base() + size );
            }


            mem_inline size_type available()
            
{
                
return size;
            }


            mem_inline 
void *alloc( size_type req_size, entry< ALLOC > *obj )
            
{
                
void    *ptr = (void *base;

                
base += req_size;
                size 
-= req_size;

                ents.push_back( obj );
            
                
return ptr;
            }


            mem_inline time_type priority() 
const
            
{
                time_type    last_use_time 
= 0;

                
for( std::vector< entry< ALLOC > * >::const_iterator i = ents.begin();
                        i 
!= ents.end(); ++i )
                
{
                    last_use_time 
+= (*i)->last_use_time;
                }


                last_use_time 
/= static_cast<time_type>( ents.size() );

                
return last_use_time;
            }


            mem_inline 
bool operator < ( const page & right ) const
            
{
                
return ( priority() < right.priority() );
            }


        
public:
            mem_align 
struct {
                
byte                            *base;
                page                            
*next;
                page                            
*prev;
                size_type                        size;
                std::vector
< entry< ALLOC > * >    ents;
            }
;
        }
;
        
        
class chunk {
        
public:
            mem_inline chunk( size_type _size, chunk 
*old )
            
{
                size 
= _size;
                next 
= old;
                prev 
= NULL;
                
if( next )
                    next
->prev = this;
            }


            mem_inline size_type available()
            
{
                
return size;
            }


        
public:
            chunk                    
*next;
            chunk                    
*prev;
            size_type                size;
        }
;

    
public:
        mem_inline pool()
        
{
            current_time 
= 0;
            pages 
= NULL;
            chunks 
= NULL;
            allocated 
= 0;
        }


        mem_inline 
~pool()
        
{
            destory();
        }


        mem_inline time_type get_current_time()
        
{
            
return ( ++ current_time );
        }


        mem_inline 
void *alloc( size_type size, entry< ALLOC > *obj )
        
{
            
void    *ptr = NULL;

            
++ allocated;

            
if( search_chunk( ptr, size ) )
                
return ptr;
            
else if( search_page( ptr, size, obj ) )
                
return ptr;
            
else if( (size + sizeof(page)) > al.available() )
            
{
                
if( search_entry( ptr, size, obj ) )
                    
return ptr;
                
else
                
{
                    recycle_page( size );

                    
if( search_page( ptr, size, obj ) )
                        
return ptr;
                    
else
                        
return NULL;
                }

            }

            
else
            
{
                allocate_page( size );

                
if( search_page( ptr, size, obj ) )
                    
return ptr;
                
else
                    
return NULL;
            }

        }


        mem_inline 
void dealloc( void *ptr, size_type size, entry< ALLOC > *obj )
        
{
            
-- allocated;

            
for( std::vector< entry< ALLOC > * >::iterator i = g_ents.begin();
                    i 
!= g_ents.end(); ++i )
            
{
                
if( obj == *i )
                
{
                    g_ents.erase( i );
                    
break;
                }

            }


            
if( size >= sizeof(chunk) )
                chunks 
= new (ptr) chunk( size, chunks );
        
            
if( allocated == 0 )
                destory();
        }


    
private:
        mem_inline 
void destory()
        
{
            page    
*= pages;
        
            
while( p )
            
{
                pages 
= p->next;
                p
->~page();
                al.dealloc( p, p
->get_size() );
                p 
= pages;
            }


            chunks 
= NULL;

            g_ents.clear();
        }


        mem_inline 
bool search_chunk( void * & ptr, size_type size )
        
{
            chunk    
*= chunks;
            
            
while( p )
            
{
                
if( size <= p->available() )
                
{
                    ptr 
= (void *) p;
                    
                    
if( p->prev )
                        p
->prev->next = p->next;
                    
if( p->next )
                        p
->next->prev = p->prev;
                    
                    
return true;
                }


                p 
= p->next;
            }


            
return false;
        }


        mem_inline 
bool search_page( void * & ptr, size_type size, entry< ALLOC > *obj )
        
{
            page    
*= pages;
            
            
while( p )
            
{
                
if( size <= p->available() )
                
{
                    ptr 
= p->alloc( size, obj );

                    g_ents.push_back( obj );
                    
                    
if( p->prev )
                        p
->prev->next = p->next;
                    
if( p->next )
                        p
->next->prev = p->prev;
                    
                    
return true;
                }


                p 
= p->next;
            }


            
return false;
        }


        mem_inline 
bool search_entry( void * & ptr, size_type size, entry< ALLOC > *obj )
        
{
            std::sort( g_ents.begin(), g_ents.end(), compare_entry
< ALLOC > );

            
for( std::vector< entry< ALLOC > * >::iterator i = g_ents.begin();
                    i 
!= g_ents.end(); ++i )
            
{
                
if!(*i)->is_locked() && (*i)->stream_out( ptr, size ) )
                
{
                    
*= obj;
                    
return true;
                }

            }


            
return false;
        }


        mem_inline 
void recycle_page( size_type size )
        
{
            
if( pages )
            
{
                page    
*p, *old;

                old 
= pages;
                p 
= pages->next;

                
while( p )
                
{
                    
if*< *old )
                        old 
= p;

                    p 
= p->next;
                }


                
if( old->prev )
                    old
->prev->next = old->next;
                
if( old->next )
                    old
->next->prev = old->prev;

                old
->recycle( pages );
                pages 
= old;
            }

        }


        mem_inline 
void allocate_page( size_type size )
        
{
            size_type    asize 
= mem_min( mem_max( sizeof(page) + size, mem_page_size ), al.available() );

            pages 
= new (al.alloc( asize )) page( asize - sizeof(page), pages );
        }


    
private:
        time_type                        current_time;
        time_type                        allocated;
        ALLOC                            al;
        std::vector
< entry< ALLOC > * >    g_ents;
        page                            
*pages;
        chunk                            
*chunks;
    }
;

}
    //    namespace mem


#pragma pack(pop)


#endif    //    __MEM_MAN__
原文地址:https://www.cnblogs.com/len3d/p/988562.html