vlq.ts 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import type { StringReader, StringWriter } from './strings';
  2. export const comma = ','.charCodeAt(0);
  3. export const semicolon = ';'.charCodeAt(0);
  4. const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  5. const intToChar = new Uint8Array(64); // 64 possible chars.
  6. const charToInt = new Uint8Array(128); // z is 122 in ASCII
  7. for (let i = 0; i < chars.length; i++) {
  8. const c = chars.charCodeAt(i);
  9. intToChar[i] = c;
  10. charToInt[c] = i;
  11. }
  12. export function decodeInteger(reader: StringReader, relative: number): number {
  13. let value = 0;
  14. let shift = 0;
  15. let integer = 0;
  16. do {
  17. const c = reader.next();
  18. integer = charToInt[c];
  19. value |= (integer & 31) << shift;
  20. shift += 5;
  21. } while (integer & 32);
  22. const shouldNegate = value & 1;
  23. value >>>= 1;
  24. if (shouldNegate) {
  25. value = -0x80000000 | -value;
  26. }
  27. return relative + value;
  28. }
  29. export function encodeInteger(builder: StringWriter, num: number, relative: number): number {
  30. let delta = num - relative;
  31. delta = delta < 0 ? (-delta << 1) | 1 : delta << 1;
  32. do {
  33. let clamped = delta & 0b011111;
  34. delta >>>= 5;
  35. if (delta > 0) clamped |= 0b100000;
  36. builder.write(intToChar[clamped]);
  37. } while (delta > 0);
  38. return num;
  39. }
  40. export function hasMoreVlq(reader: StringReader, max: number) {
  41. if (reader.pos >= max) return false;
  42. return reader.peek() !== comma;
  43. }