koffi 2.1.0 → 2.1.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.
Files changed (313) hide show
  1. package/ChangeLog.md +13 -1
  2. package/build/qemu/2.1.2/koffi_darwin_arm64.tar.gz +0 -0
  3. package/build/qemu/2.1.2/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/2.1.2/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/2.1.2/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/2.1.2/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/2.1.2/koffi_linux_arm32hf.tar.gz +0 -0
  8. package/build/qemu/2.1.2/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/2.1.2/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/2.1.2/koffi_linux_riscv64hf64.tar.gz +0 -0
  11. package/build/qemu/2.1.2/koffi_linux_x64.tar.gz +0 -0
  12. package/build/qemu/2.1.2/koffi_openbsd_ia32.tar.gz +0 -0
  13. package/build/qemu/2.1.2/koffi_openbsd_x64.tar.gz +0 -0
  14. package/build/qemu/2.1.2/koffi_win32_arm64.tar.gz +0 -0
  15. package/build/qemu/2.1.2/koffi_win32_ia32.tar.gz +0 -0
  16. package/build/qemu/2.1.2/koffi_win32_x64.tar.gz +0 -0
  17. package/doc/templates/badges.html +3 -0
  18. package/package.json +2 -2
  19. package/src/abi_arm64.cc +35 -1
  20. package/src/abi_x64_win.cc +2 -8
  21. package/src/abi_x86.cc +1 -7
  22. package/src/call.cc +2 -2
  23. package/src/call.hh +1 -1
  24. package/src/ffi.hh +1 -1
  25. package/src/util.hh +6 -0
  26. package/test/raylib.js +37 -5
  27. package/vendor/libcc/libcc.cc +488 -254
  28. package/vendor/libcc/libcc.hh +1463 -1277
  29. package/vendor/raylib/BINDINGS.md +87 -70
  30. package/vendor/raylib/CHANGELOG +263 -50
  31. package/vendor/raylib/CMakeLists.txt +12 -0
  32. package/vendor/raylib/CMakeOptions.txt +8 -1
  33. package/vendor/raylib/CONVENTIONS.md +2 -3
  34. package/vendor/raylib/FAQ.md +137 -0
  35. package/vendor/raylib/HISTORY.md +62 -29
  36. package/vendor/raylib/LICENSE +1 -1
  37. package/vendor/raylib/README.md +22 -17
  38. package/vendor/raylib/ROADMAP.md +8 -7
  39. package/vendor/raylib/cmake/CompileDefinitions.cmake +19 -15
  40. package/vendor/raylib/cmake/GlfwImport.cmake +2 -0
  41. package/vendor/raylib/cmake/LibraryConfigurations.cmake +22 -16
  42. package/vendor/raylib/cmake/raylib-config.cmake +52 -49
  43. package/vendor/raylib/examples/CMakeLists.txt +14 -9
  44. package/vendor/raylib/examples/Makefile +112 -125
  45. package/vendor/raylib/examples/Makefile.Android +1 -1
  46. package/vendor/raylib/examples/Makefile.Web +145 -158
  47. package/vendor/raylib/examples/README.md +141 -141
  48. package/vendor/raylib/examples/audio/audio_module_playing.c +9 -4
  49. package/vendor/raylib/examples/audio/audio_multichannel_sound.c +8 -3
  50. package/vendor/raylib/examples/audio/audio_music_stream.c +16 -11
  51. package/vendor/raylib/examples/audio/audio_raw_stream.c +57 -9
  52. package/vendor/raylib/examples/audio/audio_sound_loading.c +8 -3
  53. package/vendor/raylib/examples/audio/audio_stream_effects.c +179 -0
  54. package/vendor/raylib/examples/audio/audio_stream_effects.png +0 -0
  55. package/vendor/raylib/examples/build.zig +17 -6
  56. package/vendor/raylib/examples/core/core_2d_camera.c +8 -4
  57. package/vendor/raylib/examples/core/core_2d_camera_mouse_zoom.c +105 -0
  58. package/vendor/raylib/examples/core/core_2d_camera_mouse_zoom.png +0 -0
  59. package/vendor/raylib/examples/core/core_2d_camera_platformer.c +11 -6
  60. package/vendor/raylib/examples/core/core_3d_camera_first_person.c +9 -4
  61. package/vendor/raylib/examples/core/core_3d_camera_free.c +9 -4
  62. package/vendor/raylib/examples/core/core_3d_camera_mode.c +8 -3
  63. package/vendor/raylib/examples/core/core_3d_picking.c +9 -4
  64. package/vendor/raylib/examples/core/core_basic_screen_manager.c +9 -7
  65. package/vendor/raylib/examples/core/core_basic_window.c +8 -3
  66. package/vendor/raylib/examples/core/core_basic_window_web.c +13 -11
  67. package/vendor/raylib/examples/core/core_custom_frame_control.c +9 -4
  68. package/vendor/raylib/examples/core/core_custom_logging.c +12 -8
  69. package/vendor/raylib/examples/core/core_drop_files.c +20 -12
  70. package/vendor/raylib/examples/core/core_input_gamepad.c +20 -15
  71. package/vendor/raylib/examples/core/core_input_gestures.c +19 -15
  72. package/vendor/raylib/examples/core/core_input_keys.c +8 -3
  73. package/vendor/raylib/examples/core/core_input_mouse.c +8 -3
  74. package/vendor/raylib/examples/core/core_input_mouse_wheel.c +8 -3
  75. package/vendor/raylib/examples/core/core_input_multitouch.c +8 -3
  76. package/vendor/raylib/examples/core/core_loading_thread.c +10 -6
  77. package/vendor/raylib/examples/core/core_random_values.c +8 -3
  78. package/vendor/raylib/examples/core/core_scissor_test.c +8 -3
  79. package/vendor/raylib/examples/core/core_smooth_pixelperfect.c +9 -4
  80. package/vendor/raylib/examples/core/core_split_screen.c +8 -3
  81. package/vendor/raylib/examples/core/core_storage_values.c +109 -3
  82. package/vendor/raylib/examples/core/core_vr_simulator.c +15 -7
  83. package/vendor/raylib/examples/core/core_window_flags.c +8 -3
  84. package/vendor/raylib/examples/core/core_window_letterbox.c +13 -18
  85. package/vendor/raylib/examples/core/core_window_should_close.c +77 -0
  86. package/vendor/raylib/examples/core/core_window_should_close.png +0 -0
  87. package/vendor/raylib/examples/core/core_world_screen.c +9 -4
  88. package/vendor/raylib/examples/examples_template.c +8 -3
  89. package/vendor/raylib/examples/models/models_animation.c +11 -7
  90. package/vendor/raylib/examples/models/models_billboard.c +9 -4
  91. package/vendor/raylib/examples/models/models_box_collisions.c +8 -3
  92. package/vendor/raylib/examples/models/models_cubicmap.c +9 -4
  93. package/vendor/raylib/examples/models/models_first_person_maze.c +9 -4
  94. package/vendor/raylib/examples/models/models_geometric_shapes.c +8 -3
  95. package/vendor/raylib/examples/models/models_heightmap.c +9 -4
  96. package/vendor/raylib/examples/models/models_loading.c +21 -17
  97. package/vendor/raylib/examples/models/models_loading_gltf.c +15 -41
  98. package/vendor/raylib/examples/models/models_loading_vox.c +9 -4
  99. package/vendor/raylib/examples/models/models_mesh_generation.c +71 -58
  100. package/vendor/raylib/examples/models/models_mesh_picking.c +25 -7
  101. package/vendor/raylib/examples/models/models_orthographic_projection.c +8 -5
  102. package/vendor/raylib/examples/models/models_rlgl_solar_system.c +6 -4
  103. package/vendor/raylib/examples/models/models_skybox.c +16 -12
  104. package/vendor/raylib/examples/models/models_waving_cubes.c +9 -4
  105. package/vendor/raylib/examples/models/models_yaw_pitch_roll.c +12 -7
  106. package/vendor/raylib/examples/models/resources/LICENSE.md +9 -10
  107. package/vendor/raylib/examples/models/resources/models/gltf/LICENSE +2 -23
  108. package/vendor/raylib/examples/models/resources/models/gltf/{raylib_32x32.glb → raylib_logo_3d.glb} +0 -0
  109. package/vendor/raylib/examples/models/resources/models/gltf/robot.blend +0 -0
  110. package/vendor/raylib/examples/models/resources/models/gltf/robot.glb +0 -0
  111. package/vendor/raylib/examples/others/easings_testbed.c +10 -8
  112. package/vendor/raylib/examples/others/easings_testbed.png +0 -0
  113. package/vendor/raylib/examples/others/embedded_files_loading.c +10 -5
  114. package/vendor/raylib/examples/others/embedded_files_loading.png +0 -0
  115. package/vendor/raylib/examples/others/raylib_opengl_interop.c +10 -6
  116. package/vendor/raylib/{src/extras/easings.h → examples/others/reasings.h} +38 -38
  117. package/vendor/raylib/examples/others/rlgl_compute_shader.c +21 -20
  118. package/vendor/raylib/examples/others/rlgl_compute_shader.png +0 -0
  119. package/vendor/raylib/examples/others/rlgl_standalone.c +4 -4
  120. package/vendor/raylib/examples/others/rlgl_standalone.png +0 -0
  121. package/vendor/raylib/examples/raylib_compile_execute.bat +2 -2
  122. package/vendor/raylib/examples/shaders/resources/shaders/glsl330/lighting.fs +1 -1
  123. package/vendor/raylib/examples/shaders/resources/shaders/glsl330/{base_lighting_instanced.vs → lighting_instancing.vs} +2 -2
  124. package/vendor/raylib/examples/shaders/rlights.h +14 -27
  125. package/vendor/raylib/examples/shaders/shaders_basic_lighting.c +24 -26
  126. package/vendor/raylib/examples/shaders/shaders_custom_uniform.c +10 -5
  127. package/vendor/raylib/examples/shaders/shaders_eratosthenes.c +13 -8
  128. package/vendor/raylib/examples/shaders/shaders_fog.c +8 -12
  129. package/vendor/raylib/examples/shaders/shaders_hot_reloading.c +10 -5
  130. package/vendor/raylib/examples/shaders/shaders_julia_set.c +9 -4
  131. package/vendor/raylib/examples/shaders/shaders_mesh_instancing.c +45 -119
  132. package/vendor/raylib/examples/shaders/shaders_model_shader.c +10 -5
  133. package/vendor/raylib/examples/shaders/shaders_multi_sample2d.c +8 -3
  134. package/vendor/raylib/examples/shaders/shaders_palette_switch.c +8 -3
  135. package/vendor/raylib/examples/shaders/shaders_postprocessing.c +9 -4
  136. package/vendor/raylib/examples/shaders/shaders_raymarching.c +14 -11
  137. package/vendor/raylib/examples/shaders/shaders_shapes_textures.c +8 -3
  138. package/vendor/raylib/examples/shaders/shaders_simple_mask.c +10 -5
  139. package/vendor/raylib/examples/shaders/shaders_spotlight.c +10 -6
  140. package/vendor/raylib/examples/shaders/shaders_texture_drawing.c +9 -4
  141. package/vendor/raylib/examples/shaders/shaders_texture_outline.c +8 -3
  142. package/vendor/raylib/examples/shaders/shaders_texture_waves.c +8 -3
  143. package/vendor/raylib/{src/extras → examples/shapes}/raygui.h +1290 -1141
  144. package/vendor/raylib/examples/{others/easings.h → shapes/reasings.h} +40 -40
  145. package/vendor/raylib/examples/shapes/shapes_basic_shapes.c +8 -3
  146. package/vendor/raylib/examples/shapes/shapes_bouncing_ball.c +8 -3
  147. package/vendor/raylib/examples/shapes/shapes_collision_area.c +10 -4
  148. package/vendor/raylib/examples/shapes/shapes_colors_palette.c +8 -3
  149. package/vendor/raylib/examples/shapes/shapes_draw_circle_sector.c +9 -4
  150. package/vendor/raylib/examples/shapes/shapes_draw_rectangle_rounded.c +9 -4
  151. package/vendor/raylib/examples/shapes/shapes_draw_ring.c +10 -6
  152. package/vendor/raylib/examples/shapes/shapes_easings_ball_anim.c +9 -4
  153. package/vendor/raylib/examples/shapes/shapes_easings_box_anim.c +9 -4
  154. package/vendor/raylib/examples/shapes/shapes_easings_rectangle_array.c +9 -4
  155. package/vendor/raylib/examples/shapes/shapes_following_eyes.c +8 -3
  156. package/vendor/raylib/examples/shapes/shapes_lines_bezier.c +8 -3
  157. package/vendor/raylib/examples/shapes/shapes_logo_raylib.c +8 -3
  158. package/vendor/raylib/examples/shapes/shapes_logo_raylib_anim.c +8 -3
  159. package/vendor/raylib/examples/shapes/shapes_rectangle_scaling.c +14 -5
  160. package/vendor/raylib/examples/shapes/shapes_top_down_lights.c +355 -0
  161. package/vendor/raylib/examples/shapes/shapes_top_down_lights.png +0 -0
  162. package/vendor/raylib/examples/text/resources/DotGothic16-Regular.ttf +0 -0
  163. package/vendor/raylib/examples/text/resources/DotGothic16-Regular_OFL.txt +93 -0
  164. package/vendor/raylib/examples/text/resources/LICENSE.md +1 -1
  165. package/vendor/raylib/examples/text/text_codepoints_loading.c +138 -0
  166. package/vendor/raylib/examples/text/text_codepoints_loading.png +0 -0
  167. package/vendor/raylib/examples/text/text_draw_3d.c +42 -33
  168. package/vendor/raylib/examples/text/text_font_filters.c +14 -11
  169. package/vendor/raylib/examples/text/text_font_loading.c +9 -4
  170. package/vendor/raylib/examples/text/text_font_sdf.c +9 -4
  171. package/vendor/raylib/examples/text/text_font_spritefont.c +12 -6
  172. package/vendor/raylib/examples/text/text_format_text.c +8 -3
  173. package/vendor/raylib/examples/text/text_input_box.c +8 -3
  174. package/vendor/raylib/examples/text/text_raylib_fonts.c +9 -4
  175. package/vendor/raylib/examples/text/text_rectangle_bounds.c +9 -5
  176. package/vendor/raylib/examples/text/text_unicode.c +9 -7
  177. package/vendor/raylib/examples/text/text_writing_anim.c +8 -3
  178. package/vendor/raylib/examples/textures/resources/scarfy_run.gif +0 -0
  179. package/vendor/raylib/examples/textures/textures_background_scrolling.c +8 -3
  180. package/vendor/raylib/examples/textures/textures_blend_modes.c +8 -3
  181. package/vendor/raylib/examples/textures/textures_bunnymark.c +8 -3
  182. package/vendor/raylib/examples/textures/textures_draw_tiled.c +14 -10
  183. package/vendor/raylib/examples/textures/textures_fog_of_war.c +154 -0
  184. package/vendor/raylib/examples/textures/textures_fog_of_war.png +0 -0
  185. package/vendor/raylib/examples/textures/textures_gif_player.c +121 -0
  186. package/vendor/raylib/examples/textures/textures_gif_player.png +0 -0
  187. package/vendor/raylib/examples/textures/textures_image_drawing.c +8 -3
  188. package/vendor/raylib/examples/textures/textures_image_generation.c +8 -3
  189. package/vendor/raylib/examples/textures/textures_image_loading.c +8 -3
  190. package/vendor/raylib/examples/textures/textures_image_processing.c +8 -3
  191. package/vendor/raylib/examples/textures/textures_image_text.c +8 -3
  192. package/vendor/raylib/examples/textures/textures_logo_raylib.c +8 -3
  193. package/vendor/raylib/examples/textures/textures_mouse_painting.c +9 -4
  194. package/vendor/raylib/examples/textures/textures_npatch_drawing.c +8 -3
  195. package/vendor/raylib/examples/textures/textures_particles_blending.c +8 -3
  196. package/vendor/raylib/examples/textures/textures_polygon.c +9 -5
  197. package/vendor/raylib/examples/textures/textures_raw_data.c +8 -3
  198. package/vendor/raylib/examples/textures/{textures_rectangle.c → textures_sprite_anim.c} +11 -5
  199. package/vendor/raylib/examples/textures/{textures_rectangle.png → textures_sprite_anim.png} +0 -0
  200. package/vendor/raylib/examples/textures/textures_sprite_button.c +8 -3
  201. package/vendor/raylib/examples/textures/textures_sprite_explosion.c +8 -3
  202. package/vendor/raylib/examples/textures/textures_srcrec_dstrec.c +8 -3
  203. package/vendor/raylib/examples/textures/textures_to_image.c +8 -3
  204. package/vendor/raylib/parser/LICENSE +1 -1
  205. package/vendor/raylib/parser/Makefile +28 -0
  206. package/vendor/raylib/parser/README.md +49 -5
  207. package/vendor/raylib/parser/output/raylib_api.json +10717 -0
  208. package/vendor/raylib/parser/output/raylib_api.lua +7435 -0
  209. package/vendor/raylib/parser/{raylib_api.txt → output/raylib_api.txt} +1371 -824
  210. package/vendor/raylib/parser/{raylib_api.xml → output/raylib_api.xml} +827 -595
  211. package/vendor/raylib/parser/raylib_parser.c +1174 -196
  212. package/vendor/raylib/projects/4coder/Makefile +2 -4
  213. package/vendor/raylib/projects/4coder/main.c +0 -1
  214. package/vendor/raylib/projects/CMake/CMakeLists.txt +13 -16
  215. package/vendor/raylib/projects/CMake/README.md +27 -0
  216. package/vendor/raylib/projects/CMake/core_basic_window.c +52 -31
  217. package/vendor/raylib/projects/CodeBlocks/README.md +4 -4
  218. package/vendor/raylib/projects/Geany/core_basic_window.c +1 -1
  219. package/vendor/raylib/projects/Notepad++/c_raylib.xml +168 -128
  220. package/vendor/raylib/projects/Notepad++/npes_saved_tcc.txt +0 -0
  221. package/vendor/raylib/projects/Notepad++/npes_saved_w64devkit.txt +0 -0
  222. package/vendor/raylib/projects/Notepad++/npes_saved_zig.txt +0 -0
  223. package/vendor/raylib/projects/Notepad++/raylib_npp_parser/raylib_npp.xml +168 -84
  224. package/vendor/raylib/projects/Notepad++/raylib_npp_parser/raylib_to_parse.h +67 -51
  225. package/vendor/raylib/projects/README.md +1 -1
  226. package/vendor/raylib/projects/VSCode/.vscode/c_cpp_properties.json +1 -1
  227. package/vendor/raylib/projects/VSCode/Makefile +8 -11
  228. package/vendor/raylib/projects/VSCode/main.c +53 -26
  229. package/vendor/raylib/projects/VSCode/resources/LICENSE +1 -0
  230. package/vendor/raylib/projects/scripts/build-linux.sh +6 -6
  231. package/vendor/raylib/projects/scripts/build-osx.sh +6 -6
  232. package/vendor/raylib/projects/scripts/build-rpi.sh +6 -6
  233. package/vendor/raylib/projects/scripts/build-windows.bat +2 -2
  234. package/vendor/raylib/src/CMakeLists.txt +6 -7
  235. package/vendor/raylib/src/Makefile +209 -103
  236. package/vendor/raylib/src/build.zig +56 -20
  237. package/vendor/raylib/src/config.h +32 -27
  238. package/vendor/raylib/src/external/cgltf.h +342 -104
  239. package/vendor/raylib/src/external/dr_wav.h +487 -225
  240. package/vendor/raylib/src/external/glfw/src/posix_time.c +1 -3
  241. package/vendor/raylib/src/external/glfw/src/wl_init.c +1 -3
  242. package/vendor/raylib/src/external/jar_xm.h +2 -1
  243. package/vendor/raylib/src/external/miniaudio.h +62251 -42061
  244. package/vendor/raylib/src/external/qoi.h +671 -0
  245. package/vendor/raylib/src/external/stb_vorbis.h +1 -1
  246. package/vendor/raylib/src/external/vox_loader.h +30 -25
  247. package/vendor/raylib/src/minshell.html +82 -0
  248. package/vendor/raylib/src/raudio.c +359 -201
  249. package/vendor/raylib/src/raylib.dll.rc +5 -5
  250. package/vendor/raylib/src/raylib.dll.rc.data +0 -0
  251. package/vendor/raylib/src/raylib.h +95 -63
  252. package/vendor/raylib/src/raylib.rc +5 -5
  253. package/vendor/raylib/src/raylib.rc.data +0 -0
  254. package/vendor/raylib/src/raymath.h +391 -133
  255. package/vendor/raylib/src/rcamera.h +32 -41
  256. package/vendor/raylib/src/rcore.c +775 -471
  257. package/vendor/raylib/src/rgestures.h +5 -5
  258. package/vendor/raylib/src/rglfw.c +3 -3
  259. package/vendor/raylib/src/rlgl.h +184 -144
  260. package/vendor/raylib/src/rmodels.c +207 -144
  261. package/vendor/raylib/src/rshapes.c +105 -47
  262. package/vendor/raylib/src/rtext.c +255 -38
  263. package/vendor/raylib/src/rtextures.c +167 -71
  264. package/vendor/raylib/src/shell.html +63 -63
  265. package/vendor/raylib/src/utils.c +49 -3
  266. package/vendor/raylib/src/utils.h +3 -3
  267. package/build/qemu/2.1.0/koffi_darwin_arm64.tar.gz +0 -0
  268. package/build/qemu/2.1.0/koffi_darwin_x64.tar.gz +0 -0
  269. package/build/qemu/2.1.0/koffi_freebsd_arm64.tar.gz +0 -0
  270. package/build/qemu/2.1.0/koffi_freebsd_ia32.tar.gz +0 -0
  271. package/build/qemu/2.1.0/koffi_freebsd_x64.tar.gz +0 -0
  272. package/build/qemu/2.1.0/koffi_linux_arm32hf.tar.gz +0 -0
  273. package/build/qemu/2.1.0/koffi_linux_arm64.tar.gz +0 -0
  274. package/build/qemu/2.1.0/koffi_linux_ia32.tar.gz +0 -0
  275. package/build/qemu/2.1.0/koffi_linux_riscv64hf64.tar.gz +0 -0
  276. package/build/qemu/2.1.0/koffi_linux_x64.tar.gz +0 -0
  277. package/build/qemu/2.1.0/koffi_openbsd_ia32.tar.gz +0 -0
  278. package/build/qemu/2.1.0/koffi_openbsd_x64.tar.gz +0 -0
  279. package/build/qemu/2.1.0/koffi_win32_arm64.tar.gz +0 -0
  280. package/build/qemu/2.1.0/koffi_win32_ia32.tar.gz +0 -0
  281. package/build/qemu/2.1.0/koffi_win32_x64.tar.gz +0 -0
  282. package/vendor/raylib/CONTRIBUTORS.md +0 -63
  283. package/vendor/raylib/SPONSORS.md +0 -68
  284. package/vendor/raylib/examples/core/core_quat_conversion.c +0 -132
  285. package/vendor/raylib/examples/core/core_quat_conversion.png +0 -0
  286. package/vendor/raylib/examples/models/resources/models/gltf/AnimatedMorphCube.glb +0 -0
  287. package/vendor/raylib/examples/models/resources/models/gltf/AnimatedTriangle.gltf +0 -118
  288. package/vendor/raylib/examples/models/resources/models/gltf/BoxAnimated.glb +0 -0
  289. package/vendor/raylib/examples/models/resources/models/gltf/girl.glb +0 -0
  290. package/vendor/raylib/examples/models/resources/models/gltf/rigged_figure.glb +0 -0
  291. package/vendor/raylib/examples/models/resources/models/gltf/vertex_colored_object.glb +0 -0
  292. package/vendor/raylib/examples/models/resources/models/iqm/vertex_colored_object.iqm +0 -0
  293. package/vendor/raylib/examples/models/rlights.h +0 -183
  294. package/vendor/raylib/examples/others/raudio_standalone.c +0 -152
  295. package/vendor/raylib/examples/others/resources/audio/country.mp3 +0 -0
  296. package/vendor/raylib/examples/others/resources/audio/target.ogg +0 -0
  297. package/vendor/raylib/examples/others/resources/audio/weird.wav +0 -0
  298. package/vendor/raylib/examples/physics/physics_demo.c +0 -128
  299. package/vendor/raylib/examples/physics/physics_demo.png +0 -0
  300. package/vendor/raylib/examples/physics/physics_friction.c +0 -142
  301. package/vendor/raylib/examples/physics/physics_friction.png +0 -0
  302. package/vendor/raylib/examples/physics/physics_movement.c +0 -128
  303. package/vendor/raylib/examples/physics/physics_movement.png +0 -0
  304. package/vendor/raylib/examples/physics/physics_restitution.c +0 -129
  305. package/vendor/raylib/examples/physics/physics_restitution.png +0 -0
  306. package/vendor/raylib/examples/physics/physics_shatter.c +0 -111
  307. package/vendor/raylib/examples/physics/physics_shatter.png +0 -0
  308. package/vendor/raylib/parser/raylib_api.json +0 -6668
  309. package/vendor/raylib/projects/VS2019/raylib/raylib.rc +0 -0
  310. package/vendor/raylib/projects/VS2019/raylib/resource.h +0 -14
  311. package/vendor/raylib/src/extras/physac.h +0 -1977
  312. package/vendor/raylib/src/extras/rmem.h +0 -751
  313. package/vendor/raylib/src/raudio.h +0 -198
