All files / json-pack/src/cbor CborEncoderStable.ts

97.95% Statements 48/49
100% Branches 11/11
75% Functions 3/4
97.77% Lines 44/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 695x 5x   5x   5x 42950x 1390x 58x 22x     5x   4131x 4131x 4131x 4131x 4131x 15098x 15098x 15098x           21475x 21475x 21475x 21475x 21475x 21475x 21475x 21475x 21475x 21475x 21475x 21475x 2x 2x   21475x   20779x 20779x   667x 667x 667x   18x 18x 18x     11x 11x 11x     21475x              
import {CborEncoder} from './CborEncoder';
import {sort} from '@jsonjoy.com/util/lib/sort/insertion2';
import {MAJOR_OVERLAY} from './constants';
import {objKeyCmp} from '@jsonjoy.com/util/lib/objKeyCmp';
 
const strHeaderLength = (strSize: number): 1 | 2 | 3 | 5 => {
  if (strSize <= 23) return 1;
  else if (strSize <= 0xff) return 2;
  else if (strSize <= 0xffff) return 3;
  else return 5;
};
 
export class CborEncoderStable extends CborEncoder {
  public writeObj(obj: Record<string, unknown>): void {
    const keys = Object.keys(obj);
    sort(keys, objKeyCmp);
    const length = keys.length;
    this.writeObjHdr(length);
    for (let i = 0; i < length; i++) {
      const key = keys[i];
      this.writeStr(key);
      this.writeAny(obj[key]);
    }
  }
 
  /** @todo This implementation might be even faster than the default one, verify that. */
  public writeStr(str: string): void {
    const writer = this.writer;
    const length = str.length;
    const maxSize = length * 4;
    writer.ensureCapacity(5 + maxSize);
    const headerLengthGuess = strHeaderLength(length);
    const x0 = writer.x;
    const x1 = x0 + headerLengthGuess;
    writer.x = x1;
    const bytesWritten = writer.utf8(str);
    const uint8 = writer.uint8;
    const headerLength = strHeaderLength(bytesWritten);
    if (headerLength !== headerLengthGuess) {
      const shift = headerLength - headerLengthGuess;
      uint8.copyWithin(x1 + shift, x1, x1 + bytesWritten);
    }
    switch (headerLength) {
      case 1:
        uint8[x0] = MAJOR_OVERLAY.STR + bytesWritten;
        break;
      case 2:
        uint8[x0] = 0x78;
        uint8[x0 + 1] = bytesWritten;
        break;
      case 3: {
        uint8[x0] = 0x79;
        writer.view.setUint16(x0 + 1, bytesWritten);
        break;
      }
      case 5: {
        uint8[x0] = 0x7a;
        writer.view.setUint32(x0 + 1, bytesWritten);
        break;
      }
    }
    writer.x = x0 + headerLength + bytesWritten;
  }
 
  public writeUndef(): void {
    this.writeNull();
  }
}