regex.h Source File

regex.h Source File#

Composable Kernel: regex.h Source File
regex.h
Go to the documentation of this file.
1// Tencent is pleased to support the open source community by making RapidJSON available.
2//
3// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4//
5// Licensed under the MIT License (the "License"); you may not use this file except
6// in compliance with the License. You may obtain a copy of the License at
7//
8// http://opensource.org/licenses/MIT
9//
10// Unless required by applicable law or agreed to in writing, software distributed
11// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13// specific language governing permissions and limitations under the License.
14
15#ifndef RAPIDJSON_INTERNAL_REGEX_H_
16#define RAPIDJSON_INTERNAL_REGEX_H_
17
18#include "../allocators.h"
19#include "../stream.h"
20#include "stack.h"
21
22#ifdef __clang__
23RAPIDJSON_DIAG_PUSH
24RAPIDJSON_DIAG_OFF(padded)
25RAPIDJSON_DIAG_OFF(switch - enum)
26#elif defined(_MSC_VER)
27RAPIDJSON_DIAG_PUSH
28RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
29#endif
30
31#ifdef __GNUC__
32RAPIDJSON_DIAG_PUSH
33RAPIDJSON_DIAG_OFF(effc++)
34#endif
35
36#ifndef RAPIDJSON_REGEX_VERBOSE
37#define RAPIDJSON_REGEX_VERBOSE 0
38#endif
39
41namespace internal {
42
44// DecodedStream
45
46template <typename SourceStream, typename Encoding>
48{
49 public:
50 DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
51 unsigned Peek() { return codepoint_; }
52 unsigned Take()
53 {
54 unsigned c = codepoint_;
55 if(c) // No further decoding when '\0'
56 Decode();
57 return c;
58 }
59
60 private:
61 void Decode()
62 {
63 if(!Encoding::Decode(ss_, &codepoint_))
64 codepoint_ = 0;
65 }
66
67 SourceStream& ss_;
68 unsigned codepoint_;
69};
70
72// GenericRegex
73
74static const SizeType kRegexInvalidState =
75 ~SizeType(0);
76static const SizeType kRegexInvalidRange = ~SizeType(0);
77
78template <typename Encoding, typename Allocator>
80
82
113template <typename Encoding, typename Allocator = CrtAllocator>
115{
116 public:
118 typedef typename Encoding::Ch Ch;
119 template <typename, typename>
120 friend class GenericRegexSearch;
121
122 GenericRegex(const Ch* source, Allocator* allocator = 0)
123 : ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()),
124 allocator_(allocator ? allocator : ownAllocator_),
125 states_(allocator_, 256),
126 ranges_(allocator_, 256),
127 root_(kRegexInvalidState),
128 stateCount_(),
129 rangeCount_(),
130 anchorBegin_(),
131 anchorEnd_()
132 {
135 Parse(ds);
136 }
137
138 ~GenericRegex() { RAPIDJSON_DELETE(ownAllocator_); }
139
140 bool IsValid() const { return root_ != kRegexInvalidState; }
141
142 private:
143 enum Operator
144 {
145 kZeroOrOne,
146 kZeroOrMore,
147 kOneOrMore,
148 kConcatenation,
149 kAlternation,
150 kLeftParenthesis
151 };
152
153 static const unsigned kAnyCharacterClass = 0xFFFFFFFF;
154 static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
155 static const unsigned kRangeNegationFlag = 0x80000000;
156
157 struct Range
158 {
159 unsigned start; //
160 unsigned end;
161 SizeType next;
162 };
163
164 struct State
165 {
166 SizeType out;
167 SizeType out1;
168 SizeType rangeStart;
169 unsigned codepoint;
170 };
171
172 struct Frag
173 {
174 Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
175 SizeType start;
176 SizeType out;
177 SizeType minIndex;
178 };
179
180 State& GetState(SizeType index)
181 {
182 RAPIDJSON_ASSERT(index < stateCount_);
183 return states_.template Bottom<State>()[index];
184 }
185
186 const State& GetState(SizeType index) const
187 {
188 RAPIDJSON_ASSERT(index < stateCount_);
189 return states_.template Bottom<State>()[index];
190 }
191
192 Range& GetRange(SizeType index)
193 {
194 RAPIDJSON_ASSERT(index < rangeCount_);
195 return ranges_.template Bottom<Range>()[index];
196 }
197
198 const Range& GetRange(SizeType index) const
199 {
200 RAPIDJSON_ASSERT(index < rangeCount_);
201 return ranges_.template Bottom<Range>()[index];
202 }
203
204 template <typename InputStream>
205 void Parse(DecodedStream<InputStream, Encoding>& ds)
206 {
207 Stack<Allocator> operandStack(allocator_, 256); // Frag
208 Stack<Allocator> operatorStack(allocator_, 256); // Operator
209 Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
210
211 *atomCountStack.template Push<unsigned>() = 0;
212
213 unsigned codepoint;
214 while(ds.Peek() != 0)
215 {
216 switch(codepoint = ds.Take())
217 {
218 case '^': anchorBegin_ = true; break;
219
220 case '$': anchorEnd_ = true; break;
221
222 case '|':
223 while(!operatorStack.Empty() &&
224 *operatorStack.template Top<Operator>() < kAlternation)
225 if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
226 return;
227 *operatorStack.template Push<Operator>() = kAlternation;
228 *atomCountStack.template Top<unsigned>() = 0;
229 break;
230
231 case '(':
232 *operatorStack.template Push<Operator>() = kLeftParenthesis;
233 *atomCountStack.template Push<unsigned>() = 0;
234 break;
235
236 case ')':
237 while(!operatorStack.Empty() &&
238 *operatorStack.template Top<Operator>() != kLeftParenthesis)
239 if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
240 return;
241 if(operatorStack.Empty())
242 return;
243 operatorStack.template Pop<Operator>(1);
244 atomCountStack.template Pop<unsigned>(1);
245 ImplicitConcatenation(atomCountStack, operatorStack);
246 break;
247
248 case '?':
249 if(!Eval(operandStack, kZeroOrOne))
250 return;
251 break;
252
253 case '*':
254 if(!Eval(operandStack, kZeroOrMore))
255 return;
256 break;
257
258 case '+':
259 if(!Eval(operandStack, kOneOrMore))
260 return;
261 break;
262
263 case '{': {
264 unsigned n, m;
265 if(!ParseUnsigned(ds, &n))
266 return;
267
268 if(ds.Peek() == ',')
269 {
270 ds.Take();
271 if(ds.Peek() == '}')
272 m = kInfinityQuantifier;
273 else if(!ParseUnsigned(ds, &m) || m < n)
274 return;
275 }
276 else
277 m = n;
278
279 if(!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
280 return;
281 ds.Take();
282 }
283 break;
284
285 case '.':
286 PushOperand(operandStack, kAnyCharacterClass);
287 ImplicitConcatenation(atomCountStack, operatorStack);
288 break;
289
290 case '[': {
291 SizeType range;
292 if(!ParseRange(ds, &range))
293 return;
294 SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
295 GetState(s).rangeStart = range;
296 *operandStack.template Push<Frag>() = Frag(s, s, s);
297 }
298 ImplicitConcatenation(atomCountStack, operatorStack);
299 break;
300
301 case '\\': // Escape character
302 if(!CharacterEscape(ds, &codepoint))
303 return; // Unsupported escape character
304 // fall through to default
305 RAPIDJSON_DELIBERATE_FALLTHROUGH;
306
307 default: // Pattern character
308 PushOperand(operandStack, codepoint);
309 ImplicitConcatenation(atomCountStack, operatorStack);
310 }
311 }
312
313 while(!operatorStack.Empty())
314 if(!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
315 return;
316
317 // Link the operand to matching state.
318 if(operandStack.GetSize() == sizeof(Frag))
319 {
320 Frag* e = operandStack.template Pop<Frag>(1);
321 Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
322 root_ = e->start;
323
324#if RAPIDJSON_REGEX_VERBOSE
325 printf("root: %d\n", root_);
326 for(SizeType i = 0; i < stateCount_; i++)
327 {
328 State& s = GetState(i);
329 printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
330 }
331 printf("\n");
332#endif
333 }
334 }
335
336 SizeType NewState(SizeType out, SizeType out1, unsigned codepoint)
337 {
338 State* s = states_.template Push<State>();
339 s->out = out;
340 s->out1 = out1;
341 s->codepoint = codepoint;
342 s->rangeStart = kRegexInvalidRange;
343 return stateCount_++;
344 }
345
346 void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint)
347 {
348 SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
349 *operandStack.template Push<Frag>() = Frag(s, s, s);
350 }
351
352 void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack)
353 {
354 if(*atomCountStack.template Top<unsigned>())
355 *operatorStack.template Push<Operator>() = kConcatenation;
356 (*atomCountStack.template Top<unsigned>())++;
357 }
358
359 SizeType Append(SizeType l1, SizeType l2)
360 {
361 SizeType old = l1;
362 while(GetState(l1).out != kRegexInvalidState)
363 l1 = GetState(l1).out;
364 GetState(l1).out = l2;
365 return old;
366 }
367
368 void Patch(SizeType l, SizeType s)
369 {
370 for(SizeType next; l != kRegexInvalidState; l = next)
371 {
372 next = GetState(l).out;
373 GetState(l).out = s;
374 }
375 }
376
377 bool Eval(Stack<Allocator>& operandStack, Operator op)
378 {
379 switch(op)
380 {
381 case kConcatenation:
382 RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
383 {
384 Frag e2 = *operandStack.template Pop<Frag>(1);
385 Frag e1 = *operandStack.template Pop<Frag>(1);
386 Patch(e1.out, e2.start);
387 *operandStack.template Push<Frag>() =
388 Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
389 }
390 return true;
391
392 case kAlternation:
393 if(operandStack.GetSize() >= sizeof(Frag) * 2)
394 {
395 Frag e2 = *operandStack.template Pop<Frag>(1);
396 Frag e1 = *operandStack.template Pop<Frag>(1);
397 SizeType s = NewState(e1.start, e2.start, 0);
398 *operandStack.template Push<Frag>() =
399 Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
400 return true;
401 }
402 return false;
403
404 case kZeroOrOne:
405 if(operandStack.GetSize() >= sizeof(Frag))
406 {
407 Frag e = *operandStack.template Pop<Frag>(1);
408 SizeType s = NewState(kRegexInvalidState, e.start, 0);
409 *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
410 return true;
411 }
412 return false;
413
414 case kZeroOrMore:
415 if(operandStack.GetSize() >= sizeof(Frag))
416 {
417 Frag e = *operandStack.template Pop<Frag>(1);
418 SizeType s = NewState(kRegexInvalidState, e.start, 0);
419 Patch(e.out, s);
420 *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
421 return true;
422 }
423 return false;
424
425 case kOneOrMore:
426 if(operandStack.GetSize() >= sizeof(Frag))
427 {
428 Frag e = *operandStack.template Pop<Frag>(1);
429 SizeType s = NewState(kRegexInvalidState, e.start, 0);
430 Patch(e.out, s);
431 *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
432 return true;
433 }
434 return false;
435
436 default:
437 // syntax error (e.g. unclosed kLeftParenthesis)
438 return false;
439 }
440 }
441
442 bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m)
443 {
444 RAPIDJSON_ASSERT(n <= m);
445 RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
446
447 if(n == 0)
448 {
449 if(m == 0) // a{0} not support
450 return false;
451 else if(m == kInfinityQuantifier)
452 Eval(operandStack, kZeroOrMore); // a{0,} -> a*
453 else
454 {
455 Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
456 for(unsigned i = 0; i < m - 1; i++)
457 CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
458 for(unsigned i = 0; i < m - 1; i++)
459 Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
460 }
461 return true;
462 }
463
464 for(unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
465 CloneTopOperand(operandStack);
466
467 if(m == kInfinityQuantifier)
468 Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
469 else if(m > n)
470 {
471 CloneTopOperand(operandStack); // a{3,5} -> a a a a
472 Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
473 for(unsigned i = n; i < m - 1; i++)
474 CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
475 for(unsigned i = n; i < m; i++)
476 Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
477 }
478
479 for(unsigned i = 0; i < n - 1; i++)
480 Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
481
482 return true;
483 }
484
485 static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
486
487 void CloneTopOperand(Stack<Allocator>& operandStack)
488 {
489 const Frag src =
490 *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
491 SizeType count =
492 stateCount_ -
493 src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
494 State* s = states_.template Push<State>(count);
495 memcpy(s, &GetState(src.minIndex), count * sizeof(State));
496 for(SizeType j = 0; j < count; j++)
497 {
498 if(s[j].out != kRegexInvalidState)
499 s[j].out += count;
500 if(s[j].out1 != kRegexInvalidState)
501 s[j].out1 += count;
502 }
503 *operandStack.template Push<Frag>() =
504 Frag(src.start + count, src.out + count, src.minIndex + count);
505 stateCount_ += count;
506 }
507
508 template <typename InputStream>
509 bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u)
510 {
511 unsigned r = 0;
512 if(ds.Peek() < '0' || ds.Peek() > '9')
513 return false;
514 while(ds.Peek() >= '0' && ds.Peek() <= '9')
515 {
516 if(r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
517 return false; // overflow
518 r = r * 10 + (ds.Take() - '0');
519 }
520 *u = r;
521 return true;
522 }
523
524 template <typename InputStream>
525 bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range)
526 {
527 bool isBegin = true;
528 bool negate = false;
529 int step = 0;
530 SizeType start = kRegexInvalidRange;
531 SizeType current = kRegexInvalidRange;
532 unsigned codepoint;
533 while((codepoint = ds.Take()) != 0)
534 {
535 if(isBegin)
536 {
537 isBegin = false;
538 if(codepoint == '^')
539 {
540 negate = true;
541 continue;
542 }
543 }
544
545 switch(codepoint)
546 {
547 case ']':
548 if(start == kRegexInvalidRange)
549 return false; // Error: nothing inside []
550 if(step == 2)
551 { // Add trailing '-'
552 SizeType r = NewRange('-');
553 RAPIDJSON_ASSERT(current != kRegexInvalidRange);
554 GetRange(current).next = r;
555 }
556 if(negate)
557 GetRange(start).start |= kRangeNegationFlag;
558 *range = start;
559 return true;
560
561 case '\\':
562 if(ds.Peek() == 'b')
563 {
564 ds.Take();
565 codepoint = 0x0008; // Escape backspace character
566 }
567 else if(!CharacterEscape(ds, &codepoint))
568 return false;
569 // fall through to default
570 RAPIDJSON_DELIBERATE_FALLTHROUGH;
571
572 default:
573 switch(step)
574 {
575 case 1:
576 if(codepoint == '-')
577 {
578 step++;
579 break;
580 }
581 // fall through to step 0 for other characters
582 RAPIDJSON_DELIBERATE_FALLTHROUGH;
583
584 case 0: {
585 SizeType r = NewRange(codepoint);
586 if(current != kRegexInvalidRange)
587 GetRange(current).next = r;
588 if(start == kRegexInvalidRange)
589 start = r;
590 current = r;
591 }
592 step = 1;
593 break;
594
595 default:
596 RAPIDJSON_ASSERT(step == 2);
597 GetRange(current).end = codepoint;
598 step = 0;
599 }
600 }
601 }
602 return false;
603 }
604
605 SizeType NewRange(unsigned codepoint)
606 {
607 Range* r = ranges_.template Push<Range>();
608 r->start = r->end = codepoint;
609 r->next = kRegexInvalidRange;
610 return rangeCount_++;
611 }
612
613 template <typename InputStream>
614 bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint)
615 {
616 unsigned codepoint;
617 switch(codepoint = ds.Take())
618 {
619 case '^':
620 case '$':
621 case '|':
622 case '(':
623 case ')':
624 case '?':
625 case '*':
626 case '+':
627 case '.':
628 case '[':
629 case ']':
630 case '{':
631 case '}':
632 case '\\': *escapedCodepoint = codepoint; return true;
633 case 'f': *escapedCodepoint = 0x000C; return true;
634 case 'n': *escapedCodepoint = 0x000A; return true;
635 case 'r': *escapedCodepoint = 0x000D; return true;
636 case 't': *escapedCodepoint = 0x0009; return true;
637 case 'v': *escapedCodepoint = 0x000B; return true;
638 default: return false; // Unsupported escape character
639 }
640 }
641
642 Allocator* ownAllocator_;
643 Allocator* allocator_;
644 Stack<Allocator> states_;
645 Stack<Allocator> ranges_;
646 SizeType root_;
647 SizeType stateCount_;
648 SizeType rangeCount_;
649
650 static const unsigned kInfinityQuantifier = ~0u;
651
652 // For SearchWithAnchoring()
653 bool anchorBegin_;
654 bool anchorEnd_;
655};
656
657template <typename RegexType, typename Allocator = CrtAllocator>
659{
660 public:
661 typedef typename RegexType::EncodingType Encoding;
662 typedef typename Encoding::Ch Ch;
663
664 GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0)
665 : regex_(regex),
666 allocator_(allocator),
667 ownAllocator_(0),
668 state0_(allocator, 0),
669 state1_(allocator, 0),
670 stateSet_()
671 {
672 RAPIDJSON_ASSERT(regex_.IsValid());
673 if(!allocator_)
674 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
675 stateSet_ = static_cast<uint32_t*>(allocator_->Malloc(GetStateSetSize()));
676 state0_.template Reserve<SizeType>(regex_.stateCount_);
677 state1_.template Reserve<SizeType>(regex_.stateCount_);
678 }
679
681 {
682 Allocator::Free(stateSet_);
683 RAPIDJSON_DELETE(ownAllocator_);
684 }
685
686 template <typename InputStream>
687 bool Match(InputStream& is)
688 {
689 return SearchWithAnchoring(is, true, true);
690 }
691
692 bool Match(const Ch* s)
693 {
695 return Match(is);
696 }
697
698 template <typename InputStream>
699 bool Search(InputStream& is)
700 {
701 return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
702 }
703
704 bool Search(const Ch* s)
705 {
707 return Search(is);
708 }
709
710 private:
711 typedef typename RegexType::State State;
712 typedef typename RegexType::Range Range;
713
714 template <typename InputStream>
715 bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd)
716 {
718
719 state0_.Clear();
720 Stack<Allocator>*current = &state0_, *next = &state1_;
721 const size_t stateSetSize = GetStateSetSize();
722 std::memset(stateSet_, 0, stateSetSize);
723
724 bool matched = AddState(*current, regex_.root_);
725 unsigned codepoint;
726 while(!current->Empty() && (codepoint = ds.Take()) != 0)
727 {
728 std::memset(stateSet_, 0, stateSetSize);
729 next->Clear();
730 matched = false;
731 for(const SizeType* s = current->template Bottom<SizeType>();
732 s != current->template End<SizeType>();
733 ++s)
734 {
735 const State& sr = regex_.GetState(*s);
736 if(sr.codepoint == codepoint || sr.codepoint == RegexType::kAnyCharacterClass ||
737 (sr.codepoint == RegexType::kRangeCharacterClass &&
738 MatchRange(sr.rangeStart, codepoint)))
739 {
740 matched = AddState(*next, sr.out) || matched;
741 if(!anchorEnd && matched)
742 return true;
743 }
744 if(!anchorBegin)
745 AddState(*next, regex_.root_);
746 }
747 internal::Swap(current, next);
748 }
749
750 return matched;
751 }
752
753 size_t GetStateSetSize() const { return (regex_.stateCount_ + 31) / 32 * 4; }
754
755 // Return whether the added states is a match state
756 bool AddState(Stack<Allocator>& l, SizeType index)
757 {
758 RAPIDJSON_ASSERT(index != kRegexInvalidState);
759
760 const State& s = regex_.GetState(index);
761 if(s.out1 != kRegexInvalidState)
762 { // Split
763 bool matched = AddState(l, s.out);
764 return AddState(l, s.out1) || matched;
765 }
766 else if(!(stateSet_[index >> 5] & (1u << (index & 31))))
767 {
768 stateSet_[index >> 5] |= (1u << (index & 31));
769 *l.template PushUnsafe<SizeType>() = index;
770 }
771 return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not
772 // validated due to reallocation.
773 }
774
775 bool MatchRange(SizeType rangeIndex, unsigned codepoint) const
776 {
777 bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
778 while(rangeIndex != kRegexInvalidRange)
779 {
780 const Range& r = regex_.GetRange(rangeIndex);
781 if(codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
782 return yes;
783 rangeIndex = r.next;
784 }
785 return !yes;
786 }
787
788 const RegexType& regex_;
789 Allocator* allocator_;
790 Allocator* ownAllocator_;
791 Stack<Allocator> state0_;
792 Stack<Allocator> state1_;
793 uint32_t* stateSet_;
794};
795
798
799} // namespace internal
801
802#ifdef __GNUC__
803RAPIDJSON_DIAG_POP
804#endif
805
806#if defined(__clang__) || defined(_MSC_VER)
807RAPIDJSON_DIAG_POP
808#endif
809
810#endif // RAPIDJSON_INTERNAL_REGEX_H_
Definition regex.h:48
DecodedStream(SourceStream &ss)
Definition regex.h:50
unsigned Take()
Definition regex.h:52
unsigned Peek()
Definition regex.h:51
Regular expression engine with subset of ECMAscript grammar.
Definition regex.h:115
bool IsValid() const
Definition regex.h:140
GenericRegex(const Ch *source, Allocator *allocator=0)
Definition regex.h:122
Encoding::Ch Ch
Definition regex.h:118
~GenericRegex()
Definition regex.h:138
Encoding EncodingType
Definition regex.h:117
friend class GenericRegexSearch
Definition regex.h:120
Definition regex.h:659
GenericRegexSearch(const RegexType &regex, Allocator *allocator=0)
Definition regex.h:664
bool Search(InputStream &is)
Definition regex.h:699
RegexType::EncodingType Encoding
Definition regex.h:661
Encoding::Ch Ch
Definition regex.h:662
bool Search(const Ch *s)
Definition regex.h:704
bool Match(const Ch *s)
Definition regex.h:692
~GenericRegexSearch()
Definition regex.h:680
bool Match(InputStream &is)
Definition regex.h:687
A type-unsafe stack for storing different types of data.
Definition stack.h:38
bool Empty() const
Definition stack.h:205
Concept for allocating, resizing and freeing memory block.
Concept for encoding of Unicode characters.
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:451
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition rapidjson.h:121
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition rapidjson.h:124
Definition allocators.h:459
GenericRegexSearch< Regex > RegexSearch
Definition regex.h:797
void Swap(T &a, T &b) RAPIDJSON_NOEXCEPT
Custom swap() to avoid dependency on C++ <algorithm> header.
Definition swap.h:33
GenericRegex< UTF8<> > Regex
Definition regex.h:796
const CharType(& source)[N]
Definition pointer.h:1559
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1517
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition rapidjson.h:746
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.).
Definition rapidjson.h:429
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition rapidjson.h:742
unsigned int uint32_t
Definition stdint.h:126
Read-only string stream.
Definition stream.h:163