1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang;
  27 
  28 /**
  29  * Helper for string concatenation. These methods are mostly looked up with private lookups
  30  * from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle}
  31  * combinators there.
  32  */
  33 final class StringConcatHelper {
  34 
  35     private StringConcatHelper() {
  36         // no instantiation
  37     }
  38 
  39     /**
  40      * Check for overflow, throw exception on overflow.
  41      * @param lengthCoder String length and coder
  42      * @return lengthCoder
  43      */
  44     private static long checkOverflow(long lengthCoder) {
  45         if ((int)lengthCoder >= 0) {
  46             return lengthCoder;
  47         }
  48         throw new OutOfMemoryError("Overflow: String length out of range");
  49     }
  50 
  51     /**
  52      * Mix value length and coder into current length and coder.
  53      * @param current current length
  54      * @param value   value to mix in
  55      * @return new length and coder
  56      */
  57     static long mix(long current, boolean value) {
  58         return checkOverflow(current + (value ? 4 : 5));
  59     }
  60 
  61     /**
  62      * Mix value length and coder into current length and coder.
  63      * @param current current length
  64      * @param value   value to mix in
  65      * @return new length and coder
  66      */
  67     static long mix(long current, byte value) {
  68         return mix(current, (int)value);
  69     }
  70 
  71     /**
  72      * Mix value length and coder into current length and coder.
  73      * @param current current length
  74      * @param value   value to mix in
  75      * @return new length and coder
  76      */
  77     static long mix(long current, char value) {
  78         return checkOverflow(current + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16);
  79     }
  80 
  81     /**
  82      * Mix value length and coder into current length and coder.
  83      * @param current current length
  84      * @param value   value to mix in
  85      * @return new length and coder
  86      */
  87     static long mix(long current, short value) {
  88         return mix(current, (int)value);
  89     }
  90 
  91     /**
  92      * Mix value length and coder into current length and coder.
  93      * @param current current length
  94      * @param value   value to mix in
  95      * @return new length and coder
  96      */
  97     static long mix(long current, int value) {
  98         return checkOverflow(current + Integer.stringSize(value));
  99     }
 100 
 101     /**
 102      * Mix value length and coder into current length and coder.
 103      * @param current current length
 104      * @param value   value to mix in
 105      * @return new length and coder
 106      */
 107     static long mix(long current, long value) {
 108         return checkOverflow(current + Long.stringSize(value));
 109     }
 110 
 111     /**
 112      * Mix value length and coder into current length and coder.
 113      * @param current current length
 114      * @param value   value to mix in
 115      * @return new length and coder
 116      */
 117     static long mix(long current, String value) {
 118         current += value.length();
 119         if (value.coder() == String.UTF16) {
 120             current |= UTF16;
 121         }
 122         return checkOverflow(current);
 123     }
 124 
 125     /**
 126      * Prepends the stringly representation of boolean value into buffer,
 127      * given the coder and final index. Index is measured in chars, not in bytes!
 128      *
 129      * @param indexCoder final char index in the buffer, along with coder packed
 130      *                   into higher bits.
 131      * @param buf        buffer to append to
 132      * @param value      boolean value to encode
 133      * @return           updated index (coder value retained)
 134      */
 135     static long prepend(long indexCoder, byte[] buf, boolean value) {
 136         int index = (int)indexCoder;
 137         if (indexCoder < UTF16) {
 138             if (value) {
 139                 buf[--index] = 'e';
 140                 buf[--index] = 'u';
 141                 buf[--index] = 'r';
 142                 buf[--index] = 't';
 143             } else {
 144                 buf[--index] = 'e';
 145                 buf[--index] = 's';
 146                 buf[--index] = 'l';
 147                 buf[--index] = 'a';
 148                 buf[--index] = 'f';
 149             }
 150             return index;
 151         } else {
 152             if (value) {
 153                 StringUTF16.putChar(buf, --index, 'e');
 154                 StringUTF16.putChar(buf, --index, 'u');
 155                 StringUTF16.putChar(buf, --index, 'r');
 156                 StringUTF16.putChar(buf, --index, 't');
 157             } else {
 158                 StringUTF16.putChar(buf, --index, 'e');
 159                 StringUTF16.putChar(buf, --index, 's');
 160                 StringUTF16.putChar(buf, --index, 'l');
 161                 StringUTF16.putChar(buf, --index, 'a');
 162                 StringUTF16.putChar(buf, --index, 'f');
 163             }
 164             return index | UTF16;
 165         }
 166     }
 167 
 168     /**
 169      * Prepends the stringly representation of byte value into buffer,
 170      * given the coder and final index. Index is measured in chars, not in bytes!
 171      *
 172      * @param indexCoder final char index in the buffer, along with coder packed
 173      *                   into higher bits.
 174      * @param buf        buffer to append to
 175      * @param value      byte value to encode
 176      * @return           updated index (coder value retained)
 177      */
 178     static long prepend(long indexCoder, byte[] buf, byte value) {
 179         return prepend(indexCoder, buf, (int)value);
 180     }
 181 
 182     /**
 183      * Prepends the stringly representation of char value into buffer,
 184      * given the coder and final index. Index is measured in chars, not in bytes!
 185      *
 186      * @param indexCoder final char index in the buffer, along with coder packed
 187      *                   into higher bits.
 188      * @param buf        buffer to append to
 189      * @param value      char value to encode
 190      * @return           updated index (coder value retained)
 191      */
 192     static long prepend(long indexCoder, byte[] buf, char value) {
 193         if (indexCoder < UTF16) {
 194             buf[(int)(--indexCoder)] = (byte) (value & 0xFF);
 195         } else {
 196             StringUTF16.putChar(buf, (int)(--indexCoder), value);
 197         }
 198         return indexCoder;
 199     }
 200 
 201     /**
 202      * Prepends the stringly representation of short value into buffer,
 203      * given the coder and final index. Index is measured in chars, not in bytes!
 204      *
 205      * @param indexCoder final char index in the buffer, along with coder packed
 206      *                   into higher bits.
 207      * @param buf        buffer to append to
 208      * @param value      short value to encode
 209      * @return           updated index (coder value retained)
 210      */
 211     static long prepend(long indexCoder, byte[] buf, short value) {
 212         return prepend(indexCoder, buf, (int)value);
 213     }
 214 
 215     /**
 216      * Prepends the stringly representation of integer value into buffer,
 217      * given the coder and final index. Index is measured in chars, not in bytes!
 218      *
 219      * @param indexCoder final char index in the buffer, along with coder packed
 220      *                   into higher bits.
 221      * @param buf        buffer to append to
 222      * @param value      integer value to encode
 223      * @return           updated index (coder value retained)
 224      */
 225     static long prepend(long indexCoder, byte[] buf, int value) {
 226         if (indexCoder < UTF16) {
 227             return Integer.getChars(value, (int)indexCoder, buf);
 228         } else {
 229             return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16;
 230         }
 231     }
 232 
 233     /**
 234      * Prepends the stringly representation of long value into buffer,
 235      * given the coder and final index. Index is measured in chars, not in bytes!
 236      *
 237      * @param indexCoder final char index in the buffer, along with coder packed
 238      *                   into higher bits.
 239      * @param buf        buffer to append to
 240      * @param value      long value to encode
 241      * @return           updated index (coder value retained)
 242      */
 243     static long prepend(long indexCoder, byte[] buf, long value) {
 244         if (indexCoder < UTF16) {
 245             return Long.getChars(value, (int)indexCoder, buf);
 246         } else {
 247             return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16;
 248         }
 249     }
 250 
 251     /**
 252      * Prepends the stringly representation of String value into buffer,
 253      * given the coder and final index. Index is measured in chars, not in bytes!
 254      *
 255      * @param indexCoder final char index in the buffer, along with coder packed
 256      *                   into higher bits.
 257      * @param buf        buffer to append to
 258      * @param value      String value to encode
 259      * @return           updated index (coder value retained)
 260      */
 261     static long prepend(long indexCoder, byte[] buf, String value) {
 262         indexCoder -= value.length();
 263         if (indexCoder < UTF16) {
 264             value.getBytes(buf, (int)indexCoder, String.LATIN1);
 265         } else {
 266             value.getBytes(buf, (int)indexCoder, String.UTF16);
 267         }
 268         return indexCoder;
 269     }
 270 
 271     /**
 272      * Instantiates the String with given buffer and coder
 273      * @param buf           buffer to use
 274      * @param indexCoder    remaining index (should be zero) and coder
 275      * @return String       resulting string
 276      */
 277     static String newString(byte[] buf, long indexCoder) {
 278         // Use the private, non-copying constructor (unsafe!)
 279         if (indexCoder == LATIN1) {
 280             return new String(buf, String.LATIN1);
 281         } else if (indexCoder == UTF16) {
 282             return new String(buf, String.UTF16);
 283         } else {
 284             throw new InternalError("Storage is not completely initialized, " + (int)indexCoder + " bytes left");
 285         }
 286     }
 287 
 288     private static final long LATIN1 = (long)String.LATIN1 << 32;
 289 
 290     private static final long UTF16 = (long)String.UTF16 << 32;
 291 
 292     /**
 293      * Provides the initial coder for the String.
 294      * @return initial coder, adjusted into the upper half
 295      */
 296     static long initialCoder() {
 297         return String.COMPACT_STRINGS ? LATIN1 : UTF16;
 298     }
 299 
 300 }