1/*=============================================================================
2    Copyright (c) 2002 Juan Carlos Arevalo-Baeza
3    Copyright (c) 2002-2006 Hartmut Kaiser
4    Copyright (c) 2003 Giovanni Bajo
5    http://spirit.sourceforge.net/
6
7    Use, modification and distribution is subject to the Boost Software
8    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9    http://www.boost.org/LICENSE_1_0.txt)
10=============================================================================*/
11#ifndef BOOST_SPIRIT_CLASSIC_ITERATOR_IMPL_POSITION_ITERATOR_IPP
12#define BOOST_SPIRIT_CLASSIC_ITERATOR_IMPL_POSITION_ITERATOR_IPP
13
14#include <boost/config.hpp>
15#include <boost/iterator_adaptors.hpp>
16#include <boost/type_traits/add_const.hpp>
17#include <boost/mpl/if.hpp>
18#include <boost/type_traits/is_same.hpp>
19#include <boost/spirit/home/classic/core/nil.hpp>  // for nil_t
20#include <iterator> // for std::iterator_traits
21
22namespace boost { namespace spirit {
23
24BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
25
26///////////////////////////////////////////////////////////////////////////////
27//
28//  position_policy<file_position_without_column>
29//
30//  Specialization to handle file_position_without_column. Only take care of
31//  newlines since no column tracking is needed.
32//
33///////////////////////////////////////////////////////////////////////////////
34template <typename String>
35class position_policy<file_position_without_column_base<String> > {
36
37public:
38    void next_line(file_position_without_column_base<String>& pos)
39    {
40        ++pos.line;
41    }
42
43    void set_tab_chars(unsigned int /*chars*/){}
44    void next_char(file_position_without_column_base<String>& /*pos*/)    {}
45    void tabulation(file_position_without_column_base<String>& /*pos*/)   {}
46};
47
48///////////////////////////////////////////////////////////////////////////////
49//
50//  position_policy<file_position>
51//
52//  Specialization to handle file_position. Track characters and tabulation
53//  to compute the current column correctly.
54//
55//  Default tab size is 4. You can change this with the set_tabchars member
56//  of position_iterator.
57//
58///////////////////////////////////////////////////////////////////////////////
59template <typename String>
60class position_policy<file_position_base<String> > {
61
62public:
63    position_policy()
64        : m_CharsPerTab(4)
65    {}
66
67    void next_line(file_position_base<String>& pos)
68    {
69        ++pos.line;
70        pos.column = 1;
71    }
72
73    void set_tab_chars(unsigned int chars)
74    {
75        m_CharsPerTab = chars;
76    }
77
78    void next_char(file_position_base<String>& pos)
79    {
80        ++pos.column;
81    }
82
83    void tabulation(file_position_base<String>& pos)
84    {
85        pos.column += m_CharsPerTab - (pos.column - 1) % m_CharsPerTab;
86    }
87
88private:
89    unsigned int m_CharsPerTab;
90};
91
92/* namespace boost::spirit { */ namespace iterator_ { namespace impl {
93
94template <typename T>
95struct make_const : boost::add_const<T>
96{};
97
98template <typename T>
99struct make_const<T&>
100{
101    typedef typename boost::add_const<T>::type& type;
102};
103
104///////////////////////////////////////////////////////////////////////////////
105//
106//  position_iterator_base_generator
107//
108//  Metafunction to generate the iterator type using boost::iterator_adaptors,
109//  hiding all the metaprogramming thunking code in it. It is used
110//  mainly to keep the public interface (position_iterator) cleanear.
111//
112///////////////////////////////////////////////////////////////////////////////
113template <typename MainIterT, typename ForwardIterT, typename PositionT>
114struct position_iterator_base_generator
115{
116private:
117    typedef std::iterator_traits<ForwardIterT> traits;
118    typedef typename traits::value_type value_type;
119    typedef typename traits::iterator_category iter_category_t;
120    typedef typename traits::reference reference;
121
122    // Position iterator is always a non-mutable iterator
123    typedef typename boost::add_const<value_type>::type const_value_type;
124
125public:
126    // Check if the MainIterT is nil. If it's nil, it means that the actual
127    //  self type is position_iterator. Otherwise, it's a real type we
128    //  must use
129    typedef typename boost::mpl::if_<
130        typename boost::is_same<MainIterT, nil_t>::type,
131        position_iterator<ForwardIterT, PositionT, nil_t>,
132        MainIterT
133    >::type main_iter_t;
134
135    typedef boost::iterator_adaptor<
136        main_iter_t,
137        ForwardIterT,
138        const_value_type,
139        boost::forward_traversal_tag,
140        typename make_const<reference>::type
141    > type;
142};
143
144}}
145
146BOOST_SPIRIT_CLASSIC_NAMESPACE_END
147
148}} /* namespace boost::spirit::iterator_::impl */
149
150#endif
151