diff --git a/runtime/Cpp/runtime/src/atn/ATNConfigSet.h b/runtime/Cpp/runtime/src/atn/ATNConfigSet.h
index 602e818f0e3..f55a2a21941 100755
--- a/runtime/Cpp/runtime/src/atn/ATNConfigSet.h
+++ b/runtime/Cpp/runtime/src/atn/ATNConfigSet.h
@@ -46,7 +46,7 @@ namespace atn {
ATNConfigSet(const ATNConfigSet &other);
- ATNConfigSet(ATNConfigSet &&) = delete;
+ ATNConfigSet(ATNConfigSet&&) = delete;
explicit ATNConfigSet(bool fullCtx);
@@ -68,7 +68,7 @@ namespace atn {
bool addAll(const ATNConfigSet &other);
- std::vector getStates() const;
+ std::vector getStates() const;
/**
* Gets the complete set of represented alternatives for the configuration
diff --git a/runtime/Cpp/runtime/src/atn/ATNSimulator.cpp b/runtime/Cpp/runtime/src/atn/ATNSimulator.cpp
index 25c0c2f3eb4..3abe6882ff9 100755
--- a/runtime/Cpp/runtime/src/atn/ATNSimulator.cpp
+++ b/runtime/Cpp/runtime/src/atn/ATNSimulator.cpp
@@ -23,12 +23,11 @@ void ATNSimulator::clearDFA() {
throw UnsupportedOperationException("This ATN simulator does not support clearing the DFA.");
}
-PredictionContextCache& ATNSimulator::getSharedContextCache() {
+PredictionContextCache& ATNSimulator::getSharedContextCache() const {
return _sharedContextCache;
}
-Ref ATNSimulator::getCachedContext(Ref const& context) {
+Ref ATNSimulator::getCachedContext(const Ref &context) {
// This function must only be called with an active state lock, as we are going to change a shared structure.
- std::map[, Ref> visited;
- return PredictionContext::getCachedContext(context, _sharedContextCache, visited);
+ return PredictionContext::getCachedContext(context, getSharedContextCache());
}
diff --git a/runtime/Cpp/runtime/src/atn/ATNSimulator.h b/runtime/Cpp/runtime/src/atn/ATNSimulator.h
index 2dfb4bd953f..2c842c03d42 100755
--- a/runtime/Cpp/runtime/src/atn/ATNSimulator.h
+++ b/runtime/Cpp/runtime/src/atn/ATNSimulator.h
@@ -37,8 +37,9 @@ namespace atn {
* @since 4.3
*/
virtual void clearDFA();
- virtual PredictionContextCache& getSharedContextCache();
- virtual Ref getCachedContext(Ref const& context);
+
+ PredictionContextCache& getSharedContextCache() const;
+ Ref getCachedContext(const Ref &context);
protected:
///
diff --git a/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.cpp b/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.cpp
index b5b12612502..2bd2139fe49 100755
--- a/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.cpp
+++ b/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.cpp
@@ -4,11 +4,14 @@
*/
#include "support/Arrays.h"
+#include "support/Casts.h"
#include "atn/SingletonPredictionContext.h"
+#include "misc/MurmurHash.h"
#include "atn/ArrayPredictionContext.h"
using namespace antlr4::atn;
+using namespace antlrcpp;
ArrayPredictionContext::ArrayPredictionContext(Ref const& a)
: ArrayPredictionContext({ a->parent }, { a->returnState }) {
@@ -16,9 +19,10 @@ ArrayPredictionContext::ArrayPredictionContext(Ref> parents,
std::vector returnStates)
- : PredictionContext(calculateHashCode(parents, returnStates)), parents(std::move(parents)), returnStates(std::move(returnStates)) {
+ : parents(std::move(parents)), returnStates(std::move(returnStates)) {
assert(this->parents.size() > 0);
assert(this->returnStates.size() > 0);
+ assert(this->parents.size() == this->returnStates.size());
}
PredictionContextType ArrayPredictionContext::getContextType() const {
@@ -34,7 +38,7 @@ size_t ArrayPredictionContext::size() const {
return returnStates.size();
}
-Ref ArrayPredictionContext::getParent(size_t index) const {
+const Ref& ArrayPredictionContext::getParent(size_t index) const {
return parents[index];
}
@@ -42,21 +46,28 @@ size_t ArrayPredictionContext::getReturnState(size_t index) const {
return returnStates[index];
}
-bool ArrayPredictionContext::operator == (PredictionContext const& o) const {
- if (this == &o) {
- return true;
+size_t ArrayPredictionContext::hashCodeImpl() const {
+ size_t hash = misc::MurmurHash::initialize();
+ hash = misc::MurmurHash::update(hash, static_cast(getContextType()));
+ for (const auto &parent : parents) {
+ hash = misc::MurmurHash::update(hash, parent);
}
- if (o.getContextType() != PredictionContextType::ARRAY) {
- return false;
+ for (const auto &returnState : returnStates) {
+ hash = misc::MurmurHash::update(hash, returnState);
}
+ return misc::MurmurHash::finish(hash, 1 + parents.size() + returnStates.size());
+}
- const ArrayPredictionContext *other = static_cast(&o);
- if (hashCode() != other->hashCode()) {
- return false; // can't be same if hash is different
+bool ArrayPredictionContext::equals(const PredictionContext &other) const {
+ if (this == &other) {
+ return true;
}
-
- return antlrcpp::Arrays::equals(returnStates, other->returnStates) &&
- antlrcpp::Arrays::equals(parents, other->parents);
+ if (getContextType() != other.getContextType()) {
+ return false;
+ }
+ const ArrayPredictionContext &array = downCast(other);
+ return Arrays::equals(returnStates, array.returnStates) &&
+ Arrays::equals(parents, array.parents);
}
std::string ArrayPredictionContext::toString() const {
diff --git a/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.h b/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.h
index da405668d0c..377167d3fcc 100755
--- a/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.h
+++ b/runtime/Cpp/runtime/src/atn/ArrayPredictionContext.h
@@ -20,24 +20,27 @@ namespace atn {
/// returnState == EMPTY_RETURN_STATE.
// Also here: we use a strong reference to our parents to avoid having them freed prematurely.
// See also SinglePredictionContext.
- const std::vector][> parents;
+ std::vector][> parents;
/// Sorted for merge, no duplicates; if present, EMPTY_RETURN_STATE is always last.
- const std::vector returnStates;
+ std::vector returnStates;
explicit ArrayPredictionContext(Ref const &a);
ArrayPredictionContext(std::vector][> parents, std::vector returnStates);
- PredictionContextType getContextType() const override;
-
- virtual bool isEmpty() const override;
- virtual size_t size() const override;
- virtual Ref getParent(size_t index) const override;
- virtual size_t getReturnState(size_t index) const override;
- bool operator == (const PredictionContext &o) const override;
+ ArrayPredictionContext(ArrayPredictionContext&&) = default;
- virtual std::string toString() const override;
+ PredictionContextType getContextType() const override;
+ bool isEmpty() const override;
+ size_t size() const override;
+ const Ref& getParent(size_t index) const override;
+ size_t getReturnState(size_t index) const override;
+ bool equals(const PredictionContext &other) const override;
+ std::string toString() const override;
+
+ protected:
+ size_t hashCodeImpl() const override;
};
} // namespace atn
diff --git a/runtime/Cpp/runtime/src/atn/PredictionContext.cpp b/runtime/Cpp/runtime/src/atn/PredictionContext.cpp
index 5e1a18f01c9..b3d39611aaf 100755
--- a/runtime/Cpp/runtime/src/atn/PredictionContext.cpp
+++ b/runtime/Cpp/runtime/src/atn/PredictionContext.cpp
@@ -18,16 +18,120 @@
using namespace antlr4;
using namespace antlr4::misc;
using namespace antlr4::atn;
-
using namespace antlrcpp;
-std::atomic PredictionContext::globalNodeCount(0);
+namespace {
+
+ bool combineCommonParents(std::vector][> &parents) {
+ std::unordered_set][> uniqueParents;
+ bool changed = false;
+ for (const auto &parent : parents) {
+ uniqueParents.insert(parent);
+ }
+ for (auto &parent : parents) {
+ auto iterator = uniqueParents.find(parent);
+ if (iterator->get() != parent.get()) {
+ changed = true;
+ parent = *iterator;
+ }
+ }
+ return changed;
+ }
+
+ Ref getCachedContextImpl(const Ref &context,
+ PredictionContextCache &contextCache,
+ std::unordered_map][, Ref> &visited) {
+ if (context->isEmpty()) {
+ return context;
+ }
+
+ {
+ auto iterator = visited.find(context);
+ if (iterator != visited.end()) {
+ return iterator->second; // Not necessarly the same as context.
+ }
+ }
+
+ auto cached = contextCache.get(context);
+ if (cached) {
+ visited[context] = cached;
+ return cached;
+ }
+
+ bool changed = false;
+
+ std::vector][> parents(context->size());
+ for (size_t i = 0; i < parents.size(); i++) {
+ auto parent = getCachedContextImpl(context->getParent(i), contextCache, visited);
+ if (changed || parent != context->getParent(i)) {
+ if (!changed) {
+ parents.clear();
+ for (size_t j = 0; j < context->size(); j++) {
+ parents.push_back(context->getParent(j));
+ }
+
+ changed = true;
+ }
+
+ parents[i] = std::move(parent);
+ }
+ }
+
+ if (!changed) {
+ visited[context] = context;
+ contextCache.put(context);
+ return context;
+ }
+
+ Ref updated;
+ if (parents.empty()) {
+ updated = PredictionContext::EMPTY;
+ } else if (parents.size() == 1) {
+ updated = SingletonPredictionContext::create(std::move(parents[0]), context->getReturnState(0));
+ contextCache.put(updated);
+ } else {
+ updated = std::make_shared(std::move(parents), downCast(context.get())->returnStates);
+ contextCache.put(updated);
+ }
+
+ visited[updated] = updated;
+ visited[context] = updated;
+
+ return updated;
+ }
+
+ void getAllContextNodesImpl(const Ref &context, std::vector][> &nodes,
+ std::unordered_set &visited) {
+
+ if (visited.find(context.get()) != visited.end()) {
+ return; // Already done.
+ }
+
+ visited.insert(context.get());
+ nodes.push_back(context);
+
+ for (size_t i = 0; i < context->size(); i++) {
+ getAllContextNodesImpl(context->getParent(i), nodes, visited);
+ }
+ }
+
+ size_t insertOrAssignNodeId(std::unordered_map &nodeIds, size_t &nodeId, const PredictionContext *node) {
+ auto existing = nodeIds.find(node);
+ if (existing != nodeIds.end()) {
+ return existing->second;
+ }
+ return nodeIds.insert({node, nodeId++}).first->second;
+ }
+
+}
+
const Ref PredictionContext::EMPTY = std::make_shared(nullptr, PredictionContext::EMPTY_RETURN_STATE);
//----------------- PredictionContext ----------------------------------------------------------------------------------
-PredictionContext::PredictionContext(size_t cachedHashCode) : id(globalNodeCount.fetch_add(1, std::memory_order_relaxed)), cachedHashCode(cachedHashCode) {
-}
+PredictionContext::PredictionContext() : _hashCode(0) {}
+
+PredictionContext::PredictionContext(PredictionContext&& other) : _hashCode(other._hashCode.exchange(0, std::memory_order_relaxed)) {}
Ref PredictionContext::fromRuleContext(const ATN &atn, RuleContext *outerContext) {
if (outerContext == nullptr) {
@@ -41,15 +145,14 @@ Ref PredictionContext::fromRuleContext(const ATN &atn,
}
// If we have a parent, convert it to a PredictionContext graph
- Ref parent = PredictionContext::fromRuleContext(atn, dynamic_cast(outerContext->parent));
+ auto parent = PredictionContext::fromRuleContext(atn,
+ outerContext->parent != nullptr && outerContext->parent->getTreeType() == antlr4::tree::ParseTreeType::RULE
+ ? downCast(outerContext->parent)
+ : nullptr);
ATNState *state = atn.states.at(outerContext->invokingState);
const RuleTransition *transition = downCast(state->transitions[0].get());
- return SingletonPredictionContext::create(parent, transition->followState->stateNumber);
-}
-
-bool PredictionContext::isEmpty() const {
- return this == EMPTY.get();
+ return SingletonPredictionContext::create(std::move(parent), transition->followState->stateNumber);
}
bool PredictionContext::hasEmptyPath() const {
@@ -58,40 +161,19 @@ bool PredictionContext::hasEmptyPath() const {
}
size_t PredictionContext::hashCode() const {
- return cachedHashCode;
-}
-
-size_t PredictionContext::calculateEmptyHashCode() {
- size_t hash = MurmurHash::initialize(INITIAL_HASH);
- hash = MurmurHash::finish(hash, 0);
- return hash;
-}
-
-size_t PredictionContext::calculateHashCode(Ref parent, size_t returnState) {
- size_t hash = MurmurHash::initialize(INITIAL_HASH);
- hash = MurmurHash::update(hash, parent);
- hash = MurmurHash::update(hash, returnState);
- hash = MurmurHash::finish(hash, 2);
- return hash;
-}
-
-size_t PredictionContext::calculateHashCode(const std::vector][> &parents,
- const std::vector &returnStates) {
- size_t hash = MurmurHash::initialize(INITIAL_HASH);
-
- for (const auto &parent : parents) {
- hash = MurmurHash::update(hash, parent);
- }
-
- for (const auto &returnState : returnStates) {
- hash = MurmurHash::update(hash, returnState);
+ auto hash = _hashCode.load(std::memory_order_relaxed);
+ if (hash == 0) {
+ hash = hashCodeImpl();
+ if (hash == 0) {
+ hash = std::numeric_limits::max();
+ }
+ _hashCode.store(hash, std::memory_order_relaxed);
}
-
- return MurmurHash::finish(hash, parents.size() + returnStates.size());
+ return hash;
}
-Ref PredictionContext::merge(const Ref &a,
- const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache) {
+Ref PredictionContext::merge(Ref a, Ref b,
+ bool rootIsWildcard, PredictionContextMergeCache *mergeCache) {
assert(a && b);
// share same graph if both same
@@ -103,8 +185,8 @@ Ref PredictionContext::merge(const RefgetContextType();
if (aType == PredictionContextType::SINGLETON && bType == PredictionContextType::SINGLETON) {
- return mergeSingletons(std::static_pointer_cast(a),
- std::static_pointer_cast(b), rootIsWildcard, mergeCache);
+ return mergeSingletons(std::static_pointer_cast(std::move(a)),
+ std::static_pointer_cast(std::move(b)), rootIsWildcard, mergeCache);
}
// At least one of a or b is array.
@@ -121,23 +203,23 @@ Ref PredictionContext::merge(const Ref left;
if (aType == PredictionContextType::SINGLETON) {
- left = std::make_shared(std::static_pointer_cast(a));
+ left = std::make_shared(std::static_pointer_cast(std::move(a)));
} else {
- left = std::static_pointer_cast(a);
+ left = std::static_pointer_cast(std::move(a));
}
Ref right;
if (bType == PredictionContextType::SINGLETON) {
- right = std::make_shared(std::static_pointer_cast(b));
+ right = std::make_shared(std::static_pointer_cast(std::move(b)));
} else {
- right = std::static_pointer_cast(b);
+ right = std::static_pointer_cast(std::move(b));
}
- return mergeArrays(left, right, rootIsWildcard, mergeCache);
+ return mergeArrays(std::move(left), std::move(right), rootIsWildcard, mergeCache);
}
-Ref PredictionContext::mergeSingletons(const Ref &a,
- const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache) {
+Ref PredictionContext::mergeSingletons(Ref a, Ref b,
+ bool rootIsWildcard, PredictionContextMergeCache *mergeCache) {
- if (mergeCache != nullptr) { // Can be null if not given to the ATNState from which this call originates.
+ if (mergeCache) {
auto existing = mergeCache->get(a, b);
if (existing) {
return existing;
@@ -148,18 +230,18 @@ Ref PredictionContext::mergeSingletons(const Ref rootMerge = mergeRoot(a, b, rootIsWildcard);
+ auto rootMerge = mergeRoot(a, b, rootIsWildcard);
if (rootMerge) {
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, rootMerge);
+ if (mergeCache) {
+ return mergeCache->put(a, b, rootMerge);
}
return rootMerge;
}
- Ref parentA = a->parent;
- Ref parentB = b->parent;
+ auto parentA = a->parent;
+ auto parentB = b->parent;
if (a->returnState == b->returnState) { // a == b
- Ref parent = merge(parentA, parentB, rootIsWildcard, mergeCache);
+ auto parent = merge(parentA, parentB, rootIsWildcard, mergeCache);
// If parent is same as existing a or b parent or reduced to a parent, return it.
if (parent == parentA) { // ax + bx = ax, if a=b
@@ -173,55 +255,55 @@ Ref PredictionContext::mergeSingletons(const Ref a_ = SingletonPredictionContext::create(parent, a->returnState);
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, a_);
- }
- return a_;
- } else {
- // a != b payloads differ
- // see if we can collapse parents due to $+x parents if local ctx
- Ref singleParent;
- if (a == b || (*parentA == *parentB)) { // ax + bx = [a,b]x
- singleParent = parentA;
- }
- if (singleParent) { // parents are same, sort payloads and use same parent
- std::vector payloads = { a->returnState, b->returnState };
- if (a->returnState > b->returnState) {
- payloads[0] = b->returnState;
- payloads[1] = a->returnState;
- }
- std::vector][> parents = { singleParent, singleParent };
- Ref a_ = std::make_shared(std::move(parents), std::move(payloads));
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, a_);
- }
- return a_;
- }
-
- // parents differ and can't merge them. Just pack together
- // into array; can't merge.
- // ax + by = [ax,by]
- Ref a_;
- if (a->returnState > b->returnState) { // sort by payload
- std::vector payloads = { b->returnState, a->returnState };
- std::vector][> parents = { b->parent, a->parent };
- a_ = std::make_shared(std::move(parents), std::move(payloads));
- } else {
- std::vector payloads = {a->returnState, b->returnState};
- std::vector][> parents = { a->parent, b->parent };
- a_ = std::make_shared(std::move(parents), std::move(payloads));
- }
-
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, a_);
- }
- return a_;
- }
+ auto c = SingletonPredictionContext::create(std::move(parent), a->returnState);
+ if (mergeCache) {
+ return mergeCache->put(a, b, std::move(c));
+ }
+ return c;
+ }
+ // a != b payloads differ
+ // see if we can collapse parents due to $+x parents if local ctx
+ Ref singleParent;
+ if (a == b || (*parentA == *parentB)) { // ax + bx = [a,b]x
+ singleParent = parentA;
+ }
+ if (singleParent) { // parents are same, sort payloads and use same parent
+ std::vector payloads = { a->returnState, b->returnState };
+ if (a->returnState > b->returnState) {
+ payloads[0] = b->returnState;
+ payloads[1] = a->returnState;
+ }
+ std::vector][> parents = { singleParent, singleParent };
+ auto c = std::make_shared(std::move(parents), std::move(payloads));
+ if (mergeCache) {
+ return mergeCache->put(a, b, std::move(c));
+ }
+ return c;
+ }
+
+ // parents differ and can't merge them. Just pack together
+ // into array; can't merge.
+ // ax + by = [ax,by]
+ if (a->returnState > b->returnState) { // sort by payload
+ std::vector payloads = { b->returnState, a->returnState };
+ std::vector][> parents = { b->parent, a->parent };
+ auto c = std::make_shared(std::move(parents), std::move(payloads));
+ if (mergeCache) {
+ return mergeCache->put(a, b, std::move(c));
+ }
+ return c;
+ }
+ std::vector payloads = {a->returnState, b->returnState};
+ std::vector][> parents = { a->parent, b->parent };
+ auto c = std::make_shared(std::move(parents), std::move(payloads));
+ if (mergeCache) {
+ return mergeCache->put(a, b, std::move(c));
+ }
+ return c;
}
-Ref PredictionContext::mergeRoot(const Ref &a,
- const Ref &b, bool rootIsWildcard) {
+Ref PredictionContext::mergeRoot(Ref a, Ref b,
+ bool rootIsWildcard) {
if (rootIsWildcard) {
if (a == EMPTY) { // * + b = *
return EMPTY;
@@ -236,23 +318,21 @@ Ref PredictionContext::mergeRoot(const Ref payloads = { b->returnState, EMPTY_RETURN_STATE };
std::vector][> parents = { b->parent, nullptr };
- Ref joined = std::make_shared(std::move(parents), std::move(payloads));
- return joined;
+ return std::make_shared(std::move(parents), std::move(payloads));
}
if (b == EMPTY) { // x + $ = [$,x] ($ is always first if present)
std::vector payloads = { a->returnState, EMPTY_RETURN_STATE };
std::vector][> parents = { a->parent, nullptr };
- Ref joined = std::make_shared(std::move(parents), std::move(payloads));
- return joined;
+ return std::make_shared(std::move(parents), std::move(payloads));
}
}
return nullptr;
}
-Ref PredictionContext::mergeArrays(const Ref &a,
- const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache) {
+Ref PredictionContext::mergeArrays(Ref a, Ref b,
+ bool rootIsWildcard, PredictionContextMergeCache *mergeCache) {
- if (mergeCache != nullptr) {
+ if (mergeCache) {
auto existing = mergeCache->get(a, b);
if (existing) {
return existing;
@@ -273,32 +353,29 @@ Ref PredictionContext::mergeArrays(const RefreturnStates.size() && j < b->returnStates.size()) {
- Ref a_parent = a->parents[i];
- Ref b_parent = b->parents[j];
+ auto parentA = a->parents[i];
+ auto parentB = b->parents[j];
if (a->returnStates[i] == b->returnStates[j]) {
// same payload (stack tops are equal), must yield merged singleton
size_t payload = a->returnStates[i];
// $+$ = $
- bool both$ = payload == EMPTY_RETURN_STATE && !a_parent && !b_parent;
- bool ax_ax = (a_parent && b_parent) && *a_parent == *b_parent; // ax+ax -> ax
+ bool both$ = payload == EMPTY_RETURN_STATE && !parentA && !parentB;
+ bool ax_ax = (parentA && parentB) && *parentA == *parentB; // ax+ax -> ax
if (both$ || ax_ax) {
- mergedParents[k] = a_parent; // choose left
+ mergedParents[k] = std::move(parentA); // choose left
mergedReturnStates[k] = payload;
- }
- else { // ax+ay -> a'[x,y]
- Ref mergedParent = merge(a_parent, b_parent, rootIsWildcard, mergeCache);
- mergedParents[k] = mergedParent;
+ } else { // ax+ay -> a'[x,y]
+ mergedParents[k] = merge(std::move(parentA), std::move(parentB), rootIsWildcard, mergeCache);
mergedReturnStates[k] = payload;
}
i++; // hop over left one as usual
j++; // but also skip one in right side since we merge
} else if (a->returnStates[i] < b->returnStates[j]) { // copy a[i] to M
- mergedParents[k] = a_parent;
+ mergedParents[k] = std::move(parentA);
mergedReturnStates[k] = a->returnStates[i];
i++;
- }
- else { // b > a, copy b[j] to M
- mergedParents[k] = b_parent;
+ } else { // b > a, copy b[j] to M
+ mergedParents[k] = std::move(parentB);
mergedReturnStates[k] = b->returnStates[j];
j++;
}
@@ -307,13 +384,13 @@ Ref PredictionContext::mergeArrays(const RefreturnStates.size()) {
- for (std::vector::size_type p = i; p < a->returnStates.size(); p++) {
+ for (auto p = i; p < a->returnStates.size(); p++) {
mergedParents[k] = a->parents[p];
mergedReturnStates[k] = a->returnStates[p];
k++;
}
} else {
- for (std::vector::size_type p = j; p < b->returnStates.size(); p++) {
+ for (auto p = j; p < b->returnStates.size(); p++) {
mergedParents[k] = b->parents[p];
mergedReturnStates[k] = b->returnStates[p];
k++;
@@ -323,60 +400,41 @@ Ref PredictionContext::mergeArrays(const Ref a_ = SingletonPredictionContext::create(mergedParents[0], mergedReturnStates[0]);
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, a_);
+ auto c = SingletonPredictionContext::create(std::move(mergedParents[0]), mergedReturnStates[0]);
+ if (mergeCache) {
+ return mergeCache->put(a, b, std::move(c));
}
- return a_;
+ return c;
}
mergedParents.resize(k);
mergedReturnStates.resize(k);
}
- Ref M = std::make_shared(mergedParents, mergedReturnStates);
+ ArrayPredictionContext m(std::move(mergedParents), std::move(mergedReturnStates));
// if we created same array as a or b, return that instead
// TODO: track whether this is possible above during merge sort for speed
- if (*M == *a) {
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, a);
+ if (m == *a) {
+ if (mergeCache) {
+ return mergeCache->put(a, b, a);
}
return a;
}
- if (*M == *b) {
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, b);
+ if (m == *b) {
+ if (mergeCache) {
+ return mergeCache->put(a, b, b);
}
return b;
}
- // ml: this part differs from Java code. We have to recreate the context as the parents array is copied on creation.
- if (combineCommonParents(mergedParents)) {
- mergedReturnStates.resize(mergedParents.size());
- M = std::make_shared(mergedParents, mergedReturnStates);
+ if (combineCommonParents(m.parents)) {
+ m.returnStates.resize(m.parents.size());
}
-
- if (mergeCache != nullptr) {
- mergeCache->put(a, b, M);
+ auto c = std::make_shared(std::move(m));
+ if (mergeCache) {
+ return mergeCache->put(a, b, std::move(c));
}
- return M;
-}
-
-bool PredictionContext::combineCommonParents(std::vector][> &parents) {
-
- std::set][> uniqueParents;
- for (size_t p = 0; p < parents.size(); ++p) {
- Ref parent = parents[p];
- if (uniqueParents.find(parent) == uniqueParents.end()) { // don't replace
- uniqueParents.insert(parent);
- }
- }
-
- for (size_t p = 0; p < parents.size(); ++p) {
- parents[p] = *uniqueParents.find(parents[p]);
- }
-
- return true;
+ return c;
}
std::string PredictionContext::toDOTString(const Ref &context) {
@@ -388,13 +446,12 @@ std::string PredictionContext::toDOTString(const Ref &c
ss << "digraph G {\n" << "rankdir=LR;\n";
std::vector][> nodes = getAllContextNodes(context);
- std::sort(nodes.begin(), nodes.end(), [](const Ref &o1, const Ref &o2) {
- return o1->id - o2->id;
- });
+ std::unordered_map nodeIds;
+ size_t nodeId = 0;
for (const auto ¤t : nodes) {
if (current->getContextType() == PredictionContextType::SINGLETON) {
- std::string s = std::to_string(current->id);
+ std::string s = std::to_string(insertOrAssignNodeId(nodeIds, nodeId, current.get()));
ss << " s" << s;
std::string returnState = std::to_string(current->getReturnState(0));
if (current == PredictionContext::EMPTY) {
@@ -404,7 +461,7 @@ std::string PredictionContext::toDOTString(const Ref &c
continue;
}
Ref arr = std::static_pointer_cast(current);
- ss << " s" << arr->id << " [shape=box, label=\"" << "[";
+ ss << " s" << insertOrAssignNodeId(nodeIds, nodeId, arr.get()) << " [shape=box, label=\"" << "[";
bool first = true;
for (auto inv : arr->returnStates) {
if (!first) {
@@ -429,7 +486,7 @@ std::string PredictionContext::toDOTString(const Ref &c
if (!current->getParent(i)) {
continue;
}
- ss << " s" << current->id << "->" << "s" << current->getParent(i)->id;
+ ss << " s" << insertOrAssignNodeId(nodeIds, nodeId, current.get()) << "->" << "s" << insertOrAssignNodeId(nodeIds, nodeId, current->getParent(i).get());
if (current->size() > 1) {
ss << " [label=\"parent[" << i << "]\"];\n";
} else {
@@ -444,104 +501,23 @@ std::string PredictionContext::toDOTString(const Ref &c
// The "visited" map is just a temporary structure to control the retrieval process (which is recursive).
Ref PredictionContext::getCachedContext(const Ref &context,
- PredictionContextCache &contextCache, std::map][, Ref> &visited) {
- if (context->isEmpty()) {
- return context;
- }
-
- {
- auto iterator = visited.find(context);
- if (iterator != visited.end())
- return iterator->second; // Not necessarly the same as context.
- }
-
- auto iterator = contextCache.find(context);
- if (iterator != contextCache.end()) {
- visited[context] = *iterator;
-
- return *iterator;
- }
-
- bool changed = false;
-
- std::vector][> parents(context->size());
- for (size_t i = 0; i < parents.size(); i++) {
- Ref parent = getCachedContext(context->getParent(i), contextCache, visited);
- if (changed || parent != context->getParent(i)) {
- if (!changed) {
- parents.clear();
- for (size_t j = 0; j < context->size(); j++) {
- parents.push_back(context->getParent(j));
- }
-
- changed = true;
- }
-
- parents[i] = parent;
- }
- }
-
- if (!changed) {
- contextCache.insert(context);
- visited[context] = context;
-
- return context;
- }
-
- Ref updated;
- if (parents.empty()) {
- updated = EMPTY;
- } else if (parents.size() == 1) {
- updated = SingletonPredictionContext::create(parents[0], context->getReturnState(0));
- contextCache.insert(updated);
- } else {
- updated = std::make_shared(parents, std::dynamic_pointer_cast(context)->returnStates);
- contextCache.insert(updated);
- }
-
- visited[updated] = updated;
- visited[context] = updated;
-
- return updated;
+ PredictionContextCache &contextCache) {
+ std::unordered_map][, Ref> visited;
+ return getCachedContextImpl(context, contextCache, visited);
}
std::vector][> PredictionContext::getAllContextNodes(const Ref &context) {
std::vector][> nodes;
- std::set visited;
- getAllContextNodes_(context, nodes, visited);
+ std::unordered_set visited;
+ getAllContextNodesImpl(context, nodes, visited);
return nodes;
}
-
-void PredictionContext::getAllContextNodes_(const Ref &context, std::vector][> &nodes,
- std::set &visited) {
-
- if (visited.find(context.get()) != visited.end()) {
- return; // Already done.
- }
-
- visited.insert(context.get());
- nodes.push_back(context);
-
- for (size_t i = 0; i < context->size(); i++) {
- getAllContextNodes_(context->getParent(i), nodes, visited);
- }
-}
-
-std::string PredictionContext::toString() const {
-
- return antlrcpp::toString(this);
-}
-
-std::string PredictionContext::toString(Recognizer * /*recog*/) const {
- return toString();
-}
-
-std::vector PredictionContext::toStrings(Recognizer *recognizer, int currentState) {
+std::vector PredictionContext::toStrings(Recognizer *recognizer, int currentState) const {
return toStrings(recognizer, EMPTY, currentState);
}
-std::vector PredictionContext::toStrings(Recognizer *recognizer, const Ref &stop, int currentState) {
+std::vector PredictionContext::toStrings(Recognizer *recognizer, const Ref &stop, int currentState) const {
std::vector result;
@@ -610,33 +586,39 @@ std::vector PredictionContext::toStrings(Recognizer *recognizer, co
return result;
}
-//----------------- PredictionContextMergeCache ------------------------------------------------------------------------
+//----------------- PredictionContextCache ------------------------------------------------------------------------
-Ref PredictionContextMergeCache::put(Ref const& key1, Ref const& key2,
- Ref const& value) {
- Ref previous;
+void PredictionContextCache::put(const Ref &value) {
+ _data.insert(value);
+}
- auto iterator = _data.find(key1);
- if (iterator == _data.end())
- _data[key1][key2] = value;
- else {
- auto iterator2 = iterator->second.find(key2);
- if (iterator2 != iterator->second.end())
- previous = iterator2->second;
- iterator->second[key2] = value;
+Ref PredictionContextCache::get(const Ref &value) const {
+ auto iterator = _data.find(value);
+ if (iterator == _data.end()) {
+ return nullptr;
}
+ return *iterator;
+}
- return previous;
+//----------------- PredictionContextMergeCache ------------------------------------------------------------------------
+
+Ref PredictionContextMergeCache::put(const Ref &key1,
+ const Ref &key2,
+ Ref value) {
+ return _data.try_emplace(key1).first->second.insert_or_assign(key2, std::move(value)).first->second;
}
-Ref PredictionContextMergeCache::get(Ref const& key1, Ref const& key2) {
- auto iterator = _data.find(key1);
- if (iterator == _data.end())
+Ref PredictionContextMergeCache::get(const Ref &key1,
+ const Ref &key2) const {
+ auto iterator1 = _data.find(key1);
+ if (iterator1 == _data.end()) {
return nullptr;
+ }
- auto iterator2 = iterator->second.find(key2);
- if (iterator2 == iterator->second.end())
+ auto iterator2 = iterator1->second.find(key2);
+ if (iterator2 == iterator1->second.end()) {
return nullptr;
+ }
return iterator2->second;
}
@@ -644,20 +626,3 @@ Ref PredictionContextMergeCache::get(ReftoString() + "\n";
-
- return result;
-}
-
-size_t PredictionContextMergeCache::count() const {
- size_t result = 0;
- for (const auto &entry : _data)
- result += entry.second.size();
- return result;
-}
-
diff --git a/runtime/Cpp/runtime/src/atn/PredictionContext.h b/runtime/Cpp/runtime/src/atn/PredictionContext.h
index 94bba89b56c..5c7f379e6a2 100755
--- a/runtime/Cpp/runtime/src/atn/PredictionContext.h
+++ b/runtime/Cpp/runtime/src/atn/PredictionContext.h
@@ -15,12 +15,9 @@
namespace antlr4 {
namespace atn {
- struct PredictionContextHasher;
- struct PredictionContextComparer;
+ class PredictionContextCache;
class PredictionContextMergeCache;
- typedef std::unordered_set][, PredictionContextHasher, PredictionContextComparer> PredictionContextCache;
-
class ANTLR4CPP_PUBLIC PredictionContext {
public:
/// Represents $ in local context prediction, which means wildcard.
@@ -35,69 +32,12 @@ namespace atn {
// conflict with real return states.
static constexpr size_t EMPTY_RETURN_STATE = std::numeric_limits::max() - 9;
- private:
- static constexpr size_t INITIAL_HASH = 1;
-
- public:
- static std::atomic globalNodeCount;
- const size_t id;
-
- ///
- /// Stores the computed hash code of this . The hash
- /// code is computed in parts to match the following reference algorithm.
- ///
- /// ]
- /// private int referenceHashCode() {
- /// int hash = ();
- ///
- /// for (int i = 0; i < ; i++) {
- /// hash = (hash, (i));
- /// }
- ///
- /// for (int i = 0; i < ; i++) {
- /// hash = (hash, (i));
- /// }
- ///
- /// hash = (hash, 2 * );
- /// return hash;
- /// }
- ///
- ///
- const size_t cachedHashCode;
-
- protected:
- explicit PredictionContext(size_t cachedHashCode);
-
- public:
- virtual ~PredictionContext() = default;
-
- virtual PredictionContextType getContextType() const = 0;
-
/// Convert a RuleContext tree to a PredictionContext graph.
/// Return EMPTY if outerContext is empty.
static Ref fromRuleContext(const ATN &atn, RuleContext *outerContext);
-
- virtual size_t size() const = 0;
- virtual Ref getParent(size_t index) const = 0;
- virtual size_t getReturnState(size_t index) const = 0;
-
- virtual bool operator == (const PredictionContext &o) const = 0;
-
- /// This means only the EMPTY (wildcard? not sure) context is in set.
- virtual bool isEmpty() const;
- virtual bool hasEmptyPath() const;
- virtual size_t hashCode() const;
-
- protected:
- static size_t calculateEmptyHashCode();
- static size_t calculateHashCode(Ref parent, size_t returnState);
- static size_t calculateHashCode(const std::vector[> &parents,
- const std::vector &returnStates);
-
- public:
// dispatch
- static Ref merge(const Ref &a, const Ref &b,
- bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
+ static Ref merge(Ref a, Ref b,
+ bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
///
/// Merge two instances.
@@ -133,8 +73,8 @@ namespace atn {
/// {@code true} if this is a local-context merge,
/// otherwise false to indicate a full-context merge
///
- static Ref mergeSingletons(const Ref &a,
- const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
+ static Ref mergeSingletons(Ref a, Ref b,
+ bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
/**
* Handle case where at least one of {@code a} or {@code b} is
@@ -174,8 +114,8 @@ namespace atn {
* @param rootIsWildcard {@code true} if this is a local-context merge,
* otherwise false to indicate a full-context merge
*/
- static Ref mergeRoot(const Ref &a,
- const Ref &b, bool rootIsWildcard);
+ static Ref mergeRoot(Ref a, Ref b,
+ bool rootIsWildcard);
/**
* Merge two {@link ArrayPredictionContext} instances.
@@ -196,65 +136,120 @@ namespace atn {
* {@link SingletonPredictionContext}.]
*
*/
- static Ref mergeArrays(const Ref &a,
- const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
-
- protected:
- /// Make pass over all M parents; merge any equal() ones.
- /// @returns true if the list has been changed (i.e. duplicates where found).
- static bool combineCommonParents(std::vector[> &parents);
+ static Ref mergeArrays(Ref a, Ref b,
+ bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
- public:
static std::string toDOTString(const Ref &context);
static Ref getCachedContext(const Ref &context,
- PredictionContextCache &contextCache,
- std::map][, Ref> &visited);
+ PredictionContextCache &contextCache);
// ter's recursive version of Sam's getAllNodes()
static std::vector][> getAllContextNodes(const Ref &context);
- static void getAllContextNodes_(const Ref &context,
- std::vector][> &nodes, std::set &visited);
- virtual std::string toString() const;
- virtual std::string toString(Recognizer *recog) const;
+ virtual ~PredictionContext() = default;
- std::vector toStrings(Recognizer *recognizer, int currentState);
- std::vector toStrings(Recognizer *recognizer, const Ref &stop, int currentState);
- };
+ virtual PredictionContextType getContextType() const = 0;
- struct PredictionContextHasher {
- size_t operator () (const Ref &k) const {
- return k->hashCode();
- }
+ virtual size_t size() const = 0;
+ virtual const Ref& getParent(size_t index) const = 0;
+ virtual size_t getReturnState(size_t index) const = 0;
+
+ /// This means only the EMPTY (wildcard? not sure) context is in set.
+ virtual bool isEmpty() const = 0;
+ bool hasEmptyPath() const;
+
+ size_t hashCode() const;
+
+ virtual bool equals(const PredictionContext &other) const = 0;
+
+ virtual std::string toString() const = 0;
+
+ std::vector toStrings(Recognizer *recognizer, int currentState) const;
+ std::vector toStrings(Recognizer *recognizer, const Ref &stop, int currentState) const;
+
+ protected:
+ PredictionContext();
+
+ PredictionContext(PredictionContext&& other);
+
+ virtual size_t hashCodeImpl() const = 0;
+
+ private:
+ mutable std::atomic _hashCode;
};
- struct PredictionContextComparer {
- bool operator () (const Ref &lhs, const Ref &rhs) const
- {
- if (lhs == rhs) // Object identity.
- return true;
- return (lhs->hashCode() == rhs->hashCode()) && (*lhs == *rhs);
- }
+ inline bool operator==(const PredictionContext &lhs, const PredictionContext &rhs) {
+ return lhs.equals(rhs);
+ }
+
+ inline bool operator!=(const PredictionContext &lhs, const PredictionContext &rhs) {
+ return !operator==(lhs, rhs);
+ }
+
+ class ANTLR4CPP_PUBLIC PredictionContextCache final {
+ public:
+ void put(const Ref &value);
+
+ Ref get(const Ref &value) const;
+
+ private:
+ struct PredictionContextHasher final {
+ size_t operator()(const Ref &predictionContext) const {
+ return predictionContext->hashCode();
+ }
+ };
+
+ struct PredictionContextComparer final {
+ bool operator()(const Ref &lhs, const Ref &rhs) const {
+ return *lhs == *rhs;
+ }
+ };
+
+ std::unordered_set][, PredictionContextHasher, PredictionContextComparer> _data;
};
- class PredictionContextMergeCache {
+ class ANTLR4CPP_PUBLIC PredictionContextMergeCache final {
public:
- Ref put(Ref const& key1, Ref const& key2,
- Ref const& value);
- Ref get(Ref const& key1, Ref const& key2);
+ Ref put(const Ref &key1,
+ const Ref &key2,
+ Ref value);
+
+ Ref get(const Ref &key1,
+ const Ref &key2) const;
void clear();
- std::string toString() const;
- size_t count() const;
private:
+ struct PredictionContextHasher final {
+ size_t operator()(const Ref &predictionContext) const {
+ return predictionContext->hashCode();
+ }
+ };
+
+ struct PredictionContextComparer final {
+ bool operator()(const Ref &lhs, const Ref &rhs) const {
+ return *lhs == *rhs;
+ }
+ };
+
std::unordered_map][,
- std::unordered_map][, Ref, PredictionContextHasher, PredictionContextComparer>,
+ std::unordered_map][, Ref,
+ PredictionContextHasher, PredictionContextComparer>,
PredictionContextHasher, PredictionContextComparer> _data;
};
-} // namespace atn
-} // namespace antlr4
+} // namespace atn
+} // namespace antlr4
+
+namespace std {
+
+ template <>
+ struct hash<::antlr4::atn::PredictionContext> {
+ size_t operator()(const ::antlr4::atn::PredictionContext &predictionContext) const {
+ return predictionContext.hashCode();
+ }
+ };
+} // namespace std
diff --git a/runtime/Cpp/runtime/src/atn/PredictionMode.cpp b/runtime/Cpp/runtime/src/atn/PredictionMode.cpp
index 755eb454429..f36d42f1625 100755
--- a/runtime/Cpp/runtime/src/atn/PredictionMode.cpp
+++ b/runtime/Cpp/runtime/src/atn/PredictionMode.cpp
@@ -73,8 +73,8 @@ bool PredictionModeClass::hasSLLConflictTerminatingPrediction(PredictionMode mod
}
bool PredictionModeClass::hasConfigInRuleStopState(ATNConfigSet *configs) {
- for (auto &c : configs->configs) {
- if (is(c->state)) {
+ for (const auto &config : configs->configs) {
+ if (config->state != nullptr && config->state->getStateType() == ATNStateType::RULE_STOP) {
return true;
}
}
@@ -84,7 +84,7 @@ bool PredictionModeClass::hasConfigInRuleStopState(ATNConfigSet *configs) {
bool PredictionModeClass::allConfigsInRuleStopStates(ATNConfigSet *configs) {
for (auto &config : configs->configs) {
- if (!is(config->state)) {
+ if (config->state == nullptr || config->state->getStateType() != ATNStateType::RULE_STOP) {
return false;
}
}
@@ -142,7 +142,7 @@ size_t PredictionModeClass::getUniqueAlt(const std::vector& al
antlrcpp::BitSet PredictionModeClass::getAlts(const std::vector& altsets) {
antlrcpp::BitSet all;
- for (antlrcpp::BitSet alts : altsets) {
+ for (const auto &alts : altsets) {
all |= alts;
}
@@ -151,43 +151,44 @@ antlrcpp::BitSet PredictionModeClass::getAlts(const std::vectorconfigs) {
+ for (const auto &config : configs->configs) {
alts.set(config->alt);
}
return alts;
}
std::vector PredictionModeClass::getConflictingAltSubsets(ATNConfigSet *configs) {
- std::unordered_map configToAlts;
+ std::unordered_map configToAlts;
for (auto &config : configs->configs) {
configToAlts[config.get()].set(config->alt);
}
std::vector values;
- for (auto it : configToAlts) {
- values.push_back(it.second);
+ values.reserve(configToAlts.size());
+ for (const auto &pair : configToAlts) {
+ values.push_back(pair.second);
}
return values;
}
-std::map PredictionModeClass::getStateToAltMap(ATNConfigSet *configs) {
- std::map m;
- for (auto &c : configs->configs) {
+std::unordered_map PredictionModeClass::getStateToAltMap(ATNConfigSet *configs) {
+ std::unordered_map m;
+ for (const auto &c : configs->configs) {
m[c->state].set(c->alt);
}
return m;
}
bool PredictionModeClass::hasStateAssociatedWithOneAlt(ATNConfigSet *configs) {
- std::map x = getStateToAltMap(configs);
- for (std::map::iterator it = x.begin(); it != x.end(); it++){
- if (it->second.count() == 1) return true;
+ auto x = getStateToAltMap(configs);
+ for (const auto &pair : x){
+ if (pair.second.count() == 1) return true;
}
return false;
}
size_t PredictionModeClass::getSingleViableAlt(const std::vector& altsets) {
antlrcpp::BitSet viableAlts;
- for (antlrcpp::BitSet alts : altsets) {
+ for (const auto &alts : altsets) {
size_t minAlt = alts.nextSetBit(0);
viableAlts.set(minAlt);
diff --git a/runtime/Cpp/runtime/src/atn/PredictionMode.h b/runtime/Cpp/runtime/src/atn/PredictionMode.h
index 726f4cf40f5..11d1bbe034b 100755
--- a/runtime/Cpp/runtime/src/atn/PredictionMode.h
+++ b/runtime/Cpp/runtime/src/atn/PredictionMode.h
@@ -425,7 +425,7 @@ namespace atn {
/// cref="ATNConfig#alt alt"/>
///
///
- static std::map getStateToAltMap(ATNConfigSet *configs);
+ static std::unordered_map getStateToAltMap(ATNConfigSet *configs);
static bool hasStateAssociatedWithOneAlt(ATNConfigSet *configs);
diff --git a/runtime/Cpp/runtime/src/atn/SemanticContext.h b/runtime/Cpp/runtime/src/atn/SemanticContext.h
index b7193332f78..22df35241e8 100755
--- a/runtime/Cpp/runtime/src/atn/SemanticContext.h
+++ b/runtime/Cpp/runtime/src/atn/SemanticContext.h
@@ -193,8 +193,6 @@ namespace atn {
} // namespace atn
} // namespace antlr4
-// Hash function for SemanticContext, used in the MurmurHash::update function
-
namespace std {
template <>
diff --git a/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.cpp b/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.cpp
index 5fe4f8aacd2..c65fc6bd783 100755
--- a/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.cpp
+++ b/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.cpp
@@ -5,16 +5,18 @@
#include "atn/SingletonPredictionContext.h"
+#include "support/Casts.h"
+#include "misc/MurmurHash.h"
+
using namespace antlr4::atn;
+using namespace antlrcpp;
SingletonPredictionContext::SingletonPredictionContext(Ref parent, size_t returnState)
- : PredictionContext(parent ? calculateHashCode(parent, returnState) : calculateEmptyHashCode()),
- parent(std::move(parent)), returnState(returnState) {
+ : parent(std::move(parent)), returnState(returnState) {
assert(returnState != ATNState::INVALID_STATE_NUMBER);
}
Ref SingletonPredictionContext::create(Ref parent, size_t returnState) {
-
if (returnState == EMPTY_RETURN_STATE && parent) {
// someone can pass in the bits of an array ctx that mean $
return std::dynamic_pointer_cast(EMPTY);
@@ -34,7 +36,7 @@ size_t SingletonPredictionContext::size() const {
return 1;
}
-Ref SingletonPredictionContext::getParent(size_t index) const {
+const Ref& SingletonPredictionContext::getParent(size_t index) const {
assert(index == 0);
((void)(index)); // Make Release build happy.
return parent;
@@ -46,29 +48,32 @@ size_t SingletonPredictionContext::getReturnState(size_t index) const {
return returnState;
}
-bool SingletonPredictionContext::operator == (const PredictionContext &o) const {
- if (this == &o) {
+size_t SingletonPredictionContext::hashCodeImpl() const {
+ size_t hash = misc::MurmurHash::initialize();
+ hash = misc::MurmurHash::update(hash, static_cast(getContextType()));
+ hash = misc::MurmurHash::update(hash, parent);
+ hash = misc::MurmurHash::update(hash, returnState);
+ return misc::MurmurHash::finish(hash, 3);
+}
+
+bool SingletonPredictionContext::equals(const PredictionContext &other) const {
+ if (this == &other) {
return true;
}
-
- if (o.getContextType() != PredictionContextType::SINGLETON) {
+ if (getContextType() != other.getContextType()) {
return false;
}
-
- const SingletonPredictionContext *other = static_cast(&o);
- if (this->hashCode() != other->hashCode()) {
- return false; // can't be same if hash is different
- }
-
- if (returnState != other->returnState)
+ const auto &singleton = downCast(other);
+ if (returnState != singleton.returnState) {
return false;
-
- if (!parent && !other->parent)
+ }
+ if (!parent && !singleton.parent) {
return true;
- if (!parent || !other->parent)
+ }
+ if (!parent || !singleton.parent) {
return false;
-
- return parent == other->parent || *parent == *other->parent;
+ }
+ return parent == singleton.parent || *parent == *singleton.parent;
}
std::string SingletonPredictionContext::toString() const {
diff --git a/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.h b/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.h
index 44af6d6df7d..46beb3b5754 100755
--- a/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.h
+++ b/runtime/Cpp/runtime/src/atn/SingletonPredictionContext.h
@@ -12,6 +12,8 @@ namespace atn {
class ANTLR4CPP_PUBLIC SingletonPredictionContext final : public PredictionContext {
public:
+ static Ref create(Ref parent, size_t returnState);
+
// Usually a parent is linked via a weak ptr. Not so here as we have kinda reverse reference chain.
// There are no child contexts stored here and often the parent context is left dangling when it's
// owning ATNState is released. In order to avoid having this context released as well (leaving all other contexts
@@ -21,18 +23,17 @@ namespace atn {
const size_t returnState;
SingletonPredictionContext(Ref parent, size_t returnState);
- virtual ~SingletonPredictionContext() = default;
-
- static Ref create(Ref parent, size_t returnState);
PredictionContextType getContextType() const override;
-
- virtual bool isEmpty() const override;
- virtual size_t size() const override;
- virtual Ref getParent(size_t index) const override;
- virtual size_t getReturnState(size_t index) const override;
- virtual bool operator == (const PredictionContext &o) const override;
- virtual std::string toString() const override;
+ bool isEmpty() const override;
+ size_t size() const override;
+ const Ref& getParent(size_t index) const override;
+ size_t getReturnState(size_t index) const override;
+ bool equals(const PredictionContext &other) const override;
+ std::string toString() const override;
+
+ protected:
+ size_t hashCodeImpl() const override;
};
} // namespace atn
diff --git a/runtime/Cpp/runtime/src/misc/IntervalSet.cpp b/runtime/Cpp/runtime/src/misc/IntervalSet.cpp
index 31f26b77616..ea910afe6e9 100755
--- a/runtime/Cpp/runtime/src/misc/IntervalSet.cpp
+++ b/runtime/Cpp/runtime/src/misc/IntervalSet.cpp
@@ -265,18 +265,13 @@ bool IntervalSet::contains(size_t el) const {
}
bool IntervalSet::contains(ssize_t el) const {
- if (_intervals.empty())
+ if (_intervals.empty() || el < _intervals.front().a || el > _intervals.back().b) {
return false;
-
- if (el < _intervals[0].a) // list is sorted and el is before first interval; not here
- return false;
-
- for (const auto &interval : _intervals) {
- if (el >= interval.a && el <= interval.b) {
- return true; // found in this interval
- }
}
- return false;
+
+ return std::binary_search(_intervals.begin(), _intervals.end(), Interval(el, el), [](const Interval &lhs, const Interval &rhs) {
+ return lhs.b < rhs.a;
+ });
}
bool IntervalSet::isEmpty() const {
@@ -306,7 +301,7 @@ ssize_t IntervalSet::getMinElement() const {
return Token::INVALID_TYPE;
}
- return _intervals[0].a;
+ return _intervals.front().a;
}
std::vector const& IntervalSet::getIntervals() const {
]