restack.h
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:22k
源码类别:

模拟服务器

开发平台:

C/C++

  1. //+---------------------------------------------------------------------------
  2. //
  3. //  Copyright ( C ) Microsoft Corporation, 1994 - 2002.
  4. //
  5. //  File:       restack.h
  6. //
  7. //  Functions:  a quick-'n'-dirty, type-unsafe stack used by the iterative
  8. //              regular expression algorithm
  9. //
  10. //  Notes:      Care must be taken when using this stack. You must pop off
  11. //              the correct type of object, otherwise you get garbage. Also,
  12. //              in the current implementation, you shouldn't push anything
  13. //              that has a non-trivial destructor, or if you do, then don't
  14. //              use the set_jump/long_jump methods.
  15. //
  16. //  Author:     Eric Niebler ( ericne@microsoft.com )
  17. //
  18. //  History:    11/15/2001   ericne   Created
  19. //
  20. //----------------------------------------------------------------------------
  21. #ifndef HETERO_STACK_H
  22. #define HETERO_STACK_H
  23. #include <string>
  24. #include <utility>
  25. #include <typeinfo>
  26. #include <stdexcept>
  27. #include <functional>
  28. namespace regex
  29. {
  30. namespace detail
  31. {
  32. // For compile-time assertions that generate
  33. // no run-time overhead.
  34. template< bool f > struct static_assert;
  35. template<>         struct static_assert<true> { static_assert() {} };
  36. #ifdef _MSC_VER
  37. // warning C4127: conditional expression is constant
  38. // warning C4189: local variable is initialized but not referenced
  39. // warning C4244: conversion from 'T' to 'int', possible loss of data
  40. // warning C4510: default constructor could not be generated
  41. // warning C4610: struct can never be instantiated - user defined constructor required
  42. #pragma warning( push )
  43. #pragma warning( disable : 4127 4189 4244 4510 4610 )
  44. // Make sure nobody has tampered with the packing before defining the
  45. // alignof structure
  46. #pragma pack( push )
  47. #pragma pack() // use the default packing
  48. #endif
  49. template< typename T >
  50. class alignof
  51. {
  52.     struct helper
  53.     {
  54.         helper();
  55.         char c_;
  56.         T t_;
  57.     };
  58. public:
  59.     enum { value = sizeof(helper)-sizeof(T) < sizeof(T) ? sizeof(helper)-sizeof(T) : sizeof(T) };
  60. };
  61. #ifdef _MSC_VER
  62. #pragma pack( pop )
  63. #endif
  64. template< typename T >
  65. struct unique_type_info
  66. {
  67.     static std::type_info const *const value;
  68.     static bool equals(
  69.         std::type_info const *const * ppti )
  70.     {
  71.         return ppti == & value || **ppti == typeid(T);
  72.     }
  73. };
  74. template< typename T >
  75. std::type_info const *const unique_type_info<T>::value = &typeid(T);
  76. //
  77. // Type traits
  78. //
  79. typedef char (&yes_type)[1];
  80. typedef char (&no_type)[2];
  81. #if defined(_MSC_VER) & _MSC_VER <= 1300
  82.     // For use in conditional typedefs
  83.     template< bool F, typename T, typename U >
  84.     class select
  85.     {
  86.         template< bool > struct select_helper { typedef U type; };
  87.         template<> struct select_helper<true> { typedef T type; };
  88.     public:
  89.         typedef typename select_helper<F>::type type;
  90.     };
  91.     // Check to see whether T is convertible to a U
  92.     template< typename T, typename U >
  93.     class is_convertible
  94.     {
  95.         static yes_type __cdecl  _convertible_helper( U );
  96.         static no_type  __cdecl  _convertible_helper(...);
  97.         static T t;
  98.     public:
  99.         enum { value = ( sizeof(_convertible_helper(t)) == sizeof(yes_type) ) };
  100.     };
  101. #else
  102.     // For use in conditional typedefs
  103.     template< bool F, typename T, typename U > struct select { typedef U type; };
  104.     template< typename T, typename U > struct select<true,T,U> { typedef T type; };
  105.     // Check to see whether T is convertible to a U
  106.     template< typename U > yes_type   _convertible_helper( U );
  107.     template< typename U > no_type    _convertible_helper(...);
  108.     template< typename T, typename U >
  109.     class is_convertible
  110.     {
  111.         static T t;
  112.     public:
  113.         enum { value = ( sizeof(_convertible_helper<U>(t)) == sizeof(yes_type) ) };
  114.     };
  115. #endif
  116. } // namespace detail
  117. // --------------------------------------------------------------------------
  118. //
  119. // Class:       hetero_stack
  120. //
  121. // Description: Fast, heterogeneous stack.
  122. //
  123. // Methods:     _alloc          - reserve space on stack
  124. //              _unwind         - unwind the stack
  125. //              hetero_stack    - c'tor
  126. //              ~hetero_stack   - d'tor, release all dynamic memory
  127. //              push            - push an object on the stack
  128. //              pop             - pop an object from the stack
  129. //
  130. // Members:     m_first_node    -
  131. //              m_current_node  -
  132. //
  133. // Typedefs:    byte            -
  134. //
  135. // History:     10/19/2001 - ericne - Created
  136. //
  137. // --------------------------------------------------------------------------
  138. template
  139. <
  140.     size_t  Alignment          = sizeof(void*),
  141.     bool    RuntimeTypeCheck   = true,  // should we perform run-time type checking?
  142.     bool    AssumePOD          = false, // assume non-throwing copy/assign/destroy for better perf
  143.     size_t  DynamicBlockSize   = 4096,  // blocks allocated from heap are this size
  144.     size_t  StaticBlockSize    = 1024   // initial block on stack is this size
  145. >
  146. class hetero_stack
  147. {
  148. public:
  149.     typedef hetero_stack<Alignment,RuntimeTypeCheck,AssumePOD,DynamicBlockSize,StaticBlockSize> stack_type;
  150.     template< typename T >
  151.     struct size_of
  152.     {
  153.         enum
  154.         {
  155.             // round up sizeof(T) to the nearest multiple of Alignment
  156.             aligned = ( sizeof( T ) + Alignment - 1 ) & ~( Alignment - 1 ),
  157.             with_rtti = RuntimeTypeCheck ?
  158.                 aligned + size_of<std::type_info const*const*>::aligned :
  159.                 aligned
  160.         };
  161.     };
  162. private:
  163.     static void _check_align()
  164.     {
  165.         // The alignment must be a power of 2
  166.         detail::static_assert<
  167.             Alignment == 1    || Alignment == 2    || Alignment == 4   ||
  168.             Alignment == 8    || Alignment == 16   || Alignment == 32  ||
  169.             Alignment == 128  || Alignment == 256  || Alignment == 512 ||
  170.             Alignment == 1024 || Alignment == 2048 || Alignment == 4096 > const align_check;
  171.         ( void ) align_check;
  172.     }
  173.     typedef unsigned char byte;
  174.     struct stack_node
  175.     {
  176.         struct header
  177.         {
  178.             stack_node * m_back;
  179.             stack_node * m_next;
  180.             byte       * m_current; // ptr into m_mem. alloc from here
  181.             byte       * m_end;     // ptr to last+1 byte in m_mem
  182.         };
  183.         union
  184.         {
  185.             header  m_head;
  186.             byte    m_align[ size_of<header>::aligned ];
  187.         };
  188.         // This is the buffer into which values will be pushed and popped.
  189.         // It is guaranteed to meet the Alignment requirements because of
  190.         // the union above.
  191.         byte         m_mem[1];
  192.         size_t size() const // throw()
  193.         {
  194.             return ( size_t )( m_head.m_end - m_mem );
  195.         }
  196.     };
  197.     enum
  198.     {
  199.         DYNAMIC_BLOCK_SIZE =
  200.             DynamicBlockSize > sizeof( stack_node ) ?
  201.             DynamicBlockSize : sizeof( stack_node )
  202.     };
  203.     union
  204.     {
  205.         byte m_buf[ offsetof( stack_node, m_mem ) + StaticBlockSize ];
  206.         stack_node m_node;
  207.     } m_first_node;
  208.     stack_node * m_current_node;
  209.     // Cache these for faster access
  210.     byte * m_begin;
  211.     byte * m_current;
  212.     byte * m_end;
  213.     void * _grow( size_t size ) // throw(std::bad_alloc)
  214.     {
  215.         // write the cached value of current into the node.
  216.         // OK to do this even if later statements throw.
  217.         m_current_node->m_head.m_current = m_current;
  218.         // Do we have a node with available memory already?
  219.         if( m_current_node->m_head.m_next )
  220.         {
  221.             // Does this node have enough room?
  222.             if( size <= m_current_node->m_head.m_next->size() )
  223.             {
  224.                 m_current_node = m_current_node->m_head.m_next;
  225.                 m_current = m_current_node->m_head.m_current = m_current_node->m_mem + size;
  226.                 m_end     = m_current_node->m_head.m_end;
  227.                 return m_begin = m_current_node->m_mem;
  228.             }
  229.             // Create a new node and insert it into the list
  230.             stack_node * new_node = static_cast<stack_node*>( ::operator new( size + offsetof( stack_node, m_mem ) ) );
  231.             
  232.             new_node->m_head.m_back = m_current_node;
  233.             new_node->m_head.m_next = m_current_node->m_head.m_next;
  234.             
  235.             m_current = m_end = new_node->m_head.m_current = new_node->m_head.m_end = new_node->m_mem + size;
  236.             m_current_node->m_head.m_next->m_head.m_back = new_node;
  237.             m_current_node->m_head.m_next = new_node;
  238.             m_current_node = new_node;
  239.             return m_begin = m_current_node->m_mem;
  240.         }
  241.         // We need to create a new node from scratch
  242.         size_t new_size = (std::max)( size, (size_t)DYNAMIC_BLOCK_SIZE - offsetof( stack_node, m_mem ) );
  243.         stack_node * new_node = static_cast<stack_node*>( ::operator new( new_size + offsetof( stack_node, m_mem ) ) );
  244.         
  245.         new_node->m_head.m_back = m_current_node;
  246.         new_node->m_head.m_next = NULL;
  247.         
  248.         m_current = new_node->m_head.m_current = new_node->m_mem + size;
  249.         m_end     = new_node->m_head.m_end     = new_node->m_mem + new_size;
  250.         m_current_node->m_head.m_next = new_node;
  251.         m_current_node = new_node;
  252.         return m_begin = m_current_node->m_mem;
  253.     }
  254.     void * _alloc( size_t size ) // throw(std::bad_alloc)
  255.     {
  256.         // This is the ptr to return
  257.         void * mem = m_current;
  258.         // Advance the high-water mark
  259.         m_current += size;
  260.         // Check to see if we have overflown this buffer
  261.         if( std::less<void*>()( m_end, m_current ) )
  262.         {
  263.             // oops, back this out.
  264.             m_current -= size;
  265.             // allocate a new block and return a ptr to the new memory
  266.             return _grow( size );
  267.         }
  268.         return mem;
  269.     }
  270.     void * _unwind( byte * pb ) // throw()
  271.     {
  272.         // roll back the stack
  273.         m_current = pb;
  274.         // If we've unwound this whole block, then make the
  275.         // previous node the current node
  276.         if( m_current == m_begin )
  277.         {
  278.             // write the cached value of m_current into m_current_node
  279.             m_current_node->m_head.m_current = m_current;
  280.             m_current_node = m_current_node->m_head.m_back;
  281.             // update the cache
  282.             m_begin   = m_current_node->m_mem;
  283.             m_current = m_current_node->m_head.m_current;
  284.             m_end     = m_current_node->m_head.m_end;
  285.         }
  286.         return pb;
  287.     }
  288.     void * _unwind( size_t size ) // throw()
  289.     {
  290.         return _unwind( m_current - size );
  291.     }
  292.     struct real_unwinder;
  293.     friend struct real_unwinder;
  294.     struct real_unwinder
  295.     {
  296.         stack_type * pstack_;
  297.         size_t       size_;
  298.         bool         dismissed_;
  299.         real_unwinder( stack_type * pstack, size_t size ) // throw()
  300.             : pstack_(pstack), size_(size), dismissed_(false) {}
  301.         ~real_unwinder() // throw()
  302.         {
  303.             if( ! dismissed_ )
  304.                 pstack_->_unwind( size_ );
  305.         }
  306.         void dismiss() // throw()
  307.         {
  308.             dismissed_ = true;
  309.         }
  310.     };
  311.     struct dummy_unwinder
  312.     {
  313.         dummy_unwinder( stack_type *, size_t ) {} // throw()
  314.         void dismiss() {} // throw()
  315.     };
  316.     // Disallow these for now. Might implement them later.
  317.     hetero_stack( hetero_stack const & );
  318.     hetero_stack & operator=( hetero_stack const & );
  319. public:
  320.     class type_error : public std::logic_error
  321.     {
  322.         std::type_info const * prequested_type_;
  323.         std::type_info const * pactual_type_;
  324.     public:
  325.         type_error( 
  326.             std::type_info const & requested_type,
  327.             std::type_info const & actual_type,
  328.             std::string const & s = "type error in hetero_stack" ) // throw()
  329.           : std::logic_error( s + " (requested type: " + requested_type.name()
  330.                 + ", actual type: " + actual_type.name() + ")" ),
  331.             prequested_type_( &requested_type ),
  332.             pactual_type_( &actual_type )
  333.         {
  334.         }
  335.         std::type_info const & requested_type() const // throw()
  336.         {
  337.             return *prequested_type_;
  338.         }
  339.         std::type_info const & actual_type() const // throw()
  340.         {
  341.             return *pactual_type_;
  342.         }
  343.     };
  344.     hetero_stack() // throw()
  345.       : m_current_node( &m_first_node.m_node )
  346.     {
  347.         _check_align();
  348.         m_first_node.m_node.m_head.m_back    = & m_first_node.m_node;
  349.         m_first_node.m_node.m_head.m_next    = NULL;
  350.         m_begin = m_current = m_first_node.m_node.m_head.m_current = m_first_node.m_node.m_mem;
  351.         m_end = m_first_node.m_node.m_head.m_end = m_first_node.m_buf + sizeof( m_first_node );
  352.     }
  353.     ~hetero_stack() // throw()
  354.     {
  355.         m_current_node = m_first_node.m_node.m_head.m_next;
  356.         for( stack_node * next_node; m_current_node; m_current_node = next_node )
  357.         {
  358.             next_node = m_current_node->m_head.m_next;
  359.             ::operator delete( static_cast<void*>( m_current_node ) );
  360.         }
  361.     }
  362.     template< typename T >
  363.     inline void push( T const & t ) // throw(std::bad_alloc,...)
  364.     {
  365.         // Make sure that the alignment for type T is not worse
  366.         // than our declared alignment.
  367.         detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
  368.         ( void ) align_test;
  369.         // If T won't throw in copy c'tor, and if RuntimeTypeCheck is false,
  370.         // then we don't need to use an unwinder object.
  371.         typedef typename ::regex::detail::select< AssumePOD, // || detail::has_trivial_copy<T>::value,
  372.             dummy_unwinder, real_unwinder >::type unwinder;
  373.         // If this throws, it doesn't change state,
  374.         // so there is nothing to roll back.
  375.         void * pv = _alloc( size_of<T>::with_rtti );
  376.         // Rolls back the _alloc if later steps throw
  377.         // BUGBUG we can do the alloc, but not update m_current until after
  378.         // the copy c'tor to avoid the need for an unwinder object
  379.         unwinder guard1( this, size_of<T>::with_rtti );
  380.         new ( pv ) T( t ); // Could throw if ! has_trivial_copy<T>::value
  381.         // If we are debugging the stack, then push a pointer to the type_info
  382.         // for this type T. It will be checked in pop().
  383.         if( RuntimeTypeCheck )
  384.         {
  385.             new ( static_cast<byte*>( pv ) + size_of<T>::aligned ) 
  386.                 ( std::type_info const*const* )( & detail::unique_type_info<T>::value );
  387.         }
  388.         // ok, everything succeeded -- dismiss the guard
  389.         guard1.dismiss();
  390.     }
  391.     template< typename T >
  392.     inline void pop( T & t ) // throw(...)
  393.     {
  394.         detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
  395.         ( void ) align_test;
  396.         // If we are debugging the stack, then in push() we pushed a pointer
  397.         // to the type_info struct for this type T.  Check it now.
  398.         if( RuntimeTypeCheck )
  399.         {
  400.             void * pti = m_current - size_of<std::type_info const*const*>::aligned;
  401.             if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
  402.                 throw type_error( typeid( T ), ***static_cast<std::type_info const*const**>( pti ) );
  403.         }
  404.         // Don't change state yet because assignment op could throw!
  405.         void * pT = m_current - size_of<T>::with_rtti;
  406.         t = *static_cast<T const*>( pT ); // could throw
  407.         static_cast<T const*>( pT )->~T();
  408.         _unwind( static_cast<byte*>( pT ) );
  409.     }
  410.     // Call this version of pop when you don't need the popped value
  411.     template< typename T >
  412.     inline void pop() // throw(type_error,...)
  413.     {
  414.         detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
  415.         ( void ) align_test;
  416.         // If we are debugging the stack, then in push() we pushed a pointer
  417.         // to the type_info struct for this type T.  Check it now.
  418.         if( RuntimeTypeCheck )
  419.         {
  420.             void * pti = m_current - size_of<std::type_info const*const*>::aligned;
  421.             if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
  422.                 throw type_error( typeid( T ), ***static_cast<std::type_info const*const**>( pti ) );
  423.         }
  424.         T const * pT = static_cast<T const *>( _unwind( size_of<T>::with_rtti ) );
  425.         pT->~T();
  426.     }
  427.     // Call this version of pop when you don't need the popped value and
  428.     // throwing an exception isn't an option
  429.     template< typename T >
  430.     inline bool pop( std::nothrow_t const & ) // throw()
  431.     {
  432.         detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
  433.         ( void ) align_test;
  434.         // If we are debugging the stack, then in push() we pushed a pointer
  435.         // to the type_info struct for this type T.  Check it now.
  436.         if( RuntimeTypeCheck )
  437.         {
  438.             void * pti = m_current - size_of<std::type_info const*const*>::aligned;
  439.             if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
  440.                 return false; // type error, can't throw so bail.
  441.         }
  442.         T const * pT = static_cast<T const *>( _unwind( size_of<T>::with_rtti ) );
  443.         pT->~T();
  444.         return true;
  445.     }
  446.     template< typename T >
  447.     inline T & top( T ) const // throw(type_error,...)
  448.     {
  449.         detail::static_assert<( Alignment >= detail::alignof<T>::value )> const align_test;
  450.         ( void ) align_test;
  451.         if( RuntimeTypeCheck )
  452.         {
  453.             // If we are debugging the stack, then the top of the stack is a
  454.             // pointer to a type_info struct. Assert that we have the correct type.
  455.             void * pti = m_current - size_of<std::type_info const*const*>::aligned;
  456.             if( ! detail::unique_type_info<T>::equals( *static_cast<std::type_info const*const**>( pti ) ) )
  457.                 throw type_error( typeid( T ), ***static_cast<std::type_info const*const**>( pti ) );
  458.         }
  459.         void * pT = m_current - size_of<T>::with_rtti;
  460.         return *static_cast<T*>( pT );
  461.     }
  462.     // Fetch the type_info for the element at the top of the stack
  463.     std::type_info const & top_type() const // throw()
  464.     {
  465.         detail::static_assert< RuntimeTypeCheck > const type_check; ( void ) type_check;
  466.         void * pti = m_current - size_of<std::type_info const*const*>::aligned;
  467.         return ***static_cast<std::type_info const*const**>( pti );
  468.     }
  469.     // Get a pointer to the top of the stack
  470.     void * set_jump() const // throw()
  471.     {
  472.         return m_current;
  473.     }
  474.     // Quick and dirty stack unwind. Does not call destructors.
  475.     void long_jump( void * jump_ptr ) // throw()
  476.     {
  477.         for( ;; )
  478.         {
  479.             if( std::less<void*>()( jump_ptr, m_current_node->m_mem ) ||
  480.                 std::less<void*>()( m_current_node->m_head.m_end, jump_ptr ) )
  481.             {
  482.                 m_current_node->m_head.m_current = m_current_node->m_mem;
  483.                 m_current_node = m_current_node->m_head.m_back;
  484.             }
  485.             else
  486.             {
  487.                 m_begin   = m_current_node->m_mem;
  488.                 m_current = m_current_node->m_head.m_current = static_cast<byte*>( jump_ptr );
  489.                 m_end     = m_current_node->m_head.m_end;
  490.                 return;
  491.             }
  492.         }
  493.     }
  494.     bool empty() const // throw()
  495.     {
  496.         return m_current == m_first_node.m_node.m_mem;
  497.     }
  498.     // Use scoped_push for automatically pushing/popping
  499.     // things to and from the stack. This is especially useful
  500.     // if you want to push a bunch of things "atomically".  For
  501.     // instance:
  502.     //
  503.     // typedef hetero_stack<>::scoped_pop scoped_pop;
  504.     // scoped_pop p1 = stack.scoped_push( int(1) ); // could throw
  505.     // scoped_pop p2 = stack.scoped_push( std::string("foo") ); // could throw
  506.     // stack.push( float(3.14159) ); // could throw
  507.     // p2.dismiss(); // ok, nothing threw, so ...
  508.     // p1.dismiss(); //  ... dismiss the scoped_pops
  509.     //
  510.     // If p2 and p1 are not dismissed, as in the case when an
  511.     // exception gets thrown, then they automatically pop their
  512.     // arguments from the stack.
  513.     class scoped_pop_base
  514.     {
  515.     protected:
  516.         stack_type * pstack_;
  517.         bool mutable owns_;
  518.         scoped_pop_base & operator=( scoped_pop_base const & ); // disallow assignment
  519.     public:
  520.         scoped_pop_base( stack_type * pstack ) // throw(std::bad_alloc,...)
  521.           : pstack_( pstack )
  522.           , owns_( true )
  523.         {
  524.         }
  525.         scoped_pop_base( scoped_pop_base const & that ) // throw() // destructive copy
  526.           : pstack_( that.pstack_ )
  527.           , owns_( that.owns_ )
  528.         {
  529.             // This popper takes ownership, that popper gives it up.
  530.             that.owns_ = false;
  531.         }
  532.         void dismiss() const // throw()
  533.         {
  534.             owns_ = false;
  535.         }
  536.     };
  537.     template< typename T >
  538.     struct scoped_pop_t : public scoped_pop_base
  539.     {
  540.         scoped_pop_t( stack_type * pstack, T const & t ) // throw(std::bad_alloc,...)
  541.           : scoped_pop_base( pstack )
  542.         {
  543.             // Note that if this throws an exception the destructor
  544.             // will not get called, which is what we want.
  545.             pstack_->push( t );
  546.         }
  547.         ~scoped_pop_t() // throw()
  548.         {
  549.             // If we own this stack space, pop it.
  550.             if( owns_ )
  551.                 pstack_->template pop<T>( std::nothrow );
  552.         }
  553.     };
  554.     template< typename T >
  555.     scoped_pop_t<T> scoped_push( T const & t ) // throw(...)
  556.     {
  557.         return scoped_pop_t<T>( this, t );
  558.     }
  559.     typedef scoped_pop_base const & scoped_pop;
  560. };
  561. // BUGBUG push and pop *must* be balanced since d'tors need to be called.
  562. // Iterative execution of regex matching makes this difficult considering
  563. // the fact that push() could cause an exception to be thrown.  The entire
  564. // stack of sub_expr* must be backtracked completely and correctly.
  565. // Alternate solution: push nothing that needs to be destroyed.
  566. #ifdef _MSC_VER
  567. #pragma warning( pop )
  568. #endif
  569. } // namespace regex
  570. #endif