package antlr // Copyright (c) 2012-2022 The ANTLR Project. All rights reserved. // Use of this file is governed by the BSD 3-clause license that // can be found in the LICENSE.txt file in the project root. // This file contains all the implementations of custom comparators used for generic collections when the // Hash() and Equals() funcs supplied by the struct objects themselves need to be overridden. Normally, we would // put the comparators in the source file for the struct themselves, but given the organization of this code is // sorta kinda based upon the Java code, I found it confusing trying to find out which comparator was where and used by // which instantiation of a collection. For instance, an Array2DHashSet in the Java source, when used with ATNConfig // collections requires three different comparators depending on what the collection is being used for. Collecting - pun intended - // all the comparators here, makes it much easier to see which implementation of hash and equals is used by which collection. // It also makes it easy to verify that the Hash() and Equals() functions marry up with the Java implementations. // ObjEqComparator is the equivalent of the Java ObjectEqualityComparator, which is the default instance of // Equality comparator. We do not have inheritance in Go, only interfaces, so we use generics to enforce some // type safety and avoid having to implement this for every type that we want to perform comparison on. // // This comparator works by using the standard Hash() and Equals() methods of the type T that is being compared. Which // allows us to use it in any collection instance that does not require a special hash or equals implementation. type ObjEqComparator[T Collectable[T]] struct{} var ( aStateEqInst = &ObjEqComparator[ATNState]{} aConfEqInst = &ObjEqComparator[*ATNConfig]{} // aConfCompInst is the comparator used for the ATNConfigSet for the configLookup cache aConfCompInst = &ATNConfigComparator[*ATNConfig]{} atnConfCompInst = &BaseATNConfigComparator[*ATNConfig]{} dfaStateEqInst = &ObjEqComparator[*DFAState]{} semctxEqInst = &ObjEqComparator[SemanticContext]{} atnAltCfgEqInst = &ATNAltConfigComparator[*ATNConfig]{} pContextEqInst = &ObjEqComparator[*PredictionContext]{} ) // Equals2 delegates to the Equals() method of type T func (c *ObjEqComparator[T]) Equals2(o1, o2 T) bool { return o1.Equals(o2) } // Hash1 delegates to the Hash() method of type T func (c *ObjEqComparator[T]) Hash1(o T) int { return o.Hash() } type SemCComparator[T Collectable[T]] struct{} // ATNConfigComparator is used as the comparator for the configLookup field of an ATNConfigSet // and has a custom Equals() and Hash() implementation, because equality is not based on the // standard Hash() and Equals() methods of the ATNConfig type. type ATNConfigComparator[T Collectable[T]] struct { } // Equals2 is a custom comparator for ATNConfigs specifically for configLookup func (c *ATNConfigComparator[T]) Equals2(o1, o2 *ATNConfig) bool { // Same pointer, must be equal, even if both nil // if o1 == o2 { return true } // If either are nil, but not both, then the result is false // if o1 == nil || o2 == nil { return false } return o1.GetState().GetStateNumber() == o2.GetState().GetStateNumber() && o1.GetAlt() == o2.GetAlt() && o1.GetSemanticContext().Equals(o2.GetSemanticContext()) } // Hash1 is custom hash implementation for ATNConfigs specifically for configLookup func (c *ATNConfigComparator[T]) Hash1(o *ATNConfig) int { hash := 7 hash = 31*hash + o.GetState().GetStateNumber() hash = 31*hash + o.GetAlt() hash = 31*hash + o.GetSemanticContext().Hash() return hash } // ATNAltConfigComparator is used as the comparator for mapping configs to Alt Bitsets type ATNAltConfigComparator[T Collectable[T]] struct { } // Equals2 is a custom comparator for ATNConfigs specifically for configLookup func (c *ATNAltConfigComparator[T]) Equals2(o1, o2 *ATNConfig) bool { // Same pointer, must be equal, even if both nil // if o1 == o2 { return true } // If either are nil, but not both, then the result is false // if o1 == nil || o2 == nil { return false } return o1.GetState().GetStateNumber() == o2.GetState().GetStateNumber() && o1.GetContext().Equals(o2.GetContext()) } // Hash1 is custom hash implementation for ATNConfigs specifically for configLookup func (c *ATNAltConfigComparator[T]) Hash1(o *ATNConfig) int { h := murmurInit(7) h = murmurUpdate(h, o.GetState().GetStateNumber()) h = murmurUpdate(h, o.GetContext().Hash()) return murmurFinish(h, 2) } // BaseATNConfigComparator is used as the comparator for the configLookup field of a ATNConfigSet // and has a custom Equals() and Hash() implementation, because equality is not based on the // standard Hash() and Equals() methods of the ATNConfig type. type BaseATNConfigComparator[T Collectable[T]] struct { } // Equals2 is a custom comparator for ATNConfigs specifically for baseATNConfigSet func (c *BaseATNConfigComparator[T]) Equals2(o1, o2 *ATNConfig) bool { // Same pointer, must be equal, even if both nil // if o1 == o2 { return true } // If either are nil, but not both, then the result is false // if o1 == nil || o2 == nil { return false } return o1.GetState().GetStateNumber() == o2.GetState().GetStateNumber() && o1.GetAlt() == o2.GetAlt() && o1.GetSemanticContext().Equals(o2.GetSemanticContext()) } // Hash1 is custom hash implementation for ATNConfigs specifically for configLookup, but in fact just // delegates to the standard Hash() method of the ATNConfig type. func (c *BaseATNConfigComparator[T]) Hash1(o *ATNConfig) int { return o.Hash() }