summaryrefslogtreecommitdiffstats
blob: 402956b87d45fc5e99c31ff655987ab9b833e2d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//  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_SPLIT_DEQUE_POLICY_APR_06_2008_0138PM)
#define BOOST_SPIRIT_ITERATOR_SPLIT_DEQUE_POLICY_APR_06_2008_0138PM

#include <boost/spirit/home/support/iterators/multi_pass_fwd.hpp>
#include <boost/spirit/home/support/iterators/detail/multi_pass.hpp>
#include <boost/assert.hpp>
#include <vector>

namespace boost { namespace spirit { namespace iterator_policies
{
    ///////////////////////////////////////////////////////////////////////////
    //  class split_std_deque
    //
    //  Implementation of the StoragePolicy used by multi_pass
    //  This stores all data in a std::vector (despite its name), and keeps an 
    //  offset to the current position. It stores all the data unless there is 
    //  only one iterator using the queue.
    // 
    ///////////////////////////////////////////////////////////////////////////
    struct split_std_deque
    {
        enum { threshold = 16 };

        ///////////////////////////////////////////////////////////////////////
        template <typename Value>
        class unique //: public detail::default_storage_policy
        {
        private:
            typedef std::vector<Value> queue_type;

        protected:
            unique() : queued_position(0) {}

            unique(unique const& x)
              : queued_position(x.queued_position) {}

            void swap(unique& x)
            {
                boost::swap(queued_position, x.queued_position);
            }

            // This is called when the iterator is dereferenced.  It's a 
            // template method so we can recover the type of the multi_pass 
            // iterator and call advance_input and input_is_valid.
            template <typename MultiPass>
            static typename MultiPass::reference 
            dereference(MultiPass const& mp)
            {
                queue_type& queue = mp.shared()->queued_elements;
                typename queue_type::size_type size = queue.size();

                BOOST_ASSERT(mp.queued_position <= size);

                if (mp.queued_position == size)
                {
                    // check if this is the only iterator
                    if (size >= threshold && MultiPass::is_unique(mp))
                    {
                        // free up the memory used by the queue.
                        queue.clear();
                        mp.queued_position = 0;
                    }
                    return MultiPass::get_input(mp);
                }

                return queue[mp.queued_position];
            }

            // This is called when the iterator is incremented. It's a template
            // method so we can recover the type of the multi_pass iterator
            // and call is_unique and advance_input.
            template <typename MultiPass>
            static void increment(MultiPass& mp)
            {
                queue_type& queue = mp.shared()->queued_elements;
                typename queue_type::size_type size = queue.size();

                BOOST_ASSERT(mp.queued_position <= size);

//                 // do not increment iterator as long as the current token is
//                 // invalid
//                 if (size > 0 && !MultiPass::input_is_valid(mp, queue[mp.queued_position-1]))
//                     return;

                if (mp.queued_position == size)
                {
                    // check if this is the only iterator
                    if (size >= threshold && MultiPass::is_unique(mp))
                    {
                        // free up the memory used by the queue. we avoid 
                        // clearing the queue on every increment, though, 
                        // because this would be too time consuming
                        queue.clear();
                        mp.queued_position = 0;
                    }
                    else
                    {
                        queue.push_back(MultiPass::get_input(mp));
                        ++mp.queued_position;
                    }
                    MultiPass::advance_input(mp);
                }
                else
                {
                    ++mp.queued_position;
                }
            }

            // called to forcibly clear the queue
            template <typename MultiPass>
            static void clear_queue(MultiPass& mp)
            {
                mp.shared()->queued_elements.clear();
                mp.queued_position = 0;
            }

            // called to determine whether the iterator is an eof iterator
            template <typename MultiPass>
            static bool is_eof(MultiPass const& mp)
            {
                return mp.queued_position == mp.shared()->queued_elements.size() 
                    && MultiPass::input_at_eof(mp);
            }

            // called by operator==
            template <typename MultiPass>
            static bool equal_to(MultiPass const& mp, MultiPass const& x) 
            {
                return mp.queued_position == x.queued_position;
            }

            // called by operator<
            template <typename MultiPass>
            static bool less_than(MultiPass const& mp, MultiPass const& x)
            {
                return mp.queued_position < x.queued_position;
            }

            template <typename MultiPass>
            static void destroy(MultiPass&) {}

        protected:
            mutable typename queue_type::size_type queued_position;
        }; 

        ///////////////////////////////////////////////////////////////////////
        template <typename Value>
        struct shared
        {
            shared() 
            {
                queued_elements.reserve(threshold); 
            }

            typedef std::vector<Value> queue_type;
            queue_type queued_elements;
        }; 

    }; // split_std_deque

}}}

#endif