@@ -84,7 +84,7 @@ namespace RG {
84
84
 
85
85
  #define RG_LINE_READER_STEP_SIZE 65536
86
86
 
87
- #define RG_ASYNC_MAX_THREADS 256
87
+ #define RG_ASYNC_MAX_THREADS 2048
88
88
  #define RG_ASYNC_MAX_IDLE_TIME 10000
89
89
  #define RG_FIBER_DEFAULT_STACK_SIZE Kibibytes(128)
90
90
 
@@ -622,7 +622,7 @@ T ApplyMask(T value, U mask, bool enable)
622
622
  if (enable) {
623
623
  return value | (T)mask;
624
624
  } else {
625
- return value & (T)~mask;
625
+ return value & ~(T)mask;
626
626
  }
627
627
  }
628
628
 
@@ -824,28 +824,27 @@ static inline constexpr Strider<T> MakeStrider(T (&arr)[N])
824
824
  return Strider<T>(arr, RG_SIZE(T));
825
825
  }
826
826
 
827
+ enum class AllocFlag {
828
+ Zero = 1,
829
+ Resizable = 2
830
+ };
831
+
827
832
  class Allocator {
828
833
  RG_DELETE_COPY(Allocator)
829
834
 
830
835
  public:
831
- enum class Flag {
832
- Zero = 1,
833
- Resizable = 2
834
- };
835
-
836
836
  Allocator() = default;
837
837
  virtual ~Allocator() = default;
838
838
 
839
839
  virtual void *Allocate(Size size, unsigned int flags = 0) = 0;
840
- virtual void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags = 0) = 0;
841
- virtual void Release(void *ptr, Size size) = 0;
840
+ virtual void *Resize(void *ptr, Size old_size, Size new_size, unsigned int flags = 0) = 0;
841
+ virtual void Release(const void *ptr, Size size) = 0;
842
842
  };
843
843
 
844
844
  Allocator *GetDefaultAllocator();
845
845
  Allocator *GetNullAllocator();
846
846
 
847
- template <typename T>
848
- Span<T> AllocateMemory(Allocator *alloc, Size size, unsigned int flags = 0)
847
+ static inline void *AllocateRaw(Allocator *alloc, Size size, unsigned int flags = 0)
849
848
  {
850
849
  RG_ASSERT(size >= 0);
851
850
 
@@ -853,13 +852,40 @@ Span<T> AllocateMemory(Allocator *alloc, Size size, unsigned int flags = 0)
853
852
  alloc = GetDefaultAllocator();
854
853
  }
855
854
 
855
+ void *ptr = alloc->Allocate(size, flags);
856
+ return ptr;
857
+ }
858
+
859
+ template <typename T>
860
+ T *AllocateOne(Allocator *alloc, unsigned int flags = 0)
861
+ {
862
+ if (!alloc) {
863
+ alloc = GetDefaultAllocator();
864
+ }
865
+
866
+ Size size = RG_SIZE(T);
867
+
856
868
  T *ptr = (T *)alloc->Allocate(size, flags);
857
- return MakeSpan(ptr, size);
869
+ return ptr;
858
870
  }
859
871
 
860
872
  template <typename T>
861
- Span<T> ResizeMemory(Allocator *alloc, T *ptr, Size old_size, Size new_size,
862
- unsigned int flags = 0)
873
+ Span<T> AllocateSpan(Allocator *alloc, Size len, unsigned int flags = 0)
874
+ {
875
+ RG_ASSERT(len >= 0);
876
+
877
+ if (!alloc) {
878
+ alloc = GetDefaultAllocator();
879
+ }
880
+
881
+ Size size = len * RG_SIZE(T);
882
+
883
+ T *ptr = (T *)alloc->Allocate(size, flags);
884
+ return MakeSpan(ptr, len);
885
+ }
886
+
887
+ static inline void *ResizeRaw(Allocator *alloc, void *ptr, Size old_size, Size new_size,
888
+ unsigned int flags = 0)
863
889
  {
864
890
  RG_ASSERT(new_size >= 0);
865
891
 
@@ -867,28 +893,56 @@ Span<T> ResizeMemory(Allocator *alloc, T *ptr, Size old_size, Size new_size,
867
893
  alloc = GetDefaultAllocator();
868
894
  }
869
895
 
870
- alloc->Resize((void **)&ptr, old_size, new_size, flags);
871
- return MakeSpan(ptr, new_size);
896
+ ptr = alloc->Resize(ptr, old_size, new_size, flags);
897
+ return ptr;
898
+ }
899
+
900
+ template <typename T>
901
+ Span<T> ResizeSpan(Allocator *alloc, Span<T> mem, Size new_len,
902
+ unsigned int flags = 0)
903
+ {
904
+ RG_ASSERT(new_len >= 0);
905
+
906
+ if (!alloc) {
907
+ alloc = GetDefaultAllocator();
908
+ }
909
+
910
+ Size old_size = mem.len * RG_SIZE(T);
911
+ Size new_size = new_len * RG_SIZE(T);
912
+
913
+ mem.ptr = (T *)alloc->Resize(mem.ptr, old_size, new_size, flags);
914
+ return MakeSpan(mem.ptr, new_len);
915
+ }
916
+
917
+ static inline void ReleaseRaw(Allocator *alloc, const void *ptr, Size size)
918
+ {
919
+ if (!alloc) {
920
+ alloc = GetDefaultAllocator();
921
+ }
922
+
923
+ alloc->Release(ptr, size);
872
924
  }
873
925
 
874
926
  template<typename T>
875
- void ReleaseMemory(Allocator *alloc, Span<T> mem)
927
+ void ReleaseOne(Allocator *alloc, T *ptr)
876
928
  {
877
929
  if (!alloc) {
878
930
  alloc = GetDefaultAllocator();
879
931
  }
880
932
 
881
- alloc->Release((void *)mem.ptr, mem.len);
933
+ alloc->Release((void *)ptr, RG_SIZE(T));
882
934
  }
883
935
 
884
936
  template<typename T>
885
- void ReleaseMemory(Allocator *alloc, T *ptr, Size size)
937
+ void ReleaseSpan(Allocator *alloc, Span<T> mem)
886
938
  {
887
939
  if (!alloc) {
888
940
  alloc = GetDefaultAllocator();
889
941
  }
890
942
 
891
- alloc->Release((void *)ptr, size);
943
+ Size size = mem.len * RG_SIZE(T);
944
+
945
+ alloc->Release((void *)mem.ptr, size);
892
946
  }
893
947
 
894
948
  class LinkedAllocator final: public Allocator {
@@ -899,7 +953,7 @@ class LinkedAllocator final: public Allocator {
899
953
  struct Bucket {
900
954
  // Keep head first or stuff will break
901
955
  Node head;
902
- uint8_t data[8]; // Extra size is used to align pointer
956
+ uint8_t data[];
903
957
  };
904
958
 
905
959
  Allocator *allocator;
@@ -917,18 +971,17 @@ public:
917
971
  void ReleaseAll();
918
972
 
919
973
  void *Allocate(Size size, unsigned int flags = 0) override;
920
- void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
921
- void Release(void *ptr, Size size) override;
974
+ void *Resize(void *ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
975
+ void Release(const void *ptr, Size size) override;
922
976
 
923
977
  private:
924
- static Bucket *PointerToBucket(void *ptr)
925
- { return (Bucket *)((uint8_t *)ptr - RG_OFFSET_OF(Bucket, data)); }
978
+ static Bucket *PointerToBucket(void *ptr);
926
979
  };
927
980
 
928
981
  class BlockAllocatorBase: public Allocator {
929
982
  struct Bucket {
930
983
  Size used;
931
- uint8_t data[8]; // Extra size is used to align pointer
984
+ uint8_t data[];
932
985
  };
933
986
 
934
987
  Size block_size;
@@ -944,8 +997,8 @@ public:
944
997
  }
945
998
 
946
999
  void *Allocate(Size size, unsigned int flags = 0) override;
947
- void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
948
- void Release(void *ptr, Size size) override;
1000
+ void *Resize(void *ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
1001
+ void Release(const void *ptr, Size size) override;
949
1002
 
950
1003
  protected:
951
1004
  void CopyFrom(BlockAllocatorBase *other);
@@ -1315,7 +1368,7 @@ public:
1315
1368
  len = new_capacity;
1316
1369
  }
1317
1370
 
1318
- ptr = ResizeMemory(allocator, ptr, capacity * RG_SIZE(T), new_capacity * RG_SIZE(T)).ptr;
1371
+ ptr = (T *)ResizeRaw(allocator, ptr, capacity * RG_SIZE(T), new_capacity * RG_SIZE(T));
1319
1372
  capacity = new_capacity;
1320
1373
  }
1321
1374
  }
@@ -1327,7 +1380,7 @@ public:
1327
1380
  }
1328
1381
  }
1329
1382
 
1330
- void Grow(Size reserve_capacity = 1)
1383
+ T *Grow(Size reserve_capacity = 1)
1331
1384
  {
1332
1385
  RG_ASSERT(capacity >= 0);
1333
1386
  RG_ASSERT(reserve_capacity >= 0);
@@ -1345,6 +1398,8 @@ public:
1345
1398
 
1346
1399
  SetCapacity(new_capacity);
1347
1400
  }
1401
+
1402
+ return ptr + len;
1348
1403
  }
1349
1404
 
1350
1405
  void Trim(Size extra_capacity = 0) { SetCapacity(len + extra_capacity); }
@@ -1612,9 +1667,9 @@ public:
1612
1667
  Size bucket_offset = (offset + len) % BucketSize;
1613
1668
 
1614
1669
  if (bucket_idx >= buckets.len) {
1615
- Bucket *new_bucket = AllocateMemory<Bucket>(buckets.allocator, RG_SIZE(Bucket)).ptr;
1670
+ Bucket *new_bucket = AllocateOne<Bucket>(buckets.allocator);
1616
1671
  new (&new_bucket->allocator) AllocatorType();
1617
- new_bucket->values = AllocateMemory<T>(&new_bucket->allocator, BucketSize * RG_SIZE(T)).ptr;
1672
+ new_bucket->values = (T *)AllocateRaw(&new_bucket->allocator, BucketSize * RG_SIZE(T));
1618
1673
 
1619
1674
  buckets.Append(new_bucket);
1620
1675
  }
@@ -1731,7 +1786,7 @@ private:
1731
1786
  void DeleteBucket(Bucket *bucket)
1732
1787
  {
1733
1788
  bucket->allocator.~AllocatorType();
1734
- ReleaseMemory(buckets.allocator, bucket, RG_SIZE(Bucket));
1789
+ ReleaseOne(buckets.allocator, bucket);
1735
1790
  }
1736
1791
  };
1737
1792
 
@@ -2244,10 +2299,10 @@ private:
2244
2299
  Size old_capacity = capacity;
2245
2300
 
2246
2301
  if (new_capacity) {
2247
- used = AllocateMemory<size_t>(allocator,
2248
- (new_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t),
2249
- (int)Allocator::Flag::Zero).ptr;
2250
- data = AllocateMemory<ValueType>(allocator, new_capacity * RG_SIZE(ValueType)).ptr;
2302
+ used = (size_t *)AllocateRaw(allocator,
2303
+ (new_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t),
2304
+ (int)AllocFlag::Zero);
2305
+ data = (ValueType *)AllocateRaw(allocator, new_capacity * RG_SIZE(ValueType));
2251
2306
  for (Size i = 0; i < new_capacity; i++) {
2252
2307
  new (&data[i]) ValueType();
2253
2308
  }
@@ -2269,9 +2324,8 @@ private:
2269
2324
  capacity = 0;
2270
2325
  }
2271
2326
 
2272
- ReleaseMemory(allocator, old_used,
2273
- (old_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t));
2274
- ReleaseMemory(allocator, old_data, old_capacity * RG_SIZE(ValueType));
2327
+ ReleaseRaw(allocator, old_used, (old_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t));
2328
+ ReleaseRaw(allocator, old_data, old_capacity * RG_SIZE(ValueType));
2275
2329
  }
2276
2330
 
2277
2331
  void MarkUsed(Size idx)
