source: NonGTP/Boost/boost/spirit/iterator/fixed_size_queue.hpp @ 857

Revision 857, 10.3 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Copyright (c) 2001, Daniel C. Nuffer
3    Copyright (c) 2003, Hartmut Kaiser
4    http://spirit.sourceforge.net/
5
6    Use, modification and distribution is subject to the Boost Software
7    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8    http://www.boost.org/LICENSE_1_0.txt)
9=============================================================================*/
10#ifndef FIXED_SIZE_QUEUE
11#define FIXED_SIZE_QUEUE
12
13#include <cstdlib>
14#include <iterator>
15#include <cstddef>
16
17#include <boost/spirit/core/assert.hpp> // for BOOST_SPIRIT_ASSERT
18
19// FIXES for broken compilers
20#include <boost/config.hpp>
21#include <boost/iterator_adaptors.hpp>
22
23#define BOOST_SPIRIT_ASSERT_FSQ_SIZE \
24    BOOST_SPIRIT_ASSERT(((m_tail + N + 1) - m_head) % (N+1) == m_size % (N+1)) \
25    /**/
26
27///////////////////////////////////////////////////////////////////////////////
28namespace boost { namespace spirit {
29
30///////////////////////////////////////////////////////////////////////////////
31namespace impl {
32
33#if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \
34    BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
35#error "Please use at least Boost V1.31.0 while compiling the fixed_size_queue class!"
36#else // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
37
38template <typename QueueT, typename T, typename PointerT>
39class fsq_iterator
40:   public boost::iterator_adaptor<
41        fsq_iterator<QueueT, T, PointerT>,
42        PointerT,
43        T,
44        std::random_access_iterator_tag
45    >
46{
47public:
48    typedef typename QueueT::position_t position;
49    typedef boost::iterator_adaptor<
50            fsq_iterator<QueueT, T, PointerT>, PointerT, T,
51            std::random_access_iterator_tag
52        > base_t;
53
54    fsq_iterator() {}
55    fsq_iterator(position const &p_) : p(p_) {}
56   
57    position const &get_position() const { return p; }
58   
59private:
60    friend class boost::iterator_core_access;
61   
62    typename base_t::reference dereference() const
63    {
64        return p.self->m_queue[p.pos];
65    }
66
67    void increment()
68    {
69        ++p.pos;
70        if (p.pos == QueueT::MAX_SIZE+1)
71            p.pos = 0;
72    }
73
74    void decrement()
75    {
76        if (p.pos == 0)
77            p.pos = QueueT::MAX_SIZE;
78        else
79            --p.pos;
80    }
81
82    template <
83        typename OtherDerivedT, typename OtherIteratorT,
84        typename V, typename C, typename R, typename D
85    >   
86    bool equal(iterator_adaptor<OtherDerivedT, OtherIteratorT, V, C, R, D>
87        const &x) const
88    {
89        position const &rhs_pos =
90            static_cast<OtherDerivedT const &>(x).get_position();
91        return (p.self == rhs_pos.self) && (p.pos == rhs_pos.pos);
92    }
93
94    template <
95        typename OtherDerivedT, typename OtherIteratorT,
96        typename V, typename C, typename R, typename D
97    >   
98    typename base_t::difference_type distance_to(
99        iterator_adaptor<OtherDerivedT, OtherIteratorT, V, C, R, D>
100        const &x) const
101    {
102        typedef typename base_t::difference_type diff_t;
103
104        position const &p2 =
105            static_cast<OtherDerivedT const &>(x).get_position();
106        std::size_t pos1 = p.pos;
107        std::size_t pos2 = p2.pos;
108
109        // Undefined behaviour if the iterators come from different
110        //  containers
111        BOOST_SPIRIT_ASSERT(p.self == p2.self);
112
113        if (pos1 < p.self->m_head)
114            pos1 += QueueT::MAX_SIZE;
115        if (pos2 < p2.self->m_head)
116            pos2 += QueueT::MAX_SIZE;
117
118        if (pos2 > pos1)
119            return diff_t(pos2 - pos1);
120        else
121            return -diff_t(pos1 - pos2);
122    }
123
124    void advance(typename base_t::difference_type n)
125    {
126        // Notice that we don't care values of n that can
127        //  wrap around more than one time, since it would
128        //  be undefined behaviour anyway (going outside
129        //  the begin/end range). Negative wrapping is a bit
130        //  cumbersome because we don't want to case p.pos
131        //  to signed.
132        if (n < 0)
133        {
134            n = -n;
135            if (p.pos < (std::size_t)n)
136                p.pos = QueueT::MAX_SIZE+1 - (n - p.pos);
137            else
138                p.pos -= n;
139        }
140        else
141        {
142            p.pos += n;
143            if (p.pos >= QueueT::MAX_SIZE+1)
144                p.pos -= QueueT::MAX_SIZE+1;
145        }
146    }
147   
148private:
149    position p;
150};
151
152#endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
153
154///////////////////////////////////////////////////////////////////////////////
155} /* namespace impl */
156
157template <typename T, std::size_t N>
158class fixed_size_queue
159{
160private:
161    struct position
162    {
163        fixed_size_queue* self;
164        std::size_t pos;
165
166        position() : self(0), pos(0) {}
167
168        // The const_cast here is just to avoid to have two different
169        //  position structures for the const and non-const case.
170        // The const semantic is guaranteed by the iterator itself
171        position(const fixed_size_queue* s, std::size_t p)
172            : self(const_cast<fixed_size_queue*>(s)), pos(p)
173        {}
174    };
175
176public:
177    // Declare the iterators
178    typedef impl::fsq_iterator<fixed_size_queue<T, N>, T, T*> iterator;
179    typedef impl::fsq_iterator<fixed_size_queue<T, N>, T const, T const*>
180        const_iterator;
181    typedef position position_t;
182
183    friend class impl::fsq_iterator<fixed_size_queue<T, N>, T, T*>;
184    friend class impl::fsq_iterator<fixed_size_queue<T, N>, T const, T const*>;
185   
186    fixed_size_queue();
187    fixed_size_queue(const fixed_size_queue& x);
188    fixed_size_queue& operator=(const fixed_size_queue& x);
189    ~fixed_size_queue();
190
191    void push_back(const T& e);
192    void push_front(const T& e);
193    void serve(T& e);
194    void pop_front();
195
196    bool empty() const
197    {
198        return m_size == 0;
199    }
200
201    bool full() const
202    {
203        return m_size == N;
204    }
205
206    iterator begin()
207    {
208        return iterator(position(this, m_head));
209    }
210
211    const_iterator begin() const
212    {
213        return const_iterator(position(this, m_head));
214    }
215
216    iterator end()
217    {
218        return iterator(position(this, m_tail));
219    }
220
221    const_iterator end() const
222    {
223        return const_iterator(position(this, m_tail));
224    }
225
226    std::size_t size() const
227    {
228        return m_size;
229    }
230
231    T& front()
232    {
233        return m_queue[m_head];
234    }
235
236    const T& front() const
237    {
238        return m_queue[m_head];
239    }
240
241private:
242    // Redefine the template parameters to avoid using partial template
243    //  specialization on the iterator policy to extract N.
244    BOOST_STATIC_CONSTANT(std::size_t, MAX_SIZE = N);
245
246    std::size_t m_head;
247    std::size_t m_tail;
248    std::size_t m_size;
249    T m_queue[N+1];
250};
251
252template <typename T, std::size_t N>
253inline
254fixed_size_queue<T, N>::fixed_size_queue()
255    : m_head(0)
256    , m_tail(0)
257    , m_size(0)
258{
259    BOOST_SPIRIT_ASSERT(m_size <= N+1);
260    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
261    BOOST_SPIRIT_ASSERT(m_head <= N+1);
262    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
263}
264
265template <typename T, std::size_t N>
266inline
267fixed_size_queue<T, N>::fixed_size_queue(const fixed_size_queue& x)
268    : m_head(x.m_head)
269    , m_tail(x.m_tail)
270    , m_size(x.m_size)
271{
272    copy(x.begin(), x.end(), begin());
273    BOOST_SPIRIT_ASSERT(m_size <= N+1);
274    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
275    BOOST_SPIRIT_ASSERT(m_head <= N+1);
276    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
277}
278
279template <typename T, std::size_t N>
280inline fixed_size_queue<T, N>&
281fixed_size_queue<T, N>::operator=(const fixed_size_queue& x)
282{
283    if (this != &x)
284    {
285        m_head = x.m_head;
286        m_tail = x.m_tail;
287        m_size = x.m_size;
288        copy(x.begin(), x.end(), begin());
289    }
290    BOOST_SPIRIT_ASSERT(m_size <= N+1);
291    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
292    BOOST_SPIRIT_ASSERT(m_head <= N+1);
293    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
294
295    return *this;
296}
297
298template <typename T, std::size_t N>
299inline
300fixed_size_queue<T, N>::~fixed_size_queue()
301{
302    BOOST_SPIRIT_ASSERT(m_size <= N+1);
303    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
304    BOOST_SPIRIT_ASSERT(m_head <= N+1);
305    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
306}
307
308template <typename T, std::size_t N>
309inline void
310fixed_size_queue<T, N>::push_back(const T& e)
311{
312    BOOST_SPIRIT_ASSERT(m_size <= N+1);
313    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
314    BOOST_SPIRIT_ASSERT(m_head <= N+1);
315    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
316
317    BOOST_SPIRIT_ASSERT(!full());
318
319    m_queue[m_tail] = e;
320    ++m_size;
321    ++m_tail;
322    if (m_tail == N+1)
323        m_tail = 0;
324
325
326    BOOST_SPIRIT_ASSERT(m_size <= N+1);
327    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
328    BOOST_SPIRIT_ASSERT(m_head <= N+1);
329    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
330}
331
332template <typename T, std::size_t N>
333inline void
334fixed_size_queue<T, N>::push_front(const T& e)
335{
336    BOOST_SPIRIT_ASSERT(m_size <= N+1);
337    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
338    BOOST_SPIRIT_ASSERT(m_head <= N+1);
339    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
340
341    BOOST_SPIRIT_ASSERT(!full());
342
343    if (m_head == 0)
344        m_head = N;
345    else
346        --m_head;
347
348    m_queue[m_head] = e;
349    ++m_size;
350
351    BOOST_SPIRIT_ASSERT(m_size <= N+1);
352    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
353    BOOST_SPIRIT_ASSERT(m_head <= N+1);
354    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
355}
356
357
358template <typename T, std::size_t N>
359inline void
360fixed_size_queue<T, N>::serve(T& e)
361{
362    BOOST_SPIRIT_ASSERT(m_size <= N+1);
363    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
364    BOOST_SPIRIT_ASSERT(m_head <= N+1);
365    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
366
367    e = m_queue[m_head];
368    pop_front();
369}
370
371
372
373template <typename T, std::size_t N>
374inline void
375fixed_size_queue<T, N>::pop_front()
376{
377    BOOST_SPIRIT_ASSERT(m_size <= N+1);
378    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
379    BOOST_SPIRIT_ASSERT(m_head <= N+1);
380    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
381
382    ++m_head;
383    if (m_head == N+1)
384        m_head = 0;
385    --m_size;
386
387    BOOST_SPIRIT_ASSERT(m_size <= N+1);
388    BOOST_SPIRIT_ASSERT_FSQ_SIZE;
389    BOOST_SPIRIT_ASSERT(m_head <= N+1);
390    BOOST_SPIRIT_ASSERT(m_tail <= N+1);
391}
392
393///////////////////////////////////////////////////////////////////////////////
394}} // namespace boost::spirit
395
396#undef BOOST_SPIRIT_ASSERT_FSQ_SIZE
397
398#endif
Note: See TracBrowser for help on using the repository browser.