michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef vm_MatchPairs_h michael@0: #define vm_MatchPairs_h michael@0: michael@0: #include "jsalloc.h" michael@0: michael@0: #include "ds/LifoAlloc.h" michael@0: #include "js/Vector.h" michael@0: michael@0: /* michael@0: * RegExp match results are succinctly represented by pairs of integer michael@0: * indices delimiting (start, limit] segments of the input string. michael@0: * michael@0: * The pair count for a given RegExp match is the capturing parentheses michael@0: * count plus one for the "0 capturing paren" whole text match. michael@0: */ michael@0: michael@0: namespace js { michael@0: michael@0: struct MatchPair michael@0: { michael@0: int start; michael@0: int limit; michael@0: michael@0: MatchPair() michael@0: : start(-1), limit(-1) michael@0: { } michael@0: michael@0: MatchPair(int start, int limit) michael@0: : start(start), limit(limit) michael@0: { } michael@0: michael@0: size_t length() const { JS_ASSERT(!isUndefined()); return limit - start; } michael@0: bool isEmpty() const { return length() == 0; } michael@0: bool isUndefined() const { return start < 0; } michael@0: michael@0: void displace(size_t amount) { michael@0: start += (start < 0) ? 0 : amount; michael@0: limit += (limit < 0) ? 0 : amount; michael@0: } michael@0: michael@0: inline bool check() const { michael@0: JS_ASSERT(limit >= start); michael@0: JS_ASSERT_IF(start < 0, start == -1); michael@0: JS_ASSERT_IF(limit < 0, limit == -1); michael@0: return true; michael@0: } michael@0: }; michael@0: michael@0: /* Base class for RegExp execution output. */ michael@0: class MatchPairs michael@0: { michael@0: protected: michael@0: size_t pairCount_; /* Length of pairs_. */ michael@0: MatchPair *pairs_; /* Raw pointer into an allocated MatchPair buffer. */ michael@0: michael@0: protected: michael@0: /* Not used directly: use ScopedMatchPairs or VectorMatchPairs. */ michael@0: MatchPairs() michael@0: : pairCount_(0), pairs_(nullptr) michael@0: { } michael@0: michael@0: protected: michael@0: /* Functions used by friend classes. */ michael@0: friend class RegExpShared; michael@0: friend class RegExpStatics; michael@0: michael@0: /* MatchPair buffer allocator: set pairs_ and pairCount_. */ michael@0: virtual bool allocOrExpandArray(size_t pairCount) = 0; michael@0: michael@0: bool initArray(size_t pairCount); michael@0: bool initArrayFrom(MatchPairs ©From); michael@0: void forgetArray() { pairs_ = nullptr; } michael@0: michael@0: void displace(size_t disp); michael@0: void checkAgainst(size_t inputLength) { michael@0: #ifdef DEBUG michael@0: for (size_t i = 0; i < pairCount_; i++) { michael@0: const MatchPair &p = pair(i); michael@0: JS_ASSERT(p.check()); michael@0: if (p.isUndefined()) michael@0: continue; michael@0: JS_ASSERT(size_t(p.limit) <= inputLength); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: public: michael@0: /* Querying functions in the style of RegExpStatics. */ michael@0: bool empty() const { return pairCount_ == 0; } michael@0: size_t pairCount() const { JS_ASSERT(pairCount_ > 0); return pairCount_; } michael@0: size_t parenCount() const { return pairCount_ - 1; } michael@0: michael@0: public: michael@0: unsigned *rawBuf() const { return reinterpret_cast(pairs_); } michael@0: size_t length() const { return pairCount_; } michael@0: michael@0: /* Pair accessors. */ michael@0: const MatchPair &pair(size_t i) const { michael@0: JS_ASSERT(pairCount_ && i < pairCount_); michael@0: JS_ASSERT(pairs_); michael@0: return pairs_[i]; michael@0: } michael@0: michael@0: const MatchPair &operator[](size_t i) const { return pair(i); } michael@0: }; michael@0: michael@0: /* MatchPairs allocated into temporary storage, removed when out of scope. */ michael@0: class ScopedMatchPairs : public MatchPairs michael@0: { michael@0: LifoAllocScope lifoScope_; michael@0: michael@0: public: michael@0: /* Constructs an implicit LifoAllocScope. */ michael@0: ScopedMatchPairs(LifoAlloc *lifoAlloc) michael@0: : lifoScope_(lifoAlloc) michael@0: { } michael@0: michael@0: const MatchPair &operator[](size_t i) const { return pair(i); } michael@0: michael@0: protected: michael@0: bool allocOrExpandArray(size_t pairCount); michael@0: }; michael@0: michael@0: /* michael@0: * MatchPairs allocated into permanent storage, for RegExpStatics. michael@0: * The Vector of MatchPairs is reusable by Vector expansion. michael@0: */ michael@0: class VectorMatchPairs : public MatchPairs michael@0: { michael@0: Vector vec_; michael@0: michael@0: public: michael@0: VectorMatchPairs() { michael@0: vec_.clear(); michael@0: } michael@0: michael@0: const MatchPair &operator[](size_t i) const { return pair(i); } michael@0: michael@0: protected: michael@0: friend class RegExpStatics; michael@0: bool allocOrExpandArray(size_t pairCount); michael@0: }; michael@0: michael@0: /* michael@0: * Passes either MatchPair or MatchPairs through ExecuteRegExp() michael@0: * to avoid duplication of generic code. michael@0: */ michael@0: struct MatchConduit michael@0: { michael@0: union { michael@0: MatchPair *pair; michael@0: MatchPairs *pairs; michael@0: } u; michael@0: bool isPair; michael@0: michael@0: explicit MatchConduit(MatchPair *pair) { michael@0: isPair = true; michael@0: u.pair = pair; michael@0: } michael@0: explicit MatchConduit(MatchPairs *pairs) { michael@0: isPair = false; michael@0: u.pairs = pairs; michael@0: } michael@0: }; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif /* vm_MatchPairs_h */