/*
* 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.list;
import net.yadan.banana.DebugLevel;
import net.yadan.banana.Formatter;
import net.yadan.banana.memory.IBuffer;
import net.yadan.banana.memory.IMemAllocator;
import net.yadan.banana.memory.block.BlockAllocator;
import net.yadan.banana.memory.malloc.ChainedAllocator;
import net.yadan.banana.memory.malloc.MultiSizeAllocator;
/**
* @author omry
* @created Apr 21, 2013
*/
public class DoubleLinkedList implements ILinkedList {
private static final int PREV_OFFSET = 0;
private static final int NEXT_OFFSET = 1;
private static final int DATA_OFFSET = 2;
public static final int RESERVED_SIZE = DATA_OFFSET;
private int m_head;
private int m_tail;
private int m_size;
private IMemAllocator m_memory;
private DebugLevel m_debugLevel;
private Formatter m_linkFormatter;
public DoubleLinkedList(int maxBlocks, int blockSize, double growthFactor) {
init(new ChainedAllocator(maxBlocks, blockSize + RESERVED_SIZE, growthFactor));
}
public DoubleLinkedList(int maxBlocks, int sizes[], double growthFactor) {
int sizes1[] = new int[sizes.length];
for(int i=0;i<sizes.length;i++){
sizes1[i] = sizes[i] + RESERVED_SIZE;
}
init(new MultiSizeAllocator(maxBlocks, sizes1, growthFactor));
}
public DoubleLinkedList(IMemAllocator memory) {
init(memory);
}
protected void init(IMemAllocator memory) {
m_memory = memory;
m_head = -1;
m_tail = -1;
m_size = 0;
}
@Override
public int insertHead(int size) {
int link = m_memory.malloc(size + RESERVED_SIZE);
m_memory.setInt(link, NEXT_OFFSET, m_head);
m_memory.setInt(link, PREV_OFFSET, -1);
if (m_head != -1) {
m_memory.setInt(m_head, PREV_OFFSET, link);
}
m_head = link;
if (m_tail == -1) {
m_tail = link;
}
m_size++;
return link;
}
@Override
public int insert(int size, int anchor) {
int link = m_memory.malloc(size + RESERVED_SIZE);
if (m_head == -1 && anchor == m_head) {
m_head = link;
m_tail = link;
m_memory.setInt(link, NEXT_OFFSET, -1);
m_memory.setInt(link, PREV_OFFSET, -1);
} else {
int next = m_memory.getInt(anchor, NEXT_OFFSET);
m_memory.setInt(link, NEXT_OFFSET, next);
if (next != -1) {
m_memory.setInt(next, PREV_OFFSET, link);
}
m_memory.setInt(link, PREV_OFFSET, anchor);
m_memory.setInt(anchor, NEXT_OFFSET, link);
if (anchor == m_tail) {
m_tail = link;
}
}
m_size++;
return link;
}
@Override
public void removeHead() {
if (m_head != -1) {
int new_head = getNext(m_head);
if (m_head == m_tail) {
m_tail = -1;
} else {
setPrev(new_head, -1);
}
m_memory.free(m_head);
m_head = new_head;
m_size--;
}
}
@Override
public int appendTail(int size) {
int link = m_memory.malloc(size + RESERVED_SIZE);
setNext(link, -1);
setPrev(link, m_tail);
if (m_head == -1) {
m_head = link;
} else {
setNext(m_tail, link);
}
m_tail = link;
m_size++;
return link;
}
@Override
public void remove(int link) {
if (link == m_head) {
m_head = getNext(link);
}
if (link == m_tail) {
m_tail = getPrev(link);
}
if (getPrev(link) != -1) {
setNext(getPrev(link), getNext(link));
}
if (getNext(link) != -1) {
setPrev(getNext(link), getPrev(link));
}
m_size--;
m_memory.free(link);
}
private void setNext(int link, int next) {
m_memory.setInt(link, NEXT_OFFSET, next);
}
private void setPrev(int link, int prev) {
m_memory.setInt(link, PREV_OFFSET, prev);
}
@Override
public int getInt(int link, int offset_in_data) {
return m_memory.getInt(link, DATA_OFFSET + offset_in_data);
}
@Override
public long getLong(int link, int offset_in_data) {
return m_memory.getLong(link, DATA_OFFSET + offset_in_data);
}
@Override
public void setLong(int link, int offset_in_data, long data) {
m_memory.setLong(link, DATA_OFFSET + offset_in_data, data);
}
@Override
public short getUpperShort(int link, int offset) {
return m_memory.getUpperShort(link, offset + DATA_OFFSET);
}
@Override
public short getLowerShort(int link, int offset) {
return m_memory.getLowerShort(link, offset + DATA_OFFSET);
}
@Override
public void setUpperShort(int link, int offset, int s) {
m_memory.setUpperShort(link, offset + DATA_OFFSET, s);
}
@Override
public void setLowerShort(int link, int offset, int s) {
m_memory.setLowerShort(link, offset + DATA_OFFSET, s);
}
@Override
public void setInt(int link, int offset_in_data, int data) {
m_memory.setInt(link, DATA_OFFSET + offset_in_data, data);
}
@Override
public void setInts(int link, int dst_offset_in_record, int[] src_data, int src_pos, int length) {
m_memory.setInts(link, DATA_OFFSET + dst_offset_in_record, src_data, src_pos, length);
}
@Override
public void getInts(int link, int src_offset_in_record, int[] dst_data, int dst_pos, int length) {
m_memory.getInts(link, DATA_OFFSET + src_offset_in_record, dst_data, dst_pos, length);
}
@Override
public void getBuffer(int link, int src_offset_in_record, IBuffer dst, int length) {
m_memory.getBuffer(link, DATA_OFFSET + src_offset_in_record, dst, length);
}
@Override
public final int getHead() {
return m_head;
}
@Override
public final int getTail() {
return m_tail;
}
@Override
public int getNext(int link) {
return m_memory.getInt(link, NEXT_OFFSET);
}
@Override
public int getPrev(int pointer) {
return m_memory.getInt(pointer, PREV_OFFSET);
}
@Override
public void clear() {
int n = m_head;
while (n != -1) {
int next = m_memory.getInt(n, NEXT_OFFSET);
m_memory.free(n);
n = next;
}
m_head = m_tail = -1;
m_size = 0;
}
@Override
public IMemAllocator getAllocator() {
return m_memory;
}
public static int getIntArraySize(int maxBlocks, int recordSize) {
return BlockAllocator.getIntArraySize(maxBlocks, recordSize + RESERVED_SIZE);
}
@Override
public int size() {
return m_size;
}
@Override
public int insertHead(IBuffer data) {
int ret = insertHead(data.size());
setInts(ret, 0, data.array(), 0, data.size());
return ret;
}
@Override
public int insert(IBuffer data, int anchor) {
int ret = insert(data.size(), anchor);
setInts(ret, 0, data.array(), 0, data.size());
return ret;
}
@Override
public int appendTail(IBuffer data) {
int ret = appendTail(data.size());
setInts(ret, 0, data.array(), 0, data.size());
return ret;
}
@Override
public boolean isEmpty() {
return m_size == 0;
}
@Override
public long computeMemoryUsage() {
return m_memory.computeMemoryUsage();
}
@Override
public void setDebug(DebugLevel level) {
m_debugLevel = level;
}
@Override
public DebugLevel getDebug() {
return m_debugLevel;
}
@Override
public String toString() {
return ListUtil.listToString(this);
}
@Override
public void setFormatter(Formatter formatter) {
m_linkFormatter = formatter;
}
@Override
public Formatter getFormatter() {
return m_linkFormatter;
}
@Override
public int maximumCapacityFor(int link) {
return m_memory.maximumCapacityFor(link) - RESERVED_SIZE;
}
@Override
public float getFloat(int link, int offset) {
return m_memory.getFloat(link, DATA_OFFSET + offset);
}
@Override
public void setFloat(int link, int offset, float f) {
m_memory.setFloat(link, DATA_OFFSET + offset, f);
}
@Override
public double getDouble(int link, int offset_in_data) {
return m_memory.getDouble(link, offset_in_data + DATA_OFFSET);
}
@Override
public void setDouble(int link, int offset_in_data, double data) {
m_memory.setDouble(link, offset_in_data + DATA_OFFSET, data);
}
@Override
public void setChars(int pointer, int dst_offset, char[] src_data, int src_pos, int num_chars) {
m_memory.setChars(pointer, dst_offset + DATA_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) {
m_memory.getChars(pointer, src_offset + DATA_OFFSET, dst_data, dst_pos, num_chars);
}
}