@no-k/hermes 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +88 -0
  3. package/bin/hermes.mjs +159 -0
  4. package/catalog.json +1084 -0
  5. package/lib/catalog.mjs +51 -0
  6. package/package.json +28 -0
  7. package/templates/algorithm/geometry/ccw/ccw.ts +25 -0
  8. package/templates/algorithm/geometry/ccw/index.ts +1 -0
  9. package/templates/algorithm/geometry/convex-hull/convex-hull.ts +43 -0
  10. package/templates/algorithm/geometry/convex-hull/index.ts +1 -0
  11. package/templates/algorithm/geometry/polygon-area/index.ts +1 -0
  12. package/templates/algorithm/geometry/polygon-area/polygon-area.ts +13 -0
  13. package/templates/algorithm/graph/bellman-ford/bellman-ford.ts +46 -0
  14. package/templates/algorithm/graph/bellman-ford/index.ts +1 -0
  15. package/templates/algorithm/graph/bfs/bfs.ts +21 -0
  16. package/templates/algorithm/graph/bfs/index.ts +1 -0
  17. package/templates/algorithm/graph/dfs/dfs.ts +22 -0
  18. package/templates/algorithm/graph/dfs/index.ts +1 -0
  19. package/templates/algorithm/graph/dijkstra/dijkstra.ts +37 -0
  20. package/templates/algorithm/graph/dijkstra/index.ts +1 -0
  21. package/templates/algorithm/graph/floyd-warshall/floyd-warshall.ts +17 -0
  22. package/templates/algorithm/graph/floyd-warshall/index.ts +1 -0
  23. package/templates/algorithm/graph/kruskal/index.ts +1 -0
  24. package/templates/algorithm/graph/kruskal/kruskal.ts +29 -0
  25. package/templates/algorithm/graph/prim/index.ts +1 -0
  26. package/templates/algorithm/graph/prim/prim.ts +44 -0
  27. package/templates/algorithm/graph/topology-sort/index.ts +1 -0
  28. package/templates/algorithm/graph/topology-sort/topology-sort.ts +31 -0
  29. package/templates/algorithm/search/binary-search/binary-search.ts +74 -0
  30. package/templates/algorithm/search/binary-search/index.ts +1 -0
  31. package/templates/algorithm/string/kmp/index.ts +1 -0
  32. package/templates/algorithm/string/kmp/kmp.ts +46 -0
  33. package/templates/algorithm/string/z-algorithm/index.ts +1 -0
  34. package/templates/algorithm/string/z-algorithm/z-algorithm.ts +41 -0
  35. package/templates/algorithm/tree/avl-tree/avl-tree.ts +197 -0
  36. package/templates/algorithm/tree/avl-tree/index.ts +1 -0
  37. package/templates/algorithm/tree/binary-search-tree/binary-search-tree.ts +144 -0
  38. package/templates/algorithm/tree/binary-search-tree/index.ts +1 -0
  39. package/templates/algorithm/tree/lca/index.ts +1 -0
  40. package/templates/algorithm/tree/lca/lca.ts +119 -0
  41. package/templates/array/chunk/chunk.ts +13 -0
  42. package/templates/array/chunk/index.ts +1 -0
  43. package/templates/array/compact/compact.ts +8 -0
  44. package/templates/array/compact/index.ts +1 -0
  45. package/templates/array/count-by/count-by.ts +12 -0
  46. package/templates/array/count-by/index.ts +1 -0
  47. package/templates/array/difference/difference.ts +6 -0
  48. package/templates/array/difference/index.ts +1 -0
  49. package/templates/array/drop/drop.ts +7 -0
  50. package/templates/array/drop/index.ts +1 -0
  51. package/templates/array/group-by/group-by.ts +18 -0
  52. package/templates/array/group-by/index.ts +1 -0
  53. package/templates/array/intersection/index.ts +1 -0
  54. package/templates/array/intersection/intersection.ts +15 -0
  55. package/templates/array/key-by/index.ts +1 -0
  56. package/templates/array/key-by/key-by.ts +11 -0
  57. package/templates/array/max-by/index.ts +1 -0
  58. package/templates/array/max-by/max-by.ts +20 -0
  59. package/templates/array/min-by/index.ts +1 -0
  60. package/templates/array/min-by/min-by.ts +20 -0
  61. package/templates/array/partition/index.ts +1 -0
  62. package/templates/array/partition/partition.ts +16 -0
  63. package/templates/array/range/index.ts +1 -0
  64. package/templates/array/range/range.ts +22 -0
  65. package/templates/array/sample/index.ts +1 -0
  66. package/templates/array/sample/sample.ts +10 -0
  67. package/templates/array/shuffle/index.ts +1 -0
  68. package/templates/array/shuffle/shuffle.ts +15 -0
  69. package/templates/array/sort-by/index.ts +1 -0
  70. package/templates/array/sort-by/sort-by.ts +32 -0
  71. package/templates/array/sum-by/index.ts +1 -0
  72. package/templates/array/sum-by/sum-by.ts +9 -0
  73. package/templates/array/take/index.ts +1 -0
  74. package/templates/array/take/take.ts +7 -0
  75. package/templates/array/union/index.ts +1 -0
  76. package/templates/array/union/union.ts +5 -0
  77. package/templates/array/unique/index.ts +1 -0
  78. package/templates/array/unique/unique.ts +5 -0
  79. package/templates/array/unique-by/index.ts +1 -0
  80. package/templates/array/unique-by/unique-by.ts +19 -0
  81. package/templates/array/windowed/index.ts +1 -0
  82. package/templates/array/windowed/windowed.ts +15 -0
  83. package/templates/array/zip/index.ts +1 -0
  84. package/templates/array/zip/zip.ts +11 -0
  85. package/templates/boolean/parse-boolean/index.ts +1 -0
  86. package/templates/boolean/parse-boolean/parse-boolean.ts +17 -0
  87. package/templates/boolean/toggle/index.ts +1 -0
  88. package/templates/boolean/toggle/toggle.ts +2 -0
  89. package/templates/boolean/xor/index.ts +1 -0
  90. package/templates/boolean/xor/xor.ts +2 -0
  91. package/templates/data-structure/deque/deque.ts +79 -0
  92. package/templates/data-structure/deque/index.ts +1 -0
  93. package/templates/data-structure/fenwick-tree/fenwick-tree.ts +76 -0
  94. package/templates/data-structure/fenwick-tree/index.ts +1 -0
  95. package/templates/data-structure/heap/heap.ts +88 -0
  96. package/templates/data-structure/heap/index.ts +3 -0
  97. package/templates/data-structure/heap/max-heap.ts +7 -0
  98. package/templates/data-structure/heap/min-heap.ts +7 -0
  99. package/templates/data-structure/priority-queue/index.ts +1 -0
  100. package/templates/data-structure/priority-queue/priority-queue.ts +44 -0
  101. package/templates/data-structure/queue/index.ts +1 -0
  102. package/templates/data-structure/queue/queue.ts +66 -0
  103. package/templates/data-structure/segment-tree/index.ts +1 -0
  104. package/templates/data-structure/segment-tree/segment-tree.ts +79 -0
  105. package/templates/data-structure/trie/index.ts +1 -0
  106. package/templates/data-structure/trie/trie.ts +104 -0
  107. package/templates/data-structure/union-find/index.ts +1 -0
  108. package/templates/data-structure/union-find/union-find.ts +79 -0
  109. package/templates/dom/attribute/attribute.ts +24 -0
  110. package/templates/dom/attribute/index.ts +1 -0
  111. package/templates/dom/class-name/class-name.ts +48 -0
  112. package/templates/dom/class-name/index.ts +1 -0
  113. package/templates/dom/is-element/index.ts +1 -0
  114. package/templates/dom/is-element/is-element.ts +20 -0
  115. package/templates/dom/query/index.ts +1 -0
  116. package/templates/dom/query/query.ts +7 -0
  117. package/templates/http/content-type/content-type.ts +130 -0
  118. package/templates/http/content-type/index.ts +1 -0
  119. package/templates/http/header/header.ts +56 -0
  120. package/templates/http/header/index.ts +1 -0
  121. package/templates/http/method/index.ts +1 -0
  122. package/templates/http/method/method.ts +25 -0
  123. package/templates/http/status/index.ts +1 -0
  124. package/templates/http/status/status.ts +191 -0
  125. package/templates/number/clamp/clamp.ts +11 -0
  126. package/templates/number/clamp/index.ts +1 -0
  127. package/templates/number/factorial/factorial.ts +15 -0
  128. package/templates/number/factorial/index.ts +1 -0
  129. package/templates/number/format-thousands/format-thousands.ts +24 -0
  130. package/templates/number/format-thousands/index.ts +1 -0
  131. package/templates/number/gcd/gcd.ts +13 -0
  132. package/templates/number/gcd/index.ts +1 -0
  133. package/templates/number/in-range/in-range.ts +3 -0
  134. package/templates/number/in-range/index.ts +1 -0
  135. package/templates/number/is-even/index.ts +1 -0
  136. package/templates/number/is-even/is-even.ts +5 -0
  137. package/templates/number/is-odd/index.ts +1 -0
  138. package/templates/number/is-odd/is-odd.ts +7 -0
  139. package/templates/number/lcm/index.ts +1 -0
  140. package/templates/number/lcm/lcm.ts +12 -0
  141. package/templates/number/lerp/index.ts +1 -0
  142. package/templates/number/lerp/lerp.ts +3 -0
  143. package/templates/number/percentage/index.ts +1 -0
  144. package/templates/number/percentage/percentage.ts +7 -0
  145. package/templates/number/random/index.ts +1 -0
  146. package/templates/number/random/random.ts +9 -0
  147. package/templates/number/random-int/index.ts +1 -0
  148. package/templates/number/random-int/random-int.ts +9 -0
  149. package/templates/number/round/index.ts +1 -0
  150. package/templates/number/round/round.ts +22 -0
  151. package/templates/number/safe-parse-number/index.ts +1 -0
  152. package/templates/number/safe-parse-number/safe-parse-number.ts +29 -0
  153. package/templates/number/to-ordinal/index.ts +1 -0
  154. package/templates/number/to-ordinal/to-ordinal.ts +28 -0
  155. package/templates/object/deep-clone/deep-clone.ts +47 -0
  156. package/templates/object/deep-clone/index.ts +1 -0
  157. package/templates/object/deep-equal/deep-equal.ts +66 -0
  158. package/templates/object/deep-equal/index.ts +1 -0
  159. package/templates/object/deep-merge/deep-merge.ts +49 -0
  160. package/templates/object/deep-merge/index.ts +1 -0
  161. package/templates/object/defaults/defaults.ts +14 -0
  162. package/templates/object/defaults/index.ts +1 -0
  163. package/templates/object/filter-object/filter-object.ts +11 -0
  164. package/templates/object/filter-object/index.ts +1 -0
  165. package/templates/object/get/get.ts +75 -0
  166. package/templates/object/get/index.ts +1 -0
  167. package/templates/object/has/has.ts +60 -0
  168. package/templates/object/has/index.ts +1 -0
  169. package/templates/object/invert/index.ts +1 -0
  170. package/templates/object/invert/invert.ts +13 -0
  171. package/templates/object/map-keys/index.ts +1 -0
  172. package/templates/object/map-keys/map-keys.ts +16 -0
  173. package/templates/object/map-values/index.ts +1 -0
  174. package/templates/object/map-values/map-values.ts +14 -0
  175. package/templates/object/omit/index.ts +1 -0
  176. package/templates/object/omit/omit.ts +15 -0
  177. package/templates/object/omit-by/index.ts +1 -0
  178. package/templates/object/omit-by/omit-by.ts +19 -0
  179. package/templates/object/pick/index.ts +1 -0
  180. package/templates/object/pick/pick.ts +15 -0
  181. package/templates/object/pick-by/index.ts +1 -0
  182. package/templates/object/pick-by/pick-by.ts +19 -0
  183. package/templates/object/set/index.ts +1 -0
  184. package/templates/object/set/set.ts +118 -0
  185. package/templates/string/capitalize/capitalize.ts +4 -0
  186. package/templates/string/capitalize/index.ts +1 -0
  187. package/templates/string/change-case/change-case.ts +98 -0
  188. package/templates/string/change-case/index.ts +1 -0
  189. package/templates/string/char/char.ts +14 -0
  190. package/templates/string/char/index.ts +1 -0
  191. package/templates/string/count-occurrences/count-occurrences.ts +20 -0
  192. package/templates/string/count-occurrences/index.ts +1 -0
  193. package/templates/string/escape-html/escape-html.ts +16 -0
  194. package/templates/string/escape-html/index.ts +1 -0
  195. package/templates/string/get-decorated-string/get-decorated-string.ts +7 -0
  196. package/templates/string/get-decorated-string/index.ts +1 -0
  197. package/templates/string/is-blank/index.ts +1 -0
  198. package/templates/string/is-blank/is-blank.ts +6 -0
  199. package/templates/string/mask/index.ts +1 -0
  200. package/templates/string/mask/mask.ts +30 -0
  201. package/templates/string/pad/index.ts +1 -0
  202. package/templates/string/pad/pad.ts +17 -0
  203. package/templates/string/random-string/index.ts +1 -0
  204. package/templates/string/random-string/random-string.ts +20 -0
  205. package/templates/string/reverse/index.ts +1 -0
  206. package/templates/string/reverse/reverse.ts +6 -0
  207. package/templates/string/slugify/index.ts +1 -0
  208. package/templates/string/slugify/slugify.ts +11 -0
  209. package/templates/string/strip-tags/index.ts +1 -0
  210. package/templates/string/strip-tags/strip-tags.ts +8 -0
  211. package/templates/string/template/index.ts +1 -0
  212. package/templates/string/template/template.ts +14 -0
  213. package/templates/string/truncate/index.ts +1 -0
  214. package/templates/string/truncate/truncate.ts +17 -0
  215. package/templates/string/truncate-middle/index.ts +1 -0
  216. package/templates/string/truncate-middle/truncate-middle.ts +25 -0
  217. package/templates/string/uuid/index.ts +1 -0
  218. package/templates/string/uuid/uuid.ts +9 -0
  219. package/templates/tailwindcss/class-variant/class-variant.ts +35 -0
  220. package/templates/tailwindcss/class-variant/index.ts +1 -0
  221. package/templates/tailwindcss/cn/cn.ts +29 -0
  222. package/templates/tailwindcss/cn/index.ts +1 -0
  223. package/templates/tailwindcss/create-tailwind-css/create-tailwind-css.ts +16 -0
  224. package/templates/tailwindcss/create-tailwind-css/index.ts +1 -0
  225. package/templates/tailwindcss/tw-merge-config/index.ts +1 -0
  226. package/templates/tailwindcss/tw-merge-config/tw-merge-config.ts +14 -0
  227. package/templates/type/get-type/get-type.ts +27 -0
  228. package/templates/type/get-type/index.ts +1 -0
  229. package/templates/type/is-type-of/index.ts +1 -0
  230. package/templates/type/is-type-of/is-type-of.ts +26 -0
  231. package/templates/util/mutex/index.ts +1 -0
  232. package/templates/util/mutex/mutex.ts +109 -0
  233. package/templates/util/url-parser/index.ts +1 -0
  234. package/templates/util/url-parser/url-parser.ts +44 -0
