CompressionTable.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.CompressionTable = void 0;
  4. const JsonPackExtension_1 = require("../JsonPackExtension");
  5. const isSafeInteger = Number.isSafeInteger;
  6. class CompressionTable {
  7. constructor() {
  8. this.integers = new Set();
  9. this.nonIntegers = new Set();
  10. this.table = [];
  11. this.map = new Map();
  12. }
  13. static create(value) {
  14. const table = new CompressionTable();
  15. table.walk(value);
  16. table.finalize();
  17. return table;
  18. }
  19. addInteger(int) {
  20. this.integers.add(int);
  21. }
  22. addLiteral(value) {
  23. if (isSafeInteger(value)) {
  24. this.addInteger(value);
  25. return;
  26. }
  27. this.nonIntegers.add(value);
  28. }
  29. walk(value) {
  30. switch (typeof value) {
  31. case 'object': {
  32. if (!value)
  33. return this.addLiteral(null);
  34. const constructor = value.constructor;
  35. switch (constructor) {
  36. case Object: {
  37. const obj = value;
  38. for (const key in obj) {
  39. this.addLiteral(key);
  40. this.walk(obj[key]);
  41. }
  42. break;
  43. }
  44. case Array: {
  45. const arr = value;
  46. const len = arr.length;
  47. for (let i = 0; i < len; i++)
  48. this.walk(arr[i]);
  49. break;
  50. }
  51. case Map: {
  52. const map = value;
  53. map.forEach((value, key) => {
  54. this.walk(key);
  55. this.walk(value);
  56. });
  57. break;
  58. }
  59. case Set: {
  60. const set = value;
  61. set.forEach((value) => {
  62. this.walk(value);
  63. });
  64. break;
  65. }
  66. case JsonPackExtension_1.JsonPackExtension: {
  67. const ext = value;
  68. this.addInteger(ext.tag);
  69. this.walk(ext.val);
  70. }
  71. }
  72. return;
  73. }
  74. default:
  75. return this.addLiteral(value);
  76. }
  77. }
  78. finalize() {
  79. const integers = Array.from(this.integers);
  80. integers.sort((a, b) => a - b);
  81. const len = integers.length;
  82. const table = this.table;
  83. const map = this.map;
  84. if (len > 0) {
  85. const first = integers[0];
  86. table.push(first);
  87. map.set(first, 0);
  88. let last = first;
  89. for (let i = 1; i < len; i++) {
  90. const int = integers[i];
  91. table.push(int - last);
  92. map.set(int, i);
  93. last = int;
  94. }
  95. }
  96. const nonIntegers = Array.from(this.nonIntegers);
  97. nonIntegers.sort();
  98. const lenNonIntegers = nonIntegers.length;
  99. for (let i = 0; i < lenNonIntegers; i++) {
  100. const value = nonIntegers[i];
  101. table.push(value);
  102. map.set(value, len + i);
  103. }
  104. this.integers.clear();
  105. this.nonIntegers.clear();
  106. }
  107. getIndex(value) {
  108. const index = this.map.get(value);
  109. if (index === undefined)
  110. throw new Error(`Value [${value}] not found in compression table.`);
  111. return index;
  112. }
  113. getTable() {
  114. return this.table;
  115. }
  116. compress(value) {
  117. switch (typeof value) {
  118. case 'object': {
  119. if (!value)
  120. return this.getIndex(null);
  121. const constructor = value.constructor;
  122. switch (constructor) {
  123. case Object: {
  124. const obj = value;
  125. const newObj = {};
  126. for (const key in obj)
  127. newObj[this.getIndex(key)] = this.compress(obj[key]);
  128. return newObj;
  129. }
  130. case Array: {
  131. const arr = value;
  132. const newArr = [];
  133. const len = arr.length;
  134. for (let i = 0; i < len; i++)
  135. newArr.push(this.compress(arr[i]));
  136. return newArr;
  137. }
  138. case Map: {
  139. const map = value;
  140. const newMap = new Map();
  141. map.forEach((value, key) => {
  142. newMap.set(this.compress(key), this.compress(value));
  143. });
  144. return newMap;
  145. }
  146. case Set: {
  147. const set = value;
  148. const newSet = new Set();
  149. set.forEach((value) => {
  150. newSet.add(this.compress(value));
  151. });
  152. break;
  153. }
  154. case JsonPackExtension_1.JsonPackExtension: {
  155. const ext = value;
  156. const newExt = new JsonPackExtension_1.JsonPackExtension(this.getIndex(ext.tag), this.compress(ext.val));
  157. return newExt;
  158. }
  159. }
  160. throw new Error('UNEXPECTED_OBJECT');
  161. }
  162. default: {
  163. return this.getIndex(value);
  164. }
  165. }
  166. }
  167. }
  168. exports.CompressionTable = CompressionTable;
  169. //# sourceMappingURL=CompressionTable.js.map