@@ -2742,723 +2796,411 @@ static const char *const TimeModeNames[] = {
2742
2796
  TimeSpec DecomposeTime(int64_t time, TimeMode mode = TimeMode::Local);
2743
2797
 
2744
2798
  // ------------------------------------------------------------------------
2745
- // Streams
2799
+ // Format
2746
2800
  // ------------------------------------------------------------------------
2747
2801
 
2748
- enum class CompressionType {
2749
- None,
2750
- Zlib,
2751
- Gzip,
2752
- Brotli
2753
- };
2754
- static const char *const CompressionTypeNames[] = {
2755
- "None",
2756
- "Zlib",
2757
- "Gzip",
2758
- "Brotli"
2759
- };
2802
+ class StreamWriter;
2760
2803
 
2761
- enum class CompressionSpeed {
2762
- Default,
2763
- Slow,
2764
- Fast
2804
+ enum class FmtType {
2805
+ Str1,
2806
+ Str2,
2807
+ Buffer,
2808
+ Char,
2809
+ Bool,
2810
+ Integer,
2811
+ Unsigned,
2812
+ Float,
2813
+ Double,
2814
+ Binary,
2815
+ BigHex,
2816
+ SmallHex,
2817
+ MemorySize,
2818
+ DiskSize,
2819
+ Date,
2820
+ TimeISO,
2821
+ TimeNice,
2822
+ Random,
2823
+ FlagNames,
2824
+ FlagOptions,
2825
+ Span
2765
2826
  };
2766
2827
 
2767
- class StreamReader {
2768
- RG_DELETE_COPY(StreamReader)
2769
-
2770
- enum class SourceType {
2771
- Memory,
2772
- File,
2773
- Function
2774
- };
2775
-
2776
- const char *filename = nullptr;
2777
- bool error = true;
2778
-
2779
- struct {
2780
- SourceType type = SourceType::Memory;
2781
- union U {
2782
- struct {
2783
- Span<const uint8_t> buf;
2784
- Size pos;
2785
- } memory;
2786
- struct {
2787
- FILE *fp;
2788
- bool owned;
2789
- } file;
2790
- std::function<Size(Span<uint8_t> buf)> func;
2791
-
2792
- // StreamReader deals with func destructor
2793
- U() {}
2794
- ~U() {}
2795
- } u;
2796
-
2797
- bool eof = false;
2798
- } source;
2799
-
2800
- struct {
2801
- CompressionType type = CompressionType::None;
2802
- union {
2803
- struct MinizInflateContext *miniz;
2804
- struct BrotliDecompressContext *brotli;
2805
- } u;
2806
- } compression;
2807
-
2808
- int64_t raw_len = -1;
2809
- Size raw_read = 0;
2810
- bool eof = false;
2811
-
2812
- BlockAllocator str_alloc;
2813
-
2828
+ class FmtArg {
2814
2829
  public:
2815
- StreamReader() { Close(true); }
2816
- StreamReader(Span<const uint8_t> buf, const char *filename = nullptr,
2817
- CompressionType compression_type = CompressionType::None)
2818
- : StreamReader() { Open(buf, filename, compression_type); }
2819
- StreamReader(FILE *fp, const char *filename,
2820
- CompressionType compression_type = CompressionType::None)
2821
- : StreamReader() { Open(fp, filename, compression_type); }
2822
- StreamReader(const char *filename,
2823
- CompressionType compression_type = CompressionType::None)
2824
- : StreamReader() { Open(filename, compression_type); }
2825
- StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
2826
- CompressionType compression_type = CompressionType::None)
2827
- : StreamReader() { Open(func, filename, compression_type); }
2828
- ~StreamReader() { Close(true); }
2829
-
2830
- bool Open(Span<const uint8_t> buf, const char *filename = nullptr,
2831
- CompressionType compression_type = CompressionType::None);
2832
- bool Open(FILE *fp, const char *filename,
2833
- CompressionType compression_type = CompressionType::None);
2834
- bool Open(const char *filename, CompressionType compression_type = CompressionType::None);
2835
- bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
2836
- CompressionType compression_type = CompressionType::None);
2837
- bool Close() { return Close(false); }
2838
-
2839
- // File-specific
2840
- bool Rewind();
2841
-
2842
- const char *GetFileName() const { return filename; }
2843
- CompressionType GetCompressionType() const { return compression.type; }
2844
- bool IsValid() const { return filename && !error; }
2845
- bool IsEOF() const { return eof; }
2846
-
2847
- Size Read(Span<uint8_t> out_buf);
2848
- Size Read(Span<char> out_buf) { return Read(out_buf.As<uint8_t>()); }
2849
- Size Read(Size max_len, void *out_buf) { return Read(MakeSpan((uint8_t *)out_buf, max_len)); }
2850
-
2851
- Size ReadAll(Size max_len, HeapArray<uint8_t> *out_buf);
2852
- Size ReadAll(Size max_len, HeapArray<char> *out_buf)
2853
- { return ReadAll(max_len, (HeapArray<uint8_t> *)out_buf); }
2854
-
2855
- int64_t ComputeRawLen();
2830
+ FmtType type;
2831
+ union {
2832
+ const char *str1;
2833
+ Span<const char> str2;
2834
+ char buf[32];
2835
+ char ch;
2836
+ bool b;
2837
+ int64_t i;
2838
+ uint64_t u;
2839
+ struct {
2840
+ float value;
2841
+ int min_prec;
2842
+ int max_prec;
2843
+ } f;
2844
+ struct {
2845
+ double value;
2846
+ int min_prec;
2847
+ int max_prec;
2848
+ } d;
2849
+ const void *ptr;
2850
+ LocalDate date;
2851
+ struct {
2852
+ TimeSpec spec;
2853
+ bool ms;
2854
+ } time;
2855
+ struct {
2856
+ Size len;
2857
+ const char *chars;
2858
+ } random;
2859
+ struct {
2860
+ uint64_t flags;
2861
+ union {
2862
+ Span<const char *const> names;
2863
+ Span<const struct OptionDesc> options;
2864
+ } u;
2865
+ const char *separator;
2866
+ } flags;
2856
2867
 
2857
- private:
2858
- bool Close(bool implicit);
2868
+ struct {
2869
+ FmtType type;
2870
+ int type_len;
2871
+ const void *ptr;
2872
+ Size len;
2873
+ const char *separator;
2874
+ } span;
2875
+ } u;
2859
2876
 
2860
- bool InitDecompressor(CompressionType type);
2877
+ int repeat = 1;
2878
+ int pad_len = 0;
2879
+ char pad_char = 0;
2861
2880
 
2862
- Size ReadInflate(Size max_len, void *out_buf);
2863
- Size ReadBrotli(Size max_len, void *out_buf);
2881
+ FmtArg() = default;
2882
+ FmtArg(std::nullptr_t) : type(FmtType::Str1) { u.str1 = "(null)"; }
2883
+ FmtArg(const char *str) : type(FmtType::Str1) { u.str1 = str ? str : "(null)"; }
2884
+ FmtArg(Span<const char> str) : type(FmtType::Str2) { u.str2 = str; }
2885
+ FmtArg(char c) : type(FmtType::Char) { u.ch = c; }
2886
+ FmtArg(bool b) : type(FmtType::Bool) { u.b = b; }
2887
+ FmtArg(unsigned char i) : type(FmtType::Unsigned) { u.u = i; }
2888
+ FmtArg(short i) : type(FmtType::Integer) { u.i = i; }
2889
+ FmtArg(unsigned short i) : type(FmtType::Unsigned) { u.u = i; }
2890
+ FmtArg(int i) : type(FmtType::Integer) { u.i = i; }
2891
+ FmtArg(unsigned int i) : type(FmtType::Unsigned) { u.u = i; }
2892
+ FmtArg(long i) : type(FmtType::Integer) { u.i = i; }
2893
+ FmtArg(unsigned long i) : type(FmtType::Unsigned) { u.u = i; }
2894
+ FmtArg(long long i) : type(FmtType::Integer) { u.i = i; }
2895
+ FmtArg(unsigned long long i) : type(FmtType::Unsigned) { u.u = i; }
2896
+ FmtArg(float f) : type(FmtType::Float) { u.f = { f, 0, INT_MAX }; }
2897
+ FmtArg(double d) : type(FmtType::Double) { u.d = { d, 0, INT_MAX }; }
2898
+ FmtArg(const void *ptr) : type(FmtType::BigHex) { u.u = (uint64_t)ptr; }
2899
+ FmtArg(const LocalDate &date) : type(FmtType::Date) { u.date = date; }
2864
2900
 
2865
- Size ReadRaw(Size max_len, void *out_buf);
2901
+ FmtArg &Repeat(int new_repeat) { repeat = new_repeat; return *this; }
2902
+ FmtArg &Pad(int len, char c = ' ') { pad_char = c; pad_len = len; return *this; }
2903
+ FmtArg &Pad0(int len) { return Pad(len, '0'); }
2866
2904
  };
2867
2905
 
2868
- static inline Size ReadFile(const char *filename, CompressionType compression_type, Span<uint8_t> out_buf)
2906
+ static inline FmtArg FmtBin(uint64_t u)
2869
2907
  {
2870
- StreamReader st(filename, compression_type);
2871
- return st.Read(out_buf);
2908
+ FmtArg arg;
2909
+ arg.type = FmtType::Binary;
2910
+ arg.u.u = u;
2911
+ return arg;
2872
2912
  }
2873
- static inline Size ReadFile(const char *filename, Span<uint8_t> out_buf)
2913
+ static inline FmtArg FmtHex(uint64_t u, FmtType type = FmtType::BigHex)
2874
2914
  {
2875
- StreamReader st(filename);
2876
- return st.Read(out_buf);
2915
+ RG_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
2916
+
2917
+ FmtArg arg;
2918
+ arg.type = type;
2919
+ arg.u.u = u;
2920
+ return arg;
2877
2921
  }
2878
- static inline Size ReadFile(const char *filename, CompressionType compression_type, Span<char> out_buf)
2879
- {
2880
- StreamReader st(filename, compression_type);
2881
- return st.Read(out_buf);
2882
- }
2883
- static inline Size ReadFile(const char *filename, Span<char> out_buf)
2922
+
2923
+ static inline FmtArg FmtFloat(float f, int min_prec, int max_prec)
2884
2924
  {
2885
- StreamReader st(filename);
2886
- return st.Read(out_buf);
2925
+ FmtArg arg;
2926
+ arg.type = FmtType::Float;
2927
+ arg.u.f.value = f;
2928
+ arg.u.f.min_prec = min_prec;
2929
+ arg.u.f.max_prec = max_prec;
2930
+ return arg;
2887
2931
  }
2932
+ static inline FmtArg FmtFloat(float f, int prec) { return FmtFloat(f, prec, prec); }
2933
+ static inline FmtArg FmtFloat(float f) { return FmtFloat(f, 0, INT_MAX); }
2888
2934
 
2889
- static inline Size ReadFile(const char *filename, Size max_len, CompressionType compression_type,
2890
- HeapArray<uint8_t> *out_buf)
2935
+ static inline FmtArg FmtDouble(double d, int min_prec, int max_prec)
2891
2936
  {
2892
- StreamReader st(filename, compression_type);
2893
- return st.ReadAll(max_len, out_buf);
2937
+ FmtArg arg;
2938
+ arg.type = FmtType::Double;
2939
+ arg.u.d.value = d;
2940
+ arg.u.d.min_prec = min_prec;
2941
+ arg.u.d.max_prec = max_prec;
2942
+ return arg;
2894
2943
  }
2895
- static inline Size ReadFile(const char *filename, Size max_len, HeapArray<uint8_t> *out_buf)
2944
+ static inline FmtArg FmtDouble(double d, int prec) { return FmtDouble(d, prec, prec); }
2945
+ static inline FmtArg FmtDouble(double d) { return FmtDouble(d, 0, INT_MAX); }
2946
+
2947
+ static inline FmtArg FmtMemSize(int64_t size)
2896
2948
  {
2897
- StreamReader st(filename);
2898
- return st.ReadAll(max_len, out_buf);
2949
+ FmtArg arg;
2950
+ arg.type = FmtType::MemorySize;
2951
+ arg.u.i = size;
2952
+ return arg;
2899
2953
  }
2900
- static inline Size ReadFile(const char *filename, Size max_len, CompressionType compression_type,
2901
- HeapArray<char> *out_buf)
2954
+ static inline FmtArg FmtDiskSize(int64_t size)
2902
2955
  {
2903
- StreamReader st(filename, compression_type);
2904
- return st.ReadAll(max_len, out_buf);
2956
+ FmtArg arg;
2957
+ arg.type = FmtType::DiskSize;
2958
+ arg.u.i = size;
2959
+ return arg;
2905
2960
  }
2906
- static inline Size ReadFile(const char *filename, Size max_len, HeapArray<char> *out_buf)
2961
+
2962
+ static inline FmtArg FmtTimeISO(TimeSpec spec, bool ms = false)
2907
2963
  {
2908
- StreamReader st(filename);
2909
- return st.ReadAll(max_len, out_buf);
2964
+ FmtArg arg;
2965
+ arg.type = FmtType::TimeISO;
2966
+ arg.u.time.spec = spec;
2967
+ arg.u.time.ms = ms;
2968
+ return arg;
2910
2969
  }
2911
2970
 
2912
- class LineReader {
2913
- RG_DELETE_COPY(LineReader)
2914
-
2915
- HeapArray<char> buf;
2916
- Span<char> view = {};
2971
+ static inline FmtArg FmtTimeNice(TimeSpec spec, bool ms = false)
2972
+ {
2973
+ FmtArg arg;
2974
+ arg.type = FmtType::TimeNice;
2975
+ arg.u.time.spec = spec;
2976
+ arg.u.time.ms = ms;
2977
+ return arg;
2978
+ }
2917
2979
 
2918
- StreamReader *st;
2919
- bool error;
2920
- bool eof = false;
2980
+ static inline FmtArg FmtRandom(Size len, const char *chars = nullptr)
2981
+ {
2982
+ RG_ASSERT(len < 256);
2983
+ len = std::min(len, (Size)256);
2921
2984
 
2922
- Span<char> line = {};
2923
- int line_number = 0;
2985
+ FmtArg arg;
2986
+ arg.type = FmtType::Random;
2987
+ arg.u.random.len = len;
2988
+ arg.u.random.chars = chars;
2989
+ return arg;
2990
+ }
2924
2991
 
2925
- public:
2926
- LineReader(StreamReader *st) : st(st), error(!st->IsValid()) {}
2992
+ static inline FmtArg FmtFlags(uint64_t flags, Span<const char *const> names, const char *sep = ", ")
2993
+ {
2994
+ FmtArg arg;
2995
+ arg.type = FmtType::FlagNames;
2996
+ arg.u.flags.flags = flags & ((1ull << names.len) - 1);
2997
+ arg.u.flags.u.names = names;
2998
+ arg.u.flags.separator = sep;
2999
+ return arg;
3000
+ }
2927
3001
 
2928
- const char *GetFileName() const { return st->GetFileName(); }
2929
- int GetLineNumber() const { return line_number; }
2930
- bool IsValid() const { return !error; }
2931
- bool IsEOF() const { return eof; }
3002
+ static inline FmtArg FmtFlags(uint64_t flags, Span<const struct OptionDesc> options, const char *sep = ", ")
3003
+ {
3004
+ FmtArg arg;
3005
+ arg.type = FmtType::FlagOptions;
3006
+ arg.u.flags.flags = flags & ((1ull << options.len) - 1);
3007
+ arg.u.flags.u.options = options;
3008
+ arg.u.flags.separator = sep;
3009
+ return arg;
3010
+ }
2932
3011
 
2933
- bool Next(Span<char> *out_line);
2934
- bool Next(Span<const char> *out_line) { return Next((Span<char> *)out_line); }
3012
+ template <typename T>
3013
+ FmtArg FmtSpan(Span<T> arr, FmtType type, const char *sep = ", ")
3014
+ {
3015
+ FmtArg arg;
3016
+ arg.type = FmtType::Span;
3017
+ arg.u.span.type = type;
3018
+ arg.u.span.type_len = RG_SIZE(T);
3019
+ arg.u.span.ptr = (const void *)arr.ptr;
3020
+ arg.u.span.len = arr.len;
3021
+ arg.u.span.separator = sep;
3022
+ return arg;
3023
+ }
3024
+ template <typename T>
3025
+ FmtArg FmtSpan(Span<T> arr, const char *sep = ", ") { return FmtSpan(arr, FmtArg(T()).type, sep); }
3026
+ template <typename T, Size N>
3027
+ FmtArg FmtSpan(T (&arr)[N], FmtType type, const char *sep = ", ") { return FmtSpan(MakeSpan(arr), type, sep); }
3028
+ template <typename T, Size N>
3029
+ FmtArg FmtSpan(T (&arr)[N], const char *sep = ", ") { return FmtSpan(MakeSpan(arr), sep); }
2935
3030
 
2936
- void PushLogFilter();
3031
+ enum class LogLevel {
3032
+ Debug,
3033
+ Info,
3034
+ Warning,
3035
+ Error
2937
3036
  };
2938
3037
 
2939
- enum class StreamWriterFlag {
2940
- Exclusive = 1 << 0,
2941
- Atomic = 1 << 1
2942
- };
3038
+ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, Span<char> out_buf);
3039
+ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, HeapArray<char> *out_buf);
3040
+ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, Allocator *alloc);
3041
+ void PrintFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *out_st);
3042
+ void PrintFmt(const char *fmt, Span<const FmtArg> args, FILE *out_fp);
3043
+ void PrintLnFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *out_st);
3044
+ void PrintLnFmt(const char *fmt, Span<const FmtArg> args, FILE *out_fp);
2943
3045
 
2944
- class StreamWriter {
2945
- RG_DELETE_COPY(StreamWriter)
3046
+ #define DEFINE_FMT_VARIANT(Name, Ret, Type) \
3047
+ static inline Ret Name(Type out, const char *fmt) \
3048
+ { \
3049
+ return Name##Fmt(fmt, {}, out); \
3050
+ } \
3051
+ template <typename... Args> \
3052
+ Ret Name(Type out, const char *fmt, Args... args) \
3053
+ { \
3054
+ const FmtArg fmt_args[] = { FmtArg(args)... }; \
3055
+ return Name##Fmt(fmt, fmt_args, out); \
3056
+ }
2946
3057
 
2947
- enum class DestinationType {
2948
- Memory,
2949
- File,
2950
- Function
2951
- };
3058
+ DEFINE_FMT_VARIANT(Fmt, Span<char>, Span<char>)
3059
+ DEFINE_FMT_VARIANT(Fmt, Span<char>, HeapArray<char> *)
3060
+ DEFINE_FMT_VARIANT(Fmt, Span<char>, Allocator *)
3061
+ DEFINE_FMT_VARIANT(Print, void, StreamWriter *)
3062
+ DEFINE_FMT_VARIANT(Print, void, FILE *)
3063
+ DEFINE_FMT_VARIANT(PrintLn, void, StreamWriter *)
3064
+ DEFINE_FMT_VARIANT(PrintLn, void, FILE *)
2952
3065
 
2953
- const char *filename = nullptr;
2954
- bool error = true;
3066
+ #undef DEFINE_FMT_VARIANT
2955
3067
 
2956
- struct {
2957
- DestinationType type = DestinationType::Memory;
2958
- union U {
2959
- struct {
2960
- HeapArray<uint8_t> *memory;
2961
- Size start;
2962
- } mem;
2963
- struct {
2964
- FILE *fp;
2965
- bool owned;
3068
+ // Print formatted strings to stdout
3069
+ template <typename... Args>
3070
+ void Print(const char *fmt, Args... args)
3071
+ {
3072
+ Print(stdout, fmt, args...);
3073
+ }
3074
+ template <typename... Args>
3075
+ void PrintLn(const char *fmt, Args... args)
3076
+ {
3077
+ PrintLn(stdout, fmt, args...);
3078
+ }
2966
3079
 
2967
- // Atomic write mode
2968
- const char *tmp_filename;
2969
- bool tmp_exclusive;
2970
- } file;
2971
- std::function<bool(Span<const uint8_t>)> func;
3080
+ // PrintLn variants without format strings
3081
+ void PrintLn(StreamWriter *out_st);
3082
+ void PrintLn(FILE *out_fp);
3083
+ void PrintLn();
2972
3084
 
2973
- // StreamWriter deals with func destructor
2974
- U() {}
2975
- ~U() {}
2976
- } u;
3085
+ // ------------------------------------------------------------------------
3086
+ // Debug and errors
3087
+ // ------------------------------------------------------------------------
2977
3088
 
2978
- bool vt100;
2979
- } dest;
3089
+ typedef void LogFunc(LogLevel level, const char *ctx, const char *msg);
3090
+ typedef void LogFilterFunc(LogLevel level, const char *ctx, const char *msg,
3091
+ FunctionRef<LogFunc> func);
2980
3092
 
2981
- struct {
2982
- CompressionType type = CompressionType::None;
2983
- CompressionSpeed speed = CompressionSpeed::Default;
2984
- union {
2985
- struct MinizDeflateContext *miniz;
2986
- struct BrotliEncoderStateStruct *brotli;
2987
- } u;
2988
- } compression;
3093
+ const char *GetQualifiedEnv(const char *name);
3094
+ bool GetDebugFlag(const char *name);
2989
3095
 
2990
- BlockAllocator str_alloc;
3096
+ void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg> args);
2991
3097
 
2992
- public:
2993
- StreamWriter() { Close(true); }
2994
- StreamWriter(HeapArray<uint8_t> *mem, const char *filename = nullptr,
2995
- CompressionType compression_type = CompressionType::None,
2996
- CompressionSpeed compression_speed = CompressionSpeed::Default)
2997
- : StreamWriter() { Open(mem, filename, compression_type, compression_speed); }
2998
- StreamWriter(FILE *fp, const char *filename,
2999
- CompressionType compression_type = CompressionType::None,
3000
- CompressionSpeed compression_speed = CompressionSpeed::Default)
3001
- : StreamWriter() { Open(fp, filename, compression_type, compression_speed); }
3002
- StreamWriter(const char *filename, unsigned int flags = 0,
3003
- CompressionType compression_type = CompressionType::None,
3004
- CompressionSpeed compression_speed = CompressionSpeed::Default)
3005
- : StreamWriter() { Open(filename, flags, compression_type, compression_speed); }
3006
- StreamWriter(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
3007
- CompressionType compression_type = CompressionType::None,
3008
- CompressionSpeed compression_speed = CompressionSpeed::Default)
3009
- : StreamWriter() { Open(func, filename, compression_type, compression_speed); }
3010
- ~StreamWriter() { Close(true); }
3098
+ static inline void Log(LogLevel level, const char *ctx)
3099
+ {
3100
+ LogFmt(level, ctx, "", {});
3101
+ }
3102
+ static inline void Log(LogLevel level, const char *ctx, const char *fmt)
3103
+ {
3104
+ LogFmt(level, ctx, fmt, {});
3105
+ }
3106
+ template <typename... Args>
3107
+ static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args... args)
3108
+ {
3109
+ const FmtArg fmt_args[] = { FmtArg(args)... };
3110
+ LogFmt(level, ctx, fmt, fmt_args);
3111
+ }
3011
3112
 
