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


xbot_talker
Author(s): wangxiaoyun
autogenerated on Sat Oct 10 2020 03:27:53