]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/wave/util/cpp_macromap_utils.hpp
efdf6801636954a96766ec68c015cec9989e399d
[ceph.git] / ceph / src / boost / boost / wave / util / cpp_macromap_utils.hpp
1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3
4 Token sequence analysis and transformation helper functions
5
6 http://www.boost.org/
7
8 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
9 Software License, Version 1.0. (See accompanying file
10 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 =============================================================================*/
12
13 #if !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)
14 #define BOOST_CPP_MACROMAP_UTIL_HPP_HK041119
15
16 #include <boost/assert.hpp>
17
18 #include <boost/wave/wave_config.hpp>
19 #include <boost/wave/token_ids.hpp>
20 #include <boost/wave/util/unput_queue_iterator.hpp>
21 #include <boost/wave/language_support.hpp>
22
23 // this must occur after all of the includes and before any code appears
24 #ifdef BOOST_HAS_ABI_HEADERS
25 #include BOOST_ABI_PREFIX
26 #endif
27
28 ///////////////////////////////////////////////////////////////////////////////
29 //
30 // This file contains the definition of several token sequence analyze
31 // and transformation utility functions needed during macro handling.
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34
35 ///////////////////////////////////////////////////////////////////////////////
36 namespace boost {
37 namespace wave {
38 namespace util {
39
40 ///////////////////////////////////////////////////////////////////////////////
41 namespace on_exit {
42
43 ///////////////////////////////////////////////////////////////////////////
44 //
45 // On destruction pop the first element of the list given as the argument
46 //
47 ///////////////////////////////////////////////////////////////////////////
48 template <typename ContainerT>
49 class pop_front {
50 public:
51 pop_front(ContainerT &list_) : list(list_) {}
52 ~pop_front() { list.pop_front(); }
53
54 private:
55 ContainerT &list;
56 };
57
58 ///////////////////////////////////////////////////////////////////////////
59 //
60 // Append a given list to the list given as argument
61 // On destruction pop the first element of the list given as argument
62 //
63 ///////////////////////////////////////////////////////////////////////////
64 template <typename ContainerT>
65 class splice_pop_front {
66 public:
67 splice_pop_front(ContainerT &list_, ContainerT &queue)
68 : list(list_)
69 {
70 list.splice(list.end(), queue);
71 }
72 ~splice_pop_front() { list.pop_front(); }
73
74 private:
75 ContainerT &list;
76 };
77
78 ///////////////////////////////////////////////////////////////////////////
79 //
80 // On destruction reset a referenced value to its initial state
81 //
82 ///////////////////////////////////////////////////////////////////////////
83 template <typename TypeT>
84 class reset {
85 public:
86 reset(TypeT &target_value_, TypeT new_value)
87 : target_value(target_value_), old_value(target_value_)
88 {
89 target_value_ = new_value;
90 }
91 ~reset() { target_value = old_value; }
92
93 private:
94 TypeT &target_value;
95 TypeT old_value;
96 };
97
98 ///////////////////////////////////////////////////////////////////////////
99 //
100 // On destruction assign the given iterator back
101 //
102 ///////////////////////////////////////////////////////////////////////////
103 template <typename IteratorT, typename UnputIteratorT>
104 class assign
105 {
106 public:
107 assign(IteratorT &it_, UnputIteratorT const &uit_)
108 : it(it_), uit(uit_) {}
109 ~assign() { it = uit.base(); }
110
111 private:
112 IteratorT &it;
113 UnputIteratorT const &uit;
114 };
115
116 template <typename IteratorT>
117 class assign<IteratorT, IteratorT> {
118 public:
119 assign(IteratorT &it_, IteratorT const &uit_)
120 : it(it_), uit(uit_) {}
121 ~assign() { it = uit; }
122
123 private:
124 IteratorT &it;
125 IteratorT const &uit;
126 };
127
128 ///////////////////////////////////////////////////////////////////////////////
129 } // namespace on_exit
130
131 ///////////////////////////////////////////////////////////////////////////////
132 namespace impl {
133
134 ///////////////////////////////////////////////////////////////////////////////
135 //
136 // Test, whether a given identifier resolves to a predefined name
137 //
138 ///////////////////////////////////////////////////////////////////////////////
139 template <typename ContextT, typename StringT>
140 inline bool
141 is_special_macroname (ContextT const & ctx, StringT const &name)
142 {
143 if (name.size() < 7)
144 return false;
145
146 if ("defined" == name)
147 return true;
148
149 #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
150 if (boost::wave::need_has_include(ctx.get_language()) &&
151 ("__has_include" == name))
152 return true;
153 #endif
154
155 if ('_' == name[0] && '_' == name[1]) {
156 StringT str = name.substr(2);
157
158 if (str == "cplusplus" || str == "STDC__" ||
159 str == "TIME__" || str == "DATE__" ||
160 str == "LINE__" || str == "FILE__" ||
161 str == "INCLUDE_LEVEL__")
162 {
163 return true;
164 }
165 }
166 return false;
167 }
168
169 ///////////////////////////////////////////////////////////////////////////////
170 //
171 // Test, whether two tokens are to be considered equal (different sequences
172 // of whitespace are considered to be equal)
173 //
174 ///////////////////////////////////////////////////////////////////////////////
175 template <typename TokenT>
176 inline bool
177 token_equals(TokenT const &left, TokenT const &right)
178 {
179 using namespace boost::wave;
180
181 if (IS_CATEGORY(left, ParameterTokenType)) {
182 // if the existing token is of type T_PARAMETERBASE, then the right token
183 // must be of type T_IDENTIFIER or a keyword
184 token_id id = token_id(right);
185
186 return (T_IDENTIFIER == id ||
187 IS_CATEGORY(id, KeywordTokenType) ||
188 IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
189 IS_CATEGORY(id, BoolLiteralTokenType)) &&
190 left.get_value() == right.get_value();
191 }
192
193 // if the left token has whitespace, the value is irrelevant
194 return token_id(left) == token_id(right) && (
195 IS_CATEGORY(left, WhiteSpaceTokenType) ||
196 left.get_value() == right.get_value()
197 );
198 }
199
200 ///////////////////////////////////////////////////////////////////////////////
201 //
202 // Tests, whether two macro definitions are equal
203 //
204 ///////////////////////////////////////////////////////////////////////////////
205 template <typename ContainerT>
206 inline bool
207 definition_equals(ContainerT const &definition,
208 ContainerT const &new_definition)
209 {
210 typedef typename ContainerT::const_iterator const_iterator_type;
211
212 const_iterator_type first1 = definition.begin();
213 const_iterator_type last1 = definition.end();
214 const_iterator_type first2 = new_definition.begin();
215 const_iterator_type last2 = new_definition.end();
216
217 while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2))
218 {
219 // skip whitespace, if both sequences have a whitespace next
220 token_id id1 = next_token<const_iterator_type>::peek(first1, last1, false);
221 token_id id2 = next_token<const_iterator_type>::peek(first2, last2, false);
222
223 if (IS_CATEGORY(id1, WhiteSpaceTokenType) &&
224 IS_CATEGORY(id2, WhiteSpaceTokenType))
225 {
226 // all consecutive whitespace tokens count as one whitespace
227 // adjust first1 and first2 accordingly
228 skip_whitespace(first1, last1);
229 skip_whitespace(first2, last2);
230 }
231 else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) &&
232 !IS_CATEGORY(id2, WhiteSpaceTokenType))
233 {
234 ++first1;
235 ++first2;
236 }
237 else {
238 // the sequences differ
239 break;
240 }
241 }
242 return (first1 == last1 && first2 == last2) ? true : false;
243 }
244
245 ///////////////////////////////////////////////////////////////////////////////
246 //
247 // Tests, whether two given sets of macro parameters are equal
248 //
249 ///////////////////////////////////////////////////////////////////////////////
250 template <typename ContainerT>
251 inline bool
252 parameters_equal(ContainerT const &parameters, ContainerT const &new_parameters)
253 {
254 if (parameters.size() != new_parameters.size())
255 return false; // different parameter count
256
257 typedef typename ContainerT::const_iterator const_iterator_type;
258
259 const_iterator_type first1 = parameters.begin();
260 const_iterator_type last1 = parameters.end();
261 const_iterator_type first2 = new_parameters.begin();
262 const_iterator_type last2 = new_parameters.end();
263
264 while (first1 != last1 && first2 != last2) {
265 // parameters are different, if the corresponding tokens are different
266 using namespace boost::wave;
267 if (token_id(*first1) != token_id(*first2) ||
268 (*first1).get_value() != (*first2).get_value())
269 {
270 break;
271 }
272 ++first1;
273 ++first2;
274 }
275 return (first1 == last1 && first2 == last2) ? true : false;
276 }
277
278 ///////////////////////////////////////////////////////////////////////////////
279 //
280 // Strip leading and trailing whitespace from the given token sequence
281 //
282 ///////////////////////////////////////////////////////////////////////////////
283 template <typename ContainerT>
284 inline void
285 trim_replacement_list (ContainerT &replacement_list)
286 {
287 using namespace boost::wave;
288
289 // strip leading whitespace
290 if (replacement_list.size() > 0) {
291 typename ContainerT::iterator end = replacement_list.end();
292 typename ContainerT::iterator it = replacement_list.begin();
293
294 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
295 token_id id(*it);
296 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
297 typename ContainerT::iterator next = it;
298 ++next;
299 replacement_list.erase(it);
300 it = next;
301 }
302 else {
303 ++it;
304 }
305 }
306 }
307
308 // strip trailing whitespace
309 if (replacement_list.size() > 0) {
310 typename ContainerT::reverse_iterator rend = replacement_list.rend();
311 typename ContainerT::reverse_iterator rit = replacement_list.rbegin();
312
313 while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType))
314 ++rit;
315
316 typename ContainerT::iterator end = replacement_list.end();
317 typename ContainerT::iterator it = rit.base();
318
319 while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
320 token_id id(*it);
321 if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
322 typename ContainerT::iterator next = it;
323 ++next;
324 replacement_list.erase(it);
325 it = next;
326 }
327 else {
328 ++it;
329 }
330 }
331 }
332 }
333
334 ///////////////////////////////////////////////////////////////////////////////
335 //
336 // Tests, whether the given token sequence consists out of whitespace only
337 //
338 ///////////////////////////////////////////////////////////////////////////////
339 template <typename ContainerT>
340 inline bool
341 is_whitespace_only (ContainerT const &argument)
342 {
343 typename ContainerT::const_iterator end = argument.end();
344 for (typename ContainerT::const_iterator it = argument.begin();
345 it != end; ++it)
346 {
347 if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
348 return false;
349 }
350 return true;
351 }
352
353 ///////////////////////////////////////////////////////////////////////////////
354 //
355 // Tests whether the given token sequence consists only of whitespace
356 // and placemarkers
357 //
358 ///////////////////////////////////////////////////////////////////////////////
359 template <typename ContainerT>
360 inline bool
361 is_blank_only (ContainerT const &argument)
362 {
363 typename ContainerT::const_iterator end = argument.end();
364 for (typename ContainerT::const_iterator it = argument.begin();
365 it != end; ++it)
366 {
367 if (!IS_CATEGORY(*it, WhiteSpaceTokenType) &&
368 (T_PLACEMARKER != token_id(*it)))
369 return false;
370 }
371 return true;
372 }
373
374 ///////////////////////////////////////////////////////////////////////////////
375 //
376 // Remove all placeholder tokens from the given token sequence
377 //
378 ///////////////////////////////////////////////////////////////////////////////
379 template <typename ContainerT>
380 inline void
381 remove_placeholders (ContainerT &replacement_list)
382 {
383 using namespace boost::wave;
384
385 // strip leading whitespace
386 if (replacement_list.size() > 0) {
387 typename ContainerT::iterator end = replacement_list.end();
388 typename ContainerT::iterator it = replacement_list.begin();
389
390 while (it != end) {
391 token_id id(*it);
392 if (T_PLACEHOLDER == id || T_PLACEMARKER == id) {
393 typename ContainerT::iterator next = it;
394 ++next;
395 replacement_list.erase(it);
396 it = next;
397 }
398 else {
399 ++it;
400 }
401 }
402
403 // remove all 'new' leading and trailing whitespace
404 if (is_whitespace_only(replacement_list))
405 trim_replacement_list(replacement_list);
406 }
407 }
408
409 ///////////////////////////////////////////////////////////////////////////////
410 //
411 // Remove all whitespace tokens on the left side of the given token sequence
412 //
413 ///////////////////////////////////////////////////////////////////////////////
414 template <typename ContainerT>
415 inline void
416 trim_sequence_left (ContainerT &argument)
417 {
418 using namespace boost::wave;
419
420 // strip leading whitespace (should be only one token)
421 if (argument.size() > 0 &&
422 IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
423 {
424 argument.pop_front();
425 }
426 }
427
428 ///////////////////////////////////////////////////////////////////////////////
429 //
430 // Remove all whitespace tokens on the right side of the given token sequence
431 //
432 ///////////////////////////////////////////////////////////////////////////////
433 template <typename ContainerT>
434 inline void
435 trim_sequence_right (ContainerT &argument)
436 {
437 using namespace boost::wave;
438
439 // strip trailing whitespace (should be only one token)
440 if (argument.size() > 0 &&
441 IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
442 {
443 argument.pop_back();
444 }
445 }
446
447 ///////////////////////////////////////////////////////////////////////////////
448 //
449 // Remove all whitespace tokens on the left and right sides of the given token
450 // sequence
451 //
452 ///////////////////////////////////////////////////////////////////////////////
453 template <typename ContainerT>
454 inline void
455 trim_sequence (ContainerT &argument)
456 {
457 trim_sequence_left(argument);
458 trim_sequence_right(argument);
459 }
460
461 ///////////////////////////////////////////////////////////////////////////////
462 // call 'skipped_token' preprocessing hook
463 template <typename ContextT>
464 void call_skipped_token_hook(ContextT& ctx,
465 typename ContextT::token_type const& skipped)
466 {
467 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
468 ctx.get_hooks().skipped_token(skipped);
469 #else
470 ctx.get_hooks().skipped_token(ctx.derived(), skipped);
471 #endif
472 }
473
474 ///////////////////////////////////////////////////////////////////////////////
475 //
476 // Skip forward to a given token
477 //
478 ///////////////////////////////////////////////////////////////////////////////
479 template <typename ContextT, typename IteratorT>
480 inline bool
481 skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end,
482 token_id id, bool& seen_newline)
483 {
484 using namespace boost::wave;
485 if (token_id(*it) == id)
486 return true;
487
488 // call_skipped_token_hook(ctx, *it);
489 if (++it == end)
490 return false;
491
492 while (IS_CATEGORY(*it, WhiteSpaceTokenType) ||
493 T_NEWLINE == token_id(*it))
494 {
495 if (T_NEWLINE == token_id(*it))
496 seen_newline = true;
497
498 // call_skipped_token_hook(ctx, *it);
499 if (++it == end)
500 return false;
501 }
502 return token_id(*it) == id;
503 }
504
505 ///////////////////////////////////////////////////////////////////////////////
506 //
507 // Get the full name of a given macro name (concatenate the string
508 // representations of the single tokens).
509 //
510 ///////////////////////////////////////////////////////////////////////////////
511 template <typename IteratorT>
512 inline std::string
513 get_full_name(IteratorT const &begin, IteratorT const &end)
514 {
515 std::string full_name;
516 for (IteratorT err_it = begin; err_it != end; ++err_it)
517 full_name += (*err_it).get_value().c_str();
518
519 return full_name;
520 }
521
522 ///////////////////////////////////////////////////////////////////////////////
523 //
524 // The following predicate is used in conjunction with the remove_copy_if
525 // algorithm to allow the detection of an eventually copied operator ##.
526 // No removal is performed in any case.
527 //
528 ///////////////////////////////////////////////////////////////////////////////
529 class find_concat_operator {
530 public:
531 find_concat_operator(bool &found_) : found_concat(found_) {}
532
533 template <typename TokenT>
534 bool operator()(TokenT const &tok)
535 {
536 using namespace boost::wave;
537 if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
538 found_concat = true;
539 return false;
540 }
541
542 private:
543 bool &found_concat;
544 };
545
546 ///////////////////////////////////////////////////////////////////////////////
547 // Convert a string of an arbitrary string compatible type to a internal
548 // string (BOOST_WAVE_STRING)
549 template <typename Target, typename Src>
550 struct to_string_helper
551 {
552 typedef Target type;
553
554 static Target call(Src const& str)
555 {
556 return Target(str.c_str());
557 }
558 };
559
560 // do nothing if types are equal
561 template <typename Src>
562 struct to_string_helper<Src, Src>
563 {
564 typedef Src const& type;
565
566 static Src const& call(Src const& str)
567 {
568 return str;
569 }
570 };
571
572 template <typename Target>
573 struct to_string_helper<Target, char const*>
574 {
575 typedef Target type;
576
577 static Target call(char const* str)
578 {
579 return Target(str);
580 }
581 };
582
583 ///////////////////////////////////////////////////////////////////////////////
584 } // namespace impl
585
586 template <typename Target, typename Src>
587 inline typename impl::to_string_helper<Target, Src>::type
588 to_string(Src const& src)
589 {
590 return impl::to_string_helper<Target, Src>::call(src);
591 }
592
593 ///////////////////////////////////////////////////////////////////////////////
594 } // namespace util
595 } // namespace wave
596 } // namespace boost
597
598 // the suffix header occurs after all of the code
599 #ifdef BOOST_HAS_ABI_HEADERS
600 #include BOOST_ABI_SUFFIX
601 #endif
602
603 #endif // !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)