3012
- bool Open(HeapArray<uint8_t> *mem, const char *filename = nullptr,
3013
- CompressionType compression_type = CompressionType::None,
3014
- CompressionSpeed compression_speed = CompressionSpeed::Default);
3015
- bool Open(FILE *fp, const char *filename,
3016
- CompressionType compression_type = CompressionType::None,
3017
- CompressionSpeed compression_speed = CompressionSpeed::Default);
3018
- bool Open(const char *filename, unsigned int flags = 0,
3019
- CompressionType compression_type = CompressionType::None,
3020
- CompressionSpeed compression_speed = CompressionSpeed::Default);
3021
- bool Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
3022
- CompressionType compression_type = CompressionType::None,
3023
- CompressionSpeed compression_speed = CompressionSpeed::Default);
3024
- bool Close() { return Close(false); }
3025
-
3026
- // For compressed streams, Flush may not be complete and only Close() can finalize the file.
3027
- bool Flush();
3028
-
3029
- const char *GetFileName() const { return filename; }
3030
- CompressionType GetCompressionType() const { return compression.type; }
3031
- bool IsVt100() const { return dest.vt100; }
3032
- bool IsValid() const { return filename && !error; }
3033
-
3034
- bool Write(Span<const uint8_t> buf);
3035
- bool Write(Span<const char> buf) { return Write(buf.As<const uint8_t>()); }
3036
- bool Write(char buf) { return Write(MakeSpan(&buf, 1)); }
3037
- bool Write(const void *buf, Size len) { return Write(MakeSpan((const uint8_t *)buf, len)); }
3038
-
3039
- private:
3040
- bool Close(bool implicit);
3041
-
3042
- bool InitCompressor(CompressionType type, CompressionSpeed speed);
3043
-
3044
- bool WriteDeflate(Span<const uint8_t> buf);
3045
- bool WriteBrotli(Span<const uint8_t> buf);
3046
-
3047
- bool WriteRaw(Span<const uint8_t> buf);
3048
- };
3113
+ // Shortcut log functions
3114
+ #ifdef RG_DEBUG
3115
+ template <typename... Args>
3116
+ static inline void LogDebug(Args... args) { Log(LogLevel::Debug, "Debug", args...); }
3117
+ #else
3118
+ template <typename... Args>
3119
+ static inline void LogDebug(Args...) {}
3120
+ #endif
3121
+ template <typename... Args>
3122
+ static inline void LogInfo(Args... args) { Log(LogLevel::Info, nullptr, args...); }
3123
+ template <typename... Args>
3124
+ static inline void LogWarning(Args... args) { Log(LogLevel::Warning, "Warning", args...); }
3125
+ template <typename... Args>
3126
+ static inline void LogError(Args... args) { Log(LogLevel::Error, "Error", args...); }
3049
3127
 
3050
- static inline bool WriteFile(Span<const uint8_t> buf, const char *filename, unsigned int flags = 0,
3051
- CompressionType compression_type = CompressionType::None)
3052
- {
3053
- StreamWriter st(filename, flags, compression_type);
3054
- st.Write(buf);
3055
- return st.Close();
3056
- }
3057
- static inline bool WriteFile(Span<const char> buf, const char *filename, unsigned int flags = 0,
3058
- CompressionType compression_type = CompressionType::None)
3059
- {
3060
- StreamWriter st(filename, flags, compression_type);
3061
- st.Write(buf);
3062
- return st.Close();
3063
- }
3128
+ void SetLogHandler(const std::function<LogFunc> &func);
3129
+ void DefaultLogHandler(LogLevel level, const char *ctx, const char *msg);
3064
3130
 
3065
- bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer);
3131
+ void PushLogFilter(const std::function<LogFilterFunc> &func);
3132
+ void PopLogFilter();
3066
3133
 
3067
- // For convenience, don't close them
3068
- extern StreamReader stdin_st;
3069
- extern StreamWriter stdout_st;
3070
- extern StreamWriter stderr_st;
3134
+ #ifdef _WIN32
3135
+ bool RedirectLogToWindowsEvents(const char *name);
3136
+ #endif
3071
3137
 
3072
3138
  // ------------------------------------------------------------------------
3073
- // Format
3139
+ // Strings
3074
3140
  // ------------------------------------------------------------------------
3075
3141
 
3076
- enum class FmtType {
3077
- Str1,
3078
- Str2,
3079
- Buffer,
3080
- Char,
3081
- Bool,
3082
- Integer,
3083
- Unsigned,
3084
- Float,
3085
- Double,
3086
- Binary,
3087
- Hexadecimal,
3088
- MemorySize,
3089
- DiskSize,
3090
- Date,
3091
- TimeISO,
3092
- TimeNice,
3093
- Random,
3094
- FlagNames,
3095
- FlagOptions,
3096
- Span
3097
- };
3098
-
3099
- class FmtArg {
3100
- public:
3101
- FmtType type;
3102
- union {
3103
- const char *str1;
3104
- Span<const char> str2;
3105
- char buf[32];
3106
- char ch;
3107
- bool b;
3108
- int64_t i;
3109
- uint64_t u;
3110
- struct {
3111
- float value;
3112
- int min_prec;
3113
- int max_prec;
3114
- } f;
3115
- struct {
3116
- double value;
3117
- int min_prec;
3118
- int max_prec;
3119
- } d;
3120
- const void *ptr;
3121
- LocalDate date;
3122
- TimeSpec time;
3123
- Size random_len;
3124
- struct {
3125
- uint64_t flags;
3126
- union {
3127
- Span<const char *const> names;
3128
- Span<const struct OptionDesc> options;
3129
- } u;
3130
- const char *separator;
3131
- } flags;
3132
-
3133
- struct {
3134
- FmtType type;
3135
- int type_len;
3136
- const void *ptr;
3137
- Size len;
3138
- const char *separator;
3139
- } span;
3140
- } u;
3141
-
3142
- int repeat = 1;
3143
- int pad_len = 0;
3144
- char pad_char = 0;
3145
-
3146
- FmtArg() = default;
3147
- FmtArg(std::nullptr_t) : type(FmtType::Str1) { u.str1 = "(null)"; }
3148
- FmtArg(const char *str) : type(FmtType::Str1) { u.str1 = str ? str : "(null)"; }
3149
- FmtArg(Span<const char> str) : type(FmtType::Str2) { u.str2 = str; }
3150
- FmtArg(char c) : type(FmtType::Char) { u.ch = c; }
3151
- FmtArg(bool b) : type(FmtType::Bool) { u.b = b; }
3152
- FmtArg(unsigned char i) : type(FmtType::Unsigned) { u.u = i; }
3153
- FmtArg(short i) : type(FmtType::Integer) { u.i = i; }
3154
- FmtArg(unsigned short i) : type(FmtType::Unsigned) { u.u = i; }
3155
- FmtArg(int i) : type(FmtType::Integer) { u.i = i; }
3156
- FmtArg(unsigned int i) : type(FmtType::Unsigned) { u.u = i; }
3157
- FmtArg(long i) : type(FmtType::Integer) { u.i = i; }
3158
- FmtArg(unsigned long i) : type(FmtType::Unsigned) { u.u = i; }
3159
- FmtArg(long long i) : type(FmtType::Integer) { u.i = i; }
3160
- FmtArg(unsigned long long i) : type(FmtType::Unsigned) { u.u = i; }
3161
- FmtArg(float f) : type(FmtType::Float) { u.f = { f, 0, INT_MAX }; }
3162
- FmtArg(double d) : type(FmtType::Double) { u.d = { d, 0, INT_MAX }; }
3163
- FmtArg(const void *ptr) : type(FmtType::Hexadecimal) { u.u = (uint64_t)ptr; }
3164
- FmtArg(const LocalDate &date) : type(FmtType::Date) { u.date = date; }
3165
-
3166
- FmtArg &Repeat(int new_repeat) { repeat = new_repeat; return *this; }
3167
- FmtArg &Pad(int len, char c = ' ') { pad_char = c; pad_len = len; return *this; }
3168
- FmtArg &Pad0(int len) { return Pad(len, '0'); }
3169
- };
3142
+ bool CopyString(const char *str, Span<char> buf);
3143
+ bool CopyString(Span<const char> str, Span<char> buf);
3144
+ Span<char> DuplicateString(Span<const char> str, Allocator *alloc);
3170
3145
 
3171
- static inline FmtArg FmtBin(uint64_t u)
3146
+ static inline bool IsAsciiAlpha(int c)
3172
3147
  {
3173
- FmtArg arg;
3174
- arg.type = FmtType::Binary;
3175
- arg.u.u = u;
3176
- return arg;
3148
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
3177
3149
  }
3178
- static inline FmtArg FmtHex(uint64_t u)
3150
+ static inline bool IsAsciiDigit(int c)
3179
3151
  {
3180
- FmtArg arg;
3181
- arg.type = FmtType::Hexadecimal;
3182
- arg.u.u = u;
3183
- return arg;
3152
+ return (c >= '0' && c <= '9');
3184
3153
  }
3185
-
3186
- static inline FmtArg FmtFloat(float f, int min_prec, int max_prec)
3154
+ static inline bool IsAsciiAlphaOrDigit(int c)
3187
3155
  {
3188
- FmtArg arg;
3189
- arg.type = FmtType::Float;
3190
- arg.u.f.value = f;
3191
- arg.u.f.min_prec = min_prec;
3192
- arg.u.f.max_prec = max_prec;
3193
- return arg;
3156
+ return IsAsciiAlpha(c) || IsAsciiDigit(c);
3194
3157
  }
3195
- static inline FmtArg FmtFloat(float f, int prec) { return FmtFloat(f, prec, prec); }
3196
- static inline FmtArg FmtFloat(float f) { return FmtFloat(f, 0, INT_MAX); }
3197
-
3198
- static inline FmtArg FmtDouble(double d, int min_prec, int max_prec)
3158
+ static inline bool IsAsciiWhite(int c)
3199
3159
  {
3200
- FmtArg arg;
3201
- arg.type = FmtType::Double;
3202
- arg.u.d.value = d;
3203
- arg.u.d.min_prec = min_prec;
3204
- arg.u.d.max_prec = max_prec;
3205
- return arg;
3160
+ return c == ' ' || c == '\t' || c == '\v' ||
3161
+ c == '\n' || c == '\r' || c == '\f';
3206
3162
  }
3207
- static inline FmtArg FmtDouble(double d, int prec) { return FmtDouble(d, prec, prec); }
3208
- static inline FmtArg FmtDouble(double d) { return FmtDouble(d, 0, INT_MAX); }
3209
3163
 
3210
- static inline FmtArg FmtMemSize(int64_t size)
3164
+ static inline char UpperAscii(int c)
3211
3165
  {
3212
- FmtArg arg;
3213
- arg.type = FmtType::MemorySize;
3214
- arg.u.i = size;
3215
- return arg;
3166
+ if (c >= 'a' && c <= 'z') {
3167
+ return (char)(c - 32);
3168
+ } else {
3169
+ return (char)c;
3170
+ }
3216
3171
  }
3217
- static inline FmtArg FmtDiskSize(int64_t size)
3172
+ static inline char LowerAscii(int c)
3218
3173
  {
3219
- FmtArg arg;
3220
- arg.type = FmtType::DiskSize;
3221
- arg.u.i = size;
3222
- return arg;
3174
+ if (c >= 'A' && c <= 'Z') {
3175
+ return (char)(c + 32);
3176
+ } else {
3177
+ return (char)c;
3178
+ }
3223
3179
  }
3224
3180
 
3225
- static inline FmtArg FmtTimeISO(TimeSpec spec)
3181
+ static inline bool TestStr(Span<const char> str1, Span<const char> str2)
3226
3182
  {
3227
- FmtArg arg;
3228
- arg.type = FmtType::TimeISO;
3229
- arg.u.time = spec;
3230
- return arg;
3183
+ if (str1.len != str2.len)
3184
+ return false;
3185
+ for (Size i = 0; i < str1.len; i++) {
3186
+ if (str1[i] != str2[i])
3187
+ return false;
3188
+ }
3189
+ return true;
3231
3190
  }
3232
-
3233
- static inline FmtArg FmtTimeNice(TimeSpec spec)
3191
+ static inline bool TestStr(Span<const char> str1, const char *str2)
3234
3192
  {
3235
- FmtArg arg;
3236
- arg.type = FmtType::TimeNice;
3237
- arg.u.time = spec;
3238
- return arg;
3193
+ Size i;
3194
+ for (i = 0; i < str1.len && str2[i]; i++) {
3195
+ if (str1[i] != str2[i])
3196
+ return false;
3197
+ }
3198
+ return (i == str1.len) && !str2[i];
3239
3199
  }
3240
-
3241
- static inline FmtArg FmtRandom(Size len)
3242
- {
3243
- RG_ASSERT(len < 256);
3244
- len = std::min(len, (Size)256);
3245
-
3246
- FmtArg arg;
3247
- arg.type = FmtType::Random;
3248
- arg.u.random_len = len;
3249
- return arg;
3250
- }
3251
-
3252
- static inline FmtArg FmtFlags(uint64_t flags, Span<const char *const> names, const char *sep = ", ")
3253
- {
3254
- FmtArg arg;
3255
- arg.type = FmtType::FlagNames;
3256
- arg.u.flags.flags = flags & ((1ull << names.len) - 1);
3257
- arg.u.flags.u.names = names;
3258
- arg.u.flags.separator = sep;
3259
- return arg;
3260
- }
3261
-
3262
- static inline FmtArg FmtFlags(uint64_t flags, Span<const struct OptionDesc> options, const char *sep = ", ")
3263
- {
3264
- FmtArg arg;
3265
- arg.type = FmtType::FlagOptions;
3266
- arg.u.flags.flags = flags & ((1ull << options.len) - 1);
3267
- arg.u.flags.u.options = options;
3268
- arg.u.flags.separator = sep;
3269
- return arg;
3270
- }
3271
-
3272
- template <typename T>
3273
- FmtArg FmtSpan(Span<T> arr, FmtType type, const char *sep = ", ")
3274
- {
3275
- FmtArg arg;
3276
- arg.type = FmtType::Span;
3277
- arg.u.span.type = type;
3278
- arg.u.span.type_len = RG_SIZE(T);
3279
- arg.u.span.ptr = (const void *)arr.ptr;
3280
- arg.u.span.len = arr.len;
3281
- arg.u.span.separator = sep;
3282
- return arg;
3283
- }
3284
- template <typename T>
3285
- FmtArg FmtSpan(Span<T> arr, const char *sep = ", ") { return FmtSpan(arr, FmtArg(T()).type, sep); }
3286
- template <typename T, Size N>
3287
- FmtArg FmtSpan(T (&arr)[N], FmtType type, const char *sep = ", ") { return FmtSpan(MakeSpan(arr), type, sep); }
3288
- template <typename T, Size N>
3289
- FmtArg FmtSpan(T (&arr)[N], const char *sep = ", ") { return FmtSpan(MakeSpan(arr), sep); }
3290
-
3291
- enum class LogLevel {
3292
- Debug,
3293
- Info,
3294
- Warning,
3295
- Error
3296
- };
3297
-
3298
- Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, Span<char> out_buf);
3299
- Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, HeapArray<char> *out_buf);
3300
- Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, Allocator *alloc);
3301
- void PrintFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *out_st);
3302
- void PrintFmt(const char *fmt, Span<const FmtArg> args, FILE *out_fp);
3303
- void PrintLnFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *out_st);
3304
- void PrintLnFmt(const char *fmt, Span<const FmtArg> args, FILE *out_fp);
3305
-
3306
- #define DEFINE_FMT_VARIANT(Name, Ret, Type) \
3307
- static inline Ret Name(Type out, const char *fmt) \
3308
- { \
3309
- return Name##Fmt(fmt, {}, out); \
3310
- } \
3311
- template <typename... Args> \
3312
- Ret Name(Type out, const char *fmt, Args... args) \
3313
- { \
3314
- const FmtArg fmt_args[] = { FmtArg(args)... }; \
3315
- return Name##Fmt(fmt, fmt_args, out); \
3316
- }
3317
-
3318
- DEFINE_FMT_VARIANT(Fmt, Span<char>, Span<char>)
3319
- DEFINE_FMT_VARIANT(Fmt, Span<char>, HeapArray<char> *)
3320
- DEFINE_FMT_VARIANT(Fmt, Span<char>, Allocator *)
3321
- DEFINE_FMT_VARIANT(Print, void, StreamWriter *)
3322
- DEFINE_FMT_VARIANT(Print, void, FILE *)
3323
- DEFINE_FMT_VARIANT(PrintLn, void, StreamWriter *)
3324
- DEFINE_FMT_VARIANT(PrintLn, void, FILE *)
3325
-
3326
- #undef DEFINE_FMT_VARIANT
3327
-
3328
- // Print formatted strings to stdout
3329
- template <typename... Args>
3330
- void Print(const char *fmt, Args... args)
3331
- {
3332
- Print(stdout, fmt, args...);
3333
- }
3334
- template <typename... Args>
3335
- void PrintLn(const char *fmt, Args... args)
3336
- {
3337
- PrintLn(stdout, fmt, args...);
3338
- }
3339
-
3340
- // PrintLn variants without format strings
3341
- static inline void PrintLn(StreamWriter *out_st) { out_st->Write('\n'); }
3342
- static inline void PrintLn(FILE *out_fp) { fputc('\n', out_fp); }
3343
- static inline void PrintLn() { putchar('\n'); }
3344
-
3345
- // ------------------------------------------------------------------------
3346
- // Debug and errors
3347
- // ------------------------------------------------------------------------
3348
-
3349
- typedef void LogFunc(LogLevel level, const char *ctx, const char *msg);
3350
- typedef void LogFilterFunc(LogLevel level, const char *ctx, const char *msg,
3351
- FunctionRef<LogFunc> func);
3352
-
3353
- const char *GetQualifiedEnv(const char *name);
3354
- bool GetDebugFlag(const char *name);
3355
-
3356
- void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg> args);
3357
-
3358
- static inline void Log(LogLevel level, const char *ctx)
3359
- {
3360
- LogFmt(level, ctx, "", {});
3361
- }
3362
- static inline void Log(LogLevel level, const char *ctx, const char *fmt)
3363
- {
3364
- LogFmt(level, ctx, fmt, {});
3365
- }
3366
- template <typename... Args>
3367
- static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args... args)
3368
- {
3369
- const FmtArg fmt_args[] = { FmtArg(args)... };
3370
- LogFmt(level, ctx, fmt, fmt_args);
3371
- }
3372
-
3373
- // Shortcut log functions
3374
- #ifdef RG_DEBUG
3375
- template <typename... Args>
3376
- static inline void LogDebug(Args... args) { Log(LogLevel::Debug, "Debug", args...); }
3377
- #else
3378
- template <typename... Args>
3379
- static inline void LogDebug(Args...) {}
3380
- #endif
3381
- template <typename... Args>
3382
- static inline void LogInfo(Args... args) { Log(LogLevel::Info, nullptr, args...); }
3383
- template <typename... Args>
3384
- static inline void LogError(Args... args) { Log(LogLevel::Error, "Error", args...); }
3385
-
3386
- void SetLogHandler(const std::function<LogFunc> &func);
3387
- void DefaultLogHandler(LogLevel level, const char *ctx, const char *msg);
3388
-
3389
- void PushLogFilter(const std::function<LogFilterFunc> &func);
3390
- void PopLogFilter();
3391
-
3392
- #ifdef _WIN32
3393
- bool RedirectLogToWindowsEvents(const char *name);
3394
- #endif
3395
-
3396
- // ------------------------------------------------------------------------
3397
- // Strings
3398
- // ------------------------------------------------------------------------
3399
-
3400
- bool CopyString(const char *str, Span<char> buf);
3401
- bool CopyString(Span<const char> str, Span<char> buf);
3402
- Span<char> DuplicateString(Span<const char> str, Allocator *alloc);
3403
-
3404
- static inline bool IsAsciiAlpha(int c)
3405
- {
3406
- return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
3407
- }
3408
- static inline bool IsAsciiDigit(int c)
3409
- {
3410
- return (c >= '0' && c <= '9');
3411
- }
3412
- static inline bool IsAsciiAlphaOrDigit(int c)
3413
- {
3414
- return IsAsciiAlpha(c) || IsAsciiDigit(c);
3415
- }
3416
- static inline bool IsAsciiWhite(int c)
3417
- {
3418
- return c == ' ' || c == '\t' || c == '\v' ||
3419
- c == '\n' || c == '\r' || c == '\f';
3420
- }
3421
-
3422
- static inline char UpperAscii(int c)
3423
- {
3424
- if (c >= 'a' && c <= 'z') {
3425
- return (char)(c - 32);
3426
- } else {
3427
- return (char)c;
3428
- }
3429
- }
3430
- static inline char LowerAscii(int c)
3431
- {
3432
- if (c >= 'A' && c <= 'Z') {
3433
- return (char)(c + 32);
3434
- } else {
3435
- return (char)c;
3436
- }
3437
- }
3438
-
3439
- static inline bool TestStr(Span<const char> str1, Span<const char> str2)
3440
- {
3441
- if (str1.len != str2.len)
3442
- return false;
3443
- for (Size i = 0; i < str1.len; i++) {
3444
- if (str1[i] != str2[i])
3445
- return false;
3446
- }
3447
- return true;
3448
- }
3449
- static inline bool TestStr(Span<const char> str1, const char *str2)
3450
- {
3451
- Size i;
3452
- for (i = 0; i < str1.len && str2[i]; i++) {
3453
- if (str1[i] != str2[i])
3454
- return false;
3455
- }
3456
- return (i == str1.len) && !str2[i];
3457
- }
3458
- static inline bool TestStr(const char *str1, Span<const char> str2)
3459
- { return TestStr(str2, str1); }
3460
- static inline bool TestStr(const char *str1, const char *str2)
3461
- { return !strcmp(str1, str2); }
3200
+ static inline bool TestStr(const char *str1, Span<const char> str2)
3201
+ { return TestStr(str2, str1); }
3202
+ static inline bool TestStr(const char *str1, const char *str2)
3203
+ { return !strcmp(str1, str2); }
3462
3204
 
