koffi 0.9.1 → 0.9.2
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.
- package/CMakeLists.txt +2 -36
- package/build/ALL_BUILD.vcxproj +4 -8
- package/build/CMakeCache.txt +1 -13
- package/build/CMakeFiles/3.23.0-rc1/CMakeDetermineCompilerABI_C.bin +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeDetermineCompilerABI_CXX.bin +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/CompilerIdC.exe +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CMakeCCompilerId.obj +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/CompilerIdCXX.exe +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CMakeCXXCompilerId.obj +0 -0
- package/build/CMakeFiles/CMakeOutput.log +14 -14
- package/build/CMakeFiles/TargetDirectories.txt +0 -1
- package/build/CMakeFiles/generate.stamp.depend +81 -0
- package/build/Release/koffi.node +0 -0
- package/build/ZERO_CHECK.vcxproj +4 -4
- package/build/cmake_install.cmake +1 -1
- package/build/koffi.dir/Release/call_arm64.obj +0 -0
- package/build/koffi.dir/Release/call_x64_sysv.obj +0 -0
- package/build/koffi.dir/Release/call_x64_win.obj +0 -0
- package/build/koffi.dir/Release/call_x64_win_fwd.obj +0 -0
- package/build/koffi.dir/Release/call_x86.obj +0 -0
- package/build/koffi.dir/Release/ffi.obj +0 -0
- package/build/koffi.dir/Release/koffi.tlog/CL.command.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/CL.read.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/CL.write.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/CustomBuild.read.1.tlog +81 -0
- package/build/koffi.dir/Release/koffi.tlog/koffi.write.1u.tlog +0 -0
- package/build/koffi.dir/Release/libcc.obj +0 -0
- package/build/koffi.dir/Release/util.obj +0 -0
- package/build/koffi.dir/Release/win_delay_load_hook.obj +0 -0
- package/build/koffi.sln +0 -14
- package/build/koffi.vcxproj +21 -21
- package/build/koffi.vcxproj.filters +1 -1
- package/build/x64/Release/ALL_BUILD/ALL_BUILD.recipe +0 -3
- package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.read.1.tlog +81 -0
- package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.read.1.tlog +81 -0
- package/package.json +1 -1
- package/vendor/dragonbox/CMakeLists.txt +123 -0
- package/vendor/dragonbox/LICENSE-Apache2-LLVM +218 -0
- package/vendor/dragonbox/LICENSE-Boost +23 -0
- package/vendor/dragonbox/README.md +277 -0
- package/vendor/dragonbox/cmake/dragonboxConfig.cmake +1 -0
- package/vendor/dragonbox/include/dragonbox/dragonbox.h +2670 -0
- package/vendor/dragonbox/include/dragonbox/dragonbox_to_chars.h +108 -0
- package/vendor/dragonbox/other_files/Dragonbox.pdf +0 -0
- package/vendor/dragonbox/other_files/Dragonbox_old.pdf +0 -0
- package/vendor/dragonbox/other_files/milo_benchmark.png +0 -0
- package/vendor/dragonbox/other_files/unknown_win64_vc2019.html +540 -0
- package/vendor/dragonbox/other_files/unknown_win64_vc2019_randomdigit_time.png +0 -0
- package/vendor/dragonbox/source/dragonbox_to_chars.cpp +303 -0
- package/vendor/dragonbox/subproject/3rdparty/grisu_exact/CMakeLists.txt +24 -0
- package/vendor/dragonbox/subproject/3rdparty/grisu_exact/fp_to_chars.cpp +238 -0
- package/vendor/dragonbox/subproject/3rdparty/grisu_exact/fp_to_chars.h +95 -0
- package/vendor/dragonbox/subproject/3rdparty/grisu_exact/grisu_exact.h +2666 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/CMakeLists.txt +16 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/common.h +114 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/d2s.c +509 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/d2s_full_table.h +367 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/d2s_intrinsics.h +357 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/digit_table.h +35 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/f2s.c +345 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/f2s_full_table.h +55 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/f2s_intrinsics.h +128 -0
- package/vendor/dragonbox/subproject/3rdparty/ryu/ryu/ryu.h +46 -0
- package/vendor/dragonbox/subproject/3rdparty/schubfach/CMakeLists.txt +22 -0
- package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_32.cc +699 -0
- package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_32.h +31 -0
- package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_64.cc +1354 -0
- package/vendor/dragonbox/subproject/3rdparty/schubfach/schubfach_64.h +31 -0
- package/vendor/dragonbox/subproject/3rdparty/shaded_plots/example_shaded_plots.m +68 -0
- package/vendor/dragonbox/subproject/3rdparty/shaded_plots/license.txt +25 -0
- package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_distribution.m +92 -0
- package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_distribution_prctile.m +121 -0
- package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_histogram_shaded.m +99 -0
- package/vendor/dragonbox/subproject/3rdparty/shaded_plots/plot_shaded.m +93 -0
- package/vendor/dragonbox/subproject/benchmark/CMakeLists.txt +65 -0
- package/vendor/dragonbox/subproject/benchmark/include/benchmark.h +40 -0
- package/vendor/dragonbox/subproject/benchmark/matlab/plot_benchmarks.m +22 -0
- package/vendor/dragonbox/subproject/benchmark/matlab/plot_digit_benchmark.m +78 -0
- package/vendor/dragonbox/subproject/benchmark/matlab/plot_uniform_benchmark.m +95 -0
- package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary32_clang.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary32_msvc.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary64_clang.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/results/digits_benchmark_binary64_msvc.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary32_clang.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary32_msvc.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary64_clang.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/results/uniform_benchmark_binary64_msvc.png +0 -0
- package/vendor/dragonbox/subproject/benchmark/source/benchmark.cpp +238 -0
- package/vendor/dragonbox/subproject/benchmark/source/dragonbox.cpp +30 -0
- package/vendor/dragonbox/subproject/benchmark/source/grisu_exact.cpp +36 -0
- package/vendor/dragonbox/subproject/benchmark/source/ryu.cpp +27 -0
- package/vendor/dragonbox/subproject/benchmark/source/schubfach.cpp +31 -0
- package/vendor/dragonbox/subproject/common/CMakeLists.txt +42 -0
- package/vendor/dragonbox/subproject/common/include/best_rational_approx.h +97 -0
- package/vendor/dragonbox/subproject/common/include/big_uint.h +218 -0
- package/vendor/dragonbox/subproject/common/include/continued_fractions.h +174 -0
- package/vendor/dragonbox/subproject/common/include/good_rational_approx.h +267 -0
- package/vendor/dragonbox/subproject/common/include/random_float.h +182 -0
- package/vendor/dragonbox/subproject/common/include/rational_continued_fractions.h +57 -0
- package/vendor/dragonbox/subproject/common/source/big_uint.cpp +602 -0
- package/vendor/dragonbox/subproject/meta/CMakeLists.txt +41 -0
- package/vendor/dragonbox/subproject/meta/results/binary32_generated_cache.txt +82 -0
- package/vendor/dragonbox/subproject/meta/results/binary64_compressed_cache_error_table.txt +10 -0
- package/vendor/dragonbox/subproject/meta/results/binary64_generated_cache.txt +623 -0
- package/vendor/dragonbox/subproject/meta/source/generate_cache.cpp +126 -0
- package/vendor/dragonbox/subproject/meta/source/live_test.cpp +81 -0
- package/vendor/dragonbox/subproject/meta/source/perf_test.cpp +104 -0
- package/vendor/dragonbox/subproject/meta/source/sandbox.cpp +20 -0
- package/vendor/dragonbox/subproject/test/CMakeLists.txt +70 -0
- package/vendor/dragonbox/subproject/test/results/binary32.csv +255 -0
- package/vendor/dragonbox/subproject/test/results/binary64.csv +2047 -0
- package/vendor/dragonbox/subproject/test/results/plot_required_bits.m +18 -0
- package/vendor/dragonbox/subproject/test/source/test_all_shorter_interval_cases.cpp +88 -0
- package/vendor/dragonbox/subproject/test/source/uniform_random_test.cpp +95 -0
- package/vendor/dragonbox/subproject/test/source/verify_cache_precision.cpp +338 -0
- package/vendor/dragonbox/subproject/test/source/verify_compressed_cache.cpp +154 -0
- package/vendor/dragonbox/subproject/test/source/verify_fast_multiplication.cpp +168 -0
- package/vendor/dragonbox/subproject/test/source/verify_log_computation.cpp +251 -0
- package/vendor/dragonbox/subproject/test/source/verify_magic_division.cpp +113 -0
- package/vendor/libcc/libcc.cc +7651 -0
- package/vendor/libcc/libcc.hh +4312 -0
- package/vendor/node-addon-api/CHANGELOG.md +859 -0
- package/vendor/node-addon-api/CODE_OF_CONDUCT.md +4 -0
- package/vendor/node-addon-api/CONTRIBUTING.md +93 -0
- package/vendor/node-addon-api/LICENSE.md +13 -0
- package/vendor/node-addon-api/README.md +293 -0
- package/vendor/node-addon-api/appveyor.yml +37 -0
- package/vendor/node-addon-api/benchmark/README.md +47 -0
- package/vendor/node-addon-api/benchmark/binding.gyp +25 -0
- package/vendor/node-addon-api/benchmark/function_args.cc +217 -0
- package/vendor/node-addon-api/benchmark/function_args.js +60 -0
- package/vendor/node-addon-api/benchmark/index.js +34 -0
- package/vendor/node-addon-api/benchmark/property_descriptor.cc +91 -0
- package/vendor/node-addon-api/benchmark/property_descriptor.js +37 -0
- package/vendor/node-addon-api/common.gypi +21 -0
- package/vendor/node-addon-api/doc/addon.md +163 -0
- package/vendor/node-addon-api/doc/array.md +81 -0
- package/vendor/node-addon-api/doc/array_buffer.md +155 -0
- package/vendor/node-addon-api/doc/async_context.md +86 -0
- package/vendor/node-addon-api/doc/async_operations.md +31 -0
- package/vendor/node-addon-api/doc/async_worker.md +427 -0
- package/vendor/node-addon-api/doc/async_worker_variants.md +557 -0
- package/vendor/node-addon-api/doc/bigint.md +97 -0
- package/vendor/node-addon-api/doc/boolean.md +68 -0
- package/vendor/node-addon-api/doc/buffer.md +150 -0
- package/vendor/node-addon-api/doc/callback_scope.md +54 -0
- package/vendor/node-addon-api/doc/callbackinfo.md +97 -0
- package/vendor/node-addon-api/doc/checker-tool.md +32 -0
- package/vendor/node-addon-api/doc/class_property_descriptor.md +115 -0
- package/vendor/node-addon-api/doc/cmake-js.md +68 -0
- package/vendor/node-addon-api/doc/conversion-tool.md +28 -0
- package/vendor/node-addon-api/doc/creating_a_release.md +62 -0
- package/vendor/node-addon-api/doc/dataview.md +248 -0
- package/vendor/node-addon-api/doc/date.md +68 -0
- package/vendor/node-addon-api/doc/env.md +196 -0
- package/vendor/node-addon-api/doc/error.md +120 -0
- package/vendor/node-addon-api/doc/error_handling.md +254 -0
- package/vendor/node-addon-api/doc/escapable_handle_scope.md +80 -0
- package/vendor/node-addon-api/doc/external.md +63 -0
- package/vendor/node-addon-api/doc/function.md +402 -0
- package/vendor/node-addon-api/doc/function_reference.md +238 -0
- package/vendor/node-addon-api/doc/generator.md +13 -0
- package/vendor/node-addon-api/doc/handle_scope.md +63 -0
- package/vendor/node-addon-api/doc/hierarchy.md +91 -0
- package/vendor/node-addon-api/doc/instance_wrap.md +408 -0
- package/vendor/node-addon-api/doc/maybe.md +76 -0
- package/vendor/node-addon-api/doc/memory_management.md +27 -0
- package/vendor/node-addon-api/doc/name.md +29 -0
- package/vendor/node-addon-api/doc/node-gyp.md +82 -0
- package/vendor/node-addon-api/doc/number.md +163 -0
- package/vendor/node-addon-api/doc/object.md +432 -0
- package/vendor/node-addon-api/doc/object_lifetime_management.md +83 -0
- package/vendor/node-addon-api/doc/object_reference.md +117 -0
- package/vendor/node-addon-api/doc/object_wrap.md +561 -0
- package/vendor/node-addon-api/doc/prebuild_tools.md +16 -0
- package/vendor/node-addon-api/doc/promises.md +79 -0
- package/vendor/node-addon-api/doc/property_descriptor.md +286 -0
- package/vendor/node-addon-api/doc/propertylvalue.md +50 -0
- package/vendor/node-addon-api/doc/range_error.md +59 -0
- package/vendor/node-addon-api/doc/reference.md +113 -0
- package/vendor/node-addon-api/doc/setup.md +110 -0
- package/vendor/node-addon-api/doc/string.md +93 -0
- package/vendor/node-addon-api/doc/symbol.md +61 -0
- package/vendor/node-addon-api/doc/threadsafe.md +121 -0
- package/vendor/node-addon-api/doc/threadsafe_function.md +290 -0
- package/vendor/node-addon-api/doc/type_error.md +59 -0
- package/vendor/node-addon-api/doc/typed_array.md +78 -0
- package/vendor/node-addon-api/doc/typed_array_of.md +137 -0
- package/vendor/node-addon-api/doc/typed_threadsafe_function.md +306 -0
- package/vendor/node-addon-api/doc/value.md +340 -0
- package/vendor/node-addon-api/doc/version_management.md +43 -0
- package/vendor/node-addon-api/except.gypi +25 -0
- package/vendor/node-addon-api/index.js +11 -0
- package/vendor/node-addon-api/napi-inl.deprecated.h +192 -0
- package/vendor/node-addon-api/napi-inl.h +6209 -0
- package/vendor/node-addon-api/napi.h +2983 -0
- package/vendor/node-addon-api/node_api.gyp +9 -0
- package/vendor/node-addon-api/noexcept.gypi +26 -0
- package/vendor/node-addon-api/nothing.c +0 -0
- package/vendor/node-addon-api/package-support.json +21 -0
- package/vendor/node-addon-api/package.json +399 -0
- package/vendor/node-addon-api/test/README.md +91 -0
- package/vendor/node-addon-api/test/addon.cc +36 -0
- package/vendor/node-addon-api/test/addon.js +11 -0
- package/vendor/node-addon-api/test/addon_build/index.js +49 -0
- package/vendor/node-addon-api/test/addon_build/tpl/addon.cc +17 -0
- package/vendor/node-addon-api/test/addon_build/tpl/binding.gyp +62 -0
- package/vendor/node-addon-api/test/addon_build/tpl/index.js +9 -0
- package/vendor/node-addon-api/test/addon_build/tpl/package.json +11 -0
- package/vendor/node-addon-api/test/addon_data.cc +99 -0
- package/vendor/node-addon-api/test/addon_data.js +46 -0
- package/vendor/node-addon-api/test/array_buffer.cc +243 -0
- package/vendor/node-addon-api/test/array_buffer.js +69 -0
- package/vendor/node-addon-api/test/async_context.cc +21 -0
- package/vendor/node-addon-api/test/async_context.js +86 -0
- package/vendor/node-addon-api/test/async_progress_queue_worker.cc +83 -0
- package/vendor/node-addon-api/test/async_progress_queue_worker.js +46 -0
- package/vendor/node-addon-api/test/async_progress_worker.cc +134 -0
- package/vendor/node-addon-api/test/async_progress_worker.js +61 -0
- package/vendor/node-addon-api/test/async_worker.cc +106 -0
- package/vendor/node-addon-api/test/async_worker.js +179 -0
- package/vendor/node-addon-api/test/async_worker_nocallback.js +13 -0
- package/vendor/node-addon-api/test/async_worker_persistent.cc +63 -0
- package/vendor/node-addon-api/test/async_worker_persistent.js +24 -0
- package/vendor/node-addon-api/test/basic_types/array.cc +40 -0
- package/vendor/node-addon-api/test/basic_types/array.js +35 -0
- package/vendor/node-addon-api/test/basic_types/boolean.cc +38 -0
- package/vendor/node-addon-api/test/basic_types/boolean.js +35 -0
- package/vendor/node-addon-api/test/basic_types/number.cc +99 -0
- package/vendor/node-addon-api/test/basic_types/number.js +114 -0
- package/vendor/node-addon-api/test/basic_types/value.cc +120 -0
- package/vendor/node-addon-api/test/basic_types/value.js +133 -0
- package/vendor/node-addon-api/test/bigint.cc +91 -0
- package/vendor/node-addon-api/test/bigint.js +53 -0
- package/vendor/node-addon-api/test/binding-swallowexcept.cc +12 -0
- package/vendor/node-addon-api/test/binding.cc +171 -0
- package/vendor/node-addon-api/test/binding.gyp +117 -0
- package/vendor/node-addon-api/test/buffer.cc +183 -0
- package/vendor/node-addon-api/test/buffer.js +69 -0
- package/vendor/node-addon-api/test/callbackscope.cc +22 -0
- package/vendor/node-addon-api/test/callbackscope.js +49 -0
- package/vendor/node-addon-api/test/common/index.js +113 -0
- package/vendor/node-addon-api/test/common/test_helper.h +61 -0
- package/vendor/node-addon-api/test/dataview/dataview.cc +48 -0
- package/vendor/node-addon-api/test/dataview/dataview.js +35 -0
- package/vendor/node-addon-api/test/dataview/dataview_read_write.cc +115 -0
- package/vendor/node-addon-api/test/dataview/dataview_read_write.js +90 -0
- package/vendor/node-addon-api/test/date.cc +44 -0
- package/vendor/node-addon-api/test/date.js +18 -0
- package/vendor/node-addon-api/test/env_cleanup.cc +88 -0
- package/vendor/node-addon-api/test/env_cleanup.js +56 -0
- package/vendor/node-addon-api/test/error.cc +287 -0
- package/vendor/node-addon-api/test/error.js +81 -0
- package/vendor/node-addon-api/test/error_handling_for_primitives.cc +13 -0
- package/vendor/node-addon-api/test/error_handling_for_primitives.js +29 -0
- package/vendor/node-addon-api/test/error_terminating_environment.js +94 -0
- package/vendor/node-addon-api/test/external.cc +81 -0
- package/vendor/node-addon-api/test/external.js +88 -0
- package/vendor/node-addon-api/test/function.cc +295 -0
- package/vendor/node-addon-api/test/function.js +121 -0
- package/vendor/node-addon-api/test/function_reference.cc +202 -0
- package/vendor/node-addon-api/test/function_reference.js +157 -0
- package/vendor/node-addon-api/test/globalObject/global_object.cc +61 -0
- package/vendor/node-addon-api/test/globalObject/global_object_delete_property.cc +31 -0
- package/vendor/node-addon-api/test/globalObject/global_object_delete_property.js +61 -0
- package/vendor/node-addon-api/test/globalObject/global_object_get_property.cc +40 -0
- package/vendor/node-addon-api/test/globalObject/global_object_get_property.js +57 -0
- package/vendor/node-addon-api/test/globalObject/global_object_has_own_property.cc +28 -0
- package/vendor/node-addon-api/test/globalObject/global_object_has_own_property.js +48 -0
- package/vendor/node-addon-api/test/globalObject/global_object_set_property.cc +31 -0
- package/vendor/node-addon-api/test/globalObject/global_object_set_property.js +58 -0
- package/vendor/node-addon-api/test/handlescope.cc +60 -0
- package/vendor/node-addon-api/test/handlescope.js +14 -0
- package/vendor/node-addon-api/test/index.js +136 -0
- package/vendor/node-addon-api/test/maybe/check.cc +23 -0
- package/vendor/node-addon-api/test/maybe/index.js +38 -0
- package/vendor/node-addon-api/test/memory_management.cc +17 -0
- package/vendor/node-addon-api/test/memory_management.js +9 -0
- package/vendor/node-addon-api/test/movable_callbacks.cc +23 -0
- package/vendor/node-addon-api/test/movable_callbacks.js +21 -0
- package/vendor/node-addon-api/test/name.cc +108 -0
- package/vendor/node-addon-api/test/name.js +59 -0
- package/vendor/node-addon-api/test/napi_child.js +14 -0
- package/vendor/node-addon-api/test/object/delete_property.cc +38 -0
- package/vendor/node-addon-api/test/object/delete_property.js +41 -0
- package/vendor/node-addon-api/test/object/finalizer.cc +29 -0
- package/vendor/node-addon-api/test/object/finalizer.js +28 -0
- package/vendor/node-addon-api/test/object/get_property.cc +34 -0
- package/vendor/node-addon-api/test/object/get_property.js +40 -0
- package/vendor/node-addon-api/test/object/has_own_property.cc +34 -0
- package/vendor/node-addon-api/test/object/has_own_property.js +34 -0
- package/vendor/node-addon-api/test/object/has_property.cc +38 -0
- package/vendor/node-addon-api/test/object/has_property.js +37 -0
- package/vendor/node-addon-api/test/object/object.cc +348 -0
- package/vendor/node-addon-api/test/object/object.js +217 -0
- package/vendor/node-addon-api/test/object/object_deprecated.cc +66 -0
- package/vendor/node-addon-api/test/object/object_deprecated.js +47 -0
- package/vendor/node-addon-api/test/object/object_freeze_seal.cc +25 -0
- package/vendor/node-addon-api/test/object/object_freeze_seal.js +61 -0
- package/vendor/node-addon-api/test/object/set_property.cc +37 -0
- package/vendor/node-addon-api/test/object/set_property.js +29 -0
- package/vendor/node-addon-api/test/object/subscript_operator.cc +42 -0
- package/vendor/node-addon-api/test/object/subscript_operator.js +17 -0
- package/vendor/node-addon-api/test/object_reference.cc +219 -0
- package/vendor/node-addon-api/test/object_reference.js +259 -0
- package/vendor/node-addon-api/test/objectwrap.cc +268 -0
- package/vendor/node-addon-api/test/objectwrap.js +284 -0
- package/vendor/node-addon-api/test/objectwrap_constructor_exception.cc +26 -0
- package/vendor/node-addon-api/test/objectwrap_constructor_exception.js +18 -0
- package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.cc +30 -0
- package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.js +13 -0
- package/vendor/node-addon-api/test/objectwrap_removewrap.cc +45 -0
- package/vendor/node-addon-api/test/objectwrap_removewrap.js +40 -0
- package/vendor/node-addon-api/test/objectwrap_worker_thread.js +19 -0
- package/vendor/node-addon-api/test/promise.cc +29 -0
- package/vendor/node-addon-api/test/promise.js +18 -0
- package/vendor/node-addon-api/test/reference.cc +24 -0
- package/vendor/node-addon-api/test/reference.js +14 -0
- package/vendor/node-addon-api/test/run_script.cc +56 -0
- package/vendor/node-addon-api/test/run_script.js +45 -0
- package/vendor/node-addon-api/test/symbol.cc +79 -0
- package/vendor/node-addon-api/test/symbol.js +73 -0
- package/vendor/node-addon-api/test/testUtil.js +54 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.cc +195 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.js +188 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.cc +63 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.js +12 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.cc +115 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.js +14 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.cc +26 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.js +7 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.cc +225 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.js +59 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.cc +42 -0
- package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.js +53 -0
- package/vendor/node-addon-api/test/thunking_manual.cc +140 -0
- package/vendor/node-addon-api/test/thunking_manual.js +17 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.cc +215 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.js +188 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.cc +68 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.js +12 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_existing_tsfn.cc +127 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_existing_tsfn.js +14 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.cc +28 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.js +7 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_sum.cc +237 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_sum.js +59 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.cc +53 -0
- package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.js +53 -0
- package/vendor/node-addon-api/test/typedarray-bigint.js +58 -0
- package/vendor/node-addon-api/test/typedarray.cc +216 -0
- package/vendor/node-addon-api/test/typedarray.js +69 -0
- package/vendor/node-addon-api/test/version_management.cc +27 -0
- package/vendor/node-addon-api/test/version_management.js +31 -0
- package/vendor/node-addon-api/tools/README.md +73 -0
- package/vendor/node-addon-api/tools/check-napi.js +100 -0
- package/vendor/node-addon-api/tools/clang-format.js +68 -0
- package/vendor/node-addon-api/tools/conversion.js +309 -0
- package/vendor/node-addon-api/tools/eslint-format.js +71 -0
- package/build/Raylib.dir/Release/Raylib.dll.recipe +0 -14
- package/build/Raylib.dir/Release/Raylib.tlog/CL.command.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CL.read.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CL.write.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.command.1.tlog +0 -10
- package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.read.1.tlog +0 -27
- package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.write.1.tlog +0 -2
- package/build/Raylib.dir/Release/Raylib.tlog/Raylib.lastbuildstate +0 -2
- package/build/Raylib.dir/Release/Raylib.tlog/Raylib.write.1u.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/link.command.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/link.read.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/link.write.1.tlog +0 -0
- package/build/Raylib.dir/Release/raudio.obj +0 -0
- package/build/Raylib.dir/Release/rcore.obj +0 -0
- package/build/Raylib.dir/Release/rglfw.obj +0 -0
- package/build/Raylib.dir/Release/rmodels.obj +0 -0
- package/build/Raylib.dir/Release/rshapes.obj +0 -0
- package/build/Raylib.dir/Release/rtext.obj +0 -0
- package/build/Raylib.dir/Release/rtextures.obj +0 -0
- package/build/Raylib.dir/Release/utils.obj +0 -0
- package/build/Raylib.vcxproj +0 -358
- package/build/Raylib.vcxproj.filters +0 -37
- package/build/Release/Raylib.dll +0 -0
- package/build/Release/Raylib.exp +0 -0
- package/build/Release/Raylib.lib +0 -0
|
@@ -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
|
+
}
|