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