tigerbeetle 0.0.34 → 0.0.37

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/ext/tb_client/extconf.rb +13 -13
  4. data/ext/tb_client/tigerbeetle/LICENSE +177 -0
  5. data/ext/tb_client/tigerbeetle/build.zig +2327 -0
  6. data/ext/tb_client/tigerbeetle/src/aof.zig +1000 -0
  7. data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +808 -0
  8. data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +1283 -0
  9. data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +1704 -0
  10. data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +341 -0
  11. data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +1450 -0
  12. data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +1659 -0
  13. data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +406 -0
  14. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +1084 -0
  15. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +286 -0
  16. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +158 -0
  17. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +229 -0
  18. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +110 -0
  19. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +386 -0
  20. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +34 -0
  21. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +281 -0
  22. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +312 -0
  23. data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +138 -0
  24. data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +466 -0
  25. data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +157 -0
  26. data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +90 -0
  27. data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +203 -0
  28. data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +79 -0
  29. data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +542 -0
  30. data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +109 -0
  31. data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +86 -0
  32. data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +370 -0
  33. data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +386 -0
  34. data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +167 -0
  35. data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +126 -0
  36. data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +996 -0
  37. data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +748 -0
  38. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +3238 -0
  39. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +1718 -0
  40. data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +190 -0
  41. data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +104 -0
  42. data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +75 -0
  43. data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +522 -0
  44. data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +267 -0
  45. data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +3 -0
  46. data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +379 -0
  47. data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +131 -0
  48. data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +63 -0
  49. data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +588 -0
  50. data/ext/tb_client/tigerbeetle/src/clients/rust/assets/tb_client.h +386 -0
  51. data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +73 -0
  52. data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +106 -0
  53. data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +305 -0
  54. data/ext/tb_client/tigerbeetle/src/config.zig +296 -0
  55. data/ext/tb_client/tigerbeetle/src/constants.zig +790 -0
  56. data/ext/tb_client/tigerbeetle/src/copyhound.zig +202 -0
  57. data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +72 -0
  58. data/ext/tb_client/tigerbeetle/src/direction.zig +11 -0
  59. data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +158 -0
  60. data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +156 -0
  61. data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +252 -0
  62. data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +313 -0
  63. data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +87 -0
  64. data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +63 -0
  65. data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +47 -0
  66. data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +28 -0
  67. data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +61 -0
  68. data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +169 -0
  69. data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +46 -0
  70. data/ext/tb_client/tigerbeetle/src/ewah.zig +445 -0
  71. data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +128 -0
  72. data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +171 -0
  73. data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +179 -0
  74. data/ext/tb_client/tigerbeetle/src/integration_tests.zig +662 -0
  75. data/ext/tb_client/tigerbeetle/src/io/common.zig +155 -0
  76. data/ext/tb_client/tigerbeetle/src/io/darwin.zig +1093 -0
  77. data/ext/tb_client/tigerbeetle/src/io/linux.zig +1880 -0
  78. data/ext/tb_client/tigerbeetle/src/io/test.zig +1005 -0
  79. data/ext/tb_client/tigerbeetle/src/io/windows.zig +1598 -0
  80. data/ext/tb_client/tigerbeetle/src/io.zig +34 -0
  81. data/ext/tb_client/tigerbeetle/src/iops.zig +134 -0
  82. data/ext/tb_client/tigerbeetle/src/list.zig +236 -0
  83. data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +848 -0
  84. data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +179 -0
  85. data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +424 -0
  86. data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +420 -0
  87. data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +2117 -0
  88. data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +182 -0
  89. data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +1119 -0
  90. data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +1102 -0
  91. data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +200 -0
  92. data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +1495 -0
  93. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +739 -0
  94. data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +166 -0
  95. data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +754 -0
  96. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +1294 -0
  97. data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +510 -0
  98. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +1263 -0
  99. data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +628 -0
  100. data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +247 -0
  101. data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +116 -0
  102. data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +543 -0
  103. data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +938 -0
  104. data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +293 -0
  105. data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +362 -0
  106. data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +99 -0
  107. data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +17 -0
  108. data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +1036 -0
  109. data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +617 -0
  110. data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +84 -0
  111. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +1500 -0
  112. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +149 -0
  113. data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +7 -0
  114. data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +865 -0
  115. data/ext/tb_client/tigerbeetle/src/lsm/table.zig +607 -0
  116. data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +843 -0
  117. data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +105 -0
  118. data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +40 -0
  119. data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +630 -0
  120. data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +933 -0
  121. data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +557 -0
  122. data/ext/tb_client/tigerbeetle/src/message_buffer.zig +469 -0
  123. data/ext/tb_client/tigerbeetle/src/message_bus.zig +1214 -0
  124. data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +936 -0
  125. data/ext/tb_client/tigerbeetle/src/message_pool.zig +343 -0
  126. data/ext/tb_client/tigerbeetle/src/multiversion.zig +2195 -0
  127. data/ext/tb_client/tigerbeetle/src/queue.zig +390 -0
  128. data/ext/tb_client/tigerbeetle/src/repl/completion.zig +201 -0
  129. data/ext/tb_client/tigerbeetle/src/repl/parser.zig +1356 -0
  130. data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +496 -0
  131. data/ext/tb_client/tigerbeetle/src/repl.zig +1034 -0
  132. data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +973 -0
  133. data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +1866 -0
  134. data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +304 -0
  135. data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +227 -0
  136. data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +658 -0
  137. data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +466 -0
  138. data/ext/tb_client/tigerbeetle/src/scripts/release.zig +1058 -0
  139. data/ext/tb_client/tigerbeetle/src/scripts.zig +105 -0
  140. data/ext/tb_client/tigerbeetle/src/shell.zig +1195 -0
  141. data/ext/tb_client/tigerbeetle/src/stack.zig +260 -0
  142. data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +911 -0
  143. data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +2079 -0
  144. data/ext/tb_client/tigerbeetle/src/state_machine.zig +4872 -0
  145. data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +288 -0
  146. data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +3128 -0
  147. data/ext/tb_client/tigerbeetle/src/static_allocator.zig +82 -0
  148. data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +157 -0
  149. data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +292 -0
  150. data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +65 -0
  151. data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +1414 -0
  152. data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +92 -0
  153. data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +677 -0
  154. data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +336 -0
  155. data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +511 -0
  156. data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +112 -0
  157. data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +1160 -0
  158. data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +142 -0
  159. data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +361 -0
  160. data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +275 -0
  161. data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +295 -0
  162. data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +436 -0
  163. data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +48 -0
  164. data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +402 -0
  165. data/ext/tb_client/tigerbeetle/src/storage.zig +489 -0
  166. data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +180 -0
  167. data/ext/tb_client/tigerbeetle/src/testing/bench.zig +146 -0
  168. data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +53 -0
  169. data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +61 -0
  170. data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +76 -0
  171. data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +110 -0
  172. data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +412 -0
  173. data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +331 -0
  174. data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +458 -0
  175. data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +1198 -0
  176. data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +128 -0
  177. data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +181 -0
  178. data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +144 -0
  179. data/ext/tb_client/tigerbeetle/src/testing/id.zig +97 -0
  180. data/ext/tb_client/tigerbeetle/src/testing/io.zig +317 -0
  181. data/ext/tb_client/tigerbeetle/src/testing/marks.zig +126 -0
  182. data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +533 -0
  183. data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +154 -0
  184. data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +389 -0
  185. data/ext/tb_client/tigerbeetle/src/testing/storage.zig +1247 -0
  186. data/ext/tb_client/tigerbeetle/src/testing/table.zig +249 -0
  187. data/ext/tb_client/tigerbeetle/src/testing/time.zig +98 -0
  188. data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +212 -0
  189. data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +26 -0
  190. data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +580 -0
  191. data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +39 -0
  192. data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +214 -0
  193. data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +34 -0
  194. data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +766 -0
  195. data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +543 -0
  196. data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +181 -0
  197. data/ext/tb_client/tigerbeetle/src/tidy.zig +1448 -0
  198. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +227 -0
  199. data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +1069 -0
  200. data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +1422 -0
  201. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +1658 -0
  202. data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +518 -0
  203. data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +36 -0
  204. data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +646 -0
  205. data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +958 -0
  206. data/ext/tb_client/tigerbeetle/src/time.zig +236 -0
  207. data/ext/tb_client/tigerbeetle/src/trace/event.zig +745 -0
  208. data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +462 -0
  209. data/ext/tb_client/tigerbeetle/src/trace.zig +556 -0
  210. data/ext/tb_client/tigerbeetle/src/unit_tests.zig +321 -0
  211. data/ext/tb_client/tigerbeetle/src/vopr.zig +1785 -0
  212. data/ext/tb_client/tigerbeetle/src/vortex.zig +101 -0
  213. data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +473 -0
  214. data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +208 -0
  215. data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +43 -0
  216. data/ext/tb_client/tigerbeetle/src/vsr/client.zig +768 -0
  217. data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +532 -0
  218. data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +338 -0
  219. data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +1019 -0
  220. data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +279 -0
  221. data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +1381 -0
  222. data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +315 -0
  223. data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +1460 -0
  224. data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +757 -0
  225. data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +797 -0
  226. data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +2586 -0
  227. data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +308 -0
  228. data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +1777 -0
  229. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +715 -0
  230. data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +185 -0
  231. data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +333 -0
  232. data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +12355 -0
  233. data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +416 -0
  234. data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +165 -0
  235. data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +2910 -0
  236. data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +1075 -0
  237. data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +1603 -0
  238. data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +484 -0
  239. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +405 -0
  240. data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +355 -0
  241. data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +29 -0
  242. data/ext/tb_client/tigerbeetle/src/vsr.zig +1727 -0
  243. data/lib/tb_client/shared_lib.rb +12 -5
  244. data/lib/tigerbeetle/client.rb +1 -1
  245. data/lib/tigerbeetle/platforms.rb +9 -0
  246. data/lib/tigerbeetle/version.rb +2 -2
  247. data/tigerbeetle.gemspec +22 -5
  248. metadata +242 -3
  249. data/ext/tb_client/pkg.tar.gz +0 -0
