]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
20effc67 TL |
13 | #if !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119) |
14 | #define BOOST_CPP_MACROMAP_UTIL_HPP_HK041119 | |
7c673cae FG |
15 | |
16 | #include <boost/assert.hpp> | |
17 | ||
18 | #include <boost/wave/wave_config.hpp> | |
19 | #include <boost/wave/token_ids.hpp> | |
b32b8144 | 20 | #include <boost/wave/util/unput_queue_iterator.hpp> |
20effc67 | 21 | #include <boost/wave/language_support.hpp> |
7c673cae FG |
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 | // | |
b32b8144 | 30 | // This file contains the definition of several token sequence analyze |
7c673cae FG |
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 | // | |
b32b8144 | 45 | // On destruction pop the first element of the list given as the argument |
7c673cae FG |
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 | // | |
b32b8144 FG |
60 | // Append a given list to the list given as argument |
61 | // On destruction pop the first element of the list given as argument | |
7c673cae FG |
62 | // |
63 | /////////////////////////////////////////////////////////////////////////// | |
64 | template <typename ContainerT> | |
65 | class splice_pop_front { | |
66 | public: | |
b32b8144 FG |
67 | splice_pop_front(ContainerT &list_, ContainerT &queue) |
68 | : list(list_) | |
7c673cae FG |
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: | |
b32b8144 | 107 | assign(IteratorT &it_, UnputIteratorT const &uit_) |
7c673cae FG |
108 | : it(it_), uit(uit_) {} |
109 | ~assign() { it = uit.base(); } | |
110 | ||
111 | private: | |
112 | IteratorT ⁢ | |
113 | UnputIteratorT const &uit; | |
114 | }; | |
115 | ||
116 | template <typename IteratorT> | |
117 | class assign<IteratorT, IteratorT> { | |
118 | public: | |
b32b8144 | 119 | assign(IteratorT &it_, IteratorT const &uit_) |
7c673cae FG |
120 | : it(it_), uit(uit_) {} |
121 | ~assign() { it = uit; } | |
122 | ||
123 | private: | |
124 | IteratorT ⁢ | |
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 | /////////////////////////////////////////////////////////////////////////////// | |
20effc67 | 139 | template <typename ContextT, typename StringT> |
b32b8144 | 140 | inline bool |
20effc67 | 141 | is_special_macroname (ContextT const & ctx, StringT const &name) |
7c673cae FG |
142 | { |
143 | if (name.size() < 7) | |
144 | return false; | |
145 | ||
146 | if ("defined" == name) | |
147 | return true; | |
148 | ||
20effc67 TL |
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 | ||
7c673cae | 155 | if ('_' == name[0] && '_' == name[1]) { |
20effc67 | 156 | StringT str = name.substr(2); |
7c673cae | 157 | |
b32b8144 | 158 | if (str == "cplusplus" || str == "STDC__" || |
7c673cae FG |
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> | |
b32b8144 | 176 | inline bool |
7c673cae FG |
177 | token_equals(TokenT const &left, TokenT const &right) |
178 | { | |
179 | using namespace boost::wave; | |
180 | ||
181 | if (IS_CATEGORY(left, ParameterTokenType)) { | |
20effc67 TL |
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); | |
7c673cae | 185 | |
b32b8144 | 186 | return (T_IDENTIFIER == id || |
7c673cae FG |
187 | IS_CATEGORY(id, KeywordTokenType) || |
188 | IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) || | |
b32b8144 | 189 | IS_CATEGORY(id, BoolLiteralTokenType)) && |
7c673cae FG |
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> | |
b32b8144 FG |
206 | inline bool |
207 | definition_equals(ContainerT const &definition, | |
7c673cae FG |
208 | ContainerT const &new_definition) |
209 | { | |
210 | typedef typename ContainerT::const_iterator const_iterator_type; | |
211 | ||
20effc67 TL |
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(); | |
7c673cae | 216 | |
b32b8144 | 217 | while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2)) |
7c673cae | 218 | { |
20effc67 TL |
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); | |
7c673cae | 222 | |
b32b8144 FG |
223 | if (IS_CATEGORY(id1, WhiteSpaceTokenType) && |
224 | IS_CATEGORY(id2, WhiteSpaceTokenType)) | |
7c673cae | 225 | { |
20effc67 TL |
226 | // all consecutive whitespace tokens count as one whitespace |
227 | // adjust first1 and first2 accordingly | |
7c673cae FG |
228 | skip_whitespace(first1, last1); |
229 | skip_whitespace(first2, last2); | |
230 | } | |
b32b8144 FG |
231 | else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) && |
232 | !IS_CATEGORY(id2, WhiteSpaceTokenType)) | |
7c673cae FG |
233 | { |
234 | ++first1; | |
235 | ++first2; | |
236 | } | |
237 | else { | |
20effc67 | 238 | // the sequences differ |
7c673cae FG |
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> | |
b32b8144 | 251 | inline bool |
7c673cae FG |
252 | parameters_equal(ContainerT const ¶meters, 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 | ||
20effc67 TL |
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(); | |
7c673cae FG |
263 | |
264 | while (first1 != last1 && first2 != last2) { | |
20effc67 | 265 | // parameters are different, if the corresponding tokens are different |
7c673cae FG |
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 | ||
20effc67 | 289 | // strip leading whitespace |
7c673cae | 290 | if (replacement_list.size() > 0) { |
20effc67 TL |
291 | typename ContainerT::iterator end = replacement_list.end(); |
292 | typename ContainerT::iterator it = replacement_list.begin(); | |
7c673cae | 293 | |
b32b8144 | 294 | while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { |
7c673cae FG |
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 | ||
20effc67 | 308 | // strip trailing whitespace |
7c673cae | 309 | if (replacement_list.size() > 0) { |
20effc67 TL |
310 | typename ContainerT::reverse_iterator rend = replacement_list.rend(); |
311 | typename ContainerT::reverse_iterator rit = replacement_list.rbegin(); | |
7c673cae | 312 | |
b32b8144 | 313 | while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType)) |
7c673cae FG |
314 | ++rit; |
315 | ||
20effc67 TL |
316 | typename ContainerT::iterator end = replacement_list.end(); |
317 | typename ContainerT::iterator it = rit.base(); | |
7c673cae | 318 | |
b32b8144 | 319 | while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) { |
7c673cae FG |
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 | ||
20effc67 TL |
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 | ||
7c673cae FG |
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 | ||
20effc67 | 385 | // strip leading whitespace |
7c673cae | 386 | if (replacement_list.size() > 0) { |
20effc67 TL |
387 | typename ContainerT::iterator end = replacement_list.end(); |
388 | typename ContainerT::iterator it = replacement_list.begin(); | |
7c673cae FG |
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 | ||
20effc67 | 403 | // remove all 'new' leading and trailing whitespace |
7c673cae FG |
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 | ||
20effc67 | 420 | // strip leading whitespace (should be only one token) |
7c673cae FG |
421 | if (argument.size() > 0 && |
422 | IS_CATEGORY(argument.front(), WhiteSpaceTokenType)) | |
423 | { | |
424 | argument.pop_front(); | |
425 | } | |
426 | } | |
b32b8144 | 427 | |
7c673cae FG |
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 | ||
20effc67 | 439 | // strip trailing whitespace (should be only one token) |
7c673cae FG |
440 | if (argument.size() > 0 && |
441 | IS_CATEGORY(argument.back(), WhiteSpaceTokenType)) | |
442 | { | |
443 | argument.pop_back(); | |
444 | } | |
445 | } | |
446 | ||
447 | /////////////////////////////////////////////////////////////////////////////// | |
448 | // | |
b32b8144 | 449 | // Remove all whitespace tokens on the left and right sides of the given token |
7c673cae FG |
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> | |
b32b8144 | 464 | void call_skipped_token_hook(ContextT& ctx, |
7c673cae FG |
465 | typename ContextT::token_type const& skipped) |
466 | { | |
467 | #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 | |
b32b8144 | 468 | ctx.get_hooks().skipped_token(skipped); |
7c673cae FG |
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> | |
b32b8144 FG |
480 | inline bool |
481 | skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end, | |
7c673cae FG |
482 | token_id id, bool& seen_newline) |
483 | { | |
484 | using namespace boost::wave; | |
b32b8144 | 485 | if (token_id(*it) == id) |
7c673cae FG |
486 | return true; |
487 | ||
488 | // call_skipped_token_hook(ctx, *it); | |
b32b8144 | 489 | if (++it == end) |
7c673cae FG |
490 | return false; |
491 | ||
b32b8144 FG |
492 | while (IS_CATEGORY(*it, WhiteSpaceTokenType) || |
493 | T_NEWLINE == token_id(*it)) | |
7c673cae FG |
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 | // | |
b32b8144 | 507 | // Get the full name of a given macro name (concatenate the string |
7c673cae FG |
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; | |
b32b8144 | 516 | for (IteratorT err_it = begin; err_it != end; ++err_it) |
7c673cae FG |
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 | /////////////////////////////////////////////////////////////////////////////// | |
b32b8144 | 547 | // Convert a string of an arbitrary string compatible type to a internal |
7c673cae FG |
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 | ||
20effc67 | 603 | #endif // !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119) |