summaryrefslogtreecommitdiffstats
path: root/js/src/vm/MatchPairs.h
blob: 6bb60b46ddb3d9114e4146d175d76aea8e06049e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * 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 "js/AllocPolicy.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 final {
  int32_t start;
  int32_t limit;

  static constexpr int32_t NoMatch = -1;

  MatchPair() : start(NoMatch), limit(NoMatch) {}

  MatchPair(int32_t start, int32_t limit) : start(start), limit(limit) {}

  size_t length() const {
    MOZ_ASSERT(!isUndefined());
    return limit - start;
  }
  bool isUndefined() const { return start < 0; }

  inline bool check() const {
    MOZ_ASSERT(limit >= start);
    MOZ_ASSERT_IF(start < 0, start == NoMatch);
    MOZ_ASSERT_IF(limit < 0, limit == NoMatch);
    return true;
  }

  // Note: return int32_t instead of size_t to prevent signed => unsigned
  // conversions in caller functions.
  static constexpr int32_t offsetOfStart() {
    return int32_t(offsetof(MatchPair, start));
  }
  static constexpr int32_t offsetOfLimit() {
    return int32_t(offsetof(MatchPair, limit));
  }
};

// MachPairs is used as base class for VectorMatchPairs but can also be
// stack-allocated (without a Vector) in JIT code.
class MatchPairs {
 protected:
  /* Length of pairs_. */
  uint32_t pairCount_;

  /* Raw pointer into an allocated MatchPair buffer. */
  MatchPair* pairs_;

 protected:
  /* Not used directly: use VectorMatchPairs. */
  MatchPairs() : pairCount_(0), pairs_(nullptr) {}

 protected:
  /* Functions used by friend classes. */
  friend class RegExpShared;
  friend class RegExpStatics;

  void forgetArray() { pairs_ = nullptr; }

 public:
  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
  }

  /* Querying functions in the style of RegExpStatics. */
  bool empty() const { return pairCount_ == 0; }
  size_t pairCount() const {
    MOZ_ASSERT(pairCount_ > 0);
    return pairCount_;
  }

  // Note: return int32_t instead of size_t to prevent signed => unsigned
  // conversions in caller functions.
  static constexpr int32_t offsetOfPairs() {
    return int32_t(offsetof(MatchPairs, pairs_));
  }
  static constexpr int32_t offsetOfPairCount() {
    return int32_t(offsetof(MatchPairs, pairCount_));
  }

  int32_t* pairsRaw() { return reinterpret_cast<int32_t*>(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];
  }
};

class VectorMatchPairs : public MatchPairs {
  Vector<MatchPair, 10, SystemAllocPolicy> vec_;

 protected:
  friend class RegExpShared;
  friend class RegExpStatics;

  /* MatchPair buffer allocator: set pairs_ and pairCount_. */
  bool allocOrExpandArray(size_t pairCount);

  bool initArrayFrom(VectorMatchPairs& copyFrom);

  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    return vec_.sizeOfExcludingThis(mallocSizeOf);
  }
};

} /* namespace js */

#endif /* vm_MatchPairs_h */