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

Re-worked TreeMap comparators, considering null-keys #1695

Merged
merged 1 commit into from
Nov 20, 2016
Merged

Re-worked TreeMap comparators, considering null-keys #1695

merged 1 commit into from
Nov 20, 2016

Conversation

danieldietrich
Copy link
Contributor

@danieldietrich danieldietrich commented Nov 20, 2016

Update: This behavioral change was reverted in #1696

Fixes #1549

Map<K, V> map = TreeMap.empty();

// ordinary Maps are expected to accept null values:
map.put(null, "ok");

Copy link
Contributor Author

@danieldietrich danieldietrich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments

@@ -448,7 +448,7 @@ private TreeMap(RedBlackTree<Tuple2<K, V>> entries) {
* @return A new Map containing the given entries
*/
public static <K, V> TreeMap<K, V> of(Comparator<? super K> keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return of(keyComparator, k1, v1, k2, v2, k3, v3).put(k4, v4);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous version called TreeMap.put, which was bad for these reasons:

  • TreeMap.put was called, which creates RedBlackTree-wrappers
  • of(...) recursively called O(n) times of() before starting to add values

The current version

  • calls put on RedBlackTree, which does not create intermediate TreeMap objects
  • turns the recursive call into an iteration, which is more efficient in this case

@@ -37,7 +37,7 @@ protected String className() {

@Override
protected <T1 extends Comparable<? super T1>, T2> TreeMap<T1, T2> emptyMap() {
return TreeMap.empty(nullsFirst());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using nullsFirst() was terribly wrong. It made unit tests artificially work which were not intended to work.

1, null, 2, null, 3, null);
treeMap2.get(2);

}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will remove this in a second...

for (Tuple2<? extends K, ? extends V> entry : entries) {
tree = tree.insert((Tuple2<K, V>) entry);
}
return tree.isEmpty() ? (TreeMap<K, V>) empty() : new TreeMap<>(tree);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was wrong, because the comparator was not used in the empty case

Objects.requireNonNull(keyComparator, "keyComparator is null");
Objects.requireNonNull(entry, "entry is null");
return TreeMap.<K, V> empty(keyComparator).put(entry);
public static <K, V> TreeMap<K, V> ofAll(Comparator<? super K> keyComparator, java.util.Map<? extends K, ? extends V> map) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method was missing

@codecov-io
Copy link

codecov-io commented Nov 20, 2016

Current coverage is 97.04% (diff: 89.07%)

Merging #1695 into master will decrease coverage by 0.01%

@@             master      #1695   diff @@
==========================================
  Files            89         89          
  Lines         11247      11277    +30   
  Methods           0          0          
  Messages          0          0          
  Branches       1888       1888          
==========================================
+ Hits          10917      10944    +27   
- Misses          187        193     +6   
+ Partials        143        140     -3   

Powered by Codecov. Last update ee2f094...2767cf7

}

@Override
public <K2, V2> TreeMap<K2, V2> bimap(Comparator<? super K2> keyComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

}

@Override
public <K2, V2> TreeMap<K2, V2> bimap(Comparator<? super K2> keyComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

@@ -1225,34 +1183,201 @@ public String toString() {
return mkString(stringPrefix() + "(", ", ", ")");
}

// -- private helpers

private static <K, K2, V, V2> TreeMap<K2, V2> bimap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

@@ -1225,34 +1183,201 @@ public String toString() {
return mkString(stringPrefix() + "(", ", ", ")");
}

// -- private helpers

private static <K, K2, V, V2> TreeMap<K2, V2> bimap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

return createTreeMap(entryComparator, map.entries, entry -> entry.map(keyMapper, valueMapper));
}

private static <K, V, K2, V2> TreeMap<K2, V2> flatMap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

return createTreeMap(entryComparator, map.entries, entry -> entry.map(keyMapper, valueMapper));
}

private static <K, V, K2, V2> TreeMap<K2, V2> flatMap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

return createTreeMap(entryComparator, map.entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2)));
}

private static <K, K2, V, V2> TreeMap<K2, V2> map(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

return createTreeMap(entryComparator, map.entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2)));
}

private static <K, K2, V, V2> TreeMap<K2, V2> map(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

return new TreeMap<>(tree);
}

private static <K, K2, V, V2> TreeMap<K2, V2> createTreeMap(EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not

return new TreeMap<>(tree);
}

private static <K, K2, V, V2> TreeMap<K2, V2> createTreeMap(EntryComparator<K2, V2> entryComparator,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it must not


private static final long serialVersionUID = 1L;

final Comparator<K> keyComparator;
Copy link
Contributor Author

@danieldietrich danieldietrich Nov 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private: ok
accessor methods: oh my god - no! (no getters and setters please. we have keyComparator())

}

@Override
public <K2, V2> TreeMap<K2, V2> bimap(Comparator<? super K2> keyComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'K2' must match pattern '^[A-Z]$'.

}

@Override
public <K2, V2> TreeMap<K2, V2> bimap(Comparator<? super K2> keyComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'V2' must match pattern '^[A-Z]$'.

@@ -1225,34 +1183,201 @@ public String toString() {
return mkString(stringPrefix() + "(", ", ", ")");
}

// -- private helpers

private static <K, K2, V, V2> TreeMap<K2, V2> bimap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'K2' must match pattern '^[A-Z]$'.

@@ -1225,34 +1183,201 @@ public String toString() {
return mkString(stringPrefix() + "(", ", ", ")");
}

// -- private helpers

private static <K, K2, V, V2> TreeMap<K2, V2> bimap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'V2' must match pattern '^[A-Z]$'.

return createTreeMap(entryComparator, map.entries, entry -> entry.map(keyMapper, valueMapper));
}

private static <K, V, K2, V2> TreeMap<K2, V2> flatMap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'K2' must match pattern '^[A-Z]$'.

return createTreeMap(entryComparator, map.entries, entry -> entry.map(keyMapper, valueMapper));
}

private static <K, V, K2, V2> TreeMap<K2, V2> flatMap(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'V2' must match pattern '^[A-Z]$'.

return createTreeMap(entryComparator, map.entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2)));
}

private static <K, K2, V, V2> TreeMap<K2, V2> map(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'K2' must match pattern '^[A-Z]$'.

return createTreeMap(entryComparator, map.entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2)));
}

private static <K, K2, V, V2> TreeMap<K2, V2> map(TreeMap<K, V> map, EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'V2' must match pattern '^[A-Z]$'.

return new TreeMap<>(tree);
}

private static <K, K2, V, V2> TreeMap<K2, V2> createTreeMap(EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'K2' must match pattern '^[A-Z]$'.

return new TreeMap<>(tree);
}

private static <K, K2, V, V2> TreeMap<K2, V2> createTreeMap(EntryComparator<K2, V2> entryComparator,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Checkstyle] ERROR: Name 'V2' must match pattern '^[A-Z]$'.

@danieldietrich
Copy link
Contributor Author

This was the last fix for 2.0.5 - now starting to cherry-pick.

@danieldietrich danieldietrich merged commit e4459b1 into vavr-io:master Nov 20, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants