ReaderCache { @NotNull public T get(long msb, long lsb, int offset, Function<Integer, T> loader) { int hash = getEntryHash(msb, lsb, offset); if (fastCache == null) { T value = loader.apply(offset); assert value != null; return value; } T value = fastCache.get(hash, msb, lsb, offset); if (value != null) { return value; } CacheKey key = new CacheKey(hash, msb, lsb, offset); value = cache.getIfPresent(key); if (value == null) { value = loader.apply(offset); assert value != null; cache.put(key, value); } if (isSmall(value)) { fastCache.put(hash, new FastCacheEntry<>(hash, msb, lsb, offset, value)); } return value; } protected  ReaderCache(long maxWeight, int averageWeight,
            @NotNull String name, @NotNull Weigher<CacheKey, T> weigher); @NotNull CacheStats getStats(); @NotNull T get(long msb, long lsb, int offset, Function<Integer, T> loader); void clear();  }
@Test public void empty() { final AtomicInteger counter = new AtomicInteger(); Function<Integer, String> loader = new Function<Integer, String>() { @Override @NotNull public String apply(@Nullable Integer input) { counter.incrementAndGet(); return valueOf(input); } }; StringCache c = new StringCache(0); for (int repeat = 0; repeat < 10; repeat++) { for (int i = 0; i < 1000; i++) { assertEquals(valueOf(i), c.get(i, i, i, loader)); } } assertTrue(valueOf(counter), counter.get() > 1000); assertTrue(valueOf(counter), counter.get() < 5000); }
@Test public void largeEntries() { final AtomicInteger counter = new AtomicInteger(); final String large = new String(new char[1024]); Function<Integer, String> loader = new Function<Integer, String>() { @Override @Nullable public String apply(@Nullable Integer input) { counter.incrementAndGet(); return large + input; } }; StringCache c = new StringCache(1024); for (int repeat = 0; repeat < 10; repeat++) { for (int i = 0; i < 1000; i++) { assertEquals(large + i, c.get(i, i, i, loader)); assertEquals(large + 0, c.get(0, 0, 0, loader)); } } assertTrue(valueOf(counter), counter.get() > 9000); assertTrue(valueOf(counter), counter.get() < 10000); }
@Test public void randomized() { ArrayList<Function<Integer, String>> loaderList = new ArrayList<Function<Integer, String>>(); int segmentCount = 10; for (int i = 0; i < segmentCount; i++) { final int x = i; Function<Integer, String> loader = new Function<Integer, String>() { @Override @Nullable public String apply(@Nullable Integer input) { return "loader #" + x + " offset " + input; } }; loaderList.add(loader); } StringCache c = new StringCache(10); Random r = new Random(1); for (int i = 0; i < 1000; i++) { int segment = r.nextInt(segmentCount); int offset = r.nextInt(10); Function<Integer, String> loader = loaderList.get(segment); String x = c.get(segment, segment, offset, loader); assertEquals(loader.apply(offset), x); } }