@@ -0,0 +1 @@
1
+ export * from "./sample";
@@ -0,0 +1,10 @@
1
+ // 배열에서 무작위로 원소 하나를 골라 반환한다. 빈 배열이면 null을 반환한다.
2
+ // 각 원소가 균등 확률로 뽑힌다. 난수는 런타임의 Math.random을 사용한다.
3
+ export const sample = <T>(array: T[]): T | null => {
4
+ if (array.length === 0) {
5
+ return null;
6
+ }
7
+
8
+ const index = Math.floor(Math.random() * array.length);
9
+ return array[index];
10
+ };
@@ -0,0 +1 @@
1
+ export * from "./shuffle";
@@ -0,0 +1,15 @@
1
+ // Fisher-Yates 셔플로 무작위 순서의 새 배열을 반환한다. 입력 배열은 변형하지
2
+ // 않는다. 뒤에서 앞으로 훑으며 각 위치를 [0, index] 구간의 임의 위치와 교환하므로
3
+ // 모든 순열이 균등 확률로 나온다. 난수는 런타임의 Math.random을 사용한다.
4
+ export const shuffle = <T>(array: T[]): T[] => {
5
+ const result = array.slice();
6
+
7
+ for (let index = result.length - 1; index > 0; index -= 1) {
8
+ const swap = Math.floor(Math.random() * (index + 1));
9
+ const temp = result[index];
10
+ result[index] = result[swap];
11
+ result[swap] = temp;
12
+ }
13
+
14
+ return result;
15
+ };
@@ -0,0 +1 @@
1
+ export * from "./sort-by";
@@ -0,0 +1,32 @@
1
+ // keyFn이 돌려준 키를 기준으로 오름차순 안정 정렬한 새 배열을 반환한다.
2
+ // 입력 배열은 변형하지 않는다. 키가 같은 항목들은 원래 순서를 유지한다(안정).
3
+ //
4
+ // 키 타입은 number | string로 한정한다. 두 키를 빼거나 직접 비교하는 대신
5
+ // compareKey 하나로 처리해, number는 차이로 string은 사전식으로 비교한다.
6
+ // string 비교에 localeCompare를 쓰지 않는 이유는 로케일에 따라 결과가 달라져
7
+ // 코드 단위 비교(`<`/`>`)가 더 결정적이기 때문이다.
8
+ const compareKey = (a: number | string, b: number | string): number => {
9
+ if (typeof a === "number" && typeof b === "number") {
10
+ return a - b;
11
+ }
12
+
13
+ const left = String(a);
14
+ const right = String(b);
15
+ if (left < right) {
16
+ return -1;
17
+ }
18
+ if (left > right) {
19
+ return 1;
20
+ }
21
+ return 0;
22
+ };
23
+
24
+ export const sortBy = <T>(array: T[], keyFn: (item: T) => number | string): T[] => {
25
+ // 키를 항목당 한 번만 계산해 두고(슈워츠 변환) 비교에서 재호출하지 않는다.
26
+ // index를 함께 들고 가 동점일 때 원래 순서로 풀어 안정성을 보장한다.
27
+ // (Array.prototype.sort 자체도 ES2019부터 안정이지만, 키 캐싱을 위해 래핑한다.)
28
+ return array
29
+ .map((item, index) => ({ item, index, key: keyFn(item) }))
30
+ .sort((a, b) => compareKey(a.key, b.key) || a.index - b.index)
31
+ .map((entry) => entry.item);
32
+ };
@@ -0,0 +1 @@
1
+ export * from "./sum-by";
@@ -0,0 +1,9 @@
1
+ export const sumBy = <T>(array: T[], valueFn: (item: T) => number): number => {
2
+ let total = 0;
3
+
4
+ for (const item of array) {
5
+ total += valueFn(item);
6
+ }
7
+
8
+ return total;
9
+ };
@@ -0,0 +1 @@
1
+ export * from "./take";
@@ -0,0 +1,7 @@
1
+ // 배열 앞에서 n개를 잘라 새 배열로 반환한다. 입력 배열은 변형하지 않는다.
2
+ // n이 0 이하면 빈 배열, n이 길이보다 크면 전체 복사본을 돌려준다.
3
+ // slice의 음수 인덱스 해석을 피하려고 n을 [0, length]로 먼저 클램프한다.
4
+ export const take = <T>(array: readonly T[], n: number): T[] => {
5
+ const count = Math.min(Math.max(n, 0), array.length);
6
+ return array.slice(0, count);
7
+ };
@@ -0,0 +1 @@
1
+ export * from "./union";
@@ -0,0 +1,5 @@
1
+ export const union = <T>(a: T[], b: T[]): T[] => {
2
+ // Set이 삽입 순서를 보존하므로 a 먼저, b 다음 순서로 넣으면 등장 순서가 유지되고
3
+ // 중복은 자동으로 제거된다.
4
+ return [...new Set([...a, ...b])];
5
+ };
@@ -0,0 +1 @@
1
+ export * from "./unique";
@@ -0,0 +1,5 @@
1
+ // 배열에서 중복을 제거한다. Set의 SameValueZero 동등성으로 판정하며,
2
+ // 각 값의 첫 등장 순서를 그대로 보존한다. 입력 배열은 변형하지 않는다.
3
+ export const unique = <T>(array: readonly T[]): T[] => {
4
+ return [...new Set(array)];
5
+ };
@@ -0,0 +1 @@
1
+ export * from "./unique-by";
@@ -0,0 +1,19 @@
1
+ // keyFn이 돌려준 키를 기준으로 중복을 제거한다. 같은 키가 처음 나온 항목만
2
+ // 남기고 첫 등장 순서를 보존한다. 입력 배열은 변형하지 않는다.
3
+ // 키 비교는 Set의 SameValueZero 동등성을 따른다.
4
+ export const uniqueBy = <T, K>(array: readonly T[], keyFn: (item: T) => K): T[] => {
5
+ const seen = new Set<K>();
6
+ const result: T[] = [];
7
+
8
+ for (const item of array) {
9
+ const key = keyFn(item);
10
+ if (seen.has(key)) {
11
+ continue;
12
+ }
13
+
14
+ seen.add(key);
15
+ result.push(item);
16
+ }
17
+
18
+ return result;
19
+ };
@@ -0,0 +1 @@
1
+ export * from "./windowed";
@@ -0,0 +1,15 @@
1
+ export const windowed = <T>(array: T[], size: number, step = 1): T[][] => {
2
+ if (size <= 0 || step <= 0) {
3
+ return [];
4
+ }
5
+
6
+ const result: T[][] = [];
7
+
8
+ // 마지막 시작 인덱스는 size만큼 꽉 찬 윈도우가 나오는 지점까지다.
9
+ // array.length < size면 루프가 한 번도 돌지 않아 빈 배열이 된다.
10
+ for (let index = 0; index + size <= array.length; index += step) {
11
+ result.push(array.slice(index, index + size));
12
+ }
13
+
14
+ return result;
15
+ };
@@ -0,0 +1 @@
1
+ export * from "./zip";
@@ -0,0 +1,11 @@
1
+ export const zip = <A, B>(a: A[], b: B[]): [A, B][] => {
2
+ // 길이가 다르면 짧은 쪽에서 멈춘다. 남는 원소는 짝이 없으므로 버린다.
3
+ const length = Math.min(a.length, b.length);
4
+ const result: [A, B][] = [];
5
+
6
+ for (let index = 0; index < length; index += 1) {
7
+ result.push([a[index], b[index]]);
8
+ }
9
+
10
+ return result;
11
+ };
@@ -0,0 +1 @@
1
+ export * from "./parse-boolean";
@@ -0,0 +1,17 @@
1
+ // 다양한 입력을 boolean으로 해석한다.
2
+ // true/"true"/"1"/"yes"/"y"/"on"(대소문자·앞뒤 공백 무시)과 0이 아닌 숫자는 true,
3
+ // 그 외(false/0/null/undefined/빈 문자열 등)는 false.
4
+ const TRUTHY = new Set(["true", "1", "yes", "y", "on"]);
5
+
6
+ export const parseBoolean = (value: unknown): boolean => {
7
+ if (typeof value === "boolean") {
8
+ return value;
9
+ }
10
+ if (typeof value === "number") {
11
+ return value !== 0;
12
+ }
13
+ if (typeof value === "string") {
14
+ return TRUTHY.has(value.trim().toLowerCase());
15
+ }
16
+ return false;
17
+ };
@@ -0,0 +1 @@
1
+ export * from "./toggle";
@@ -0,0 +1,2 @@
1
+ // boolean 값을 반전한다.
2
+ export const toggle = (value: boolean): boolean => !value;
@@ -0,0 +1 @@
1
+ export * from "./xor";
@@ -0,0 +1,2 @@
1
+ // 배타적 논리합. 두 boolean 중 정확히 하나만 true일 때 true.
2
+ export const xor = (a: boolean, b: boolean): boolean => a !== b;
@@ -0,0 +1,79 @@
1
+ export class Deque<T> {
2
+ private items = new Map<number, T>();
3
+ private head = 0;
4
+ private tail = 0;
5
+
6
+ size() {
7
+ return this.tail - this.head;
8
+ }
9
+
10
+ isEmpty() {
11
+ return this.size() === 0;
12
+ }
13
+
14
+ pushFront(value: T) {
15
+ this.head -= 1;
16
+ this.items.set(this.head, value);
17
+ }
18
+
19
+ pushBack(value: T) {
20
+ this.items.set(this.tail, value);
21
+ this.tail += 1;
22
+ }
23
+
24
+ popFront(): T | null {
25
+ if (this.isEmpty()) {
26
+ return null;
27
+ }
28
+
29
+ const value = this.items.get(this.head) as T;
30
+ this.items.delete(this.head);
31
+ this.head += 1;
32
+
33
+ return value;
34
+ }
35
+
36
+ popBack(): T | null {
37
+ if (this.isEmpty()) {
38
+ return null;
39
+ }
40
+
41
+ this.tail -= 1;
42
+ const value = this.items.get(this.tail) as T;
43
+ this.items.delete(this.tail);
44
+
45
+ return value;
46
+ }
47
+
48
+ front(): T | null {
49
+ if (this.isEmpty()) {
50
+ return null;
51
+ }
52
+
53
+ return this.items.get(this.head) as T;
54
+ }
55
+
56
+ back(): T | null {
57
+ if (this.isEmpty()) {
58
+ return null;
59
+ }
60
+
61
+ return this.items.get(this.tail - 1) as T;
62
+ }
63
+
64
+ clear() {
65
+ this.items.clear();
66
+ this.head = 0;
67
+ this.tail = 0;
68
+ }
69
+
70
+ toArray() {
71
+ const result: T[] = [];
72
+
73
+ for (let index = this.head; index < this.tail; index += 1) {
74
+ result.push(this.items.get(index) as T);
75
+ }
76
+
77
+ return result;
78
+ }
79
+ }
@@ -0,0 +1 @@
1
+ export * from "./deque";
@@ -0,0 +1,76 @@
1
+ export class FenwickTree {
2
+ private tree: number[];
3
+ private values: number[];
4
+
5
+ constructor(sizeOrValues: number | number[]) {
6
+ const size = Array.isArray(sizeOrValues) ? sizeOrValues.length : sizeOrValues;
7
+ this.tree = Array(size + 1).fill(0);
8
+ this.values = Array(size).fill(0);
9
+
10
+ if (Array.isArray(sizeOrValues)) {
11
+ sizeOrValues.forEach((value, index) => {
12
+ this.set(index, value);
13
+ });
14
+ }
15
+ }
16
+
17
+ size() {
18
+ return this.values.length;
19
+ }
20
+
21
+ update(index: number, delta: number) {
22
+ this.assertIndex(index);
23
+
24
+ this.values[index] += delta;
25
+
26
+ for (let current = index + 1; current < this.tree.length; current += current & -current) {
27
+ this.tree[current] += delta;
28
+ }
29
+ }
30
+
31
+ set(index: number, value: number) {
32
+ this.assertIndex(index);
33
+ this.update(index, value - this.values[index]);
34
+ }
35
+
36
+ get(index: number) {
37
+ this.assertIndex(index);
38
+
39
+ return this.values[index];
40
+ }
41
+
42
+ prefixSum(index: number) {
43
+ if (index < 0) {
44
+ return 0;
45
+ }
46
+
47
+ if (index >= this.size()) {
48
+ throw new RangeError("index is out of range");
49
+ }
50
+
51
+ let result = 0;
52
+
53
+ for (let current = index + 1; current > 0; current -= current & -current) {
54
+ result += this.tree[current];
55
+ }
56
+
57
+ return result;
58
+ }
59
+
60
+ rangeSum(left: number, right: number) {
61
+ if (left > right) {
62
+ return 0;
63
+ }
64
+
65
+ this.assertIndex(left);
66
+ this.assertIndex(right);
67
+
68
+ return this.prefixSum(right) - this.prefixSum(left - 1);
69
+ }
70
+
71
+ private assertIndex(index: number) {
72
+ if (!Number.isInteger(index) || index < 0 || index >= this.size()) {
73
+ throw new RangeError("index is out of range");
74
+ }
75
+ }
76
+ }
@@ -0,0 +1 @@
1
+ export * from "./fenwick-tree";
@@ -0,0 +1,88 @@
1
+ export abstract class Heap<T> {
2
+ items: T[];
3
+ compareBy: (item: T) => number;
4
+
5
+ constructor(options: { compareBy: Heap<T>["compareBy"] }) {
6
+ this.items = [];
7
+ this.compareBy = options.compareBy;
8
+ }
9
+
10
+ size() {
11
+ return this.items.length;
12
+ }
13
+
14
+ peek(): T | null {
15
+ if (!this.size()) {
16
+ return null;
17
+ }
18
+
19
+ return this.items[0];
20
+ }
21
+
22
+ push(value: T) {
23
+ this.items.push(value);
24
+ this.bubbleUp();
25
+ }
26
+
27
+ pop(): T | null {
28
+ if (!this.size()) {
29
+ return null;
30
+ }
31
+
32
+ const top = this.items[0];
33
+ const last = this.items[this.size() - 1];
34
+ this.items.pop();
35
+
36
+ if (this.size()) {
37
+ this.items[0] = last;
38
+ this.bubbleDown();
39
+ }
40
+
41
+ return top;
42
+ }
43
+
44
+ swap(a: number, b: number) {
45
+ [this.items[a], this.items[b]] = [this.items[b], this.items[a]];
46
+ }
47
+
48
+ /**
49
+ * 루트에 더 가까워야 하는(우선순위가 높은) 쪽을 음수로 반환합니다.
50
+ * MinHeap은 값이 작을수록, MaxHeap은 값이 클수록 우선순위가 높습니다.
51
+ */
52
+ abstract compare(aIndex: number, bIndex: number): number;
53
+
54
+ bubbleUp() {
55
+ let index = this.size() - 1;
56
+
57
+ while (index > 0) {
58
+ const parentIndex = Math.floor((index - 1) / 2);
59
+
60
+ if (this.compare(parentIndex, index) <= 0) {
61
+ break;
62
+ }
63
+
64
+ this.swap(index, parentIndex);
65
+ index = parentIndex;
66
+ }
67
+ }
68
+
69
+ bubbleDown() {
70
+ let index = 0;
71
+
72
+ while (index * 2 + 1 < this.size()) {
73
+ const leftIndex = index * 2 + 1;
74
+ const rightIndex = index * 2 + 2;
75
+
76
+ const isRightHigherPriority = rightIndex < this.size() && this.compare(rightIndex, leftIndex) < 0;
77
+
78
+ const targetIndex = isRightHigherPriority ? rightIndex : leftIndex;
79
+
80
+ if (this.compare(index, targetIndex) <= 0) {
81
+ break;
82
+ }
83
+
84
+ this.swap(index, targetIndex);
85
+ index = targetIndex;
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./heap";
2
+ export * from "./min-heap";
3
+ export * from "./max-heap";
@@ -0,0 +1,7 @@
1
+ import { Heap } from "./heap";
2
+
3
+ export class MaxHeap<T> extends Heap<T> {
4
+ compare(aIndex: number, bIndex: number): number {
5
+ return this.compareBy(this.items[bIndex]) - this.compareBy(this.items[aIndex]);
6
+ }
7
+ }
@@ -0,0 +1,7 @@
1
+ import { Heap } from "./heap";
2
+
3
+ export class MinHeap<T> extends Heap<T> {
4
+ compare(aIndex: number, bIndex: number): number {
5
+ return this.compareBy(this.items[aIndex]) - this.compareBy(this.items[bIndex]);
6
+ }
7
+ }
@@ -0,0 +1 @@
1
+ export * from "./priority-queue";
@@ -0,0 +1,44 @@
1
+ import { Heap } from "../heap/heap";
2
+
3
+ type Compare<T> = (a: T, b: T) => number;
4
+
5
+ const defaultCompare = <T>(a: T, b: T) => {
6
+ if (a < b) {
7
+ return -1;
8
+ }
9
+
10
+ if (a > b) {
11
+ return 1;
12
+ }
13
+
14
+ return 0;
15
+ };
16
+
17
+ export class PriorityQueue<T> extends Heap<T> {
18
+ private compareItems: Compare<T>;
19
+
20
+ constructor(options: { compare?: Compare<T> } = {}) {
21
+ super({ compareBy: () => 0 });
22
+ this.compareItems = options.compare ?? defaultCompare;
23
+ }
24
+
25
+ compare(aIndex: number, bIndex: number): number {
26
+ return this.compareItems(this.items[aIndex], this.items[bIndex]);
27
+ }
28
+
29
+ enqueue(value: T) {
30
+ this.push(value);
31
+ }
32
+
33
+ dequeue(): T | null {
34
+ return this.pop();
35
+ }
36
+
37
+ isEmpty() {
38
+ return this.size() === 0;
39
+ }
40
+
41
+ clear() {
42
+ this.items = [];
43
+ }
44
+ }
@@ -0,0 +1 @@
1
+ export * from "./queue";
@@ -0,0 +1,66 @@
1
+ class Node<T> {
2
+ value: T;
3
+ next: Node<T> | null;
4
+
5
+ constructor(value: T) {
6
+ this.value = value;
7
+ this.next = null;
8
+ }
9
+ }
10
+
11
+ export class Queue<T> {
12
+ _size: number;
13
+ _head: Node<T> | null;
14
+ _tail: Node<T> | null;
15
+
16
+ constructor() {
17
+ this._size = 0;
18
+ this._head = null;
19
+ this._tail = null;
20
+ }
21
+
22
+ enqueue(newValue: T) {
23
+ const newNode = new Node(newValue);
24
+
25
+ if (this._head === null) {
26
+ this._head = this._tail = newNode;
27
+ this._size += 1;
28
+ return;
29
+ }
30
+
31
+ if (this._tail) {
32
+ this._tail.next = newNode;
33
+ }
34
+
35
+ this._tail = newNode;
36
+ this._size += 1;
37
+ }
38
+
39
+ dequeue(): T | null {
40
+ if (this._head) {
41
+ const value = this._head.value;
42
+ this._head = this._head.next;
43
+ this._size -= 1;
44
+
45
+ return value;
46
+ }
47
+
48
+ return null;
49
+ }
50
+
51
+ peek() {
52
+ if (this._head) {
53
+ return this._head;
54
+ }
55
+
56
+ return null;
57
+ }
58
+
59
+ size() {
60
+ return this._size;
61
+ }
62
+
63
+ isEmpty() {
64
+ return this._size === 0;
65
+ }
66
+ }
@@ -0,0 +1 @@
1
+ export * from "./segment-tree";