'Return True iff self and other have equal values.
:param visited_self: A set containing the ids of all ``self``
feature structures we\'ve already visited.
:param visited_other: A set containing the ids of all ``other``
feature structures we\'ve already visited.
:param visited_pairs: A set containing ``(selfid, otherid)`` pairs
for all pairs of feature structures we\'ve already visited.'

def _equal(self, other, check_reentrance, visited_self, visited_other, visited_pairs):

    if (self is other):
        return True
    if (self.__class__ != other.__class__):
        return False
    if (len(self) != len(other)):
        return False
    if (set(self._keys()) != set(other._keys())):
        return False
    if check_reentrance:
        if ((id(self) in visited_self) or (id(other) in visited_other)):
            return ((id(self), id(other)) in visited_pairs)
    elif ((id(self), id(other)) in visited_pairs):
        return True
    visited_self.add(id(self))
    visited_other.add(id(other))
    visited_pairs.add((id(self), id(other)))
    for (fname, self_fval) in self._items():
        other_fval = other[fname]
        if isinstance(self_fval, FeatStruct):
            if (not self_fval._equal(other_fval, check_reentrance, visited_self, visited_other, visited_pairs)):
                return False
        elif (self_fval != other_fval):
            return False
    return True
