tigerbeetle 0.0.36 → 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.
- checksums.yaml +4 -4
- data/ext/tb_client/extconf.rb +13 -13
- data/ext/tb_client/tigerbeetle/LICENSE +177 -0
- data/ext/tb_client/tigerbeetle/build.zig +2327 -0
- data/ext/tb_client/tigerbeetle/src/aof.zig +1000 -0
- data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +808 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +1283 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +1704 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +341 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +1450 -0
- data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +1659 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +406 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +1084 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +286 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +158 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +229 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +110 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +386 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +34 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +281 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +312 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +138 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +466 -0
- data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +157 -0
- data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +90 -0
- data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +203 -0
- data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +79 -0
- data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +542 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +109 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +86 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +370 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +386 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +167 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +126 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +996 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +748 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +3238 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +1718 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +190 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +104 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +75 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +522 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +267 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +3 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +379 -0
- data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +131 -0
- data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +63 -0
- data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +588 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/assets/tb_client.h +386 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +73 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +106 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +305 -0
- data/ext/tb_client/tigerbeetle/src/config.zig +296 -0
- data/ext/tb_client/tigerbeetle/src/constants.zig +790 -0
- data/ext/tb_client/tigerbeetle/src/copyhound.zig +202 -0
- data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +72 -0
- data/ext/tb_client/tigerbeetle/src/direction.zig +11 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +158 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +156 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +252 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +313 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +87 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +63 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +47 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +28 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +61 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +169 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +46 -0
- data/ext/tb_client/tigerbeetle/src/ewah.zig +445 -0
- data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +128 -0
- data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +171 -0
- data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +179 -0
- data/ext/tb_client/tigerbeetle/src/integration_tests.zig +662 -0
- data/ext/tb_client/tigerbeetle/src/io/common.zig +155 -0
- data/ext/tb_client/tigerbeetle/src/io/darwin.zig +1093 -0
- data/ext/tb_client/tigerbeetle/src/io/linux.zig +1880 -0
- data/ext/tb_client/tigerbeetle/src/io/test.zig +1005 -0
- data/ext/tb_client/tigerbeetle/src/io/windows.zig +1598 -0
- data/ext/tb_client/tigerbeetle/src/io.zig +34 -0
- data/ext/tb_client/tigerbeetle/src/iops.zig +134 -0
- data/ext/tb_client/tigerbeetle/src/list.zig +236 -0
- data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +848 -0
- data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +179 -0
- data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +424 -0
- data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +420 -0
- data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +2117 -0
- data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +182 -0
- data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +1119 -0
- data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +1102 -0
- data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +200 -0
- data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +1495 -0
- data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +739 -0
- data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +166 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +754 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +1294 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +510 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +1263 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +628 -0
- data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +247 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +116 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +543 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +938 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +293 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +362 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +99 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +17 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +1036 -0
- data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +617 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +84 -0
- data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +1500 -0
- data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +149 -0
- data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +7 -0
- data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +865 -0
- data/ext/tb_client/tigerbeetle/src/lsm/table.zig +607 -0
- data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +843 -0
- data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +105 -0
- data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +40 -0
- data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +630 -0
- data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +933 -0
- data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +557 -0
- data/ext/tb_client/tigerbeetle/src/message_buffer.zig +469 -0
- data/ext/tb_client/tigerbeetle/src/message_bus.zig +1214 -0
- data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +936 -0
- data/ext/tb_client/tigerbeetle/src/message_pool.zig +343 -0
- data/ext/tb_client/tigerbeetle/src/multiversion.zig +2195 -0
- data/ext/tb_client/tigerbeetle/src/queue.zig +390 -0
- data/ext/tb_client/tigerbeetle/src/repl/completion.zig +201 -0
- data/ext/tb_client/tigerbeetle/src/repl/parser.zig +1356 -0
- data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +496 -0
- data/ext/tb_client/tigerbeetle/src/repl.zig +1034 -0
- data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +973 -0
- data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +1866 -0
- data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +304 -0
- data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +227 -0
- data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +658 -0
- data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +466 -0
- data/ext/tb_client/tigerbeetle/src/scripts/release.zig +1058 -0
- data/ext/tb_client/tigerbeetle/src/scripts.zig +105 -0
- data/ext/tb_client/tigerbeetle/src/shell.zig +1195 -0
- data/ext/tb_client/tigerbeetle/src/stack.zig +260 -0
- data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +911 -0
- data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +2079 -0
- data/ext/tb_client/tigerbeetle/src/state_machine.zig +4872 -0
- data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +288 -0
- data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +3128 -0
- data/ext/tb_client/tigerbeetle/src/static_allocator.zig +82 -0
- data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +157 -0
- data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +292 -0
- data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +65 -0
- data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +1414 -0
- data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +92 -0
- data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +677 -0
- data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +336 -0
- data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +511 -0
- data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +112 -0
- data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +1160 -0
- data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +142 -0
- data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +361 -0
- data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +275 -0
- data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +295 -0
- data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +436 -0
- data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +48 -0
- data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +402 -0
- data/ext/tb_client/tigerbeetle/src/storage.zig +489 -0
- data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +180 -0
- data/ext/tb_client/tigerbeetle/src/testing/bench.zig +146 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +53 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +61 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +76 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +110 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +412 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +331 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +458 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +1198 -0
- data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +128 -0
- data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +181 -0
- data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +144 -0
- data/ext/tb_client/tigerbeetle/src/testing/id.zig +97 -0
- data/ext/tb_client/tigerbeetle/src/testing/io.zig +317 -0
- data/ext/tb_client/tigerbeetle/src/testing/marks.zig +126 -0
- data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +533 -0
- data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +154 -0
- data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +389 -0
- data/ext/tb_client/tigerbeetle/src/testing/storage.zig +1247 -0
- data/ext/tb_client/tigerbeetle/src/testing/table.zig +249 -0
- data/ext/tb_client/tigerbeetle/src/testing/time.zig +98 -0
- data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +212 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +26 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +580 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +39 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +214 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +34 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +766 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +543 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +181 -0
- data/ext/tb_client/tigerbeetle/src/tidy.zig +1448 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +227 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +1069 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +1422 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +1658 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +518 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +36 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +646 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +958 -0
- data/ext/tb_client/tigerbeetle/src/time.zig +236 -0
- data/ext/tb_client/tigerbeetle/src/trace/event.zig +745 -0
- data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +462 -0
- data/ext/tb_client/tigerbeetle/src/trace.zig +556 -0
- data/ext/tb_client/tigerbeetle/src/unit_tests.zig +321 -0
- data/ext/tb_client/tigerbeetle/src/vopr.zig +1785 -0
- data/ext/tb_client/tigerbeetle/src/vortex.zig +101 -0
- data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +473 -0
- data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +208 -0
- data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +43 -0
- data/ext/tb_client/tigerbeetle/src/vsr/client.zig +768 -0
- data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +532 -0
- data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +338 -0
- data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +1019 -0
- data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +279 -0
- data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +1381 -0
- data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +315 -0
- data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +1460 -0
- data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +757 -0
- data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +797 -0
- data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +2586 -0
- data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +308 -0
- data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +1777 -0
- data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +715 -0
- data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +185 -0
- data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +333 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +12355 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +416 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +165 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +2910 -0
- data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +1075 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +1603 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +484 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +405 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +355 -0
- data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +29 -0
- data/ext/tb_client/tigerbeetle/src/vsr.zig +1727 -0
- data/lib/tb_client/shared_lib.rb +12 -5
- data/lib/tigerbeetle/platforms.rb +9 -0
- data/lib/tigerbeetle/version.rb +1 -1
- data/tigerbeetle.gemspec +22 -5
- metadata +242 -3
- data/ext/tb_client/pkg.tar.gz +0 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
//! Stable, non-allocating, out-of-place LSD radix sort over unsigned integer keys.
|
|
2
|
+
//! Sorts `values` in ascending order by `key_from_value`, using `values_scratch`
|
|
3
|
+
//! as an equally sized, disjoint swap buffer. Keys must be an unsigned `Int`.
|
|
4
|
+
//! The sorted result is in the original buffer `values`.
|
|
5
|
+
//! The implementation builds per-pass histograms, skips trivial passes (all items
|
|
6
|
+
//! in one bucket), and uses a fixed digit width (8 or 11 bits based on `Value` size)
|
|
7
|
+
//! to reduce the number of passes. Buffers are swapped after each non-trivial pass;
|
|
8
|
+
//! if the number of such passes is odd, results are copied back so `values` holds
|
|
9
|
+
//! the output on return.
|
|
10
|
+
|
|
11
|
+
const std = @import("std");
|
|
12
|
+
const assert = std.debug.assert;
|
|
13
|
+
const stdx = @import("stdx.zig");
|
|
14
|
+
|
|
15
|
+
/// Stable, ascending radix sort for unsigned integers. The sorted result will be in `values`.
|
|
16
|
+
pub fn sort(
|
|
17
|
+
comptime Key: type,
|
|
18
|
+
comptime Value: type,
|
|
19
|
+
comptime key_from_value: fn (*const Value) callconv(.@"inline") Key,
|
|
20
|
+
values: []Value,
|
|
21
|
+
values_scratch: []Value,
|
|
22
|
+
) void {
|
|
23
|
+
comptime {
|
|
24
|
+
assert(@typeInfo(Key) == .int);
|
|
25
|
+
assert(@typeInfo(Key).int.signedness == .unsigned);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
assert(stdx.disjoint_slices(Value, Value, values, values_scratch));
|
|
29
|
+
assert(values.len == values_scratch.len);
|
|
30
|
+
assert(values.len <= std.math.maxInt(u32));
|
|
31
|
+
|
|
32
|
+
if (values.len == 0) return;
|
|
33
|
+
if (values.len <= 32) {
|
|
34
|
+
return std.sort.insertion(Value, values, {}, struct {
|
|
35
|
+
fn lessThan(_: void, a: Value, b: Value) bool {
|
|
36
|
+
return key_from_value(&a) < key_from_value(&b);
|
|
37
|
+
}
|
|
38
|
+
}.lessThan);
|
|
39
|
+
}
|
|
40
|
+
radix_sort(Key, Value, key_from_value, values, values_scratch);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fn radix_sort(
|
|
44
|
+
comptime Key: type,
|
|
45
|
+
comptime Value: type,
|
|
46
|
+
comptime key_from_value: fn (*const Value) callconv(.@"inline") Key,
|
|
47
|
+
values: []Value,
|
|
48
|
+
values_scratch: []Value,
|
|
49
|
+
) void {
|
|
50
|
+
const count: u32 = @intCast(values.len);
|
|
51
|
+
// Heuristic: use more bits for larger value sizes to reduce the number of passes.
|
|
52
|
+
const radix_bits_heuristic = if (@sizeOf(Value) >= 128) 11 else 8;
|
|
53
|
+
const radix_bits = @min(@bitSizeOf(Key), radix_bits_heuristic);
|
|
54
|
+
const radix_passes = stdx.div_ceil(@bitSizeOf(Key), radix_bits);
|
|
55
|
+
const radix_partitions = 1 << radix_bits;
|
|
56
|
+
const radix_mask: u32 = radix_partitions - 1;
|
|
57
|
+
|
|
58
|
+
const BitsKey = std.math.Log2Int(Key); // Used to shift the key for each pass.
|
|
59
|
+
const Histograms: type = [radix_passes][radix_partitions]u32;
|
|
60
|
+
comptime assert(@sizeOf(Histograms) <= 200 * stdx.KiB);
|
|
61
|
+
|
|
62
|
+
// Create histograms per radix pass in a single iteration over `values`.
|
|
63
|
+
const histograms = blk: {
|
|
64
|
+
var histograms: Histograms align(64) = @splat(@splat(0));
|
|
65
|
+
|
|
66
|
+
for (values) |*value| {
|
|
67
|
+
const key = key_from_value(value);
|
|
68
|
+
inline for (0..radix_passes) |pass| {
|
|
69
|
+
const pass_bit_offset: BitsKey = @intCast(pass * radix_bits);
|
|
70
|
+
const partition_id: u32 = @intCast((key >> pass_bit_offset) & radix_mask);
|
|
71
|
+
histograms[pass][partition_id] += 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
break :blk histograms;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
var source: []Value = values;
|
|
78
|
+
var target: []Value = values_scratch;
|
|
79
|
+
var target_offsets: [radix_partitions]u32 = @splat(0);
|
|
80
|
+
|
|
81
|
+
inline for (0..radix_passes) |pass| {
|
|
82
|
+
// Determine if a pass is trivial if exactly one partition has all `count` elements.
|
|
83
|
+
const pass_trivial: bool = for (histograms[pass]) |partition_count| {
|
|
84
|
+
if (partition_count == count) break true;
|
|
85
|
+
} else false;
|
|
86
|
+
|
|
87
|
+
if (!pass_trivial) {
|
|
88
|
+
// Build prefix sums.
|
|
89
|
+
var next_offset: u32 = 0;
|
|
90
|
+
for (0..radix_partitions) |partition_id| {
|
|
91
|
+
target_offsets[partition_id] = next_offset;
|
|
92
|
+
next_offset += histograms[pass][partition_id];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Partitioning pass.
|
|
96
|
+
const pass_bit_offset: BitsKey = @intCast(pass * radix_bits);
|
|
97
|
+
for (source) |*value| {
|
|
98
|
+
const key: Key = key_from_value(value);
|
|
99
|
+
const partition_id: u32 = @intCast((key >> pass_bit_offset) & radix_mask);
|
|
100
|
+
|
|
101
|
+
target[target_offsets[partition_id]] = value.*;
|
|
102
|
+
target_offsets[partition_id] += 1;
|
|
103
|
+
}
|
|
104
|
+
std.mem.swap([]Value, &source, &target);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Copy the values back into the input buffer `values`.
|
|
109
|
+
if (values.ptr != source.ptr) {
|
|
110
|
+
stdx.copy_disjoint(.exact, Value, values, values_scratch);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const ratio = stdx.PRNG.ratio;
|
|
115
|
+
|
|
116
|
+
pub fn TestValueType(comptime Key: type, comptime value_length: usize) type {
|
|
117
|
+
return struct {
|
|
118
|
+
const Value = @This();
|
|
119
|
+
|
|
120
|
+
x: Key,
|
|
121
|
+
y: u32, // y ensures that values are distinct for the purpose of checking stability.
|
|
122
|
+
padding: [value_length]u8 = @splat(0),
|
|
123
|
+
|
|
124
|
+
inline fn key_from_value(value: *const Value) Key {
|
|
125
|
+
return value.x;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn compare_x_ascending(_: void, a: Value, b: Value) bool {
|
|
129
|
+
return a.x < b.x;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
fn compare_x_descending(_: void, a: Value, b: Value) bool {
|
|
133
|
+
return a.x > b.x;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
test "radix_sort: smoke" {
|
|
139
|
+
const Value = TestValueType(u8, 0);
|
|
140
|
+
var values: [5]Value = .{
|
|
141
|
+
Value{ .x = 3, .y = 0 },
|
|
142
|
+
Value{ .x = 2, .y = 0 },
|
|
143
|
+
Value{ .x = 3, .y = 1 },
|
|
144
|
+
Value{ .x = 1, .y = 0 },
|
|
145
|
+
Value{ .x = 5, .y = 0 },
|
|
146
|
+
};
|
|
147
|
+
const values_expected: [5]Value = .{
|
|
148
|
+
Value{ .x = 1, .y = 0 },
|
|
149
|
+
Value{ .x = 2, .y = 0 },
|
|
150
|
+
Value{ .x = 3, .y = 0 },
|
|
151
|
+
Value{ .x = 3, .y = 1 },
|
|
152
|
+
Value{ .x = 5, .y = 0 },
|
|
153
|
+
};
|
|
154
|
+
var values_scratch: [5]Value = undefined;
|
|
155
|
+
radix_sort(
|
|
156
|
+
u8,
|
|
157
|
+
Value,
|
|
158
|
+
Value.key_from_value,
|
|
159
|
+
&values,
|
|
160
|
+
&values_scratch,
|
|
161
|
+
);
|
|
162
|
+
try std.testing.expectEqual(values_expected, values);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Ascending order + stability against a (x,y) baseline, with a large Value
|
|
166
|
+
// payload to exercise the 11-bit radix path (since @sizeOf(Value) >= 128).
|
|
167
|
+
test "radix_sort: ascending & stable on many duplicates" {
|
|
168
|
+
const Key = u32;
|
|
169
|
+
const Value = TestValueType(Key, 128); // >=128 so radix_bits heuristic picks 11
|
|
170
|
+
const allocator = std.testing.allocator;
|
|
171
|
+
|
|
172
|
+
const n: usize = 2048;
|
|
173
|
+
|
|
174
|
+
const values = try allocator.alloc(Value, n);
|
|
175
|
+
defer allocator.free(values);
|
|
176
|
+
|
|
177
|
+
const scratch = try allocator.alloc(Value, n);
|
|
178
|
+
defer allocator.free(scratch);
|
|
179
|
+
|
|
180
|
+
// Many duplicates; y = original index (used to check stability).
|
|
181
|
+
for (values, 0..) |*v, i| {
|
|
182
|
+
const k: Key = @intCast(i % 257);
|
|
183
|
+
v.* = .{ .x = k, .y = @intCast(i) };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
radix_sort(Key, Value, Value.key_from_value, values, scratch);
|
|
187
|
+
|
|
188
|
+
// Verify that the order is `ascending` and `stable`.
|
|
189
|
+
for (values[0 .. values.len - 1], values[1..]) |a, b| {
|
|
190
|
+
switch (std.math.order(a.x, b.x)) {
|
|
191
|
+
.eq => try std.testing.expect(a.y < b.y),
|
|
192
|
+
.lt => try std.testing.expect(a.x < b.x),
|
|
193
|
+
.gt => unreachable,
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// All keys equal → every pass is "trivial". Sort should be a no-op on values,
|
|
199
|
+
// keep relative order (stability).
|
|
200
|
+
test "radix_sort: all-equal keys preserve relative order (stability)" {
|
|
201
|
+
const Key = u64;
|
|
202
|
+
const Value = TestValueType(Key, 8);
|
|
203
|
+
const allocator = std.testing.allocator;
|
|
204
|
+
|
|
205
|
+
const n: usize = 1024;
|
|
206
|
+
|
|
207
|
+
const values = try allocator.alloc(Value, n);
|
|
208
|
+
defer allocator.free(values);
|
|
209
|
+
|
|
210
|
+
const scratch = try allocator.alloc(Value, n);
|
|
211
|
+
defer allocator.free(scratch);
|
|
212
|
+
|
|
213
|
+
// Fill scratch with a sentinel to detect writes.
|
|
214
|
+
const sentinel: Value = .{ .x = 0xFFFF_FFFF_FFFF_FFFF, .y = 0xDEAD_BEEF };
|
|
215
|
+
for (scratch) |*s| s.* = sentinel;
|
|
216
|
+
|
|
217
|
+
// All keys identical; y = original index to check stability.
|
|
218
|
+
for (values, 0..) |*v, i| {
|
|
219
|
+
v.* = .{ .x = 42, .y = @intCast(i) };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
radix_sort(Key, Value, Value.key_from_value, values, scratch);
|
|
223
|
+
|
|
224
|
+
// Verify that the order is `ascending` and `stable`.
|
|
225
|
+
for (values[0 .. values.len - 1], values[1..]) |a, b| {
|
|
226
|
+
switch (std.math.order(a.x, b.x)) {
|
|
227
|
+
.eq => try std.testing.expect(a.y < b.y),
|
|
228
|
+
.lt => try std.testing.expect(a.x < b.x),
|
|
229
|
+
.gt => unreachable,
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
test "fuzz radix_sort_stable" {
|
|
235
|
+
inline for (.{
|
|
236
|
+
.{ u3, 0 }, // Smaller than radix bits.
|
|
237
|
+
.{ u256, 130 }, // Largest histogram, requires multiple passes and bit heuristic.
|
|
238
|
+
}) |pair| {
|
|
239
|
+
const Key = pair.@"0";
|
|
240
|
+
const value_size_min = pair.@"1";
|
|
241
|
+
const allocator = std.testing.allocator;
|
|
242
|
+
|
|
243
|
+
const Value = TestValueType(Key, value_size_min);
|
|
244
|
+
|
|
245
|
+
var prng = stdx.PRNG.from_seed_testing();
|
|
246
|
+
|
|
247
|
+
const values_max = 1 << 18; // Explores uneven and even passes to test copy back.
|
|
248
|
+
const values_all = try allocator.alloc(Value, values_max);
|
|
249
|
+
defer allocator.free(values_all);
|
|
250
|
+
|
|
251
|
+
const values_all_scratch = try allocator.alloc(Value, values_max);
|
|
252
|
+
defer allocator.free(values_all_scratch);
|
|
253
|
+
|
|
254
|
+
for (0..64) |_| {
|
|
255
|
+
const values_count = prng.range_inclusive(u32, 2, values_max);
|
|
256
|
+
const values = values_all[0..values_count];
|
|
257
|
+
const values_scratch = values_all_scratch[0..values_count];
|
|
258
|
+
|
|
259
|
+
{
|
|
260
|
+
// Set up `values`.
|
|
261
|
+
for (values) |*value| {
|
|
262
|
+
value.* = .{
|
|
263
|
+
.x = prng.int_inclusive(Key, @min(
|
|
264
|
+
std.math.maxInt(Key),
|
|
265
|
+
values_count * 2 - 1,
|
|
266
|
+
)),
|
|
267
|
+
.y = undefined,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Sort algorithms often optimize the case of already-sorted
|
|
272
|
+
// (or already-reverse-sorted) sub-arrays.
|
|
273
|
+
const partitions_count = prng.range_inclusive(
|
|
274
|
+
u32,
|
|
275
|
+
1,
|
|
276
|
+
@max(values_count, 64) - 1,
|
|
277
|
+
);
|
|
278
|
+
// The `partition_reverse_probability` is a subset of the partitions sorted by
|
|
279
|
+
// `partition_sort_percent`.
|
|
280
|
+
const partition_sort_probability = ratio(prng.int_inclusive(u8, 100), 100);
|
|
281
|
+
const partition_reverse_probability = ratio(prng.int_inclusive(u8, 100), 100);
|
|
282
|
+
|
|
283
|
+
var partitions_remaining: u32 = partitions_count;
|
|
284
|
+
var partition_offset: u32 = 0;
|
|
285
|
+
while (partition_offset < values_count) {
|
|
286
|
+
const partition_size = size: {
|
|
287
|
+
if (partitions_remaining == 1) {
|
|
288
|
+
break :size values_count - partition_offset;
|
|
289
|
+
} else {
|
|
290
|
+
break :size prng.range_inclusive(
|
|
291
|
+
u32,
|
|
292
|
+
1,
|
|
293
|
+
values_count - partition_offset,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
if (prng.chance(partition_sort_probability)) {
|
|
299
|
+
const partition = values[partition_offset..][0..partition_size];
|
|
300
|
+
if (prng.chance(partition_reverse_probability)) {
|
|
301
|
+
std.mem.sortUnstable(
|
|
302
|
+
Value,
|
|
303
|
+
partition,
|
|
304
|
+
{},
|
|
305
|
+
Value.compare_x_descending,
|
|
306
|
+
);
|
|
307
|
+
} else {
|
|
308
|
+
std.mem.sortUnstable(
|
|
309
|
+
Value,
|
|
310
|
+
partition,
|
|
311
|
+
{},
|
|
312
|
+
Value.compare_x_ascending,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
partitions_remaining -= 1;
|
|
318
|
+
partition_offset += partition_size;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
for (values, 0..) |*value, i| value.y = @intCast(i);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
radix_sort(Key, Value, Value.key_from_value, values, values_scratch);
|
|
325
|
+
|
|
326
|
+
// Verify that the order is `ascending` and `stable`.
|
|
327
|
+
for (values[0 .. values.len - 1], values[1..]) |a, b| {
|
|
328
|
+
switch (std.math.order(a.x, b.x)) {
|
|
329
|
+
.eq => try std.testing.expect(a.y < b.y),
|
|
330
|
+
.lt => try std.testing.expect(a.x < b.x),
|
|
331
|
+
.gt => unreachable,
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|