Coverage Summary for Class: FlatByteArrayWriter (com.ghost.serialization.writer)

Class Class, % Method, % Branch, % Line, % Instruction, %
FlatByteArrayWriter 100% (1/1) 100% (21/21) 75% (39/52) 89.8% (158/176) 86.3% (724/839)


 package com.ghost.serialization.writer
 
 import com.ghost.serialization.InternalGhostApi
 import com.ghost.serialization.parser.GhostJsonConstants as C
 import com.ghost.serialization.parser.GhostJsonConstants.BUFFER_SCALE_FACTOR
 import com.ghost.serialization.parser.GhostJsonConstants.HIGH_SURROGATE_END
 import com.ghost.serialization.parser.GhostJsonConstants.HIGH_SURROGATE_START
 import com.ghost.serialization.parser.GhostJsonConstants.INITIAL_WRITE_BUFFER_SIZE
 import com.ghost.serialization.parser.GhostHeuristics
 import com.ghost.serialization.parser.GhostJsonConstants.LOW_SURROGATE_END
 import com.ghost.serialization.parser.GhostJsonConstants.LOW_SURROGATE_START
 import com.ghost.serialization.parser.GhostJsonConstants.SHIFT_10
 import com.ghost.serialization.parser.GhostJsonConstants.SHIFT_12
 import com.ghost.serialization.parser.GhostJsonConstants.UNICODE_BASE
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_1BYTE_LIMIT
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_2BYTE_LIMIT
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_2BYTE_PREFIX
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_3BYTE_PREFIX
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_4BYTE_PREFIX
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_CONT_MASK
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_CONT_PREFIX
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_MAX_BMP_BYTES
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_REPLACEMENT_CHAR
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_SHIFT_18
 import com.ghost.serialization.parser.GhostJsonConstants.UTF8_SHIFT_6
 import com.ghost.serialization.parser.GhostJsonConstants.CAPACITY_GROWTH_SHIFT
 import okio.ByteString
 
 /**
  * A growing flat-array byte buffer used as the in-memory output target for
  * [GhostJsonFlatWriter]. It is intentionally a `final` concrete class with no
  * interface or superclass so every byte-write made by [GhostJsonFlatWriter]
  * resolves as a monomorphic call the JIT (HotSpot/ART) and Kotlin/Native AOT
  * compiler can fully inline — no v-table lookup, no segment management, just
  * direct array stores.
  *
  * Compared to the streaming path that writes through [okio.Buffer]/segments,
  * this class trades the ability to incrementally drain bytes for ~2-3x
  * faster small-encode throughput. The full encoded payload is exposed at
  * the end of the encode via [toByteArray] / [toStringUtf8] (or accessed
  * directly via [array] + [size] for zero-copy fast paths).
  */
 @InternalGhostApi
 class FlatByteArrayWriter(private val initialCapacity: Int = INITIAL_WRITE_BUFFER_SIZE) {
 
     /**
      * Backing store. The slice `array[0 until size]` is the live encoded
      * payload; everything past `size` is uninitialized / stale capacity.
      */
     var array: ByteArray = ByteArray(initialCapacity)
         private set
 
     /** Number of bytes currently written into [array]. */
     var size: Int = 0
         private set
 
     /**
      * Grows [array] until at least `extraBytes` more bytes can fit past
      * the current [size]. Capacity grows geometrically by [BUFFER_SCALE_FACTOR]
      * to amortize copy cost over many writes.
      */
     private fun ensureCapacity(extraBytes: Int) {
         val requiredCapacity = size + extraBytes
         if (requiredCapacity < 0) {
             throw IllegalStateException(C.ERR_CAPACITY_OVERFLOW_PREFIX + "size=$size, extraBytes=$extraBytes")
         }
         if (requiredCapacity > array.size) {
             var newCapacity = array.size
             if (newCapacity == 0) {
                 newCapacity = INITIAL_WRITE_BUFFER_SIZE
             }
             while (newCapacity < requiredCapacity) {
                 val nextCapacity = newCapacity + (newCapacity shr CAPACITY_GROWTH_SHIFT)
                 if (nextCapacity < newCapacity) {
                     newCapacity = Int.MAX_VALUE
                     break
                 }
                 newCapacity = nextCapacity
             }
             if (newCapacity < requiredCapacity) {
                 newCapacity = requiredCapacity
             }
             array = array.copyOf(newCapacity)
         }
     }
 
     /** Appends a single byte (low 8 bits of [byteAsInt]). Optimized for inlining. */
     fun writeByte(byteAsInt: Int) {
         val currentSize = size
         val backingArray = array
         if (currentSize < backingArray.size) {
             backingArray[currentSize] = byteAsInt.toByte()
             size = currentSize + 1
         } else {
             growAndWrite(byteAsInt)
         }
     }
 
     private fun growAndWrite(byteAsInt: Int) {
         ensureCapacity(1)
         array[size++] = byteAsInt.toByte()
     }
 
     /**
      * Appends exactly two bytes in a single bounds-check.
      * Use instead of two consecutive [writeByte] calls whenever both bytes
      * are known at the call site (e.g. opening + closing quotes, escape pairs).
      */
     fun write2Bytes(firstByte: Int, secondByte: Int) {
         val currentSize = size
         val backingArray = array
         if (currentSize + 1 < backingArray.size) {
             backingArray[currentSize] = firstByte.toByte()
             backingArray[currentSize + 1] = secondByte.toByte()
             size = currentSize + 2
         } else {
             ensureCapacity(2)
             val updatedArray = array
             updatedArray[currentSize] = firstByte.toByte()
             updatedArray[currentSize + 1] = secondByte.toByte()
             size = currentSize + 2
         }
     }
 
     /**
      * Writes `"text"` directly into [array] for a caller-verified plain-ASCII
      * string (all chars in [0x20, 0x7E] with no `"` or `\`).
      *
      * Avoids the scratch-buffer accumulation used by the generic escape path,
      * saving one intermediate copy + thread-local acquire for the common case.
      */
     fun writeQuotedAscii(text: String, length: Int) {
         ensureCapacity(length + C.STRING_QUOTE_PAIR_BYTES)
         val backingArray = array
         var writeIndex = size
         backingArray[writeIndex++] = C.QUOTE_INT.toByte()
         var charIndex = 0
         // Unrolled x4 for instruction-level parallelism
         while (charIndex + 3 < length) {
             backingArray[writeIndex] = text[charIndex].code.toByte()
             backingArray[writeIndex + 1] = text[charIndex + 1].code.toByte()
             backingArray[writeIndex + 2] = text[charIndex + 2].code.toByte()
             backingArray[writeIndex + 3] = text[charIndex + 3].code.toByte()
             writeIndex += 4
             charIndex += 4
         }
         while (charIndex < length) {
             backingArray[writeIndex++] = text[charIndex].code.toByte()
             charIndex++
         }
         backingArray[writeIndex++] = C.QUOTE_INT.toByte()
         size = writeIndex
     }
 
     /** Appends every byte from [bytes] to the live payload. */
     fun write(bytes: ByteArray) {
         ensureCapacity(bytes.size)
         bytes.copyInto(array, size)
         size += bytes.size
     }
 
     /** Appends `bytes[offset until offset + length]` to the live payload. */
     fun write(bytes: ByteArray, offset: Int, length: Int) {
         ensureCapacity(length)
         bytes.copyInto(
             array,
             size,
             offset,
             offset + length
         )
         size += length
     }
 
     /** Appends every byte of the immutable [byteString] to the live payload. */
     fun write(byteString: ByteString) {
         val length = byteString.size
         ensureCapacity(length)
         byteString.copyInto(
             0,
             array,
             size,
             length
         )
         size += length
     }
 
     /** UTF-8 encodes the entire string [text] directly into the payload. */
     fun writeUtf8(text: String) {
         writeUtf8(text, 0, text.length)
     }
 
     /**
      * UTF-8 encodes `text[beginIndex until endIndex)` directly into [array].
      *
      * Hand-rolled to avoid the intermediate `String.toByteArray()` copy that
      * `okio.Buffer.writeUtf8` would otherwise allocate. The ASCII fast-path
      * (BMP code points below [UTF8_1BYTE_LIMIT]) collapses to a single
      * array store per character. Surrogate pairs are decoded into a 4-byte
      * sequence; lone surrogates emit [UTF8_REPLACEMENT_CHAR].
      */
     fun writeUtf8(text: String, beginIndex: Int, endIndex: Int) {
         val count = endIndex - beginIndex
         ensureCapacity(count * UTF8_MAX_BMP_BYTES)
         var sourceIndex = beginIndex
         var writeIndex = size
         val backingArray = array
 
         // ASCII Fast-Path with unrolling
         while (sourceIndex + 3 < endIndex) {
             val charCode0 = text[sourceIndex].code
             val charCode1 = text[sourceIndex + 1].code
             val charCode2 = text[sourceIndex + 2].code
             val charCode3 = text[sourceIndex + 3].code
 
             if ((charCode0 or charCode1 or charCode2 or charCode3) < UTF8_1BYTE_LIMIT) {
                 backingArray[writeIndex] = charCode0.toByte()
                 backingArray[writeIndex + 1] = charCode1.toByte()
                 backingArray[writeIndex + 2] = charCode2.toByte()
                 backingArray[writeIndex + 3] = charCode3.toByte()
                 sourceIndex += 4
                 writeIndex += 4
             } else {
                 break
             }
         }
 
         while (sourceIndex < endIndex) {
             val codePoint = text[sourceIndex].code
             when {
                 codePoint < UTF8_1BYTE_LIMIT -> {
                     backingArray[writeIndex++] = codePoint.toByte()
                 }
 
                 codePoint < UTF8_2BYTE_LIMIT -> {
                     backingArray[writeIndex++] =
                         (UTF8_2BYTE_PREFIX or (codePoint shr UTF8_SHIFT_6)).toByte()
                     backingArray[writeIndex++] =
                         (UTF8_CONT_PREFIX or (codePoint and UTF8_CONT_MASK)).toByte()
                 }
 
                 codePoint !in HIGH_SURROGATE_START..LOW_SURROGATE_END -> {
                     backingArray[writeIndex++] =
                         (UTF8_3BYTE_PREFIX or (codePoint shr SHIFT_12)).toByte()
                     backingArray[writeIndex++] =
                         (UTF8_CONT_PREFIX or ((codePoint shr UTF8_SHIFT_6) and UTF8_CONT_MASK)).toByte()
                     backingArray[writeIndex++] =
                         (UTF8_CONT_PREFIX or (codePoint and UTF8_CONT_MASK)).toByte()
                 }
 
                 codePoint <= HIGH_SURROGATE_END && sourceIndex + 1 < endIndex -> {
                     val lowSurrogate = text[sourceIndex + 1].code
                     if (lowSurrogate in LOW_SURROGATE_START..LOW_SURROGATE_END) {
                         val fullCodePoint = UNICODE_BASE +
                             (((codePoint - HIGH_SURROGATE_START) shl SHIFT_10) or
                                 (lowSurrogate - LOW_SURROGATE_START))
                         backingArray[writeIndex++] =
                             (UTF8_4BYTE_PREFIX or (fullCodePoint shr UTF8_SHIFT_18)).toByte()
                         backingArray[writeIndex++] =
                             (UTF8_CONT_PREFIX or ((fullCodePoint shr SHIFT_12) and UTF8_CONT_MASK)).toByte()
                         backingArray[writeIndex++] =
                             (UTF8_CONT_PREFIX or ((fullCodePoint shr UTF8_SHIFT_6) and UTF8_CONT_MASK)).toByte()
                         backingArray[writeIndex++] =
                             (UTF8_CONT_PREFIX or (fullCodePoint and UTF8_CONT_MASK)).toByte()
                         sourceIndex++
                     } else {
                         UTF8_REPLACEMENT_CHAR.copyInto(backingArray, writeIndex)
                         writeIndex += UTF8_REPLACEMENT_CHAR.size
                     }
                 }
 
                 else -> {
                     UTF8_REPLACEMENT_CHAR.copyInto(backingArray, writeIndex)
                     writeIndex += UTF8_REPLACEMENT_CHAR.size
                 }
             }
             sourceIndex++
         }
         size = writeIndex
     }
 
     /**
      * Writes a JSON string containing a single BMP code point, without allocating a [String].
      */
     fun writeQuotedBmpCodeUnit(codePoint: Int) {
         ensureCapacity(C.STRING_QUOTE_PAIR_BYTES + C.UTF8_3BYTE_SIZE)
         writeByte(C.QUOTE_INT)
         writeBmpUtf8CodeUnit(codePoint)
         writeByte(C.QUOTE_INT)
     }
 
     private fun writeBmpUtf8CodeUnit(codePoint: Int) {
         when {
             codePoint < UTF8_1BYTE_LIMIT -> writeByte(codePoint)
             codePoint < UTF8_2BYTE_LIMIT -> {
                 writeByte(UTF8_2BYTE_PREFIX or (codePoint shr UTF8_SHIFT_6))
                 writeByte(UTF8_CONT_PREFIX or (codePoint and UTF8_CONT_MASK))
             }
             else -> {
                 writeByte(UTF8_3BYTE_PREFIX or (codePoint shr SHIFT_12))
                 writeByte(UTF8_CONT_PREFIX or ((codePoint shr UTF8_SHIFT_6) and UTF8_CONT_MASK))
                 writeByte(UTF8_CONT_PREFIX or (codePoint and UTF8_CONT_MASK))
             }
         }
     }
 
     /** Writes the literal "true" directly. */
     fun writeTrue() {
         ensureCapacity(4)
         val backingArray = array
         var writeIndex = size
         backingArray[writeIndex++] = C.T_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.R_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.U_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.E_BYTE_INT.toByte()
         size = writeIndex
     }
 
     /** Writes the literal "false" directly. */
     fun writeFalse() {
         ensureCapacity(5)
         val backingArray = array
         var writeIndex = size
         backingArray[writeIndex++] = C.F_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.A_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.L_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.S_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.E_BYTE_INT.toByte()
         size = writeIndex
     }
 
     /** Writes the literal "null" directly. */
     fun writeNull() {
         ensureCapacity(4)
         val backingArray = array
         var writeIndex = size
         backingArray[writeIndex++] = C.N_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.U_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.L_BYTE_INT.toByte()
         backingArray[writeIndex++] = C.L_BYTE_INT.toByte()
         size = writeIndex
     }
 
     /** Writes the literal ".0" directly. */
     fun writeDotZero() {
         ensureCapacity(2)
         val backingArray = array
         var writeIndex = size
         backingArray[writeIndex++] = C.DOT_INT.toByte()
         backingArray[writeIndex++] = C.ZERO_INT.toByte()
         size = writeIndex
     }
 
     /**
      * Marks the buffer as empty without releasing capacity, so the next
      * encode reuses the already-grown [array].
      */
     fun reset() {
         size = 0
         if (array.size > GhostHeuristics.maxWarmWriteBufferCapacity) {
             array = ByteArray(initialCapacity)
         }
     }
 
     /** Returns a fresh [ByteArray] containing exactly the encoded payload. */
     fun toByteArray(): ByteArray = array.copyOf(size)
 
     /** Decodes the encoded payload back into a [String] (UTF-8). */
     fun toStringUtf8(): String = array.decodeToString(0, size)
 }