3463
3205
  // Allow direct Span<const char> equality comparison
3464
3206
  inline bool Span<const char>::operator==(Span<const char> other) const
@@ -3563,729 +3305,1173 @@ static inline Size StartsWith(const char *str, const char *prefix)
3563
3305
  if (str[i] != prefix[i])
3564
3306
  return 0;
3565
3307
 
3566
- i++;
3567
- }
3308
+ i++;
3309
+ }
3310
+
3311
+ return !prefix[i] ? i : 0;
3312
+ }
3313
+
3314
+ static inline bool EndsWith(Span<const char> str, const char *suffix)
3315
+ {
3316
+ Size i = str.len - 1;
3317
+ Size j = (Size)strlen(suffix) - 1;
3318
+ while (i >= 0 && j >= 0) {
3319
+ if (str[i] != suffix[j])
3320
+ return false;
3321
+
3322
+ i--;
3323
+ j--;
3324
+ }
3325
+
3326
+ return j < 0;
3327
+ }
3328
+
3329
+ static inline Size FindStr(Span<const char> str, Span<const char> needle)
3330
+ {
3331
+ if (!needle.len)
3332
+ return 0;
3333
+ if (needle.len > str.len)
3334
+ return -1;
3335
+
3336
+ Size end = str.len - needle.len;
3337
+
3338
+ for (Size i = 0; i <= end; i++) {
3339
+ if (!memcmp(str.ptr + i, needle.ptr, (size_t)needle.len))
3340
+ return i;
3341
+ }
3342
+
3343
+ return -1;
3344
+ }
3345
+ static inline Size FindStr(const char *str, const char *needle)
3346
+ {
3347
+ const char *ret = strstr(str, needle);
3348
+ return ret ? ret - str : -1;
3349
+ }
3350
+
3351
+ static inline Span<char> SplitStr(Span<char> str, char split_char, Span<char> *out_remainder = nullptr)
3352
+ {
3353
+ Size part_len = 0;
3354
+ while (part_len < str.len) {
3355
+ if (str[part_len] == split_char) {
3356
+ if (out_remainder) {
3357
+ *out_remainder = str.Take(part_len + 1, str.len - part_len - 1);
3358
+ }
3359
+ return str.Take(0, part_len);
3360
+ }
3361
+ part_len++;
3362
+ }
3363
+
3364
+ if (out_remainder) {
3365
+ *out_remainder = str.Take(str.len, 0);
3366
+ }
3367
+ return str;
3368
+ }
3369
+ static inline Span<char> SplitStr(char *str, char split_char, char **out_remainder = nullptr)
3370
+ {
3371
+ Size part_len = 0;
3372
+ while (str[part_len]) {
3373
+ if (str[part_len] == split_char) {
3374
+ if (out_remainder) {
3375
+ *out_remainder = str + part_len + 1;
3376
+ }
3377
+ return MakeSpan(str, part_len);
3378
+ }
3379
+ part_len++;
3380
+ }
3381
+
3382
+ if (out_remainder) {
3383
+ *out_remainder = str + part_len;
3384
+ }
3385
+ return MakeSpan(str, part_len);
3386
+ }
3387
+ static inline Span<const char> SplitStr(Span<const char> str, char split_char, Span<const char> *out_remainder = nullptr)
3388
+ { return SplitStr(MakeSpan((char *)str.ptr, str.len), split_char, (Span<char> *)out_remainder); }
3389
+ static inline Span<const char> SplitStr(const char *str, char split_char, const char **out_remainder = nullptr)
3390
+ { return SplitStr((char *)str, split_char, (char **)out_remainder); }
3391
+
3392
+ static inline Span<char> SplitStrLine(Span<char> str, Span<char> *out_remainder = nullptr)
3393
+ {
3394
+ Span<char> part = SplitStr(str, '\n', out_remainder);
3395
+ if (part.len < str.len && part.len && part[part.len - 1] == '\r') {
3396
+ part.len--;
3397
+ }
3398
+ return part;
3399
+ }
3400
+ static inline Span<char> SplitStrLine(char *str, char **out_remainder = nullptr)
3401
+ {
3402
+ Span<char> part = SplitStr(str, '\n', out_remainder);
3403
+ if (str[part.len] && part.len && part[part.len - 1] == '\r') {
3404
+ part.len--;
3405
+ }
3406
+ return part;
3407
+ }
3408
+ static inline Span<const char> SplitStrLine(Span<const char> str, Span<const char> *out_remainder = nullptr)
3409
+ { return SplitStrLine(MakeSpan((char *)str.ptr, str.len), (Span<char> *)out_remainder); }
3410
+ static inline Span<const char> SplitStrLine(const char *str, const char **out_remainder = nullptr)
3411
+ { return SplitStrLine((char *)str, (char **)out_remainder); }
3412
+
3413
+ static inline Span<char> SplitStrAny(Span<char> str, const char *split_chars, Span<char> *out_remainder = nullptr)
3414
+ {
3415
+ Bitset<256> split_mask;
3416
+ for (Size i = 0; split_chars[i]; i++) {
3417
+ uint8_t c = (uint8_t)split_chars[i];
3418
+ split_mask.Set(c);
3419
+ }
3420
+
3421
+ Size part_len = 0;
3422
+ while (part_len < str.len) {
3423
+ uint8_t c = (uint8_t)str[part_len];
3424
+
3425
+ if (split_mask.Test(c)) {
3426
+ if (out_remainder) {
3427
+ *out_remainder = str.Take(part_len + 1, str.len - part_len - 1);
3428
+ }
3429
+ return str.Take(0, part_len);
3430
+ }
3431
+ part_len++;
3432
+ }
3433
+
3434
+ if (out_remainder) {
3435
+ *out_remainder = str.Take(str.len, 0);
3436
+ }
3437
+ return str;
3438
+ }
3439
+ static inline Span<char> SplitStrAny(char *str, const char *split_chars, char **out_remainder = nullptr)
3440
+ {
3441
+ Bitset<256> split_mask;
3442
+ for (Size i = 0; split_chars[i]; i++) {
3443
+ uint8_t c = (uint8_t)split_chars[i];
3444
+ split_mask.Set(c);
3445
+ }
3446
+
3447
+ Size part_len = 0;
3448
+ while (str[part_len]) {
3449
+ uint8_t c = (uint8_t)str[part_len];
3450
+
3451
+ if (split_mask.Test(c)) {
3452
+ if (out_remainder) {
3453
+ *out_remainder = str + part_len + 1;
3454
+ }
3455
+ return MakeSpan(str, part_len);
3456
+ }
3457
+ part_len++;
3458
+ }
3459
+
3460
+ if (out_remainder) {
3461
+ *out_remainder = str + part_len;
3462
+ }
3463
+ return MakeSpan(str, part_len);
3464
+ }
3465
+ static inline Span<const char> SplitStrAny(Span<const char> str, const char *split_chars, Span<const char> *out_remainder = nullptr)
3466
+ { return SplitStrAny(MakeSpan((char *)str.ptr, str.len), split_chars, (Span<char> *)out_remainder); }
3467
+ static inline Span<const char> SplitStrAny(const char *str, const char *split_chars, const char **out_remainder = nullptr)
3468
+ { return SplitStrAny((char *)str, split_chars, (char **)out_remainder); }
3469
+
3470
+ static inline Span<const char> SplitStrReverse(Span<const char> str, char split_char,
3471
+ Span<const char> *out_remainder = nullptr)
3472
+ {
3473
+ Size remainder_len = str.len - 1;
3474
+ while (remainder_len >= 0) {
3475
+ if (str[remainder_len] == split_char) {
3476
+ if (out_remainder) {
3477
+ *out_remainder = str.Take(0, remainder_len);
3478
+ }
3479
+ return str.Take(remainder_len + 1, str.len - remainder_len - 1);
3480
+ }
3481
+ remainder_len--;
3482
+ }
3483
+
3484
+ if (out_remainder) {
3485
+ *out_remainder = str.Take(0, 0);
3486
+ }
3487
+ return str;
3488
+ }
3489
+ static inline Span<const char> SplitStrReverse(const char *str, char split_char,
3490
+ Span<const char> *out_remainder = nullptr)
3491
+ { return SplitStrReverse(MakeSpan(str, strlen(str)), split_char, out_remainder); }
3492
+
3493
+ static inline Span<const char> SplitStrReverseAny(Span<const char> str, const char *split_chars,
3494
+ Span<const char> *out_remainder = nullptr)
3495
+ {
3496
+ Bitset<256> split_mask;
3497
+ for (Size i = 0; split_chars[i]; i++) {
3498
+ uint8_t c = (uint8_t)split_chars[i];
3499
+ split_mask.Set(c);
3500
+ }
3501
+
3502
+ Size remainder_len = str.len - 1;
3503
+ while (remainder_len >= 0) {
3504
+ uint8_t c = (uint8_t)str[remainder_len];
3505
+
3506
+ if (split_mask.Test(c)) {
3507
+ if (out_remainder) {
3508
+ *out_remainder = str.Take(0, remainder_len);
3509
+ }
3510
+ return str.Take(remainder_len + 1, str.len - remainder_len - 1);
3511
+ }
3512
+ remainder_len--;
3513
+ }
3514
+
3515
+ if (out_remainder) {
3516
+ *out_remainder = str.Take(0, 0);
3517
+ }
3518
+ return str;
3519
+ }
3520
+ static inline Span<const char> SplitStrReverseAny(const char *str, const char *split_chars,
3521
+ Span<const char> *out_remainder = nullptr)
3522
+ { return SplitStrReverseAny(MakeSpan(str, strlen(str)), split_chars, out_remainder); }
3523
+
3524
+ static inline Span<char> TrimStrLeft(Span<char> str, const char *trim_chars = " \t\r\n")
3525
+ {
3526
+ while (str.len && strchr(trim_chars, str[0]) && str[0]) {
3527
+ str.ptr++;
3528
+ str.len--;
3529
+ }
3530
+
3531
+ return str;
3532
+ }
3533
+ static inline Span<char> TrimStrRight(Span<char> str, const char *trim_chars = " \t\r\n")
3534
+ {
3535
+ while (str.len && strchr(trim_chars, str[str.len - 1]) && str[str.len - 1]) {
3536
+ str.len--;
3537
+ }
3538
+
3539
+ return str;
3540
+ }
3541
+ static inline Span<char> TrimStr(Span<char> str, const char *trim_chars = " \t\r\n")
3542
+ {
3543
+ str = TrimStrRight(str, trim_chars);
3544
+ str = TrimStrLeft(str, trim_chars);
3545
+
3546
+ return str;
3547
+ }
3548
+ static inline Span<const char> TrimStrLeft(Span<const char> str, const char *trim_chars = " \t\r\n")
3549
+ { return TrimStrLeft(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3550
+ static inline Span<const char> TrimStrRight(Span<const char> str, const char *trim_chars = " \t\r\n")
3551
+ { return TrimStrRight(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3552
+ static inline Span<const char> TrimStr(Span<const char> str, const char *trim_chars = " \t\r\n")
3553
+ { return TrimStr(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3554
+
3555
+ template <typename T>
3556
+ bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3557
+ Span<const char> *out_remaining = nullptr)
3558
+ {
3559
+ if (RG_UNLIKELY(!str.len)) {
3560
+ if (flags & (int)ParseFlag::Log) {
3561
+ LogError("Cannot convert empty string to integer");
3562
+ }
3563
+ return false;
3564
+ }
3565
+
3566
+ uint64_t value = 0;
3567
+
3568
+ Size pos = 0;
3569
+ uint64_t neg = 0;
3570
+ if (str.len >= 2) {
3571
+ if (std::numeric_limits<T>::min() < 0 && str[0] == '-') {
3572
+ pos = 1;
3573
+ neg = UINT64_MAX;
3574
+ } else if (str[0] == '+') {
3575
+ pos = 1;
3576
+ }
3577
+ }
3578
+
3579
+ for (; pos < str.len; pos++) {
3580
+ unsigned int digit = (unsigned int)(str[pos] - '0');
3581
+ if (RG_UNLIKELY(digit > 9)) {
3582
+ if (!pos || flags & (int)ParseFlag::End) {
3583
+ if (flags & (int)ParseFlag::Log) {
3584
+ LogError("Malformed integer number '%1'", str);
3585
+ }
3586
+ return false;
3587
+ } else {
3588
+ break;
3589
+ }
3590
+ }
3591
+
3592
+ uint64_t new_value = (value * 10) + digit;
3593
+ if (RG_UNLIKELY(new_value < value))
3594
+ goto overflow;
3595
+ value = new_value;
3596
+ }
3597
+ if (RG_UNLIKELY(value > (uint64_t)std::numeric_limits<T>::max()))
3598
+ goto overflow;
3599
+ value = ((value ^ neg) - neg);
3600
+
3601
+ if (out_remaining) {
3602
+ *out_remaining = str.Take(pos, str.len - pos);
3603
+ }
3604
+ *out_value = (T)value;
3605
+ return true;
3606
+
3607
+ overflow:
3608
+ if (flags & (int)ParseFlag::Log) {
3609
+ LogError("Integer overflow for number '%1' (max = %2)", str,
3610
+ std::numeric_limits<T>::max());
3611
+ }
3612
+ return false;
3613
+ }
3614
+
3615
+ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3616
+ Span<const char> *out_remaining = nullptr);
3617
+
3618
+ static inline Size EncodeUtf8(int32_t c, char out_buf[4])
3619
+ {
3620
+ if (c < 0x80) {
3621
+ out_buf[0] = (char)c;
3622
+ return 1;
3623
+ } else if (c < 0x800) {
3624
+ out_buf[0] = (char)(0xC0 | (c >> 6));
3625
+ out_buf[1] = (char)(0x80 | (c & 0x3F));
3626
+ return 2;
3627
+ } else if (c >= 0xD800 && c < 0xE000) {
3628
+ return 0;
3629
+ } else if (c < 0x10000) {
3630
+ out_buf[0] = (char)(0xE0 | (c >> 12));
3631
+ out_buf[1] = (char)(0x80 | ((c >> 6) & 0x3F));
3632
+ out_buf[2] = (char)(0x80 | (c & 0x3F));
3633
+ return 3;
3634
+ } else if (c < 0x110000) {
3635
+ out_buf[0] = (char)(0xF0 | (c >> 18));
3636
+ out_buf[1] = (char)(0x80 | ((c >> 12) & 0x3F));
3637
+ out_buf[2] = (char)(0x80 | ((c >> 6) & 0x3F));
3638
+ out_buf[3] = (char)(0x80 | (c & 0x3F));
3639
+ return 4;
3640
+ } else {
3641
+ return 0;
3642
+ }
3643
+ }
3644
+
3645
+ static inline int CountUtf8Bytes(char c)
3646
+ {
3647
+ int ones = CountLeadingZeros((uint32_t)~c << 24);
3648
+ return std::min(std::max(ones, 1), 4);
3649
+ }
3650
+
3651
+ static inline Size DecodeUtf8(const char *str, int32_t *out_c)
3652
+ {
3653
+ RG_ASSERT(str[0]);
3654
+
3655
+ const uint8_t *ptr = (const uint8_t *)str;
3656
+
3657
+ if (ptr[0] < 0x80) {
3658
+ *out_c = ptr[0];
3659
+ return 1;
3660
+ } else if (RG_UNLIKELY(ptr[0] - 0xC2 > 0xF4 - 0xC2)) {
3661
+ return 0;
3662
+ } else if (RG_LIKELY(ptr[1])) {
3663
+ if (ptr[0] < 0xE0 && (ptr[1] & 0xC0) == 0x80) {
3664
+ *out_c = ((ptr[0] & 0x1F) << 6) | (ptr[1] & 0x3F);
3665
+ return 2;
3666
+ } else if (RG_LIKELY(ptr[2])) {
3667
+ if (ptr[0] < 0xF0 && (ptr[1] & 0xC0) == 0x80 &&
3668
+ (ptr[2] & 0xC0) == 0x80) {
3669
+ *out_c = ((ptr[0] & 0xF) << 12) | ((ptr[1] & 0x3F) << 6) | (ptr[2] & 0x3F);
3670
+ return 3;
3671
+ } else if (RG_LIKELY(ptr[3])) {
3672
+ if ((ptr[1] & 0xC0) == 0x80 &&
3673
+ (ptr[2] & 0xC0) == 0x80 &&
3674
+ (ptr[3] & 0xC0) == 0x80) {
3675
+ *out_c = ((ptr[0] & 0x7) << 18) | ((ptr[1] & 0x3F) << 12) | ((ptr[2] & 0x3F) << 6) | (ptr[3] & 0x3F);
3676
+ return 4;
3677
+ }
3678
+ }
3679
+ }
3680
+ }
3681
+
3682
+ return 0;
3683
+ }
3684
+
3685
+ static inline Size DecodeUtf8(Span<const char> str, Size offset, int32_t *out_c)
3686
+ {
3687
+ RG_ASSERT(offset < str.len);
3688
+
3689
+ const uint8_t *ptr = (const uint8_t *)(str.ptr + offset);
3690
+ Size available = str.len - offset;
3691
+
3692
+ if (ptr[0] < 0x80) {
3693
+ *out_c = ptr[0];
3694
+ return 1;
3695
+ } else if (RG_UNLIKELY(ptr[0] - 0xC2 > 0xF4 - 0xC2)) {
3696
+ return 0;
3697
+ } else if (ptr[0] < 0xE0 &&
3698
+ RG_LIKELY(available >= 2 && (ptr[1] & 0xC0) == 0x80)) {
3699
+ *out_c = ((ptr[0] & 0x1F) << 6) | (ptr[1] & 0x3F);
3700
+ return 2;
3701
+ } else if (ptr[0] < 0xF0 &&
3702
+ RG_LIKELY(available >= 3 && (ptr[1] & 0xC0) == 0x80 &&
3703
+ (ptr[2] & 0xC0) == 0x80)) {
3704
+ *out_c = ((ptr[0] & 0xF) << 12) | ((ptr[1] & 0x3F) << 6) | (ptr[2] & 0x3F);
3705
+ return 3;
3706
+ } else if (RG_LIKELY(available >= 4 && (ptr[1] & 0xC0) == 0x80 &&
3707
+ (ptr[2] & 0xC0) == 0x80 &&
3708
+ (ptr[3] & 0xC0) == 0x80)) {
3709
+ *out_c = ((ptr[0] & 0x7) << 18) | ((ptr[1] & 0x3F) << 12) | ((ptr[2] & 0x3F) << 6) | (ptr[3] & 0x3F);
3710
+ return 4;
3711
+ } else {
3712
+ return 0;
3713
+ }
3714
+ }
3715
+
3716
+ // ------------------------------------------------------------------------
3717
+ // System
3718
+ // ------------------------------------------------------------------------
3719
+
3720
+ #ifdef _WIN32
3721
+ #define RG_PATH_SEPARATORS "\\/"
3722
+ #define RG_PATH_DELIMITER ';'
3723
+ #define RG_SHARED_LIBRARY_EXTENSION ".dll"
3724
+ #else
3725
+ #define RG_PATH_SEPARATORS "/"
3726
+ #define RG_PATH_DELIMITER ':'
3727
+ #define RG_SHARED_LIBRARY_EXTENSION ".so"
3728
+ #endif
3729
+
3730
+ #ifdef _WIN32
3731
+ bool IsWin32Utf8();
3732
+ Size ConvertUtf8ToWin32Wide(Span<const char> str, Span<wchar_t> out_str_w);
3733
+ Size ConvertWin32WideToUtf8(const wchar_t *str_w, Span<char> out_str);
3734
+ char *GetWin32ErrorString(uint32_t error_code = UINT32_MAX);
3735
+ #endif
3736
+
3737
+ void SetEnvironmentVar(const char *name, const char *value);
3738
+ void DeleteEnvironmentVar(const char *name);
3739
+
3740
+ static inline bool IsPathSeparator(char c)
3741
+ {
3742
+ #ifdef _WIN32
3743
+ return c == '/' || c == '\\';
3744
+ #else
3745
+ return c == '/';
3746
+ #endif
3747
+ }
3748
+
3749
+ enum class CompressionType {
3750
+ None,
3751
+ Zlib,
3752
+ Gzip,
3753
+ Brotli
3754
+ };
3755
+ static const char *const CompressionTypeNames[] = {
3756
+ "None",
3757
+ "Zlib",
3758
+ "Gzip",
3759
+ "Brotli"
3760
+ };
3761
+
3762
+ Span<const char> GetPathDirectory(Span<const char> filename);
3763
+ Span<const char> GetPathExtension(Span<const char> filename,
3764
+ CompressionType *out_compression_type = nullptr);
3765
+ CompressionType GetPathCompression(Span<const char> filename);
3766
+
3767
+ Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, Allocator *alloc);
3768
+ static inline Span<char> NormalizePath(Span<const char> path, Allocator *alloc)
3769
+ { return NormalizePath(path, {}, alloc); }
3770
+
3771
+ bool PathIsAbsolute(const char *path);
3772
+ bool PathIsAbsolute(Span<const char> path);
3773
+ bool PathContainsDotDot(const char *path);
3774
+
3775
+ enum class StatFlag {
3776
+ IgnoreMissing = 1 << 0,
3777
+ FollowSymlink = 1 << 1
3778
+ };
3779
+
3780
+ enum class FileType {
3781
+ Directory,
3782
+ File,
3783
+ Link,
3784
+ Device,
3785
+ Pipe,
3786
+ Socket
3787
+ };
3788
+ static const char *const FileTypeNames[] = {
3789
+ "Directory",
3790
+ "File",
3791
+ "Link",
3792
+ "Device",
3793
+ "Pipe",
3794
+ "Socket"
3795
+ };
3796
+
3797
+ struct FileInfo {
3798
+ FileType type;
3799
+
3800
+ int64_t size;
3801
+ int64_t mtime;
3802
+ unsigned int mode;
3803
+ };
3804
+
3805
+ enum class StatResult {
3806
+ Success,
3807
+
3808
+ MissingPath,
3809
+ AccessDenied,
3810
+ PartialEnum,
3811
+ CallbackFail,
3812
+ OtherError
3813
+ };
3814
+
3815
+ StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info);
3816
+ static inline StatResult StatFile(const char *filename, FileInfo *out_info)
3817
+ { return StatFile(filename, 0, out_info); }
3818
+
3819
+ enum class RenameFlag {
3820
+ Overwrite = 1 << 0,
3821
+ Sync = 1 << 1
3822
+ };
3823
+
3824
+ // Sync failures are logged but not reported as errors (function returns true)
3825
+ bool RenameFile(const char *src_filename, const char *dest_filename, unsigned int flags);
3826
+
3827
+ enum class EnumResult {
3828
+ Success,
3829
+
3830
+ MissingPath,
3831
+ AccessDenied,
3832
+ PartialEnum,
3833
+ CallbackFail,
3834
+ OtherError
3835
+ };
3836
+
3837
+ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_files,
3838
+ FunctionRef<bool(const char *, FileType)> func);
3839
+ bool EnumerateFiles(const char *dirname, const char *filter, Size max_depth, Size max_files,
3840
+ Allocator *str_alloc, HeapArray<const char *> *out_files);
3841
+ bool IsDirectoryEmpty(const char *dirname);
3842
+
3843
+ bool TestFile(const char *filename);
3844
+ bool TestFile(const char *filename, FileType type);
3845
+
3846
+ bool MatchPathName(const char *path, const char *spec);
3847
+ bool MatchPathSpec(const char *path, const char *spec);
3848
+
3849
+ bool FindExecutableInPath(const char *path, const char *name,
3850
+ Allocator *alloc = nullptr, const char **out_path = nullptr);
3851
+ bool FindExecutableInPath(const char *name, Allocator *alloc = nullptr,
3852
+ const char **out_path = nullptr);
3568
3853
 
3569
- return !prefix[i] ? i : 0;
3570
- }
3854
+ bool SetWorkingDirectory(const char *directory);
3855
+ const char *GetWorkingDirectory();
3571
3856
 
