📄 restack.h
字号:
m_end = m_current_node->m_head.m_end;
}
return pb;
}
void * _unwind( size_t size ) // throw()
{
return _unwind( m_current - size );
}
struct real_unwinder;
friend struct real_unwinder;
struct real_unwinder
{
stack_type * pstack_;
size_t size_;
bool dismissed_;
real_unwinder( stack_type * pstack, size_t size ) // throw()
: pstack_(pstack), size_(size), dismissed_(false) {}
~real_unwinder() // throw()
{
if( ! dismissed_ )
pstack_->_unwind( size_ );
}
void dismiss() // throw()
{
dismissed_ = true;
}
};
struct dummy_unwinder
{
dummy_unwinder( stack_type *, size_t ) {} // throw()
void dismiss() {} // throw()
};
// Disallow these for now. Might implement them later.
hetero_stack( hetero_stack const & );
hetero_stack & operator=( hetero_stack const & );
public:
class type_error : public std::logic_error
{
std::type_info const * prequested_type_;
std::type_info const * pactual_type_;
public:
type_error(
std::type_info const & requested_type,
std::type_info const & actual_type,
std::string const & s = "type error in hetero_stack" ) // throw()
: std::logic_error( s + " (requested type: " + requested_type.name()
+ ", actual type: " + actual_type.name() + ")" ),
prequested_type_( &requested_type ),
pactual_type_( &actual_type )
{
}
std::type_info const & requested_type() const // throw()
{
return *prequested_type_;
}
std::type_info const & actual_type() const // throw()
{
return *pactual_type_;
}
};
hetero_stack() // throw()
: m_current_node( &m_first_node.m_node )
{
_check_align();
m_first_node.m_node.m_head.m_back = & m_first_node.m_node;
m_first_node.m_node.m_head.m_next = NULL;
m_begin = m_current = m_first_node.m_node.m_head.m_current = m_first_node.m_node.m_mem;
m_end = m_first_node.m_node.m_head.m_end = m_first_node.m_buf + sizeof( m_first_node );
}
~hetero_stack() // throw()
{
m_current_node = m_first_node.m_node.m_head.m_next;
for( stack_node * next_node; m_current_node; m_current_node = next_node )
{
next_node = m_current_node->m_head.m_next;
::operator delete( static_cast<void*>( m_current_node ) );
}
}
template< typename T >
inline void push( T const & t ) // throw(std::bad_alloc,...)
{
// Make sure that the alignment for type T is not worse
// than our declared alignment.
detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
( void ) align_test;
// If T won't throw in copy c'tor, and if RuntimeTypeCheck is false,
// then we don't need to use an unwinder object.
typedef typename ::regex::detail::select< AssumePOD, // || detail::has_trivial_copy<T>::value,
dummy_unwinder, real_unwinder >::type unwinder;
// If this throws, it doesn't change state,
// so there is nothing to roll back.
void * pv = _alloc( size_of<T>::with_rtti );
// Rolls back the _alloc if later steps throw
// BUGBUG we can do the alloc, but not update m_current until after
// the copy c'tor to avoid the need for an unwinder object
unwinder guard1( this, size_of<T>::with_rtti );
new ( pv ) T( t ); // Could throw if ! has_trivial_copy<T>::value
// If we are debugging the stack, then push a pointer to the type_info
// for this type T. It will be checked in pop().
if( RuntimeTypeCheck )
{
new ( static_cast<byte*>( pv ) + size_of<T>::aligned )
( std::type_info const*const* )( & detail::unique_type_info<T>::value );
}
// ok, everything succeeded -- dismiss the guard
guard1.dismiss();
}
template< typename T >
inline void pop( T & t ) // throw(...)
{
detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
( void ) align_test;
// If we are debugging the stack, then in push() we pushed a pointer
// to the type_info struct for this type T. Check it now.
if( RuntimeTypeCheck )
{
void * pti = m_current - size_of<std::type_info const*const*>::aligned;
if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
throw type_error( typeid( T ), ***static_cast<std::type_info const*const**>( pti ) );
}
// Don't change state yet because assignment op could throw!
void * pT = m_current - size_of<T>::with_rtti;
t = *static_cast<T const*>( pT ); // could throw
static_cast<T const*>( pT )->~T();
_unwind( static_cast<byte*>( pT ) );
}
// Call this version of pop when you don't need the popped value
template< typename T >
inline void pop() // throw(type_error,...)
{
detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
( void ) align_test;
// If we are debugging the stack, then in push() we pushed a pointer
// to the type_info struct for this type T. Check it now.
if( RuntimeTypeCheck )
{
void * pti = m_current - size_of<std::type_info const*const*>::aligned;
if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
throw type_error( typeid( T ), ***static_cast<std::type_info const*const**>( pti ) );
}
T const * pT = static_cast<T const *>( _unwind( size_of<T>::with_rtti ) );
pT->~T();
}
// Call this version of pop when you don't need the popped value and
// throwing an exception isn't an option
template< typename T >
inline bool pop( std::nothrow_t const & ) // throw()
{
detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
( void ) align_test;
// If we are debugging the stack, then in push() we pushed a pointer
// to the type_info struct for this type T. Check it now.
if( RuntimeTypeCheck )
{
void * pti = m_current - size_of<std::type_info const*const*>::aligned;
if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
return false; // type error, can't throw so bail.
}
T const * pT = static_cast<T const *>( _unwind( size_of<T>::with_rtti ) );
pT->~T();
return true;
}
template< typename T >
inline T & top( T ) const // throw(type_error,...)
{
detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
( void ) align_test;
if( RuntimeTypeCheck )
{
// If we are debugging the stack, then the top of the stack is a
// pointer to a type_info struct. Assert that we have the correct type.
void * pti = m_current - size_of<std::type_info const*const*>::aligned;
if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
throw type_error( typeid( T ), ***static_cast<std::type_info const*const**>( pti ) );
}
void * pT = m_current - size_of<T>::with_rtti;
return *static_cast<T*>( pT );
}
// Fetch the type_info for the element at the top of the stack
std::type_info const & top_type() const // throw()
{
detail::static_assert< RuntimeTypeCheck > const type_check; ( void ) type_check;
void * pti = m_current - size_of<std::type_info const*const*>::aligned;
return ***static_cast<std::type_info const*const**>( pti );
}
// Get a pointer to the top of the stack
void * set_jump() const // throw()
{
return m_current;
}
// Quick and dirty stack unwind. Does not call destructors.
void long_jump( void * jump_ptr ) // throw()
{
for( ;; )
{
if( std::less<void*>()( jump_ptr, m_current_node->m_mem ) ||
std::less<void*>()( m_current_node->m_head.m_end, jump_ptr ) )
{
m_current_node->m_head.m_current = m_current_node->m_mem;
m_current_node = m_current_node->m_head.m_back;
}
else
{
m_begin = m_current_node->m_mem;
m_current = m_current_node->m_head.m_current = static_cast<byte*>( jump_ptr );
m_end = m_current_node->m_head.m_end;
return;
}
}
}
bool empty() const // throw()
{
return m_current == m_first_node.m_node.m_mem;
}
// Use scoped_push for automatically pushing/popping
// things to and from the stack. This is especially useful
// if you want to push a bunch of things "atomically". For
// instance:
//
// typedef hetero_stack<>::scoped_pop scoped_pop;
// scoped_pop p1 = stack.scoped_push( int(1) ); // could throw
// scoped_pop p2 = stack.scoped_push( std::string("foo") ); // could throw
// stack.push( float(3.14159) ); // could throw
// p2.dismiss(); // ok, nothing threw, so ...
// p1.dismiss(); // ... dismiss the scoped_pops
//
// If p2 and p1 are not dismissed, as in the case when an
// exception gets thrown, then they automatically pop their
// arguments from the stack.
class scoped_pop_base
{
protected:
stack_type * pstack_;
bool mutable owns_;
scoped_pop_base & operator=( scoped_pop_base const & ); // disallow assignment
public:
scoped_pop_base( stack_type * pstack ) // throw(std::bad_alloc,...)
: pstack_( pstack )
, owns_( true )
{
}
scoped_pop_base( scoped_pop_base const & that ) // throw() // destructive copy
: pstack_( that.pstack_ )
, owns_( that.owns_ )
{
// This popper takes ownership, that popper gives it up.
that.owns_ = false;
}
void dismiss() const // throw()
{
owns_ = false;
}
};
template< typename T >
struct scoped_pop_t : public scoped_pop_base
{
scoped_pop_t( stack_type * pstack, T const & t ) // throw(std::bad_alloc,...)
: scoped_pop_base( pstack )
{
// Note that if this throws an exception the destructor
// will not get called, which is what we want.
pstack_->push( t );
}
~scoped_pop_t() // throw()
{
// If we own this stack space, pop it.
if( owns_ )
pstack_->template pop<T>( std::nothrow );
}
};
template< typename T >
scoped_pop_t<T> scoped_push( T const & t ) // throw(...)
{
return scoped_pop_t<T>( this, t );
}
typedef scoped_pop_base const & scoped_pop;
};
// BUGBUG push and pop *must* be balanced since d'tors need to be called.
// Iterative execution of regex matching makes this difficult considering
// the fact that push() could cause an exception to be thrown. The entire
// stack of sub_expr* must be backtracked completely and correctly.
// Alternate solution: push nothing that needs to be destroyed.
#ifdef _MSC_VER
#pragma warning( pop )
#endif
} // namespace regex
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -