/src/contrib/boost-1.52.0/boost/xpressive/detail/utility/sequence_stack.hpp

https://gitlab.com/tylerluo/pythonocc · C++ Header · 259 lines · 185 code · 41 blank · 33 comment · 17 complexity · d9751b6abc706ddc5d4c1aa2d4c970aa MD5 · raw file

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // sequence_stack.hpp
  3. //
  4. // Copyright 2008 Eric Niebler. Distributed under the Boost
  5. // Software License, Version 1.0. (See accompanying file
  6. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
  8. #define BOOST_XPRESSIVE_DETAIL_SEQUENCE_STACK_HPP_EAN_10_04_2005
  9. // MS compatible compilers support #pragma once
  10. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  11. # pragma once
  12. # pragma warning(push)
  13. # pragma warning(disable : 4127) // conditional expression constant
  14. #endif
  15. #include <algorithm>
  16. #include <functional>
  17. namespace boost { namespace xpressive { namespace detail
  18. {
  19. struct fill_t {} const fill = {};
  20. //////////////////////////////////////////////////////////////////////////
  21. // sequence_stack
  22. //
  23. // For storing a stack of sequences of type T, where each sequence
  24. // is guaranteed to be stored in contiguous memory.
  25. template<typename T>
  26. struct sequence_stack
  27. {
  28. private:
  29. static T *allocate(std::size_t size, T const &t)
  30. {
  31. std::size_t i = 0;
  32. T *p = (T *)::operator new(size * sizeof(T));
  33. try
  34. {
  35. for(; i < size; ++i)
  36. ::new((void *)(p+i)) T(t);
  37. }
  38. catch(...)
  39. {
  40. deallocate(p, i);
  41. throw;
  42. }
  43. return p;
  44. }
  45. static void deallocate(T *p, std::size_t i)
  46. {
  47. while(i-- > 0)
  48. (p+i)->~T();
  49. ::operator delete(p);
  50. }
  51. struct chunk
  52. {
  53. chunk(std::size_t size, T const &t, std::size_t count, chunk *back, chunk *next)
  54. : begin_(allocate(size, t))
  55. , curr_(begin_ + count)
  56. , end_(begin_ + size)
  57. , back_(back)
  58. , next_(next)
  59. {
  60. if(this->back_)
  61. this->back_->next_ = this;
  62. if(this->next_)
  63. this->next_->back_ = this;
  64. }
  65. ~chunk()
  66. {
  67. deallocate(this->begin_, this->size());
  68. }
  69. std::size_t size() const
  70. {
  71. return static_cast<std::size_t>(this->end_ - this->begin_);
  72. }
  73. T *const begin_, *curr_, *const end_;
  74. chunk *back_, *next_;
  75. private:
  76. chunk &operator =(chunk const &);
  77. };
  78. chunk *current_chunk_;
  79. // Cache these for faster access
  80. T *begin_;
  81. T *curr_;
  82. T *end_;
  83. T *grow_(std::size_t count, T const &t)
  84. {
  85. if(this->current_chunk_)
  86. {
  87. // write the cached value of current into the expr.
  88. // OK to do this even if later statements throw.
  89. this->current_chunk_->curr_ = this->curr_;
  90. // Do we have a expr with enough available memory already?
  91. if(this->current_chunk_->next_ && count <= this->current_chunk_->next_->size())
  92. {
  93. this->current_chunk_ = this->current_chunk_->next_;
  94. this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_ + count;
  95. this->end_ = this->current_chunk_->end_;
  96. this->begin_ = this->current_chunk_->begin_;
  97. std::fill_n(this->begin_, count, t);
  98. return this->begin_;
  99. }
  100. // grow exponentially
  101. std::size_t new_size = (std::max)(count, static_cast<std::size_t>(this->current_chunk_->size() * 1.5));
  102. // Create a new expr and insert it into the list
  103. this->current_chunk_ = new chunk(new_size, t, count, this->current_chunk_, this->current_chunk_->next_);
  104. }
  105. else
  106. {
  107. // first chunk is 256
  108. std::size_t new_size = (std::max)(count, static_cast<std::size_t>(256U));
  109. // Create a new expr and insert it into the list
  110. this->current_chunk_ = new chunk(new_size, t, count, 0, 0);
  111. }
  112. this->begin_ = this->current_chunk_->begin_;
  113. this->curr_ = this->current_chunk_->curr_;
  114. this->end_ = this->current_chunk_->end_;
  115. return this->begin_;
  116. }
  117. void unwind_chunk_()
  118. {
  119. // write the cached value of curr_ into current_chunk_
  120. this->current_chunk_->curr_ = this->begin_;
  121. // make the previous chunk the current
  122. this->current_chunk_ = this->current_chunk_->back_;
  123. // update the cache
  124. this->begin_ = this->current_chunk_->begin_;
  125. this->curr_ = this->current_chunk_->curr_;
  126. this->end_ = this->current_chunk_->end_;
  127. }
  128. bool in_current_chunk(T *ptr) const
  129. {
  130. return !std::less<void*>()(ptr, this->begin_) && std::less<void*>()(ptr, this->end_);
  131. }
  132. public:
  133. sequence_stack()
  134. : current_chunk_(0)
  135. , begin_(0)
  136. , curr_(0)
  137. , end_(0)
  138. {
  139. }
  140. ~sequence_stack()
  141. {
  142. this->clear();
  143. }
  144. // walk to the front of the linked list
  145. void unwind()
  146. {
  147. if(this->current_chunk_)
  148. {
  149. while(this->current_chunk_->back_)
  150. {
  151. this->current_chunk_->curr_ = this->current_chunk_->begin_;
  152. this->current_chunk_ = this->current_chunk_->back_;
  153. }
  154. this->begin_ = this->curr_ = this->current_chunk_->curr_ = this->current_chunk_->begin_;
  155. this->end_ = this->current_chunk_->end_;
  156. }
  157. }
  158. void clear()
  159. {
  160. // walk to the front of the list
  161. this->unwind();
  162. // delete the list
  163. for(chunk *next; this->current_chunk_; this->current_chunk_ = next)
  164. {
  165. next = this->current_chunk_->next_;
  166. delete this->current_chunk_;
  167. }
  168. this->begin_ = this->curr_ = this->end_ = 0;
  169. }
  170. T *push_sequence(std::size_t count, T const &t)
  171. {
  172. // This is the ptr to return
  173. T *ptr = this->curr_;
  174. // Advance the high-water mark
  175. this->curr_ += count;
  176. // Check to see if we have overflowed this buffer
  177. if(std::less<void*>()(this->end_, this->curr_))
  178. {
  179. // oops, back this out.
  180. this->curr_ = ptr;
  181. // allocate a new block and return a ptr to the new memory
  182. return this->grow_(count, t);
  183. }
  184. return ptr;
  185. }
  186. T *push_sequence(std::size_t count, T const &t, fill_t)
  187. {
  188. T *ptr = this->push_sequence(count, t);
  189. std::fill_n(ptr, count, t);
  190. return ptr;
  191. }
  192. void unwind_to(T *ptr)
  193. {
  194. while(!this->in_current_chunk(ptr))
  195. {
  196. // completely unwind the current chunk, move to the previous chunk
  197. this->unwind_chunk_();
  198. }
  199. this->current_chunk_->curr_ = this->curr_ = ptr;
  200. }
  201. // shrink-to-fit: remove any unused nodes in the chain
  202. void conserve()
  203. {
  204. if(this->current_chunk_)
  205. {
  206. for(chunk *next; this->current_chunk_->next_; this->current_chunk_->next_ = next)
  207. {
  208. next = this->current_chunk_->next_->next_;
  209. delete this->current_chunk_->next_;
  210. }
  211. }
  212. }
  213. };
  214. }}} // namespace boost::xpressive::detail
  215. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  216. # pragma warning(pop)
  217. #endif
  218. #endif