Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For container types, check hash code before deep equality #58

Open
dlurton opened this issue Aug 12, 2021 · 0 comments
Open

For container types, check hash code before deep equality #58

dlurton opened this issue Aug 12, 2021 · 0 comments

Comments

@dlurton
Copy link
Contributor

dlurton commented Aug 12, 2021

For example, the StructElementImpl class implements Any.equals using the code shown below. Checking if two containers are equal could be considerably faster if the Any.equals override for each container type considered the Any.hashCode before checking deep equality. The hash code is already lazily computed and never re-computed, so this has the potential to significantly increase performance for certain uses of this library.

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is StructElementImpl) return false

        // TODO: compare hash code here--if not equal, values are not equal

        if (annotations != other.annotations) return false

        // We might avoid materializing fieldsByName by checking fields.size first
        if (this.size != other.size) return false
        if (this.fieldsByName.size != other.fieldsByName.size) return false

        // If we make it this far we can compare the list of field names in both
        if(this.fieldsByName.keys != other.fieldsByName.keys) return false

        // If we make it this far then we have to take the expensive approach of comparing the individual values in
        // [this] and [other].
        //
        // A field group is a list of fields with the same name. Within each field group we count the number of times
        // each value appears in both [this] and [other]. Each field group is equivalent if every value that appears n
        // times in one group also appears n times in the other group.

        this.fieldsByName.forEach { thisFieldGroup ->
            val thisSubGroup: Map<AnyElement, Int> = thisFieldGroup.value.groupingBy { it }.eachCount()

            // [otherGroup] should never be null due to the `if` statement above.
            val otherGroup = other.fieldsByName[thisFieldGroup.key]
                             ?: error("unexpectedly missing other field named '${thisFieldGroup.key}'")

            val otherSubGroup: Map<AnyElement, Int> = otherGroup.groupingBy { it }.eachCount()

            // Simple equality should work from here
            if(thisSubGroup != otherSubGroup) {
                return false
            }
        }

        // Metas intentionally not included here.

        return true
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant