mirror of
https://github.com/collinsmith/riiablo.git
synced 2025-02-23 21:21:28 +07:00
Impl of pooling for arrays and buckets of arrays of sizes
This commit is contained in:
parent
16670d6e89
commit
5bc47dbf98
49
core/src/main/java/com/riiablo/map2/util/ArrayPool.java
Normal file
49
core/src/main/java/com/riiablo/map2/util/ArrayPool.java
Normal file
@ -0,0 +1,49 @@
|
||||
package com.riiablo.map2.util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
|
||||
public class ArrayPool<E> extends Pool<E> {
|
||||
static <E> E create(Class<E> clazz, int length) {
|
||||
return clazz.cast(Array.newInstance(clazz.getComponentType(), length));
|
||||
}
|
||||
|
||||
public static <E> ArrayPool<E> get(Class<E> clazz, int length) {
|
||||
return new ArrayPool<>(clazz, length, 16, 16);
|
||||
}
|
||||
|
||||
public static <E> Pool<E> get(
|
||||
Class<E> clazz,
|
||||
int length,
|
||||
int initialCapacity,
|
||||
int maxCapacity
|
||||
) {
|
||||
return new ArrayPool<>(clazz, length, initialCapacity, maxCapacity);
|
||||
}
|
||||
|
||||
final Class<E> clazz;
|
||||
final int length;
|
||||
|
||||
ArrayPool(Class<E> clazz, int length, int initialCapacity, int maxCapacity) {
|
||||
super(initialCapacity, maxCapacity);
|
||||
this.clazz = clazz;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected E newObject() {
|
||||
return create(clazz, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("clazz", clazz.getSimpleName())
|
||||
.append("length", length)
|
||||
.append("max", max)
|
||||
.append("peak", peak)
|
||||
.toString();
|
||||
}
|
||||
}
|
98
core/src/main/java/com/riiablo/map2/util/BucketPool.java
Normal file
98
core/src/main/java/com/riiablo/map2/util/BucketPool.java
Normal file
@ -0,0 +1,98 @@
|
||||
package com.riiablo.map2.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.NoSuchElementException;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.IntArray;
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
|
||||
import com.riiablo.logger.LogManager;
|
||||
import com.riiablo.logger.Logger;
|
||||
|
||||
public class BucketPool<E> {
|
||||
private static final Logger log = LogManager.getLogger(BucketPool.class);
|
||||
|
||||
final Class<E> clazz;
|
||||
final Array<ArrayPool<E>> pools;
|
||||
|
||||
BucketPool(Class<E> clazz, int[] lengths, int offset, int length) {
|
||||
this.clazz = clazz;
|
||||
Arrays.sort(lengths, offset, offset + length);
|
||||
pools = new Array<>(ArrayPool.class);
|
||||
for (int i = offset, s = i + length; i < s; i++) {
|
||||
pools.add(ArrayPool.get(clazz, lengths[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public Pool<E> get(int length) {
|
||||
for (ArrayPool<E> pool : pools) {
|
||||
if (length <= pool.length) {
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NoSuchElementException("No bucket big enough for length: " + length);
|
||||
}
|
||||
|
||||
public E obtain(int length) {
|
||||
try {
|
||||
Pool<E> pool = get(length);
|
||||
return pool.obtain();
|
||||
} catch (NoSuchElementException t) {
|
||||
E instance = ArrayPool.create(clazz, length);
|
||||
log.debugf("obtain custom-sized array instance: 0x%h %s length %d",
|
||||
System.identityHashCode(instance),
|
||||
clazz.getSimpleName(),
|
||||
length);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public void free(E o) {
|
||||
int length = ArrayUtils.getLength(o);
|
||||
if (length <= 0) return;
|
||||
try {
|
||||
Pool<E> pool = get(length);
|
||||
pool.free(o);
|
||||
} catch (NoSuchElementException t) {
|
||||
log.debugf("free custom-sized array instance: 0x%h %s length %d",
|
||||
System.identityHashCode(o),
|
||||
clazz.getSimpleName(),
|
||||
length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this)
|
||||
.append("pools", pools)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public static <E> Builder<E> builder(Class<E> clazz) {
|
||||
if (!clazz.isArray()) throw new IllegalArgumentException("clazz must be an array type");
|
||||
return new Builder<>(clazz);
|
||||
}
|
||||
|
||||
public static class Builder<E> {
|
||||
final Class<E> clazz;
|
||||
final IntArray lengths;
|
||||
|
||||
Builder(Class<E> clazz) {
|
||||
this.clazz = clazz;
|
||||
lengths = new IntArray(4);
|
||||
}
|
||||
|
||||
public Builder<E> add(int length) {
|
||||
lengths.add(length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BucketPool<E> build() {
|
||||
return new BucketPool<>(clazz, lengths.items, 0, lengths.size);
|
||||
}
|
||||
}
|
||||
}
|
77
core/src/test/java/com/riiablo/map2/util/BucketPoolTest.java
Normal file
77
core/src/test/java/com/riiablo/map2/util/BucketPoolTest.java
Normal file
@ -0,0 +1,77 @@
|
||||
package com.riiablo.map2.util;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.riiablo.logger.Level;
|
||||
import com.riiablo.logger.LogManager;
|
||||
import com.riiablo.logger.OutputStreamAppender;
|
||||
|
||||
class BucketPoolTest {
|
||||
@BeforeAll
|
||||
static void before() {
|
||||
LogManager.getRootLogger().addAppender(new OutputStreamAppender(System.out));
|
||||
LogManager.setLevel("com.riiablo.map2.util", Level.TRACE);
|
||||
}
|
||||
|
||||
static BucketPool<byte[]> newByteInstance() {
|
||||
return BucketPool
|
||||
.builder(byte[].class)
|
||||
.add(16)
|
||||
.add(32)
|
||||
.add(64)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void byte_array_pool() {
|
||||
BucketPool<byte[]> buckets = newByteInstance();
|
||||
assertEquals(3, buckets.pools.size);
|
||||
assertEquals(16, buckets.pools.get(0).length);
|
||||
assertEquals(32, buckets.pools.get(1).length);
|
||||
assertEquals(64, buckets.pools.get(2).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void byte_array_pool_get() {
|
||||
BucketPool<byte[]> buckets = newByteInstance();
|
||||
assertEquals(buckets.get(15), buckets.pools.get(0));
|
||||
assertEquals(buckets.get(16), buckets.pools.get(0));
|
||||
assertEquals(buckets.get(31), buckets.pools.get(1));
|
||||
assertEquals(buckets.get(32), buckets.pools.get(1));
|
||||
assertEquals(buckets.get(63), buckets.pools.get(2));
|
||||
assertEquals(buckets.get(64), buckets.pools.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void byte_array_pool_get_high() {
|
||||
BucketPool<byte[]> buckets = newByteInstance();
|
||||
assertThrows(NoSuchElementException.class, () -> buckets.get(65));
|
||||
}
|
||||
|
||||
@Test
|
||||
void byte_array_pool_obtain_15() {
|
||||
BucketPool<byte[]> buckets = newByteInstance();
|
||||
byte[] data = buckets.obtain(15);
|
||||
assertTrue(data.length >= 15);
|
||||
buckets.free(data);
|
||||
}
|
||||
|
||||
@Test
|
||||
void byte_array_pool_obtain_16() {
|
||||
BucketPool<byte[]> buckets = newByteInstance();
|
||||
byte[] data = buckets.obtain(16);
|
||||
assertTrue(data.length >= 16);
|
||||
buckets.free(data);
|
||||
}
|
||||
|
||||
@Test
|
||||
void byte_array_pool_obtain_65() {
|
||||
BucketPool<byte[]> buckets = newByteInstance();
|
||||
byte[] data = buckets.obtain(65);
|
||||
assertTrue(data.length >= 65);
|
||||
buckets.free(data);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user