fixed_size_queue.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // Copyright (c) 2001 Daniel C. Nuffer
  2. // Copyright (c) 2001-2011 Hartmut Kaiser
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #if !defined(BOOST_SPIRIT_ITERATOR_FIXED_SIZE_QUEUE_MAR_16_2007_1137AM)
  7. #define BOOST_SPIRIT_ITERATOR_FIXED_SIZE_QUEUE_MAR_16_2007_1137AM
  8. #include <cstdlib>
  9. #include <iterator>
  10. #include <cstddef>
  11. #include <boost/config.hpp>
  12. #include <boost/assert.hpp> // for BOOST_ASSERT
  13. #include <boost/iterator_adaptors.hpp>
  14. ///////////////////////////////////////////////////////////////////////////////
  15. // Make sure we're using a decent version of the Boost.IteratorAdaptors lib
  16. #if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \
  17. BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
  18. #error "Please use at least Boost V1.31.0 while compiling the fixed_size_queue class!"
  19. #endif
  20. ///////////////////////////////////////////////////////////////////////////////
  21. #define BOOST_SPIRIT_ASSERT_FSQ_SIZE \
  22. BOOST_ASSERT(((m_tail + N + 1) - m_head) % (N+1) == m_size % (N+1)) \
  23. /**/
  24. ///////////////////////////////////////////////////////////////////////////////
  25. namespace boost { namespace spirit { namespace detail
  26. {
  27. ///////////////////////////////////////////////////////////////////////////
  28. template <typename Queue, typename T, typename Pointer>
  29. class fsq_iterator
  30. : public boost::iterator_facade<
  31. fsq_iterator<Queue, T, Pointer>, T,
  32. std::random_access_iterator_tag
  33. >
  34. {
  35. public:
  36. typedef typename Queue::position_type position_type;
  37. typedef boost::iterator_facade<
  38. fsq_iterator<Queue, T, Pointer>, T,
  39. std::random_access_iterator_tag
  40. > base_type;
  41. fsq_iterator() {}
  42. fsq_iterator(position_type const &p_) : p(p_) {}
  43. position_type &get_position() { return p; }
  44. position_type const &get_position() const { return p; }
  45. private:
  46. friend class boost::iterator_core_access;
  47. typename base_type::reference dereference() const
  48. {
  49. return p.self->m_queue[p.pos];
  50. }
  51. void increment()
  52. {
  53. ++p.pos;
  54. if (p.pos == Queue::MAX_SIZE+1)
  55. p.pos = 0;
  56. }
  57. void decrement()
  58. {
  59. if (p.pos == 0)
  60. p.pos = Queue::MAX_SIZE;
  61. else
  62. --p.pos;
  63. }
  64. bool is_eof() const
  65. {
  66. return p.self == 0 || p.pos == p.self->size();
  67. }
  68. template <typename Q, typename T_, typename P>
  69. bool equal(fsq_iterator<Q, T_, P> const &x) const
  70. {
  71. if (is_eof())
  72. return x.is_eof();
  73. if (x.is_eof())
  74. return false;
  75. position_type const &rhs_pos = x.get_position();
  76. return (p.self == rhs_pos.self) && (p.pos == rhs_pos.pos);
  77. }
  78. template <typename Q, typename T_, typename P>
  79. typename base_type::difference_type distance_to(
  80. fsq_iterator<Q, T_, P> const &x) const
  81. {
  82. typedef typename base_type::difference_type difference_type;
  83. position_type const &p2 = x.get_position();
  84. std::size_t pos1 = p.pos;
  85. std::size_t pos2 = p2.pos;
  86. // Undefined behavior if the iterators come from different
  87. // containers
  88. BOOST_ASSERT(p.self == p2.self);
  89. if (pos1 < p.self->m_head)
  90. pos1 += Queue::MAX_SIZE;
  91. if (pos2 < p2.self->m_head)
  92. pos2 += Queue::MAX_SIZE;
  93. if (pos2 > pos1)
  94. return difference_type(pos2 - pos1);
  95. else
  96. return -difference_type(pos1 - pos2);
  97. }
  98. void advance(typename base_type::difference_type n)
  99. {
  100. // Notice that we don't care values of n that can
  101. // wrap around more than one time, since it would
  102. // be undefined behavior anyway (going outside
  103. // the begin/end range). Negative wrapping is a bit
  104. // cumbersome because we don't want to case p.pos
  105. // to signed.
  106. if (n < 0)
  107. {
  108. n = -n;
  109. if (p.pos < (std::size_t)n)
  110. p.pos = Queue::MAX_SIZE+1 - (n - p.pos);
  111. else
  112. p.pos -= n;
  113. }
  114. else
  115. {
  116. p.pos += n;
  117. if (p.pos >= Queue::MAX_SIZE+1)
  118. p.pos -= Queue::MAX_SIZE+1;
  119. }
  120. }
  121. private:
  122. position_type p;
  123. };
  124. ///////////////////////////////////////////////////////////////////////////
  125. template <typename T, std::size_t N>
  126. class fixed_size_queue
  127. {
  128. private:
  129. struct position
  130. {
  131. fixed_size_queue* self;
  132. std::size_t pos;
  133. position() : self(0), pos(0) {}
  134. // The const_cast here is just to avoid to have two different
  135. // position structures for the const and non-const case.
  136. // The const semantic is guaranteed by the iterator itself
  137. position(const fixed_size_queue* s, std::size_t p)
  138. : self(const_cast<fixed_size_queue*>(s)), pos(p)
  139. {}
  140. bool is_initialized() const { return self != 0; }
  141. void set_queue(fixed_size_queue* q) { self = q; }
  142. };
  143. public:
  144. // Declare the iterators
  145. typedef fsq_iterator<fixed_size_queue<T, N>, T, T*> iterator;
  146. typedef
  147. fsq_iterator<fixed_size_queue<T, N>, T const, T const*>
  148. const_iterator;
  149. typedef position position_type;
  150. friend class fsq_iterator<fixed_size_queue<T, N>, T, T*>;
  151. friend class fsq_iterator<fixed_size_queue<T, N>, T const, T const*>;
  152. fixed_size_queue();
  153. fixed_size_queue(const fixed_size_queue& x);
  154. fixed_size_queue& operator=(const fixed_size_queue& x);
  155. ~fixed_size_queue();
  156. void push_back(const T& e);
  157. void push_front(const T& e);
  158. void serve(T& e);
  159. void pop_front();
  160. bool empty() const
  161. {
  162. return m_size == 0;
  163. }
  164. bool full() const
  165. {
  166. return m_size == N;
  167. }
  168. iterator begin()
  169. {
  170. return iterator(position(this, m_head));
  171. }
  172. const_iterator begin() const
  173. {
  174. return const_iterator(position(this, m_head));
  175. }
  176. iterator end()
  177. {
  178. return iterator(position(0, m_tail));
  179. }
  180. const_iterator end() const
  181. {
  182. return const_iterator(position(0, m_tail));
  183. }
  184. std::size_t size() const
  185. {
  186. return m_size;
  187. }
  188. T& front()
  189. {
  190. return m_queue[m_head];
  191. }
  192. const T& front() const
  193. {
  194. return m_queue[m_head];
  195. }
  196. private:
  197. // Redefine the template parameters to avoid using partial template
  198. // specialization on the iterator policy to extract N.
  199. BOOST_STATIC_CONSTANT(std::size_t, MAX_SIZE = N);
  200. std::size_t m_head;
  201. std::size_t m_tail;
  202. std::size_t m_size;
  203. T m_queue[N+1];
  204. };
  205. template <typename T, std::size_t N>
  206. inline
  207. fixed_size_queue<T, N>::fixed_size_queue()
  208. : m_head(0)
  209. , m_tail(0)
  210. , m_size(0)
  211. {
  212. BOOST_ASSERT(m_size <= N+1);
  213. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  214. BOOST_ASSERT(m_head <= N+1);
  215. BOOST_ASSERT(m_tail <= N+1);
  216. }
  217. template <typename T, std::size_t N>
  218. inline
  219. fixed_size_queue<T, N>::fixed_size_queue(const fixed_size_queue& x)
  220. : m_head(x.m_head)
  221. , m_tail(x.m_tail)
  222. , m_size(x.m_size)
  223. {
  224. copy(x.begin(), x.end(), begin());
  225. BOOST_ASSERT(m_size <= N+1);
  226. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  227. BOOST_ASSERT(m_head <= N+1);
  228. BOOST_ASSERT(m_tail <= N+1);
  229. }
  230. template <typename T, std::size_t N>
  231. inline fixed_size_queue<T, N>&
  232. fixed_size_queue<T, N>::operator=(const fixed_size_queue& x)
  233. {
  234. if (this != &x)
  235. {
  236. m_head = x.m_head;
  237. m_tail = x.m_tail;
  238. m_size = x.m_size;
  239. copy(x.begin(), x.end(), begin());
  240. }
  241. BOOST_ASSERT(m_size <= N+1);
  242. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  243. BOOST_ASSERT(m_head <= N+1);
  244. BOOST_ASSERT(m_tail <= N+1);
  245. return *this;
  246. }
  247. template <typename T, std::size_t N>
  248. inline
  249. fixed_size_queue<T, N>::~fixed_size_queue()
  250. {
  251. BOOST_ASSERT(m_size <= N+1);
  252. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  253. BOOST_ASSERT(m_head <= N+1);
  254. BOOST_ASSERT(m_tail <= N+1);
  255. }
  256. template <typename T, std::size_t N>
  257. inline void
  258. fixed_size_queue<T, N>::push_back(const T& e)
  259. {
  260. BOOST_ASSERT(m_size <= N+1);
  261. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  262. BOOST_ASSERT(m_head <= N+1);
  263. BOOST_ASSERT(m_tail <= N+1);
  264. BOOST_ASSERT(!full());
  265. m_queue[m_tail] = e;
  266. ++m_size;
  267. ++m_tail;
  268. if (m_tail == N+1)
  269. m_tail = 0;
  270. BOOST_ASSERT(m_size <= N+1);
  271. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  272. BOOST_ASSERT(m_head <= N+1);
  273. BOOST_ASSERT(m_tail <= N+1);
  274. }
  275. template <typename T, std::size_t N>
  276. inline void
  277. fixed_size_queue<T, N>::push_front(const T& e)
  278. {
  279. BOOST_ASSERT(m_size <= N+1);
  280. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  281. BOOST_ASSERT(m_head <= N+1);
  282. BOOST_ASSERT(m_tail <= N+1);
  283. BOOST_ASSERT(!full());
  284. if (m_head == 0)
  285. m_head = N;
  286. else
  287. --m_head;
  288. m_queue[m_head] = e;
  289. ++m_size;
  290. BOOST_ASSERT(m_size <= N+1);
  291. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  292. BOOST_ASSERT(m_head <= N+1);
  293. BOOST_ASSERT(m_tail <= N+1);
  294. }
  295. template <typename T, std::size_t N>
  296. inline void
  297. fixed_size_queue<T, N>::serve(T& e)
  298. {
  299. BOOST_ASSERT(m_size <= N+1);
  300. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  301. BOOST_ASSERT(m_head <= N+1);
  302. BOOST_ASSERT(m_tail <= N+1);
  303. e = m_queue[m_head];
  304. pop_front();
  305. }
  306. template <typename T, std::size_t N>
  307. inline void
  308. fixed_size_queue<T, N>::pop_front()
  309. {
  310. BOOST_ASSERT(m_size <= N+1);
  311. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  312. BOOST_ASSERT(m_head <= N+1);
  313. BOOST_ASSERT(m_tail <= N+1);
  314. ++m_head;
  315. if (m_head == N+1)
  316. m_head = 0;
  317. --m_size;
  318. BOOST_ASSERT(m_size <= N+1);
  319. BOOST_SPIRIT_ASSERT_FSQ_SIZE;
  320. BOOST_ASSERT(m_head <= N+1);
  321. BOOST_ASSERT(m_tail <= N+1);
  322. }
  323. }}}
  324. #undef BOOST_SPIRIT_ASSERT_FSQ_SIZE
  325. #endif