summaryrefslogtreecommitdiff
path: root/boost/xpressive/detail/static/width_of.hpp
blob: f7f6f9ecd529db6fe8896061013bafcb8924530f (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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
///////////////////////////////////////////////////////////////////////////////
// width_of.hpp
//
//  Copyright 2008 Eric Niebler. 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)

#ifndef BOOST_XPRESSIVE_DETAIL_STATIC_WIDTH_OF_HPP_EAN_10_04_2005
#define BOOST_XPRESSIVE_DETAIL_STATIC_WIDTH_OF_HPP_EAN_10_04_2005

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <boost/ref.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/times.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/size_t.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/xpressive/detail/detail_fwd.hpp>
#include <boost/xpressive/detail/static/type_traits.hpp>
#include <boost/proto/traits.hpp>

namespace boost { namespace xpressive { namespace detail
{
    template<typename Expr, typename Char, typename Tag = typename Expr::proto_tag>
    struct width_of;

    ///////////////////////////////////////////////////////////////////////////////
    // add_widths
    //
    template<std::size_t N, std::size_t M>
    struct add_widths
      : mpl::size_t<N + M>
    {};

    template<std::size_t M>
    struct add_widths<unknown_width::value, M>
      : unknown_width
    {};

    template<std::size_t N>
    struct add_widths<N, unknown_width::value>
      : unknown_width
    {};

    template<>
    struct add_widths<unknown_width::value, unknown_width::value>
      : unknown_width
    {};

    ///////////////////////////////////////////////////////////////////////////////
    // or_widths
    //
    template<std::size_t N, std::size_t M>
    struct or_widths
      : unknown_width
    {};

    template<std::size_t N>
    struct or_widths<N, N>
      : mpl::size_t<N>
    {};

    ///////////////////////////////////////////////////////////////////////////////
    // width_of_terminal
    //
    template<typename Expr, typename Char, bool IsXpr = is_xpr<Expr>::value>
    struct width_of_terminal
      : mpl::size_t<Expr::width>    // xpressive literals
    {};

    template<typename Expr, typename Char>
    struct width_of_terminal<Expr, Char, false>
      : unknown_width       // unknown literals (eg, basic_string, basic_regex, etc.)
    {};

    template<typename Char>
    struct width_of_terminal<Char, Char, false>
      : mpl::size_t<1>      // char literals
    {};

    template<typename Char>
    struct width_of_terminal<char, Char, false>
      : mpl::size_t<1>      // char literals
    {};

    template<>
    struct width_of_terminal<char, char, false>
      : mpl::size_t<1>      // char literals
    {};

    template<typename Elem, std::size_t N, typename Char>
    struct width_of_terminal<Elem (&) [N], Char, false>
      : mpl::size_t<N-is_char<Elem>::value>    // string literals
    {};

    template<typename Elem, std::size_t N, typename Char>
    struct width_of_terminal<Elem const (&) [N], Char, false>
      : mpl::size_t<N-is_char<Elem>::value>    // string literals
    {};

    ///////////////////////////////////////////////////////////////////////////////
    // width_of
    //
    template<typename Expr, typename Char, typename Tag>
    struct width_of
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::terminal>
      : width_of_terminal<typename proto::result_of::value<Expr>::type, Char>
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::shift_right>
      : add_widths<
            width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char>::value
          , width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>::value
        >
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::bitwise_or>
      : or_widths<
            width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char>::value
          , width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>::value
        >
    {};

    template<typename Expr, typename Char, typename Left>
    struct width_of_assign
    {};

    template<typename Expr, typename Char>
    struct width_of_assign<Expr, Char, mark_placeholder>
      : width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>
    {};

    template<typename Expr, typename Char>
    struct width_of_assign<Expr, Char, set_initializer>
      : mpl::size_t<1>
    {};

    template<typename Expr, typename Char, typename Nbr>
    struct width_of_assign<Expr, Char, attribute_placeholder<Nbr> >
      : unknown_width
    {};

    // either (s1 = ...) or (a1 = ...) or (set = ...)
    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::assign>
      : width_of_assign<
            Expr
          , Char
          , typename proto::result_of::value<
                typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr
            >::type
        >
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, modifier_tag>
      : width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, lookahead_tag>
      : mpl::size_t<0>
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, lookbehind_tag>
      : mpl::size_t<0>
    {};

    // keep() is used to turn off backtracking, so they should only be used
    // for things that are variable-width (eg. quantified)
    template<typename Expr, typename Char>
    struct width_of<Expr, Char, keeper_tag>
      : unknown_width
    {
        // TODO: keep() now has a second meaning: execute actions immediately.
        // In that sense, it is perfectly reasonable to put a fixed-width
        // sub-expression in a keep. Can fixed-width keep() sub-expressions
        // use the simple_repeat_matcher?
    };

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::unary_plus>
      : unknown_width
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::dereference>
      : unknown_width
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::logical_not>
      : unknown_width
    {};

    template<typename Expr, typename Char, uint_t Min, uint_t Max>
    struct width_of<Expr, Char, generic_quant_tag<Min, Max> >
      : unknown_width
    {};

    template<typename Expr, typename Char, uint_t Count>
    struct width_of<Expr, Char, generic_quant_tag<Count, Count> >
      : mpl::if_c<
            mpl::equal_to<unknown_width, width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char> >::value
          , unknown_width
          , mpl::times<
                width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char>
              , mpl::size_t<Count>
            >
        >::type
    {};

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::negate>
      : width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char>
    {};

    // when complementing a set or an assertion, the width is that of the set (1) or the assertion (0)
    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::complement>
      : width_of<typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr, Char>
    {};

    // The comma is used in list-initialized sets, and the width of sets are 1
    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::comma>
      : mpl::size_t<1>
    {};

    // The subscript operator[] is used for sets, as in set['a' | range('b','h')],
    // or for actions as in (any >> expr)[ action ]
    template<typename Expr, typename Char, typename Left>
    struct width_of_subscript
      : width_of<Left, Char>
    {};

    template<typename Expr, typename Char>
    struct width_of_subscript<Expr, Char, set_initializer_type>
      : mpl::size_t<1>
    {
        // If Left is "set" then make sure that Right has a width_of 1
        BOOST_MPL_ASSERT_RELATION(
            1
          , ==
          , (width_of<typename remove_reference<typename Expr::proto_child1>::type::proto_base_expr, Char>::value));
    };

    template<typename Expr, typename Char>
    struct width_of<Expr, Char, proto::tag::subscript>
      : width_of_subscript<Expr, Char, typename remove_reference<typename Expr::proto_child0>::type::proto_base_expr>
    {};

}}} // namespace boost::xpressive::detail

#undef UNREF

#endif