From 86d1bf3f27fdff24cf78c3baf2db457c70b334d3 Mon Sep 17 00:00:00 2001 From: James Baker Date: Mon, 28 Nov 2022 16:47:27 +0000 Subject: [PATCH] Faster LinkedHashMap tail() (#2725) Change: LinkedHashMap tail() is now constant-time, from being O(size) time and space. Motivation: We have a use case which looks somewhat like the following. 1. It's effectively a Queue use case (fifo). 2. Iteration order needs to be stable. 3. Elements in the queue frequently need to be verified as present in the queue. 4. Occasionally, removals must occur, which are usually from the head of the queue although occasionally randomly. We started with a Queue and eventually found performance issues from too much linear scanning. This was not obviously going to be a bottleneck since our queues are usually of very small size, but ended up so. The next type we considered was a LinkedHashSet, using the `head` and `tail` methods to implement a dequeue-like operation and the set operations being sufficient for the other operations. Unfortunately, it seems that `tail` at present copies the entire queue despite not seemingly needing to. We moved to our own hand-crafted HashSet+Queue structure, but this PR seems like it'd generally be beneficial for users of Vavr! --- vavr/src/main/java/io/vavr/collection/LinkedHashMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vavr/src/main/java/io/vavr/collection/LinkedHashMap.java b/vavr/src/main/java/io/vavr/collection/LinkedHashMap.java index 51cf4bfa3..aba65b6a8 100644 --- a/vavr/src/main/java/io/vavr/collection/LinkedHashMap.java +++ b/vavr/src/main/java/io/vavr/collection/LinkedHashMap.java @@ -956,7 +956,7 @@ public LinkedHashMap tail() { if (isEmpty()) { throw new UnsupportedOperationException("tail of empty LinkedHashMap"); } else { - return LinkedHashMap.ofEntries(list.tail()); + return wrap(list.tail(), map.remove(list.head()._1())); } }