RFR [15] 6394757: rev2: AbstractSet.removeAll semantics are surprisingly dependent on relative sizes

Jason Mehrens jason_mehrens at hotmail.com
Wed May 20 20:21:34 UTC 2020


Biasing towards ordering is covered in https://bugs.openjdk.java.net/browse/JDK-8181146 (read the markmail thread link in the ticket) and some of those changes worked there way into
http://hg.openjdk.java.net/jdk/jdk14/file/6c954123ee8d/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java#l1708 and http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/ConcurrentSkipListMap.java?r1=1.176&r2=1.177

I think there is some merit in even biasing toward ordering for non-sorted sets/maps to avoid expensive contains calls.  Any change we apply to equals we can usually apply a similar idea to containsAll.

I'm not sure about computing the hash code during equals.  It is not ideal but seems to solve the case you raised. I doubt it passes the compatibility bar for behavior or performance.

Jason

________________________________________
From: Alan Snyder <javalists at cbfiddle.com>
Sent: Wednesday, May 20, 2020 1:53 PM
To: Jason Mehrens
Cc: core-libs-dev
Subject: Re: RFR [15] 6394757: rev2: AbstractSet.removeAll semantics are surprisingly dependent on relative sizes

Do you believe that Set.equals() should behave this way on SortedSets?

On May 20, 2020, at 11:23 AM, Jason Mehrens <jason_mehrens at hotmail.com<mailto:jason_mehrens at hotmail.com>> wrote:

public class SetEquals {

   public static void main(String[] args) {
       Comparator<String> cc = String.CASE_INSENSITIVE_ORDER;
       Set<String> s1 = new TreeSet<>(cc);
       Set<String> s2 = new TreeSet<>(cc);
       s1.add("hello");
       s2.add("Hello");
       System.out.println(equals(s1, s2));
       System.out.println(equals(s2, s1));
       System.out.println(s1.hashCode() == s2.hashCode());
   }

   private static boolean equals(Set<?> s1, Set<?> s2) {
       if (s2 == null) {
           return false;
       }

       if (s1 == s2) {
           return true;
       }

       int s1h = 0;
       int s2h = 0;
       Iterator<?> e1 = s1.iterator();
       Iterator<?> e2 = s2.iterator();

       if (s1 instanceof SortedSet && s2 instanceof SortedSet
               && isSameOrder((SortedSet) s1, (SortedSet) s2)) {
           //TODO: raw type warnings.
           Comparator cmp = ((SortedSet<?>) s1).comparator();
           if (cmp == null) {
               cmp = Comparator.naturalOrder();
           }
           while (e1.hasNext() && e2.hasNext()) {
               Object o1 = e1.next();
               Object o2 = e2.next();

               try {
                   if (cmp.compare(o1, o2) != 0
                           && (!s1.contains(o2) || !s2.contains(o1))) {
                       return false;
                   }
               } catch (ClassCastException cce) {
                   return false;
               }

               s1h += Objects.hashCode(o1);
               s2h += Objects.hashCode(o2);

               //Iteration order should be the same.
               if (s1h != s2h) {
                   return false;
               }
           }
       } else {
           while (e1.hasNext() && e2.hasNext()) {
               Object o1 = e1.next();
               Object o2 = e2.next();

               try {
                   if (!Objects.equals(o1, o2)
                           && (!s1.contains(o2) || !s2.contains(o1))) {
                       return false;
                   }
               } catch (ClassCastException cce) {
                   return false;
               }

               s1h += Objects.hashCode(o1);
               s2h += Objects.hashCode(o2);
           }
       }
       return s1h == s2h && !e1.hasNext() && !e2.hasNext();
   }

   private static boolean isSameOrder(SortedSet<?> s1, SortedSet<?> s2) {
       //null matches natural ordering or unwrap to find a singleton.
       //Avoid calling equals on comparator.
       return Collections.reverseOrder(s1.comparator())
               == Collections.reverseOrder(s2.comparator());
   }
}



More information about the core-libs-dev mailing list