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