com.amazon.ion.impl.UnifiedInputBufferX Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ion-java Show documentation
Show all versions of ion-java Show documentation
A Java implementation of the Amazon Ion data notation.
/*
* Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.ion.impl;
abstract class UnifiedInputBufferX
{
public enum BufferType { BYTES, CHARS }
protected int _page_size;
protected UnifiedDataPageX[] _buffers;
protected int _buffer_current;
protected int _buffer_count;
protected int _locks;
public static UnifiedInputBufferX makePageBuffer(byte[] bytes, int offset, int length) {
UnifiedInputBufferX buf = new UnifiedInputBufferX.Bytes(bytes, offset, length);
return buf;
}
public static UnifiedInputBufferX makePageBuffer(char[] chars, int offset, int length) {
UnifiedInputBufferX buf = new UnifiedInputBufferX.Chars(chars, offset, length);
return buf;
}
public static UnifiedInputBufferX makePageBuffer(CharSequence chars, int offset, int length) {
char [] char_array = chars_make_char_array(chars, offset, length);
UnifiedInputBufferX buf = makePageBuffer(char_array, 0, length);
return buf;
}
public static UnifiedInputBufferX makePageBuffer(BufferType bufferType, int initialPageSize)
{
UnifiedInputBufferX buf;
switch(bufferType) {
case CHARS:
buf = new UnifiedInputBufferX.Chars(initialPageSize);
break;
case BYTES:
buf = new UnifiedInputBufferX.Bytes(initialPageSize);
break;
default:
throw new IllegalArgumentException("invalid buffer type");
}
return buf;
}
protected static final char[] chars_make_char_array(CharSequence chars,
int offset,
int length)
{
char[] char_array = new char[length];
for (int ii=offset; ii 0");
} else if (initialPageSize > _Private_IonConstants.ARRAY_MAXIMUM_SIZE) {
throw new IllegalArgumentException("page size must be < " + _Private_IonConstants.ARRAY_MAXIMUM_SIZE);
}
_page_size = initialPageSize;
_buffers = new UnifiedDataPageX[10];
}
public abstract BufferType getType();
public abstract int maxValue();
public final void putCharAt(long fileOffset, int c) {
if (c < 0 || c > maxValue()) throw new IllegalArgumentException("value ("+c+")is out of range (0 to "+maxValue()+")");
// since we start at _curr the common case find the buffer immediately
UnifiedDataPageX page = null;
for (int ii=_buffer_current; ii>=0; ii--) {
if (_buffers[ii].containsOffset(fileOffset)) {
page = _buffers[ii];
break;
}
}
if (page == null) throw new IllegalArgumentException();
int offset = (int)(fileOffset - page.getStartingFileOffset());
page.putValue(offset, c);
}
public final UnifiedDataPageX getCurrentPage() {
return _buffers[_buffer_current];
}
public final int getCurrentPageIdx() {
return _buffer_current;
}
public final int getPageCount() {
return _buffer_count;
}
public final void incLock() {
_locks++;
}
public final boolean decLock() {
_locks--;
return (_locks == 0);
}
public final UnifiedDataPageX getPage(int pageIdx) {
if (pageIdx < 0 || pageIdx >= _buffer_count) {
throw new IndexOutOfBoundsException();
}
return _buffers[pageIdx];
}
protected final int getNextFilledPageIdx() {
int idx = _buffer_current + 1;
if (idx < _buffer_count) {
UnifiedDataPageX p = _buffers[idx];
if (p != null) {
_buffer_current = idx;
return idx;
}
}
return -1;
}
protected final UnifiedDataPageX getEmptyPageIdx() {
UnifiedDataPageX next = null;
if (_buffer_count < _buffers.length) {
next = _buffers[_buffer_count];
}
if (next == null) {
next = make_page(_page_size);
}
else {
assert(_buffer_count == (_buffer_current + 1));
}
return next;
}
abstract protected UnifiedDataPageX make_page(int page_size);
protected final UnifiedDataPageX setCurrentPage(int idx, UnifiedDataPageX curr) {
setPage(idx, curr, true);
if (idx != _buffer_current) {
_buffer_current = idx;
if (idx >= _buffer_count) {
_buffer_count = idx + 1;
}
}
UnifiedDataPageX p = _buffers[idx];
return p;
}
protected final void setPage(int idx, UnifiedDataPageX curr, boolean recycleOldPage)
{
int oldlen = _buffers.length;
if (idx >= oldlen) {
int newlen = oldlen * 2;
UnifiedDataPageX[] newbuf = new UnifiedDataPageX[newlen];
System.arraycopy(_buffers, 0, newbuf, 0, oldlen);
_buffers = newbuf;
}
UnifiedDataPageX prev = _buffers[idx];
_buffers[idx] = curr;
if (idx >= _buffer_count) {
_buffer_count = idx + 1;
}
// if the caller wants us to we'll hold onto this
// page for a bit, since it's now available
if (recycleOldPage
&& prev != null
&& prev != curr
&& (idx + 1) < _buffers.length // it's not worth reallocating the _buffers array for this
) {
_buffers[idx+1] = prev;
}
}
/**
* resets the buffer list to start at the current page
* this releases any "extra" pages. This does hold
* on to 1 extra page, if there is one, since two pages
* if a common occurrence for values that cross the
* page boundary.
*
* when this exits there will be either just the current
* page in the buffer list or the current page and 1
* preallocated page just after it (in idx 1).
*/
protected final void resetToCurrentPage()
{
int p0_idx = getCurrentPageIdx();
if (p0_idx > 0) {
// this is a common "do nothing" case, it happens
// when we reset to the page and there are no saved
// pages - i.e. the mark is contained in curr
release_pages_to(p0_idx);
}
}
private final void release_pages_to(int p0_idx) {
assert(p0_idx > 0);
// we'll try to save the now unneeded 0th empty page
UnifiedDataPageX empty_page = _buffers[0];
// now bump all the page ptrs down to release the
// pages that precede the current page
int dst = 0;
int src = p0_idx;
while (src<_buffer_count) {
_buffers[dst++] = _buffers[src++];
}
// clear any trailing page ptrs
int end = _buffer_count + 1; // we may have an extra page ptr saved at buffer[count]
if (end >= _buffers.length) {
end = _buffers.length;
}
while (dst < end) {
_buffers[dst++] = null;
}
_buffer_current -= p0_idx;
_buffer_count -= p0_idx;
_buffers[_buffer_count] = empty_page;
}
/**
* this clears all the pages out, except to save
* one page (unallocated)
*
*/
protected final void clear() {
UnifiedDataPageX curr = getCurrentPage();
for (int ii=0; ii<_buffers.length; ii++) {
_buffers[ii] = null;
}
// curr is null when underlying stream is empty.
if (curr != null)
{
_buffers[0] = curr;
curr.reset(0);
}
_buffer_count = 0;
_buffer_current = 0;
}
static class Bytes extends UnifiedInputBufferX {
protected Bytes(int initialPageSize) {
super(initialPageSize);
}
protected Bytes(byte[] bytes, int offset, int length) {
super(length);
_buffers[0] = new UnifiedDataPageX.Bytes(bytes, offset, length);
_buffer_current = 0;
_buffer_count = 1;
}
@Override
public final BufferType getType() { return BufferType.BYTES; }
@Override
protected final UnifiedDataPageX make_page(int page_size) {
UnifiedDataPageX p = new UnifiedDataPageX.Bytes(page_size);
return p;
}
@Override
public final int maxValue() { return 0xff; }
}
static class Chars extends UnifiedInputBufferX {
protected Chars(int initialPageSize) {
super(initialPageSize);
}
/** Retains a reference to the chars array! */
protected Chars(char[] chars, int offset, int length) {
super(offset + length);
_buffers[0] = new UnifiedDataPageX.Chars(chars, offset, length);
_buffer_current = 0;
_buffer_count = 1;
}
/**
* Makes a copy of the {@link CharSequence}.
*/
protected Chars(CharSequence chars, int offset, int length) {
this(chars_make_char_array(chars, offset, length), 0, length);
}
@Override
public final BufferType getType() { return BufferType.CHARS; }
@Override
protected final UnifiedDataPageX make_page(int page_size) {
UnifiedDataPageX p = new UnifiedDataPageX.Chars(page_size);
return p;
}
@Override
public final int maxValue() { return 0xffff; }
}
}