All files / json-hash hash.ts

98.38% Statements 61/62
100% Branches 11/11
100% Functions 6/6
97.95% Lines 48/49

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 69 70 71174x     174x 174x   174x 174x 174x 174x 174x 174x 174x     174x 3029895x     174x 63380x 63380x 63380x 63380x 544182x 63380x     174x 44x 44x 44x 44x 94x 44x     174x 181725x   111686x   58850x 58850x   10656x 10407x 9635x 9635x 12793x 9635x   772x 728x 728x 728x 728x 4530x 4530x 4530x   728x     533x         156564x  
import {sort} from '@jsonjoy.com/util/lib/sort/insertion';
import type {PackValue} from '@jsonjoy.com/json-pack/lib/types';
 
export enum CONST {
  START_STATE = 5381,
 
  NULL = 982452847,
  TRUE = 982453247,
  FALSE = 982454243,
  ARRAY = 982452259,
  STRING = 982453601,
  OBJECT = 982454533,
  BINARY = 982454837,
}
 
export const updateNum = (state: number, num: number): number => {
  return (state << 5) + state + num;
};
 
export const updateStr = (state: number, str: string): number => {
  const length = str.length;
  state = updateNum(state, CONST.STRING);
  state = updateNum(state, length);
  let i = length;
  while (i) state = (state << 5) + state + str.charCodeAt(--i);
  return state;
};
 
export const updateBin = (state: number, bin: Uint8Array): number => {
  const length = bin.length;
  state = updateNum(state, CONST.BINARY);
  state = updateNum(state, length);
  let i = length;
  while (i) state = (state << 5) + state + bin[--i];
  return state;
};
 
export const updateJson = (state: number, json: unknown): number => {
  switch (typeof json) {
    case 'number':
      return updateNum(state, json);
    case 'string':
      state = updateNum(state, CONST.STRING);
      return updateStr(state, json);
    case 'object': {
      if (json === null) return updateNum(state, CONST.NULL);
      if (Array.isArray(json)) {
        const length = json.length;
        state = updateNum(state, CONST.ARRAY);
        for (let i = 0; i < length; i++) state = updateJson(state, json[i]);
        return state;
      }
      if (json instanceof Uint8Array) return updateBin(state, json);
      state = updateNum(state, CONST.OBJECT);
      const keys = sort(Object.keys(json as object));
      const length = keys.length;
      for (let i = 0; i < length; i++) {
        const key = keys[i];
        state = updateStr(state, key);
        state = updateJson(state, (json as any)[key]);
      }
      return state;
    }
    case 'boolean':
      return updateNum(state, json ? CONST.TRUE : CONST.FALSE);
  }
  return state;
};
 
export const hash = (json: PackValue) => updateJson(CONST.START_STATE, json) >>> 0;