/* * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.lang; /** * Helper for string concatenation. These methods are mostly looked up with private lookups * from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle} * combinators there. */ class StringConcatHelper { private StringConcatHelper() { // no instantiation } /** * Check for overflow, throw the exception on overflow. * @param len String length * @return length */ private static int checkOverflow(int len) { if (len < 0) { throw new OutOfMemoryError("Overflow: String length out of range"); } return len; } /** * Mix value length into current length * @param current current length * @param value value to mix in * @return new length */ static int mixLen(int current, boolean value) { return checkOverflow(current + (value ? 4 : 5)); } /** * Mix value length into current length * @param current current length * @param value value to mix in * @return new length */ static int mixLen(int current, byte value) { return mixLen(current, (int)value); } /** * Mix value length into current length * @param current current length * @param value value to mix in * @return new length */ static int mixLen(int current, char value) { return checkOverflow(current + 1); } /** * Mix value length into current length * @param current current length * @param value value to mix in * @return new length */ static int mixLen(int current, short value) { return mixLen(current, (int)value); } /** * Mix value length into current length * @param current current length * @param value value to mix in * @return new length */ static int mixLen(int current, int value) { return checkOverflow(current + Integer.stringSize(value)); } /** * Mix value length into current length * @param current current length * @param value value to mix in * @return new length */ static int mixLen(int current, long value) { return checkOverflow(current + Long.stringSize(value)); } /** * Mix value length into current length * @param current current length * @param value value to mix in * @return new length */ static int mixLen(int current, String value) { return checkOverflow(current + value.length()); } /** * Mix coder into current coder * @param current current coder * @param value value to mix in * @return new coder */ static byte mixCoder(byte current, char value) { return (byte)(current | (StringLatin1.canEncode(value) ? 0 : 1)); } /** * Mix coder into current coder * @param current current coder * @param value value to mix in * @return new coder */ static byte mixCoder(byte current, String value) { return (byte)(current | value.coder()); } /** * Mix coder into current coder * @param current current coder * @param value value to mix in * @return new coder */ static byte mixCoder(byte current, boolean value) { // Booleans are represented with Latin1 return current; } /** * Mix coder into current coder * @param current current coder * @param value value to mix in * @return new coder */ static byte mixCoder(byte current, byte value) { // Bytes are represented with Latin1 return current; } /** * Mix coder into current coder * @param current current coder * @param value value to mix in * @return new coder */ static byte mixCoder(byte current, short value) { // Shorts are represented with Latin1 return current; } /** * Mix coder into current coder * @param current current coder * @param value value to mix in * @return new coder */ static byte mixCoder(byte current, int value) { // Ints are represented with Latin1 return current; } /** * Mix coder into current coder * @param current current coder * @param value value to mix in * @return new coder */ static byte mixCoder(byte current, long value) { // Longs are represented with Latin1 return current; } /** * Prepends the stringly representation of boolean value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param index final char index in the buffer * @param buf buffer to append to * @param coder coder to add with * @param value boolean value to encode * @return new index */ static int prepend(int index, byte[] buf, byte coder, boolean value) { if (coder == String.LATIN1) { if (value) { buf[--index] = 'e'; buf[--index] = 'u'; buf[--index] = 'r'; buf[--index] = 't'; } else { buf[--index] = 'e'; buf[--index] = 's'; buf[--index] = 'l'; buf[--index] = 'a'; buf[--index] = 'f'; } } else { if (value) { StringUTF16.putChar(buf, --index, 'e'); StringUTF16.putChar(buf, --index, 'u'); StringUTF16.putChar(buf, --index, 'r'); StringUTF16.putChar(buf, --index, 't'); } else { StringUTF16.putChar(buf, --index, 'e'); StringUTF16.putChar(buf, --index, 's'); StringUTF16.putChar(buf, --index, 'l'); StringUTF16.putChar(buf, --index, 'a'); StringUTF16.putChar(buf, --index, 'f'); } } return index; } /** * Prepends the stringly representation of byte value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param index final char index in the buffer * @param buf buffer to append to * @param coder coder to add with * @param value byte value to encode * @return new index */ static int prepend(int index, byte[] buf, byte coder, byte value) { return prepend(index, buf, coder, (int)value); } /** * Prepends the stringly representation of char value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param index final char index in the buffer * @param buf buffer to append to * @param coder coder to add with * @param value char value to encode * @return new index */ static int prepend(int index, byte[] buf, byte coder, char value) { if (coder == String.LATIN1) { buf[--index] = (byte) (value & 0xFF); } else { StringUTF16.putChar(buf, --index, value); } return index; } /** * Prepends the stringly representation of short value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param index final char index in the buffer * @param buf buffer to append to * @param coder coder to add with * @param value short value to encode * @return new index */ static int prepend(int index, byte[] buf, byte coder, short value) { return prepend(index, buf, coder, (int)value); } /** * Prepends the stringly representation of integer value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param index final char index in the buffer * @param buf buffer to append to * @param coder coder to add with * @param value integer value to encode * @return new index */ static int prepend(int index, byte[] buf, byte coder, int value) { if (coder == String.LATIN1) { return Integer.getChars(value, index, buf); } else { return Integer.getCharsUTF16(value, index, buf); } } /** * Prepends the stringly representation of long value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param index final char index in the buffer * @param buf buffer to append to * @param coder coder to add with * @param value long value to encode * @return new index */ static int prepend(int index, byte[] buf, byte coder, long value) { if (coder == String.LATIN1) { return Long.getChars(value, index, buf); } else { return Long.getCharsUTF16(value, index, buf); } } /** * Prepends the stringly representation of String value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param index final char index in the buffer * @param buf buffer to append to * @param coder coder to add with * @param value String value to encode * @return new index */ static int prepend(int index, byte[] buf, byte coder, String value) { index -= value.length(); value.getBytes(buf, index, coder); return index; } /** * Instantiates the String with given buffer and coder * @param buf buffer to use * @param coder coder to use * @return String resulting string */ static String newString(byte[] buf, byte coder) { // Use the private, non-copying constructor (unsafe!) return new String(buf, coder); } }