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 the exception on overflow.
  41      * @param len String length
  42      * @return length
  43      */
  44     private static int checkOverflow(int len) {
  45         if (len < 0) {
  46             throw new OutOfMemoryError("Overflow: String length out of range");
  47         }
  48         return len;
  49     }
  50 
  51     /**
  52      * Mix value length into current length
  53      * @param current current length
  54      * @param value   value to mix in
  55      * @return new length
  56      */
  57     static int mixLen(int current, boolean value) {
  58         return checkOverflow(current + (value ? 4 : 5));
  59     }
  60 
  61     /**
  62      * Mix value length into current length
  63      * @param current current length
  64      * @param value   value to mix in
  65      * @return new length
  66      */
  67     static int mixLen(int current, byte value) {
  68         return mixLen(current, (int)value);
  69     }
  70 
  71     /**
  72      * Mix value length into current length
  73      * @param current current length
  74      * @param value   value to mix in
  75      * @return new length
  76      */
  77     static int mixLen(int current, char value) {
  78         return checkOverflow(current + 1);
  79     }
  80 
  81     /**
  82      * Mix value length into current length
  83      * @param current current length
  84      * @param value   value to mix in
  85      * @return new length
  86      */
  87     static int mixLen(int current, short value) {
  88         return mixLen(current, (int)value);
  89     }
  90 
  91     /**
  92      * Mix value length into current length
  93      * @param current current length
  94      * @param value   value to mix in
  95      * @return new length
  96      */
  97     static int mixLen(int current, int value) {
  98         return checkOverflow(current + Integer.stringSize(value));
  99     }
 100 
 101     /**
 102      * Mix value length into current length
 103      * @param current current length
 104      * @param value   value to mix in
 105      * @return new length
 106      */
 107     static int mixLen(int current, long value) {
 108         return checkOverflow(current + Long.stringSize(value));
 109     }
 110 
 111     /**
 112      * Mix value length into current length
 113      * @param current current length
 114      * @param value   value to mix in
 115      * @return new length
 116      */
 117     static int mixLen(int current, String value) {
 118         return checkOverflow(current + value.length());
 119     }
 120 
 121     /**
 122      * Mix coder into current coder
 123      * @param current current coder
 124      * @param value   value to mix in
 125      * @return new coder
 126      */
 127     static byte mixCoder(byte current, char value) {
 128         return (byte)(current | (StringLatin1.canEncode(value) ? 0 : 1));
 129     }
 130 
 131     /**
 132      * Mix coder into current coder
 133      * @param current current coder
 134      * @param value   value to mix in
 135      * @return new coder
 136      */
 137     static byte mixCoder(byte current, String value) {
 138         return (byte)(current | value.coder());
 139     }
 140 
 141     /**
 142      * Mix coder into current coder
 143      * @param current current coder
 144      * @param value   value to mix in
 145      * @return new coder
 146      */
 147     static byte mixCoder(byte current, boolean value) {
 148         // Booleans are represented with Latin1
 149         return current;
 150     }
 151 
 152     /**
 153      * Mix coder into current coder
 154      * @param current current coder
 155      * @param value   value to mix in
 156      * @return new coder
 157      */
 158     static byte mixCoder(byte current, byte value) {
 159         // Bytes are represented with Latin1
 160         return current;
 161     }
 162 
 163     /**
 164      * Mix coder into current coder
 165      * @param current current coder
 166      * @param value   value to mix in
 167      * @return new coder
 168      */
 169     static byte mixCoder(byte current, short value) {
 170         // Shorts are represented with Latin1
 171         return current;
 172     }
 173 
 174     /**
 175      * Mix coder into current coder
 176      * @param current current coder
 177      * @param value   value to mix in
 178      * @return new coder
 179      */
 180     static byte mixCoder(byte current, int value) {
 181         // Ints are represented with Latin1
 182         return current;
 183     }
 184 
 185     /**
 186      * Mix coder into current coder
 187      * @param current current coder
 188      * @param value   value to mix in
 189      * @return new coder
 190      */
 191     static byte mixCoder(byte current, long value) {
 192         // Longs are represented with Latin1
 193         return current;
 194     }
 195 
 196     /**
 197      * Prepends the stringly representation of boolean value into buffer,
 198      * given the coder and final index. Index is measured in chars, not in bytes!
 199      *
 200      * @param index final char index in the buffer
 201      * @param buf   buffer to append to
 202      * @param coder coder to add with
 203      * @param value boolean value to encode
 204      * @return new index
 205      */
 206     static int prepend(int index, byte[] buf, byte coder, boolean value) {
 207         if (coder == String.LATIN1) {
 208             if (value) {
 209                 buf[--index] = 'e';
 210                 buf[--index] = 'u';
 211                 buf[--index] = 'r';
 212                 buf[--index] = 't';
 213             } else {
 214                 buf[--index] = 'e';
 215                 buf[--index] = 's';
 216                 buf[--index] = 'l';
 217                 buf[--index] = 'a';
 218                 buf[--index] = 'f';
 219             }
 220         } else {
 221             if (value) {
 222                 StringUTF16.putChar(buf, --index, 'e');
 223                 StringUTF16.putChar(buf, --index, 'u');
 224                 StringUTF16.putChar(buf, --index, 'r');
 225                 StringUTF16.putChar(buf, --index, 't');
 226             } else {
 227                 StringUTF16.putChar(buf, --index, 'e');
 228                 StringUTF16.putChar(buf, --index, 's');
 229                 StringUTF16.putChar(buf, --index, 'l');
 230                 StringUTF16.putChar(buf, --index, 'a');
 231                 StringUTF16.putChar(buf, --index, 'f');
 232             }
 233         }
 234         return index;
 235     }
 236 
 237     /**
 238      * Prepends the stringly representation of byte value into buffer,
 239      * given the coder and final index. Index is measured in chars, not in bytes!
 240      *
 241      * @param index final char index in the buffer
 242      * @param buf   buffer to append to
 243      * @param coder coder to add with
 244      * @param value byte value to encode
 245      * @return new index
 246      */
 247     static int prepend(int index, byte[] buf, byte coder, byte value) {
 248         return prepend(index, buf, coder, (int)value);
 249     }
 250 
 251     /**
 252      * Prepends the stringly representation of char value into buffer,
 253      * given the coder and final index. Index is measured in chars, not in bytes!
 254      *
 255      * @param index final char index in the buffer
 256      * @param buf   buffer to append to
 257      * @param coder coder to add with
 258      * @param value char value to encode
 259      * @return new index
 260      */
 261     static int prepend(int index, byte[] buf, byte coder, char value) {
 262         if (coder == String.LATIN1) {
 263             buf[--index] = (byte) (value & 0xFF);
 264         } else {
 265             StringUTF16.putChar(buf, --index, value);
 266         }
 267         return index;
 268     }
 269 
 270     /**
 271      * Prepends the stringly representation of short value into buffer,
 272      * given the coder and final index. Index is measured in chars, not in bytes!
 273      *
 274      * @param index final char index in the buffer
 275      * @param buf   buffer to append to
 276      * @param coder coder to add with
 277      * @param value short value to encode
 278      * @return new index
 279      */
 280     static int prepend(int index, byte[] buf, byte coder, short value) {
 281         return prepend(index, buf, coder, (int)value);
 282     }
 283 
 284     /**
 285      * Prepends the stringly representation of integer value into buffer,
 286      * given the coder and final index. Index is measured in chars, not in bytes!
 287      *
 288      * @param index final char index in the buffer
 289      * @param buf   buffer to append to
 290      * @param coder coder to add with
 291      * @param value integer value to encode
 292      * @return new index
 293      */
 294     static int prepend(int index, byte[] buf, byte coder, int value) {
 295         if (coder == String.LATIN1) {
 296             return Integer.getChars(value, index, buf);
 297         } else {
 298             return StringUTF16.getChars(value, index, buf);
 299         }
 300     }
 301 
 302     /**
 303      * Prepends the stringly representation of long value into buffer,
 304      * given the coder and final index. Index is measured in chars, not in bytes!
 305      *
 306      * @param index final char index in the buffer
 307      * @param buf   buffer to append to
 308      * @param coder coder to add with
 309      * @param value long value to encode
 310      * @return new index
 311      */
 312     static int prepend(int index, byte[] buf, byte coder, long value) {
 313         if (coder == String.LATIN1) {
 314             return Long.getChars(value, index, buf);
 315         } else {
 316             return StringUTF16.getChars(value, index, buf);
 317         }
 318     }
 319 
 320     /**
 321      * Prepends the stringly representation of String value into buffer,
 322      * given the coder and final index. Index is measured in chars, not in bytes!
 323      *
 324      * @param index final char index in the buffer
 325      * @param buf   buffer to append to
 326      * @param coder coder to add with
 327      * @param value String value to encode
 328      * @return new index
 329      */
 330     static int prepend(int index, byte[] buf, byte coder, String value) {
 331         index -= value.length();
 332         value.getBytes(buf, index, coder);
 333         return index;
 334     }
 335 
 336     /**
 337      * Instantiates the String with given buffer and coder
 338      * @param buf     buffer to use
 339      * @param index   remaining index
 340      * @param coder   coder to use
 341      * @return String resulting string
 342      */
 343     static String newString(byte[] buf, int index, byte coder) {
 344         // Use the private, non-copying constructor (unsafe!)
 345         if (index != 0) {
 346             throw new InternalError("Storage is not completely initialized, " + index + " bytes left");
 347         }
 348         return new String(buf, coder);
 349     }
 350 
 351     /**
 352      * Provides the initial coder for the String.
 353      * @return initial coder
 354      */
 355     static byte initialCoder() {
 356         return String.COMPACT_STRINGS ? String.LATIN1 : String.UTF16;
 357     }
 358 
 359 }