3572
- static inline bool EndsWith(Span<const char> str, const char *suffix)
3573
- {
3574
- Size i = str.len - 1;
3575
- Size j = (Size)strlen(suffix) - 1;
3576
- while (i >= 0 && j >= 0) {
3577
- if (str[i] != suffix[j])
3578
- return false;
3857
+ const char *GetApplicationExecutable(); // Can be NULL (EmSDK)
3858
+ const char *GetApplicationDirectory(); // Can be NULL (EmSDK)
3579
3859
 
3580
- i--;
3581
- j--;
3582
- }
3860
+ bool MakeDirectory(const char *directory, bool error_if_exists = true);
3861
+ bool MakeDirectoryRec(Span<const char> directory);
3862
+ bool UnlinkDirectory(const char *directory, bool error_if_missing = false);
3863
+ bool UnlinkFile(const char *filename, bool error_if_missing = false);
3864
+ bool EnsureDirectoryExists(const char *filename);
3583
3865
 
3584
- return j < 0;
3585
- }
3866
+ enum class OpenFlag {
3867
+ Read = 1 << 0,
3868
+ Write = 1 << 1,
3869
+ Append = 1 << 2,
3586
3870
 
3587
- static inline Size FindStr(Span<const char> str, Span<const char> needle)
3588
- {
3589
- if (!needle.len)
3590
- return 0;
3591
- if (needle.len > str.len)
3592
- return -1;
3871
+ Exclusive = 1 << 3
3872
+ };
3593
3873
 
3594
- Size end = str.len - needle.len;
3874
+ enum class OpenResult {
3875
+ Success = 0,
3595
3876
 
3596
- for (Size i = 0; i <= end; i++) {
3597
- if (!memcmp(str.ptr + i, needle.ptr, (size_t)needle.len))
3598
- return i;
3599
- }
3877
+ MissingPath = 1 << 0,
3878
+ FileExists = 1 << 1,
3879
+ AccessDenied = 1 << 2,
3880
+ OtherError = 1 << 3
3881
+ };
3600
3882
 
3601
- return -1;
3883
+ OpenResult OpenDescriptor(const char *filename, unsigned int flags, unsigned int silent, int *out_fd);
3884
+ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silent, FILE **out_fp);
3885
+
3886
+ static inline OpenResult OpenDescriptor(const char *filename, unsigned int flags, int *out_fd)
3887
+ { return OpenDescriptor(filename, flags, 0, out_fd); }
3888
+ static inline OpenResult OpenFile(const char *filename, unsigned int flags, FILE **out_fp)
3889
+ { return OpenFile(filename, flags, 0, out_fp); }
3890
+ static inline int OpenDescriptor(const char *filename, unsigned int flags)
3891
+ {
3892
+ int fd = -1;
3893
+ if (OpenDescriptor(filename, flags, &fd) != OpenResult::Success)
3894
+ return -1;
3895
+ return fd;
3602
3896
  }
3603
- static inline Size FindStr(const char *str, const char *needle)
3897
+ static inline FILE *OpenFile(const char *filename, unsigned int flags)
3604
3898
  {
3605
- const char *ret = strstr(str, needle);
3606
- return ret ? ret - str : -1;
3899
+ FILE *fp;
3900
+ if (OpenFile(filename, flags, &fp) != OpenResult::Success)
3901
+ return nullptr;
3902
+ return fp;
3607
3903
  }
3608
3904
 
