// Copyright (c) 2001 Daniel C. Nuffer // Copyright (c) 2001-2011 Hartmut Kaiser // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #if !defined(BOOST_SPIRIT_ITERATOR_FIXED_SIZE_QUEUE_MAR_16_2007_1137AM) #define BOOST_SPIRIT_ITERATOR_FIXED_SIZE_QUEUE_MAR_16_2007_1137AM #include #include #include #include #include // for BOOST_ASSERT #include /////////////////////////////////////////////////////////////////////////////// // Make sure we're using a decent version of the Boost.IteratorAdaptors lib #if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \ BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200 #error "Please use at least Boost V1.31.0 while compiling the fixed_size_queue class!" #endif /////////////////////////////////////////////////////////////////////////////// #define BOOST_SPIRIT_ASSERT_FSQ_SIZE \ BOOST_ASSERT(((m_tail + N + 1) - m_head) % (N+1) == m_size % (N+1)) \ /**/ /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace detail { /////////////////////////////////////////////////////////////////////////// template class fsq_iterator : public boost::iterator_facade< fsq_iterator, T, std::random_access_iterator_tag > { public: typedef typename Queue::position_type position_type; typedef boost::iterator_facade< fsq_iterator, T, std::random_access_iterator_tag > base_type; fsq_iterator() {} fsq_iterator(position_type const &p_) : p(p_) {} position_type &get_position() { return p; } position_type const &get_position() const { return p; } private: friend class boost::iterator_core_access; typename base_type::reference dereference() const { return p.self->m_queue[p.pos]; } void increment() { ++p.pos; if (p.pos == Queue::MAX_SIZE+1) p.pos = 0; } void decrement() { if (p.pos == 0) p.pos = Queue::MAX_SIZE; else --p.pos; } bool is_eof() const { return p.self == 0 || p.pos == p.self->size(); } template bool equal(fsq_iterator const &x) const { if (is_eof()) return x.is_eof(); if (x.is_eof()) return false; position_type const &rhs_pos = x.get_position(); return (p.self == rhs_pos.self) && (p.pos == rhs_pos.pos); } template typename base_type::difference_type distance_to( fsq_iterator const &x) const { typedef typename base_type::difference_type difference_type; position_type const &p2 = x.get_position(); std::size_t pos1 = p.pos; std::size_t pos2 = p2.pos; // Undefined behavior if the iterators come from different // containers BOOST_ASSERT(p.self == p2.self); if (pos1 < p.self->m_head) pos1 += Queue::MAX_SIZE; if (pos2 < p2.self->m_head) pos2 += Queue::MAX_SIZE; if (pos2 > pos1) return difference_type(pos2 - pos1); else return -difference_type(pos1 - pos2); } void advance(typename base_type::difference_type n) { // Notice that we don't care values of n that can // wrap around more than one time, since it would // be undefined behavior anyway (going outside // the begin/end range). Negative wrapping is a bit // cumbersome because we don't want to case p.pos // to signed. if (n < 0) { n = -n; if (p.pos < (std::size_t)n) p.pos = Queue::MAX_SIZE+1 - (n - p.pos); else p.pos -= n; } else { p.pos += n; if (p.pos >= Queue::MAX_SIZE+1) p.pos -= Queue::MAX_SIZE+1; } } private: position_type p; }; /////////////////////////////////////////////////////////////////////////// template class fixed_size_queue { private: struct position { fixed_size_queue* self; std::size_t pos; position() : self(0), pos(0) {} // The const_cast here is just to avoid to have two different // position structures for the const and non-const case. // The const semantic is guaranteed by the iterator itself position(const fixed_size_queue* s, std::size_t p) : self(const_cast(s)), pos(p) {} bool is_initialized() const { return self != 0; } void set_queue(fixed_size_queue* q) { self = q; } }; public: // Declare the iterators typedef fsq_iterator, T, T*> iterator; typedef fsq_iterator, T const, T const*> const_iterator; typedef position position_type; friend class fsq_iterator, T, T*>; friend class fsq_iterator, T const, T const*>; fixed_size_queue(); fixed_size_queue(const fixed_size_queue& x); fixed_size_queue& operator=(const fixed_size_queue& x); ~fixed_size_queue(); void push_back(const T& e); void push_front(const T& e); void serve(T& e); void pop_front(); bool empty() const { return m_size == 0; } bool full() const { return m_size == N; } iterator begin() { return iterator(position(this, m_head)); } const_iterator begin() const { return const_iterator(position(this, m_head)); } iterator end() { return iterator(position(0, m_tail)); } const_iterator end() const { return const_iterator(position(0, m_tail)); } std::size_t size() const { return m_size; } T& front() { return m_queue[m_head]; } const T& front() const { return m_queue[m_head]; } private: // Redefine the template parameters to avoid using partial template // specialization on the iterator policy to extract N. BOOST_STATIC_CONSTANT(std::size_t, MAX_SIZE = N); std::size_t m_head; std::size_t m_tail; std::size_t m_size; T m_queue[N+1]; }; template inline fixed_size_queue::fixed_size_queue() : m_head(0) , m_tail(0) , m_size(0) { BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); } template inline fixed_size_queue::fixed_size_queue(const fixed_size_queue& x) : m_head(x.m_head) , m_tail(x.m_tail) , m_size(x.m_size) { copy(x.begin(), x.end(), begin()); BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); } template inline fixed_size_queue& fixed_size_queue::operator=(const fixed_size_queue& x) { if (this != &x) { m_head = x.m_head; m_tail = x.m_tail; m_size = x.m_size; copy(x.begin(), x.end(), begin()); } BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); return *this; } template inline fixed_size_queue::~fixed_size_queue() { BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); } template inline void fixed_size_queue::push_back(const T& e) { BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); BOOST_ASSERT(!full()); m_queue[m_tail] = e; ++m_size; ++m_tail; if (m_tail == N+1) m_tail = 0; BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); } template inline void fixed_size_queue::push_front(const T& e) { BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); BOOST_ASSERT(!full()); if (m_head == 0) m_head = N; else --m_head; m_queue[m_head] = e; ++m_size; BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); } template inline void fixed_size_queue::serve(T& e) { BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); e = m_queue[m_head]; pop_front(); } template inline void fixed_size_queue::pop_front() { BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); ++m_head; if (m_head == N+1) m_head = 0; --m_size; BOOST_ASSERT(m_size <= N+1); BOOST_SPIRIT_ASSERT_FSQ_SIZE; BOOST_ASSERT(m_head <= N+1); BOOST_ASSERT(m_tail <= N+1); } }}} #undef BOOST_SPIRIT_ASSERT_FSQ_SIZE #endif