content: // ASM: a very small and fast Java bytecode manipulation framework
  // Copyright (c) 2000-2011 INRIA, France Telecom
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions
  // are met:
  // 1. Redistributions of source code must retain the above copyright
  //    notice, this list of conditions and the following disclaimer.
  // 2. Redistributions in binary form must reproduce the above copyright
  //    notice, this list of conditions and the following disclaimer in the
  //    documentation and/or other materials provided with the distribution.
  // 3. Neither the name of the copyright holders nor the names of its
  //    contributors may be used to endorse or promote products derived from
  //    this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  // THE POSSIBILITY OF SUCH DAMAGE.
  package com.alibaba.fastjson2.internal.asm;
  
  /**
   * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
   * on top of a ByteArrayOutputStream, but is more efficient.
   *
   * @author Eric Bruneton
   */
  public class ByteVector {
      /**
       * The content of this vector. Only the first {@link #length} bytes contain real data.
       */
      byte[] data;
  
      /**
       * The actual number of bytes in this vector.
       */
      int length;
  
      /**
       * Constructs a new {@link ByteVector} with the given initial capacity.
       *
       * @param initialCapacity the initial capacity of the byte vector to be constructed.
       */
      public ByteVector(final int initialCapacity) {
          data = new byte[initialCapacity];
      }
  
      /**
       * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
       *
       * @param byteValue a byte.
       * @return this byte vector.
       */
      public ByteVector putByte(final int byteValue) {
          int currentLength = length;
          if (currentLength + 1 > data.length) {
              enlarge(1);
          }
          data[currentLength++] = (byte) byteValue;
          length = currentLength;
          return this;
      }
  
      /**
       * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
       *
       * @param byteValue1 a byte.
       * @param byteValue2 another byte.
       */
      final void put11(final int byteValue1, final int byteValue2) {
          int currentLength = length;
          if (currentLength + 2 > data.length) {
              enlarge(2);
          }
          byte[] currentData = data;
          currentData[currentLength++] = (byte) byteValue1;
          currentData[currentLength++] = (byte) byteValue2;
          length = currentLength;
      }
  
      /**
       * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
       *
       * @param shortValue a short.
       * @return this byte vector.
       */
      public ByteVector putShort(final int shortValue) {
          int currentLength = length;
          if (currentLength + 2 > data.length) {
              enlarge(2);
          }
          byte[] currentData = data;
          currentData[currentLength++] = (byte) (shortValue >>> 8);
          currentData[currentLength++] = (byte) shortValue;
          length = currentLength;
          return this;
      }
  
      /**
       * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
       * necessary.
       *
       * @param byteValue  a byte.
       * @param shortValue a short.
       * @return this byte vector.
       */
      final ByteVector put12(final int byteValue, final int shortValue) {
          int currentLength = length;
          if (currentLength + 3 > data.length) {
              enlarge(3);
          }
          byte[] currentData = data;
          currentData[currentLength++] = (byte) byteValue;
          currentData[currentLength++] = (byte) (shortValue >>> 8);
          currentData[currentLength++] = (byte) shortValue;
          length = currentLength;
          return this;
      }
  
      /**
       * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
       *
       * @param intValue an int.
       * @return this byte vector.
       */
      public ByteVector putInt(final int intValue) {
          int currentLength = length;
          if (currentLength + 4 > data.length) {
              enlarge(4);
          }
          byte[] currentData = data;
          currentData[currentLength++] = (byte) (intValue >>> 24);
          currentData[currentLength++] = (byte) (intValue >>> 16);
          currentData[currentLength++] = (byte) (intValue >>> 8);
          currentData[currentLength++] = (byte) intValue;
          length = currentLength;
          return this;
      }
  
      /**
       * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
       * if necessary.
       *
       * @param byteValue a byte.
       * @param shortValue1 a short.
       * @param shortValue2 another short.
       */
      final void put122(final int byteValue, final int shortValue1, final int shortValue2) {
          int currentLength = length;
          if (currentLength + 5 > data.length) {
              enlarge(5);
          }
          byte[] currentData = data;
          currentData[currentLength++] = (byte) byteValue;
          currentData[currentLength++] = (byte) (shortValue1 >>> 8);
          currentData[currentLength++] = (byte) shortValue1;
          currentData[currentLength++] = (byte) (shortValue2 >>> 8);
          currentData[currentLength++] = (byte) shortValue2;
          length = currentLength;
      }
  
      /**
       * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
       *
       * @param longValue a long.
       */
      public void putLong(final long longValue) {
          int currentLength = length;
          if (currentLength + 8 > data.length) {
              enlarge(8);
          }
          byte[] currentData = data;
          int intValue = (int) (longValue >>> 32);
          currentData[currentLength++] = (byte) (intValue >>> 24);
          currentData[currentLength++] = (byte) (intValue >>> 16);
          currentData[currentLength++] = (byte) (intValue >>> 8);
          currentData[currentLength++] = (byte) intValue;
          intValue = (int) longValue;
          currentData[currentLength++] = (byte) (intValue >>> 24);
          currentData[currentLength++] = (byte) (intValue >>> 16);
          currentData[currentLength++] = (byte) (intValue >>> 8);
          currentData[currentLength++] = (byte) intValue;
          length = currentLength;
      }
  
      /**
       * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
       * necessary.
       *
       * @param stringValue a String whose UTF8 encoded length must be less than 65536.
       */
      // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
      public void putUTF8(final String stringValue) {
          int charLength = stringValue.length();
          if (charLength > 65535) {
              throw new IllegalArgumentException("UTF8 string too large");
          }
          int currentLength = length;
          if (currentLength + 2 + charLength > data.length) {
              enlarge(2 + charLength);
          }
          byte[] currentData = data;
          // Optimistic algorithm: instead of computing the byte length and then serializing the string
          // (which requires two loops), we assume the byte length is equal to char length (which is the
          // most frequent case), and we start serializing the string right away. During the
          // serialization, if we find that this assumption is wrong, we continue with the general method.
          currentData[currentLength++] = (byte) (charLength >>> 8);
          currentData[currentLength++] = (byte) charLength;
          for (int i = 0; i < charLength; ++i) {
              char charValue = stringValue.charAt(i);
              if (charValue >= '\u0001' && charValue <= '\u007F') {
                  currentData[currentLength++] = (byte) charValue;
              } else {
                  length = currentLength;
                  encodeUtf8(stringValue, i);
                  return;
              }
          }
          length = currentLength;
      }
  
      /**
       * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
       * necessary. The string length is encoded in two bytes before the encoded characters, if there is
       * space for that (i.e. if this.length - offset - 2 &gt;= 0).
       *
       * @param stringValue the String to encode.
       * @param offset the index of the first character to encode. The previous characters are supposed
       * to have already been encoded, using only one byte per character.
       */
      final void encodeUtf8(final String stringValue, final int offset) {
          int charLength = stringValue.length();
          int byteLength = offset;
          for (int i = offset; i < charLength; ++i) {
              char charValue = stringValue.charAt(i);
              if (charValue >= 0x0001 && charValue <= 0x007F) {
                  byteLength++;
              } else if (charValue <= 0x07FF) {
                  byteLength += 2;
              } else {
                  byteLength += 3;
              }
          }
          if (byteLength > 65535) {
              throw new IllegalArgumentException("UTF8 string too large");
          }
          // Compute where 'byteLength' must be stored in 'data', and store it at this location.
          int byteLengthOffset = length - offset - 2;
          if (byteLengthOffset >= 0) {
              data[byteLengthOffset] = (byte) (byteLength >>> 8);
              data[byteLengthOffset + 1] = (byte) byteLength;
          }
          if (length + byteLength - offset > data.length) {
              enlarge(byteLength - offset);
          }
          int currentLength = length;
          for (int i = offset; i < charLength; ++i) {
              char charValue = stringValue.charAt(i);
              if (charValue >= 0x0001 && charValue <= 0x007F) {
                  data[currentLength++] = (byte) charValue;
              } else if (charValue <= 0x07FF) {
                  data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
                  data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
              } else {
                  data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
                  data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
                  data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
              }
          }
          length = currentLength;
      }
  
      /**
       * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
       * necessary.
       *
       * @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
       * bytes into this byte vector.
       * @param byteOffset index of the first byte of byteArrayValue that must be copied.
       * @param byteLength number of bytes of byteArrayValue that must be copied.
       */
      public void putByteArray(
              final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
          if (length + byteLength > data.length) {
              enlarge(byteLength);
          }
          if (byteArrayValue != null) {
              System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
          }
          length += byteLength;
      }
  
      /**
       * Enlarges this byte vector so that it can receive 'size' more bytes.
       *
       * @param size number of additional bytes that this byte vector should be able to receive.
       */
      private void enlarge(final int size) {
          int doubleCapacity = 2 * data.length;
          int minimalCapacity = length + size;
          byte[] newData = new byte[Math.max(doubleCapacity, minimalCapacity)];
          System.arraycopy(data, 0, newData, 0, length);
          data = newData;
      }
  }
  