]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/regex/v5/regex_format.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / regex / v5 / regex_format.hpp
1 /*
2 *
3 * Copyright (c) 1998-2009 John Maddock
4 * Copyright 2008 Eric Niebler.
5 *
6 * Use, modification and distribution are subject to the
7 * Boost Software License, Version 1.0. (See accompanying file
8 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 *
10 */
11
12 /*
13 * LOCATION: see http://www.boost.org for most recent version.
14 * FILE regex_format.hpp
15 * VERSION see <boost/version.hpp>
16 * DESCRIPTION: Provides formatting output routines for search and replace
17 * operations. Note this is an internal header file included
18 * by regex.hpp, do not include on its own.
19 */
20
21 #ifndef BOOST_REGEX_FORMAT_HPP
22 #define BOOST_REGEX_FORMAT_HPP
23
24 #include <type_traits>
25 #include <functional>
26
27 namespace boost{
28
29 //
30 // Forward declaration:
31 //
32 template <class BidiIterator, class Allocator = typename std::vector<sub_match<BidiIterator> >::allocator_type >
33 class match_results;
34
35 namespace BOOST_REGEX_DETAIL_NS{
36
37 //
38 // struct trivial_format_traits:
39 // defines minimum localisation support for formatting
40 // in the case that the actual regex traits is unavailable.
41 //
42 template <class charT>
43 struct trivial_format_traits
44 {
45 typedef charT char_type;
46
47 static std::ptrdiff_t length(const charT* p)
48 {
49 return global_length(p);
50 }
51 static charT tolower(charT c)
52 {
53 return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c);
54 }
55 static charT toupper(charT c)
56 {
57 return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c);
58 }
59 static int value(const charT c, int radix)
60 {
61 int result = global_value(c);
62 return result >= radix ? -1 : result;
63 }
64 int toi(const charT*& p1, const charT* p2, int radix)const
65 {
66 return (int)global_toi(p1, p2, radix, *this);
67 }
68 };
69
70 #ifdef BOOST_REGEX_MSVC
71 # pragma warning(push)
72 #pragma warning(disable:26812)
73 #endif
74 template <class OutputIterator, class Results, class traits, class ForwardIter>
75 class basic_regex_formatter
76 {
77 public:
78 typedef typename traits::char_type char_type;
79 basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
80 : m_traits(t), m_results(r), m_out(o), m_position(), m_end(), m_flags(), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {}
81 OutputIterator format(ForwardIter p1, ForwardIter p2, match_flag_type f);
82 OutputIterator format(ForwardIter p1, match_flag_type f)
83 {
84 return format(p1, p1 + m_traits.length(p1), f);
85 }
86 private:
87 typedef typename Results::value_type sub_match_type;
88 enum output_state
89 {
90 output_copy,
91 output_next_lower,
92 output_next_upper,
93 output_lower,
94 output_upper,
95 output_none
96 };
97
98 void put(char_type c);
99 void put(const sub_match_type& sub);
100 void format_all();
101 void format_perl();
102 void format_escape();
103 void format_conditional();
104 void format_until_scope_end();
105 bool handle_perl_verb(bool have_brace);
106
107 inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const std::integral_constant<bool, false>&)
108 {
109 std::vector<char_type> v(i, j);
110 return (i != j) ? this->m_results.named_subexpression(&v[0], &v[0] + v.size())
111 : this->m_results.named_subexpression(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
112 }
113 inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const std::integral_constant<bool, true>&)
114 {
115 return this->m_results.named_subexpression(i, j);
116 }
117 inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j)
118 {
119 typedef typename std::is_convertible<ForwardIter, const char_type*>::type tag_type;
120 return get_named_sub(i, j, tag_type());
121 }
122 inline int get_named_sub_index(ForwardIter i, ForwardIter j, const std::integral_constant<bool, false>&)
123 {
124 std::vector<char_type> v(i, j);
125 return (i != j) ? this->m_results.named_subexpression_index(&v[0], &v[0] + v.size())
126 : this->m_results.named_subexpression_index(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
127 }
128 inline int get_named_sub_index(ForwardIter i, ForwardIter j, const std::integral_constant<bool, true>&)
129 {
130 return this->m_results.named_subexpression_index(i, j);
131 }
132 inline int get_named_sub_index(ForwardIter i, ForwardIter j)
133 {
134 typedef typename std::is_convertible<ForwardIter, const char_type*>::type tag_type;
135 return get_named_sub_index(i, j, tag_type());
136 }
137 #ifdef BOOST_REGEX_MSVC
138 // msvc-8.0 issues a spurious warning on the call to std::advance here:
139 #pragma warning(push)
140 #pragma warning(disable:4244)
141 #endif
142 inline int toi(ForwardIter& i, ForwardIter j, int base, const std::integral_constant<bool, false>&)
143 {
144 if(i != j)
145 {
146 std::vector<char_type> v(i, j);
147 const char_type* start = &v[0];
148 const char_type* pos = start;
149 int r = (int)m_traits.toi(pos, &v[0] + v.size(), base);
150 std::advance(i, pos - start);
151 return r;
152 }
153 return -1;
154 }
155 #ifdef BOOST_REGEX_MSVC
156 #pragma warning(pop)
157 #endif
158 inline int toi(ForwardIter& i, ForwardIter j, int base, const std::integral_constant<bool, true>&)
159 {
160 return m_traits.toi(i, j, base);
161 }
162 inline int toi(ForwardIter& i, ForwardIter j, int base)
163 {
164 #if defined(_MSC_VER) && defined(__INTEL_COMPILER) && ((__INTEL_COMPILER == 9999) || (__INTEL_COMPILER == 1210))
165 // Workaround for Intel support issue #656654.
166 // See also https://svn.boost.org/trac/boost/ticket/6359
167 return toi(i, j, base, std::integral_constant<bool, false>());
168 #else
169 typedef typename std::is_convertible<ForwardIter, const char_type*&>::type tag_type;
170 return toi(i, j, base, tag_type());
171 #endif
172 }
173
174 const traits& m_traits; // the traits class for localised formatting operations
175 const Results& m_results; // the match_results being used.
176 OutputIterator m_out; // where to send output.
177 ForwardIter m_position; // format string, current position
178 ForwardIter m_end; // format string end
179 match_flag_type m_flags; // format flags to use
180 output_state m_state; // what to do with the next character
181 output_state m_restore_state; // what state to restore to.
182 bool m_have_conditional; // we are parsing a conditional
183 private:
184 basic_regex_formatter(const basic_regex_formatter&);
185 basic_regex_formatter& operator=(const basic_regex_formatter&);
186 };
187 #ifdef BOOST_REGEX_MSVC
188 # pragma warning(pop)
189 #endif
190
191 template <class OutputIterator, class Results, class traits, class ForwardIter>
192 OutputIterator basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format(ForwardIter p1, ForwardIter p2, match_flag_type f)
193 {
194 m_position = p1;
195 m_end = p2;
196 m_flags = f;
197 format_all();
198 return m_out;
199 }
200
201 template <class OutputIterator, class Results, class traits, class ForwardIter>
202 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_all()
203 {
204 // over and over:
205 while(m_position != m_end)
206 {
207 switch(*m_position)
208 {
209 case '&':
210 if(m_flags & ::boost::regex_constants::format_sed)
211 {
212 ++m_position;
213 put(m_results[0]);
214 break;
215 }
216 put(*m_position++);
217 break;
218 case '\\':
219 format_escape();
220 break;
221 case '(':
222 if(m_flags & boost::regex_constants::format_all)
223 {
224 ++m_position;
225 bool have_conditional = m_have_conditional;
226 m_have_conditional = false;
227 format_until_scope_end();
228 m_have_conditional = have_conditional;
229 if(m_position == m_end)
230 return;
231 BOOST_REGEX_ASSERT(*m_position == static_cast<char_type>(')'));
232 ++m_position; // skip the closing ')'
233 break;
234 }
235 put(*m_position);
236 ++m_position;
237 break;
238 case ')':
239 if(m_flags & boost::regex_constants::format_all)
240 {
241 return;
242 }
243 put(*m_position);
244 ++m_position;
245 break;
246 case ':':
247 if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
248 {
249 return;
250 }
251 put(*m_position);
252 ++m_position;
253 break;
254 case '?':
255 if(m_flags & boost::regex_constants::format_all)
256 {
257 ++m_position;
258 format_conditional();
259 break;
260 }
261 put(*m_position);
262 ++m_position;
263 break;
264 case '$':
265 if((m_flags & format_sed) == 0)
266 {
267 format_perl();
268 break;
269 }
270 // not a special character:
271 BOOST_REGEX_FALLTHROUGH;
272 default:
273 put(*m_position);
274 ++m_position;
275 break;
276 }
277 }
278 }
279
280 template <class OutputIterator, class Results, class traits, class ForwardIter>
281 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_perl()
282 {
283 //
284 // On entry *m_position points to a '$' character
285 // output the information that goes with it:
286 //
287 BOOST_REGEX_ASSERT(*m_position == '$');
288 //
289 // see if this is a trailing '$':
290 //
291 if(++m_position == m_end)
292 {
293 --m_position;
294 put(*m_position);
295 ++m_position;
296 return;
297 }
298 //
299 // OK find out what kind it is:
300 //
301 bool have_brace = false;
302 ForwardIter save_position = m_position;
303 switch(*m_position)
304 {
305 case '&':
306 ++m_position;
307 put(this->m_results[0]);
308 break;
309 case '`':
310 ++m_position;
311 put(this->m_results.prefix());
312 break;
313 case '\'':
314 ++m_position;
315 put(this->m_results.suffix());
316 break;
317 case '$':
318 put(*m_position++);
319 break;
320 case '+':
321 if((++m_position != m_end) && (*m_position == '{'))
322 {
323 ForwardIter base = ++m_position;
324 while((m_position != m_end) && (*m_position != '}')) ++m_position;
325 if(m_position != m_end)
326 {
327 // Named sub-expression:
328 put(get_named_sub(base, m_position));
329 ++m_position;
330 break;
331 }
332 else
333 {
334 m_position = --base;
335 }
336 }
337 put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
338 break;
339 case '{':
340 have_brace = true;
341 ++m_position;
342 BOOST_REGEX_FALLTHROUGH;
343 default:
344 // see if we have a number:
345 {
346 std::ptrdiff_t len = std::distance(m_position, m_end);
347 //len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
348 int v = this->toi(m_position, m_position + len, 10);
349 if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}'))))
350 {
351 // Look for a Perl-5.10 verb:
352 if(!handle_perl_verb(have_brace))
353 {
354 // leave the $ as is, and carry on:
355 m_position = --save_position;
356 put(*m_position);
357 ++m_position;
358 }
359 break;
360 }
361 // otherwise output sub v:
362 put(this->m_results[v]);
363 if(have_brace)
364 ++m_position;
365 }
366 }
367 }
368
369 template <class OutputIterator, class Results, class traits, class ForwardIter>
370 bool basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::handle_perl_verb(bool have_brace)
371 {
372 //
373 // We may have a capitalised string containing a Perl action:
374 //
375 static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' };
376 static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' };
377 static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' };
378 static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' };
379 static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' };
380 static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' };
381
382 if(m_position == m_end)
383 return false;
384 if(have_brace && (*m_position == '^'))
385 ++m_position;
386
387 std::ptrdiff_t max_len = m_end - m_position;
388
389 if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH))
390 {
391 m_position += 5;
392 if(have_brace)
393 {
394 if((m_position != m_end) && (*m_position == '}'))
395 ++m_position;
396 else
397 {
398 m_position -= 5;
399 return false;
400 }
401 }
402 put(this->m_results[0]);
403 return true;
404 }
405 if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH))
406 {
407 m_position += 8;
408 if(have_brace)
409 {
410 if((m_position != m_end) && (*m_position == '}'))
411 ++m_position;
412 else
413 {
414 m_position -= 8;
415 return false;
416 }
417 }
418 put(this->m_results.prefix());
419 return true;
420 }
421 if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH))
422 {
423 m_position += 9;
424 if(have_brace)
425 {
426 if((m_position != m_end) && (*m_position == '}'))
427 ++m_position;
428 else
429 {
430 m_position -= 9;
431 return false;
432 }
433 }
434 put(this->m_results.suffix());
435 return true;
436 }
437 if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH))
438 {
439 m_position += 16;
440 if(have_brace)
441 {
442 if((m_position != m_end) && (*m_position == '}'))
443 ++m_position;
444 else
445 {
446 m_position -= 16;
447 return false;
448 }
449 }
450 put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
451 return true;
452 }
453 if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT))
454 {
455 m_position += 20;
456 if(have_brace)
457 {
458 if((m_position != m_end) && (*m_position == '}'))
459 ++m_position;
460 else
461 {
462 m_position -= 20;
463 return false;
464 }
465 }
466 put(this->m_results.get_last_closed_paren());
467 return true;
468 }
469 if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT))
470 {
471 m_position += 2;
472 if(have_brace)
473 {
474 if((m_position != m_end) && (*m_position == '}'))
475 ++m_position;
476 else
477 {
478 m_position -= 2;
479 return false;
480 }
481 }
482 put(this->m_results.get_last_closed_paren());
483 return true;
484 }
485 return false;
486 }
487
488 template <class OutputIterator, class Results, class traits, class ForwardIter>
489 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_escape()
490 {
491 // skip the escape and check for trailing escape:
492 if(++m_position == m_end)
493 {
494 put(static_cast<char_type>('\\'));
495 return;
496 }
497 // now switch on the escape type:
498 switch(*m_position)
499 {
500 case 'a':
501 put(static_cast<char_type>('\a'));
502 ++m_position;
503 break;
504 case 'f':
505 put(static_cast<char_type>('\f'));
506 ++m_position;
507 break;
508 case 'n':
509 put(static_cast<char_type>('\n'));
510 ++m_position;
511 break;
512 case 'r':
513 put(static_cast<char_type>('\r'));
514 ++m_position;
515 break;
516 case 't':
517 put(static_cast<char_type>('\t'));
518 ++m_position;
519 break;
520 case 'v':
521 put(static_cast<char_type>('\v'));
522 ++m_position;
523 break;
524 case 'x':
525 if(++m_position == m_end)
526 {
527 put(static_cast<char_type>('x'));
528 return;
529 }
530 // maybe have \x{ddd}
531 if(*m_position == static_cast<char_type>('{'))
532 {
533 ++m_position;
534 int val = this->toi(m_position, m_end, 16);
535 if(val < 0)
536 {
537 // invalid value treat everything as literals:
538 put(static_cast<char_type>('x'));
539 put(static_cast<char_type>('{'));
540 return;
541 }
542 if((m_position == m_end) || (*m_position != static_cast<char_type>('}')))
543 {
544 --m_position;
545 while(*m_position != static_cast<char_type>('\\'))
546 --m_position;
547 ++m_position;
548 put(*m_position++);
549 return;
550 }
551 ++m_position;
552 put(static_cast<char_type>(val));
553 return;
554 }
555 else
556 {
557 std::ptrdiff_t len = std::distance(m_position, m_end);
558 len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
559 int val = this->toi(m_position, m_position + len, 16);
560 if(val < 0)
561 {
562 --m_position;
563 put(*m_position++);
564 return;
565 }
566 put(static_cast<char_type>(val));
567 }
568 break;
569 case 'c':
570 if(++m_position == m_end)
571 {
572 --m_position;
573 put(*m_position++);
574 return;
575 }
576 put(static_cast<char_type>(*m_position++ % 32));
577 break;
578 case 'e':
579 put(static_cast<char_type>(27));
580 ++m_position;
581 break;
582 default:
583 // see if we have a perl specific escape:
584 if((m_flags & boost::regex_constants::format_sed) == 0)
585 {
586 bool breakout = false;
587 switch(*m_position)
588 {
589 case 'l':
590 ++m_position;
591 m_restore_state = m_state;
592 m_state = output_next_lower;
593 breakout = true;
594 break;
595 case 'L':
596 ++m_position;
597 m_state = output_lower;
598 breakout = true;
599 break;
600 case 'u':
601 ++m_position;
602 m_restore_state = m_state;
603 m_state = output_next_upper;
604 breakout = true;
605 break;
606 case 'U':
607 ++m_position;
608 m_state = output_upper;
609 breakout = true;
610 break;
611 case 'E':
612 ++m_position;
613 m_state = output_copy;
614 breakout = true;
615 break;
616 }
617 if(breakout)
618 break;
619 }
620 // see if we have a \n sed style backreference:
621 std::ptrdiff_t len = std::distance(m_position, m_end);
622 len = (std::min)(static_cast<std::ptrdiff_t>(1), len);
623 int v = this->toi(m_position, m_position+len, 10);
624 if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
625 {
626 put(m_results[v]);
627 break;
628 }
629 else if(v == 0)
630 {
631 // octal ecape sequence:
632 --m_position;
633 len = std::distance(m_position, m_end);
634 len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
635 v = this->toi(m_position, m_position + len, 8);
636 BOOST_REGEX_ASSERT(v >= 0);
637 put(static_cast<char_type>(v));
638 break;
639 }
640 // Otherwise output the character "as is":
641 put(*m_position++);
642 break;
643 }
644 }
645
646 template <class OutputIterator, class Results, class traits, class ForwardIter>
647 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_conditional()
648 {
649 if(m_position == m_end)
650 {
651 // oops trailing '?':
652 put(static_cast<char_type>('?'));
653 return;
654 }
655 int v;
656 if(*m_position == '{')
657 {
658 ForwardIter base = m_position;
659 ++m_position;
660 v = this->toi(m_position, m_end, 10);
661 if(v < 0)
662 {
663 // Try a named subexpression:
664 while((m_position != m_end) && (*m_position != '}'))
665 ++m_position;
666 v = this->get_named_sub_index(base + 1, m_position);
667 }
668 if((v < 0) || (*m_position != '}'))
669 {
670 m_position = base;
671 // oops trailing '?':
672 put(static_cast<char_type>('?'));
673 return;
674 }
675 // Skip trailing '}':
676 ++m_position;
677 }
678 else
679 {
680 std::ptrdiff_t len = std::distance(m_position, m_end);
681 len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
682 v = this->toi(m_position, m_position + len, 10);
683 }
684 if(v < 0)
685 {
686 // oops not a number:
687 put(static_cast<char_type>('?'));
688 return;
689 }
690
691 // output varies depending upon whether sub-expression v matched or not:
692 if(m_results[v].matched)
693 {
694 m_have_conditional = true;
695 format_all();
696 m_have_conditional = false;
697 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
698 {
699 // skip the ':':
700 ++m_position;
701 // save output state, then turn it off:
702 output_state saved_state = m_state;
703 m_state = output_none;
704 // format the rest of this scope:
705 format_until_scope_end();
706 // restore output state:
707 m_state = saved_state;
708 }
709 }
710 else
711 {
712 // save output state, then turn it off:
713 output_state saved_state = m_state;
714 m_state = output_none;
715 // format until ':' or ')':
716 m_have_conditional = true;
717 format_all();
718 m_have_conditional = false;
719 // restore state:
720 m_state = saved_state;
721 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
722 {
723 // skip the ':':
724 ++m_position;
725 // format the rest of this scope:
726 format_until_scope_end();
727 }
728 }
729 }
730
731 template <class OutputIterator, class Results, class traits, class ForwardIter>
732 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_until_scope_end()
733 {
734 do
735 {
736 format_all();
737 if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
738 return;
739 put(*m_position++);
740 }while(m_position != m_end);
741 }
742
743 template <class OutputIterator, class Results, class traits, class ForwardIter>
744 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(char_type c)
745 {
746 // write a single character to output
747 // according to which case translation mode we are in:
748 switch(this->m_state)
749 {
750 case output_none:
751 return;
752 case output_next_lower:
753 c = m_traits.tolower(c);
754 this->m_state = m_restore_state;
755 break;
756 case output_next_upper:
757 c = m_traits.toupper(c);
758 this->m_state = m_restore_state;
759 break;
760 case output_lower:
761 c = m_traits.tolower(c);
762 break;
763 case output_upper:
764 c = m_traits.toupper(c);
765 break;
766 default:
767 break;
768 }
769 *m_out = c;
770 ++m_out;
771 }
772
773 template <class OutputIterator, class Results, class traits, class ForwardIter>
774 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(const sub_match_type& sub)
775 {
776 typedef typename sub_match_type::iterator iterator_type;
777 iterator_type i = sub.first;
778 while(i != sub.second)
779 {
780 put(*i);
781 ++i;
782 }
783 }
784
785 template <class S>
786 class string_out_iterator
787 {
788 S* out;
789 public:
790 string_out_iterator(S& s) : out(&s) {}
791 string_out_iterator& operator++() { return *this; }
792 string_out_iterator& operator++(int) { return *this; }
793 string_out_iterator& operator*() { return *this; }
794 string_out_iterator& operator=(typename S::value_type v)
795 {
796 out->append(1, v);
797 return *this;
798 }
799
800 typedef std::ptrdiff_t difference_type;
801 typedef typename S::value_type value_type;
802 typedef value_type* pointer;
803 typedef value_type& reference;
804 typedef std::output_iterator_tag iterator_category;
805 };
806
807 template <class OutputIterator, class Iterator, class Alloc, class ForwardIter, class traits>
808 OutputIterator regex_format_imp(OutputIterator out,
809 const match_results<Iterator, Alloc>& m,
810 ForwardIter p1, ForwardIter p2,
811 match_flag_type flags,
812 const traits& t
813 )
814 {
815 if(flags & regex_constants::format_literal)
816 {
817 return BOOST_REGEX_DETAIL_NS::copy(p1, p2, out);
818 }
819
820 BOOST_REGEX_DETAIL_NS::basic_regex_formatter<
821 OutputIterator,
822 match_results<Iterator, Alloc>,
823 traits, ForwardIter> f(out, m, t);
824 return f.format(p1, p2, flags);
825 }
826
827 template <class T>
828 struct has_const_iterator
829 {
830 template <class U>
831 static typename U::const_iterator tester(U*);
832 static char tester(...);
833
834 static T* get();
835
836 static const bool value = sizeof(tester(get())) != sizeof(char);
837 };
838
839 struct any_type
840 {
841 template <class T>
842 any_type(const T&);
843 template <class T, class U>
844 any_type(const T&, const U&);
845 template <class T, class U, class V>
846 any_type(const T&, const U&, const V&);
847 };
848 typedef char no_type;
849 typedef char (&unary_type)[2];
850 typedef char (&binary_type)[3];
851 typedef char (&ternary_type)[4];
852
853 no_type check_is_formatter(unary_type, binary_type, ternary_type);
854 template<typename T>
855 unary_type check_is_formatter(T const &, binary_type, ternary_type);
856 template<typename T>
857 binary_type check_is_formatter(unary_type, T const &, ternary_type);
858 template<typename T, typename U>
859 binary_type check_is_formatter(T const &, U const &, ternary_type);
860 template<typename T>
861 ternary_type check_is_formatter(unary_type, binary_type, T const &);
862 template<typename T, typename U>
863 ternary_type check_is_formatter(T const &, binary_type, U const &);
864 template<typename T, typename U>
865 ternary_type check_is_formatter(unary_type, T const &, U const &);
866 template<typename T, typename U, typename V>
867 ternary_type check_is_formatter(T const &, U const &, V const &);
868
869 struct unary_binary_ternary
870 {
871 typedef unary_type (*unary_fun)(any_type);
872 typedef binary_type (*binary_fun)(any_type, any_type);
873 typedef ternary_type (*ternary_fun)(any_type, any_type, any_type);
874 operator unary_fun();
875 operator binary_fun();
876 operator ternary_fun();
877 };
878
879 template<typename Formatter, bool IsFunction = std::is_function<Formatter>::value>
880 struct formatter_wrapper
881 : Formatter
882 , unary_binary_ternary
883 {
884 formatter_wrapper(){}
885 };
886
887 template<typename Formatter>
888 struct formatter_wrapper<Formatter, true>
889 : unary_binary_ternary
890 {
891 operator Formatter *();
892 };
893
894 template<typename Formatter>
895 struct formatter_wrapper<Formatter *, false>
896 : unary_binary_ternary
897 {
898 operator Formatter *();
899 };
900
901 template <class T>
902 struct do_unwrap_reference
903 {
904 typedef T type;
905 };
906 template <class T>
907 struct do_unwrap_reference<std::reference_wrapper<T> >
908 {
909 typedef T type;
910 };
911
912 template <class T>
913 T& do_unwrap_ref(T& r) { return r; }
914 template <class T>
915 T& do_unwrap_ref(std::reference_wrapper<T> const& r) { return r.get(); }
916
917 template <class F, class M, class O>
918 struct format_traits_imp
919 {
920 private:
921 //
922 // F must be a pointer, a function, or a class with a function call operator:
923 //
924 static_assert((::std::is_pointer<F>::value || ::std::is_function<F>::value || ::std::is_class<F>::value), "The functor must be a pointer or a class with a function call operator");
925 static formatter_wrapper<typename do_unwrap_reference<F>::type> f;
926 static M m;
927 static O out;
928 static boost::regex_constants::match_flag_type flags;
929 public:
930 static const int value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags)));
931 };
932
933 template <class F, class M, class O>
934 struct format_traits
935 {
936 public:
937 //
938 // Type is std::integral_constant<int, N> where N is one of:
939 //
940 // 0 : F is a pointer to a presumably null-terminated string.
941 // 1 : F is a character-container such as a std::string.
942 // 2 : F is a Unary Functor.
943 // 3 : F is a Binary Functor.
944 // 4 : F is a Ternary Functor.
945 //
946 typedef typename std::conditional<
947 std::is_pointer<F>::value && !std::is_function<typename std::remove_pointer<F>::type>::value,
948 std::integral_constant<int, 0>,
949 typename std::conditional<
950 has_const_iterator<F>::value,
951 std::integral_constant<int, 1>,
952 std::integral_constant<int, format_traits_imp<F, M, O>::value>
953 >::type
954 >::type type;
955 //
956 // This static assertion will fail if the functor passed does not accept
957 // the same type of arguments passed.
958 //
959 static_assert( std::is_class<F>::value && !has_const_iterator<F>::value ? (type::value > 1) : true, "Argument mismatch in Functor type");
960 };
961
962 template <class Base, class Match>
963 struct format_functor3
964 {
965 format_functor3(Base b) : func(b) {}
966 template <class OutputIter>
967 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f)
968 {
969 return do_unwrap_ref(func)(m, i, f);
970 }
971 template <class OutputIter, class Traits>
972 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
973 {
974 return (*this)(m, i, f);
975 }
976 private:
977 Base func;
978 format_functor3(const format_functor3&);
979 format_functor3& operator=(const format_functor3&);
980 };
981
982 template <class Base, class Match>
983 struct format_functor2
984 {
985 format_functor2(Base b) : func(b) {}
986 template <class OutputIter>
987 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
988 {
989 return do_unwrap_ref(func)(m, i);
990 }
991 template <class OutputIter, class Traits>
992 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
993 {
994 return (*this)(m, i, f);
995 }
996 private:
997 Base func;
998 format_functor2(const format_functor2&);
999 format_functor2& operator=(const format_functor2&);
1000 };
1001
1002 template <class Base, class Match>
1003 struct format_functor1
1004 {
1005 format_functor1(Base b) : func(b) {}
1006
1007 template <class S, class OutputIter>
1008 OutputIter do_format_string(const S& s, OutputIter i)
1009 {
1010 return std::copy(s.begin(), s.end(), i);
1011 }
1012 template <class S, class OutputIter>
1013 inline OutputIter do_format_string(const S* s, OutputIter i)
1014 {
1015 while(s && *s)
1016 {
1017 *i = *s;
1018 ++i;
1019 ++s;
1020 }
1021 return i;
1022 }
1023 template <class OutputIter>
1024 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
1025 {
1026 return do_format_string(do_unwrap_ref(func)(m), i);
1027 }
1028 template <class OutputIter, class Traits>
1029 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
1030 {
1031 return (*this)(m, i, f);
1032 }
1033 private:
1034 Base func;
1035 format_functor1(const format_functor1&);
1036 format_functor1& operator=(const format_functor1&);
1037 };
1038
1039 template <class charT, class Match, class Traits>
1040 struct format_functor_c_string
1041 {
1042 format_functor_c_string(const charT* ps) : func(ps) {}
1043
1044 template <class OutputIter>
1045 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
1046 {
1047 //typedef typename Match::char_type char_type;
1048 const charT* end = func;
1049 while(*end) ++end;
1050 return regex_format_imp(i, m, func, end, f, t);
1051 }
1052 private:
1053 const charT* func;
1054 format_functor_c_string(const format_functor_c_string&);
1055 format_functor_c_string& operator=(const format_functor_c_string&);
1056 };
1057
1058 template <class Container, class Match, class Traits>
1059 struct format_functor_container
1060 {
1061 format_functor_container(const Container& c) : func(c) {}
1062
1063 template <class OutputIter>
1064 OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
1065 {
1066 //typedef typename Match::char_type char_type;
1067 return BOOST_REGEX_DETAIL_NS::regex_format_imp(i, m, func.begin(), func.end(), f, t);
1068 }
1069 private:
1070 const Container& func;
1071 format_functor_container(const format_functor_container&);
1072 format_functor_container& operator=(const format_functor_container&);
1073 };
1074
1075 template <class Func, class Match, class OutputIterator, class Traits = BOOST_REGEX_DETAIL_NS::trivial_format_traits<typename Match::char_type> >
1076 struct compute_functor_type
1077 {
1078 typedef typename format_traits<Func, Match, OutputIterator>::type tag;
1079 typedef typename std::remove_cv< typename std::remove_pointer<Func>::type>::type maybe_char_type;
1080
1081 typedef typename std::conditional<
1082 tag::value == 0, format_functor_c_string<maybe_char_type, Match, Traits>,
1083 typename std::conditional<
1084 tag::value == 1, format_functor_container<Func, Match, Traits>,
1085 typename std::conditional<
1086 tag::value == 2, format_functor1<Func, Match>,
1087 typename std::conditional<
1088 tag::value == 3, format_functor2<Func, Match>,
1089 format_functor3<Func, Match>
1090 >::type
1091 >::type
1092 >::type
1093 >::type type;
1094 };
1095
1096 } // namespace BOOST_REGEX_DETAIL_NS
1097
1098 template <class OutputIterator, class Iterator, class Allocator, class Functor>
1099 inline OutputIterator regex_format(OutputIterator out,
1100 const match_results<Iterator, Allocator>& m,
1101 Functor fmt,
1102 match_flag_type flags = format_all
1103 )
1104 {
1105 return m.format(out, fmt, flags);
1106 }
1107
1108 template <class Iterator, class Allocator, class Functor>
1109 inline std::basic_string<typename match_results<Iterator, Allocator>::char_type> regex_format(const match_results<Iterator, Allocator>& m,
1110 Functor fmt,
1111 match_flag_type flags = format_all)
1112 {
1113 return m.format(fmt, flags);
1114 }
1115
1116 } // namespace boost
1117
1118 #endif // BOOST_REGEX_FORMAT_HPP
1119
1120
1121
1122
1123
1124