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