koffi 0.9.1 → 0.9.4

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 (439) hide show
  1. package/CMakeLists.txt +2 -36
  2. package/package.json +3 -3
  3. package/vendor/dragonbox/CMakeLists.txt +123 -0
  4. package/vendor/dragonbox/LICENSE-Apache2-LLVM +218 -0
  5. package/vendor/dragonbox/LICENSE-Boost +23 -0
  6. package/vendor/dragonbox/README.md +277 -0
  7. package/vendor/dragonbox/cmake/dragonboxConfig.cmake +1 -0
  8. package/vendor/dragonbox/include/dragonbox/dragonbox.h +2670 -0
  9. package/vendor/dragonbox/include/dragonbox/dragonbox_to_chars.h +108 -0
  10. package/vendor/dragonbox/other_files/Dragonbox.pdf +0 -0
  11. package/vendor/dragonbox/other_files/Dragonbox_old.pdf +0 -0
  12. package/vendor/dragonbox/other_files/milo_benchmark.png +0 -0
  13. package/vendor/dragonbox/other_files/unknown_win64_vc2019.html +540 -0
  14. package/vendor/dragonbox/other_files/unknown_win64_vc2019_randomdigit_time.png +0 -0
  15. package/vendor/dragonbox/source/dragonbox_to_chars.cpp +303 -0
  16. package/vendor/dragonbox/subproject/3rdparty/grisu_exact/CMakeLists.txt +24 -0
  17. package/vendor/dragonbox/subproject/3rdparty/grisu_exact/fp_to_chars.cpp +238 -0
  18. package/vendor/dragonbox/subproject/3rdparty/grisu_exact/fp_to_chars.h +95 -0
  19. package/vendor/dragonbox/subproject/3rdparty/grisu_exact/grisu_exact.h +2666 -0
  20. package/vendor/dragonbox/subproject/3rdparty/ryu/CMakeLists.txt +16 -0
  21. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/common.h +114 -0
  22. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/d2s.c +509 -0
  23. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/d2s_full_table.h +367 -0
  24. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/d2s_intrinsics.h +357 -0
  25. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/digit_table.h +35 -0
  26. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/f2s.c +345 -0
  27. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/f2s_full_table.h +55 -0
  28. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/f2s_intrinsics.h +128 -0
  29. package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/ryu.h +46 -0
  30. package/vendor/dragonbox/subproject/3rdparty/schubfach/CMakeLists.txt +22 -0
  31. package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_32.cc +699 -0
  32. package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_32.h +31 -0
  33. package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_64.cc +1354 -0
  34. package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_64.h +31 -0
  35. package/vendor/dragonbox/subproject/3rdparty/shaded_plots/example_shaded_plots.m +68 -0
  36. package/vendor/dragonbox/subproject/3rdparty/shaded_plots/license.txt +25 -0
  37. package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_distribution.m +92 -0
  38. package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_distribution_prctile.m +121 -0
  39. package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_histogram_shaded.m +99 -0
  40. package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_shaded.m +93 -0
  41. package/vendor/dragonbox/subproject/benchmark/CMakeLists.txt +65 -0
  42. package/vendor/dragonbox/subproject/benchmark/include/benchmark.h +40 -0
  43. package/vendor/dragonbox/subproject/benchmark/matlab/plot_benchmarks.m +22 -0
  44. package/vendor/dragonbox/subproject/benchmark/matlab/plot_digit_benchmark.m +78 -0
  45. package/vendor/dragonbox/subproject/benchmark/matlab/plot_uniform_benchmark.m +95 -0
  46. package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary32_clang.png +0 -0
  47. package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary32_msvc.png +0 -0
  48. package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary64_clang.png +0 -0
  49. package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary64_msvc.png +0 -0
  50. package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary32_clang.png +0 -0
  51. package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary32_msvc.png +0 -0
  52. package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary64_clang.png +0 -0
  53. package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary64_msvc.png +0 -0
  54. package/vendor/dragonbox/subproject/benchmark/source/benchmark.cpp +238 -0
  55. package/vendor/dragonbox/subproject/benchmark/source/dragonbox.cpp +30 -0
  56. package/vendor/dragonbox/subproject/benchmark/source/grisu_exact.cpp +36 -0
  57. package/vendor/dragonbox/subproject/benchmark/source/ryu.cpp +27 -0
  58. package/vendor/dragonbox/subproject/benchmark/source/schubfach.cpp +31 -0
  59. package/vendor/dragonbox/subproject/common/CMakeLists.txt +42 -0
  60. package/vendor/dragonbox/subproject/common/include/best_rational_approx.h +97 -0
  61. package/vendor/dragonbox/subproject/common/include/big_uint.h +218 -0
  62. package/vendor/dragonbox/subproject/common/include/continued_fractions.h +174 -0
  63. package/vendor/dragonbox/subproject/common/include/good_rational_approx.h +267 -0
  64. package/vendor/dragonbox/subproject/common/include/random_float.h +182 -0
  65. package/vendor/dragonbox/subproject/common/include/rational_continued_fractions.h +57 -0
  66. package/vendor/dragonbox/subproject/common/source/big_uint.cpp +602 -0
  67. package/vendor/dragonbox/subproject/meta/CMakeLists.txt +41 -0
  68. package/vendor/dragonbox/subproject/meta/results/binary32_generated_cache.txt +82 -0
  69. package/vendor/dragonbox/subproject/meta/results/binary64_compressed_cache_error_table.txt +10 -0
  70. package/vendor/dragonbox/subproject/meta/results/binary64_generated_cache.txt +623 -0
  71. package/vendor/dragonbox/subproject/meta/source/generate_cache.cpp +126 -0
  72. package/vendor/dragonbox/subproject/meta/source/live_test.cpp +81 -0
  73. package/vendor/dragonbox/subproject/meta/source/perf_test.cpp +104 -0
  74. package/vendor/dragonbox/subproject/meta/source/sandbox.cpp +20 -0
  75. package/vendor/dragonbox/subproject/test/CMakeLists.txt +70 -0
  76. package/vendor/dragonbox/subproject/test/results/binary32.csv +255 -0
  77. package/vendor/dragonbox/subproject/test/results/binary64.csv +2047 -0
  78. package/vendor/dragonbox/subproject/test/results/plot_required_bits.m +18 -0
  79. package/vendor/dragonbox/subproject/test/source/test_all_shorter_interval_cases.cpp +88 -0
  80. package/vendor/dragonbox/subproject/test/source/uniform_random_test.cpp +95 -0
  81. package/vendor/dragonbox/subproject/test/source/verify_cache_precision.cpp +338 -0
  82. package/vendor/dragonbox/subproject/test/source/verify_compressed_cache.cpp +154 -0
  83. package/vendor/dragonbox/subproject/test/source/verify_fast_multiplication.cpp +168 -0
  84. package/vendor/dragonbox/subproject/test/source/verify_log_computation.cpp +251 -0
  85. package/vendor/dragonbox/subproject/test/source/verify_magic_division.cpp +113 -0
  86. package/vendor/libcc/libcc.cc +7651 -0
  87. package/vendor/libcc/libcc.hh +4312 -0
  88. package/vendor/node-addon-api/CHANGELOG.md +859 -0
  89. package/vendor/node-addon-api/CODE_OF_CONDUCT.md +4 -0
  90. package/vendor/node-addon-api/CONTRIBUTING.md +93 -0
  91. package/vendor/node-addon-api/LICENSE.md +13 -0
  92. package/vendor/node-addon-api/README.md +293 -0
  93. package/vendor/node-addon-api/appveyor.yml +37 -0
  94. package/vendor/node-addon-api/benchmark/README.md +47 -0
  95. package/vendor/node-addon-api/benchmark/binding.gyp +25 -0
  96. package/vendor/node-addon-api/benchmark/function_args.cc +217 -0
  97. package/vendor/node-addon-api/benchmark/function_args.js +60 -0
  98. package/vendor/node-addon-api/benchmark/index.js +34 -0
  99. package/vendor/node-addon-api/benchmark/property_descriptor.cc +91 -0
  100. package/vendor/node-addon-api/benchmark/property_descriptor.js +37 -0
  101. package/vendor/node-addon-api/common.gypi +21 -0
  102. package/vendor/node-addon-api/doc/addon.md +163 -0
  103. package/vendor/node-addon-api/doc/array.md +81 -0
  104. package/vendor/node-addon-api/doc/array_buffer.md +155 -0
  105. package/vendor/node-addon-api/doc/async_context.md +86 -0
  106. package/vendor/node-addon-api/doc/async_operations.md +31 -0
  107. package/vendor/node-addon-api/doc/async_worker.md +427 -0
  108. package/vendor/node-addon-api/doc/async_worker_variants.md +557 -0
  109. package/vendor/node-addon-api/doc/bigint.md +97 -0
  110. package/vendor/node-addon-api/doc/boolean.md +68 -0
  111. package/vendor/node-addon-api/doc/buffer.md +150 -0
  112. package/vendor/node-addon-api/doc/callback_scope.md +54 -0
  113. package/vendor/node-addon-api/doc/callbackinfo.md +97 -0
  114. package/vendor/node-addon-api/doc/checker-tool.md +32 -0
  115. package/vendor/node-addon-api/doc/class_property_descriptor.md +115 -0
  116. package/vendor/node-addon-api/doc/cmake-js.md +68 -0
  117. package/vendor/node-addon-api/doc/conversion-tool.md +28 -0
  118. package/vendor/node-addon-api/doc/creating_a_release.md +62 -0
  119. package/vendor/node-addon-api/doc/dataview.md +248 -0
  120. package/vendor/node-addon-api/doc/date.md +68 -0
  121. package/vendor/node-addon-api/doc/env.md +196 -0
  122. package/vendor/node-addon-api/doc/error.md +120 -0
  123. package/vendor/node-addon-api/doc/error_handling.md +254 -0
  124. package/vendor/node-addon-api/doc/escapable_handle_scope.md +80 -0
  125. package/vendor/node-addon-api/doc/external.md +63 -0
  126. package/vendor/node-addon-api/doc/function.md +402 -0
  127. package/vendor/node-addon-api/doc/function_reference.md +238 -0
  128. package/vendor/node-addon-api/doc/generator.md +13 -0
  129. package/vendor/node-addon-api/doc/handle_scope.md +63 -0
  130. package/vendor/node-addon-api/doc/hierarchy.md +91 -0
  131. package/vendor/node-addon-api/doc/instance_wrap.md +408 -0
  132. package/vendor/node-addon-api/doc/maybe.md +76 -0
  133. package/vendor/node-addon-api/doc/memory_management.md +27 -0
  134. package/vendor/node-addon-api/doc/name.md +29 -0
  135. package/vendor/node-addon-api/doc/node-gyp.md +82 -0
  136. package/vendor/node-addon-api/doc/number.md +163 -0
  137. package/vendor/node-addon-api/doc/object.md +432 -0
  138. package/vendor/node-addon-api/doc/object_lifetime_management.md +83 -0
  139. package/vendor/node-addon-api/doc/object_reference.md +117 -0
  140. package/vendor/node-addon-api/doc/object_wrap.md +561 -0
  141. package/vendor/node-addon-api/doc/prebuild_tools.md +16 -0
  142. package/vendor/node-addon-api/doc/promises.md +79 -0
  143. package/vendor/node-addon-api/doc/property_descriptor.md +286 -0
  144. package/vendor/node-addon-api/doc/propertylvalue.md +50 -0
  145. package/vendor/node-addon-api/doc/range_error.md +59 -0
  146. package/vendor/node-addon-api/doc/reference.md +113 -0
  147. package/vendor/node-addon-api/doc/setup.md +110 -0
  148. package/vendor/node-addon-api/doc/string.md +93 -0
  149. package/vendor/node-addon-api/doc/symbol.md +61 -0
  150. package/vendor/node-addon-api/doc/threadsafe.md +121 -0
  151. package/vendor/node-addon-api/doc/threadsafe_function.md +290 -0
  152. package/vendor/node-addon-api/doc/type_error.md +59 -0
  153. package/vendor/node-addon-api/doc/typed_array.md +78 -0
  154. package/vendor/node-addon-api/doc/typed_array_of.md +137 -0
  155. package/vendor/node-addon-api/doc/typed_threadsafe_function.md +306 -0
  156. package/vendor/node-addon-api/doc/value.md +340 -0
  157. package/vendor/node-addon-api/doc/version_management.md +43 -0
  158. package/vendor/node-addon-api/except.gypi +25 -0
  159. package/vendor/node-addon-api/index.js +11 -0
  160. package/vendor/node-addon-api/napi-inl.deprecated.h +192 -0
  161. package/vendor/node-addon-api/napi-inl.h +6209 -0
  162. package/vendor/node-addon-api/napi.h +2983 -0
  163. package/vendor/node-addon-api/node_api.gyp +9 -0
  164. package/vendor/node-addon-api/noexcept.gypi +26 -0
  165. package/vendor/node-addon-api/nothing.c +0 -0
  166. package/vendor/node-addon-api/package-support.json +21 -0
  167. package/vendor/node-addon-api/package.json +399 -0
  168. package/vendor/node-addon-api/test/README.md +91 -0
  169. package/vendor/node-addon-api/test/addon.cc +36 -0
  170. package/vendor/node-addon-api/test/addon.js +11 -0
  171. package/vendor/node-addon-api/test/addon_build/index.js +49 -0
  172. package/vendor/node-addon-api/test/addon_build/tpl/addon.cc +17 -0
  173. package/vendor/node-addon-api/test/addon_build/tpl/binding.gyp +62 -0
  174. package/vendor/node-addon-api/test/addon_build/tpl/index.js +9 -0
  175. package/vendor/node-addon-api/test/addon_build/tpl/package.json +11 -0
  176. package/vendor/node-addon-api/test/addon_data.cc +99 -0
  177. package/vendor/node-addon-api/test/addon_data.js +46 -0
  178. package/vendor/node-addon-api/test/array_buffer.cc +243 -0
  179. package/vendor/node-addon-api/test/array_buffer.js +69 -0
  180. package/vendor/node-addon-api/test/async_context.cc +21 -0
  181. package/vendor/node-addon-api/test/async_context.js +86 -0
  182. package/vendor/node-addon-api/test/async_progress_queue_worker.cc +83 -0
  183. package/vendor/node-addon-api/test/async_progress_queue_worker.js +46 -0
  184. package/vendor/node-addon-api/test/async_progress_worker.cc +134 -0
  185. package/vendor/node-addon-api/test/async_progress_worker.js +61 -0
  186. package/vendor/node-addon-api/test/async_worker.cc +106 -0
  187. package/vendor/node-addon-api/test/async_worker.js +179 -0
  188. package/vendor/node-addon-api/test/async_worker_nocallback.js +13 -0
  189. package/vendor/node-addon-api/test/async_worker_persistent.cc +63 -0
  190. package/vendor/node-addon-api/test/async_worker_persistent.js +24 -0
  191. package/vendor/node-addon-api/test/basic_types/array.cc +40 -0
  192. package/vendor/node-addon-api/test/basic_types/array.js +35 -0
  193. package/vendor/node-addon-api/test/basic_types/boolean.cc +38 -0
  194. package/vendor/node-addon-api/test/basic_types/boolean.js +35 -0
  195. package/vendor/node-addon-api/test/basic_types/number.cc +99 -0
  196. package/vendor/node-addon-api/test/basic_types/number.js +114 -0
  197. package/vendor/node-addon-api/test/basic_types/value.cc +120 -0
  198. package/vendor/node-addon-api/test/basic_types/value.js +133 -0
  199. package/vendor/node-addon-api/test/bigint.cc +91 -0
  200. package/vendor/node-addon-api/test/bigint.js +53 -0
  201. package/vendor/node-addon-api/test/binding-swallowexcept.cc +12 -0
  202. package/vendor/node-addon-api/test/binding.cc +171 -0
  203. package/vendor/node-addon-api/test/binding.gyp +117 -0
  204. package/vendor/node-addon-api/test/buffer.cc +183 -0
  205. package/vendor/node-addon-api/test/buffer.js +69 -0
  206. package/vendor/node-addon-api/test/callbackscope.cc +22 -0
  207. package/vendor/node-addon-api/test/callbackscope.js +49 -0
  208. package/vendor/node-addon-api/test/common/index.js +113 -0
  209. package/vendor/node-addon-api/test/common/test_helper.h +61 -0
  210. package/vendor/node-addon-api/test/dataview/dataview.cc +48 -0
  211. package/vendor/node-addon-api/test/dataview/dataview.js +35 -0
  212. package/vendor/node-addon-api/test/dataview/dataview_read_write.cc +115 -0
  213. package/vendor/node-addon-api/test/dataview/dataview_read_write.js +90 -0
  214. package/vendor/node-addon-api/test/date.cc +44 -0
  215. package/vendor/node-addon-api/test/date.js +18 -0
  216. package/vendor/node-addon-api/test/env_cleanup.cc +88 -0
  217. package/vendor/node-addon-api/test/env_cleanup.js +56 -0
  218. package/vendor/node-addon-api/test/error.cc +287 -0
  219. package/vendor/node-addon-api/test/error.js +81 -0
  220. package/vendor/node-addon-api/test/error_handling_for_primitives.cc +13 -0
  221. package/vendor/node-addon-api/test/error_handling_for_primitives.js +29 -0
  222. package/vendor/node-addon-api/test/error_terminating_environment.js +94 -0
  223. package/vendor/node-addon-api/test/external.cc +81 -0
  224. package/vendor/node-addon-api/test/external.js +88 -0
  225. package/vendor/node-addon-api/test/function.cc +295 -0
  226. package/vendor/node-addon-api/test/function.js +121 -0
  227. package/vendor/node-addon-api/test/function_reference.cc +202 -0
  228. package/vendor/node-addon-api/test/function_reference.js +157 -0
  229. package/vendor/node-addon-api/test/globalObject/global_object.cc +61 -0
  230. package/vendor/node-addon-api/test/globalObject/global_object_delete_property.cc +31 -0
  231. package/vendor/node-addon-api/test/globalObject/global_object_delete_property.js +61 -0
  232. package/vendor/node-addon-api/test/globalObject/global_object_get_property.cc +40 -0
  233. package/vendor/node-addon-api/test/globalObject/global_object_get_property.js +57 -0
  234. package/vendor/node-addon-api/test/globalObject/global_object_has_own_property.cc +28 -0
  235. package/vendor/node-addon-api/test/globalObject/global_object_has_own_property.js +48 -0
  236. package/vendor/node-addon-api/test/globalObject/global_object_set_property.cc +31 -0
  237. package/vendor/node-addon-api/test/globalObject/global_object_set_property.js +58 -0
  238. package/vendor/node-addon-api/test/handlescope.cc +60 -0
  239. package/vendor/node-addon-api/test/handlescope.js +14 -0
  240. package/vendor/node-addon-api/test/index.js +136 -0
  241. package/vendor/node-addon-api/test/maybe/check.cc +23 -0
  242. package/vendor/node-addon-api/test/maybe/index.js +38 -0
  243. package/vendor/node-addon-api/test/memory_management.cc +17 -0
  244. package/vendor/node-addon-api/test/memory_management.js +9 -0
  245. package/vendor/node-addon-api/test/movable_callbacks.cc +23 -0
  246. package/vendor/node-addon-api/test/movable_callbacks.js +21 -0
  247. package/vendor/node-addon-api/test/name.cc +108 -0
  248. package/vendor/node-addon-api/test/name.js +59 -0
  249. package/vendor/node-addon-api/test/napi_child.js +14 -0
  250. package/vendor/node-addon-api/test/object/delete_property.cc +38 -0
  251. package/vendor/node-addon-api/test/object/delete_property.js +41 -0
  252. package/vendor/node-addon-api/test/object/finalizer.cc +29 -0
  253. package/vendor/node-addon-api/test/object/finalizer.js +28 -0
  254. package/vendor/node-addon-api/test/object/get_property.cc +34 -0
  255. package/vendor/node-addon-api/test/object/get_property.js +40 -0
  256. package/vendor/node-addon-api/test/object/has_own_property.cc +34 -0
  257. package/vendor/node-addon-api/test/object/has_own_property.js +34 -0
  258. package/vendor/node-addon-api/test/object/has_property.cc +38 -0
  259. package/vendor/node-addon-api/test/object/has_property.js +37 -0
  260. package/vendor/node-addon-api/test/object/object.cc +348 -0
  261. package/vendor/node-addon-api/test/object/object.js +217 -0
  262. package/vendor/node-addon-api/test/object/object_deprecated.cc +66 -0
  263. package/vendor/node-addon-api/test/object/object_deprecated.js +47 -0
  264. package/vendor/node-addon-api/test/object/object_freeze_seal.cc +25 -0
  265. package/vendor/node-addon-api/test/object/object_freeze_seal.js +61 -0
  266. package/vendor/node-addon-api/test/object/set_property.cc +37 -0
  267. package/vendor/node-addon-api/test/object/set_property.js +29 -0
  268. package/vendor/node-addon-api/test/object/subscript_operator.cc +42 -0
  269. package/vendor/node-addon-api/test/object/subscript_operator.js +17 -0
  270. package/vendor/node-addon-api/test/object_reference.cc +219 -0
  271. package/vendor/node-addon-api/test/object_reference.js +259 -0
  272. package/vendor/node-addon-api/test/objectwrap.cc +268 -0
  273. package/vendor/node-addon-api/test/objectwrap.js +284 -0
  274. package/vendor/node-addon-api/test/objectwrap_constructor_exception.cc +26 -0
  275. package/vendor/node-addon-api/test/objectwrap_constructor_exception.js +18 -0
  276. package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.cc +30 -0
  277. package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.js +13 -0
  278. package/vendor/node-addon-api/test/objectwrap_removewrap.cc +45 -0
  279. package/vendor/node-addon-api/test/objectwrap_removewrap.js +40 -0
  280. package/vendor/node-addon-api/test/objectwrap_worker_thread.js +19 -0
  281. package/vendor/node-addon-api/test/promise.cc +29 -0
  282. package/vendor/node-addon-api/test/promise.js +18 -0
  283. package/vendor/node-addon-api/test/reference.cc +24 -0
  284. package/vendor/node-addon-api/test/reference.js +14 -0
  285. package/vendor/node-addon-api/test/run_script.cc +56 -0
  286. package/vendor/node-addon-api/test/run_script.js +45 -0
  287. package/vendor/node-addon-api/test/symbol.cc +79 -0
  288. package/vendor/node-addon-api/test/symbol.js +73 -0
  289. package/vendor/node-addon-api/test/testUtil.js +54 -0
  290. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.cc +195 -0
  291. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.js +188 -0
  292. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.cc +63 -0
  293. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.js +12 -0
  294. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.cc +115 -0
  295. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.js +14 -0
  296. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.cc +26 -0
  297. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.js +7 -0
  298. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.cc +225 -0
  299. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.js +59 -0
  300. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.cc +42 -0
  301. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.js +53 -0
  302. package/vendor/node-addon-api/test/thunking_manual.cc +140 -0
  303. package/vendor/node-addon-api/test/thunking_manual.js +17 -0
  304. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.cc +215 -0
  305. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.js +188 -0
  306. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.cc +68 -0
  307. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.js +12 -0
  308. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_existing_tsfn.cc +127 -0
  309. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_existing_tsfn.js +14 -0
  310. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.cc +28 -0
  311. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.js +7 -0
  312. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_sum.cc +237 -0
  313. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_sum.js +59 -0
  314. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.cc +53 -0
  315. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.js +53 -0
  316. package/vendor/node-addon-api/test/typedarray-bigint.js +58 -0
  317. package/vendor/node-addon-api/test/typedarray.cc +216 -0
  318. package/vendor/node-addon-api/test/typedarray.js +69 -0
  319. package/vendor/node-addon-api/test/version_management.cc +27 -0
  320. package/vendor/node-addon-api/test/version_management.js +31 -0
  321. package/vendor/node-addon-api/tools/README.md +73 -0
  322. package/vendor/node-addon-api/tools/check-napi.js +100 -0
  323. package/vendor/node-addon-api/tools/clang-format.js +68 -0
  324. package/vendor/node-addon-api/tools/conversion.js +309 -0
  325. package/vendor/node-addon-api/tools/eslint-format.js +71 -0
  326. package/build/ALL_BUILD.vcxproj +0 -190
  327. package/build/ALL_BUILD.vcxproj.filters +0 -8
  328. package/build/CMakeCache.txt +0 -429
  329. package/build/CMakeFiles/3.23.0-rc1/CMakeASMCompiler.cmake +0 -20
  330. package/build/CMakeFiles/3.23.0-rc1/CMakeASM_MASMCompiler.cmake +0 -20
  331. package/build/CMakeFiles/3.23.0-rc1/CMakeCCompiler.cmake +0 -72
  332. package/build/CMakeFiles/3.23.0-rc1/CMakeCXXCompiler.cmake +0 -83
  333. package/build/CMakeFiles/3.23.0-rc1/CMakeDetermineCompilerABI_C.bin +0 -0
  334. package/build/CMakeFiles/3.23.0-rc1/CMakeDetermineCompilerABI_CXX.bin +0 -0
  335. package/build/CMakeFiles/3.23.0-rc1/CMakeRCCompiler.cmake +0 -6
  336. package/build/CMakeFiles/3.23.0-rc1/CMakeSystem.cmake +0 -15
  337. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/CMakeCCompilerId.c +0 -828
  338. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/CompilerIdC.exe +0 -0
  339. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/CompilerIdC.vcxproj +0 -71
  340. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CMakeCCompilerId.obj +0 -0
  341. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.exe.recipe +0 -11
  342. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CL.command.1.tlog +0 -0
  343. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CL.read.1.tlog +0 -0
  344. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CL.write.1.tlog +0 -0
  345. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CompilerIdC.lastbuildstate +0 -2
  346. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/link.command.1.tlog +0 -0
  347. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/link.read.1.tlog +0 -0
  348. package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/link.write.1.tlog +0 -0
  349. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/CMakeCXXCompilerId.cpp +0 -816
  350. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/CompilerIdCXX.exe +0 -0
  351. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/CompilerIdCXX.vcxproj +0 -71
  352. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CMakeCXXCompilerId.obj +0 -0
  353. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.exe.recipe +0 -11
  354. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.command.1.tlog +0 -0
  355. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.read.1.tlog +0 -0
  356. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.write.1.tlog +0 -0
  357. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CompilerIdCXX.lastbuildstate +0 -2
  358. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.command.1.tlog +0 -0
  359. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.read.1.tlog +0 -0
  360. package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.write.1.tlog +0 -0
  361. package/build/CMakeFiles/3.23.0-rc1/VCTargetsPath.txt +0 -1
  362. package/build/CMakeFiles/3.23.0-rc1/VCTargetsPath.vcxproj +0 -31
  363. package/build/CMakeFiles/3.23.0-rc1/x64/Debug/VCTargetsPath.recipe +0 -11
  364. package/build/CMakeFiles/3.23.0-rc1/x64/Debug/VCTargetsPath.tlog/VCTargetsPath.lastbuildstate +0 -2
  365. package/build/CMakeFiles/41bcd16856091d4a38fd1f71fbe2f202/generate.stamp.rule +0 -1
  366. package/build/CMakeFiles/CMakeError.log +0 -108
  367. package/build/CMakeFiles/CMakeOutput.log +0 -413
  368. package/build/CMakeFiles/TargetDirectories.txt +0 -4
  369. package/build/CMakeFiles/cmake.check_cache +0 -1
  370. package/build/CMakeFiles/generate.stamp +0 -1
  371. package/build/CMakeFiles/generate.stamp.depend +0 -28
  372. package/build/CMakeFiles/generate.stamp.list +0 -1
  373. package/build/Raylib.dir/Release/Raylib.dll.recipe +0 -14
  374. package/build/Raylib.dir/Release/Raylib.tlog/CL.command.1.tlog +0 -0
  375. package/build/Raylib.dir/Release/Raylib.tlog/CL.read.1.tlog +0 -0
  376. package/build/Raylib.dir/Release/Raylib.tlog/CL.write.1.tlog +0 -0
  377. package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.command.1.tlog +0 -10
  378. package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.read.1.tlog +0 -27
  379. package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.write.1.tlog +0 -2
  380. package/build/Raylib.dir/Release/Raylib.tlog/Raylib.lastbuildstate +0 -2
  381. package/build/Raylib.dir/Release/Raylib.tlog/Raylib.write.1u.tlog +0 -0
  382. package/build/Raylib.dir/Release/Raylib.tlog/link.command.1.tlog +0 -0
  383. package/build/Raylib.dir/Release/Raylib.tlog/link.read.1.tlog +0 -0
  384. package/build/Raylib.dir/Release/Raylib.tlog/link.write.1.tlog +0 -0
  385. package/build/Raylib.dir/Release/raudio.obj +0 -0
  386. package/build/Raylib.dir/Release/rcore.obj +0 -0
  387. package/build/Raylib.dir/Release/rglfw.obj +0 -0
  388. package/build/Raylib.dir/Release/rmodels.obj +0 -0
  389. package/build/Raylib.dir/Release/rshapes.obj +0 -0
  390. package/build/Raylib.dir/Release/rtext.obj +0 -0
  391. package/build/Raylib.dir/Release/rtextures.obj +0 -0
  392. package/build/Raylib.dir/Release/utils.obj +0 -0
  393. package/build/Raylib.vcxproj +0 -358
  394. package/build/Raylib.vcxproj.filters +0 -37
  395. package/build/Release/Raylib.dll +0 -0
  396. package/build/Release/Raylib.exp +0 -0
  397. package/build/Release/Raylib.lib +0 -0
  398. package/build/Release/koffi.exp +0 -0
  399. package/build/Release/koffi.lib +0 -0
  400. package/build/Release/koffi.node +0 -0
  401. package/build/ZERO_CHECK.vcxproj +0 -176
  402. package/build/ZERO_CHECK.vcxproj.filters +0 -13
  403. package/build/cmake_install.cmake +0 -44
  404. package/build/koffi.dir/Release/call_arm64.obj +0 -0
  405. package/build/koffi.dir/Release/call_x64_sysv.obj +0 -0
  406. package/build/koffi.dir/Release/call_x64_win.obj +0 -0
  407. package/build/koffi.dir/Release/call_x64_win_fwd.obj +0 -0
  408. package/build/koffi.dir/Release/call_x86.obj +0 -0
  409. package/build/koffi.dir/Release/ffi.obj +0 -0
  410. package/build/koffi.dir/Release/koffi.node.recipe +0 -14
  411. package/build/koffi.dir/Release/koffi.tlog/CL.command.1.tlog +0 -0
  412. package/build/koffi.dir/Release/koffi.tlog/CL.read.1.tlog +0 -0
  413. package/build/koffi.dir/Release/koffi.tlog/CL.write.1.tlog +0 -0
  414. package/build/koffi.dir/Release/koffi.tlog/CustomBuild.command.1.tlog +0 -10
  415. package/build/koffi.dir/Release/koffi.tlog/CustomBuild.read.1.tlog +0 -27
  416. package/build/koffi.dir/Release/koffi.tlog/CustomBuild.write.1.tlog +0 -2
  417. package/build/koffi.dir/Release/koffi.tlog/Masm.read.1u.tlog +0 -0
  418. package/build/koffi.dir/Release/koffi.tlog/Masm.write.1u.tlog +0 -0
  419. package/build/koffi.dir/Release/koffi.tlog/koffi.lastbuildstate +0 -2
  420. package/build/koffi.dir/Release/koffi.tlog/koffi.write.1u.tlog +0 -0
  421. package/build/koffi.dir/Release/koffi.tlog/link.command.1.tlog +0 -0
  422. package/build/koffi.dir/Release/koffi.tlog/link.read.1.tlog +0 -0
  423. package/build/koffi.dir/Release/koffi.tlog/link.write.1.tlog +0 -0
  424. package/build/koffi.dir/Release/libcc.obj +0 -0
  425. package/build/koffi.dir/Release/util.obj +0 -0
  426. package/build/koffi.dir/Release/win_delay_load_hook.obj +0 -0
  427. package/build/koffi.sln +0 -67
  428. package/build/koffi.vcxproj +0 -363
  429. package/build/koffi.vcxproj.filters +0 -40
  430. package/build/x64/Release/ALL_BUILD/ALL_BUILD.recipe +0 -20
  431. package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/ALL_BUILD.lastbuildstate +0 -2
  432. package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.command.1.tlog +0 -10
  433. package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.read.1.tlog +0 -27
  434. package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.write.1.tlog +0 -2
  435. package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.recipe +0 -11
  436. package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.command.1.tlog +0 -10
  437. package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.read.1.tlog +0 -28
  438. package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.write.1.tlog +0 -2
  439. package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/ZERO_CHECK.lastbuildstate +0 -2