@@ -0,0 +1,848 @@
1
+ const std = @import("std");
2
+ const assert = std.debug.assert;
3
+ const math = std.math;
4
+
5
+ const stdx = @import("stdx");
6
+
7
+ const constants = @import("../constants.zig");
8
+
9
+ pub const Config = struct {
10
+ mode: enum { lower_bound, upper_bound } = .lower_bound,
11
+ prefetch: bool = true,
12
+ };
13
+
14
+ // TODO The Zig self hosted compiler will implement inlining itself before passing the IR to llvm,
15
+ // which should eliminate the current poor codegen of key_from_value.
16
+
17
+ /// Returns either the index of the value equal to `key`,
18
+ /// or if there is no such value then the index where `key` would be inserted.
19
+ ///
20
+ /// In other words, return `i` such that both:
21
+ /// * key <= key_from_value(values[i]) or i == values.len
22
+ /// * key_value_from(values[i-1]) <= key or i == 0
23
+ ///
24
+ /// If `values` contains duplicated matches, then returns
25
+ /// the first index when `Config.mode == .lower_bound`,
26
+ /// or the last index when `Config.mode == .upper_bound`.
27
+ /// This invariant can be expressed as:
28
+ /// * key_value_from(values[i-1]) < key or i == 0 when Config.mode == .lower_bound.
29
+ /// * key < key_value_from(values[i+1]) or i == values.len when Config.mode == .upper_bound.
30
+ ///
31
+ /// Expects `values` to be sorted by key.
32
+ /// Doesn't perform the extra key comparison to determine if the match is exact.
33
+ pub fn binary_search_values_upsert_index(
34
+ comptime Key: type,
35
+ comptime Value: type,
36
+ comptime key_from_value: fn (*const Value) callconv(.@"inline") Key,
37
+ values: []const Value,
38
+ key: Key,
39
+ comptime config: Config,
40
+ ) u32 {
41
+ if (values.len == 0) return 0;
42
+
43
+ var offset: usize = 0;
44
+ var length: usize = values.len;
45
+ while (length > 1) {
46
+ if (constants.verify) {
47
+ assert(offset == 0 or switch (comptime config.mode) {
48
+ .lower_bound => key_from_value(&values[offset - 1]) < key,
49
+ .upper_bound => key_from_value(&values[offset - 1]) <= key,
50
+ });
51
+
52
+ assert(offset + length == values.len or switch (comptime config.mode) {
53
+ .lower_bound => key <= key_from_value(&values[offset + length]),
54
+ .upper_bound => key < key_from_value(&values[offset + length]),
55
+ });
56
+ }
57
+
58
+ const half = length / 2;
59
+ if (config.prefetch) {
60
+ // Prefetching:
61
+ // ARRAY LAYOUTS FOR COMPARISON-BASED SEARCHING, page 18.
62
+ // https://arxiv.org/abs/1509.05053.
63
+ //
64
+ // Prefetching the two possible positions we'd need for the next iteration:
65
+ //
66
+ // [....................mid....................]
67
+ // ^ ^
68
+ // one quarter three quarters.
69
+
70
+ // We need to use pointer arithmetic and disable runtime safety to avoid bounds checks,
71
+ // otherwise prefetching would harm the performance instead of improving it.
72
+ // Since these pointers are never dereferenced, it's safe to dismiss this extra cost
73
+ // here.
74
+ @setRuntimeSafety(constants.verify);
75
+ const one_quarter = values.ptr + offset + half / 2;
76
+ const three_quarters = one_quarter + half;
77
+
78
+ // @sizeOf(Value) can be greater than a single cache line.
79
+ // In that case, we need to prefetch multiple cache lines for a single value:
80
+ comptime stdx.maybe(@sizeOf(Value) > constants.cache_line_size);
81
+ const CacheLineBytes = [*]const [constants.cache_line_size]u8;
82
+ const cache_lines_per_value = comptime stdx.div_ceil(
83
+ @sizeOf(Value),
84
+ constants.cache_line_size,
85
+ );
86
+ inline for (0..cache_lines_per_value) |i| {
87
+ // Locality = 0 means no temporal locality. That is, the data can be immediately
88
+ // dropped from the cache after it is accessed.
89
+ const options: std.builtin.PrefetchOptions = .{
90
+ .rw = .read,
91
+ .locality = 0,
92
+ .cache = .data,
93
+ };
94
+
95
+ @prefetch(@as(CacheLineBytes, @ptrCast(@alignCast(one_quarter))) + i, options);
96
+ @prefetch(@as(CacheLineBytes, @ptrCast(@alignCast(three_quarters))) + i, options);
97
+ }
98
+ }
99
+
100
+ const mid = offset + half;
101
+
102
+ // For exact matches, takes the first half if `mode == .lower_bound`,
103
+ // or the second half if `mode == .upper_bound`.
104
+ const take_upper_half: bool = (switch (comptime config.mode) {
105
+ .lower_bound => key_from_value(&values[mid]) < key,
106
+ .upper_bound => key_from_value(&values[mid]) <= key,
107
+ });
108
+
109
+ if (take_upper_half) {
110
+ @branchHint(.unpredictable);
111
+ offset = mid;
112
+ }
113
+
114
+ length -= half;
115
+ }
116
+
117
+ if (constants.verify) {
118
+ assert(length == 1);
119
+
120
+ assert(offset == 0 or switch (comptime config.mode) {
121
+ .lower_bound => key_from_value(&values[offset - 1]) < key,
122
+ .upper_bound => key_from_value(&values[offset - 1]) <= key,
123
+ });
124
+
125
+ assert(offset + length == values.len or switch (comptime config.mode) {
126
+ .lower_bound => key <= key_from_value(&values[offset + length]),
127
+ .upper_bound => key < key_from_value(&values[offset + length]),
128
+ });
129
+ }
130
+
131
+ offset += @intFromBool(key_from_value(&values[offset]) < key);
132
+
133
+ if (constants.verify) {
134
+ assert(offset == 0 or switch (config.mode) {
135
+ .lower_bound => key_from_value(&values[offset - 1]) < key,
136
+ .upper_bound => key_from_value(&values[offset - 1]) <= key,
137
+ });
138
+ assert(offset >= values.len - 1 or switch (config.mode) {
139
+ .lower_bound => key <= key_from_value(&values[offset + 1]),
140
+ .upper_bound => key < key_from_value(&values[offset + 1]),
141
+ });
142
+ assert(offset == values.len or
143
+ key <= key_from_value(&values[offset]));
144
+ }
145
+
146
+ return @intCast(offset);
147
+ }
148
+
149
+ pub inline fn binary_search_keys_upsert_index(
150
+ comptime Key: type,
151
+ keys: []const Key,
152
+ key: Key,
153
+ comptime config: Config,
154
+ ) u32 {
155
+ return binary_search_values_upsert_index(
156
+ Key,
157
+ Key,
158
+ struct {
159
+ inline fn key_from_key(k: *const Key) Key {
160
+ return k.*;
161
+ }
162
+ }.key_from_key,
163
+ keys,
164
+ key,
165
+ config,
166
+ );
167
+ }
168
+
169
+ const BinarySearchResult = struct {
170
+ index: u32,
171
+ exact: bool,
172
+ };
173
+
174
+ pub inline fn binary_search_values(
175
+ comptime Key: type,
176
+ comptime Value: type,
177
+ comptime key_from_value: fn (*const Value) callconv(.@"inline") Key,
178
+ values: []const Value,
179
+ key: Key,
180
+ comptime config: Config,
181
+ ) ?*const Value {
182
+ const index = binary_search_values_upsert_index(
183
+ Key,
184
+ Value,
185
+ key_from_value,
186
+ values,
187
+ key,
188
+ config,
189
+ );
190
+ const exact = index < values.len and key_from_value(&values[index]) == key;
191
+
192
+ if (exact) {
193
+ const value = &values[index];
194
+ assert(key == key_from_value(value));
195
+ return value;
196
+ } else {
197
+ // TODO: Figure out how to fuzz this without causing asymptotic
198
+ // slowdown in all fuzzers
199
+ return null;
200
+ }
201
+ }
202
+
203
+ pub inline fn binary_search_keys(
204
+ comptime Key: type,
205
+ keys: []const Key,
206
+ key: Key,
207
+ comptime config: Config,
208
+ ) BinarySearchResult {
209
+ const index = binary_search_keys_upsert_index(Key, keys, key, config);
210
+ return .{
211
+ .index = index,
212
+ .exact = index < keys.len and keys[index] == key,
213
+ };
214
+ }
215
+
216
+ pub const BinarySearchRangeUpsertIndexes = struct {
217
+ start: u32,
218
+ end: u32,
219
+ };
220
+
221
+ /// Same semantics of `binary_search_values_upsert_indexes`:
222
+ /// Returns either the indexes of the values equal to `key_min` and `key_max`,
223
+ /// or the indexes where they would be inserted.
224
+ ///
225
+ /// Expects `values` to be sorted by key.
226
+ /// If `values` contains duplicated matches, then returns
227
+ /// the first index for `key_min` and the last index for `key_max`.
228
+ ///
229
+ /// Doesn't perform the extra key comparison to determine if the match is exact.
230
+ pub inline fn binary_search_values_range_upsert_indexes(
231
+ comptime Key: type,
232
+ comptime Value: type,
233
+ comptime key_from_value: fn (*const Value) callconv(.@"inline") Key,
234
+ values: []const Value,
235
+ key_min: Key,
236
+ key_max: Key,
237
+ ) BinarySearchRangeUpsertIndexes {
238
+ assert(key_min <= key_max);
239
+
240
+ const start = binary_search_values_upsert_index(
241
+ Key,
242
+ Value,
243
+ key_from_value,
244
+ values,
245
+ key_min,
246
+ .{ .mode = .lower_bound },
247
+ );
248
+
249
+ if (start == values.len) return .{
250
+ .start = start,
251
+ .end = start,
252
+ };
253
+
254
+ const end = binary_search_values_upsert_index(
255
+ Key,
256
+ Value,
257
+ key_from_value,
258
+ values[start..],
259
+ key_max,
260
+ .{ .mode = .upper_bound },
261
+ );
262
+
263
+ return .{
264
+ .start = start,
265
+ .end = start + end,
266
+ };
267
+ }
268
+
269
+ pub inline fn binary_search_keys_range_upsert_indexes(
270
+ comptime Key: type,
271
+ keys: []const Key,
272
+ key_min: Key,
273
+ key_max: Key,
274
+ ) BinarySearchRangeUpsertIndexes {
275
+ return binary_search_values_range_upsert_indexes(
276
+ Key,
277
+ Key,
278
+ struct {
279
+ inline fn key_from_key(k: *const Key) Key {
280
+ return k.*;
281
+ }
282
+ }.key_from_key,
283
+ keys,
284
+ key_min,
285
+ key_max,
286
+ );
287
+ }
288
+
289
+ pub const BinarySearchRange = struct {
290
+ start: u32,
291
+ count: u32,
292
+ };
293
+
294
+ /// Returns the index of the first value greater than or equal to `key_min` and
295
+ /// the count of elements until the last value less than or equal to `key_max`.
296
+ ///
297
+ /// Expects `values` to be sorted by key.
298
+ /// The result is always safe for slicing using the `values[start..][0..count]` idiom,
299
+ /// even when no elements are matched.
300
+ pub inline fn binary_search_values_range(
301
+ comptime Key: type,
302
+ comptime Value: type,
303
+ comptime key_from_value: fn (*const Value) callconv(.@"inline") Key,
304
+ values: []const Value,
305
+ key_min: Key,
306
+ key_max: Key,
307
+ ) BinarySearchRange {
308
+ const upsert_indexes = binary_search_values_range_upsert_indexes(
309
+ Key,
310
+ Value,
311
+ key_from_value,
312
+ values,
313
+ key_min,
314
+ key_max,
315
+ );
316
+
317
+ if (upsert_indexes.start == values.len) return .{
318
+ .start = upsert_indexes.start -| 1,
319
+ .count = 0,
320
+ };
321
+
322
+ const inclusive = @intFromBool(
323
+ upsert_indexes.end < values.len and
324
+ key_max == key_from_value(&values[upsert_indexes.end]),
325
+ );
326
+ return .{
327
+ .start = upsert_indexes.start,
328
+ .count = upsert_indexes.end - upsert_indexes.start + inclusive,
329
+ };
330
+ }
331
+
332
+ pub inline fn binary_search_keys_range(
333
+ comptime Key: type,
334
+ keys: []const Key,
335
+ key_min: Key,
336
+ key_max: Key,
337
+ ) BinarySearchRange {
338
+ return binary_search_values_range(
339
+ Key,
340
+ Key,
341
+ struct {
342
+ inline fn key_from_key(k: *const Key) Key {
343
+ return k.*;
344
+ }
345
+ }.key_from_key,
346
+ keys,
347
+ key_min,
348
+ key_max,
349
+ );
350
+ }
351
+
352
+ const test_binary_search = struct {
353
+ const fuzz = @import("../testing/fuzz.zig");
354
+
355
+ const log = false;
356
+
357
+ const gpa = std.testing.allocator;
358
+
359
+ fn less_than_key(_: void, a: u32, b: u32) bool {
360
+ return a < b;
361
+ }
362
+
363
+ fn exhaustive_search(keys_count: u32, comptime mode: anytype) !void {
364
+ const keys = try gpa.alloc(u32, keys_count);
365
+ defer gpa.free(keys);
366
+
367
+ for (keys, 0..) |*key, i| key.* = @intCast(7 * i + 3);
368
+
369
+ var target_key: u32 = 0;
370
+ while (target_key < keys_count + 13) : (target_key += 1) {
371
+ var expect: BinarySearchResult = .{ .index = 0, .exact = false };
372
+ for (keys, 0..) |key, i| {
373
+ switch (std.math.order(key, target_key)) {
374
+ .lt => expect.index = @intCast(i + 1),
375
+ .eq => {
376
+ expect.index = @intCast(i);
377
+ expect.exact = true;
378
+ if (mode == .lower_bound) break;
379
+ },
380
+ .gt => break,
381
+ }
382
+ }
383
+
384
+ if (log) {
385
+ std.debug.print("keys:", .{});
386
+ for (keys) |k| std.debug.print("{},", .{k});
387
+ std.debug.print("\n", .{});
388
+ std.debug.print("target key: {}\n", .{target_key});
389
+ }
390
+
391
+ const actual = binary_search_keys(
392
+ u32,
393
+ keys,
394
+ target_key,
395
+ .{ .mode = mode },
396
+ );
397
+
398
+ if (log) std.debug.print("expected: {}, actual: {}\n", .{ expect, actual });
399
+ try std.testing.expectEqual(expect.index, actual.index);
400
+ try std.testing.expectEqual(expect.exact, actual.exact);
401
+ }
402
+ }
403
+
404
+ fn explicit_search(
405
+ keys: []const u32,
406
+ target_keys: []const u32,
407
+ expected_results: []const BinarySearchResult,
408
+ comptime mode: anytype,
409
+ ) !void {
410
+ assert(target_keys.len == expected_results.len);
411
+
412
+ for (target_keys, 0..) |target_key, i| {
413
+ if (log) {
414
+ std.debug.print("keys:", .{});
415
+ for (keys) |k| std.debug.print("{},", .{k});
416
+ std.debug.print("\n", .{});
417
+ std.debug.print("target key: {}\n", .{target_key});
418
+ }
419
+ const expect = expected_results[i];
420
+ const actual = binary_search_keys(
421
+ u32,
422
+ keys,
423
+ target_key,
424
+ .{ .mode = mode },
425
+ );
426
+ try std.testing.expectEqual(expect.index, actual.index);
427
+ try std.testing.expectEqual(expect.exact, actual.exact);
428
+ }
429
+ }
430
+
431
+ fn random_sequence(
432
+ allocator: std.mem.Allocator,
433
+ prng: *stdx.PRNG,
434
+ iter: usize,
435
+ ) ![]const u32 {
436
+ const keys_count = @min(
437
+ @as(usize, 1E6),
438
+ fuzz.random_int_exponential(prng, usize, iter),
439
+ );
440
+
441
+ const keys = try allocator.alloc(u32, keys_count);
442
+ for (keys) |*key| key.* = fuzz.random_int_exponential(prng, u32, 100);
443
+ std.mem.sort(u32, keys, {}, less_than_key);
444
+
445
+ return keys;
446
+ }
447
+
448
+ fn random_search(prng: *stdx.PRNG, iter: usize, comptime mode: anytype) !void {
449
+ const keys = try random_sequence(std.testing.allocator, prng, iter);
450
+ defer std.testing.allocator.free(keys);
451
+
452
+ const target_key = fuzz.random_int_exponential(prng, u32, 100);
453
+
454
+ var expect: BinarySearchResult = .{ .index = 0, .exact = false };
455
+ for (keys, 0..) |key, i| {
456
+ switch (std.math.order(key, target_key)) {
457
+ .lt => expect.index = @intCast(i + 1),
458
+ .eq => {
459
+ expect.index = @intCast(i);
460
+ expect.exact = true;
461
+ if (mode == .lower_bound) break;
462
+ },
463
+ .gt => break,
464
+ }
465
+ }
466
+
467
+ const actual = binary_search_keys(
468
+ u32,
469
+ keys,
470
+ target_key,
471
+ .{ .mode = mode },
472
+ );
473
+
474
+ if (log) std.debug.print("expected: {}, actual: {}\n", .{ expect, actual });
475
+ try std.testing.expectEqual(expect.index, actual.index);
476
+ try std.testing.expectEqual(expect.exact, actual.exact);
477
+ }
478
+
479
+ pub fn explicit_range_search(
480
+ sequence: []const u32,
481
+ key_min: u32,
482
+ key_max: u32,
483
+ expected: BinarySearchRange,
484
+ ) !void {
485
+ const actual = binary_search_keys_range(
486
+ u32,
487
+ sequence,
488
+ key_min,
489
+ key_max,
490
+ );
491
+
492
+ try std.testing.expectEqual(expected.start, actual.start);
493
+ try std.testing.expectEqual(expected.count, actual.count);
494
+
495
+ // Make sure that the index is valid for slicing using the [start..][0..count] idiom:
496
+ const expected_slice = sequence[expected.start..][0..expected.count];
497
+ const actual_slice = sequence[actual.start..][0..actual.count];
498
+ try std.testing.expectEqualSlices(u32, expected_slice, actual_slice);
499
+ }
500
+
501
+ fn random_range_search(prng: *stdx.PRNG, iter: usize) !void {
502
+ const keys = try random_sequence(std.testing.allocator, prng, iter);
503
+ defer std.testing.allocator.free(keys);
504
+
505
+ const target_range = blk: {
506
+ // Cover many combinations of key_min, key_max:
507
+ var key_min = if (keys.len > 0 and prng.boolean())
508
+ prng.range_inclusive(u32, keys[0], keys[keys.len - 1])
509
+ else
510
+ fuzz.random_int_exponential(prng, u32, 100);
511
+
512
+ var key_max = if (keys.len > 0 and prng.boolean())
513
+ prng.range_inclusive(u32, keys[0], keys[keys.len - 1])
514
+ else if (prng.boolean())
515
+ key_min
516
+ else
517
+ fuzz.random_int_exponential(prng, u32, 100);
518
+
519
+ if (key_max < key_min) std.mem.swap(u32, &key_min, &key_max);
520
+ assert(key_min <= key_max);
521
+
522
+ break :blk .{
523
+ .key_min = key_min,
524
+ .key_max = key_max,
525
+ };
526
+ };
527
+
528
+ var expect: BinarySearchRange = .{ .start = 0, .count = 0 };
529
+ var key_target: enum { key_min, key_max } = .key_min;
530
+ for (keys) |key| {
531
+ if (key_target == .key_min) {
532
+ switch (std.math.order(key, target_range.key_min)) {
533
+ .lt => if (expect.start < keys.len - 1) {
534
+ expect.start += 1;
535
+ },
536
+ .gt, .eq => key_target = .key_max,
537
+ }
538
+ }
539
+
540
+ if (key_target == .key_max) {
541
+ switch (std.math.order(key, target_range.key_max)) {
542
+ .lt, .eq => expect.count += 1,
543
+ .gt => break,
544
+ }
545
+ }
546
+ }
547
+
548
+ const actual = binary_search_keys_range(
549
+ u32,
550
+ keys,
551
+ target_range.key_min,
552
+ target_range.key_max,
553
+ );
554
+
555
+ if (log) std.debug.print("expected: {?}, actual: {?}\n", .{ expect, actual });
556
+ try std.testing.expectEqual(expect.start, actual.start);
557
+ try std.testing.expectEqual(expect.count, actual.count);
558
+ }
559
+ };
560
+
561
+ test "binary search: exhaustive" {
562
+ if (test_binary_search.log) std.debug.print("\n", .{});
563
+ inline for (.{ .lower_bound, .upper_bound }) |mode| {
564
+ var i: u32 = 1;
565
+ while (i < 300) : (i += 1) {
566
+ try test_binary_search.exhaustive_search(i, mode);
567
+ }
568
+ }
569
+ }
570
+
571
+ test "binary search: explicit" {
572
+ if (test_binary_search.log) std.debug.print("\n", .{});
573
+
574
+ inline for (.{ .lower_bound, .upper_bound }) |mode| {
575
+ try test_binary_search.explicit_search(
576
+ &[_]u32{},
577
+ &[_]u32{0},
578
+ &[_]BinarySearchResult{
579
+ .{ .index = 0, .exact = false },
580
+ },
581
+ mode,
582
+ );
583
+
584
+ try test_binary_search.explicit_search(
585
+ &[_]u32{4} ** 10,
586
+ &[_]u32{4},
587
+ &[_]BinarySearchResult{
588
+ .{
589
+ .index = if (mode == .lower_bound) 0 else 9,
590
+ .exact = true,
591
+ },
592
+ },
593
+ mode,
594
+ );
595
+
596
+ try test_binary_search.explicit_search(
597
+ &[_]u32{},
598
+ &[_]u32{0},
599
+ &[_]BinarySearchResult{
600
+ .{ .index = 0, .exact = false },
601
+ },
602
+ mode,
603
+ );
604
+
605
+ try test_binary_search.explicit_search(
606
+ &[_]u32{1},
607
+ &[_]u32{ 0, 1, 2 },
608
+ &[_]BinarySearchResult{
609
+ .{ .index = 0, .exact = false },
610
+ .{ .index = 0, .exact = true },
611
+ .{ .index = 1, .exact = false },
612
+ },
613
+ mode,
614
+ );
615
+
616
+ try test_binary_search.explicit_search(
617
+ &[_]u32{ 1, 3 },
618
+ &[_]u32{ 0, 1, 2, 3, 4 },
619
+ &[_]BinarySearchResult{
620
+ .{ .index = 0, .exact = false },
621
+ .{ .index = 0, .exact = true },
622
+ .{ .index = 1, .exact = false },
623
+ .{ .index = 1, .exact = true },
624
+ .{ .index = 2, .exact = false },
625
+ },
626
+ mode,
627
+ );
628
+
629
+ try test_binary_search.explicit_search(
630
+ &[_]u32{ 1, 3, 5, 8, 9, 11 },
631
+ &[_]u32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
632
+ &[_]BinarySearchResult{
633
+ .{ .index = 0, .exact = false },
634
+ .{ .index = 0, .exact = true },
635
+ .{ .index = 1, .exact = false },
636
+ .{ .index = 1, .exact = true },
637
+ .{ .index = 2, .exact = false },
638
+ .{ .index = 2, .exact = true },
639
+ .{ .index = 3, .exact = false },
640
+ .{ .index = 3, .exact = false },
641
+ .{ .index = 3, .exact = true },
642
+ .{ .index = 4, .exact = true },
643
+ .{ .index = 5, .exact = false },
644
+ .{ .index = 5, .exact = true },
645
+ .{ .index = 6, .exact = false },
646
+ .{ .index = 6, .exact = false },
647
+ },
648
+ mode,
649
+ );
650
+ }
651
+ }
652
+
653
+ test "binary search: duplicates" {
654
+ if (test_binary_search.log) std.debug.print("\n", .{});
655
+ try test_binary_search.explicit_search(
656
+ &[_]u32{ 0, 0, 3, 3, 3, 5, 5, 5, 5 },
657
+ &[_]u32{ 0, 1, 2, 3, 4, 5, 6 },
658
+ &[_]BinarySearchResult{
659
+ .{ .index = 0, .exact = true },
660
+ .{ .index = 2, .exact = false },
661
+ .{ .index = 2, .exact = false },
662
+ .{ .index = 2, .exact = true },
663
+ .{ .index = 5, .exact = false },
664
+ .{ .index = 5, .exact = true },
665
+ .{ .index = 9, .exact = false },
666
+ },
667
+ .lower_bound,
668
+ );
669
+ try test_binary_search.explicit_search(
670
+ &[_]u32{ 0, 0, 3, 3, 3, 5, 5, 5, 5 },
671
+ &[_]u32{ 0, 1, 2, 3, 4, 5, 6 },
672
+ &[_]BinarySearchResult{
673
+ .{ .index = 1, .exact = true },
674
+ .{ .index = 2, .exact = false },
675
+ .{ .index = 2, .exact = false },
676
+ .{ .index = 4, .exact = true },
677
+ .{ .index = 5, .exact = false },
678
+ .{ .index = 8, .exact = true },
679
+ .{ .index = 9, .exact = false },
680
+ },
681
+ .upper_bound,
682
+ );
683
+ }
684
+
685
+ test "binary search: random" {
686
+ var prng = stdx.PRNG.from_seed_testing();
687
+ inline for (.{ .lower_bound, .upper_bound }) |mode| {
688
+ var i: usize = 0;
689
+ while (i < 2048) : (i += 1) {
690
+ try test_binary_search.random_search(&prng, i, mode);
691
+ }
692
+ }
693
+ }
694
+
695
+ test "binary search: explicit range" {
696
+ if (test_binary_search.log) std.debug.print("\n", .{});
697
+
698
+ // Exact interval:
699
+ try test_binary_search.explicit_range_search(
700
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
701
+ 3,
702
+ 1000,
703
+ .{
704
+ .start = 0,
705
+ .count = 9,
706
+ },
707
+ );
708
+
709
+ // Larger interval:
710
+ try test_binary_search.explicit_range_search(
711
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
712
+ 2,
713
+ 1001,
714
+ .{
715
+ .start = 0,
716
+ .count = 9,
717
+ },
718
+ );
719
+
720
+ // Inclusive key_min and exclusive key_max:
721
+ try test_binary_search.explicit_range_search(
722
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
723
+ 3,
724
+ 9,
725
+ .{
726
+ .start = 0,
727
+ .count = 2,
728
+ },
729
+ );
730
+
731
+ // Exclusive key_min and inclusive key_max:
732
+ try test_binary_search.explicit_range_search(
733
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
734
+ 5,
735
+ 10,
736
+ .{
737
+ .start = 2,
738
+ .count = 1,
739
+ },
740
+ );
741
+
742
+ // Exclusive interval:
743
+ try test_binary_search.explicit_range_search(
744
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
745
+ 5,
746
+ 14,
747
+ .{
748
+ .start = 2,
749
+ .count = 1,
750
+ },
751
+ );
752
+
753
+ // Inclusive interval:
754
+ try test_binary_search.explicit_range_search(
755
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
756
+ 15,
757
+ 100,
758
+ .{
759
+ .start = 3,
760
+ .count = 5,
761
+ },
762
+ );
763
+
764
+ // Where key_min == key_max:
765
+ try test_binary_search.explicit_range_search(
766
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
767
+ 10,
768
+ 10,
769
+ .{
770
+ .start = 2,
771
+ .count = 1,
772
+ },
773
+ );
774
+
775
+ // Interval smaller than the first element:
776
+ try test_binary_search.explicit_range_search(
777
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
778
+ 1,
779
+ 2,
780
+ .{
781
+ .start = 0,
782
+ .count = 0,
783
+ },
784
+ );
785
+
786
+ // Interval greater than the last element:
787
+ try test_binary_search.explicit_range_search(
788
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
789
+ 1_001,
790
+ 10_000,
791
+ .{
792
+ .start = 8,
793
+ .count = 0,
794
+ },
795
+ );
796
+
797
+ // Nonexistent interval in the middle:
798
+ try test_binary_search.explicit_range_search(
799
+ &[_]u32{ 3, 4, 10, 15, 20, 25, 30, 100, 1000 },
800
+ 31,
801
+ 99,
802
+ .{
803
+ .start = 7,
804
+ .count = 0,
805
+ },
806
+ );
807
+
808
+ // Empty slice:
809
+ try test_binary_search.explicit_range_search(
810
+ &[_]u32{},
811
+ 1,
812
+ 2,
813
+ .{
814
+ .start = 0,
815
+ .count = 0,
816
+ },
817
+ );
818
+ }
819
+
820
+ test "binary search: duplicated range" {
821
+ if (test_binary_search.log) std.debug.print("\n", .{});
822
+ try test_binary_search.explicit_range_search(
823
+ &[_]u32{ 1, 3, 3, 3, 5, 5, 5, 7 },
824
+ 3,
825
+ 5,
826
+ .{
827
+ .start = 1,
828
+ .count = 6,
829
+ },
830
+ );
831
+ try test_binary_search.explicit_range_search(
832
+ &[_]u32{ 1, 1, 1, 3, 5, 7 },
833
+ 1,
834
+ 1,
835
+ .{
836
+ .start = 0,
837
+ .count = 3,
838
+ },
839
+ );
840
+ }
841
+
842
+ test "binary search: random range" {
843
+ var prng = stdx.PRNG.from_seed_testing();
844
+ var i: usize = 0;
845
+ while (i < 2048) : (i += 1) {
846
+ try test_binary_search.random_range_search(&prng, i);
847
+ }
848
+ }