{"id":13652496,"url":"https://github.com/Ellipsis-Labs/sokoban","last_synced_at":"2025-04-23T03:30:52.110Z","repository":{"id":50716454,"uuid":"519692608","full_name":"Ellipsis-Labs/sokoban","owner":"Ellipsis-Labs","description":"Compact, efficient data structures in contiguous byte arrays","archived":false,"fork":false,"pushed_at":"2024-08-23T18:37:14.000Z","size":143,"stargazers_count":111,"open_issues_count":4,"forks_count":18,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T14:47:40.594Z","etag":null,"topics":["data-structures","graph","rust"],"latest_commit_sha":null,"homepage":"https://docs.rs/lib-sokoban/latest/sokoban","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ellipsis-Labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-31T05:57:52.000Z","updated_at":"2025-03-28T08:25:33.000Z","dependencies_parsed_at":"2024-08-23T20:20:21.671Z","dependency_job_id":null,"html_url":"https://github.com/Ellipsis-Labs/sokoban","commit_stats":null,"previous_names":["jarry-xiao/sokoban"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ellipsis-Labs%2Fsokoban","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ellipsis-Labs%2Fsokoban/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ellipsis-Labs%2Fsokoban/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ellipsis-Labs%2Fsokoban/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ellipsis-Labs","download_url":"https://codeload.github.com/Ellipsis-Labs/sokoban/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250365332,"owners_count":21418670,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-structures","graph","rust"],"created_at":"2024-08-02T02:00:59.849Z","updated_at":"2025-04-23T03:30:50.603Z","avatar_url":"https://github.com/Ellipsis-Labs.png","language":"Rust","funding_links":[],"categories":["Code"],"sub_categories":["Libraries"],"readme":"# Sokoban\n\nCompact, efficient data structures in contiguous byte arrays.\n\n### Benchmarks\n\nBased on simple benchmarks, the naive performance of Sokoban data structures are on par with, but slightly slower than, the Rust Standard Library.\n\n```\ntest bench_tests::bench_sokoban_avl_tree_insert_1000_u128             ... bench:     134,301 ns/iter (+/- 4,033)\ntest bench_tests::bench_sokoban_avl_tree_insert_1000_u128_stack       ... bench:     134,135 ns/iter (+/- 3,620)\ntest bench_tests::bench_sokoban_avl_tree_insert_20000_u128            ... bench:   2,744,853 ns/iter (+/- 158,364)\ntest bench_tests::bench_sokoban_avl_tree_remove_u128                  ... bench:     355,992 ns/iter (+/- 22,770)\ntest bench_tests::bench_sokoban_critbit_insert_1000_u128              ... bench:      90,306 ns/iter (+/- 590)\ntest bench_tests::bench_sokoban_critbit_insert_1000_u128_stack        ... bench:      76,819 ns/iter (+/- 661)\ntest bench_tests::bench_sokoban_critbit_insert_20000_u128             ... bench:   2,839,050 ns/iter (+/- 207,241)\ntest bench_tests::bench_sokoban_critbit_remove_1000_u128              ... bench:      97,366 ns/iter (+/- 6,124)\ntest bench_tests::bench_sokoban_hash_map_insert_1000_u128             ... bench:      46,828 ns/iter (+/- 1,928)\ntest bench_tests::bench_sokoban_hash_map_insert_1000_u128_stack       ... bench:      46,686 ns/iter (+/- 1,691)\ntest bench_tests::bench_sokoban_hash_map_insert_20000_u128            ... bench:   1,492,742 ns/iter (+/- 43,362)\ntest bench_tests::bench_sokoban_hash_map_remove_1000_u128             ... bench:      59,896 ns/iter (+/- 1,782)\ntest bench_tests::bench_sokoban_red_black_tree_insert_1000_u128       ... bench:      69,574 ns/iter (+/- 8,581)\ntest bench_tests::bench_sokoban_red_black_tree_insert_1000_u128_stack ... bench:      66,057 ns/iter (+/- 8,853)\ntest bench_tests::bench_sokoban_red_black_tree_insert_20000_u128      ... bench:   1,905,406 ns/iter (+/- 25,546)\ntest bench_tests::bench_sokoban_red_black_tree_remove_1000_u128       ... bench:     128,889 ns/iter (+/- 13,508)\ntest bench_tests::bench_std_btree_map_insert_1000_u128                ... bench:      51,353 ns/iter (+/- 10,240)\ntest bench_tests::bench_std_btree_map_insert_20000_u128               ... bench:   1,535,224 ns/iter (+/- 21,645)\ntest bench_tests::bench_std_btree_map_remove_1000_u128                ... bench:     131,879 ns/iter (+/- 19,325)\ntest bench_tests::bench_std_hash_map_insert_1000_u128                 ... bench:      38,775 ns/iter (+/- 237)\ntest bench_tests::bench_std_hash_map_insert_20000_u128                ... bench:     797,904 ns/iter (+/- 10,719)\ntest bench_tests::bench_std_hash_map_remove_1000_u128                 ... bench:      57,452 ns/iter (+/- 364)\n```\n\n### Why compact data structures?\n\nFor most applications, there is no reason to look past the Rust standard library for data structures. However, when the application has limited or expensive memory and is bottlenecked by performance, programmers will often need to design custom solutions to address those constraints. These types of constraints come up quite frequently in high frequency trading, embedded systems, and blockchain development.\n\nEnter Sokoban: A library of data structures designed to simplify this exact problem.\n\n### Generic Node Allocator\n\nAlmost all data structures can be represented by some sort of connected graph of nodes and edges. The `node-allocator` module implements a raw node allocation data structure for contiguous buffers. Each entry in the buffer must contain objects of the same underlying type. Each entry will also have a fixed number of _registers_ that contain metadata relating to the current node. These registers will usually be interpreted as graph edges.\n\n```rust\n#[repr(C)]\n#[derive(Copy, Clone)]\npub struct NodeAllocator\u003c\n    T: Default + Copy + Clone + Pod + Zeroable,\n    const MAX_SIZE: usize,\n    const NUM_REGISTERS: usize,\n\u003e {\n    /// Size of the allocator\n    pub size: u64,\n    /// Furthest index of the allocator\n    bump_index: u32,\n    /// Buffer index of the first element in the free list\n    free_list_head: u32,\n    pub nodes: [Node\u003cNUM_REGISTERS, T\u003e; MAX_SIZE],\n}\n\n#[repr(C)]\n#[derive(Copy, Clone)]\npub struct Node\u003cT: Copy + Clone + Pod + Zeroable + Default, const NUM_REGISTERS: usize\u003e {\n    /// Arbitrary registers (generally used for pointers)\n    /// Note: Register 0 is ALWAYS used for the free list\n    registers: [u32; NUM_REGISTERS],\n    value: T,\n}\n```\n\nThe templated `NodeAllocator` object is flexible primitive data structure for implementing more complex types. Here's how one might use the `NodeAllocator` to implement a doubly-linked list:\n\n```rust\n// Register aliases\npub const PREV: u32 = 0;\npub const NEXT: u32 = 1;\n\n#[derive(Copy, Clone)]\npub struct DLL\u003cT: Default + Copy + Clone + Pod + Zeroable, const MAX_SIZE: usize\u003e {\n    pub head: u32,\n    pub tail: u32,\n    allocator: NodeAllocator\u003cT, MAX_SIZE, 2\u003e,\n}\n```\n\nThe DLL is essentially just a node allocator with 2 registers per node. These registers represent the `prev` and `next` pointers of a DLL node. The logic for how edges are created and removed are specific to the type, but the allocator struct provides an interface for implementing arbitrary types that have this property (trees and graphs).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEllipsis-Labs%2Fsokoban","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FEllipsis-Labs%2Fsokoban","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEllipsis-Labs%2Fsokoban/lists"}