Skip to content
This repository was archived by the owner on Mar 15, 2022. It is now read-only.

Commit c0d7884

Browse files
committed
"native" key support on JRuby's cache backend
1 parent ed8bd21 commit c0d7884

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

ext/org/jruby/ext/thread_safe/JRubyCacheBackendLibrary.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,17 @@ public RubyBoolean replace_pair(IRubyObject key, IRubyObject oldValue, IRubyObje
178178
return getRuntime().newBoolean(map.replace(key, oldValue, newValue));
179179
}
180180

181-
@JRubyMethod(name = {"key?"}, required = 1)
181+
@JRubyMethod(name = "key?", required = 1)
182182
public RubyBoolean has_key_p(IRubyObject key) {
183183
return map.containsKey(key) ? getRuntime().getTrue() : getRuntime().getFalse();
184184
}
185185

186+
@JRubyMethod
187+
public IRubyObject key(IRubyObject value) {
188+
final IRubyObject key = map.findKey(value);
189+
return key == null ? getRuntime().getNil() : key;
190+
}
191+
186192
@JRubyMethod
187193
public IRubyObject replace_if_exists(IRubyObject key, IRubyObject value) {
188194
IRubyObject result = map.replace(key, value);

ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMap.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ public interface BiFun<A,B,T> { T apply(A a, B b); }
2525
public Set<Map.Entry<K,V>> entrySet();
2626
public int size();
2727
public V getValueOrDefault(Object key, V defaultValue);
28+
29+
public boolean containsValue(V value);
30+
public K findKey(V value);
2831
}

ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,8 +2430,8 @@ else if (f.casHash(fh, fh | LOCKED)) {
24302430
@SuppressWarnings("serial") static class Traverser<K,V,R> {
24312431
final ConcurrentHashMapV8<K, V> map;
24322432
Node next; // the next entry to use
2433-
Object nextKey; // cached key field of next
2434-
Object nextVal; // cached val field of next
2433+
K nextKey; // cached key field of next
2434+
V nextVal; // cached val field of next
24352435
Node[] tab; // current table; updated if resized
24362436
int index; // index of bin to use next
24372437
int baseIndex; // current index of initial table
@@ -2461,9 +2461,9 @@ else if ((t = it.tab) == null && // force parent tab initialization
24612461
* Advances next; returns nextVal or null if terminated.
24622462
* See above for explanation.
24632463
*/
2464-
final Object advance() {
2464+
final V advance() {
24652465
Node e = next;
2466-
Object ev = null;
2466+
V ev = null;
24672467
outer: do {
24682468
if (e != null) // advance past used/skipped node
24692469
e = e.next;
@@ -2489,8 +2489,8 @@ else if ((m = map) != null && (t = tab = m.table) != null)
24892489
} // visit upper slots if present
24902490
index = (i += baseSize) < n ? i : (baseIndex = b + 1);
24912491
}
2492-
nextKey = e.key;
2493-
} while ((ev = e.val) == null); // skip deleted or special nodes
2492+
nextKey = (K) e.key;
2493+
} while ((ev = (V) e.val) == null); // skip deleted or special nodes
24942494
next = e;
24952495
return nextVal = ev;
24962496
}
@@ -2730,6 +2730,18 @@ public boolean containsValue(Object value) {
27302730
return false;
27312731
}
27322732

2733+
public K findKey(Object value) {
2734+
if (value == null)
2735+
throw new NullPointerException();
2736+
Object v;
2737+
Traverser<K,V,Object> it = new Traverser<K,V,Object>(this);
2738+
while ((v = it.advance()) != null) {
2739+
if (v == value || value.equals(v))
2740+
return it.nextKey;
2741+
}
2742+
return null;
2743+
}
2744+
27332745
/**
27342746
* Legacy method testing if some key maps into the specified value
27352747
* in this table. This method is identical in functionality to

ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,8 +2422,8 @@ else if (f.casHash(fh, fh | LOCKED)) {
24222422
@SuppressWarnings("serial") static class Traverser<K,V,R> {
24232423
final ConcurrentHashMapV8<K, V> map;
24242424
Node next; // the next entry to use
2425-
Object nextKey; // cached key field of next
2426-
Object nextVal; // cached val field of next
2425+
K nextKey; // cached key field of next
2426+
V nextVal; // cached val field of next
24272427
AtomicReferenceArray<Node> tab; // current table; updated if resized
24282428
int index; // index of bin to use next
24292429
int baseIndex; // current index of initial table
@@ -2453,9 +2453,9 @@ else if ((t = it.tab) == null && // force parent tab initialization
24532453
* Advances next; returns nextVal or null if terminated.
24542454
* See above for explanation.
24552455
*/
2456-
final Object advance() {
2456+
final V advance() {
24572457
Node e = next;
2458-
Object ev = null;
2458+
V ev = null;
24592459
outer: do {
24602460
if (e != null) // advance past used/skipped node
24612461
e = e.next;
@@ -2481,8 +2481,8 @@ else if ((m = map) != null && (t = tab = m.table) != null)
24812481
} // visit upper slots if present
24822482
index = (i += baseSize) < n ? i : (baseIndex = b + 1);
24832483
}
2484-
nextKey = e.key;
2485-
} while ((ev = e.val) == null); // skip deleted or special nodes
2484+
nextKey = (K) e.key;
2485+
} while ((ev = (V) e.val) == null); // skip deleted or special nodes
24862486
next = e;
24872487
return nextVal = ev;
24882488
}
@@ -2722,6 +2722,18 @@ public boolean containsValue(Object value) {
27222722
return false;
27232723
}
27242724

2725+
public K findKey(Object value) {
2726+
if (value == null)
2727+
throw new NullPointerException();
2728+
Object v;
2729+
Traverser<K,V,Object> it = new Traverser<K,V,Object>(this);
2730+
while ((v = it.advance()) != null) {
2731+
if (v == value || value.equals(v))
2732+
return it.nextKey;
2733+
}
2734+
return null;
2735+
}
2736+
27252737
/**
27262738
* Legacy method testing if some key maps into the specified value
27272739
* in this table. This method is identical in functionality to

0 commit comments

Comments
 (0)