1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef vm_MatchPairs_h
8 #define vm_MatchPairs_h
9 
10 #include "ds/LifoAlloc.h"
11 #include "js/AllocPolicy.h"
12 #include "js/Vector.h"
13 
14 /*
15  * RegExp match results are succinctly represented by pairs of integer
16  * indices delimiting (start, limit] segments of the input string.
17  *
18  * The pair count for a given RegExp match is the capturing parentheses
19  * count plus one for the "0 capturing paren" whole text match.
20  */
21 
22 namespace js {
23 
24 struct MatchPair final {
25   int32_t start;
26   int32_t limit;
27 
28   static constexpr int32_t NoMatch = -1;
29 
MatchPairfinal30   MatchPair() : start(NoMatch), limit(NoMatch) {}
31 
MatchPairfinal32   MatchPair(int32_t start, int32_t limit) : start(start), limit(limit) {}
33 
lengthfinal34   size_t length() const {
35     MOZ_ASSERT(!isUndefined());
36     return limit - start;
37   }
isUndefinedfinal38   bool isUndefined() const { return start < 0; }
39 
checkfinal40   inline bool check() const {
41     MOZ_ASSERT(limit >= start);
42     MOZ_ASSERT_IF(start < 0, start == NoMatch);
43     MOZ_ASSERT_IF(limit < 0, limit == NoMatch);
44     return true;
45   }
46 };
47 
48 // MachPairs is used as base class for VectorMatchPairs but can also be
49 // stack-allocated (without a Vector) in JIT code.
50 class MatchPairs {
51  protected:
52   /* Length of pairs_. */
53   uint32_t pairCount_;
54 
55   /* Raw pointer into an allocated MatchPair buffer. */
56   MatchPair* pairs_;
57 
58  protected:
59   /* Not used directly: use VectorMatchPairs. */
MatchPairs()60   MatchPairs() : pairCount_(0), pairs_(nullptr) {}
61 
62  protected:
63   /* Functions used by friend classes. */
64   friend class RegExpShared;
65   friend class RegExpStatics;
66 
forgetArray()67   void forgetArray() { pairs_ = nullptr; }
68 
69  public:
checkAgainst(size_t inputLength)70   void checkAgainst(size_t inputLength) {
71 #ifdef DEBUG
72     for (size_t i = 0; i < pairCount_; i++) {
73       const MatchPair& p = (*this)[i];
74       MOZ_ASSERT(p.check());
75       if (p.isUndefined()) {
76         continue;
77       }
78       MOZ_ASSERT(size_t(p.limit) <= inputLength);
79     }
80 #endif
81   }
82 
83   /* Querying functions in the style of RegExpStatics. */
empty()84   bool empty() const { return pairCount_ == 0; }
pairCount()85   size_t pairCount() const {
86     MOZ_ASSERT(pairCount_ > 0);
87     return pairCount_;
88   }
89 
offsetOfPairs()90   static size_t offsetOfPairs() { return offsetof(MatchPairs, pairs_); }
offsetOfPairCount()91   static size_t offsetOfPairCount() { return offsetof(MatchPairs, pairCount_); }
92 
pairsRaw()93   int32_t* pairsRaw() { return reinterpret_cast<int32_t*>(pairs_); }
94 
95  public:
length()96   size_t length() const { return pairCount_; }
97 
98   const MatchPair& operator[](size_t i) const {
99     MOZ_ASSERT(i < pairCount_);
100     return pairs_[i];
101   }
102   MatchPair& operator[](size_t i) {
103     MOZ_ASSERT(i < pairCount_);
104     return pairs_[i];
105   }
106 };
107 
108 class VectorMatchPairs : public MatchPairs {
109   Vector<MatchPair, 10, SystemAllocPolicy> vec_;
110 
111  protected:
112   friend class RegExpShared;
113   friend class RegExpStatics;
114 
115   /* MatchPair buffer allocator: set pairs_ and pairCount_. */
116   bool allocOrExpandArray(size_t pairCount);
117 
118   bool initArrayFrom(VectorMatchPairs& copyFrom);
119 };
120 
121 } /* namespace js */
122 
123 #endif /* vm_MatchPairs_h */
124