3609
- static inline Span<char> SplitStr(Span<char> str, char split_char, Span<char> *out_remainder = nullptr)
3610
- {
3611
- Size part_len = 0;
3612
- while (part_len < str.len) {
3613
- if (str[part_len] == split_char) {
3614
- if (out_remainder) {
3615
- *out_remainder = str.Take(part_len + 1, str.len - part_len - 1);
3616
- }
3617
- return str.Take(0, part_len);
3618
- }
3619
- part_len++;
3620
- }
3905
+ bool FlushFile(int fd, const char *filename);
3906
+ bool FlushFile(FILE *fp, const char *filename);
3621
3907
 
3622
- if (out_remainder) {
3623
- *out_remainder = str.Take(str.len, 0);
3624
- }
3625
- return str;
3908
+ bool FileIsVt100(FILE *fp);
3909
+
3910
+ #ifdef _WIN32
3911
+ enum class PipeMode {
3912
+ Byte,
3913
+ Message
3914
+ };
3915
+
3916
+ bool CreateOverlappedPipe(bool overlap0, bool overlap1, PipeMode mode, void *out_handles[2]); // HANDLE
3917
+ void CloseHandleSafe(void **handle_ptr); // HANDLE
3918
+ #else
3919
+ void SetSignalHandler(int signal, void (*func)(int), struct sigaction *prev = nullptr);
3920
+
3921
+ bool CreatePipe(int pfd[2]);
3922
+ void CloseDescriptorSafe(int *fd_ptr);
3923
+ #endif
3924
+
3925
+ bool ExecuteCommandLine(const char *cmd_line, FunctionRef<Span<const uint8_t>()> in_func,
3926
+ FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code);
3927
+ bool ExecuteCommandLine(const char *cmd_line, Span<const uint8_t> in_buf, Size max_len,
3928
+ HeapArray<uint8_t> *out_buf, int *out_code);
3929
+ static inline bool ExecuteCommandLine(const char *cmd_line, int *out_code) {
3930
+ return ExecuteCommandLine(cmd_line, {}, {}, out_code);
3626
3931
  }
3627
- static inline Span<char> SplitStr(char *str, char split_char, char **out_remainder = nullptr)
3932
+ static inline bool ExecuteCommandLine(const char *cmd_line, Span<const uint8_t> in_buf,
3933
+ FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code)
3628
3934
  {
3629
- Size part_len = 0;
3630
- while (str[part_len]) {
3631
- if (str[part_len] == split_char) {
3632
- if (out_remainder) {
3633
- *out_remainder = str + part_len + 1;
3634
- }
3635
- return MakeSpan(str, part_len);
3636
- }
3637
- part_len++;
3638
- }
3935
+ const auto read_once = [&]() {
3936
+ Span<const uint8_t> buf = in_buf;
3937
+ in_buf = {};
3938
+ return buf;
3939
+ };
3639
3940
 
3640
- if (out_remainder) {
3641
- *out_remainder = str + part_len;
3642
- }
3643
- return MakeSpan(str, part_len);
3941
+ return ExecuteCommandLine(cmd_line, read_once, out_func, out_code);
3644
3942
  }
3645
- static inline Span<const char> SplitStr(Span<const char> str, char split_char, Span<const char> *out_remainder = nullptr)
3646
- { return SplitStr(MakeSpan((char *)str.ptr, str.len), split_char, (Span<char> *)out_remainder); }
3647
- static inline Span<const char> SplitStr(const char *str, char split_char, const char **out_remainder = nullptr)
3648
- { return SplitStr((char *)str, split_char, (char **)out_remainder); }
3649
-
3650
- static inline Span<char> SplitStrLine(Span<char> str, Span<char> *out_remainder = nullptr)
3943
+ static inline bool ExecuteCommandLine(const char *cmd_line, Span<const char> in_buf,
3944
+ FunctionRef<void(Span<char> buf)> out_func, int *out_code)
3651
3945
  {
3652
- Span<char> part = SplitStr(str, '\n', out_remainder);
3653
- if (part.len < str.len && part.len && part[part.len - 1] == '\r') {
3654
- part.len--;
3655
- }
3656
- return part;
3946
+ const auto write = [&](Span<uint8_t> buf) { out_func(buf.As<char>()); };
3947
+
3948
+ return ExecuteCommandLine(cmd_line, in_buf.As<const uint8_t>(), write, out_code);
3657
3949
  }
3658
- static inline Span<char> SplitStrLine(char *str, char **out_remainder = nullptr)
3950
+ static inline bool ExecuteCommandLine(const char *cmd_line, Span<const char> in_buf, Size max_len,
3951
+ HeapArray<char> *out_buf, int *out_code)
3659
3952
  {
3660
- Span<char> part = SplitStr(str, '\n', out_remainder);
3661
- if (str[part.len] && part.len && part[part.len - 1] == '\r') {
3662
- part.len--;
3663
- }
3664
- return part;
3953
+ return ExecuteCommandLine(cmd_line, in_buf.As<const uint8_t>(), max_len,
3954
+ (HeapArray<uint8_t> *)out_buf, out_code);
3665
3955
  }
3666
- static inline Span<const char> SplitStrLine(Span<const char> str, Span<const char> *out_remainder = nullptr)
3667
- { return SplitStrLine(MakeSpan((char *)str.ptr, str.len), (Span<char> *)out_remainder); }
3668
- static inline Span<const char> SplitStrLine(const char *str, const char **out_remainder = nullptr)
3669
- { return SplitStrLine((char *)str, (char **)out_remainder); }
3670
3956
 
3671
- static inline Span<char> SplitStrAny(Span<char> str, const char *split_chars, Span<char> *out_remainder = nullptr)
3672
- {
3673
- Bitset<256> split_mask;
3674
- for (Size i = 0; split_chars[i]; i++) {
3675
- uint8_t c = (uint8_t)split_chars[i];
3676
- split_mask.Set(c);
3677
- }
3957
+ void WaitDelay(int64_t delay);
3678
3958
 
3679
- Size part_len = 0;
3680
- while (part_len < str.len) {
3681
- uint8_t c = (uint8_t)str[part_len];
3959
+ enum class WaitForResult {
3960
+ Interrupt,
3961
+ Message,
3962
+ Timeout
3963
+ };
3682
3964
 
3683
- if (split_mask.Test(c)) {
3684
- if (out_remainder) {
3685
- *out_remainder = str.Take(part_len + 1, str.len - part_len - 1);
3686
- }
3687
- return str.Take(0, part_len);
3688
- }
3689
- part_len++;
3690
- }
3965
+ // After WaitForInterrupt() has been called once (even with timeout 0), a few
3966
+ // signals (such as SIGINT, SIGHUP) and their Windows equivalent will be permanently ignored.
3967
+ // Beware, on Unix platforms, this may not work correctly if not called from the main thread.
3968
+ WaitForResult WaitForInterrupt(int64_t timeout = -1);
3969
+ void SignalWaitFor();
3691
3970
 
3692
- if (out_remainder) {
3693
- *out_remainder = str.Take(str.len, 0);
3694
- }
3695
- return str;
3696
- }
3697
- static inline Span<char> SplitStrAny(char *str, const char *split_chars, char **out_remainder = nullptr)
3698
- {
3699
- Bitset<256> split_mask;
3700
- for (Size i = 0; split_chars[i]; i++) {
3701
- uint8_t c = (uint8_t)split_chars[i];
3702
- split_mask.Set(c);
3703
- }
3971
+ int GetCoreCount();
3704
3972
 
3705
- Size part_len = 0;
3706
- while (str[part_len]) {
3707
- uint8_t c = (uint8_t)str[part_len];
3973
+ #ifndef _WIN32
3974
+ bool DropRootIdentity();
3975
+ #endif
3976
+ #ifdef __linux__
3977
+ bool NotifySystemd();
3978
+ #endif
3708
3979
 
3709
- if (split_mask.Test(c)) {
3710
- if (out_remainder) {
3711
- *out_remainder = str + part_len + 1;
3712
- }
3713
- return MakeSpan(str, part_len);
3714
- }
3715
- part_len++;
3716
- }
3980
+ #ifndef _WIN32
3981
+ #define RG_POSIX_RESTART_EINTR(CallCode, ErrorCond) \
3982
+ ([&]() { \
3983
+ decltype(CallCode) ret; \
3984
+ while ((ret = (CallCode)) ErrorCond && errno == EINTR); \
3985
+ return ret; \
3986
+ })()
3987
+ #endif
3717
3988
 
3718
- if (out_remainder) {
3719
- *out_remainder = str + part_len;
3720
- }
3721
- return MakeSpan(str, part_len);
3722
- }
3723
- static inline Span<const char> SplitStrAny(Span<const char> str, const char *split_chars, Span<const char> *out_remainder = nullptr)
3724
- { return SplitStrAny(MakeSpan((char *)str.ptr, str.len), split_chars, (Span<char> *)out_remainder); }
3725
- static inline Span<const char> SplitStrAny(const char *str, const char *split_chars, const char **out_remainder = nullptr)
3726
- { return SplitStrAny((char *)str, split_chars, (char **)out_remainder); }
3989
+ // ------------------------------------------------------------------------
3990
+ // Standard paths
3991
+ // ------------------------------------------------------------------------
3727
3992
 
3728
- static inline Span<const char> SplitStrReverse(Span<const char> str, char split_char,
3729
- Span<const char> *out_remainder = nullptr)
3730
- {
3731
- Size remainder_len = str.len - 1;
3732
- while (remainder_len >= 0) {
3733
- if (str[remainder_len] == split_char) {
3734
- if (out_remainder) {
3735
- *out_remainder = str.Take(0, remainder_len);
3736
- }
3737
- return str.Take(remainder_len + 1, str.len - remainder_len - 1);
3738
- }
3739
- remainder_len--;
3740
- }
3993
+ const char *GetUserConfigPath(const char *name, Allocator *alloc);
3994
+ const char *GetUserCachePath(const char *name, Allocator *alloc);
3995
+ const char *GetTemporaryDirectory();
3996
+
3997
+ const char *FindConfigFile(const char *name, Allocator *alloc, LocalArray<const char *, 4> *out_possibilities = nullptr);
3998
+
3999
+ const char *CreateUniqueFile(Span<const char> directory, const char *prefix, const char *extension,
4000
+ Allocator *alloc, FILE **out_fp = nullptr);
4001
+ const char *CreateUniqueDirectory(Span<const char> directory, const char *prefix, Allocator *alloc);
4002
+
4003
+ // ------------------------------------------------------------------------
4004
+ // Random
4005
+ // ------------------------------------------------------------------------
4006
+
4007
+ class FastRandom {
4008
+ uint64_t state[4];
4009
+
4010
+ public:
4011
+ FastRandom();
4012
+ FastRandom(uint64_t seed);
3741
4013
 
3742
- if (out_remainder) {
3743
- *out_remainder = str.Take(0, 0);
3744
- }
3745
- return str;
3746
- }
3747
- static inline Span<const char> SplitStrReverse(const char *str, char split_char,
3748
- Span<const char> *out_remainder = nullptr)
3749
- { return SplitStrReverse(MakeSpan(str, strlen(str)), split_char, out_remainder); }
4014
+ void Fill(void *buf, Size len);
4015
+ void Fill(Span<uint8_t> buf) { Fill(buf.ptr, buf.len); }
3750
4016
 
3751
- static inline Span<const char> SplitStrReverseAny(Span<const char> str, const char *split_chars,
3752
- Span<const char> *out_remainder = nullptr)
3753
- {
3754
- Bitset<256> split_mask;
3755
- for (Size i = 0; split_chars[i]; i++) {
3756
- uint8_t c = (uint8_t)split_chars[i];
3757
- split_mask.Set(c);
3758
- }
4017
+ int GetInt(int min, int max);
3759
4018
 
3760
- Size remainder_len = str.len - 1;
3761
- while (remainder_len >= 0) {
3762
- uint8_t c = (uint8_t)str[remainder_len];
4019
+ private:
4020
+ uint64_t Next();
4021
+ };
3763
4022
 
3764
- if (split_mask.Test(c)) {
3765
- if (out_remainder) {
3766
- *out_remainder = str.Take(0, remainder_len);
3767
- }
3768
- return str.Take(remainder_len + 1, str.len - remainder_len - 1);
3769
- }
3770
- remainder_len--;
3771
- }
4023
+ template <int Min = 0, int Max = INT_MAX>
4024
+ class FastRandomInt {
4025
+ RG_STATIC_ASSERT(Min >= 0);
4026
+ RG_STATIC_ASSERT(Max > Min);
3772
4027
 
3773
- if (out_remainder) {
3774
- *out_remainder = str.Take(0, 0);
3775
- }
3776
- return str;
3777
- }
3778
- static inline Span<const char> SplitStrReverseAny(const char *str, const char *split_chars,
3779
- Span<const char> *out_remainder = nullptr)
3780
- { return SplitStrReverseAny(MakeSpan(str, strlen(str)), split_chars, out_remainder); }
4028
+ FastRandom rng;
3781
4029
 
3782
- static inline Span<char> TrimStrLeft(Span<char> str, const char *trim_chars = " \t\r\n")
3783
- {
3784
- while (str.len && strchr(trim_chars, str[0])) {
3785
- str.ptr++;
3786
- str.len--;
3787
- }
4030
+ public:
4031
+ typedef int result_type;
3788
4032
 
3789
- return str;
3790
- }
3791
- static inline Span<char> TrimStrRight(Span<char> str, const char *trim_chars = " \t\r\n")
3792
- {
3793
- while (str.len && strchr(trim_chars, str[str.len - 1])) {
3794
- str.len--;
3795
- }
4033
+ static constexpr int min() { return Min; }
4034
+ static constexpr int max() { return Max; }
3796
4035
 
3797
- return str;
3798
- }
3799
- static inline Span<char> TrimStr(Span<char> str, const char *trim_chars = " \t\r\n")
3800
- {
3801
- str = TrimStrRight(str, trim_chars);
3802
- str = TrimStrLeft(str, trim_chars);
4036
+ int operator()() { return rng.GetInt(Min, Max); }
4037
+ };
3803
4038
 
3804
- return str;
3805
- }
3806
- static inline Span<const char> TrimStrLeft(Span<const char> str, const char *trim_chars = " \t\r\n")
3807
- { return TrimStrLeft(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3808
- static inline Span<const char> TrimStrRight(Span<const char> str, const char *trim_chars = " \t\r\n")
3809
- { return TrimStrRight(MakeSpan((char *)str.ptr, str.len), trim_chars); }
3810
- static inline Span<const char> TrimStr(Span<const char> str, const char *trim_chars = " \t\r\n")
3811
- { return TrimStr(MakeSpan((char *)str.ptr, str.len), trim_chars); }
4039
+ void ZeroMemorySafe(void *ptr, Size len);
4040
+ void FillRandomSafe(void *buf, Size len);
4041
+ static inline void FillRandomSafe(Span<uint8_t> buf) { FillRandomSafe(buf.ptr, buf.len); }
4042
+ int GetRandomIntSafe(int min, int max);
3812
4043
 
3813
- template <typename T>
3814
- bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3815
- Span<const char> *out_remaining = nullptr)
3816
- {
3817
- if (RG_UNLIKELY(!str.len)) {
3818
- if (flags & (int)ParseFlag::Log) {
3819
- LogError("Cannot convert empty string to integer");
3820
- }
3821
- return false;
3822
- }
4044
+ // ------------------------------------------------------------------------
4045
+ // Sockets
4046
+ // ------------------------------------------------------------------------
3823
4047
 
3824
- uint64_t value = 0;
4048
+ enum class SocketType {
4049
+ Dual,
4050
+ IPv4,
4051
+ IPv6,
4052
+ Unix
4053
+ };
4054
+ static const char *const SocketTypeNames[] = {
4055
+ "Dual",
4056
+ "IPv4",
4057
+ "IPv6",
4058
+ "Unix"
4059
+ };
3825
4060
 
3826
- Size pos = 0;
3827
- uint64_t neg = 0;
3828
- if (str.len >= 2) {
3829
- if (std::numeric_limits<T>::min() < 0 && str[0] == '-') {
3830
- pos = 1;
3831
- neg = UINT64_MAX;
3832
- } else if (str[0] == '+') {
3833
- pos = 1;
3834
- }
3835
- }
4061
+ enum class SocketMode {
4062
+ Stream,
4063
+ Messages
4064
+ };
3836
4065
 
3837
- for (; pos < str.len; pos++) {
3838
- unsigned int digit = (unsigned int)(str[pos] - '0');
3839
- if (RG_UNLIKELY(digit > 9)) {
3840
- if (!pos || flags & (int)ParseFlag::End) {
3841
- if (flags & (int)ParseFlag::Log) {
3842
- LogError("Malformed integer number '%1'", str);
3843
- }
3844
- return false;
3845
- } else {
3846
- break;
3847
- }
3848
- }
4066
+ int OpenIPSocket(SocketType type, int port, SocketMode mode = SocketMode::Stream);
3849
4067
 
3850
- uint64_t new_value = (value * 10) + digit;
3851
- if (RG_UNLIKELY(new_value < value))
3852
- goto overflow;
3853
- value = new_value;
3854
- }
3855
- if (RG_UNLIKELY(value > (uint64_t)std::numeric_limits<T>::max()))
3856
- goto overflow;
3857
- value = ((value ^ neg) - neg);
4068
+ int OpenUnixSocket(const char *path, SocketMode mode = SocketMode::Stream);
4069
+ int ConnectToUnixSocket(const char *path, SocketMode mode = SocketMode::Stream);
3858
4070
 
3859
- if (out_remaining) {
3860
- *out_remaining = str.Take(pos, str.len - pos);
3861
- }
3862
- *out_value = (T)value;
3863
- return true;
4071
+ void CloseSocket(int fd);
3864
4072
 
3865
- overflow:
3866
- if (flags & (int)ParseFlag::Log) {
3867
- LogError("Integer overflow for number '%1' (max = %2)", str,
3868
- std::numeric_limits<T>::max());
3869
- }
3870
- return false;
3871
- }
4073
+ // ------------------------------------------------------------------------
4074
+ // Tasks
4075
+ // ------------------------------------------------------------------------
3872
4076
 
3873
- bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3874
- Span<const char> *out_remaining = nullptr);
4077
+ class Async {
4078
+ RG_DELETE_COPY(Async)
3875
4079
 
3876
- static inline Size EncodeUtf8(int32_t c, char out_buf[4])
3877
- {
3878
- if (c < 0x80) {
3879
- out_buf[0] = (char)c;
3880
- return 1;
3881
- } else if (c < 0x800) {
3882
- out_buf[0] = (char)(0xC0 | (c >> 6));
3883
- out_buf[1] = (char)(0x80 | (c & 0x3F));
3884
- return 2;
3885
- } else if (c >= 0xD800 && c < 0xE000) {
3886
- return 0;
3887
- } else if (c < 0x10000) {
3888
- out_buf[0] = (char)(0xE0 | (c >> 12));
3889
- out_buf[1] = (char)(0x80 | ((c >> 6) & 0x3F));
3890
- out_buf[2] = (char)(0x80 | (c & 0x3F));
3891
- return 3;
3892
- } else if (c < 0x110000) {
3893
- out_buf[0] = (char)(0xF0 | (c >> 18));
3894
- out_buf[1] = (char)(0x80 | ((c >> 12) & 0x3F));
3895
- out_buf[2] = (char)(0x80 | ((c >> 6) & 0x3F));
3896
- out_buf[3] = (char)(0x80 | (c & 0x3F));
3897
- return 4;
3898
- } else {
3899
- return 0;
3900
- }
3901
- }
4080
+ bool stop_after_error;
4081
+ std::atomic_bool success {true};
4082
+ std::atomic_int remaining_tasks {0};
3902
4083
 
3903
- static inline int CountUtf8Bytes(char c)
3904
- {
3905
- int ones = CountLeadingZeros((uint32_t)~c << 24);
3906
- return std::min(std::max(ones, 1), 4);
3907
- }
4084
+ class AsyncPool *pool;
3908
4085
 
3909
- static inline Size DecodeUtf8(Span<const char> str, Size offset, int32_t *out_c)
3910
- {
3911
- RG_ASSERT(offset < str.len);
4086
+ public:
4087
+ Async(int threads = -1, bool stop_after_error = true);
4088
+ Async(Async *parent, bool stop_after_error = true);
4089
+ ~Async();
3912
4090
 
3913
- const uint8_t *ptr = (const uint8_t *)(str.ptr + offset);
3914
- Size available = str.len - offset;
4091
+ void Run(const std::function<bool()> &f);
4092
+ bool Sync();
3915
4093
 
3916
- if (ptr[0] < 0x80) {
3917
- *out_c = ptr[0];
3918
- return 1;
3919
- } else if (RG_UNLIKELY(ptr[0] - 0xC2 > 0xF4 - 0xC2)) {
3920
- return 0;
3921
- } else if (ptr[0] < 0xE0 &&
3922
- RG_LIKELY(available >= 2 && (ptr[1] & 0xC0) == 0x80)) {
3923
- *out_c = ((ptr[0] & 0x1F) << 6) | (ptr[1] & 0x3F);
3924
- return 2;
3925
- } else if (ptr[0] < 0xF0 &&
3926
- RG_LIKELY(available >= 3 && (ptr[1] & 0xC0) == 0x80 &&
3927
- (ptr[2] & 0xC0) == 0x80)) {
3928
- *out_c = ((ptr[0] & 0xF) << 12) | ((ptr[1] & 0x3F) << 6) | (ptr[2] & 0x3F);
3929
- return 3;
3930
- } else if (RG_LIKELY(available >= 4 && (ptr[1] & 0xC0) == 0x80 &&
3931
- (ptr[2] & 0xC0) == 0x80 &&
3932
- (ptr[3] & 0xC0) == 0x80)) {
3933
- *out_c = ((ptr[0] & 0x7) << 18) | ((ptr[1] & 0x3F) << 12) | ((ptr[2] & 0x3F) << 6) | (ptr[3] & 0x3F);
3934
- return 4;
3935
- } else {
3936
- return 0;
3937
- }
3938
- }
4094
+ int CountPendingTasks();
3939
4095
 
3940
- static inline void FormatSha256(Span<const uint8_t> hash, char out_sha256[65])
3941
- {
3942
- RG_ASSERT(hash.len == 32);
3943
- Fmt(MakeSpan(out_sha256, 65), "%1", FmtSpan(hash, FmtType::Hexadecimal, "").Pad0(-2));
3944
- }
4096
+ static bool IsTaskRunning();
4097
+ static int GetWorkerIdx();
4098
+ static int GetWorkerCount();
4099
+
4100
+ friend class AsyncPool;
4101
+ };
3945
4102
 
3946
4103
  // ------------------------------------------------------------------------
3947
- // System
4104
+ // Fibers
3948
4105
  // ------------------------------------------------------------------------
3949
4106
 
3950
- #ifdef _WIN32
3951
- #define RG_PATH_SEPARATORS "\\/"
3952
- #define RG_PATH_DELIMITER ';'
3953
- #define RG_SHARED_LIBRARY_EXTENSION ".dll"
3954
- #else
3955
- #define RG_PATH_SEPARATORS "/"
3956
- #define RG_PATH_DELIMITER ':'
3957
- #define RG_SHARED_LIBRARY_EXTENSION ".so"
3958
- #endif
3959
-
3960
- #ifdef _WIN32
3961
- bool IsWin32Utf8();
3962
- Size ConvertUtf8ToWin32Wide(Span<const char> str, Span<wchar_t> out_str_w);
3963
- Size ConvertWin32WideToUtf8(const wchar_t *str_w, Span<char> out_str);
3964
- char *GetWin32ErrorString(uint32_t error_code = UINT32_MAX);
3965
- #endif
4107
+ class Fiber {
4108
+ RG_DELETE_COPY(Fiber)
3966
4109
 
3967
- void SetEnvironmentVar(const char *name, const char *value);
3968
- void DeleteEnvironmentVar(const char *name);
4110
+ std::function<bool()> f;
3969
4111
 
3970
- static inline bool IsPathSeparator(char c)
3971
- {
3972
4112
  #ifdef _WIN32
3973
- return c == '/' || c == '\\';
4113
+ void *fiber = nullptr;
4114
+ #elif defined(RG_FIBER_USE_UCONTEXT)
4115
+ ucontext_t ucp = {};
3974
4116
  #else
3975
- return c == '/';
4117
+ std::thread thread;
4118
+
4119
+ std::mutex mutex;
4120
+ std::condition_variable cv;
4121
+ std::unique_lock<std::mutex> lock { mutex };
4122
+ int toggle = 1;
3976
4123
  #endif
3977
- }
3978
4124
 
3979
- Span<const char> GetPathDirectory(Span<const char> filename);
3980
- Span<const char> GetPathExtension(Span<const char> filename,
3981
- CompressionType *out_compression_type = nullptr);
3982
- CompressionType GetPathCompression(Span<const char> filename);
4125
+ bool done = true;
4126
+ bool success = false;
3983
4127
 
3984
- Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, Allocator *alloc);
3985
- static inline Span<char> NormalizePath(Span<const char> path, Allocator *alloc)
3986
- { return NormalizePath(path, {}, alloc); }
4128
+ public:
4129
+ Fiber(const std::function<bool()> &f, Size stack_size = RG_FIBER_DEFAULT_STACK_SIZE);
4130
+ ~Fiber();
3987
4131
 
3988
- bool PathIsAbsolute(const char *path);
3989
- bool PathIsAbsolute(Span<const char> path);
3990
- bool PathContainsDotDot(const char *path);
4132
+ void SwitchTo();
4133
+ bool Finalize();
3991
4134
 
3992
- enum class StatFlag {
3993
- IgnoreMissing = 1 << 0,
3994
- FollowSymlink = 1 << 1
3995
- };
4135
+ static bool SwitchBack();
3996
4136
 
3997
- enum class FileType {
3998
- Directory,
3999
- File,
4000
- Link,
4001
- Device,
4002
- Pipe,
4003
- Socket
4137
+ private:
4138
+ #if defined(_WIN64)
4139
+ static void FiberCallback(void *udata);
4140
+ #elif defined(_WIN32)
4141
+ static void __stdcall FiberCallback(void *udata);
4142
+ #elif defined(RG_FIBER_USE_UCONTEXT)
4143
+ static void FiberCallback(unsigned int high, unsigned int low);
4144
+ #else
4145
+ static void ThreadCallback(void *udata);
4146
+ void Toggle(int to, std::unique_lock<std::mutex> *lock);
4147
+ #endif
4004
4148
  };
4005
4149
 
4006
- struct FileInfo {
4007
- FileType type;
4008
-
4009
- int64_t size;
4010
- int64_t mtime;
4011
- };
4150
+ // ------------------------------------------------------------------------
4151
+ // Streams
4152
+ // ------------------------------------------------------------------------
4012
4153
 
4013
- enum class EnumStatus {
4014
- Error,
4015
- Partial,
4016
- Stopped,
4017
- Complete
4154
+ enum class CompressionSpeed {
4155
+ Default,
4156
+ Slow,
4157
+ Fast
4018
4158
  };
4019
4159
 
4020
- bool StatFile(const char *filename, unsigned int flags, FileInfo *out_info);
4021
- static inline bool StatFile(const char *filename, FileInfo *out_info)
4022
- { return StatFile(filename, 0, out_info); }
4160
+ class StreamReader {
4161
+ RG_DELETE_COPY(StreamReader)
4023
4162
 
4024
- // Sync failures are logged but not reported as errors (function returns true)
4025
- bool RenameFile(const char *src_filename, const char *dest_filename, bool overwrite, bool sync = true);
4163
+ enum class SourceType {
4164
+ Memory,
4165
+ File,
4166
+ Function
4167
+ };
4026
4168
 
4027
- EnumStatus EnumerateDirectory(const char *dirname, const char *filter, Size max_files,
4028
- FunctionRef<bool(const char *, FileType)> func);
4029
- bool EnumerateFiles(const char *dirname, const char *filter, Size max_depth, Size max_files,
4030
- Allocator *str_alloc, HeapArray<const char *> *out_files);
4031
- bool IsDirectoryEmpty(const char *dirname);
4169
+ const char *filename = nullptr;
4170
+ bool error = true;
4032
4171
 
4033
- bool TestFile(const char *filename);
4034
- bool TestFile(const char *filename, FileType type);
4172
+ struct {
4173
+ SourceType type = SourceType::Memory;
4174
+ union U {
4175
+ struct {
4176
+ Span<const uint8_t> buf;
4177
+ Size pos;
4178
+ } memory;
4179
+ struct {
4180
+ FILE *fp;
4181
+ bool owned;
4182
+ } file;
4183
+ std::function<Size(Span<uint8_t> buf)> func;
4035
4184
 
4036
- bool MatchPathName(const char *path, const char *spec);
4037
- bool MatchPathSpec(const char *path, const char *spec);
4185
+ // StreamReader deals with func destructor
4186
+ U() {}
4187
+ ~U() {}
4188
+ } u;
4038
4189
 
4039
- bool FindExecutableInPath(const char *path, const char *name,
4040
- Allocator *alloc = nullptr, const char **out_path = nullptr);
4041
- bool FindExecutableInPath(const char *name, Allocator *alloc = nullptr,
4042
- const char **out_path = nullptr);
4190
+ bool eof = false;
4191
+ } source;
4043
4192
 
4044
- bool SetWorkingDirectory(const char *directory);
4045
- const char *GetWorkingDirectory();
4193
+ struct {
4194
+ CompressionType type = CompressionType::None;
4195
+ union {
4196
+ struct MinizInflateContext *miniz;
4197
+ struct BrotliDecompressContext *brotli;
4198
+ } u;
4199
+ } compression;
4046
4200
 
4047
- const char *GetApplicationExecutable(); // Can be NULL (EmSDK)
4048
- const char *GetApplicationDirectory(); // Can be NULL (EmSDK)
4201
+ int64_t raw_len = -1;
4202
+ Size raw_read = 0;
4203
+ bool eof = false;
4049
4204
 
4050
- bool MakeDirectory(const char *directory, bool error_if_exists = true);
4051
- bool MakeDirectoryRec(Span<const char> directory);
4052
- bool UnlinkDirectory(const char *directory, bool error_if_missing = false);
4053
- bool UnlinkFile(const char *filename, bool error_if_missing = false);
4054
- bool EnsureDirectoryExists(const char *filename);
4205
+ BlockAllocator str_alloc;
4055
4206
 
4056
- enum class OpenFileFlag {
4057
- Read = 1 << 0,
4058
- Write = 1 << 1,
4059
- Append = 1 << 2,
4207
+ public:
4208
+ StreamReader() { Close(true); }
4209
+ StreamReader(Span<const uint8_t> buf, const char *filename = nullptr,
4210
+ CompressionType compression_type = CompressionType::None)
4211
+ : StreamReader() { Open(buf, filename, compression_type); }
4212
+ StreamReader(FILE *fp, const char *filename,
4213
+ CompressionType compression_type = CompressionType::None)
4214
+ : StreamReader() { Open(fp, filename, compression_type); }
4215
+ StreamReader(const char *filename,
4216
+ CompressionType compression_type = CompressionType::None)
4217
+ : StreamReader() { Open(filename, compression_type); }
4218
+ StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
4219
+ CompressionType compression_type = CompressionType::None)
4220
+ : StreamReader() { Open(func, filename, compression_type); }
4221
+ ~StreamReader() { Close(true); }
4060
4222
 
4061
- Exclusive = 1 << 3
4062
- };
4223
+ bool Open(Span<const uint8_t> buf, const char *filename = nullptr,
4224
+ CompressionType compression_type = CompressionType::None);
4225
+ bool Open(FILE *fp, const char *filename,
4226
+ CompressionType compression_type = CompressionType::None);
4227
+ OpenResult Open(const char *filename, CompressionType compression_type = CompressionType::None);
4228
+ bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
4229
+ CompressionType compression_type = CompressionType::None);
4230
+ bool Close() { return Close(false); }
4063
4231
 
4064
- int OpenDescriptor(const char *filename, unsigned int flags);
4065
- FILE *OpenFile(const char *filename, unsigned int flags);
4066
- bool FlushFile(FILE *fp, const char *filename);
4232
+ // File-specific
4233
+ bool Rewind();
4067
4234
 
4068
- bool FileIsVt100(FILE *fp);
4235
+ const char *GetFileName() const { return filename; }
4236
+ CompressionType GetCompressionType() const { return compression.type; }
4237
+ bool IsValid() const { return filename && !error; }
4238
+ bool IsEOF() const { return eof; }
4069
4239
 
4070
- #ifdef _WIN32
4071
- enum class PipeMode {
4072
- Byte,
4073
- Message
4074
- };
4240
+ FILE *GetFile() const;
4241
+ int GetDescriptor() const;
4075
4242
 
4076
- bool CreateOverlappedPipe(bool overlap0, bool overlap1, PipeMode mode, void *out_handles[2]); // HANDLE
4077
- void CloseHandleSafe(void **handle_ptr); // HANDLE
4078
- #else
4079
- void SetSignalHandler(int signal, void (*func)(int), struct sigaction *prev = nullptr);
4243
+ Size Read(Span<uint8_t> out_buf);
4244
+ Size Read(Span<char> out_buf) { return Read(out_buf.As<uint8_t>()); }
4245
+ Size Read(Size max_len, void *out_buf) { return Read(MakeSpan((uint8_t *)out_buf, max_len)); }
4080
4246
 
4081
- bool CreatePipe(int pfd[2]);
4082
- void CloseDescriptorSafe(int *fd_ptr);
4083
- #endif
4247
+ Size ReadAll(Size max_len, HeapArray<uint8_t> *out_buf);
4248
+ Size ReadAll(Size max_len, HeapArray<char> *out_buf)
4249
+ { return ReadAll(max_len, (HeapArray<uint8_t> *)out_buf); }
4084
4250
 
4085
- bool ExecuteCommandLine(const char *cmd_line, FunctionRef<Span<const uint8_t>()> in_func,
4086
- FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code);
4087
- bool ExecuteCommandLine(const char *cmd_line, Span<const uint8_t> in_buf, Size max_len,
4088
- HeapArray<uint8_t> *out_buf, int *out_code);
4089
- static inline bool ExecuteCommandLine(const char *cmd_line, int *out_code) {
4090
- return ExecuteCommandLine(cmd_line, {}, {}, out_code);
4091
- }
4092
- static inline bool ExecuteCommandLine(const char *cmd_line, Span<const uint8_t> in_buf,
4093
- FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code)
4094
- {
4095
- const auto read_once = [&]() {
4096
- Span<const uint8_t> buf = in_buf;
4097
- in_buf = {};
4098
- return buf;
4099
- };
4251
+ int64_t ComputeRawLen();
4252
+ int64_t GetRawRead() const { return raw_read; }
4100
4253
 
4101
- return ExecuteCommandLine(cmd_line, read_once, out_func, out_code);
4102
- }
4103
- static inline bool ExecuteCommandLine(const char *cmd_line, Span<const char> in_buf,
4104
- FunctionRef<void(Span<char> buf)> out_func, int *out_code)
4105
- {
4106
- const auto write = [&](Span<uint8_t> buf) { out_func(buf.As<char>()); };
4254
+ private:
4255
+ bool Close(bool implicit);
4107
4256
 
4108
- return ExecuteCommandLine(cmd_line, in_buf.As<const uint8_t>(), write, out_code);
4109
- }
4110
- static inline bool ExecuteCommandLine(const char *cmd_line, Span<const char> in_buf, Size max_len,
4111
- HeapArray<char> *out_buf, int *out_code)
4112
- {
4113
- return ExecuteCommandLine(cmd_line, in_buf.As<const uint8_t>(), max_len,
4114
- (HeapArray<uint8_t> *)out_buf, out_code);
4115
- }
4257
+ bool InitDecompressor(CompressionType type);
4116
4258
 
4117
- void WaitDelay(int64_t delay);
4259
+ Size ReadInflate(Size max_len, void *out_buf);
4260
+ Size ReadBrotli(Size max_len, void *out_buf);
4118
4261
 
4119
- enum class WaitForResult {
4120
- Interrupt,
4121
- Message,
4122
- Timeout
4262
+ Size ReadRaw(Size max_len, void *out_buf);
4123
4263
  };
4124
4264
 
4125
- // After WaitForInterrupt() has been called once (even with timeout 0), a few
4126
- // signals (such as SIGINT, SIGHUP) and their Windows equivalent will be permanently ignored.
4127
- // Beware, on Unix platforms, this may not work correctly if not called from the main thread.
4128
- WaitForResult WaitForInterrupt(int64_t timeout = -1);
4129
- void SignalWaitFor();
4130
-
4131
- int GetCoreCount();
4132
-
4133
- #ifndef _WIN32
4134
- bool DropRootIdentity();
4135
- #endif
4136
- #ifdef __linux__
4137
- bool NotifySystemd();
4138
- #endif
4139
-
4140
- #ifndef _WIN32
4141
- #define RG_POSIX_RESTART_EINTR(CallCode, ErrorCond) \
4142
- ([&]() { \
4143
- decltype(CallCode) ret; \
4144
- while ((ret = (CallCode)) ErrorCond && errno == EINTR); \
4145
- return ret; \
4146
- })()
4147
- #endif
4148
-
4149
- // ------------------------------------------------------------------------
4150
- // Standard paths
4151
- // ------------------------------------------------------------------------
4265
+ static inline Size ReadFile(const char *filename, CompressionType compression_type, Span<uint8_t> out_buf)
4266
+ {
4267
+ StreamReader st(filename, compression_type);
4268
+ return st.Read(out_buf);
4269
+ }
4270
+ static inline Size ReadFile(const char *filename, Span<uint8_t> out_buf)
4271
+ {
4272
+ StreamReader st(filename);
4273
+ return st.Read(out_buf);
4274
+ }
4275
+ static inline Size ReadFile(const char *filename, CompressionType compression_type, Span<char> out_buf)
4276
+ {
4277
+ StreamReader st(filename, compression_type);
4278
+ return st.Read(out_buf);
4279
+ }
4280
+ static inline Size ReadFile(const char *filename, Span<char> out_buf)
4281
+ {
4282
+ StreamReader st(filename);
4283
+ return st.Read(out_buf);
4284
+ }
4152
4285
 
4153
- const char *GetUserConfigPath(const char *name, Allocator *alloc);
4154
- const char *GetUserCachePath(const char *name, Allocator *alloc);
4155
- const char *GetTemporaryDirectory();
4286
+ static inline Size ReadFile(const char *filename, Size max_len, CompressionType compression_type,
4287
+ HeapArray<uint8_t> *out_buf)
4288
+ {
4289
+ StreamReader st(filename, compression_type);
4290
+ return st.ReadAll(max_len, out_buf);
4291
+ }
4292
+ static inline Size ReadFile(const char *filename, Size max_len, HeapArray<uint8_t> *out_buf)
4293
+ {
4294
+ StreamReader st(filename);
4295
+ return st.ReadAll(max_len, out_buf);
4296
+ }
4297
+ static inline Size ReadFile(const char *filename, Size max_len, CompressionType compression_type,
4298
+ HeapArray<char> *out_buf)
4299
+ {
4300
+ StreamReader st(filename, compression_type);
4301
+ return st.ReadAll(max_len, out_buf);
4302
+ }
4303
+ static inline Size ReadFile(const char *filename, Size max_len, HeapArray<char> *out_buf)
4304
+ {
4305
+ StreamReader st(filename);
4306
+ return st.ReadAll(max_len, out_buf);
4307
+ }
4156
4308
 
4157
- const char *FindConfigFile(const char *name, Allocator *alloc, LocalArray<const char *, 4> *out_possibilities = nullptr);
4309
+ class LineReader {
4310
+ RG_DELETE_COPY(LineReader)
4158
4311
 
4159
- const char *CreateTemporaryFile(Span<const char> directory, const char *prefix, const char *extension,
4160
- Allocator *alloc, FILE **out_fp = nullptr);
4161
- const char *CreateTemporaryDirectory(Span<const char> directory, const char *prefix, Allocator *alloc);
4312
+ HeapArray<char> buf;
4313
+ Span<char> view = {};
4162
4314
 
4163
- // ------------------------------------------------------------------------
4164
- // Random
4165
- // ------------------------------------------------------------------------
4315
+ StreamReader *st;
4316
+ bool error;
4317
+ bool eof = false;
4166
4318
 
4167
- class FastRandom {
4168
- uint64_t state[4];
4319
+ Span<char> line = {};
4320
+ int line_number = 0;
4169
4321
 
4170
4322
  public:
4171
- FastRandom();
4172
- FastRandom(uint64_t seed);
4323
+ LineReader(StreamReader *st) : st(st), error(!st->IsValid()) {}
4173
4324
 
4174
- void Fill(void *buf, Size len);
4175
- void Fill(Span<uint8_t> buf) { Fill(buf.ptr, buf.len); }
4325
+ const char *GetFileName() const { return st->GetFileName(); }
4326
+ int GetLineNumber() const { return line_number; }
4327
+ bool IsValid() const { return !error; }
4328
+ bool IsEOF() const { return eof; }
4176
4329
 
4177
- int GetInt(int min, int max);
4330
+ bool Next(Span<char> *out_line);
4331
+ bool Next(Span<const char> *out_line) { return Next((Span<char> *)out_line); }
4178
4332
 
4179
- private:
4180
- uint64_t Next();
4333
+ void PushLogFilter();
4181
4334
  };
4182
4335
 
4183
- void ZeroMemorySafe(void *ptr, Size len);
4184
- void FillRandomSafe(void *buf, Size len);
4185
- static inline void FillRandomSafe(Span<uint8_t> buf) { FillRandomSafe(buf.ptr, buf.len); }
4186
- int GetRandomIntSafe(int min, int max);
4336
+ enum class StreamWriterFlag {
4337
+ Exclusive = 1 << 0,
4338
+ Atomic = 1 << 1
4339
+ };
4187
4340
 
4188
- // ------------------------------------------------------------------------
4189
- // Sockets
4190
- // ------------------------------------------------------------------------
4341
+ class StreamWriter {
4342
+ RG_DELETE_COPY(StreamWriter)
4191
4343
 
4192
- enum class SocketType {
4193
- Dual,
4194
- IPv4,
4195
- IPv6,
4196
- Unix
4197
- };
4198
- static const char *const SocketTypeNames[] = {
4199
- "Dual",
4200
- "IPv4",
4201
- "IPv6",
4202
- "Unix"
4203
- };
4344
+ enum class DestinationType {
4345
+ Memory,
4346
+ File,
4347
+ Function
4348
+ };
4204
4349
 
4205
- enum class SocketMode {
4206
- Stream,
4207
- Messages
4208
- };
4350
+ const char *filename = nullptr;
4351
+ bool error = true;
4209
4352
 
4210
- int OpenIPSocket(SocketType type, int port, SocketMode mode = SocketMode::Stream);
4353
+ struct {
4354
+ DestinationType type = DestinationType::Memory;
4355
+ union U {
4356
+ struct {
4357
+ HeapArray<uint8_t> *memory;
4358
+ Size start;
4359
+ } mem;
4360
+ struct {
4361
+ FILE *fp;
4362
+ bool owned;
4211
4363
 
4212
- int OpenUnixSocket(const char *path, SocketMode mode = SocketMode::Stream);
4213
- int ConnectToUnixSocket(const char *path, SocketMode mode = SocketMode::Stream);
4364
+ // Atomic write mode
4365
+ const char *tmp_filename;
4366
+ bool tmp_exclusive;
4367
+ } file;
4368
+ std::function<bool(Span<const uint8_t>)> func;
4214
4369
 
4215
- void CloseSocket(int fd);
4370
+ // StreamWriter deals with func destructor
4371
+ U() {}
4372
+ ~U() {}
4373
+ } u;
4216
4374
 
4217
- // ------------------------------------------------------------------------
4218
- // Tasks
4219
- // ------------------------------------------------------------------------
4375
+ bool vt100;
4376
+ } dest;
4220
4377
 
4221
- class Async {
4222
- RG_DELETE_COPY(Async)
4378
+ struct {
4379
+ CompressionType type = CompressionType::None;
4380
+ CompressionSpeed speed = CompressionSpeed::Default;
4381
+ union {
4382
+ struct MinizDeflateContext *miniz;
4383
+ struct BrotliEncoderStateStruct *brotli;
4384
+ } u;
4385
+ } compression;
4223
4386
 
4224
- bool stop_after_error;
4225
- std::atomic_bool success {true};
4226
- std::atomic_int remaining_tasks {0};
4387
+ int64_t raw_written = 0;
4227
4388
 
4228
- class AsyncPool *pool;
4389
+ BlockAllocator str_alloc;
4229
4390
 
4230
4391
  public:
4231
- Async(int threads = -1, bool stop_after_error = true);
4232
- ~Async();
4392
+ StreamWriter() { Close(true); }
4393
+ StreamWriter(HeapArray<uint8_t> *mem, const char *filename = nullptr,
4394
+ CompressionType compression_type = CompressionType::None,
4395
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
4396
+ : StreamWriter() { Open(mem, filename, compression_type, compression_speed); }
4397
+ StreamWriter(FILE *fp, const char *filename,
4398
+ CompressionType compression_type = CompressionType::None,
4399
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
4400
+ : StreamWriter() { Open(fp, filename, compression_type, compression_speed); }
4401
+ StreamWriter(const char *filename, unsigned int flags = 0,
4402
+ CompressionType compression_type = CompressionType::None,
4403
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
4404
+ : StreamWriter() { Open(filename, flags, compression_type, compression_speed); }
4405
+ StreamWriter(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
4406
+ CompressionType compression_type = CompressionType::None,
4407
+ CompressionSpeed compression_speed = CompressionSpeed::Default)
4408
+ : StreamWriter() { Open(func, filename, compression_type, compression_speed); }
4409
+ ~StreamWriter() { Close(true); }
4233
4410
 
4234
- void Run(const std::function<bool()> &f);
4235
- bool Sync();
4411
+ bool Open(HeapArray<uint8_t> *mem, const char *filename = nullptr,
4412
+ CompressionType compression_type = CompressionType::None,
4413
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
4414
+ bool Open(FILE *fp, const char *filename,
4415
+ CompressionType compression_type = CompressionType::None,
4416
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
4417
+ bool Open(const char *filename, unsigned int flags = 0,
4418
+ CompressionType compression_type = CompressionType::None,
4419
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
4420
+ bool Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
4421
+ CompressionType compression_type = CompressionType::None,
4422
+ CompressionSpeed compression_speed = CompressionSpeed::Default);
4423
+ bool Close() { return Close(false); }
4236
4424
 
4237
- static bool IsTaskRunning();
4238
- static int GetWorkerIdx();
4425
+ // For compressed streams, Flush may not be complete and only Close() can finalize the file.
4426
+ bool Flush();
4239
4427
 
4240
- friend class AsyncPool;
4241
- };
4428
+ const char *GetFileName() const { return filename; }
4429
+ CompressionType GetCompressionType() const { return compression.type; }
4430
+ bool IsVt100() const { return dest.vt100; }
4431
+ bool IsValid() const { return filename && !error; }
4242
4432
 
4243
- // ------------------------------------------------------------------------
4244
- // Fibers
4245
- // ------------------------------------------------------------------------
4433
+ FILE *GetFile() const;
4434
+ int GetDescriptor() const;
4246
4435
 
4247
- class Fiber {
4248
- RG_DELETE_COPY(Fiber)
4436
+ bool Write(Span<const uint8_t> buf);
4437
+ bool Write(Span<const char> buf) { return Write(buf.As<const uint8_t>()); }
4438
+ bool Write(char buf) { return Write(MakeSpan(&buf, 1)); }
4439
+ bool Write(const void *buf, Size len) { return Write(MakeSpan((const uint8_t *)buf, len)); }
4249
4440
 
4250
- std::function<bool()> f;
4441
+ int64_t GetRawWritten() const { return raw_written; }
4251
4442
 
4252
- #ifdef _WIN32
4253
- void *fiber = nullptr;
4254
- #elif defined(RG_FIBER_USE_UCONTEXT)
4255
- ucontext_t ucp = {};
4256
- #else
4257
- std::thread thread;
4443
+ private:
4444
+ bool Close(bool implicit);
4258
4445
 
4259
- std::mutex mutex;
4260
- std::condition_variable cv;
4261
- std::unique_lock<std::mutex> lock { mutex };
4262
- int toggle = 1;
4263
- #endif
4446
+ bool InitCompressor(CompressionType type, CompressionSpeed speed);
4264
4447
 
4265
- bool done = true;
4266
- bool success = false;
4448
+ bool WriteDeflate(Span<const uint8_t> buf);
4449
+ bool WriteBrotli(Span<const uint8_t> buf);
4267
4450
 
4268
- public:
4269
- Fiber(const std::function<bool()> &f, Size stack_size = RG_FIBER_DEFAULT_STACK_SIZE);
4270
- ~Fiber();
4451
+ bool WriteRaw(Span<const uint8_t> buf);
4452
+ };
4271
4453
 
4272
- void SwitchTo();
4273
- bool Finalize();
4454
+ static inline bool WriteFile(Span<const uint8_t> buf, const char *filename, unsigned int flags = 0,
4455
+ CompressionType compression_type = CompressionType::None)
4456
+ {
4457
+ StreamWriter st(filename, flags, compression_type);
4458
+ st.Write(buf);
4459
+ return st.Close();
4460
+ }
4461
+ static inline bool WriteFile(Span<const char> buf, const char *filename, unsigned int flags = 0,
4462
+ CompressionType compression_type = CompressionType::None)
4463
+ {
4464
+ StreamWriter st(filename, flags, compression_type);
4465
+ st.Write(buf);
4466
+ return st.Close();
4467
+ }
4274
4468
 
4275
- static bool SwitchBack();
4469
+ bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer);
4276
4470
 
4277
- private:
4278
- #if defined(_WIN64)
4279
- static void FiberCallback(void *udata);
4280
- #elif defined(_WIN32)
4281
- static void __stdcall FiberCallback(void *udata);
4282
- #elif defined(RG_FIBER_USE_UCONTEXT)
4283
- static void FiberCallback(unsigned int high, unsigned int low);
4284
- #else
4285
- static void ThreadCallback(void *udata);
4286
- void Toggle(int to, std::unique_lock<std::mutex> *lock);
4287
- #endif
4288
- };
4471
+ // For convenience, don't close them
4472
+ extern StreamReader stdin_st;
4473
+ extern StreamWriter stdout_st;
4474
+ extern StreamWriter stderr_st;
4289
4475
 
4290
4476
  // ------------------------------------------------------------------------
4291
4477
  // INI