📄 restack.h
字号:
//+---------------------------------------------------------------------------
//
// 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 + -