⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 restack.h

📁 代理服务器原代码
💻 H
📖 第 1 页 / 共 2 页
字号:
//+---------------------------------------------------------------------------
//
//  Copyright ( C ) Microsoft Corporation, 1994 - 2002.
//
//  File:       restack.h
//
//  Functions:  a quick-'n'-dirty, type-unsafe stack used by the iterative
//              regular expression algorithm
//
//  Notes:      Care must be taken when using this stack. You must pop off
//              the correct type of object, otherwise you get garbage. Also,
//              in the current implementation, you shouldn't push anything
//              that has a non-trivial destructor, or if you do, then don't
//              use the set_jump/long_jump methods.
//
//  Author:     Eric Niebler ( ericne@microsoft.com )
//
//  History:    11/15/2001   ericne   Created
//
//----------------------------------------------------------------------------

#ifndef HETERO_STACK_H
#define HETERO_STACK_H

#include <string>
#include <utility>
#include <typeinfo>
#include <stdexcept>
#include <functional>

namespace regex
{

namespace detail
{

// For compile-time assertions that generate
// no run-time overhead.
template< bool f > struct static_assert;
template<>         struct static_assert<true> { static_assert() {} };

#ifdef _MSC_VER
// warning C4127: conditional expression is constant
// warning C4189: local variable is initialized but not referenced
// warning C4244: conversion from 'T' to 'int', possible loss of data
// warning C4510: default constructor could not be generated
// warning C4610: struct can never be instantiated - user defined constructor required
#pragma warning( push )
#pragma warning( disable : 4127 4189 4244 4510 4610 )

// Make sure nobody has tampered with the packing before defining the
// alignof structure
#pragma pack( push )
#pragma pack() // use the default packing
#endif

template< typename T >
class alignof
{
    struct helper
    {
        helper();
        char c_;
        T t_;
    };
public:
    enum { value = sizeof(helper)-sizeof(T) < sizeof(T) ? sizeof(helper)-sizeof(T) : sizeof(T) };
};

#ifdef _MSC_VER
#pragma pack( pop )
#endif

template< typename T >
struct unique_type_info
{
    static std::type_info const *const value;

    static bool equals(
        std::type_info const *const * ppti )
    {
        return ppti == & value || **ppti == typeid(T);
    }
};

template< typename T >
std::type_info const *const unique_type_info<T>::value = &typeid(T);

//
// Type traits
//

typedef char (&yes_type)[1];
typedef char (&no_type)[2];

#if defined(_MSC_VER) & _MSC_VER <= 1300
    // For use in conditional typedefs
    template< bool F, typename T, typename U >
    class select
    {
        template< bool > struct select_helper { typedef U type; };
        template<> struct select_helper<true> { typedef T type; };
    public:
        typedef typename select_helper<F>::type type;
    };

    // Check to see whether T is convertible to a U
    template< typename T, typename U >
    class is_convertible
    {
        static yes_type __cdecl  _convertible_helper( U );
        static no_type  __cdecl  _convertible_helper(...);
        static T t;
    public:
        enum { value = ( sizeof(_convertible_helper(t)) == sizeof(yes_type) ) };
    };
#else
    // For use in conditional typedefs
    template< bool F, typename T, typename U > struct select { typedef U type; };
    template< typename T, typename U > struct select<true,T,U> { typedef T type; };

    // Check to see whether T is convertible to a U
    template< typename U > yes_type   _convertible_helper( U );
    template< typename U > no_type    _convertible_helper(...);
    template< typename T, typename U >
    class is_convertible
    {
        static T t;
    public:
        enum { value = ( sizeof(_convertible_helper<U>(t)) == sizeof(yes_type) ) };
    };
#endif

} // namespace detail

// --------------------------------------------------------------------------
//
// Class:       hetero_stack
//
// Description: Fast, heterogeneous stack.
//
// Methods:     _alloc          - reserve space on stack
//              _unwind         - unwind the stack
//              hetero_stack    - c'tor
//              ~hetero_stack   - d'tor, release all dynamic memory
//              push            - push an object on the stack
//              pop             - pop an object from the stack
//
// Members:     m_first_node    -
//              m_current_node  -
//
// Typedefs:    byte            -
//
// History:     10/19/2001 - ericne - Created
//
// --------------------------------------------------------------------------
template
<
    size_t  Alignment          = sizeof(void*),
    bool    RuntimeTypeCheck   = true,  // should we perform run-time type checking?
    bool    AssumePOD          = false, // assume non-throwing copy/assign/destroy for better perf
    size_t  DynamicBlockSize   = 4096,  // blocks allocated from heap are this size
    size_t  StaticBlockSize    = 1024   // initial block on stack is this size
>
class hetero_stack
{
public:

    typedef hetero_stack<Alignment,RuntimeTypeCheck,AssumePOD,DynamicBlockSize,StaticBlockSize> stack_type;

