/* * Copyright (C) 2013 Omry Yadan <omry@yadan.net> * All rights reserved. * * See https://github.com/omry/banana/blob/master/BSD-LICENSE for licensing information */ package net.yadan.banana.memory.malloc; import java.util.Arrays; import net.yadan.banana.memory.IBlockAllocator; import net.yadan.banana.memory.IBuffer; import net.yadan.banana.memory.IMemAllocator; import net.yadan.banana.memory.MemInitializer; import net.yadan.banana.memory.block.BlockAllocator; /** * Variable length int's allocator. * * @author omry * @created May 2, 2013 */ public class MultiSizeAllocator implements IMemAllocator { private int[] m_sizes; private IBlockAllocator m_allocators[]; private int m_reservedBits; private int m_allocationBits; private int m_maxAllocationPointer; public MultiSizeAllocator(int numInitialBlocks, int sizes[]) { this(numInitialBlocks, sizes, 0); } public MultiSizeAllocator(int numInitialBlocks, int sizes[], double growthFactor) { m_sizes = new int[sizes.length]; System.arraycopy(sizes, 0, m_sizes, 0, sizes.length); // if you don't have two sizes just use IntAllocator if (m_sizes.length < 2) throw new IllegalArgumentException("Need at least two sizes"); Arrays.sort(sizes); m_allocators = new IBlockAllocator[sizes.length]; for (int i = 0; i < sizes.length; i++) { m_allocators[i] = new BlockAllocator(numInitialBlocks, sizes[i], growthFactor); } m_reservedBits = (int) Math.ceil(Math.log(sizes.length) / Math.log(2)); m_allocationBits = 32 - m_reservedBits; m_maxAllocationPointer = (int) Math.pow(2, m_allocationBits); } @Override public int malloc(int size) { int idx = findAllocatorFor(size); IBlockAllocator alloc = m_allocators[idx]; int pointer = alloc.malloc(); if (pointer > m_maxAllocationPointer) { throw new IllegalStateException("Pointer value too large"); } return encodePointer(idx, pointer); } final int encodePointer(int idx, int pointer) { return idx << m_allocationBits | pointer; } @Override public void free(int pointer) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].free(pointer); } @Override public int getInt(int pointer, int offset_in_data) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); return m_allocators[idx].getInt(pointer, offset_in_data); } @Override public void setInt(int pointer, int offset_in_data, int data) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].setInt(pointer, offset_in_data, data); } @Override public void setInts(int pointer, int dst_offset_in_record, int src_data[], int src_pos, int length) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].setInts(pointer, dst_offset_in_record, src_data, src_pos, length); } @Override public void getInts(int pointer, int src_offset_in_record, int dst_data[], int dst_pos, int length) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].getInts(pointer, src_offset_in_record, dst_data, dst_pos, length); } @Override public void getBuffer(int pointer, int src_offset_in_record, IBuffer dst, int length) { getInts(pointer, src_offset_in_record, dst.array(), 0, length); dst.setUsed(length); } @Override public long getLong(int pointer, int offset_in_data) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); return m_allocators[idx].getLong(pointer, offset_in_data); } @Override public void setLong(int pointer, int offset_in_data, long data) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].setLong(pointer, offset_in_data, data); } final int extractPointer(int pointer) { return pointer & ((1 << m_allocationBits) - 1); } public int getSizeIndex(int pointer) { assert pointer != 0 : "Invalid pointer " + pointer; assert pointer != -1 : "Invalid pointer " + pointer; return pointer >>> m_allocationBits; } public int getReservedBits() { return m_reservedBits; } int findAllocatorFor(int size) { int i = Arrays.binarySearch(m_sizes, size); if (i == -(m_sizes.length + 1)) { throw new IllegalArgumentException("Requested an allocation of unsupported size " + size + ", max " + m_sizes[m_sizes.length - 1]); } if (i < 0) { return (-i) - 1; } return i; } @Override public int computeMemoryUsageFor(int size) { return m_allocators[findAllocatorFor(size)].blockSize(); } @Override public boolean isDebug() { return m_allocators[0].isDebug(); } @Override public void setDebug(boolean debug) { for (IBlockAllocator allocator : m_allocators) { allocator.setDebug(debug); } } @Override public void setInitializer(MemInitializer initializer) { for (IBlockAllocator allocator : m_allocators) { allocator.setInitializer(initializer); } } @Override public int usedBlocks() { int used = 0; for (IBlockAllocator m : m_allocators) { used += m.usedBlocks(); } return used; } @Override public int blockSize() { throw new UnsupportedOperationException(); } @Override public int maxBlocks() { int max = 0; for (IBlockAllocator m : m_allocators) { max += m.maxBlocks(); } return max; } @Override public int freeBlocks() { int free = 0; for (IBlockAllocator m : m_allocators) { free += m.freeBlocks(); } return free; } @Override public void clear() { for (IBlockAllocator allocator : m_allocators) { allocator.clear(); } } @Override public long computeMemoryUsage() { long mem = 0; for (IBlockAllocator allocator : m_allocators) { mem += allocator.computeMemoryUsage(); } return mem; } @Override public void setGrowthFactor(double d) { for (IBlockAllocator allocator : m_allocators) { allocator.setGrowthFactor(d); } } @Override public double getGrowthFactor() { return m_allocators[0].getGrowthFactor(); } @Override public int maximumCapacityFor(int pointer) { int idx = getSizeIndex(pointer); return m_allocators[idx].blockSize(); } @Override public int realloc(int pointer, int size) { // TODO throw new UnsupportedOperationException(); } @Override public IBlockAllocator getBlocks() { throw new UnsupportedOperationException(); } @Override public String pointerDebugString(int pointer) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); StringBuilder sb = new StringBuilder(); sb.append("["); int bs = m_allocators[idx].blockSize(); for (int i = 0; i < bs; i++) { sb.append(m_allocators[idx].getInt(pointer, i)); if (i + 1 < bs) { sb.append(","); } } sb.append("]"); return "Pointer from allocator " + idx + " " + sb.toString(); } @Override public void initialize(int pointer) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].initialize(pointer); } @Override public void memSet(int pointer, int srcPos, int length, int value) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].memSet(pointer, srcPos, length, value); } @Override public short getUpperShort(int pointer, int offset) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); return m_allocators[idx].getUpperShort(pointer, offset); } @Override public short getLowerShort(int pointer, int offset) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); return m_allocators[idx].getLowerShort(pointer, offset); } @Override public void setUpperShort(int pointer, int offset, int s) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].setUpperShort(pointer, offset, s); } @Override public void setLowerShort(int pointer, int offset, int s) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].setLowerShort(pointer, offset, s); } @Override public float getFloat(int pointer, int offset) { return Float.intBitsToFloat(getInt(pointer, offset)); } @Override public void setFloat(int pointer, int offset, float f) { setInt(pointer, offset, Float.floatToIntBits(f)); } @Override public double getDouble(int pointer, int offset_in_data) { return Double.longBitsToDouble(getLong(pointer, offset_in_data)); } @Override public void setDouble(int pointer, int offset_in_data, double data) { setLong(pointer, offset_in_data, Double.doubleToLongBits(data)); } @Override public void setChars(int pointer, int dst_offset, char[] src_data, int src_pos, int num_chars) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].setChars(pointer, dst_offset, src_data, src_pos, num_chars); } @Override public void getChars(int pointer, int src_offset, char[] dst_data, int dst_pos, int num_chars) { int idx = getSizeIndex(pointer); pointer = extractPointer(pointer); m_allocators[idx].getChars(pointer, src_offset, dst_data, dst_pos, num_chars); } }