1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3     Copyright (c) 2013 Carl Barron
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 #if !defined(BOOST_SPIRIT_X3_SYMBOLS_MARCH_11_2007_1055AM)
9 #define BOOST_SPIRIT_X3_SYMBOLS_MARCH_11_2007_1055AM
10 
11 #include <boost/spirit/home/x3/core/skip_over.hpp>
12 #include <boost/spirit/home/x3/core/parser.hpp>
13 #include <boost/spirit/home/x3/string/tst.hpp>
14 #include <boost/spirit/home/x3/support/unused.hpp>
15 #include <boost/spirit/home/x3/support/traits/string_traits.hpp>
16 #include <boost/spirit/home/x3/support/traits/move_to.hpp>
17 #include <boost/spirit/home/x3/support/no_case.hpp>
18 
19 #include <boost/spirit/home/support/char_encoding/ascii.hpp>
20 #include <boost/spirit/home/support/char_encoding/iso8859_1.hpp>
21 #include <boost/spirit/home/support/char_encoding/standard.hpp>
22 #include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
23 
24 #include <initializer_list>
25 #include <iterator> // std::begin
26 #include <memory> // std::shared_ptr
27 #include <type_traits>
28 
29 #if defined(BOOST_MSVC)
30 # pragma warning(push)
31 # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
32 #endif
33 
34 namespace boost { namespace spirit { namespace x3
35 {
36     template <
37         typename Encoding
38       , typename T = unused_type
39       , typename Lookup = tst<typename Encoding::char_type, T> >
40     struct symbols_parser : parser<symbols_parser<Encoding, T, Lookup>>
41     {
42         typedef typename Encoding::char_type char_type; // the character type
43         typedef Encoding encoding;
44         typedef T value_type; // the value associated with each entry
45         typedef value_type attribute_type;
46 
47         static bool const has_attribute =
48             !std::is_same<unused_type, attribute_type>::value;
49         static bool const handles_container =
50             traits::is_container<attribute_type>::value;
51 
symbols_parserboost::spirit::x3::symbols_parser52         symbols_parser(std::string const& name = "symbols")
53           : add{*this}
54           , remove{*this}
55           , lookup(std::make_shared<Lookup>())
56           , name_(name)
57         {
58         }
59 
symbols_parserboost::spirit::x3::symbols_parser60         symbols_parser(symbols_parser const& syms)
61           : add{*this}
62           , remove{*this}
63           , lookup(syms.lookup)
64           , name_(syms.name_)
65         {
66         }
67 
68         template <typename Symbols>
symbols_parserboost::spirit::x3::symbols_parser69         symbols_parser(Symbols const& syms, std::string const& name = "symbols")
70           : symbols_parser(name)
71         {
72             for (auto& sym : syms)
73                 add(sym);
74         }
75 
76         template <typename Symbols, typename Data>
symbols_parserboost::spirit::x3::symbols_parser77         symbols_parser(Symbols const& syms, Data const& data
78               , std::string const& name = "symbols")
79           : symbols_parser(name)
80         {
81             using std::begin;
82             auto di = begin(data);
83             for (auto& sym : syms)
84                 add(sym, *di++);
85         }
86 
symbols_parserboost::spirit::x3::symbols_parser87         symbols_parser(std::initializer_list<std::pair<char_type const*, T>> syms
88               , std::string const & name="symbols")
89           : symbols_parser(name)
90         {
91             for (auto& sym : syms)
92                 add(sym.first, sym.second);
93         }
94 
symbols_parserboost::spirit::x3::symbols_parser95         symbols_parser(std::initializer_list<char_type const*> syms
96               , std::string const &name="symbols")
97           : symbols_parser(name)
98         {
99             for (auto str : syms)
100                 add(str);
101         }
102 
103         symbols_parser&
operator =boost::spirit::x3::symbols_parser104         operator=(symbols_parser const& rhs)
105         {
106             name_ = rhs.name_;
107             lookup = rhs.lookup;
108             return *this;
109         }
110 
clearboost::spirit::x3::symbols_parser111         void clear()
112         {
113             lookup->clear();
114         }
115 
116         struct adder;
117         struct remover;
118 
119         template <typename Str>
120         adder const&
operator =boost::spirit::x3::symbols_parser121         operator=(Str const& str)
122         {
123             lookup->clear();
124             return add(str);
125         }
126 
127         template <typename Str>
128         friend adder const&
operator +=(symbols_parser & sym,Str const & str)129         operator+=(symbols_parser& sym, Str const& str)
130         {
131             return sym.add(str);
132         }
133 
134         template <typename Str>
135         friend remover const&
operator -=(symbols_parser & sym,Str const & str)136         operator-=(symbols_parser& sym, Str const& str)
137         {
138             return sym.remove(str);
139         }
140 
141         template <typename F>
for_eachboost::spirit::x3::symbols_parser142         void for_each(F f) const
143         {
144             lookup->for_each(f);
145         }
146 
147         template <typename Str>
atboost::spirit::x3::symbols_parser148         value_type& at(Str const& str)
149         {
150             return *lookup->add(traits::get_string_begin<char_type>(str)
151                 , traits::get_string_end<char_type>(str), T());
152         }
153 
154         template <typename Iterator>
prefix_findboost::spirit::x3::symbols_parser155         value_type* prefix_find(Iterator& first, Iterator const& last)
156         {
157             return lookup->find(first, last, case_compare<Encoding>());
158         }
159 
160         template <typename Iterator>
prefix_findboost::spirit::x3::symbols_parser161         value_type const* prefix_find(Iterator& first, Iterator const& last) const
162         {
163             return lookup->find(first, last, case_compare<Encoding>());
164         }
165 
166         template <typename Str>
findboost::spirit::x3::symbols_parser167         value_type* find(Str const& str)
168         {
169             return find_impl(traits::get_string_begin<char_type>(str)
170                 , traits::get_string_end<char_type>(str));
171         }
172 
173         template <typename Str>
findboost::spirit::x3::symbols_parser174         value_type const* find(Str const& str) const
175         {
176             return find_impl(traits::get_string_begin<char_type>(str)
177                 , traits::get_string_end<char_type>(str));
178         }
179 
180     private:
181 
182         template <typename Iterator>
find_implboost::spirit::x3::symbols_parser183         value_type* find_impl(Iterator begin, Iterator end)
184         {
185             value_type* r = lookup->find(begin, end, case_compare<Encoding>());
186             return begin == end ? r : 0;
187         }
188 
189         template <typename Iterator>
find_implboost::spirit::x3::symbols_parser190         value_type const* find_impl(Iterator begin, Iterator end) const
191         {
192             value_type const* r = lookup->find(begin, end, case_compare<Encoding>());
193             return begin == end ? r : 0;
194         }
195 
196     public:
197 
198         template <typename Iterator, typename Context, typename Attribute>
parseboost::spirit::x3::symbols_parser199         bool parse(Iterator& first, Iterator const& last
200           , Context const& context, unused_type, Attribute& attr) const
201         {
202             x3::skip_over(first, last, context);
203 
204             if (value_type const* val_ptr
205                 = lookup->find(first, last, get_case_compare<Encoding>(context)))
206             {
207                 x3::traits::move_to(*val_ptr, attr);
208                 return true;
209             }
210             return false;
211         }
212 
nameboost::spirit::x3::symbols_parser213         void name(std::string const &str)
214         {
215             name_ = str;
216         }
nameboost::spirit::x3::symbols_parser217         std::string const &name() const
218         {
219             return name_;
220         }
221 
222         struct adder
223         {
224             template <typename Iterator>
225             adder const&
operator ()boost::spirit::x3::symbols_parser::adder226             operator()(Iterator first, Iterator last, T const& val) const
227             {
228                 sym.lookup->add(first, last, val);
229                 return *this;
230             }
231 
232             template <typename Str>
233             adder const&
operator ()boost::spirit::x3::symbols_parser::adder234             operator()(Str const& s, T const& val = T()) const
235             {
236                 sym.lookup->add(traits::get_string_begin<char_type>(s)
237                   , traits::get_string_end<char_type>(s), val);
238                 return *this;
239             }
240 
241             template <typename Str>
242             adder const&
operator ,boost::spirit::x3::symbols_parser::adder243             operator,(Str const& s) const
244             {
245                 sym.lookup->add(traits::get_string_begin<char_type>(s)
246                   , traits::get_string_end<char_type>(s), T());
247                 return *this;
248             }
249 
250             symbols_parser& sym;
251         };
252 
253         struct remover
254         {
255             template <typename Iterator>
256             remover const&
operator ()boost::spirit::x3::symbols_parser::remover257             operator()(Iterator const& first, Iterator const& last) const
258             {
259                 sym.lookup->remove(first, last);
260                 return *this;
261             }
262 
263             template <typename Str>
264             remover const&
operator ()boost::spirit::x3::symbols_parser::remover265             operator()(Str const& s) const
266             {
267                 sym.lookup->remove(traits::get_string_begin<char_type>(s)
268                   , traits::get_string_end<char_type>(s));
269                 return *this;
270             }
271 
272             template <typename Str>
273             remover const&
operator ,boost::spirit::x3::symbols_parser::remover274             operator,(Str const& s) const
275             {
276                 sym.lookup->remove(traits::get_string_begin<char_type>(s)
277                   , traits::get_string_end<char_type>(s));
278                 return *this;
279             }
280 
281             symbols_parser& sym;
282         };
283 
284         adder add;
285         remover remove;
286         std::shared_ptr<Lookup> lookup;
287         std::string name_;
288     };
289 
290     template <typename Encoding, typename T, typename Lookup>
291     struct get_info<symbols_parser<Encoding, T, Lookup>>
292     {
293       typedef std::string result_type;
operator ()boost::spirit::x3::get_info294       result_type operator()(symbols_parser< Encoding, T
295                                     , Lookup
296                                     > const& symbols) const
297       {
298          return symbols.name();
299       }
300     };
301 
302     namespace standard
303     {
304         template <typename T = unused_type>
305         using symbols = symbols_parser<char_encoding::standard, T>;
306     }
307 
308     using standard::symbols;
309 
310 #ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
311     namespace standard_wide
312     {
313         template <typename T = unused_type>
314         using symbols = symbols_parser<char_encoding::standard_wide, T>;
315     }
316 #endif
317 
318     namespace ascii
319     {
320         template <typename T = unused_type>
321         using symbols = symbols_parser<char_encoding::ascii, T>;
322     }
323 
324     namespace iso8859_1
325     {
326         template <typename T = unused_type>
327         using symbols = symbols_parser<char_encoding::iso8859_1, T>;
328     }
329 
330 }}}
331 
332 #if defined(BOOST_MSVC)
333 # pragma warning(pop)
334 #endif
335 
336 #endif
337