    template< typename T >
    struct size_of
    {
        enum
        {
            // round up sizeof(T) to the nearest multiple of Alignment
            aligned = ( sizeof( T ) + Alignment - 1 ) & ~( Alignment - 1 ),
            with_rtti = RuntimeTypeCheck ?
                aligned + size_of<std::type_info const*const*>::aligned :
                aligned
        };
    };

private:

    static void _check_align()
    {
        // The alignment must be a power of 2
        detail::static_assert<
            Alignment == 1    || Alignment == 2    || Alignment == 4   ||
            Alignment == 8    || Alignment == 16   || Alignment == 32  ||
            Alignment == 128  || Alignment == 256  || Alignment == 512 ||
            Alignment == 1024 || Alignment == 2048 || Alignment == 4096 > const align_check;
        ( void ) align_check;
    }

    typedef unsigned char byte;

    struct stack_node
    {
        struct header
        {
            stack_node * m_back;
            stack_node * m_next;
            byte       * m_current; // ptr into m_mem. alloc from here
            byte       * m_end;     // ptr to last+1 byte in m_mem
        };

        union
        {
            header  m_head;
            byte    m_align[ size_of<header>::aligned ];
        };

        // This is the buffer into which values will be pushed and popped.
        // It is guaranteed to meet the Alignment requirements because of
        // the union above.
        byte         m_mem[1];

        size_t size() const // throw()
        {
            return ( size_t )( m_head.m_end - m_mem );
        }
    };

    enum
    {
        DYNAMIC_BLOCK_SIZE =
            DynamicBlockSize > sizeof( stack_node ) ?
            DynamicBlockSize : sizeof( stack_node )
    };

    union
    {
        byte m_buf[ offsetof( stack_node, m_mem ) + StaticBlockSize ];
        stack_node m_node;
    } m_first_node;

    stack_node * m_current_node;

    // Cache these for faster access
    byte * m_begin;
    byte * m_current;
    byte * m_end;

    void * _grow( size_t size ) // throw(std::bad_alloc)
    {
        // write the cached value of current into the node.
        // OK to do this even if later statements throw.
        m_current_node->m_head.m_current = m_current;

        // Do we have a node with available memory already?
        if( m_current_node->m_head.m_next )
        {
            // Does this node have enough room?
            if( size <= m_current_node->m_head.m_next->size() )
            {
                m_current_node = m_current_node->m_head.m_next;
                m_current = m_current_node->m_head.m_current = m_current_node->m_mem + size;
                m_end     = m_current_node->m_head.m_end;
                return m_begin = m_current_node->m_mem;
            }

            // Create a new node and insert it into the list
            stack_node * new_node = static_cast<stack_node*>( ::operator new( size + offsetof( stack_node, m_mem ) ) );
            
            new_node->m_head.m_back = m_current_node;
            new_node->m_head.m_next = m_current_node->m_head.m_next;
            
            m_current = m_end = new_node->m_head.m_current = new_node->m_head.m_end = new_node->m_mem + size;

            m_current_node->m_head.m_next->m_head.m_back = new_node;
            m_current_node->m_head.m_next = new_node;
            m_current_node = new_node;

            return m_begin = m_current_node->m_mem;
        }

        // We need to create a new node from scratch
        size_t new_size = (std::max)( size, (size_t)DYNAMIC_BLOCK_SIZE - offsetof( stack_node, m_mem ) );
        stack_node * new_node = static_cast<stack_node*>( ::operator new( new_size + offsetof( stack_node, m_mem ) ) );
        
        new_node->m_head.m_back = m_current_node;
        new_node->m_head.m_next = NULL;
        
        m_current = new_node->m_head.m_current = new_node->m_mem + size;
        m_end     = new_node->m_head.m_end     = new_node->m_mem + new_size;

        m_current_node->m_head.m_next = new_node;
        m_current_node = new_node;

        return m_begin = m_current_node->m_mem;
    }

    void * _alloc( size_t size ) // throw(std::bad_alloc)
    {
        // This is the ptr to return
        void * mem = m_current;

        // Advance the high-water mark
        m_current += size;

        // Check to see if we have overflown this buffer
        if( std::less<void*>()( m_end, m_current ) )
        {
            // oops, back this out.
            m_current -= size;

            // allocate a new block and return a ptr to the new memory
            return _grow( size );
        }

        return mem;
    }

    void * _unwind( byte * pb ) // throw()
    {
        // roll back the stack
        m_current = pb;

        // If we've unwound this whole block, then make the
        // previous node the current node
        if( m_current == m_begin )
        {
            // write the cached value of m_current into m_current_node
            m_current_node->m_head.m_current = m_current;
            m_current_node = m_current_node->m_head.m_back;

            // update the cache
            m_begin   = m_current_node->m_mem;
            m_current = m_current_node->m_head.m_current;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -