All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.weeaboo.lua2.vm.Buffer Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2009 Luaj.org. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

package nl.weeaboo.lua2.vm;

import java.io.Serializable;

import javax.annotation.Nullable;

import nl.weeaboo.lua2.io.LuaSerializable;

/**
 * String buffer for use in string library methods, optimized for production of
 * StrValue instances.
 * 

* The buffer can begin initially as a wrapped {@link LuaValue} and only when * concatenation actually occurs are the bytes first copied. *

* To convert back to a {@link LuaValue} again, the function * {@link Buffer#value()} is used. * * @see LuaValue * @see LuaValue#buffer() * @see LuaString */ @LuaSerializable public final class Buffer implements Serializable { private static final long serialVersionUID = -196291611213071536L; /** Default capacity for a buffer: 64 */ private static final int DEFAULT_CAPACITY = 64; /** Shared static array with no bytes */ private static final byte[] NOBYTES = {}; /** Bytes in this buffer */ private byte[] bytes; /** Length of this buffer */ private int length; /** Offset into the byte array */ private int offset; /** Value of this buffer, when not represented in bytes */ private @Nullable LuaValue value; /** * Create buffer with default capacity (64) */ public Buffer() { this(DEFAULT_CAPACITY); } /** * Create buffer with specified initial capacity * * @param initialCapacity the initial capacity */ public Buffer(int initialCapacity) { bytes = new byte[initialCapacity]; length = 0; offset = 0; value = null; } /** * Create buffer with specified initial value * * @param value the initial value */ public Buffer(LuaValue value) { bytes = NOBYTES; length = offset = 0; this.value = value; } /** * Get buffer contents as a {@link LuaValue} * * @return value as a {@link LuaValue}, converting as necessary */ public LuaValue value() { LuaValue result = value; if (result == null) { result = tostring(); } return result; } /** * Set buffer contents as a {@link LuaValue} * * @param value value to set */ public Buffer setvalue(LuaValue value) { bytes = NOBYTES; offset = length = 0; this.value = value; return this; } /** * Convert the buffer to a {@link LuaString} * * @return the value as a {@link LuaString} */ public final LuaString tostring() { realloc(length, 0); return LuaString.valueOf(bytes, offset, length); } /** * Convert the buffer to a Java String * * @return the value as a Java String */ public String tojstring() { return value().tojstring(); } /** * Convert the buffer to a Java String * * @return the value as a Java String */ @Override public String toString() { return value().toString(); } /** * Append a single byte to the buffer. * * @return {@code this} to allow call chaining */ public final Buffer append(byte b) { makeroom(0, 1); bytes[offset + length++] = b; return this; } /** * Append a {@link LuaValue} to the buffer. * * @return {@code this} to allow call chaining */ public final Buffer append(LuaValue val) { append(val.strvalue()); return this; } /** * Append a {@link LuaString} to the buffer. * * @return {@code this} to allow call chaining */ public final Buffer append(LuaString str) { final int n = str.length(); makeroom(0, n); str.copyInto(0, bytes, offset + length, n); length += n; return this; } /** * Append a Java String to the buffer. The Java string will be converted to * bytes using the UTF8 encoding. * * @return {@code this} to allow call chaining * @see LuaString#encodeToUtf8(char[], byte[], int) */ public final Buffer append(String str) { char[] chars = str.toCharArray(); final int n = LuaString.lengthAsUtf8(chars); makeroom(0, n); LuaString.encodeToUtf8(chars, bytes, offset + length); length += n; return this; } /** * Concatenate this buffer onto a {@link LuaValue} * * @param lhs the left-hand-side value onto which we are concatenating * {@code this} * @return {@link Buffer} for use in call chaining. */ public Buffer concatTo(LuaValue lhs) { return setvalue(lhs.concat(value())); } /** * Concatenate this buffer onto a {@link LuaString} * * @param lhs the left-hand-side value onto which we are concatenating * {@code this} * @return {@link Buffer} for use in call chaining. */ public Buffer concatTo(LuaString lhs) { return value != null && !value.isstring() ? setvalue(lhs.concat(value)) : prepend(lhs); } /** * Concatenate this buffer onto a {@link LuaNumber} *

* The {@link LuaNumber} will be converted to a string before concatenating. * * @param lhs the left-hand-side value onto which we are concatenating * {@code this} * @return {@link Buffer} for use in call chaining. */ public Buffer concatTo(LuaNumber lhs) { return value != null && !value.isstring() ? setvalue(lhs.concat(value)) : prepend(lhs.strvalue()); } /** * Concatenate bytes from a {@link LuaString} onto the front of this buffer * * @param s the left-hand-side value which we will concatenate onto the * front of {@code this} * @return {@link Buffer} for use in call chaining. */ public Buffer prepend(LuaString s) { int n = s.length(); makeroom(n, 0); s.copyInto(0, bytes, offset - n, n); offset -= n; length += n; value = null; return this; } /** * Ensure there is enough room before and after the bytes. * * @param nbefore number of unused bytes which must precede the data after * this completes * @param nafter number of unused bytes which must follow the data after * this completes */ public final void makeroom(int nbefore, int nafter) { LuaString.assertValidStringLength(nbefore + length + nafter); if (value != null) { LuaString s = value.strvalue(); value = null; length = s.length(); offset = nbefore; bytes = new byte[nbefore + length + nafter]; s.copyInto(0, bytes, offset, length); } else if (offset + length + nafter > bytes.length || offset < nbefore) { int n = nbefore + length + nafter; int m = n < 32 ? 32 : n < length * 2 ? length * 2 : n; realloc(m, nbefore == 0 ? 0 : m - length - nafter); } } /** * Reallocate the internal storage for the buffer * * @param newSize the size of the buffer to use * @param newOffset the offset to use */ private final void realloc(int newSize, int newOffset) { LuaString.assertValidStringLength(newSize); if (newSize != bytes.length) { byte[] newBytes = new byte[newSize]; System.arraycopy(bytes, offset, newBytes, newOffset, length); bytes = newBytes; offset = newOffset; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy