/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.github.geophile.erdo.map.diskmap;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
class DiskPageSectionVariableLengthRecords extends DiskPageSection
{
// DiskPageSection interface
@Override
public void resetToMark()
{
super.resetToMark();
ends.truncate(count);
size =
dataPosition +
(count == 0 ? 0 : (ends.at(count - 1) - dataPosition)) +
count * OFFSET_SIZE;
}
@Override
public void close()
{
if (state != State.CLOSED) {
// Write index
for (int i = 0; i < ends.size(); i++) {
buffer.putChar(ends.at(i));
}
super.close(); // sets state to State.CLOSED
}
}
// DiskPageSectionVariableLengthRecords interface
public static DiskPageSectionVariableLengthRecords forWrite
(int metadataSize, ByteBuffer buffer)
{
return new DiskPageSectionVariableLengthRecords(metadataSize, buffer);
}
public static DiskPageSectionVariableLengthRecords forRead
(ByteBuffer pageBuffer)
{
return new DiskPageSectionVariableLengthRecords(pageBuffer);
}
// For use by this package
@Override
void setBoundariesInBuffer(int position, ByteBuffer dataBuffer)
{
assert dataBuffer.array() == buffer.array() : this;
assert position >= 0 : this;
if (position < count) {
dataBuffer.limit(start + end(position));
dataBuffer.position(position == 0 ? dataPosition : (start + end(position - 1)));
}
}
void recordEndsAt(int recordEnd)
{
// Check that remaining space will accomodate index, including new entry. But check now, before
// appending boundary.
if (buffer.remaining() < (ends.size() + 1) * OFFSET_SIZE) {
throw new BufferOverflowException();
} else {
appendBoundary(recordEnd);
size += OFFSET_SIZE;
}
}
// For use by this class
private void appendBoundary(int boundary)
{
ends.append((char) (boundary - start));
}
private int end(int position)
{
return ends.at(position);
}
// Used when creating a new page
private DiskPageSectionVariableLengthRecords(int metadataSize, ByteBuffer buffer)
{
super(metadataSize, buffer);
this.ends = new UShortArray(buffer.capacity() / 8); // A guess, but UShortArray grows as necessary
}
// Used when reading a page
private DiskPageSectionVariableLengthRecords(ByteBuffer pageBuffer)
{
super(pageBuffer);
this.ends = new UShortArray(this.count);
int p = this.start + this.size - this.count * OFFSET_SIZE;
for (int i = 0; i < this.count; i++) {
this.ends.append((char) readUShort(p));
p += OFFSET_SIZE;
}
// Parent class requires this subclass to set pageBuffer position to end of what's been read
pageBuffer.position(p);
}
// Object state
private UShortArray ends;
}