Skip to content

Commit 7e70748

Browse files
committed
Document how TBytesKey instances should be use when inserting into a cache.
1 parent 7e12dc2 commit 7e70748

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

src/main/java/org/truffleruby/core/string/TBytesKey.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ public TBytesKey(byte[] bytes, RubyEncoding encoding) {
4343
this(bytes, 0, bytes.length, Arrays.hashCode(bytes), encoding);
4444
}
4545

46+
/** Supports the creation of a cache key using a subset of bytes. This key *must* be used for lookups only. If you
47+
* want to insert into the cache, you *must* use the result of {@link #makeCacheable(boolean)}.
48+
*
49+
* @param byteArray A byte array retrieved from a {@link TruffleString}
50+
* @param encoding The Ruby encoding object needed to properly decode the associated byte array */
4651
public TBytesKey(InternalByteArray byteArray, RubyEncoding encoding) {
4752
this(
4853
byteArray.getArray(),
@@ -113,13 +118,27 @@ private boolean isPerfectFit() {
113118
return offset == 0 && length == bytes.length;
114119
}
115120

121+
/** Returns a cache key suitable for insertion into the string cache. It's quite common that we want to cache a
122+
* substring. Since we don't want to retain the entire original string, we resolve the substring by making a copy of
123+
* the byte range that we need. However, that is a costly operation and that work is discarded in the event of a
124+
* cache hit. To avoid incurring that cost unnecessarily, we allow cache keys to refer to a subset of a byte array.
125+
* While that saves computation during a cache lookup, it means such keys are unsuitable for insertion into the
126+
* cache. This method makes a key we can use safely for insertion.
127+
*
128+
* If we know that the key refers to an immutable byte array and the key does not refer to a substring, we can
129+
* safely refer to the original byte array without needing to make an additional copy.
130+
*
131+
* @param isImmutable whether the key's byte array is immutable
132+
* @return a cache key suitable for insertion */
116133
public TBytesKey makeCacheable(boolean isImmutable) {
117134
if (isImmutable && isPerfectFit()) {
118-
return new TBytesKey(bytes, encoding);
135+
return this;
119136
}
120137

121-
var simplified = ArrayUtils.extractRange(this.bytes, this.offset, this.offset + this.length);
122-
return new TBytesKey(simplified, encoding);
138+
// Make a copy of the substring's bytes so we can cache them without retaining the original byte array.
139+
var resolvedSubstring = ArrayUtils.extractRange(this.bytes, this.offset, this.offset + this.length);
140+
141+
return new TBytesKey(resolvedSubstring, encoding);
123142
}
124143

125144
public TBytesKey withNewEncoding(RubyEncoding encoding) {

0 commit comments

Comments
 (0)