io.snappydata.thrift.internal.MemStringReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of snappydata-store-client Show documentation
Show all versions of snappydata-store-client Show documentation
SnappyData store based off Pivotal GemFireXD
/*
* Adapted from Android's StringReader having license below.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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.
*/
/*
* Changes for SnappyData data platform.
*
* Portions Copyright (c) 2017 SnappyData, Inc. 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. You
* may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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. See accompanying
* LICENSE file.
*/
package io.snappydata.thrift.internal;
import java.io.IOException;
import java.io.Reader;
import com.gemstone.gemfire.internal.shared.unsafe.UnsafeHolder;
/**
* Extension of JDK StringReader to use a StringBuffer which can be shared
* with StringWriter if required.
*/
@SuppressWarnings("SynchronizeOnNonFinalField")
public final class MemStringReader extends Reader {
/**
* using StringBuffer for the case of StringWriter as the source
*/
private StringBuffer sb;
private int markpos = -1;
private int pos;
/**
* Construct a new {@code MemStringReader} with {@code str} as source.
* The size of the reader is set to the {@code length()} of the string.
*
* @param str the source string for this reader.
*/
public MemStringReader(String str) {
super();
this.sb = new StringBuffer(str);
}
/**
* Construct a new {@code MemStringReader} with {@code sb} as source.
* The size of the reader is set to the {@code length()} of the StringBuilder.
*
* @param sb the source StringBuilder for this reader.
*/
MemStringReader(StringBuffer sb) {
super();
this.sb = sb;
}
/**
* Closes this reader. Once it is closed, read operations on this reader
* will throw an {@code IOException}. Only the first invocation of this
* method has any effect.
*/
@Override
public void close() {
this.sb = null;
}
/**
* Returns a boolean indicating whether this reader is closed.
*
* @return {@code true} if closed, otherwise {@code false}.
*/
private boolean isClosed() {
return sb == null;
}
/**
* Sets a mark position in this reader. The parameter {@code readLimit} is
* ignored for this class. Calling {@code reset()} will reposition the
* reader back to the marked position.
*
* @param readLimit ignored for {@code MemStringReader} instances.
* @throws IllegalArgumentException if {@code readLimit < 0}.
* @throws IOException if this reader is closed.
* @see #markSupported()
* @see #reset()
*/
@Override
public void mark(int readLimit) throws IOException {
if (readLimit < 0) {
throw new IllegalArgumentException();
}
synchronized (lock) {
checkNotClosed();
markpos = pos;
}
}
private void checkNotClosed() throws IOException {
if (isClosed()) {
throw new IOException("MemStringReader is closed");
}
}
/**
* Indicates whether this reader supports the {@code mark()} and {@code
* reset()} methods. This implementation returns {@code true}.
*
* @return always {@code true}.
*/
@Override
public boolean markSupported() {
return true;
}
/**
* Reads a single character from the source string and returns it as an
* integer with the two higher-order bytes set to 0. Returns -1 if the end
* of the source string has been reached.
*
* @return the character read or -1 if the end of the source string has been
* reached.
* @throws IOException if this reader is closed.
*/
@Override
public int read() throws IOException {
synchronized (lock) {
checkNotClosed();
if (pos != sb.length()) {
return sb.charAt(pos++);
}
return -1;
}
}
/**
* Reads at most {@code len} characters from the source string and stores
* them at {@code offset} in the character array {@code buf}. Returns the
* number of characters actually read or -1 if the end of the source string
* has been reached.
*
* @param buf the character array to store the characters read.
* @param offset the initial position in {@code buffer} to store the
* characters read from this reader.
* @param len the maximum number of characters to read.
* @return the number of characters read or -1 if the end of the reader has
* been reached.
* @throws IndexOutOfBoundsException if {@code offset < 0} or {@code len < 0},
* or if {@code offset + len} is greater
* than the size of {@code buf}.
* @throws IOException if this reader is closed.
*/
@Override
public int read(char[] buf, int offset, int len) throws IOException {
synchronized (lock) {
checkNotClosed();
UnsafeHolder.checkBounds(buf.length, offset, len);
if (len == 0) {
return 0;
}
final int count = sb.length();
if (pos == count) {
return -1;
}
int end = pos + len > count ? count : pos + len;
sb.getChars(pos, end, buf, offset);
int read = end - pos;
pos = end;
return read;
}
}
/**
* Indicates whether this reader is ready to be read without blocking. This
* implementation always returns {@code true}.
*
* @return always {@code true}.
* @throws IOException if this reader is closed.
* @see #read()
* @see #read(char[], int, int)
*/
@Override
public boolean ready() throws IOException {
synchronized (lock) {
checkNotClosed();
return true;
}
}
/**
* Resets this reader's position to the last {@code mark()} location.
* Invocations of {@code read()} and {@code skip()} will occur from this new
* location. If this reader has not been marked, it is reset to the
* beginning of the source string.
*
* @throws IOException if this reader is closed.
* @see #mark(int)
* @see #markSupported()
*/
@Override
public void reset() throws IOException {
synchronized (lock) {
checkNotClosed();
pos = markpos != -1 ? markpos : 0;
}
}
/**
* Moves {@code charCount} characters in the source string. Unlike the
* {@link Reader#skip(long) overridden method}, this method may skip negative
* skip distances: this rewinds the input so that characters may be read
* again. When the end of the source string has been reached, the input
* cannot be rewound.
*
* @param charCount the maximum number of characters to skip. Positive values
* skip forward; negative values skip backward.
* @return the number of characters actually skipped. This is bounded below
* by the number of characters already read and above by the
* number of characters remaining:
{@code -(num chars already
* read) <= distance skipped <= num chars remaining}.
* @throws IOException if this reader is closed.
* @see #mark(int)
* @see #markSupported()
* @see #reset()
*/
@Override
public long skip(long charCount) throws IOException {
synchronized (lock) {
checkNotClosed();
int minSkip = -pos;
int maxSkip = sb.length() - pos;
if (maxSkip == 0 || charCount > maxSkip) {
charCount = maxSkip; // no rewinding if we're at the end
} else if (charCount < minSkip) {
charCount = minSkip;
}
pos += charCount;
return charCount;
}
}
public StringBuffer getStringBuilder() {
return this.sb;
}
public int length() {
final StringBuffer sb = this.sb;
return sb != null ? sb.length() : 0;
}
}