|
38 | 38 | * (inclusive) to {@link #end} (exclusive). |
39 | 39 | */ |
40 | 40 | public class IntervalWindow extends BoundedWindow implements Comparable<IntervalWindow> { |
| 41 | + |
41 | 42 | /** Start of the interval, inclusive. */ |
42 | 43 | private final Instant start; |
43 | 44 |
|
44 | 45 | /** End of the interval, exclusive. */ |
45 | 46 | private final Instant end; |
46 | 47 |
|
| 48 | + // Cached hashCode. ints don't tear and access don't need to be synchronized. |
| 49 | + // Stale reads if any will return 0 and will recalculate hashCode. |
| 50 | + // ByteString and String hashCodes are cached similarly. |
| 51 | + private int hashCode; // Default is 0. |
| 52 | + |
47 | 53 | /** Creates a new IntervalWindow that represents the half-open time interval [start, end). */ |
48 | 54 | public IntervalWindow(Instant start, Instant end) { |
49 | 55 | this.start = start; |
@@ -103,10 +109,13 @@ public boolean equals(@Nullable Object o) { |
103 | 109 |
|
104 | 110 | @Override |
105 | 111 | public int hashCode() { |
106 | | - // The end values are themselves likely to be arithmetic sequence, which |
107 | | - // is a poor distribution to use for a hashtable, so we |
108 | | - // add a highly non-linear transformation. |
109 | | - return (int) (start.getMillis() + modInverse((int) (end.getMillis() << 1) + 1)); |
| 112 | + if (hashCode == 0) { |
| 113 | + // The end values are themselves likely to be arithmetic sequence, which |
| 114 | + // is a poor distribution to use for a hashtable, so we |
| 115 | + // add a highly non-linear transformation. |
| 116 | + hashCode = (int) (start.getMillis() + modInverse((int) (end.getMillis() << 1) + 1)); |
| 117 | + } |
| 118 | + return hashCode; |
110 | 119 | } |
111 | 120 |
|
112 | 121 | /** Compute the inverse of (odd) x mod 2^32. */ |
|
0 commit comments