@@ -0,0 +1,4312 @@
1
+ // This program is free software: you can redistribute it and/or modify
2
+ // it under the terms of the GNU Affero General Public License as published by
3
+ // the Free Software Foundation, either version 3 of the License, or
4
+ // (at your option) any later version.
5
+ //
6
+ // This program is distributed in the hope that it will be useful,
7
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
8
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
+ // GNU Affero General Public License for more details.
10
+ //
11
+ // You should have received a copy of the GNU Affero General Public License
12
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
13
+
14
+ #pragma once
15
+
16
+ #include <algorithm>
17
+ #include <atomic>
18
+ #include <cmath>
19
+ #include <condition_variable>
20
+ #include <errno.h>
21
+ #include <float.h>
22
+ #include <functional>
23
+ #include <inttypes.h>
24
+ #include <limits.h>
25
+ #include <limits>
26
+ #include <memory>
27
+ #include <mutex>
28
+ #include <shared_mutex>
29
+ #include <stddef.h>
30
+ #include <stdint.h>
31
+ #include <stdio.h>
32
+ #include <stdlib.h>
33
+ #include <string.h>
34
+ #include <type_traits>
35
+ #include <utility>
36
+ #ifdef _WIN32
37
+ #include <intrin.h>
38
+ #else
39
+ #include <ucontext.h>
40
+ #endif
41
+ #ifdef __EMSCRIPTEN__
42
+ #include <emscripten.h>
43
+ #endif
44
+ #ifdef _MSC_VER
45
+ #define ENABLE_INTSAFE_SIGNED_FUNCTIONS
46
+ #include <intsafe.h>
47
+ #pragma intrinsic(_BitScanReverse)
48
+ #ifdef _WIN64
49
+ #pragma intrinsic(_BitScanReverse64)
50
+ #endif
51
+ #pragma intrinsic(__rdtsc)
52
+ #endif
53
+
54
+ struct BrotliEncoderStateStruct;
55
+
56
+ namespace RG {
57
+
58
+ // ------------------------------------------------------------------------
59
+ // Config
60
+ // ------------------------------------------------------------------------
61
+
62
+ #ifndef NDEBUG
63
+ #define RG_DEBUG
64
+ #endif
65
+
66
+ #define RG_DEFAULT_ALLOCATOR MallocAllocator
67
+ #define RG_BLOCK_ALLOCATOR_DEFAULT_SIZE Kibibytes(4)
68
+
69
+ #define RG_HEAPARRAY_BASE_CAPACITY 8
70
+ #define RG_HEAPARRAY_GROWTH_FACTOR 2.0
71
+
72
+ // Must be a power-of-two
73
+ #define RG_HASHTABLE_BASE_CAPACITY 8
74
+ #define RG_HASHTABLE_MAX_LOAD_FACTOR 0.5
75
+
76
+ #define RG_FMT_STRING_BASE_CAPACITY 256
77
+ #define RG_FMT_STRING_PRINT_BUFFER_SIZE 1024
78
+
79
+ #define RG_LINE_READER_STEP_SIZE 65536
80
+
81
+ #define RG_ASYNC_MAX_THREADS 256
82
+ #define RG_ASYNC_MAX_IDLE_TIME 10000
83
+ #define RG_FIBER_DEFAULT_STACK_SIZE Kibibytes(128)
84
+
85
+ // ------------------------------------------------------------------------
86
+ // Utility
87
+ // ------------------------------------------------------------------------
88
+
89
+ extern "C" const char *FelixTarget;
90
+ extern "C" const char *FelixVersion;
91
+ extern "C" const char *FelixCompiler;
92
+
93
+ #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
94
+ typedef int64_t Size;
95
+ #define RG_SIZE_MAX INT64_MAX
96
+ #elif defined(_WIN32) || defined(__APPLE__) || defined(__unix__)
97
+ typedef int32_t Size;
98
+ #define RG_SIZE_MAX INT32_MAX
99
+ #elif defined(__thumb__) || defined(__arm__) || defined(__EMSCRIPTEN__)
100
+ typedef int32_t Size;
101
+ #define RG_SIZE_MAX INT32_MAX
102
+ #else
103
+ #error Machine architecture not supported
104
+ #endif
105
+
106
+ #if !defined(_MSC_VER) && __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
107
+ #error This code base is not designed to support big-endian platforms
108
+ #endif
109
+ #if UINT_MAX != 0xFFFFFFFFu
110
+ #error This code base is not designed to support non-32-bits int types
111
+ #endif
112
+ #if ULLONG_MAX != 0xFFFFFFFFFFFFFFFFull
113
+ #error This code base is not designed to support non-64-bits long long types
114
+ #endif
115
+
116
+ #define RG_STRINGIFY_(a) #a
117
+ #define RG_STRINGIFY(a) RG_STRINGIFY_(a)
118
+ #define RG_CONCAT_(a, b) a ## b
119
+ #define RG_CONCAT(a, b) RG_CONCAT_(a, b)
120
+ #define RG_UNIQUE_NAME(prefix) RG_CONCAT(prefix, __COUNTER__)
121
+ #define RG_FORCE_EXPAND(x) x
122
+ #define RG_IGNORE (void)!
123
+
124
+ #if defined(__GNUC__)
125
+ #define RG_PUSH_NO_WARNINGS \
126
+ _Pragma("GCC diagnostic push") \
127
+ _Pragma("GCC diagnostic ignored \"-Wall\"") \
128
+ _Pragma("GCC diagnostic ignored \"-Wextra\"") \
129
+ _Pragma("GCC diagnostic ignored \"-Wconversion\"") \
130
+ _Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") \
131
+ _Pragma("GCC diagnostic ignored \"-Wunused-function\"") \
132
+ _Pragma("GCC diagnostic ignored \"-Wunused-variable\"") \
133
+ _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
134
+ #define RG_POP_NO_WARNINGS \
135
+ _Pragma("GCC diagnostic pop")
136
+
137
+ // thread_local has many bugs with MinGW (Windows):
138
+ // - Destructors are run after the memory is freed
139
+ // - It crashes when used in R packages
140
+ #ifdef __EMSCRIPTEN__
141
+ #define RG_THREAD_LOCAL
142
+ #else
143
+ #define RG_THREAD_LOCAL __thread
144
+ #endif
145
+ #define RG_LIKELY(Cond) __builtin_expect(!!(Cond), 1)
146
+ #define RG_UNLIKELY(Cond) __builtin_expect(!!(Cond), 0)
147
+
148
+ #ifndef SCNd8
149
+ #define SCNd8 "hhd"
150
+ #endif
151
+ #ifndef SCNi8
152
+ #define SCNi8 "hhd"
153
+ #endif
154
+ #ifndef SCNu8
155
+ #define SCNu8 "hhu"
156
+ #endif
157
+ #elif defined(_MSC_VER)
158
+ #define RG_PUSH_NO_WARNINGS __pragma(warning(push, 0))
159
+ #define RG_POP_NO_WARNINGS __pragma(warning(pop))
160
+
161
+ #define RG_THREAD_LOCAL thread_local
162
+ #define RG_LIKELY(Cond) (Cond)
163
+ #define RG_UNLIKELY(Cond) (Cond)
164
+ #else
165
+ #error Compiler not supported
166
+ #endif
167
+
168
+ #ifdef __clang__
169
+ #if __has_feature(address_sanitizer)
170
+ #define __SANITIZE_ADDRESS__
171
+ #endif
172
+ #if __has_feature(thread_sanitizer)
173
+ #define __SANITIZE_THREAD__
174
+ #endif
175
+ #if __has_feature(undefined_sanitizer)
176
+ #define __SANITIZE_UNDEFINED__
177
+ #endif
178
+ #endif
179
+
180
+ extern "C" void AssertMessage(const char *filename, int line, const char *cond);
181
+
182
+ #if defined(_MSC_VER)
183
+ #define RG_DEBUG_BREAK() __debugbreak()
184
+ #elif defined(__clang__)
185
+ #define RG_DEBUG_BREAK() __builtin_debugtrap()
186
+ #elif defined(__i386__) || defined(__x86_64__)
187
+ #define RG_DEBUG_BREAK() __asm__ __volatile__("int $0x03")
188
+ #elif defined(__thumb__)
189
+ #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xde01")
190
+ #elif defined(__aarch64__)
191
+ #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xd4200000")
192
+ #elif defined(__arm__)
193
+ #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xe7f001f0")
194
+ #endif
195
+
196
+ #define RG_CRITICAL(Cond, ...) \
197
+ do { \
198
+ if (RG_UNLIKELY(!(Cond))) { \
199
+ PrintLn(stderr, __VA_ARGS__); \
200
+ abort(); \
201
+ } \
202
+ } while (false)
203
+ #ifdef RG_DEBUG
204
+ #define RG_ASSERT(Cond) \
205
+ do { \
206
+ if (RG_UNLIKELY(!(Cond))) { \
207
+ RG::AssertMessage(__FILE__, __LINE__, RG_STRINGIFY(Cond)); \
208
+ RG_DEBUG_BREAK(); \
209
+ abort(); \
210
+ } \
211
+ } while (false)
212
+ #else
213
+ #define RG_ASSERT(Cond) \
214
+ do { \
215
+ (void)sizeof(Cond); \
216
+ } while (false)
217
+ #endif
218
+ #define RG_STATIC_ASSERT(Cond) \
219
+ static_assert((Cond), RG_STRINGIFY(Cond))
220
+
221
+ #if defined(RG_DEBUG)
222
+ #define RG_UNREACHABLE() \
223
+ do { \
224
+ RG::AssertMessage(__FILE__, __LINE__, "Reached code marked as UNREACHABLE"); \
225
+ RG_DEBUG_BREAK(); \
226
+ abort(); \
227
+ } while (false)
228
+ #elif defined(__GNUC__)
229
+ #define RG_UNREACHABLE() __builtin_unreachable()
230
+ #else
231
+ #define RG_UNREACHABLE() __assume(0)
232
+ #endif
233
+
234
+ #if defined(__EMSCRIPTEN__)
235
+ #define RG_EXPORT EMSCRIPTEN_KEEPALIVE
236
+ #elif defined(_WIN32)
237
+ #define RG_EXPORT __declspec(dllexport)
238
+ #else
239
+ #define RG_EXPORT __attribute__((visibility("default")))
240
+ #endif
241
+
242
+ #define RG_DELETE_COPY(Cls) \
243
+ Cls(const Cls&) = delete; \
244
+ Cls &operator=(const Cls&) = delete;
245
+
246
+ constexpr uint16_t MakeUInt16(uint8_t high, uint8_t low)
247
+ { return (uint16_t)(((uint16_t)high << 8) | low); }
248
+ constexpr uint32_t MakeUInt32(uint16_t high, uint16_t low) { return ((uint32_t)high << 16) | low; }
249
+ constexpr uint64_t MakeUInt64(uint32_t high, uint32_t low) { return ((uint64_t)high << 32) | low; }
250
+
251
+ constexpr Size Mebibytes(Size len) { return len * 1024 * 1024; }
252
+ constexpr Size Kibibytes(Size len) { return len * 1024; }
253
+ constexpr Size Megabytes(Size len) { return len * 1000 * 1000; }
254
+ constexpr Size Kilobytes(Size len) { return len * 1000; }
255
+
256
+ #define RG_SIZE(Type) ((RG::Size)sizeof(Type))
257
+ template <typename T, unsigned N>
258
+ char (&ComputeArraySize(T const (&)[N]))[N];
259
+ #define RG_LEN(Array) RG_SIZE(RG::ComputeArraySize(Array))
260
+ #define RG_OFFSET_OF(Type, Member) __builtin_offsetof(Type, Member)
261
+
262
+ static inline constexpr uint16_t ReverseBytes(uint16_t u)
263
+ {
264
+ return (uint16_t)(((u & 0x00FF) << 8) |
265
+ ((u & 0xFF00) >> 8));
266
+ }
267
+
268
+ static inline constexpr uint32_t ReverseBytes(uint32_t u)
269
+ {
270
+ return ((u & 0x000000FF) << 24) |
271
+ ((u & 0x0000FF00) << 8) |
272
+ ((u & 0x00FF0000) >> 8) |
273
+ ((u & 0xFF000000) >> 24);
274
+ }
275
+
276
+ static inline constexpr uint64_t ReverseBytes(uint64_t u)
277
+ {
278
+ return ((u & 0x00000000000000FF) << 56) |
279
+ ((u & 0x000000000000FF00) << 40) |
280
+ ((u & 0x0000000000FF0000) << 24) |
281
+ ((u & 0x00000000FF000000) << 8) |
282
+ ((u & 0x000000FF00000000) >> 8) |
283
+ ((u & 0x0000FF0000000000) >> 24) |
284
+ ((u & 0x00FF000000000000) >> 40) |
285
+ ((u & 0xFF00000000000000) >> 56);
286
+ }
287
+
288
+ static inline constexpr int16_t ReverseBytes(int16_t i)
289
+ { return (int16_t)ReverseBytes((uint16_t)i); }
290
+ static inline constexpr int32_t ReverseBytes(int32_t i)
291
+ { return (int32_t)ReverseBytes((uint32_t)i); }
292
+ static inline constexpr int64_t ReverseBytes(int64_t i)
293
+ { return (int64_t)ReverseBytes((uint64_t)i); }
294
+
295
+ // Sensitive to endianness
296
+ template <typename T>
297
+ constexpr T LittleEndian(T v) { return v; }
298
+ template <typename T>
299
+ constexpr T BigEndian(T v) { return ReverseBytes(v); }
300
+
301
+ #if defined(__GNUC__)
302
+ static inline int CountLeadingZeros(uint32_t u)
303
+ {
304
+ if (!u)
305
+ return 32;
306
+
307
+ return __builtin_clz(u);
308
+ }
309
+ static inline int CountLeadingZeros(uint64_t u)
310
+ {
311
+ if (!u)
312
+ return 64;
313
+
314
+ #if UINT64_MAX == ULONG_MAX
315
+ return __builtin_clzl(u);
316
+ #elif UINT64_MAX == ULLONG_MAX
317
+ return __builtin_clzll(u);
318
+ #else
319
+ #error Neither unsigned long nor unsigned long long is a 64-bit unsigned integer
320
+ #endif
321
+ }
322
+
323
+ static inline int CountTrailingZeros(uint32_t u)
324
+ {
325
+ if (!u)
326
+ return 32;
327
+
328
+ return __builtin_ctz(u);
329
+ }
330
+ static inline int CountTrailingZeros(uint64_t u)
331
+ {
332
+ if (!u)
333
+ return 64;
334
+
335
+ #if UINT64_MAX == ULONG_MAX
336
+ return __builtin_ctzl(u);
337
+ #elif UINT64_MAX == ULLONG_MAX
338
+ return __builtin_ctzll(u);
339
+ #else
340
+ #error Neither unsigned long nor unsigned long long is a 64-bit unsigned integer
341
+ #endif
342
+ }
343
+
344
+ static inline int PopCount(uint32_t u)
345
+ {
346
+ return __builtin_popcount(u);
347
+ }
348
+ static inline int PopCount(uint64_t u)
349
+ {
350
+ return __builtin_popcountll(u);
351
+ }
352
+ #elif defined(_MSC_VER)
353
+ static inline int CountLeadingZeros(uint32_t u)
354
+ {
355
+ unsigned long leading_zero;
356
+ if (_BitScanReverse(&leading_zero, u)) {
357
+ return (int)(31 - leading_zero);
358
+ } else {
359
+ return 32;
360
+ }
361
+ }
362
+ static inline int CountLeadingZeros(uint64_t u)
363
+ {
364
+ unsigned long leading_zero;
365
+ #ifdef _WIN64
366
+ if (_BitScanReverse64(&leading_zero, u)) {
367
+ return (int)(63 - leading_zero);
368
+ } else {
369
+ return 64;
370
+ }
371
+ #else
372
+ if (_BitScanReverse(&leading_zero, u >> 32)) {
373
+ return (int)(31 - leading_zero);
374
+ } else if (_BitScanReverse(&leading_zero, (uint32_t)u)) {
375
+ return (int)(63 - leading_zero);
376
+ } else {
377
+ return 64;
378
+ }
379
+ #endif
380
+ }
381
+
382
+ static inline int CountTrailingZeros(uint32_t u)
383
+ {
384
+ unsigned long trailing_zero;
385
+ if (_BitScanForward(&trailing_zero, u)) {
386
+ return (int)trailing_zero;
387
+ } else {
388
+ return 32;
389
+ }
390
+ }
391
+ static inline int CountTrailingZeros(uint64_t u)
392
+ {
393
+ unsigned long trailing_zero;
394
+ #ifdef _WIN64
395
+ if (_BitScanForward64(&trailing_zero, u)) {
396
+ return (int)trailing_zero;
397
+ } else {
398
+ return 64;
399
+ }
400
+ #else
401
+ if (_BitScanForward(&trailing_zero, (uint32_t)u)) {
402
+ return trailing_zero;
403
+ } else if (_BitScanForward(&trailing_zero, u >> 32)) {
404
+ return 32 + trailing_zero;
405
+ } else {
406
+ return 64;
407
+ }
408
+ #endif
409
+ }
410
+
411
+ static inline int PopCount(uint32_t u)
412
+ {
413
+ return __popcnt(u);
414
+ }
415
+ static inline int PopCount(uint64_t u)
416
+ {
417
+ #ifdef _WIN64
418
+ return (int)__popcnt64(u);
419
+ #else
420
+ return __popcnt(u >> 32) + __popcnt((uint32_t)u);
421
+ #endif
422
+ }
423
+ #else
424
+ #error No implementation of CountLeadingZeros(), CountTrailingZeros() and PopCount() for this compiler / toolchain
425
+ #endif
426
+
427
+ // Calling memcpy (and friends) with a NULL source pointer is undefined behavior
428
+ // even if length is 0. This is dumb, work around this.
429
+ static inline void *memcpy_safe(void *dest, const void *src, size_t len)
430
+ {
431
+ if (len) {
432
+ memcpy(dest, src, len);
433
+ }
434
+ return dest;
435
+ }
436
+ static inline void *memmove_safe(void *dest, const void *src, size_t len)
437
+ {
438
+ if (len) {
439
+ memmove(dest, src, len);
440
+ }
441
+ return dest;
442
+ }
443
+ static inline void *memset_safe(void *dest, int c, size_t len)
444
+ {
445
+ if (len) {
446
+ memset(dest, c, len);
447
+ }
448
+ return dest;
449
+ }
450
+
451
+ template <typename T, typename = typename std::enable_if<std::is_enum<T>::value, T>>
452
+ typename std::underlying_type<T>::type MaskEnum(T value)
453
+ {
454
+ auto mask = 1 << static_cast<typename std::underlying_type<T>::type>(value);
455
+ return (typename std::underlying_type<T>::type)mask;
456
+ }
457
+
458
+ template <typename Fun>
459
+ class DeferGuard {
460
+ RG_DELETE_COPY(DeferGuard)
461
+
462
+ Fun f;
463
+ bool enabled;
464
+
465
+ public:
466
+ DeferGuard() = delete;
467
+ DeferGuard(Fun f_, bool enable = true) : f(std::move(f_)), enabled(enable) {}
468
+ ~DeferGuard()
469
+ {
470
+ if (enabled) {
471
+ f();
472
+ }
473
+ }
474
+
475
+ DeferGuard(DeferGuard &&other)
476
+ : f(std::move(other.f)), enabled(other.enabled)
477
+ {
478
+ other.enabled = false;
479
+ }
480
+
481
+ void Disable() { enabled = false; }
482
+ };
483
+
484
+ // Honestly, I don't understand all the details in there, this comes from Andrei Alexandrescu.
485
+ // https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C
486
+ struct DeferGuardHelper {};
487
+ template <typename Fun>
488
+ DeferGuard<Fun> operator+(DeferGuardHelper, Fun &&f)
489
+ {
490
+ return DeferGuard<Fun>(std::forward<Fun>(f));
491
+ }
492
+
493
+ // Write 'DEFER { code };' to do something at the end of the current scope, you
494
+ // can use DEFER_N(Name) if you need to disable the guard for some reason, and
495
+ // DEFER_NC(Name, Captures) if you need to capture values.
496
+ #define RG_DEFER \
497
+ auto RG_UNIQUE_NAME(defer) = RG::DeferGuardHelper() + [&]()
498
+ #define RG_DEFER_N(Name) \
499
+ auto Name = RG::DeferGuardHelper() + [&]()
500
+ #define RG_DEFER_C(...) \
501
+ auto RG_UNIQUE_NAME(defer) = RG::DeferGuardHelper() + [&, __VA_ARGS__]()
502
+ #define RG_DEFER_NC(Name, ...) \
503
+ auto Name = RG::DeferGuardHelper() + [&, __VA_ARGS__]()
504
+
505
+ // Heavily inspired from FunctionRef in LLVM
506
+ template<typename Fn> class FunctionRef;
507
+ template<typename Ret, typename ...Params>
508
+ class FunctionRef<Ret(Params...)> {
509
+ Ret (*callback)(intptr_t callable, Params ...params) = nullptr;
510
+ intptr_t callable;
511
+
512
+ template<typename Callable>
513
+ static Ret callback_fn(intptr_t callable, Params ...params)
514
+ { return (*reinterpret_cast<Callable*>(callable))(std::forward<Params>(params)...); }
515
+
516
+ public:
517
+ FunctionRef() = default;
518
+
519
+ template <typename Callable>
520
+ FunctionRef(Callable &&callable,
521
+ std::enable_if_t<!std::is_same<std::remove_cv_t<std::remove_reference_t<Callable>>, FunctionRef>::value> * = nullptr,
522
+ std::enable_if_t<std::is_void<Ret>::value ||
523
+ std::is_convertible<decltype(std::declval<Callable>()(std::declval<Params>()...)),
524
+ Ret>::value> * = nullptr)
525
+ : callback(callback_fn<typename std::remove_reference<Callable>::type>),
526
+ callable(reinterpret_cast<intptr_t>(&callable)) {}
527
+
528
+ Ret operator()(Params ...params) const
529
+ { return callback(callable, std::forward<Params>(params)...); }
530
+
531
+ bool IsValid() const { return callback; }
532
+ };
533
+
534
+ #define RG_INIT_(ClassName) \
535
+ class ClassName { \
536
+ public: \
537
+ ClassName(); \
538
+ }; \
539
+ static ClassName RG_UNIQUE_NAME(init); \
540
+ ClassName::ClassName()
541
+ #define RG_INIT(Name) RG_INIT_(RG_UNIQUE_NAME(InitHelper))
542
+
543
+ #define RG_EXIT_(ClassName) \
544
+ class ClassName { \
545
+ public: \
546
+ ~ClassName(); \
547
+ }; \
548
+ static ClassName RG_UNIQUE_NAME(exit); \
549
+ ClassName::~ClassName()
550
+ #define RG_EXIT(Name) RG_EXIT_(RG_UNIQUE_NAME(ExitHelper))
551
+
552
+ template <typename T>
553
+ T MultiCmp()
554
+ {
555
+ return 0;
556
+ }
557
+ template <typename T, typename... Args>
558
+ T MultiCmp(T cmp_value, Args... other_args)
559
+ {
560
+ if (cmp_value) {
561
+ return cmp_value;
562
+ } else {
563
+ return MultiCmp<T>(other_args...);
564
+ }
565
+ }
566
+
567
+ template <typename T, typename U>
568
+ T ApplyMask(T value, U mask, bool enable)
569
+ {
570
+ if (enable) {
571
+ return value | (T)mask;
572
+ } else {
573
+ return value & (T)~mask;
574
+ }
575
+ }
576
+
577
+ enum class ParseFlag {
578
+ Log = 1 << 0,
579
+ Validate = 1 << 1,
580
+ End = 1 << 2
581
+ };
582
+ #define RG_DEFAULT_PARSE_FLAGS ((int)ParseFlag::Log | (int)ParseFlag::Validate | (int)ParseFlag::End)
583
+
584
+ template <typename T>
585
+ struct Vec2 {
586
+ T x;
587
+ T y;
588
+ };
589
+
590
+ template <typename T>
591
+ struct Vec3 {
592
+ T x;
593
+ T y;
594
+ T z;
595
+ };
596
+
597
+ // ------------------------------------------------------------------------
598
+ // Memory / Allocator
599
+ // ------------------------------------------------------------------------
600
+
601
+ class Allocator;
602
+
603
+ Allocator *GetDefaultAllocator();
604
+
605
+ class Allocator {
606
+ RG_DELETE_COPY(Allocator)
607
+
608
+ public:
609
+ enum class Flag {
610
+ Zero = 1,
611
+ Resizable = 2
612
+ };
613
+
614
+ Allocator() = default;
615
+ virtual ~Allocator() = default;
616
+
617
+ static void *Allocate(Allocator *alloc, Size size, unsigned int flags = 0)
618
+ {
619
+ RG_ASSERT(size >= 0);
620
+
621
+ if (!alloc) {
622
+ alloc = GetDefaultAllocator();
623
+ }
624
+ return alloc->Allocate(size, flags);
625
+ }
626
+
627
+ static void Resize(Allocator *alloc, void **ptr, Size old_size, Size new_size,
628
+ unsigned int flags = 0)
629
+ {
630
+ RG_ASSERT(new_size >= 0);
631
+
632
+ if (!alloc) {
633
+ alloc = GetDefaultAllocator();
634
+ }
635
+ alloc->Resize(ptr, old_size, new_size, flags);
636
+ }
637
+
638
+ static void Release(Allocator *alloc, void *ptr, Size size)
639
+ {
640
+ if (!alloc) {
641
+ alloc = GetDefaultAllocator();
642
+ }
643
+ alloc->Release(ptr, size);
644
+ }
645
+
646
+ protected:
647
+ virtual void *Allocate(Size size, unsigned int flags = 0) = 0;
648
+ virtual void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags = 0) = 0;
649
+ virtual void Release(void *ptr, Size size) = 0;
650
+ };
651
+
652
+ class LinkedAllocator final: public Allocator {
653
+ struct Node {
654
+ Node *prev;
655
+ Node *next;
656
+ };
657
+ struct Bucket {
658
+ // Keep head first or stuff will break
659
+ Node head;
660
+ alignas(8) uint8_t data[];
661
+ };
662
+
663
+ Allocator *allocator;
664
+ // We want allocators to be memmovable, which means we can't use a circular linked list.
665
+ // Even though it makes the code less nice.
666
+ Node list = {};
667
+
668
+ public:
669
+ LinkedAllocator(Allocator *alloc = nullptr) : allocator(alloc) {}
670
+ ~LinkedAllocator() override { ReleaseAll(); }
671
+
672
+ LinkedAllocator(LinkedAllocator &&other) { *this = std::move(other); }
673
+ LinkedAllocator& operator=(LinkedAllocator &&other);
674
+
675
+ void ReleaseAll();
676
+
677
+ protected:
678
+ void *Allocate(Size size, unsigned int flags = 0) override;
679
+ void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
680
+ void Release(void *ptr, Size size) override;
681
+
682
+ private:
683
+ static Bucket *PointerToBucket(void *ptr)
684
+ { return (Bucket *)((uint8_t *)ptr - RG_OFFSET_OF(Bucket, data)); }
685
+ };
686
+
687
+ class BlockAllocatorBase: public Allocator {
688
+ struct Bucket {
689
+ Size used;
690
+ alignas(8) uint8_t data[];
691
+ };
692
+
693
+ Size block_size;
694
+
695
+ Bucket *current_bucket = nullptr;
696
+ uint8_t *last_alloc = nullptr;
697
+
698
+ public:
699
+ BlockAllocatorBase(Size block_size = RG_BLOCK_ALLOCATOR_DEFAULT_SIZE)
700
+ : block_size(block_size)
701
+ {
702
+ RG_ASSERT(block_size > 0);
703
+ }
704
+
705
+ protected:
706
+ void *Allocate(Size size, unsigned int flags = 0) override;
707
+ void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
708
+ void Release(void *ptr, Size size) override;
709
+
710
+ void CopyFrom(BlockAllocatorBase *other);
711
+ void ForgetCurrentBlock();
712
+
713
+ virtual LinkedAllocator *GetAllocator() = 0;
714
+
715
+ private:
716
+ bool AllocateSeparately(Size aligned_size) const { return aligned_size >= block_size / 2; }
717
+
718
+ static Size AlignSizeValue(Size size)
719
+ { return (RG_SIZE(Bucket) + size + 7) / 8 * 8 - RG_SIZE(Bucket); }
720
+ };
721
+
722
+ class BlockAllocator final: public BlockAllocatorBase {
723
+ LinkedAllocator allocator;
724
+
725
+ protected:
726
+ LinkedAllocator *GetAllocator() override { return &allocator; }
727
+
728
+ public:
729
+ BlockAllocator(Size block_size = RG_BLOCK_ALLOCATOR_DEFAULT_SIZE)
730
+ : BlockAllocatorBase(block_size) {}
731
+
732
+ BlockAllocator(BlockAllocator &&other) { *this = std::move(other); }
733
+ BlockAllocator& operator=(BlockAllocator &&other);
734
+
735
+ void ReleaseAll();
736
+ };
737
+
738
+ class IndirectBlockAllocator final: public BlockAllocatorBase {
739
+ LinkedAllocator *allocator;
740
+
741
+ protected:
742
+ LinkedAllocator *GetAllocator() override { return allocator; }
743
+
744
+ public:
745
+ IndirectBlockAllocator(LinkedAllocator *alloc, Size block_size = RG_BLOCK_ALLOCATOR_DEFAULT_SIZE)
746
+ : BlockAllocatorBase(block_size), allocator(alloc) {}
747
+
748
+ IndirectBlockAllocator(IndirectBlockAllocator &&other) { *this = std::move(other); }
749
+ IndirectBlockAllocator& operator=(IndirectBlockAllocator &&other);
750
+
751
+ void ReleaseAll();
752
+ };
753
+
754
+ // ------------------------------------------------------------------------
755
+ // Reference counting
756
+ // ------------------------------------------------------------------------
757
+
758
+ template <typename T>
759
+ class RetainPtr {
760
+ T *p = nullptr;
761
+
762
+ public:
763
+ RetainPtr() = default;
764
+ RetainPtr(T *p, void (*delete_func)(std::remove_const_t<T> *))
765
+ : p(p)
766
+ {
767
+ RG_ASSERT(p);
768
+ RG_ASSERT(delete_func);
769
+ RG_ASSERT(!p->delete_func || delete_func == p->delete_func);
770
+
771
+ p->Ref();
772
+ p->delete_func = delete_func;
773
+ }
774
+ RetainPtr(T *p, bool ref = true)
775
+ : p(p)
776
+ {
777
+ if (p) {
778
+ RG_ASSERT(p->delete_func);
779
+
780
+ if (ref) {
781
+ p->Ref();
782
+ }
783
+ }
784
+ }
785
+
786
+ ~RetainPtr()
787
+ {
788
+ if (p && !p->Unref()) {
789
+ p->delete_func((std::remove_const_t<T> *)p);
790
+ }
791
+ }
792
+
793
+ RetainPtr(const RetainPtr &other)
794
+ {
795
+ p = other.p;
796
+ if (p) {
797
+ p->Ref();
798
+ }
799
+ }
800
+ RetainPtr &operator=(const RetainPtr &other)
801
+ {
802
+ if (p && !p->Unref()) {
803
+ p->delete_func((std::remove_const_t<T> *)p);
804
+ }
805
+
806
+ p = other.p;
807
+ if (p) {
808
+ p->Ref();
809
+ }
810
+
811
+ return *this;
812
+ }
813
+
814
+ operator RetainPtr<const T>() const
815
+ {
816
+ RetainPtr<const T> ptr((const T *)p);
817
+ return ptr;
818
+ }
819
+
820
+ bool IsValid() const { return p; }
821
+ operator bool() const { return p; }
822
+
823
+ T &operator*() const
824
+ {
825
+ RG_ASSERT(p);
826
+ return *p;
827
+ }
828
+ T *operator->() const { return p; }
829
+ T *GetRaw() const { return p; }
830
+ };
831
+
832
+ template <typename T>
833
+ class RetainObject {
834
+ mutable void (*delete_func)(T *) = nullptr;
835
+ mutable std::atomic_int refcount {0};
836
+
837
+ public:
838
+ void Ref() const { refcount++; }
839
+ bool Unref() const
840
+ {
841
+ int new_count = --refcount;
842
+ RG_ASSERT(new_count >= 0);
843
+ return new_count;
844
+ }
845
+
846
+ friend class RetainPtr<T>;
847
+ friend class RetainPtr<const T>;
848
+ };
849
+
850
+ // ------------------------------------------------------------------------
851
+ // Collections
852
+ // ------------------------------------------------------------------------
853
+
854
+ // I'd love to make Span default to { nullptr, 0 } but unfortunately that makes
855
+ // it a non-POD and prevents putting it in a union.
856
+ template <typename T>
857
+ struct Span {
858
+ T *ptr;
859
+ Size len;
860
+
861
+ Span() = default;
862
+ constexpr Span(T &value) : ptr(&value), len(1) {}
863
+ constexpr Span(std::initializer_list<T> l) : ptr(l.begin()), len((Size)l.size()) {}
864
+ constexpr Span(T *ptr_, Size len_) : ptr(ptr_), len(len_) {}
865
+ template <Size N>
866
+ constexpr Span(T (&arr)[N]) : ptr(arr), len(N) {}
867
+
868
+ void Reset()
869
+ {
870
+ ptr = nullptr;
871
+ len = 0;
872
+ }
873
+
874
+ T *begin() { return ptr; }
875
+ const T *begin() const { return ptr; }
876
+ T *end() { return ptr + len; }
877
+ const T *end() const { return ptr + len; }
878
+
879
+ bool IsValid() const { return ptr; }
880
+
881
+ T &operator[](Size idx)
882
+ {
883
+ RG_ASSERT(idx >= 0 && idx < len);
884
+ return ptr[idx];
885
+ }
886
+ const T &operator[](Size idx) const
887
+ {
888
+ RG_ASSERT(idx >= 0 && idx < len);
889
+ return ptr[idx];
890
+ }
891
+
892
+ operator Span<const T>() const { return Span<const T>(ptr, len); }
893
+
894
+ bool operator==(const Span &other) const
895
+ {
896
+ if (len != other.len)
897
+ return false;
898
+
899
+ for (Size i = 0; i < len; i++) {
900
+ if (ptr[i] != other.ptr[i])
901
+ return false;
902
+ }
903
+
904
+ return true;
905
+ }
906
+ bool operator!=(const Span &other) const { return !(*this == other); }
907
+
908
+ Span Take(Size offset, Size sub_len) const
909
+ {
910
+ RG_ASSERT(sub_len >= 0 && sub_len <= len);
911
+ RG_ASSERT(offset >= 0 && offset <= len - sub_len);
912
+
913
+ Span<T> sub;
914
+ sub.ptr = ptr + offset;
915
+ sub.len = sub_len;
916
+ return sub;
917
+ }
918
+
919
+ template <typename U>
920
+ Span<U> CastAs() const { return Span<U>((U *)ptr, len); }
921
+ };
922
+
923
+ // Use strlen() to build Span<const char> instead of the template-based
924
+ // array constructor.
925
+ template <>
926
+ struct Span<const char> {
927
+ const char *ptr;
928
+ Size len;
929
+
930
+ Span() = default;
931
+ constexpr Span(const char &ch) : ptr(&ch), len(1) {}
932
+ constexpr Span(const char *ptr_, Size len_) : ptr(ptr_), len(len_) {}
933
+ #ifdef __clang__
934
+ constexpr Span(const char *const &str) : ptr(str), len(str ? (Size)__builtin_strlen(str) : 0) {}
935
+ #else
936
+ constexpr Span(const char *const &str) : ptr(str), len(str ? (Size)strlen(str) : 0) {}
937
+ #endif
938
+
939
+ void Reset()
940
+ {
941
+ ptr = nullptr;
942
+ len = 0;
943
+ }
944
+
945
+ const char *begin() const { return ptr; }
946
+ const char *end() const { return ptr + len; }
947
+
948
+ bool IsValid() const { return ptr; }
949
+
950
+ char operator[](Size idx) const
951
+ {
952
+ RG_ASSERT(idx >= 0 && idx < len);
953
+ return ptr[idx];
954
+ }
955
+
956
+ // The implementation comes later, after TestStr() is available
957
+ bool operator==(Span<const char> other) const;
958
+ bool operator==(const char *other) const;
959
+ bool operator!=(Span<const char> other) const { return !(*this == other); }
960
+ bool operator!=(const char *other) const { return !(*this == other); }
961
+
962
+ Span Take(Size offset, Size sub_len) const
963
+ {
964
+ RG_ASSERT(sub_len >= 0 && sub_len <= len);
965
+ RG_ASSERT(offset >= 0 && offset <= len - sub_len);
966
+
967
+ Span<const char> sub;
968
+ sub.ptr = ptr + offset;
969
+ sub.len = sub_len;
970
+ return sub;
971
+ }
972
+
973
+ template <typename U>
974
+ Span<U> CastAs() const { return Span<U>((U *)ptr, len); }
975
+ };
976
+
977
+ template <typename T>
978
+ static inline constexpr Span<T> MakeSpan(T *ptr, Size len)
979
+ {
980
+ return Span<T>(ptr, len);
981
+ }
982
+ template <typename T>
983
+ static inline constexpr Span<T> MakeSpan(T *ptr, T *end)
984
+ {
985
+ return Span<T>(ptr, end - ptr);
986
+ }
987
+ template <typename T, Size N>
988
+ static inline constexpr Span<T> MakeSpan(T (&arr)[N])
989
+ {
990
+ return Span<T>(arr, N);
991
+ }
992
+
993
+ template <typename T>
994
+ class Strider {
995
+ public:
996
+ void *ptr = nullptr;
997
+ Size stride;
998
+
999
+ Strider() = default;
1000
+ constexpr Strider(T *ptr_) : ptr(ptr_), stride(RG_SIZE(T)) {}
1001
+ constexpr Strider(T *ptr_, Size stride_) : ptr(ptr_), stride(stride_) {}
1002
+
1003
+ bool IsValid() const { return ptr; }
1004
+
1005
+ T &operator[](Size idx) const
1006
+ {
1007
+ RG_ASSERT(idx >= 0);
1008
+ return *(T *)((uint8_t *)ptr + (idx * stride));
1009
+ }
1010
+ };
1011
+
1012
+ template <typename T>
1013
+ static inline constexpr Strider<T> MakeStrider(T *ptr)
1014
+ {
1015
+ return Strider<T>(ptr, RG_SIZE(T));
1016
+ }
1017
+ template <typename T>
1018
+ static inline constexpr Strider<T> MakeStrider(T *ptr, Size stride)
1019
+ {
1020
+ return Strider<T>(ptr, stride);
1021
+ }
1022
+ template <typename T, Size N>
1023
+ static inline constexpr Strider<T> MakeStrider(T (&arr)[N])
1024
+ {
1025
+ return Strider<T>(arr, RG_SIZE(T));
1026
+ }
1027
+
1028
+ template <typename T, Size N, Size AlignAs = alignof(T)>
1029
+ class LocalArray {
1030
+ public:
1031
+ alignas(AlignAs) T data[N];
1032
+ Size len = 0;
1033
+
1034
+ typedef T value_type;
1035
+ typedef T *iterator_type;
1036
+
1037
+ LocalArray() = default;
1038
+ LocalArray(std::initializer_list<T> l)
1039
+ {
1040
+ RG_ASSERT(l.size() <= N);
1041
+ for (const T &it: l) {
1042
+ data[len++] = it;
1043
+ }
1044
+ len = (Size)l.size();
1045
+ }
1046
+
1047
+ void Clear()
1048
+ {
1049
+ for (Size i = 0; i < len; i++) {
1050
+ data[i] = T();
1051
+ }
1052
+ len = 0;
1053
+ }
1054
+
1055
+ operator Span<T>() { return Span<T>(data, len); }
1056
+ operator Span<const T>() const { return Span<const T>(data, len); }
1057
+
1058
+ T *begin() { return data; }
1059
+ const T *begin() const { return data; }
1060
+ T *end() { return data + len; }
1061
+ const T *end() const { return data + len; }
1062
+
1063
+ Size Available() const { return RG_LEN(data) - len; }
1064
+
1065
+ T &operator[](Size idx)
1066
+ {
1067
+ RG_ASSERT(idx >= 0 && idx < len);
1068
+ return data[idx];
1069
+ }
1070
+ const T &operator[](Size idx) const
1071
+ {
1072
+ RG_ASSERT(idx >= 0 && idx < len);
1073
+ return data[idx];
1074
+ }
1075
+
1076
+ bool operator==(const LocalArray &other) const
1077
+ {
1078
+ if (len != other.len)
1079
+ return false;
1080
+
1081
+ for (Size i = 0; i < len; i++) {
1082
+ if (data[i] != other.data[i])
1083
+ return false;
1084
+ }
1085
+
1086
+ return true;
1087
+ }
1088
+ bool operator!=(const LocalArray &other) const { return !(*this == other); }
1089
+
1090
+ T *AppendDefault(Size count = 1)
1091
+ {
1092
+ RG_ASSERT(len <= N - count);
1093
+
1094
+ T *it = data + len;
1095
+ *it = {};
1096
+ len += count;
1097
+
1098
+ return it;
1099
+ }
1100
+
1101
+ T *Append(const T &value)
1102
+ {
1103
+ RG_ASSERT(len < N);
1104
+
1105
+ T *it = data + len;
1106
+ *it = value;
1107
+ len++;
1108
+
1109
+ return it;
1110
+ }
1111
+ T *Append(Span<const T> values)
1112
+ {
1113
+ RG_ASSERT(values.len <= N - len);
1114
+
1115
+ T *it = data + len;
1116
+ for (Size i = 0; i < values.len; i++) {
1117
+ data[len + i] = values[i];
1118
+ }
1119
+ len += values.len;
1120
+
1121
+ return it;
1122
+ }
1123
+
1124
+ void RemoveFrom(Size first)
1125
+ {
1126
+ RG_ASSERT(first >= 0 && first <= len);
1127
+
1128
+ for (Size i = first; i < len; i++) {
1129
+ data[i] = T();
1130
+ }
1131
+ len = first;
1132
+ }
1133
+ void RemoveLast(Size count = 1)
1134
+ {
1135
+ RG_ASSERT(count >= 0 && count <= len);
1136
+ RemoveFrom(len - count);
1137
+ }
1138
+
1139
+ Span<T> Take() const { return Span<T>(data, len); }
1140
+ Span<T> Take(Size offset, Size len) const { return Span<T>((T *)data, N).Take(offset, len); }
1141
+ Span<T> TakeAvailable() const { return Span<T>((T *)data + len, N - len); }
1142
+ };
1143
+
1144
+ template <typename T>
1145
+ class HeapArray {
1146
+ // StaticAssert(std::is_trivially_copyable<T>::value);
1147
+
1148
+ public:
1149
+ T *ptr = nullptr;
1150
+ Size len = 0;
1151
+ Size capacity = 0;
1152
+ Allocator *allocator = nullptr;
1153
+
1154
+ typedef T value_type;
1155
+ typedef T *iterator_type;
1156
+
1157
+ HeapArray() = default;
1158
+ HeapArray(Allocator *alloc, Size min_capacity = 0) : allocator(alloc)
1159
+ { SetCapacity(min_capacity); }
1160
+ HeapArray(Size min_capacity) { Reserve(min_capacity); }
1161
+ HeapArray(std::initializer_list<T> l)
1162
+ {
1163
+ Reserve(l.size());
1164
+ for (const T &it: l) {
1165
+ ptr[len++] = it;
1166
+ }
1167
+ }
1168
+ ~HeapArray() { Clear(); }
1169
+
1170
+ HeapArray(HeapArray &&other) { *this = std::move(other); }
1171
+ HeapArray &operator=(HeapArray &&other)
1172
+ {
1173
+ Clear();
1174
+ memmove_safe(this, &other, RG_SIZE(other));
1175
+ memset_safe(&other, 0, RG_SIZE(other));
1176
+ return *this;
1177
+ }
1178
+ HeapArray(const HeapArray &other) { *this = other; }
1179
+ HeapArray &operator=(const HeapArray &other)
1180
+ {
1181
+ RemoveFrom(0);
1182
+ Grow(other.capacity);
1183
+ if constexpr(!std::is_trivial<T>::value) {
1184
+ for (Size i = 0; i < other.len; i++) {
1185
+ ptr[i] = other.ptr[i];
1186
+ }
1187
+ } else {
1188
+ memcpy_safe(ptr, other.ptr, (size_t)(other.len * RG_SIZE(*ptr)));
1189
+ }
1190
+ len = other.len;
1191
+ return *this;
1192
+ }
1193
+
1194
+ void Clear()
1195
+ {
1196
+ RemoveFrom(0);
1197
+ SetCapacity(0);
1198
+ }
1199
+
1200
+ operator Span<T>() { return Span<T>(ptr, len); }
1201
+ operator Span<const T>() const { return Span<const T>(ptr, len); }
1202
+
1203
+ T *begin() { return ptr; }
1204
+ const T *begin() const { return ptr; }
1205
+ T *end() { return ptr + len; }
1206
+ const T *end() const { return ptr + len; }
1207
+
1208
+ Size Available() const { return capacity - len; }
1209
+
1210
+ T &operator[](Size idx)
1211
+ {
1212
+ RG_ASSERT(idx >= 0 && idx < len);
1213
+ return ptr[idx];
1214
+ }
1215
+ const T &operator[](Size idx) const
1216
+ {
1217
+ RG_ASSERT(idx >= 0 && idx < len);
1218
+ return ptr[idx];
1219
+ }
1220
+
1221
+ bool operator==(const HeapArray &other) const
1222
+ {
1223
+ if (len != other.len)
1224
+ return false;
1225
+
1226
+ for (Size i = 0; i < len; i++) {
1227
+ if (ptr[i] != other.ptr[i])
1228
+ return false;
1229
+ }
1230
+
1231
+ return true;
1232
+ }
1233
+ bool operator!=(const HeapArray &other) const { return !(*this == other); }
1234
+
1235
+ void SetCapacity(Size new_capacity)
1236
+ {
1237
+ RG_ASSERT(new_capacity >= 0);
1238
+
1239
+ if (new_capacity != capacity) {
1240
+ if (len > new_capacity) {
1241
+ for (Size i = new_capacity; i < len; i++) {
1242
+ ptr[i].~T();
1243
+ }
1244
+ len = new_capacity;
1245
+ }
1246
+
1247
+ Allocator::Resize(allocator, (void **)&ptr,
1248
+ capacity * RG_SIZE(T), new_capacity * RG_SIZE(T));
1249
+ capacity = new_capacity;
1250
+ }
1251
+ }
1252
+
1253
+ void Reserve(Size min_capacity)
1254
+ {
1255
+ if (min_capacity > capacity) {
1256
+ SetCapacity(min_capacity);
1257
+ }
1258
+ }
1259
+
1260
+ void Grow(Size reserve_capacity = 1)
1261
+ {
1262
+ RG_ASSERT(capacity >= 0);
1263
+ RG_ASSERT(reserve_capacity >= 0);
1264
+ RG_ASSERT((size_t)capacity + (size_t)reserve_capacity <= RG_SIZE_MAX);
1265
+
1266
+ if (reserve_capacity > capacity - len) {
1267
+ Size needed = capacity + reserve_capacity;
1268
+
1269
+ Size new_capacity;
1270
+ if (needed <= RG_HEAPARRAY_BASE_CAPACITY) {
1271
+ new_capacity = RG_HEAPARRAY_BASE_CAPACITY;
1272
+ } else {
1273
+ new_capacity = (Size)((double)(needed - 1) * RG_HEAPARRAY_GROWTH_FACTOR);
1274
+ }
1275
+
1276
+ SetCapacity(new_capacity);
1277
+ }
1278
+ }
1279
+
1280
+ void Trim(Size extra_capacity = 0) { SetCapacity(len + extra_capacity); }
1281
+
1282
+ T *AppendDefault(Size count = 1)
1283
+ {
1284
+ Grow(count);
1285
+
1286
+ T *first = ptr + len;
1287
+ if constexpr(!std::is_trivial<T>::value) {
1288
+ for (Size i = 0; i < count; i++) {
1289
+ new (ptr + len) T();
1290
+ len++;
1291
+ }
1292
+ } else {
1293
+ memset_safe(first, 0, count * RG_SIZE(T));
1294
+ len += count;
1295
+ }
1296
+ return first;
1297
+ }
1298
+
1299
+ T *Append(const T &value)
1300
+ {
1301
+ Grow();
1302
+
1303
+ T *first = ptr + len;
1304
+ if constexpr(!std::is_trivial<T>::value) {
1305
+ new (ptr + len) T;
1306
+ }
1307
+ ptr[len++] = value;
1308
+ return first;
1309
+ }
1310
+ T *Append(Span<const T> values)
1311
+ {
1312
+ Grow(values.len);
1313
+
1314
+ T *first = ptr + len;
1315
+ for (const T &value: values) {
1316
+ if constexpr(!std::is_trivial<T>::value) {
1317
+ new (ptr + len) T;
1318
+ }
1319
+ ptr[len++] = value;
1320
+ }
1321
+ return first;
1322
+ }
1323
+
1324
+ void RemoveFrom(Size first)
1325
+ {
1326
+ RG_ASSERT(first >= 0 && first <= len);
1327
+
1328
+ if constexpr(!std::is_trivial<T>::value) {
1329
+ for (Size i = first; i < len; i++) {
1330
+ ptr[i].~T();
1331
+ }
1332
+ }
1333
+ len = first;
1334
+ }
1335
+ void RemoveLast(Size count = 1)
1336
+ {
1337
+ RG_ASSERT(count >= 0 && count <= len);
1338
+ RemoveFrom(len - count);
1339
+ }
1340
+
1341
+ Span<T> Take() const { return Span<T>(ptr, len); }
1342
+ Span<T> Take(Size offset, Size len) const { return Span<T>(ptr, this->len).Take(offset, len); }
1343
+
1344
+ Span<T> Leak()
1345
+ {
1346
+ Span<T> span = *this;
1347
+
1348
+ ptr = nullptr;
1349
+ len = 0;
1350
+ capacity = 0;
1351
+
1352
+ return span;
1353
+ }
1354
+ Span<T> TrimAndLeak(Size extra_capacity = 0)
1355
+ {
1356
+ Trim(extra_capacity);
1357
+ return Leak();
1358
+ }
1359
+ };
1360
+
1361
+ template <typename T, Size BucketSize = 64, typename AllocatorType = BlockAllocator>
1362
+ class BucketArray {
1363
+ RG_DELETE_COPY(BucketArray)
1364
+
1365
+ public:
1366
+ struct Bucket {
1367
+ T *values;
1368
+ AllocatorType allocator;
1369
+ };
1370
+
1371
+ template <typename U>
1372
+ class Iterator {
1373
+ public:
1374
+ typedef std::bidirectional_iterator_tag iterator_category;
1375
+ typedef Size value_type;
1376
+ typedef Size difference_type;
1377
+ typedef Iterator *pointer;
1378
+ typedef Iterator &reference;
1379
+
1380
+ U *queue = nullptr;
1381
+ Size bucket_idx;
1382
+ Size bucket_offset;
1383
+ Bucket *bucket;
1384
+ Bucket *next_bucket;
1385
+
1386
+ Iterator() = default;
1387
+ Iterator(U *queue, Size bucket_idx, Size bucket_offset)
1388
+ : queue(queue), bucket_idx(bucket_idx), bucket_offset(bucket_offset),
1389
+ bucket(GetBucketSafe(bucket_idx)), next_bucket(GetBucketSafe(bucket_idx + 1)) {}
1390
+
1391
+ T *operator->() { return &bucket->values[bucket_offset]; }
1392
+ const T *operator->() const { return &bucket->values[bucket_offset]; }
1393
+ T &operator*() { return bucket->values[bucket_offset]; }
1394
+ const T &operator*() const { return bucket->values[bucket_offset]; }
1395
+
1396
+ Iterator &operator++()
1397
+ {
1398
+ if (++bucket_offset >= BucketSize) {
1399
+ bucket_idx++;
1400
+ if (next_bucket) {
1401
+ // We support deletion of all values up to (and including) the current one.
1402
+ // When the user does that, some or all front buckets may be gone, but we can
1403
+ // use next_bucket to fix bucket_idx.
1404
+ while (bucket_idx >= queue->buckets.len ||
1405
+ queue->buckets[bucket_idx] != next_bucket) {
1406
+ bucket_idx--;
1407
+ }
1408
+ }
1409
+ bucket_offset = 0;
1410
+
1411
+ bucket = GetBucketSafe(bucket_idx);
1412
+ next_bucket = GetBucketSafe(bucket_idx + 1);
1413
+ }
1414
+
1415
+ return *this;
1416
+ }
1417
+ Iterator operator++(int)
1418
+ {
1419
+ Iterator ret = *this;
1420
+ ++(*this);
1421
+ return ret;
1422
+ }
1423
+
1424
+ Iterator &operator--()
1425
+ {
1426
+ if (--bucket_offset < 0) {
1427
+ RG_ASSERT(bucket_idx > 0);
1428
+
1429
+ bucket_idx--;
1430
+ bucket_offset = BucketSize - 1;
1431
+
1432
+ bucket = GetBucketSafe(bucket_idx);
1433
+ next_bucket = GetBucketSafe(bucket_idx + 1);
1434
+ }
1435
+
1436
+ return *this;
1437
+ }
1438
+ Iterator operator--(int)
1439
+ {
1440
+ Iterator ret = *this;
1441
+ --(*this);
1442
+ return ret;
1443
+ }
1444
+
1445
+ bool operator==(const Iterator &other) const
1446
+ { return queue == other.queue && bucket == other.bucket &&
1447
+ bucket_offset == other.bucket_offset; }
1448
+ bool operator!=(const Iterator &other) const { return !(*this == other); }
1449
+
1450
+ private:
1451
+ Bucket *GetBucketSafe(Size idx)
1452
+ { return idx < queue->buckets.len ? queue->buckets[idx] : nullptr; }
1453
+ };
1454
+
1455
+ HeapArray<Bucket *> buckets;
1456
+ Size offset = 0;
1457
+ Size len = 0;
1458
+
1459
+ typedef T value_type;
1460
+ typedef Iterator<BucketArray> iterator_type;
1461
+
1462
+ BucketArray() {}
1463
+ BucketArray(std::initializer_list<T> l)
1464
+ {
1465
+ for (const T &value: l) {
1466
+ Append(value);
1467
+ }
1468
+ }
1469
+ ~BucketArray() { ClearBucketsAndValues(); }
1470
+
1471
+ BucketArray(BucketArray &&other) { *this = std::move(other); }
1472
+ BucketArray &operator=(BucketArray &&other)
1473
+ {
1474
+ ClearBucketsAndValues();
1475
+ memmove_safe(this, &other, RG_SIZE(other));
1476
+ memset_safe(&other, 0, RG_SIZE(other));
1477
+ return *this;
1478
+ }
1479
+
1480
+ void Clear()
1481
+ {
1482
+ ClearBucketsAndValues();
1483
+
1484
+ offset = 0;
1485
+ len = 0;
1486
+ }
1487
+
1488
+ iterator_type begin() { return iterator_type(this, 0, offset); }
1489
+ Iterator<const BucketArray<T, BucketSize>> begin() const { return Iterator<const BucketArray>(this, 0, offset); }
1490
+ iterator_type end()
1491
+ {
1492
+ Size end_idx = offset + len;
1493
+ Size bucket_idx = end_idx / BucketSize;
1494
+ Size bucket_offset = end_idx % BucketSize;
1495
+
1496
+ return iterator_type(this, bucket_idx, bucket_offset);
1497
+ }
1498
+ Iterator<const BucketArray<T, BucketSize>> end() const
1499
+ {
1500
+ Size end_idx = offset + len;
1501
+ Size bucket_idx = end_idx / BucketSize;
1502
+ Size bucket_offset = end_idx % BucketSize;
1503
+
1504
+ return Iterator<const BucketArray>(this, bucket_idx, bucket_offset);
1505
+ }
1506
+
1507
+ const T &operator[](Size idx) const
1508
+ {
1509
+ RG_ASSERT(idx >= 0 && idx < len);
1510
+
1511
+ idx += offset;
1512
+ Size bucket_idx = idx / BucketSize;
1513
+ Size bucket_offset = idx % BucketSize;
1514
+
1515
+ return buckets[bucket_idx]->values[bucket_offset];
1516
+ }
1517
+ T &operator[](Size idx) { return (T &)(*(const BucketArray *)this)[idx]; }
1518
+
1519
+ T *AppendDefault(Allocator **out_alloc = nullptr)
1520
+ {
1521
+ Size bucket_idx = (offset + len) / BucketSize;
1522
+ Size bucket_offset = (offset + len) % BucketSize;
1523
+
1524
+ if (bucket_idx >= buckets.len) {
1525
+ Bucket *new_bucket = (Bucket *)Allocator::Allocate(buckets.allocator, RG_SIZE(Bucket));
1526
+ new (&new_bucket->allocator) AllocatorType();
1527
+ new_bucket->values = (T *)Allocator::Allocate(&new_bucket->allocator, BucketSize * RG_SIZE(T));
1528
+
1529
+ buckets.Append(new_bucket);
1530
+ }
1531
+
1532
+ T *first = buckets[bucket_idx]->values + bucket_offset;
1533
+ new (first) T();
1534
+
1535
+ len++;
1536
+
1537
+ if (out_alloc) {
1538
+ *out_alloc = &buckets[bucket_idx]->allocator;
1539
+ }
1540
+ return first;
1541
+ }
1542
+
1543
+ T *Append(const T &value, Allocator **out_alloc = nullptr)
1544
+ {
1545
+ T *it = AppendDefault(out_alloc);
1546
+ *it = value;
1547
+ return it;
1548
+ }
1549
+
1550
+ void RemoveFrom(Size from)
1551
+ {
1552
+ RG_ASSERT(from >= 0 && from <= len);
1553
+
1554
+ if (from == len)
1555
+ return;
1556
+ if (!from) {
1557
+ Clear();
1558
+ return;
1559
+ }
1560
+
1561
+ Size start_idx = offset + from;
1562
+ Size start_bucket_idx = start_idx / BucketSize;
1563
+ Size start_bucket_offset = start_idx % BucketSize;
1564
+
1565
+ iterator_type from_it(this, start_bucket_idx, start_bucket_offset);
1566
+ DeleteValues(from_it, end());
1567
+
1568
+ Size delete_idx = start_bucket_idx + !!start_bucket_offset;
1569
+ for (Size i = delete_idx; i < buckets.len; i++) {
1570
+ DeleteBucket(buckets[i]);
1571
+ }
1572
+ buckets.RemoveFrom(delete_idx);
1573
+
1574
+ len = from;
1575
+ }
1576
+ void RemoveLast(Size count = 1)
1577
+ {
1578
+ RG_ASSERT(count >= 0 && count <= len);
1579
+ RemoveFrom(len - count);
1580
+ }
1581
+
1582
+ void RemoveFirst(Size count = 1)
1583
+ {
1584
+ RG_ASSERT(count >= 0 && count <= len);
1585
+
1586
+ if (count == len) {
1587
+ Clear();
1588
+ return;
1589
+ }
1590
+
1591
+ Size end_idx = offset + count;
1592
+ Size end_bucket_idx = end_idx / BucketSize;
1593
+ Size end_bucket_offset = end_idx % BucketSize;
1594
+
1595
+ iterator_type until_it(this, end_bucket_idx, end_bucket_offset);
1596
+ DeleteValues(begin(), until_it);
1597
+
1598
+ if (end_bucket_idx) {
1599
+ for (Size i = 0; i < end_bucket_idx; i++) {
1600
+ DeleteBucket(buckets[i]);
1601
+ }
1602
+ memmove_safe(&buckets[0], &buckets[end_bucket_idx],
1603
+ (size_t)((buckets.len - end_bucket_idx) * RG_SIZE(Bucket *)));
1604
+ buckets.RemoveLast(end_bucket_idx);
1605
+ }
1606
+
1607
+ offset = (offset + count) % BucketSize;
1608
+ len -= count;
1609
+ }
1610
+
1611
+ void Trim()
1612
+ {
1613
+ buckets.Trim();
1614
+ }
1615
+
1616
+ private:
1617
+ void ClearBucketsAndValues()
1618
+ {
1619
+ DeleteValues(begin(), end());
1620
+
1621
+ for (Bucket *bucket: buckets) {
1622
+ DeleteBucket(bucket);
1623
+ }
1624
+ buckets.Clear();
1625
+ }
1626
+
1627
+ void DeleteValues([[maybe_unused]] iterator_type begin,
1628
+ [[maybe_unused]] iterator_type end)
1629
+ {
1630
+ if constexpr(!std::is_trivial<T>::value) {
1631
+ for (iterator_type it = begin; it != end; ++it) {
1632
+ it->~T();
1633
+ }
1634
+ }
1635
+ }
1636
+
1637
+ void DeleteBucket(Bucket *bucket)
1638
+ {
1639
+ bucket->allocator.~AllocatorType();
1640
+ Allocator::Release(buckets.allocator, bucket, RG_SIZE(Bucket));
1641
+ }
1642
+ };
1643
+
1644
+ template <Size N>
1645
+ class Bitset {
1646
+ public:
1647
+ template <typename T>
1648
+ class Iterator {
1649
+ public:
1650
+ typedef std::input_iterator_tag iterator_category;
1651
+ typedef Size value_type;
1652
+ typedef Size difference_type;
1653
+ typedef Iterator *pointer;
1654
+ typedef Iterator &reference;
1655
+
1656
+ T *bitset = nullptr;
1657
+ Size offset;
1658
+ size_t bits = 0;
1659
+ int ctz;
1660
+
1661
+ Iterator() = default;
1662
+ Iterator(T *bitset, Size offset)
1663
+ : bitset(bitset), offset(offset - 1)
1664
+ {
1665
+ operator++();
1666
+ }
1667
+
1668
+ Size operator*() const
1669
+ {
1670
+ RG_ASSERT(offset <= RG_LEN(bitset->data));
1671
+
1672
+ if (offset == RG_LEN(bitset->data))
1673
+ return -1;
1674
+ return offset * RG_SIZE(size_t) * 8 + ctz;
1675
+ }
1676
+
1677
+ Iterator &operator++()
1678
+ {
1679
+ RG_ASSERT(offset <= RG_LEN(bitset->data));
1680
+
1681
+ while (!bits) {
1682
+ if (offset == RG_LEN(bitset->data) - 1)
1683
+ return *this;
1684
+ bits = bitset->data[++offset];
1685
+ }
1686
+
1687
+ ctz = CountTrailingZeros((uint64_t)bits);
1688
+ bits ^= (size_t)1 << ctz;
1689
+
1690
+ return *this;
1691
+ }
1692
+
1693
+ Iterator operator++(int)
1694
+ {
1695
+ Iterator ret = *this;
1696
+ ++(*this);
1697
+ return ret;
1698
+ }
1699
+
1700
+ bool operator==(const Iterator &other) const
1701
+ { return bitset == other.bitset && offset == other.offset; }
1702
+ bool operator!=(const Iterator &other) const { return !(*this == other); }
1703
+ };
1704
+
1705
+ typedef Size value_type;
1706
+ typedef Iterator<Bitset> iterator_type;
1707
+
1708
+ static constexpr Size Bits = N;
1709
+ size_t data[(N + RG_SIZE(size_t) - 1) / RG_SIZE(size_t)] = {};
1710
+
1711
+ void Clear()
1712
+ {
1713
+ memset_safe(data, 0, RG_SIZE(data));
1714
+ }
1715
+
1716
+ Iterator<Bitset> begin() { return Iterator<Bitset>(this, 0); }
1717
+ Iterator<const Bitset> begin() const { return Iterator<const Bitset>(this, 0); }
1718
+ Iterator<Bitset> end() { return Iterator<Bitset>(this, RG_LEN(data)); }
1719
+ Iterator<const Bitset> end() const { return Iterator<const Bitset>(this, RG_LEN(data)); }
1720
+
1721
+ Size PopCount() const
1722
+ {
1723
+ Size count = 0;
1724
+ for (size_t bits: data) {
1725
+ #if RG_SIZE_MAX == INT64_MAX
1726
+ count += RG::PopCount((uint64_t)bits);
1727
+ #else
1728
+ count += RG::PopCount((uint32_t)bits);
1729
+ #endif
1730
+ }
1731
+ return count;
1732
+ }
1733
+
1734
+ inline bool Test(Size idx) const
1735
+ {
1736
+ RG_ASSERT(idx >= 0 && idx < N);
1737
+
1738
+ Size offset = idx / (RG_SIZE(size_t) * 8);
1739
+ size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
1740
+
1741
+ return data[offset] & mask;
1742
+ }
1743
+ inline void Set(Size idx, bool value = true)
1744
+ {
1745
+ RG_ASSERT(idx >= 0 && idx < N);
1746
+
1747
+ Size offset = idx / (RG_SIZE(size_t) * 8);
1748
+ size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
1749
+
1750
+ data[offset] = ApplyMask(data[offset], mask, value);
1751
+ }
1752
+ inline bool TestAndSet(Size idx, bool value = true)
1753
+ {
1754
+ RG_ASSERT(idx >= 0 && idx < N);
1755
+
1756
+ Size offset = idx / (RG_SIZE(size_t) * 8);
1757
+ size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
1758
+
1759
+ bool ret = data[offset] & mask;
1760
+ data[offset] = ApplyMask(data[offset], mask, value);
1761
+
1762
+ return ret;
1763
+ }
1764
+
1765
+ Bitset &operator&=(const Bitset &other)
1766
+ {
1767
+ for (Size i = 0; i < RG_LEN(data); i++) {
1768
+ data[i] &= other.data[i];
1769
+ }
1770
+ return *this;
1771
+ }
1772
+ Bitset operator&(const Bitset &other)
1773
+ {
1774
+ Bitset ret;
1775
+ for (Size i = 0; i < RG_LEN(data); i++) {
1776
+ ret.data[i] = data[i] & other.data[i];
1777
+ }
1778
+ return ret;
1779
+ }
1780
+
1781
+ Bitset &operator|=(const Bitset &other)
1782
+ {
1783
+ for (Size i = 0; i < RG_LEN(data); i++) {
1784
+ data[i] |= other.data[i];
1785
+ }
1786
+ return *this;
1787
+ }
1788
+ Bitset operator|(const Bitset &other)
1789
+ {
1790
+ Bitset ret;
1791
+ for (Size i = 0; i < RG_LEN(data); i++) {
1792
+ ret.data[i] = data[i] | other.data[i];
1793
+ }
1794
+ return ret;
1795
+ }
1796
+
1797
+ Bitset &operator^=(const Bitset &other)
1798
+ {
1799
+ for (Size i = 0; i < RG_LEN(data); i++) {
1800
+ data[i] ^= other.data[i];
1801
+ }
1802
+ return *this;
1803
+ }
1804
+ Bitset operator^(const Bitset &other)
1805
+ {
1806
+ Bitset ret;
1807
+ for (Size i = 0; i < RG_LEN(data); i++) {
1808
+ ret.data[i] = data[i] ^ other.data[i];
1809
+ }
1810
+ return ret;
1811
+ }
1812
+
1813
+ Bitset &Flip()
1814
+ {
1815
+ for (Size i = 0; i < RG_LEN(data); i++) {
1816
+ data[i] = ~data[i];
1817
+ }
1818
+ return *this;
1819
+ }
1820
+ Bitset operator~()
1821
+ {
1822
+ Bitset ret;
1823
+ for (Size i = 0; i < RG_LEN(data); i++) {
1824
+ ret.data[i] = ~data[i];
1825
+ }
1826
+ return ret;
1827
+ }
1828
+
1829
+ // XXX: Shift operators
1830
+ };
1831
+
1832
+ template <typename KeyType, typename ValueType,
1833
+ typename Handler = typename std::remove_pointer<ValueType>::type::HashHandler>
1834
+ class HashTable {
1835
+ public:
1836
+ template <typename T>
1837
+ class Iterator {
1838
+ public:
1839
+ typedef std::forward_iterator_tag iterator_category;
1840
+ typedef ValueType value_type;
1841
+ typedef Size difference_type;
1842
+ typedef Iterator *pointer;
1843
+ typedef Iterator &reference;
1844
+
1845
+ T *table = nullptr;
1846
+ Size offset;
1847
+
1848
+ Iterator() = default;
1849
+ Iterator(T *table, Size offset)
1850
+ : table(table), offset(offset - 1) { operator++(); }
1851
+
1852
+ ValueType &operator*()
1853
+ {
1854
+ RG_ASSERT(!table->IsEmpty(offset));
1855
+ return table->data[offset];
1856
+ }
1857
+ const ValueType &operator*() const
1858
+ {
1859
+ RG_ASSERT(!table->IsEmpty(offset));
1860
+ return table->data[offset];
1861
+ }
1862
+
1863
+ Iterator &operator++()
1864
+ {
1865
+ RG_ASSERT(offset < table->capacity);
1866
+ while (++offset < table->capacity && table->IsEmpty(offset));
1867
+ return *this;
1868
+ }
1869
+
1870
+ Iterator operator++(int)
1871
+ {
1872
+ Iterator ret = *this;
1873
+ ++(*this);
1874
+ return ret;
1875
+ }
1876
+
1877
+ // Beware, in some cases a previous value may be seen again after this action
1878
+ void Remove()
1879
+ {
1880
+ table->Remove(&table->data[offset]);
1881
+ offset--;
1882
+ }
1883
+
1884
+ bool operator==(const Iterator &other) const
1885
+ { return table == other.table && offset == other.offset; }
1886
+ bool operator!=(const Iterator &other) const { return !(*this == other); }
1887
+ };
1888
+
1889
+ typedef Size value_type;
1890
+ typedef Iterator<HashTable> iterator_type;
1891
+
1892
+ size_t *used = nullptr;
1893
+ ValueType *data = nullptr;
1894
+ Size count = 0;
1895
+ Size capacity = 0;
1896
+ Allocator *allocator = nullptr;
1897
+
1898
+ HashTable() = default;
1899
+ HashTable(std::initializer_list<ValueType> l)
1900
+ {
1901
+ for (const ValueType &value: l) {
1902
+ Set(value);
1903
+ }
1904
+ }
1905
+ ~HashTable()
1906
+ {
1907
+ if constexpr(std::is_trivial<ValueType>::value) {
1908
+ count = 0;
1909
+ Rehash(0);
1910
+ } else {
1911
+ Clear();
1912
+ }
1913
+ }
1914
+
1915
+ HashTable(HashTable &&other) { *this = std::move(other); }
1916
+ HashTable &operator=(HashTable &&other)
1917
+ {
1918
+ Clear();
1919
+ memmove_safe(this, &other, RG_SIZE(other));
1920
+ memset_safe(&other, 0, RG_SIZE(other));
1921
+ return *this;
1922
+ }
1923
+ HashTable(const HashTable &other) { *this = other; }
1924
+ HashTable &operator=(const HashTable &other)
1925
+ {
1926
+ Clear();
1927
+ for (const ValueType &value: other) {
1928
+ Set(value);
1929
+ }
1930
+ return *this;
1931
+ }
1932
+
1933
+ void Clear()
1934
+ {
1935
+ for (Size i = 0; i < capacity; i++) {
1936
+ if (!IsEmpty(i)) {
1937
+ data[i].~ValueType();
1938
+ }
1939
+ }
1940
+
1941
+ count = 0;
1942
+ Rehash(0);
1943
+ }
1944
+
1945
+ void RemoveAll()
1946
+ {
1947
+ RG_STATIC_ASSERT(!std::is_pointer<ValueType>::value);
1948
+
1949
+ for (Size i = 0; i < capacity; i++) {
1950
+ if (!IsEmpty(i)) {
1951
+ data[i].~ValueType();
1952
+ }
1953
+ }
1954
+
1955
+ count = 0;
1956
+ if (used) {
1957
+ size_t len = (size_t)(capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t);
1958
+ memset_safe(used, 0, len);
1959
+ }
1960
+ }
1961
+
1962
+ Iterator<HashTable> begin() { return Iterator<HashTable>(this, 0); }
1963
+ Iterator<const HashTable> begin() const { return Iterator<const HashTable>(this, 0); }
1964
+ Iterator<HashTable> end() { return Iterator<HashTable>(this, capacity); }
1965
+ Iterator<const HashTable> end() const { return Iterator<const HashTable>(this, capacity); }
1966
+
1967
+ ValueType *Find(const KeyType &key)
1968
+ { return (ValueType *)((const HashTable *)this)->Find(key); }
1969
+ const ValueType *Find(const KeyType &key) const
1970
+ {
1971
+ if (!capacity)
1972
+ return nullptr;
1973
+
1974
+ uint64_t hash = Handler::HashKey(key);
1975
+ Size idx = HashToIndex(hash);
1976
+ return Find(&idx, key);
1977
+ }
1978
+ ValueType FindValue(const KeyType &key, const ValueType &default_value)
1979
+ { return (ValueType)((const HashTable *)this)->FindValue(key, default_value); }
1980
+ const ValueType FindValue(const KeyType &key, const ValueType &default_value) const
1981
+ {
1982
+ const ValueType *it = Find(key);
1983
+ return it ? *it : default_value;
1984
+ }
1985
+
1986
+ ValueType *Set(const ValueType &value)
1987
+ {
1988
+ const KeyType &key = Handler::GetKey(value);
1989
+ ValueType *it = Insert(key).first;
1990
+ *it = value;
1991
+ return it;
1992
+ }
1993
+ ValueType *SetDefault(const KeyType &key)
1994
+ {
1995
+ std::pair<ValueType *, bool> ret = Insert(key);
1996
+ if (!ret.second) {
1997
+ ret.first->~ValueType();
1998
+ }
1999
+ new (ret.first) ValueType();
2000
+ return ret.first;
2001
+ }
2002
+
2003
+ std::pair<ValueType *, bool> TrySet(const ValueType &value)
2004
+ {
2005
+ const KeyType &key = Handler::GetKey(value);
2006
+ std::pair<ValueType *, bool> ret = Insert(key);
2007
+ if (ret.second) {
2008
+ *ret.first = value;
2009
+ }
2010
+ return ret;
2011
+ }
2012
+ std::pair<ValueType *, bool> TrySetDefault(const KeyType &key)
2013
+ {
2014
+ std::pair<ValueType *, bool> ret = Insert(key);
2015
+ if (ret.second) {
2016
+ new (ret.first) ValueType();
2017
+ }
2018
+ return ret;
2019
+ }
2020
+
2021
+ void Remove(ValueType *it)
2022
+ {
2023
+ if (!it)
2024
+ return;
2025
+
2026
+ Size empty_idx = it - data;
2027
+ RG_ASSERT(!IsEmpty(empty_idx));
2028
+
2029
+ it->~ValueType();
2030
+ count--;
2031
+
2032
+ // Move following slots if needed
2033
+ {
2034
+ Size idx = (empty_idx + 1) & (capacity - 1);
2035
+
2036
+ while (!IsEmpty(idx)) {
2037
+ Size real_idx = KeyToIndex(Handler::GetKey(data[idx]));
2038
+
2039
+ if (TestNewSlot(real_idx, empty_idx)) {
2040
+ memmove_safe(&data[empty_idx], &data[idx], RG_SIZE(*data));
2041
+ empty_idx = idx;
2042
+ }
2043
+
2044
+ idx = (idx + 1) & (capacity - 1);
2045
+ }
2046
+ }
2047
+
2048
+ MarkEmpty(empty_idx);
2049
+ new (&data[empty_idx]) ValueType();
2050
+ }
2051
+ void Remove(const KeyType &key) { Remove(Find(key)); }
2052
+
2053
+ void Trim()
2054
+ {
2055
+ if (count) {
2056
+ Size new_capacity = (Size)1 << (64 - CountLeadingZeros((uint64_t)count));
2057
+
2058
+ if (new_capacity < RG_HASHTABLE_BASE_CAPACITY) {
2059
+ new_capacity = RG_HASHTABLE_BASE_CAPACITY;
2060
+ } else if (count > (double)new_capacity * RG_HASHTABLE_MAX_LOAD_FACTOR) {
2061
+ new_capacity *= 2;
2062
+ }
2063
+
2064
+ Rehash(new_capacity);
2065
+ } else {
2066
+ Rehash(0);
2067
+ }
2068
+ }
2069
+
2070
+ Size IsEmpty(Size idx) const { return IsEmpty(used, idx); }
2071
+
2072
+ private:
2073
+ ValueType *Find(Size *idx, const KeyType &key)
2074
+ { return (ValueType *)((const HashTable *)this)->Find(idx, key); }
2075
+ const ValueType *Find(Size *idx, const KeyType &key) const
2076
+ {
2077
+ if constexpr(std::is_pointer<ValueType>::value) {
2078
+ while (data[*idx]) {
2079
+ const KeyType &it_key = Handler::GetKey(data[*idx]);
2080
+ if (Handler::TestKeys(it_key, key))
2081
+ return &data[*idx];
2082
+ *idx = (*idx + 1) & (capacity - 1);
2083
+ }
2084
+ return nullptr;
2085
+ } else {
2086
+ while (!IsEmpty(*idx)) {
2087
+ const KeyType &it_key = Handler::GetKey(data[*idx]);
2088
+ if (Handler::TestKeys(it_key, key))
2089
+ return &data[*idx];
2090
+ *idx = (*idx + 1) & (capacity - 1);
2091
+ }
2092
+ return nullptr;
2093
+ }
2094
+ }
2095
+
2096
+ std::pair<ValueType *, bool> Insert(const KeyType &key)
2097
+ {
2098
+ uint64_t hash = Handler::HashKey(key);
2099
+
2100
+ if (capacity) {
2101
+ Size idx = HashToIndex(hash);
2102
+ ValueType *it = Find(&idx, key);
2103
+ if (!it) {
2104
+ if (count >= (Size)((double)capacity * RG_HASHTABLE_MAX_LOAD_FACTOR)) {
2105
+ Rehash(capacity << 1);
2106
+ idx = HashToIndex(hash);
2107
+ while (!IsEmpty(idx)) {
2108
+ idx = (idx + 1) & (capacity - 1);
2109
+ }
2110
+ }
2111
+ count++;
2112
+ MarkUsed(idx);
2113
+ return {&data[idx], true};
2114
+ } else {
2115
+ return {it, false};
2116
+ }
2117
+ } else {
2118
+ Rehash(RG_HASHTABLE_BASE_CAPACITY);
2119
+
2120
+ Size idx = HashToIndex(hash);
2121
+ count++;
2122
+ MarkUsed(idx);
2123
+ return {&data[idx], true};
2124
+ }
2125
+ }
2126
+
2127
+ void Rehash(Size new_capacity)
2128
+ {
2129
+ if (new_capacity == capacity)
2130
+ return;
2131
+ RG_ASSERT(count <= new_capacity);
2132
+
2133
+ size_t *old_used = used;
2134
+ ValueType *old_data = data;
2135
+ Size old_capacity = capacity;
2136
+
2137
+ if (new_capacity) {
2138
+ used = (size_t *)Allocator::Allocate(allocator,
2139
+ (new_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t),
2140
+ (int)Allocator::Flag::Zero);
2141
+ data = (ValueType *)Allocator::Allocate(allocator, new_capacity * RG_SIZE(ValueType));
2142
+ for (Size i = 0; i < new_capacity; i++) {
2143
+ new (&data[i]) ValueType();
2144
+ }
2145
+ capacity = new_capacity;
2146
+
2147
+ for (Size i = 0; i < old_capacity; i++) {
2148
+ if (!IsEmpty(old_used, i)) {
2149
+ Size new_idx = KeyToIndex(Handler::GetKey(old_data[i]));
2150
+ while (!IsEmpty(new_idx)) {
2151
+ new_idx = (new_idx + 1) & (capacity - 1);
2152
+ }
2153
+ MarkUsed(new_idx);
2154
+ memmove_safe(&data[new_idx], &old_data[i], RG_SIZE(*data));
2155
+ }
2156
+ }
2157
+ } else {
2158
+ used = nullptr;
2159
+ data = nullptr;
2160
+ capacity = 0;
2161
+ }
2162
+
2163
+ Allocator::Release(allocator, old_used,
2164
+ (old_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t));
2165
+ Allocator::Release(allocator, old_data, old_capacity * RG_SIZE(ValueType));
2166
+ }
2167
+
2168
+ void MarkUsed(Size idx)
2169
+ {
2170
+ used[idx / (RG_SIZE(size_t) * 8)] |= (1ull << (idx % (RG_SIZE(size_t) * 8)));
2171
+ }
2172
+ void MarkEmpty(Size idx)
2173
+ {
2174
+ used[idx / (RG_SIZE(size_t) * 8)] &= ~(1ull << (idx % (RG_SIZE(size_t) * 8)));
2175
+ }
2176
+ Size IsEmpty(size_t *used, Size idx) const
2177
+ {
2178
+ return !(used[idx / (RG_SIZE(size_t) * 8)] & (1ull << (idx % (RG_SIZE(size_t) * 8))));
2179
+ }
2180
+
2181
+ Size HashToIndex(uint64_t hash) const
2182
+ {
2183
+ return (Size)(hash & (uint64_t)(capacity - 1));
2184
+ }
2185
+ Size KeyToIndex(const KeyType &key) const
2186
+ {
2187
+ uint64_t hash = Handler::HashKey(key);
2188
+ return HashToIndex(hash);
2189
+ }
2190
+
2191
+ // XXX: Testing all slots each time (see Remove()) is slow and stupid
2192
+ bool TestNewSlot(Size idx, Size dest_idx) const
2193
+ {
2194
+ for (;;) {
2195
+ if (idx == dest_idx) {
2196
+ return true;
2197
+ } else if (IsEmpty(idx)) {
2198
+ return false;
2199
+ }
2200
+
2201
+ idx = (idx + 1) & (capacity - 1);
2202
+ }
2203
+ }
2204
+ };
2205
+
2206
+ template <typename T>
2207
+ class HashTraits {
2208
+ public:
2209
+ static uint64_t Hash(const T &key) { return key.Hash(); }
2210
+ static bool Test(const T &key1, const T &key2) { return key1 == key2; }
2211
+ };
2212
+
2213
+ // Stole the Hash function from Thomas Wang (see here: https://gist.github.com/badboy/6267743)
2214
+ #define DEFINE_INTEGER_HASH_TRAITS_32(Type) \
2215
+ template <> \
2216
+ class HashTraits<Type> { \
2217
+ public: \
2218
+ static uint64_t Hash(Type key) \
2219
+ { \
2220
+ uint32_t hash = (uint32_t)key; \
2221
+ \
2222
+ hash = (hash ^ 61) ^ (hash >> 16); \
2223
+ hash += hash << 3; \
2224
+ hash ^= hash >> 4; \
2225
+ hash *= 0x27D4EB2D; \
2226
+ hash ^= hash >> 15; \
2227
+ \
2228
+ return (uint64_t)hash; \
2229
+ } \
2230
+ \
2231
+ static bool Test(Type key1, Type key2) { return key1 == key2; } \
2232
+ }
2233
+ #define DEFINE_INTEGER_HASH_TRAITS_64(Type) \
2234
+ template <> \
2235
+ class HashTraits<Type> { \
2236
+ public: \
2237
+ static uint64_t Hash(Type key) \
2238
+ { \
2239
+ uint64_t hash = (uint64_t)key; \
2240
+ \
2241
+ hash = (~hash) + (hash << 18); \
2242
+ hash ^= hash >> 31; \
2243
+ hash *= 21; \
2244
+ hash ^= hash >> 11; \
2245
+ hash += hash << 6; \
2246
+ hash ^= hash >> 22; \
2247
+ \
2248
+ return hash; \
2249
+ } \
2250
+ \
2251
+ static bool Test(Type key1, Type key2) { return key1 == key2; } \
2252
+ }
2253
+
2254
+ DEFINE_INTEGER_HASH_TRAITS_32(char);
2255
+ DEFINE_INTEGER_HASH_TRAITS_32(unsigned char);
2256
+ DEFINE_INTEGER_HASH_TRAITS_32(short);
2257
+ DEFINE_INTEGER_HASH_TRAITS_32(unsigned short);
2258
+ DEFINE_INTEGER_HASH_TRAITS_32(int);
2259
+ DEFINE_INTEGER_HASH_TRAITS_32(unsigned int);
2260
+ #ifdef __LP64__
2261
+ DEFINE_INTEGER_HASH_TRAITS_64(long);
2262
+ DEFINE_INTEGER_HASH_TRAITS_64(unsigned long);
2263
+ #else
2264
+ DEFINE_INTEGER_HASH_TRAITS_32(long);
2265
+ DEFINE_INTEGER_HASH_TRAITS_32(unsigned long);
2266
+ #endif
2267
+ DEFINE_INTEGER_HASH_TRAITS_64(long long);
2268
+ DEFINE_INTEGER_HASH_TRAITS_64(unsigned long long);
2269
+ #if RG_SIZE_MAX == INT64_MAX
2270
+ DEFINE_INTEGER_HASH_TRAITS_64(void *);
2271
+ DEFINE_INTEGER_HASH_TRAITS_64(const void *);
2272
+ #else
2273
+ DEFINE_INTEGER_HASH_TRAITS_32(void *);
2274
+ DEFINE_INTEGER_HASH_TRAITS_32(const void *);
2275
+ #endif
2276
+
2277
+ #undef DEFINE_INTEGER_HASH_TRAITS_32
2278
+ #undef DEFINE_INTEGER_HASH_TRAITS_64
2279
+
2280
+ template <>
2281
+ class HashTraits<const char *> {
2282
+ public:
2283
+ // FNV-1a
2284
+ static uint64_t Hash(const char *key)
2285
+ {
2286
+ uint64_t hash = 0xCBF29CE484222325ull;
2287
+ for (Size i = 0; key[i]; i++) {
2288
+ hash ^= (uint64_t)key[i];
2289
+ hash *= 0x100000001B3ull;
2290
+ }
2291
+
2292
+ return hash;
2293
+ }
2294
+
2295
+ static bool Test(const char *key1, const char *key2) { return !strcmp(key1, key2); }
2296
+ };
2297
+
2298
+ template <>
2299
+ class HashTraits<Span<const char>> {
2300
+ public:
2301
+ // FNV-1a
2302
+ static uint64_t Hash(Span<const char> key)
2303
+ {
2304
+ uint64_t hash = 0xCBF29CE484222325ull;
2305
+ for (char c: key) {
2306
+ hash ^= (uint64_t)c;
2307
+ hash *= 0x100000001B3ull;
2308
+ }
2309
+
2310
+ return hash;
2311
+ }
2312
+
2313
+ static bool Test(Span<const char> key1, Span<const char> key2) { return key1 == key2; }
2314
+ static bool Test(Span<const char> key1, const char * key2) { return key1 == key2; }
2315
+ };
2316
+
2317
+ #define RG_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
2318
+ class Name { \
2319
+ public: \
2320
+ static KeyType GetKey(const ValueType &value) \
2321
+ { return (KeyType)(value.KeyMember); } \
2322
+ static KeyType GetKey(const ValueType *value) \
2323
+ { return (KeyType)(value->KeyMember); } \
2324
+ static uint64_t HashKey(KeyType key) \
2325
+ { return HashFunc(key); } \
2326
+ static bool TestKeys(KeyType key1, KeyType key2) \
2327
+ { return TestFunc((key1), (key2)); } \
2328
+ }
2329
+ #define RG_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
2330
+ RG_HASHTABLE_HANDLER_EX_N(HashHandler, ValueType, KeyType, KeyMember, HashFunc, TestFunc)
2331
+ #define RG_HASHTABLE_HANDLER(ValueType, KeyMember) \
2332
+ RG_HASHTABLE_HANDLER_EX(ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
2333
+ #define RG_HASHTABLE_HANDLER_N(Name, ValueType, KeyMember) \
2334
+ RG_HASHTABLE_HANDLER_EX_N(Name, ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
2335
+ #define RG_HASHTABLE_HANDLER_T(ValueType, KeyType, KeyMember) \
2336
+ RG_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
2337
+ #define RG_HASHTABLE_HANDLER_NT(Name, ValueType, KeyType, KeyMember) \
2338
+ RG_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
2339
+
2340
+ template <typename KeyType, typename ValueType>
2341
+ class HashMap {
2342
+ public:
2343
+ struct Bucket {
2344
+ KeyType key;
2345
+ ValueType value;
2346
+
2347
+ RG_HASHTABLE_HANDLER(Bucket, key);
2348
+ };
2349
+
2350
+ HashTable<KeyType, Bucket> table;
2351
+
2352
+ HashMap() {}
2353
+ HashMap(std::initializer_list<Bucket> l)
2354
+ {
2355
+ for (const Bucket &bucket: l) {
2356
+ Set(bucket.key, bucket.value);
2357
+ }
2358
+ }
2359
+
2360
+ void Clear() { table.Clear(); }
2361
+ void RemoveAll() { table.RemoveAll(); }
2362
+
2363
+ ValueType *Find(const KeyType &key)
2364
+ { return (ValueType *)((const HashMap *)this)->Find(key); }
2365
+ const ValueType *Find(const KeyType &key) const
2366
+ {
2367
+ const Bucket *table_it = table.Find(key);
2368
+ return table_it ? &table_it->value : nullptr;
2369
+ }
2370
+ ValueType FindValue(const KeyType &key, const ValueType &default_value)
2371
+ { return (ValueType)((const HashMap *)this)->FindValue(key, default_value); }
2372
+ const ValueType FindValue(const KeyType &key, const ValueType &default_value) const
2373
+ {
2374
+ const ValueType *it = Find(key);
2375
+ return it ? *it : default_value;
2376
+ }
2377
+
2378
+ ValueType *Set(const KeyType &key, const ValueType &value)
2379
+ { return &table.Set({key, value})->value; }
2380
+ ValueType *SetDefault(const KeyType &key)
2381
+ {
2382
+ Bucket *table_it = table.SetDefault(key);
2383
+ table_it->key = key;
2384
+ return &table_it->value;
2385
+ }
2386
+
2387
+ std::pair<ValueType *, bool> TrySet(const KeyType &key, const ValueType &value)
2388
+ {
2389
+ std::pair<Bucket *, bool> ret = table.TrySet({key, value});
2390
+ return { &ret.first->value, ret.second };
2391
+ }
2392
+ std::pair<ValueType *, bool> TrySetDefault(const KeyType &key)
2393
+ {
2394
+ std::pair<Bucket *, bool> ret = table.TrySetDefault(key);
2395
+ ret.first->key = key;
2396
+ return { &ret.first->value, ret.second };
2397
+ }
2398
+
2399
+ void Remove(ValueType *it)
2400
+ {
2401
+ if (!it)
2402
+ return;
2403
+ table.Remove((Bucket *)((uint8_t *)it - RG_OFFSET_OF(Bucket, value)));
2404
+ }
2405
+ void Remove(const KeyType &key) { Remove(Find(key)); }
2406
+
2407
+ void Trim() { table.Trim(); }
2408
+ };
2409
+
2410
+ template <typename ValueType>
2411
+ class HashSet {
2412
+ class Handler {
2413
+ public:
2414
+ static ValueType GetKey(const ValueType &value) { return value; }
2415
+ static ValueType GetKey(const ValueType *value) { return *value; }
2416
+ static uint64_t HashKey(const ValueType &value)
2417
+ { return HashTraits<ValueType>::Hash(value); }
2418
+ static bool TestKeys(const ValueType &value1, const ValueType &value2)
2419
+ { return HashTraits<ValueType>::Test(value1, value2); }
2420
+ };
2421
+
2422
+ public:
2423
+ HashTable<ValueType, ValueType, Handler> table;
2424
+
2425
+ HashSet() {}
2426
+ HashSet(std::initializer_list<ValueType> l)
2427
+ {
2428
+ for (const ValueType &value: l) {
2429
+ Set(value);
2430
+ }
2431
+ }
2432
+
2433
+ void Clear() { table.Clear(); }
2434
+ void RemoveAll() { table.RemoveAll(); }
2435
+
2436
+ ValueType *Find(const ValueType &value) { return table.Find(value); }
2437
+ const ValueType *Find(const ValueType &value) const { return table.Find(value); }
2438
+ ValueType FindValue(const ValueType &value, const ValueType &default_value)
2439
+ { return table.FindValue(value, default_value); }
2440
+ const ValueType FindValue(const ValueType &value, const ValueType &default_value) const
2441
+ { return table.FindValue(value, default_value); }
2442
+
2443
+ ValueType *Set(const ValueType &value) { return table.Set(value); }
2444
+ std::pair<ValueType *, bool> TrySet(const ValueType &value) { return table.TrySet(value); }
2445
+
2446
+ void Remove(ValueType *it) { table.Remove(it); }
2447
+ void Remove(const ValueType &value) { Remove(Find(value)); }
2448
+
2449
+ void Trim() { table.Trim(); }
2450
+ };
2451
+
2452
+ // ------------------------------------------------------------------------
2453
+ // Date
2454
+ // ------------------------------------------------------------------------
2455
+
2456
+ union Date {
2457
+ int32_t value;
2458
+ struct {
2459
+ // Sensitive to endianness
2460
+ int8_t day;
2461
+ int8_t month;
2462
+ int16_t year;
2463
+ } st;
2464
+
2465
+ Date() = default;
2466
+ Date(int16_t year, int8_t month, int8_t day)
2467
+ : st({day, month, year}) { RG_ASSERT(IsValid()); } // Sensitive to endianness
2468
+
2469
+ static inline bool IsLeapYear(int16_t year)
2470
+ {
2471
+ return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
2472
+ }
2473
+ static inline int8_t DaysInMonth(int16_t year, int8_t month)
2474
+ {
2475
+ static const int8_t DaysPerMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
2476
+ return (int8_t)(DaysPerMonth[month - 1] + (month == 2 && IsLeapYear(year)));
2477
+ }
2478
+
2479
+ static Date Parse(Span<const char> date_str, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
2480
+ Span<const char> *out_remaining = nullptr);
2481
+ static Date FromJulianDays(int days);
2482
+ static Date FromCalendarDate(int days) { return Date::FromJulianDays(days + 2440588); }
2483
+
2484
+ bool IsValid() const
2485
+ {
2486
+ if (st.year < -4712)
2487
+ return false;
2488
+ if (st.month < 1 || st.month > 12)
2489
+ return false;
2490
+ if (st.day < 1 || st.day > DaysInMonth(st.year, st.month))
2491
+ return false;
2492
+
2493
+ return true;
2494
+ }
2495
+
2496
+ bool operator==(Date other) const { return value == other.value; }
2497
+ bool operator!=(Date other) const { return value != other.value; }
2498
+ bool operator>(Date other) const { return value > other.value; }
2499
+ bool operator>=(Date other) const { return value >= other.value; }
2500
+ bool operator<(Date other) const { return value < other.value; }
2501
+ bool operator<=(Date other) const { return value <= other.value; }
2502
+
2503
+ int ToJulianDays() const;
2504
+ int ToCalendarDate() const { return ToJulianDays() - 2440588; }
2505
+
2506
+ int GetWeekDay() const;
2507
+
2508
+ int operator-(Date other) const
2509
+ { return ToJulianDays() - other.ToJulianDays(); }
2510
+
2511
+ Date operator+(int days) const
2512
+ {
2513
+ if (days < 5 && days > -5) {
2514
+ Date date = *this;
2515
+ if (days > 0) {
2516
+ while (days--) {
2517
+ ++date;
2518
+ }
2519
+ } else {
2520
+ while (days++) {
2521
+ --date;
2522
+ }
2523
+ }
2524
+ return date;
2525
+ } else {
2526
+ return Date::FromJulianDays(ToJulianDays() + days);
2527
+ }
2528
+ }
2529
+ // That'll fail with INT_MAX days but that's far more days than can
2530
+ // be represented as a date anyway
2531
+ Date operator-(int days) const { return *this + (-days); }
2532
+
2533
+ Date &operator+=(int days) { *this = *this + days; return *this; }
2534
+ Date &operator-=(int days) { *this = *this - days; return *this; }
2535
+ Date &operator++();
2536
+ Date operator++(int) { Date date = *this; ++(*this); return date; }
2537
+ Date &operator--();
2538
+ Date operator--(int) { Date date = *this; --(*this); return date; }
2539
+
2540
+ uint64_t Hash() const { return HashTraits<int32_t>::Hash(value); }
2541
+ };
2542
+
2543
+ // ------------------------------------------------------------------------
2544
+ // Time
2545
+ // ------------------------------------------------------------------------
2546
+
2547
+ int64_t GetUnixTime();
2548
+ int64_t GetMonotonicTime();
2549
+
2550
+ #if defined(_MSC_VER)
2551
+ static inline int64_t GetClockCounter()
2552
+ {
2553
+ return (int64_t)__rdtsc();
2554
+ }
2555
+ #elif defined(__i386__) || defined(__x86_64__)
2556
+ static inline int64_t GetClockCounter()
2557
+ {
2558
+ uint32_t counter_low, counter_high;
2559
+ __asm__ __volatile__ ("cpuid; rdtsc"
2560
+ : "=a" (counter_low), "=d" (counter_high)
2561
+ : : "%ebx", "%ecx");
2562
+ int64_t counter = ((int64_t)counter_high << 32) | counter_low;
2563
+ return counter;
2564
+ }
2565
+ #endif
2566
+
2567
+ struct TimeSpec {
2568
+ int16_t year;
2569
+ int8_t month;
2570
+ int8_t day;
2571
+ int8_t week_day; // 1 (monday) to 7 (sunday)
2572
+
2573
+ int8_t hour;
2574
+ int8_t min;
2575
+ int8_t sec;
2576
+ int16_t msec;
2577
+
2578
+ int16_t offset; // minutes
2579
+ };
2580
+
2581
+ enum class TimeMode {
2582
+ Local,
2583
+ UTC
2584
+ };
2585
+ static const char *const TimeModeNames[] = {
2586
+ "Local",
2587
+ "UTC"
2588
+ };
2589
+
2590
+ TimeSpec DecomposeTime(int64_t time, TimeMode mode = TimeMode::Local);
2591
+
2592
+ // ------------------------------------------------------------------------
2593
+ // Streams
2594
+ // ------------------------------------------------------------------------
2595
+
2596
+ enum class CompressionType {
2597
+ None,
2598
+ Zlib,
2599
+ Gzip,
2600
+ Brotli
2601
+ };
2602
+ static const char *const CompressionTypeNames[] = {
2603
+ "None",
2604
+ "Zlib",
2605
+ "Gzip",
2606
+ "Brotli"
2607
+ };
2608
+
2609
+ enum class CompressionSpeed {
2610
+ Default,
2611
+ Slow,
2612
+ Fast
2613
+ };
2614
+
2615
+ class StreamReader {
2616
+ RG_DELETE_COPY(StreamReader)
2617
+
2618
+ enum class SourceType {
2619
+ Memory,
2620
+ File,
2621
+ Function
2622
+ };
2623
+
2624
+ const char *filename = nullptr;
2625
+ bool error = true;
2626
+
2627
+ struct {
2628
+ SourceType type = SourceType::Memory;
2629
+ union U {
2630
+ struct {
2631
+ Span<const uint8_t> buf;
2632
+ Size pos;
2633
+ } memory;
2634
+ struct {
2635
+ FILE *fp;
2636
+ bool owned;
2637
+ } file;
2638
+ std::function<Size(Span<uint8_t> buf)> func;
2639
+
2640
+ // StreamReader deals with func destructor
2641
+ U() {}
2642
+ ~U() {}
2643
+ } u;
2644
+
2645
+ bool eof = false;
2646
+ } source;
2647
+
2648
+ struct {
2649
+ CompressionType type = CompressionType::None;
2650
+ union {
2651
+ struct MinizInflateContext *miniz;
2652
+ struct BrotliDecompressContext *brotli;
2653
+ } u;
2654
+ } compression;
2655
+
2656
+ int64_t raw_len = -1;
2657
+ Size raw_read = 0;
2658
+ bool eof = false;
2659
+
2660
+ BlockAllocator str_alloc;
2661
+
2662
+ public:
2663
+ StreamReader() { Close(true); }
2664
+ StreamReader(Span<const uint8_t> buf, const char *filename = nullptr,
2665
+ CompressionType compression_type = CompressionType::None)
2666
+ : StreamReader() { Open(buf, filename, compression_type); }
2667
+ StreamReader(FILE *fp, const char *filename,
2668
+ CompressionType compression_type = CompressionType::None)
2669
+ : StreamReader() { Open(fp, filename, compression_type); }
2670
+ StreamReader(const char *filename,
2671
+ CompressionType compression_type = CompressionType::None)
2672
+ : StreamReader() { Open(filename, compression_type); }
2673
+ StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
2674
+ CompressionType compression_type = CompressionType::None)
2675
+ : StreamReader() { Open(func, filename, compression_type); }
2676
+ ~StreamReader() { Close(true); }
2677
+
2678
+ bool Open(Span<const uint8_t> buf, const char *filename = nullptr,
2679
+ CompressionType compression_type = CompressionType::None);
2680
+ bool Open(FILE *fp, const char *filename,
2681
+ CompressionType compression_type = CompressionType::None);
2682
+ bool Open(const char *filename, CompressionType compression_type = CompressionType::None);
2683
+ bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
2684
+ CompressionType compression_type = CompressionType::None);
2685
+ bool Close() { return Close(false); }
2686
+
2687
+ // File-specific
2688
+ bool Rewind();
2689
+
2690
+ const char *GetFileName() const { return filename; }
2691
+ CompressionType GetCompressionType() const { return compression.type; }
2692
+ bool IsValid() const { return filename && !error; }
2693
+ bool IsEOF() const { return eof; }
2694
+
2695
+ Size Read(Span<uint8_t> out_buf);
2696
+ Size Read(Span<char> out_buf) { return Read(out_buf.CastAs<uint8_t>()); }
2697
+ Size Read(Size max_len, void *out_buf) { return Read(MakeSpan((uint8_t *)out_buf, max_len)); }
2698
+
2699
+ Size ReadAll(Size max_len, HeapArray<uint8_t> *out_buf);
2700
+ Size ReadAll(Size max_len, HeapArray<char> *out_buf)
2701
+ { return ReadAll(max_len, (HeapArray<uint8_t> *)out_buf); }
2702
+
2703
+ int64_t ComputeRawLen();
2704
+
2705
+ private:
2706
+ bool Close(bool implicit);
2707
+
2708
+ bool InitDecompressor(CompressionType type);
2709
+
2710
+ Size ReadInflate(Size max_len, void *out_buf);
2711
+ Size ReadBrotli(Size max_len, void *out_buf);
2712
+
2713
+ Size ReadRaw(Size max_len, void *out_buf);
2714
+ };
2715
+
2716
+ static inline Size ReadFile(const char *filename, Size max_len, CompressionType compression_type,
2717
+ HeapArray<uint8_t> *out_buf)
2718
+ {
2719
+ StreamReader st(filename, compression_type);
2720
+ return st.ReadAll(max_len, out_buf);
2721
+ }
2722
+ static inline Size ReadFile(const char *filename, Size max_len, HeapArray<uint8_t> *out_buf)
2723
+ {
2724
+ StreamReader st(filename);
2725
+ return st.ReadAll(max_len, out_buf);
2726
+ }
2727
+ static inline Size ReadFile(const char *filename, Size max_len, CompressionType compression_type,
2728
+ HeapArray<char> *out_buf)
2729
+ {
2730
+ StreamReader st(filename, compression_type);
2731
+ return st.ReadAll(max_len, out_buf);
2732
+ }
2733
+ static inline Size ReadFile(const char *filename, Size max_len, HeapArray<char> *out_buf)
2734
+ {
2735
+ StreamReader st(filename);
2736
+ return st.ReadAll(max_len, out_buf);
2737
+ }
2738
+
2739
+ class LineReader {
2740
+ RG_DELETE_COPY(LineReader)
2741
+
2742
+ HeapArray<char> buf;
2743
+ Span<char> view = {};
2744
+
2745
+ StreamReader *st;
2746
+ bool error;
2747
+ bool eof = false;
2748
+
2749
+ Span<char> line = {};
2750
+ int line_number = 0;
2751
+
2752
+ public:
2753
+ LineReader(StreamReader *st) : st(st), error(!st->IsValid()) {}
2754
+
2755
+ const char *GetFileName() const { return st->GetFileName(); }
2756
+ int GetLineNumber() const { return line_number; }
2757
+ bool IsValid() const { return !error; }
2758
+ bool IsEOF() const { return eof; }
2759
+
2760
+ bool Next(Span<char> *out_line);
2761
+ bool Next(Span<const char> *out_line) { return Next((Span<char> *)out_line); }
2762
+
2763
+ void PushLogFilter();
2764
+ };
2765
+
2766
+ enum class StreamWriterFlag {
2767
+ Exclusive = 1 << 0,
2768
+ Atomic = 1 << 1
2769
+ };
2770
+
2771
+ class StreamWriter {
2772
+ RG_DELETE_COPY(StreamWriter)
2773
+
2774
+ enum class DestinationType {
2775
+ Memory,
2776
+ File,
2777
+ Function
2778
+ };
2779
+
2780
+ const char *filename = nullptr;
2781
+ bool error = true;
2782
+
2783
+ struct {
2784
+ DestinationType type = DestinationType::Memory;
2785
+ union U {
2786
+ struct {
2787
+ HeapArray<uint8_t> *memory;
2788
+ Size start;
2789
+ } mem;
2790
+ struct {
2791
+ FILE *fp;
2792
+ bool owned;
2793
+
2794
+ // Atomic write mode
2795
+ const char *tmp_filename;
2796
+ bool tmp_exclusive;
2797
+ } file;
2798
+ std::function<bool(Span<const uint8_t>)> func;
2799
+
2800
+ // StreamWriter deals with func destructor
2801
+ U() {}
2802
+ ~U() {}
2803
+ } u;
2804
+
2805
+ bool vt100;
2806
+ } dest;
2807
+
2808
+ struct {
2809
+ CompressionType type = CompressionType::None;
2810
+ CompressionSpeed speed = CompressionSpeed::Default;
2811
+ union {
2812
+ struct MinizDeflateContext *miniz;
2813
+ struct BrotliEncoderStateStruct *brotli;
2814
+ } u;
2815
+ } compression;
2816
+
2817
+ BlockAllocator str_alloc;
2818
+
2819
+ public:
2820
+ StreamWriter() { Close(true); }
2821
+ StreamWriter(HeapArray<uint8_t> *mem, const char *filename = nullptr,
2822
+ CompressionType compression_type = CompressionType::None,
2823
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
2824
+ : StreamWriter() { Open(mem, filename, compression_type, compression_speed); }
2825
+ StreamWriter(FILE *fp, const char *filename,
2826
+ CompressionType compression_type = CompressionType::None,
2827
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
2828
+ : StreamWriter() { Open(fp, filename, compression_type, compression_speed); }
2829
+ StreamWriter(const char *filename, unsigned int flags = 0,
2830
+ CompressionType compression_type = CompressionType::None,
2831
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
2832
+ : StreamWriter() { Open(filename, flags, compression_type, compression_speed); }
2833
+ StreamWriter(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
2834
+ CompressionType compression_type = CompressionType::None,
2835
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
2836
+ : StreamWriter() { Open(func, filename, compression_type, compression_speed); }
2837
+ ~StreamWriter() { Close(true); }
2838
+
2839
+ bool Open(HeapArray<uint8_t> *mem, const char *filename = nullptr,
2840
+ CompressionType compression_type = CompressionType::None,
2841
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
2842
+ bool Open(FILE *fp, const char *filename,
2843
+ CompressionType compression_type = CompressionType::None,
2844
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
2845
+ bool Open(const char *filename, unsigned int flags = 0,
2846
+ CompressionType compression_type = CompressionType::None,
2847
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
2848
+ bool Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
2849
+ CompressionType compression_type = CompressionType::None,
2850
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
2851
+ bool Close() { return Close(false); }
2852
+
2853
+ // For compressed streams, Flush may not be complete and only Close() can finalize the file.
2854
+ bool Flush();
2855
+
2856
+ const char *GetFileName() const { return filename; }
2857
+ CompressionType GetCompressionType() const { return compression.type; }
2858
+ bool IsVt100() const { return dest.vt100; }
2859
+ bool IsValid() const { return filename && !error; }
2860
+
2861
+ bool Write(Span<const uint8_t> buf);
2862
+ bool Write(Span<const char> buf) { return Write(buf.CastAs<const uint8_t>()); }
2863
+ bool Write(char buf) { return Write(MakeSpan(&buf, 1)); }
2864
+ bool Write(const void *buf, Size len) { return Write(MakeSpan((const uint8_t *)buf, len)); }
2865
+
2866
+ private:
2867
+ bool Close(bool implicit);
2868
+
2869
+ bool InitCompressor(CompressionType type, CompressionSpeed speed);
2870
+
2871
+ bool WriteDeflate(Span<const uint8_t> buf);
2872
+ bool WriteBrotli(Span<const uint8_t> buf);
2873
+
2874
+ bool WriteRaw(Span<const uint8_t> buf);
2875
+ };
2876
+
2877
+ static inline bool WriteFile(Span<const uint8_t> buf, const char *filename, unsigned int flags = 0,
2878
+ CompressionType compression_type = CompressionType::None)
2879
+ {
2880
+ StreamWriter st(filename, flags, compression_type);
2881
+ st.Write(buf);
2882
+ return st.Close();
2883
+ }
2884
+ static inline bool WriteFile(Span<const char> buf, const char *filename, unsigned int flags = 0,
2885
+ CompressionType compression_type = CompressionType::None)
2886
+ {
2887
+ StreamWriter st(filename, flags, compression_type);
2888
+ st.Write(buf);
2889
+ return st.Close();
2890
+ }
2891
+
2892
+ bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer);
2893
+
2894
+ // For convenience, don't close them
2895
+ extern StreamReader stdin_st;
2896
+ extern StreamWriter stdout_st;
2897
+ extern StreamWriter stderr_st;
2898
+
2899
+ // ------------------------------------------------------------------------
2900
+ // Format
2901
+ // ------------------------------------------------------------------------
2902
+
2903
+ enum class FmtType {
2904
+ Str1,
2905
+ Str2,
2906
+ Buffer,
2907
+ Char,
2908
+ Bool,
2909
+ Integer,
2910
+ Unsigned,
2911
+ Float,
2912
+ Double,
2913
+ Binary,
2914
+ Hexadecimal,
2915
+ MemorySize,
2916
+ DiskSize,
2917
+ Date,
2918
+ TimeISO,
2919
+ TimeNice,
2920
+ Random,
2921
+ FlagNames,
2922
+ FlagOptions,
2923
+ Span
2924
+ };
2925
+
2926
+ class FmtArg {
2927
+ public:
2928
+ FmtType type;
2929
+ union {
2930
+ const char *str1;
2931
+ Span<const char> str2;
2932
+ char buf[32];
2933
+ char ch;
2934
+ bool b;
2935
+ int64_t i;
2936
+ uint64_t u;
2937
+ struct {
2938
+ float value;
2939
+ int min_prec;
2940
+ int max_prec;
2941
+ } f;
2942
+ struct {
2943
+ double value;
2944
+ int min_prec;
2945
+ int max_prec;
2946
+ } d;
2947
+ const void *ptr;
2948
+ Date date;
2949
+ TimeSpec time;
2950
+ Size random_len;
2951
+ struct {
2952
+ uint64_t flags;
2953
+ union {
2954
+ Span<const char *const> names;
2955
+ Span<const struct OptionDesc> options;
2956
+ } u;
2957
+ const char *separator;
2958
+ } flags;
2959
+
2960
+ struct {
2961
+ FmtType type;
2962
+ int type_len;
2963
+ const void *ptr;
2964
+ Size len;
2965
+ const char *separator;
2966
+ } span;
2967
+ } u;
2968
+
2969
+ int repeat = 1;
2970
+ int pad_len = 0;
2971
+ char pad_char;
2972
+
2973
+ FmtArg() = default;
2974
+ FmtArg(const char *str) : type(FmtType::Str1) { u.str1 = str ? str : "(null)"; }
2975
+ FmtArg(Span<const char> str) : type(FmtType::Str2) { u.str2 = str; }
2976
+ FmtArg(char c) : type(FmtType::Char) { u.ch = c; }
2977
+ FmtArg(bool b) : type(FmtType::Bool) { u.b = b; }
2978
+ FmtArg(unsigned char i) : type(FmtType::Unsigned) { u.u = i; }
2979
+ FmtArg(short i) : type(FmtType::Integer) { u.i = i; }
2980
+ FmtArg(unsigned short i) : type(FmtType::Unsigned) { u.u = i; }
2981
+ FmtArg(int i) : type(FmtType::Integer) { u.i = i; }
2982
+ FmtArg(unsigned int i) : type(FmtType::Unsigned) { u.u = i; }
2983
+ FmtArg(long i) : type(FmtType::Integer) { u.i = i; }
2984
+ FmtArg(unsigned long i) : type(FmtType::Unsigned) { u.u = i; }
2985
+ FmtArg(long long i) : type(FmtType::Integer) { u.i = i; }
2986
+ FmtArg(unsigned long long i) : type(FmtType::Unsigned) { u.u = i; }
2987
+ FmtArg(float f) : type(FmtType::Float) { u.f = { f, 0, INT_MAX }; }
2988
+ FmtArg(double d) : type(FmtType::Double) { u.d = { d, 0, INT_MAX }; }
2989
+ FmtArg(const void *ptr) : type(FmtType::Hexadecimal) { u.u = (uint64_t)ptr; }
2990
+ FmtArg(const Date &date) : type(FmtType::Date) { u.date = date; }
2991
+
2992
+ FmtArg &Repeat(int new_repeat) { repeat = new_repeat; return *this; }
2993
+ FmtArg &Pad(int len, char c = ' ') { pad_char = c; pad_len = len; return *this; }
2994
+ FmtArg &Pad0(int len) { return Pad(len, '0'); }
2995
+ };
2996
+
2997
+ static inline FmtArg FmtBin(uint64_t u)
2998
+ {
2999
+ FmtArg arg;
3000
+ arg.type = FmtType::Binary;
3001
+ arg.u.u = u;
3002
+ return arg;
3003
+ }
3004
+ static inline FmtArg FmtHex(uint64_t u)
3005
+ {
3006
+ FmtArg arg;
3007
+ arg.type = FmtType::Hexadecimal;
3008
+ arg.u.u = u;
3009
+ return arg;
3010
+ }
3011
+
3012
+ static inline FmtArg FmtFloat(float f, int min_prec, int max_prec)
3013
+ {
3014
+ FmtArg arg;
3015
+ arg.type = FmtType::Float;
3016
+ arg.u.f.value = f;
3017
+ arg.u.f.min_prec = min_prec;
3018
+ arg.u.f.max_prec = max_prec;
3019
+ return arg;
3020
+ }
3021
+ static inline FmtArg FmtFloat(float f, int prec) { return FmtFloat(f, prec, prec); }
3022
+ static inline FmtArg FmtFloat(float f) { return FmtFloat(f, 0, INT_MAX); }
3023
+
3024
+ static inline FmtArg FmtDouble(double d, int min_prec, int max_prec)
3025
+ {
3026
+ FmtArg arg;
3027
+ arg.type = FmtType::Double;
3028
+ arg.u.d.value = d;
3029
+ arg.u.d.min_prec = min_prec;
3030
+ arg.u.d.max_prec = max_prec;
3031
+ return arg;
3032
+ }
3033
+ static inline FmtArg FmtDouble(double d, int prec) { return FmtDouble(d, prec, prec); }
3034
+ static inline FmtArg FmtDouble(double d) { return FmtDouble(d, 0, INT_MAX); }
3035
+
3036
+ static inline FmtArg FmtMemSize(int64_t size)
3037
+ {
3038
+ FmtArg arg;
3039
+ arg.type = FmtType::MemorySize;
3040
+ arg.u.i = size;
3041
+ return arg;
3042
+ }
3043
+ static inline FmtArg FmtDiskSize(int64_t size)
3044
+ {
3045
+ FmtArg arg;
3046
+ arg.type = FmtType::DiskSize;
3047
+ arg.u.i = size;
3048
+ return arg;
3049
+ }
3050
+
3051
+ static inline FmtArg FmtTimeISO(TimeSpec spec)
3052
+ {
3053
+ FmtArg arg;
3054
+ arg.type = FmtType::TimeISO;
3055
+ arg.u.time = spec;
3056
+ return arg;
3057
+ }
3058
+
3059
+ static inline FmtArg FmtTimeNice(TimeSpec spec)
3060
+ {
3061
+ FmtArg arg;
3062
+ arg.type = FmtType::TimeNice;
3063
+ arg.u.time = spec;
3064
+ return arg;
3065
+ }
3066
+
3067
+ static inline FmtArg FmtRandom(Size len)
3068
+ {
3069
+ RG_ASSERT(len < 256);
3070
+ len = std::min(len, (Size)256);
3071
+
3072
+ FmtArg arg;
3073
+ arg.type = FmtType::Random;
3074
+ arg.u.random_len = len;
3075
+ return arg;
3076
+ }
3077
+
3078
+ static inline FmtArg FmtFlags(uint64_t flags, Span<const char *const> names, const char *sep = ", ")
3079
+ {
3080
+ FmtArg arg;
3081
+ arg.type = FmtType::FlagNames;
3082
+ arg.u.flags.flags = flags & ((1ull << names.len) - 1);
3083
+ arg.u.flags.u.names = names;
3084
+ arg.u.flags.separator = sep;
3085
+ return arg;
3086
+ }
3087
+
3088
+ static inline FmtArg FmtFlags(uint64_t flags, Span<const struct OptionDesc> options, const char *sep = ", ")
3089
+ {
3090
+ FmtArg arg;
3091
+ arg.type = FmtType::FlagOptions;
3092
+ arg.u.flags.flags = flags & ((1ull << options.len) - 1);
3093
+ arg.u.flags.u.options = options;
3094
+ arg.u.flags.separator = sep;
3095
+ return arg;
3096
+ }
3097
+
3098
+ template <typename T>
3099
+ FmtArg FmtSpan(Span<T> arr, FmtType type, const char *sep = ", ")
3100
+ {
3101
+ FmtArg arg;
3102
+ arg.type = FmtType::Span;
3103
+ arg.u.span.type = type;
3104
+ arg.u.span.type_len = RG_SIZE(T);
3105
+ arg.u.span.ptr = (const void *)arr.ptr;
3106
+ arg.u.span.len = arr.len;
3107
+ arg.u.span.separator = sep;
3108
+ return arg;
3109
+ }
3110
+ template <typename T>
3111
+ FmtArg FmtSpan(Span<T> arr, const char *sep = ", ") { return FmtSpan(arr, FmtArg(T()).type, sep); }
3112
+ template <typename T, Size N>
3113
+ FmtArg FmtSpan(T (&arr)[N], FmtType type, const char *sep = ", ") { return FmtSpan(MakeSpan(arr), type, sep); }
3114
+ template <typename T, Size N>
3115
+ FmtArg FmtSpan(T (&arr)[N], const char *sep = ", ") { return FmtSpan(MakeSpan(arr), sep); }
3116
+
3117
+ enum class LogLevel {
3118
+ Debug,
3119
+ Info,
3120
+ Warning,
3121
+ Error
3122
+ };
3123
+
3124
+ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, Span<char> out_buf);
3125
+ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, HeapArray<char> *out_buf);
3126
+ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, Allocator *alloc);
3127
+ void PrintFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *out_st);
3128
+ void PrintFmt(const char *fmt, Span<const FmtArg> args, FILE *out_fp);
3129
+ void PrintLnFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *out_st);
3130
+ void PrintLnFmt(const char *fmt, Span<const FmtArg> args, FILE *out_fp);
3131
+
3132
+ #define DEFINE_FMT_VARIANT(Name, Ret, Type) \
3133
+ static inline Ret Name(Type out, const char *fmt) \
3134
+ { \
3135
+ return Name##Fmt(fmt, {}, out); \
3136
+ } \
3137
+ template <typename... Args> \
3138
+ Ret Name(Type out, const char *fmt, Args... args) \
3139
+ { \
3140
+ const FmtArg fmt_args[] = { FmtArg(args)... }; \
3141
+ return Name##Fmt(fmt, fmt_args, out); \
3142
+ }
3143
+
3144
+ DEFINE_FMT_VARIANT(Fmt, Span<char>, Span<char>)
3145
+ DEFINE_FMT_VARIANT(Fmt, Span<char>, HeapArray<char> *)
3146
+ DEFINE_FMT_VARIANT(Fmt, Span<char>, Allocator *)
3147
+ DEFINE_FMT_VARIANT(Print, void, StreamWriter *)
3148
+ DEFINE_FMT_VARIANT(Print, void, FILE *)
3149
+ DEFINE_FMT_VARIANT(PrintLn, void, StreamWriter *)
3150
+ DEFINE_FMT_VARIANT(PrintLn, void, FILE *)
3151
+
3152
+ #undef DEFINE_FMT_VARIANT
3153
+
3154
+ // Print formatted strings to stdout
3155
+ template <typename... Args>
3156
+ void Print(const char *fmt, Args... args)
3157
+ {
3158
+ Print(stdout, fmt, args...);
3159
+ }
3160
+ template <typename... Args>
3161
+ void PrintLn(const char *fmt, Args... args)
3162
+ {
3163
+ PrintLn(stdout, fmt, args...);
3164
+ }
3165
+
3166
+ // PrintLn variants without format strings
3167
+ static inline void PrintLn(StreamWriter *out_st) { out_st->Write('\n'); }
3168
+ static inline void PrintLn(FILE *out_fp) { fputc('\n', out_fp); }
3169
+ static inline void PrintLn() { putchar('\n'); }
3170
+
3171
+ // ------------------------------------------------------------------------
3172
+ // Debug and errors
3173
+ // ------------------------------------------------------------------------
3174
+
3175
+ typedef void LogFunc(LogLevel level, const char *ctx, const char *msg);
3176
+ typedef void LogFilterFunc(LogLevel level, const char *ctx, const char *msg,
3177
+ FunctionRef<LogFunc> func);
3178
+
3179
+ const char *GetQualifiedEnv(const char *name);
3180
+ bool GetDebugFlag(const char *name);
3181
+
3182
+ void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg> args);
3183
+
3184
+ static inline void Log(LogLevel level, const char *ctx)
3185
+ {
3186
+ LogFmt(level, ctx, "", {});
3187
+ }
3188
+ static inline void Log(LogLevel level, const char *ctx, const char *fmt)
3189
+ {
3190
+ LogFmt(level, ctx, fmt, {});
3191
+ }
3192
+ template <typename... Args>
3193
+ static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args... args)
3194
+ {
3195
+ const FmtArg fmt_args[] = { FmtArg(args)... };
3196
+ LogFmt(level, ctx, fmt, fmt_args);
3197
+ }
3198
+
3199
+ // Shortcut log functions
3200
+ #ifdef RG_DEBUG
3201
+ template <typename... Args>
3202
+ static inline void LogDebug(Args... args) { Log(LogLevel::Debug, "Debug", args...); }
3203
+ #else
3204
+ template <typename... Args>
3205
+ static inline void LogDebug(Args...) {}
3206
+ #endif
3207
+ template <typename... Args>
3208
+ static inline void LogInfo(Args... args) { Log(LogLevel::Info, nullptr, args...); }
3209
+ template <typename... Args>
3210
+ static inline void LogError(Args... args) { Log(LogLevel::Error, "Error", args...); }
3211
+
3212
+ void SetLogHandler(const std::function<LogFunc> &func);
3213
+ void DefaultLogHandler(LogLevel level, const char *ctx, const char *msg);
3214
+
3215
+ void PushLogFilter(const std::function<LogFilterFunc> &func);
3216
+ void PopLogFilter();
3217
+
3218
+ // ------------------------------------------------------------------------
3219
+ // Strings
3220
+ // ------------------------------------------------------------------------
3221
+
3222
+ bool CopyString(const char *str, Span<char> buf);
3223
+ bool CopyString(Span<const char> str, Span<char> buf);
3224
+ Span<char> DuplicateString(Span<const char> str, Allocator *alloc);
3225
+
3226
+ static inline bool IsAsciiAlpha(int c)
3227
+ {
3228
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
3229
+ }
3230
+ static inline bool IsAsciiDigit(int c)
3231
+ {
3232
+ return (c >= '0' && c <= '9');
3233
+ }
3234
+ static inline bool IsAsciiAlphaOrDigit(int c)
3235
+ {
3236
+ return IsAsciiAlpha(c) || IsAsciiDigit(c);
3237
+ }
3238
+ static inline bool IsAsciiWhite(int c)
3239
+ {
3240
+ return c == ' ' || c == '\t' || c == '\v' ||
3241
+ c == '\n' || c == '\r' || c == '\f';
3242
+ }
3243
+
3244
+ static inline char UpperAscii(int c)
3245
+ {
3246
+ if (c >= 'a' && c <= 'z') {
3247
+ return (char)(c - 32);
3248
+ } else {
3249
+ return (char)c;
3250
+ }
3251
+ }
3252
+ static inline char LowerAscii(int c)
3253
+ {
3254
+ if (c >= 'A' && c <= 'Z') {
3255
+ return (char)(c + 32);
3256
+ } else {
3257
+ return (char)c;
3258
+ }
3259
+ }
3260
+
3261
+ static inline bool TestStr(Span<const char> str1, Span<const char> str2)
3262
+ {
3263
+ if (str1.len != str2.len)
3264
+ return false;
3265
+ for (Size i = 0; i < str1.len; i++) {
3266
+ if (str1[i] != str2[i])
3267
+ return false;
3268
+ }
3269
+ return true;
3270
+ }
3271
+ static inline bool TestStr(Span<const char> str1, const char *str2)
3272
+ {
3273
+ Size i;
3274
+ for (i = 0; i < str1.len && str2[i]; i++) {
3275
+ if (str1[i] != str2[i])
3276
+ return false;
3277
+ }
3278
+ return (i == str1.len) && !str2[i];
3279
+ }
3280
+ static inline bool TestStr(const char *str1, const char *str2)
3281
+ { return !strcmp(str1, str2); }
3282
+
3283
+ // Allow direct Span<const char> equality comparison
3284
+ inline bool Span<const char>::operator==(Span<const char> other) const
3285
+ { return TestStr(*this, other); }
3286
+ inline bool Span<const char>::operator==(const char *other) const
3287
+ { return TestStr(*this, other); }
3288
+
3289
+ // Case insensitive (ASCII) versions
3290
+ static inline bool TestStrI(Span<const char> str1, Span<const char> str2)
3291
+ {
3292
+ if (str1.len != str2.len)
3293
+ return false;
3294
+ for (Size i = 0; i < str1.len; i++) {
3295
+ if (LowerAscii(str1[i]) != LowerAscii(str2[i]))
3296
+ return false;
3297
+ }
3298
+ return true;
3299
+ }
3300
+ static inline bool TestStrI(Span<const char> str1, const char *str2)
3301
+ {
3302
+ Size i;
3303
+ for (i = 0; i < str1.len && str2[i]; i++) {
3304
+ if (LowerAscii(str1[i]) != LowerAscii(str2[i]))
3305
+ return false;
3306
+ }
3307
+ return (i == str1.len) && !str2[i];
3308
+ }
3309
+ static inline bool TestStrI(const char *str1, const char *str2)
3310
+ {
3311
+ Size i = 0;
3312
+ int delta;
3313
+ do {
3314
+ delta = LowerAscii(str1[i]) - LowerAscii(str2[i]);
3315
+ } while (str1[i++] && !delta);
3316
+ return !delta;
3317
+ }
3318
+
3319
+ static inline int CmpStr(Span<const char> str1, Span<const char> str2)
3320
+ {
3321
+ for (Size i = 0; i < str1.len && i < str2.len; i++) {
3322
+ int delta = str1[i] - str2[i];
3323
+ if (delta)
3324
+ return delta;
3325
+ }
3326
+ if (str1.len < str2.len) {
3327
+ return -str2[str1.len];
3328
+ } else if (str1.len > str2.len) {
3329
+ return str1[str2.len];
3330
+ } else {
3331
+ return 0;
3332
+ }
3333
+ }
3334
+ static inline int CmpStr(Span<const char> str1, const char *str2)
3335
+ {
3336
+ Size i;
3337
+ for (i = 0; i < str1.len && str2[i]; i++) {
3338
+ int delta = str1[i] - str2[i];
3339
+ if (delta)
3340
+ return delta;
3341
+ }
3342
+ if (str1.len == i) {
3343
+ return -str2[i];
3344
+ } else {
3345
+ return str1[i];
3346
+ }
3347
+ }
3348
+ static inline int CmpStr(const char *str1, const char *str2)
3349
+ { return strcmp(str1, str2); }
3350
+
3351
+ static inline Size StartsWith(Span<const char> str, Span<const char> prefix)
3352
+ {
3353
+ Size i = 0;
3354
+ while (i < str.len && i < prefix.len) {
3355
+ if (str[i] != prefix[i])
3356
+ return 0;
3357
+
3358
+ i++;
3359
+ }
3360
+
3361
+ return (i == prefix.len) ? i : 0;
3362
+ }
3363
+ static inline Size StartsWith(Span<const char> str, const char *prefix)
3364
+ {
3365
+ Size i = 0;
3366
+ while (i < str.len && prefix[i]) {
3367
+ if (str[i] != prefix[i])
3368
+ return 0;
3369
+
3370
+ i++;
3371
+ }
3372
+
3373
+ return !prefix[i] ? i : 0;
3374
+ }
3375
+ static inline Size StartsWith(const char *str, const char *prefix)
3376
+ {
3377
+ Size i = 0;
3378
+ while (str[i] && prefix[i]) {
3379
+ if (str[i] != prefix[i])
3380
+ return 0;
3381
+
3382
+ i++;
3383
+ }
3384
+
3385
+ return !prefix[i] ? i : 0;
3386
+ }
3387
+
3388
+ static inline bool EndsWith(Span<const char> str, const char *suffix)
3389
+ {
3390
+ Size i = str.len - 1;
3391
+ Size j = (Size)strlen(suffix) - 1;
3392
+ while (i >= 0 && j >= 0) {
3393
+ if (str[i] != suffix[j])
3394
+ return false;
3395
+
3396
+ i--;
3397
+ j--;
3398
+ }
3399
+
3400
+ return j < 0;
3401
+ }
3402
+
3403
+ static inline Span<char> SplitStr(Span<char> str, char split_char, Span<char> *out_remainder = nullptr)
3404
+ {
3405
+ Size part_len = 0;
3406
+ while (part_len < str.len) {
3407
+ if (str[part_len] == split_char) {
3408
+ if (out_remainder) {
3409
+ *out_remainder = str.Take(part_len + 1, str.len - part_len - 1);
3410
+ }
3411
+ return str.Take(0, part_len);
3412
+ }
3413
+ part_len++;
3414
+ }
3415
+
3416
+ if (out_remainder) {
3417
+ *out_remainder = str.Take(str.len, 0);
3418
+ }
3419
+ return str;
3420
+ }
3421
+ static inline Span<char> SplitStr(char *str, char split_char, char **out_remainder = nullptr)
3422
+ {
3423
+ Size part_len = 0;
3424
+ while (str[part_len]) {
3425
+ if (str[part_len] == split_char) {
3426
+ if (out_remainder) {
3427
+ *out_remainder = str + part_len + 1;
3428
+ }
3429
+ return MakeSpan(str, part_len);
3430
+ }
3431
+ part_len++;
3432
+ }
3433
+
3434
+ if (out_remainder) {
3435
+ *out_remainder = str + part_len;
3436
+ }
3437
+ return MakeSpan(str, part_len);
3438
+ }
3439
+ static inline Span<const char> SplitStr(Span<const char> str, char split_char, Span<const char> *out_remainder = nullptr)
3440
+ { return SplitStr(MakeSpan((char *)str.ptr, str.len), split_char, (Span<char> *)out_remainder); }
3441
+ static inline Span<const char> SplitStr(const char *str, char split_char, const char **out_remainder = nullptr)
3442
+ { return SplitStr((char *)str, split_char, (char **)out_remainder); }
3443
+
3444
+ static inline Span<char> SplitStrLine(Span<char> str, Span<char> *out_remainder = nullptr)
3445
+ {
3446
+ Span<char> part = SplitStr(str, '\n', out_remainder);
3447
+ if (part.len < str.len && part.len && part[part.len - 1] == '\r') {
3448
+ part.len--;
3449
+ }
3450
+ return part;
3451
+ }
3452
+ static inline Span<char> SplitStrLine(char *str, char **out_remainder = nullptr)
3453
+ {
3454
+ Span<char> part = SplitStr(str, '\n', out_remainder);
3455
+ if (str[part.len] && part.len && part[part.len - 1] == '\r') {
3456
+ part.len--;
3457
+ }
3458
+ return part;
3459
+ }
3460
+ static inline Span<const char> SplitStrLine(Span<const char> str, Span<const char> *out_remainder = nullptr)
3461
+ { return SplitStrLine(MakeSpan((char *)str.ptr, str.len), (Span<char> *)out_remainder); }
3462
+ static inline Span<const char> SplitStrLine(const char *str, const char **out_remainder = nullptr)
3463
+ { return SplitStrLine((char *)str, (char **)out_remainder); }
3464
+
3465
+ static inline Span<char> SplitStrAny(Span<char> str, const char *split_chars, Span<char> *out_remainder = nullptr)
3466
+ {
3467
+ Bitset<256> split_mask;
3468
+ for (Size i = 0; split_chars[i]; i++) {
3469
+ uint8_t c = (uint8_t)split_chars[i];
3470
+ split_mask.Set(c);
3471
+ }
3472
+
3473
+ Size part_len = 0;
3474
+ while (part_len < str.len) {
3475
+ uint8_t c = (uint8_t)str[part_len];
3476
+
3477
+ if (split_mask.Test(c)) {
3478
+ if (out_remainder) {
3479
+ *out_remainder = str.Take(part_len + 1, str.len - part_len - 1);
3480
+ }
3481
+ return str.Take(0, part_len);
3482
+ }
3483
+ part_len++;
3484
+ }
3485
+
3486
+ if (out_remainder) {
3487
+ *out_remainder = str.Take(str.len, 0);
3488
+ }
3489
+ return str;
3490
+ }
3491
+ static inline Span<char> SplitStrAny(char *str, const char *split_chars, char **out_remainder = nullptr)
3492
+ {
3493
+ Bitset<256> split_mask;
3494
+ for (Size i = 0; split_chars[i]; i++) {
3495
+ uint8_t c = (uint8_t)split_chars[i];
3496
+ split_mask.Set(c);
3497
+ }
3498
+
3499
+ Size part_len = 0;
3500
+ while (str[part_len]) {
3501
+ uint8_t c = (uint8_t)str[part_len];
3502
+
3503
+ if (split_mask.Test(c)) {
3504
+ if (out_remainder) {
3505
+ *out_remainder = str + part_len + 1;
3506
+ }
3507
+ return MakeSpan(str, part_len);
3508
+ }
3509
+ part_len++;
3510
+ }
3511
+
3512
+ if (out_remainder) {
3513
+ *out_remainder = str + part_len;
3514
+ }
3515
+ return MakeSpan(str, part_len);
3516
+ }
3517
+ static inline Span<const char> SplitStrAny(Span<const char> str, const char *split_chars, Span<const char> *out_remainder = nullptr)
3518
+ { return SplitStrAny(MakeSpan((char *)str.ptr, str.len), split_chars, (Span<char> *)out_remainder); }
3519
+ static inline Span<const char> SplitStrAny(const char *str, const char *split_chars, const char **out_remainder = nullptr)
3520
+ { return SplitStrAny((char *)str, split_chars, (char **)out_remainder); }
3521
+
3522
+ static inline Span<const char> SplitStrReverse(Span<const char> str, char split_char,
3523
+ Span<const char> *out_remainder = nullptr)
3524
+ {
3525
+ Size remainder_len = str.len - 1;
3526
+ while (remainder_len >= 0) {
3527
+ if (str[remainder_len] == split_char) {
3528
+ if (out_remainder) {
3529
+ *out_remainder = str.Take(0, remainder_len);
3530
+ }
3531
+ return str.Take(remainder_len + 1, str.len - remainder_len - 1);
3532
+ }
3533
+ remainder_len--;
3534
+ }
3535
+
3536
+ if (out_remainder) {
3537
+ *out_remainder = str.Take(0, 0);
3538
+ }
3539
+ return str;
3540
+ }
3541
+ static inline Span<const char> SplitStrReverse(const char *str, char split_char,
3542
+ Span<const char> *out_remainder = nullptr)
3543
+ { return SplitStrReverse(MakeSpan(str, strlen(str)), split_char, out_remainder); }
3544
+
3545
+ static inline Span<const char> SplitStrReverseAny(Span<const char> str, const char *split_chars,
3546
+ Span<const char> *out_remainder = nullptr)
3547
+ {
3548
+ Bitset<256> split_mask;
3549
+ for (Size i = 0; split_chars[i]; i++) {
3550
+ uint8_t c = (uint8_t)split_chars[i];
3551
+ split_mask.Set(c);
3552
+ }
3553
+
3554
+ Size remainder_len = str.len - 1;
3555
+ while (remainder_len >= 0) {
3556
+ uint8_t c = (uint8_t)str[remainder_len];
3557
+
3558
+ if (split_mask.Test(c)) {
3559
+ if (out_remainder) {
3560
+ *out_remainder = str.Take(0, remainder_len);
3561
+ }
3562
+ return str.Take(remainder_len + 1, str.len - remainder_len - 1);
3563
+ }
3564
+ remainder_len--;
3565
+ }
3566
+
3567
+ if (out_remainder) {
3568
+ *out_remainder = str.Take(0, 0);
3569
+ }
3570
+ return str;
3571
+ }
3572
+ static inline Span<const char> SplitStrReverseAny(const char *str, const char *split_chars,
3573
+ Span<const char> *out_remainder = nullptr)
3574
+ { return SplitStrReverseAny(MakeSpan(str, strlen(str)), split_chars, out_remainder); }
3575
+
3576
+ static inline Span<char> TrimStrLeft(Span<char> str, const char *trim_chars = " \t\r\n")
3577
+ {
3578
+ while (str.len && strchr(trim_chars, str[0])) {
3579
+ str.ptr++;
3580
+ str.len--;
3581
+ }
3582
+
3583
+ return str;
3584
+ }
3585
+ static inline Span<char> TrimStrRight(Span<char> str, const char *trim_chars = " \t\r\n")
3586
+ {
3587
+ while (str.len && strchr(trim_chars, str[str.len - 1])) {
3588
+ str.len--;
3589
+ }
3590
+
3591
+ return str;
3592
+ }
3593
+ static inline Span<char> TrimStr(Span<char> str, const char *trim_chars = " \t\r\n")
3594
+ {
3595
+ str = TrimStrRight(str, trim_chars);
3596
+ str = TrimStrLeft(str, trim_chars);
3597
+
3598
+ return str;
3599
+ }
3600
+ static inline Span<const char> TrimStrLeft(Span<const char> str, const char *trim_chars = " \t\r\n")
3601
+ { return TrimStrLeft(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3602
+ static inline Span<const char> TrimStrRight(Span<const char> str, const char *trim_chars = " \t\r\n")
3603
+ { return TrimStrRight(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3604
+ static inline Span<const char> TrimStr(Span<const char> str, const char *trim_chars = " \t\r\n")
3605
+ { return TrimStr(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3606
+
3607
+ template <typename T>
3608
+ bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3609
+ Span<const char> *out_remaining = nullptr)
3610
+ {
3611
+ if (RG_UNLIKELY(!str.len)) {
3612
+ if (flags & (int)ParseFlag::Log) {
3613
+ LogError("Cannot convert empty string to integer");
3614
+ }
3615
+ return false;
3616
+ }
3617
+
3618
+ uint64_t value = 0;
3619
+
3620
+ Size pos = 0;
3621
+ uint64_t neg = 0;
3622
+ if (str.len >= 2) {
3623
+ if (std::numeric_limits<T>::min() < 0 && str[0] == '-') {
3624
+ pos = 1;
3625
+ neg = UINT64_MAX;
3626
+ } else if (str[0] == '+') {
3627
+ pos = 1;
3628
+ }
3629
+ }
3630
+
3631
+ for (; pos < str.len; pos++) {
3632
+ unsigned int digit = (unsigned int)(str[pos] - '0');
3633
+ if (RG_UNLIKELY(digit > 9)) {
3634
+ if (!pos || flags & (int)ParseFlag::End) {
3635
+ if (flags & (int)ParseFlag::Log) {
3636
+ LogError("Malformed integer number '%1'", str);
3637
+ }
3638
+ return false;
3639
+ } else {
3640
+ break;
3641
+ }
3642
+ }
3643
+
3644
+ uint64_t new_value = (value * 10) + digit;
3645
+ if (RG_UNLIKELY(new_value < value))
3646
+ goto overflow;
3647
+ value = new_value;
3648
+ }
3649
+ if (RG_UNLIKELY(value > (uint64_t)std::numeric_limits<T>::max()))
3650
+ goto overflow;
3651
+ value = ((value ^ neg) - neg);
3652
+
3653
+ if (out_remaining) {
3654
+ *out_remaining = str.Take(pos, str.len - pos);
3655
+ }
3656
+ *out_value = (T)value;
3657
+ return true;
3658
+
3659
+ overflow:
3660
+ if (flags & (int)ParseFlag::Log) {
3661
+ LogError("Integer overflow for number '%1' (max = %2)", str,
3662
+ std::numeric_limits<T>::max());
3663
+ }
3664
+ return false;
3665
+ }
3666
+
3667
+ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3668
+ Span<const char> *out_remaining = nullptr);
3669
+
3670
+ static inline Size EncodeUtf8(int32_t c, char out_buf[4])
3671
+ {
3672
+ if (c < 0x80) {
3673
+ out_buf[0] = (char)c;
3674
+ return 1;
3675
+ } else if (c < 0x800) {
3676
+ out_buf[0] = (char)(0xC0 | (c >> 6));
3677
+ out_buf[1] = (char)(0x80 | (c & 0x3F));
3678
+ return 2;
3679
+ } else if (c >= 0xD800 && c < 0xE000) {
3680
+ return 0;
3681
+ } else if (c < 0x10000) {
3682
+ out_buf[0] = (char)(0xE0 | (c >> 12));
3683
+ out_buf[1] = (char)(0x80 | ((c >> 6) & 0x3F));
3684
+ out_buf[2] = (char)(0x80 | (c & 0x3F));
3685
+ return 3;
3686
+ } else if (c < 0x110000) {
3687
+ out_buf[0] = (char)(0xF0 | (c >> 18));
3688
+ out_buf[1] = (char)(0x80 | ((c >> 12) & 0x3F));
3689
+ out_buf[2] = (char)(0x80 | ((c >> 6) & 0x3F));
3690
+ out_buf[3] = (char)(0x80 | (c & 0x3F));
3691
+ return 4;
3692
+ } else {
3693
+ return 0;
3694
+ }
3695
+ }
3696
+
3697
+ static inline int CountUtf8Bytes(char c)
3698
+ {
3699
+ int ones = CountLeadingZeros((uint32_t)~c << 24);
3700
+ return std::min(std::max(ones, 1), 4);
3701
+ }
3702
+
3703
+ static inline Size DecodeUtf8(Span<const char> str, Size offset, int32_t *out_c)
3704
+ {
3705
+ RG_ASSERT(offset < str.len);
3706
+
3707
+ const uint8_t *ptr = (const uint8_t *)(str.ptr + offset);
3708
+ Size available = str.len - offset;
3709
+
3710
+ if (ptr[0] < 0x80) {
3711
+ *out_c = ptr[0];
3712
+ return 1;
3713
+ } else if (RG_UNLIKELY(ptr[0] - 0xC2 > 0xF4 - 0xC2)) {
3714
+ return 0;
3715
+ } else if (ptr[0] < 0xE0 &&
3716
+ RG_LIKELY(available >= 2 && (ptr[1] & 0xC0) == 0x80)) {
3717
+ *out_c = ((ptr[0] & 0x1F) << 6) | (ptr[1] & 0x3F);
3718
+ return 2;
3719
+ } else if (ptr[0] < 0xF0 &&
3720
+ RG_LIKELY(available >= 3 && (ptr[1] & 0xC0) == 0x80 &&
3721
+ (ptr[2] & 0xC0) == 0x80)) {
3722
+ *out_c = ((ptr[0] & 0xF) << 12) | ((ptr[1] & 0x3F) << 6) | (ptr[2] & 0x3F);
3723
+ return 3;
3724
+ } else if (RG_LIKELY(available >= 4 && (ptr[1] & 0xC0) == 0x80 &&
3725
+ (ptr[2] & 0xC0) == 0x80 &&
3726
+ (ptr[3] & 0xC0) == 0x80)) {
3727
+ *out_c = ((ptr[0] & 0x7) << 18) | ((ptr[1] & 0x3F) << 12) | ((ptr[2] & 0x3F) << 6) | (ptr[3] & 0x3F);
3728
+ return 4;
3729
+ } else {
3730
+ return 0;
3731
+ }
3732
+ }
3733
+
3734
+ static inline void FormatSha256(Span<const uint8_t> hash, char out_sha256[65])
3735
+ {
3736
+ RG_ASSERT(hash.len == 32);
3737
+ Fmt(MakeSpan(out_sha256, 65), "%1", FmtSpan(hash, FmtType::Hexadecimal, "").Pad0(-2));
3738
+ }
3739
+
3740
+ // ------------------------------------------------------------------------
3741
+ // System
3742
+ // ------------------------------------------------------------------------
3743
+
3744
+ #ifdef _WIN32
3745
+ #define RG_PATH_SEPARATORS "\\/"
3746
+ #define RG_PATH_DELIMITER ';'
3747
+ #define RG_SHARED_LIBRARY_EXTENSION ".dll"
3748
+ #else
3749
+ #define RG_PATH_SEPARATORS "/"
3750
+ #define RG_PATH_DELIMITER ':'
3751
+ #define RG_SHARED_LIBRARY_EXTENSION ".so"
3752
+ #endif
3753
+
3754
+ static inline bool IsPathSeparator(char c)
3755
+ {
3756
+ #ifdef _WIN32
3757
+ return c == '/' || c == '\\';
3758
+ #else
3759
+ return c == '/';
3760
+ #endif
3761
+ }
3762
+
3763
+ #ifdef _WIN32
3764
+ bool IsWin32Utf8();
3765
+ Size ConvertUtf8ToWin32Wide(Span<const char> str, Span<wchar_t> out_str_w);
3766
+ Size ConvertWin32WideToUtf8(const wchar_t *str_w, Span<char> out_str);
3767
+ char *GetWin32ErrorString(uint32_t error_code = UINT32_MAX);
3768
+ #endif
3769
+
3770
+ Span<const char> GetPathDirectory(Span<const char> filename);
3771
+ Span<const char> GetPathExtension(Span<const char> filename,
3772
+ CompressionType *out_compression_type = nullptr);
3773
+ CompressionType GetPathCompression(Span<const char> filename);
3774
+
3775
+ Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, Allocator *alloc);
3776
+ static inline Span<char> NormalizePath(Span<const char> path, Allocator *alloc)
3777
+ { return NormalizePath(path, {}, alloc); }
3778
+
3779
+ bool PathIsAbsolute(const char *path);
3780
+ bool PathIsAbsolute(Span<const char> path);
3781
+ bool PathContainsDotDot(const char *path);
3782
+
3783
+ enum class StatFlag {
3784
+ IgnoreMissing = 1 << 0,
3785
+ FollowSymlink = 1 << 1
3786
+ };
3787
+
3788
+ enum class FileType {
3789
+ Directory,
3790
+ File,
3791
+ Link,
3792
+ Unknown
3793
+ };
3794
+
3795
+ struct FileInfo {
3796
+ FileType type;
3797
+
3798
+ int64_t size;
3799
+ int64_t mtime;
3800
+ };
3801
+
3802
+ enum class EnumStatus {
3803
+ Error,
3804
+ Partial,
3805
+ Done
3806
+ };
3807
+
3808
+ bool StatFile(const char *filename, unsigned int flags, FileInfo *out_info);
3809
+ static inline bool StatFile(const char *filename, FileInfo *out_info)
3810
+ { return StatFile(filename, 0, out_info); }
3811
+
3812
+ // Sync failures are logged but not reported as errors (function returns true)
3813
+ bool RenameFile(const char *src_filename, const char *dest_filename, bool overwrite, bool sync = true);
3814
+
3815
+ EnumStatus EnumerateDirectory(const char *dirname, const char *filter, Size max_files,
3816
+ FunctionRef<bool(const char *, FileType)> func);
3817
+ bool EnumerateFiles(const char *dirname, const char *filter, Size max_depth, Size max_files,
3818
+ Allocator *str_alloc, HeapArray<const char *> *out_files);
3819
+ bool IsDirectoryEmpty(const char *dirname);
3820
+
3821
+ bool TestFile(const char *filename, FileType type = FileType::Unknown);
3822
+
3823
+ bool MatchPathName(const char *path, const char *spec);
3824
+ bool MatchPathSpec(const char *path, const char *spec);
3825
+
3826
+ bool FindExecutableInPath(const char *name, Allocator *alloc = nullptr,
3827
+ const char **out_path = nullptr);
3828
+
3829
+ bool SetWorkingDirectory(const char *directory);
3830
+ const char *GetWorkingDirectory();
3831
+
3832
+ const char *GetApplicationExecutable(); // Can be NULL (EmSDK)
3833
+ const char *GetApplicationDirectory(); // Can be NULL (EmSDK)
3834
+
3835
+ bool MakeDirectory(const char *directory, bool error_if_exists = true);
3836
+ bool MakeDirectoryRec(Span<const char> directory);
3837
+ bool UnlinkDirectory(const char *directory, bool error_if_missing = false);
3838
+ bool UnlinkFile(const char *filename, bool error_if_missing = false);
3839
+ bool EnsureDirectoryExists(const char *filename);
3840
+
3841
+ enum class OpenFileFlag {
3842
+ Read = 1 << 0,
3843
+ Write = 1 << 1,
3844
+ Append = 1 << 2,
3845
+
3846
+ Exclusive = 1 << 3
3847
+ };
3848
+
3849
+ int OpenDescriptor(const char *filename, unsigned int flags);
3850
+ FILE *OpenFile(const char *filename, unsigned int flags);
3851
+ bool FlushFile(FILE *fp, const char *filename);
3852
+
3853
+ bool FileIsVt100(FILE *fp);
3854
+
3855
+ const char *CreateTemporaryFile(Span<const char> directory, const char *prefix, const char *extension,
3856
+ Allocator *alloc, FILE **out_fp = nullptr);
3857
+ const char *CreateTemporaryDirectory(Span<const char> directory, const char *prefix, Allocator *alloc);
3858
+
3859
+ #ifndef _WIN32
3860
+ bool CreatePipe(int pfd[2]);
3861
+ #endif
3862
+
3863
+ bool ExecuteCommandLine(const char *cmd_line, FunctionRef<Span<const uint8_t>()> in_func,
3864
+ FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code);
3865
+ bool ExecuteCommandLine(const char *cmd_line, Span<const uint8_t> in_buf, Size max_len,
3866
+ HeapArray<uint8_t> *out_buf, int *out_code);
3867
+ static inline bool ExecuteCommandLine(const char *cmd_line, int *out_code) {
3868
+ return ExecuteCommandLine(cmd_line, {}, {}, out_code);
3869
+ }
3870
+ static inline bool ExecuteCommandLine(const char *cmd_line, Span<const uint8_t> in_buf,
3871
+ FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code)
3872
+ {
3873
+ const auto read_once = [&]() {
3874
+ Span<const uint8_t> buf = in_buf;
3875
+ in_buf = {};
3876
+ return buf;
3877
+ };
3878
+
3879
+ return ExecuteCommandLine(cmd_line, read_once, out_func, out_code);
3880
+ }
3881
+ static inline bool ExecuteCommandLine(const char *cmd_line, Span<const char> in_buf,
3882
+ FunctionRef<void(Span<char> buf)> out_func, int *out_code)
3883
+ {
3884
+ const auto write = [&](Span<uint8_t> buf) { out_func(buf.CastAs<char>()); };
3885
+
3886
+ return ExecuteCommandLine(cmd_line, in_buf.CastAs<const uint8_t>(), write, out_code);
3887
+ }
3888
+ static inline bool ExecuteCommandLine(const char *cmd_line, Span<const char> in_buf, Size max_len,
3889
+ HeapArray<char> *out_buf, int *out_code)
3890
+ {
3891
+ return ExecuteCommandLine(cmd_line, in_buf.CastAs<const uint8_t>(), max_len,
3892
+ (HeapArray<uint8_t> *)out_buf, out_code);
3893
+ }
3894
+
3895
+ void WaitDelay(int64_t delay);
3896
+
3897
+ enum class WaitForResult {
3898
+ Interrupt,
3899
+ Message,
3900
+ Timeout
3901
+ };
3902
+
3903
+ // After WaitForInterrupt() has been called once (even with timeout 0), a few
3904
+ // signals (such as SIGINT, SIGHUP) and their Windows equivalent will be permanently ignored.
3905
+ // Beware, on Unix platforms, this may not work correctly if not called from the main thread.
3906
+ WaitForResult WaitForInterrupt(int64_t timeout = -1);
3907
+ void SignalWaitFor();
3908
+
3909
+ int GetCoreCount();
3910
+
3911
+ #ifdef __linux__
3912
+ bool NotifySystemd();
3913
+ #endif
3914
+
3915
+ #ifndef _WIN32
3916
+ #define RG_POSIX_RESTART_EINTR(CallCode, ErrorCond) \
3917
+ ([&]() { \
3918
+ decltype(CallCode) ret; \
3919
+ while ((ret = (CallCode)) ErrorCond && errno == EINTR); \
3920
+ return ret; \
3921
+ })()
3922
+ #endif
3923
+
3924
+ // ------------------------------------------------------------------------
3925
+ // Random
3926
+ // ------------------------------------------------------------------------
3927
+
3928
+ class FastRandom {
3929
+ uint64_t state[4];
3930
+
3931
+ public:
3932
+ FastRandom();
3933
+ FastRandom(uint64_t seed);
3934
+
3935
+ void Fill(void *buf, Size len);
3936
+ void Fill(Span<uint8_t> buf) { Fill(buf.ptr, buf.len); }
3937
+
3938
+ int GetInt(int min, int max);
3939
+
3940
+ private:
3941
+ uint64_t Next();
3942
+ };
3943
+
3944
+ void ZeroMemorySafe(void *ptr, Size len);
3945
+ void FillRandomSafe(void *buf, Size len);
3946
+ static inline void FillRandomSafe(Span<uint8_t> buf) { FillRandomSafe(buf.ptr, buf.len); }
3947
+ int GetRandomIntSafe(int min, int max);
3948
+
3949
+ // ------------------------------------------------------------------------
3950
+ // Sockets
3951
+ // ------------------------------------------------------------------------
3952
+
3953
+ enum class SocketType {
3954
+ Dual,
3955
+ IPv4,
3956
+ IPv6,
3957
+ Unix
3958
+ };
3959
+ static const char *const SocketTypeNames[] = {
3960
+ "Dual",
3961
+ "IPv4",
3962
+ "IPv6",
3963
+ "Unix"
3964
+ };
3965
+
3966
+ int OpenIPSocket(SocketType type, int port);
3967
+ int OpenUnixSocket(const char *path);
3968
+ void CloseSocket(int fd);
3969
+
3970
+ // ------------------------------------------------------------------------
3971
+ // Tasks
3972
+ // ------------------------------------------------------------------------
3973
+
3974
+ class Async {
3975
+ RG_DELETE_COPY(Async)
3976
+
3977
+ bool stop_after_error;
3978
+ std::atomic_bool success {true};
3979
+ std::atomic_int remaining_tasks {0};
3980
+
3981
+ class AsyncPool *pool;
3982
+
3983
+ public:
3984
+ Async(int threads = -1, bool stop_after_error = true);
3985
+ ~Async();
3986
+
3987
+ void Run(const std::function<bool()> &f);
3988
+ bool Sync();
3989
+
3990
+ static bool IsTaskRunning();
3991
+ static int GetWorkerIdx();
3992
+
3993
+ friend class AsyncPool;
3994
+ };
3995
+
3996
+ // ------------------------------------------------------------------------
3997
+ // Fibers
3998
+ // ------------------------------------------------------------------------
3999
+
4000
+ class Fiber {
4001
+ RG_DELETE_COPY(Fiber)
4002
+
4003
+ std::function<bool()> f;
4004
+
4005
+ #ifdef _WIN32
4006
+ void *fiber = nullptr;
4007
+ #else
4008
+ ucontext_t ucp = {};
4009
+ #endif
4010
+
4011
+ bool done = true;
4012
+ bool success = false;
4013
+
4014
+ public:
4015
+ Fiber(const std::function<bool()> &f, Size stack_size = RG_FIBER_DEFAULT_STACK_SIZE);
4016
+ ~Fiber();
4017
+
4018
+ void SwitchTo();
4019
+ bool Finalize();
4020
+
4021
+ static bool SwitchBack();
4022
+
4023
+ private:
4024
+ #if defined(_WIN64)
4025
+ static void FiberCallback(void *udata);
4026
+ #elif defined(_WIN32)
4027
+ static void __stdcall FiberCallback(void *udata);
4028
+ #else
4029
+ static void FiberCallback(unsigned int high, unsigned int low);
4030
+ #endif
4031
+ };
4032
+
4033
+ // ------------------------------------------------------------------------
4034
+ // INI
4035
+ // ------------------------------------------------------------------------
4036
+
4037
+ struct IniProperty {
4038
+ Span<const char> section;
4039
+ Span<const char> key;
4040
+ Span<const char> value;
4041
+ };
4042
+
4043
+ class IniParser {
4044
+ RG_DELETE_COPY(IniParser)
4045
+
4046
+ HeapArray<char> current_section;
4047
+
4048
+ enum class LineType {
4049
+ Section,
4050
+ KeyValue,
4051
+ Exit
4052
+ };
4053
+
4054
+ LineReader reader;
4055
+ bool eof = false;
4056
+ bool error = false;
4057
+
4058
+ public:
4059
+ IniParser(StreamReader *st) : reader(st) {}
4060
+
4061
+ const char *GetFileName() const { return reader.GetFileName(); }
4062
+ bool IsValid() const { return !error; }
4063
+ bool IsEOF() const { return eof; }
4064
+
4065
+ bool Next(IniProperty *out_prop);
4066
+ bool NextInSection(IniProperty *out_prop);
4067
+
4068
+ void PushLogFilter() { reader.PushLogFilter(); }
4069
+
4070
+ private:
4071
+ LineType FindNextLine(IniProperty *out_prop);
4072
+ };
4073
+
4074
+ // ------------------------------------------------------------------------
4075
+ // Assets
4076
+ // ------------------------------------------------------------------------
4077
+
4078
+ // Keep in sync with version in packer.cc
4079
+ struct AssetInfo {
4080
+ const char *name;
4081
+ CompressionType compression_type;
4082
+ Span<const uint8_t> data;
4083
+
4084
+ const char *source_map;
4085
+
4086
+ RG_HASHTABLE_HANDLER(AssetInfo, name);
4087
+ };
4088
+
4089
+ #ifdef FELIX_HOT_ASSETS
4090
+
4091
+ bool ReloadAssets();
4092
+ Span<const AssetInfo> GetPackedAssets();
4093
+ const AssetInfo *FindPackedAsset(const char *name);
4094
+
4095
+ #else
4096
+
4097
+ // Reserved for internal use
4098
+ void InitPackedMap(Span<const AssetInfo> assets);
4099
+
4100
+ extern "C" const Span<const AssetInfo> PackedAssets;
4101
+ extern HashTable<const char *, const AssetInfo *> PackedAssets_map;
4102
+
4103
+ // By definining functions here (with static inline), we don't need PackedAssets
4104
+ // to exist unless these functions are called. It also allows the compiler to remove
4105
+ // calls to ReloadAssets in non-debug builds (LTO or not).
4106
+
4107
+ static inline bool ReloadAssets()
4108
+ {
4109
+ return false;
4110
+ }
4111
+
4112
+ static inline Span<const AssetInfo> GetPackedAssets()
4113
+ {
4114
+ return PackedAssets;
4115
+ }
4116
+
4117
+ static inline const AssetInfo *FindPackedAsset(const char *name)
4118
+ {
4119
+ InitPackedMap(PackedAssets);
4120
+ return PackedAssets_map.FindValue(name, nullptr);
4121
+ }
4122
+
4123
+ #endif
4124
+
4125
+ Span<const uint8_t> PatchAsset(const AssetInfo &asset, Allocator *alloc,
4126
+ FunctionRef<void(const char *, StreamWriter *)> func);
4127
+
4128
+ // ------------------------------------------------------------------------
4129
+ // Options
4130
+ // ------------------------------------------------------------------------
4131
+
4132
+ struct OptionDesc {
4133
+ const char *name;
4134
+ const char *help;
4135
+ };
4136
+
4137
+ enum class OptionType {
4138
+ NoValue,
4139
+ Value,
4140
+ OptionalValue
4141
+ };
4142
+
4143
+ class OptionParser {
4144
+ RG_DELETE_COPY(OptionParser)
4145
+
4146
+ Span<const char *> args;
4147
+ unsigned int flags;
4148
+
4149
+ Size pos = 0;
4150
+ Size limit;
4151
+ Size smallopt_offset = 0;
4152
+ char buf[80];
4153
+
4154
+ bool test_failed = false;
4155
+
4156
+ public:
4157
+ enum class Flag {
4158
+ SkipNonOptions = 1 << 0
4159
+ };
4160
+
4161
+ const char *current_option = nullptr;
4162
+ const char *current_value = nullptr;
4163
+
4164
+ OptionParser(Span<const char *> args, unsigned int flags = 0)
4165
+ : args(args), flags(flags), limit(args.len) {}
4166
+ OptionParser(int argc, char **argv, unsigned int flags = 0)
4167
+ : args(argc > 0 ? (const char **)(argv + 1) : nullptr, std::max(0, argc - 1)),
4168
+ flags(flags), limit(args.len) {}
4169
+
4170
+ const char *Next();
4171
+
4172
+ const char *ConsumeValue();
4173
+ const char *ConsumeNonOption();
4174
+ void ConsumeNonOptions(HeapArray<const char *> *non_options);
4175
+
4176
+ Span<const char *> GetRemainingArguments() const { return args.Take(pos, args.len - pos); }
4177
+
4178
+ bool Test(const char *test1, const char *test2, OptionType type = OptionType::NoValue);
4179
+ bool Test(const char *test1, OptionType type = OptionType::NoValue)
4180
+ { return Test(test1, nullptr, type); }
4181
+
4182
+ bool TestHasFailed() const { return test_failed; }
4183
+ void LogUnknownError() const;
4184
+ };
4185
+
4186
+ template <typename T>
4187
+ bool OptionToEnum(Span<const char *const> options, Span<const char> str, T *out_value)
4188
+ {
4189
+ for (Size i = 0; i < options.len; i++) {
4190
+ const char *opt = options[i];
4191
+
4192
+ if (TestStr(opt, str)) {
4193
+ *out_value = (T)i;
4194
+ return true;
4195
+ }
4196
+ }
4197
+
4198
+ return false;
4199
+ }
4200
+
4201
+ template <typename T>
4202
+ bool OptionToEnum(Span<const OptionDesc> options, Span<const char> str, T *out_value)
4203
+ {
4204
+ for (Size i = 0; i < options.len; i++) {
4205
+ const OptionDesc &desc = options[i];
4206
+
4207
+ if (TestStr(desc.name, str)) {
4208
+ *out_value = (T)i;
4209
+ return true;
4210
+ }
4211
+ }
4212
+
4213
+ return false;
4214
+ }
4215
+
4216
+ template <typename T>
4217
+ bool OptionToFlag(Span<const char *const> options, Span<const char> str, T *out_flags, bool enable = true)
4218
+ {
4219
+ for (Size i = 0; i < options.len; i++) {
4220
+ const char *opt = options[i];
4221
+
4222
+ if (TestStr(opt, str)) {
4223
+ *out_flags = ApplyMask(*out_flags, 1u << i, enable);
4224
+ return true;
4225
+ }
4226
+ }
4227
+
4228
+ return false;
4229
+ }
4230
+
4231
+ template <typename T>
4232
+ bool OptionToFlag(Span<const OptionDesc> options, Span<const char> str, T *out_flags, bool enable = true)
4233
+ {
4234
+ for (Size i = 0; i < options.len; i++) {
4235
+ const OptionDesc &desc = options[i];
4236
+
4237
+ if (TestStr(desc.name, str)) {
4238
+ *out_flags = ApplyMask(*out_flags, 1u << i, enable);
4239
+ return true;
4240
+ }
4241
+ }
4242
+
4243
+ return false;
4244
+ }
4245
+
4246
+ // ------------------------------------------------------------------------
4247
+ // Console prompter (simplified readline)
4248
+ // ------------------------------------------------------------------------
4249
+
4250
+ class ConsolePrompter {
4251
+ int prompt_columns = 0;
4252
+
4253
+ HeapArray<HeapArray<char>> entries;
4254
+ Size entry_idx = 0;
4255
+ Size str_offset = 0;
4256
+
4257
+ int columns = 0;
4258
+ int rows = 0;
4259
+ int rows_with_extra = 0;
4260
+ int x = 0;
4261
+ int y = 0;
4262
+
4263
+ const char *fake_input = "";
4264
+ #ifdef _WIN32
4265
+ uint32_t surrogate_buf = 0;
4266
+ #endif
4267
+
4268
+ public:
4269
+ const char *prompt = ">>> ";
4270
+ const char *mask = nullptr;
4271
+
4272
+ HeapArray<char> str;
4273
+
4274
+ ConsolePrompter();
4275
+
4276
+ bool Read(Span<const char> *out_str = nullptr);
4277
+ bool ReadYN(bool *out_value);
4278
+
4279
+ void Commit();
4280
+
4281
+ private:
4282
+ bool ReadRaw(Span<const char> *out_str);
4283
+ bool ReadRawYN(bool *out_value);
4284
+ bool ReadBuffered(Span<const char> *out_str);
4285
+ bool ReadBufferedYN(bool *out_value);
4286
+
4287
+ void ChangeEntry(Size new_idx);
4288
+
4289
+ Size SkipForward(Size offset, Size count);
4290
+ Size SkipBackward(Size offset, Size count);
4291
+ Size FindForward(Size offset, const char *chars);
4292
+ Size FindBackward(Size offset, const char *chars);
4293
+
4294
+ void Delete(Size start, Size end);
4295
+
4296
+ void RenderRaw();
4297
+ void RenderBuffered();
4298
+
4299
+ Vec2<int> GetConsoleSize();
4300
+ int32_t ReadChar();
4301
+
4302
+ int ComputeWidth(Span<const char> str);
4303
+
4304
+ void EnsureNulTermination();
4305
+ };
4306
+
4307
+ const char *Prompt(const char *prompt, const char *default_value, const char *mask, Allocator *alloc);
4308
+ static inline const char *Prompt(const char *prompt, Allocator *alloc)
4309
+ { return Prompt(prompt, nullptr, nullptr, alloc); }
4310
+ bool PromptYN(const char *prompt, bool *out_value);
4311
+
4312
+ }