range-collections-0.4.5/.cargo_vcs_info.json0000644000000001360000000000100144520ustar { "git": { "sha1": "8dd4dea4b407fb20dfaf072d8d503ba2ec757703" }, "path_in_vcs": "" }range-collections-0.4.5/.github/workflows/rust.yml000064400000000000000000000007631046102023000203650ustar 00000000000000name: Rust on: push: branches: [ master ] pull_request: branches: [ master ] env: CARGO_TERM_COLOR: always jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: fmt run: cargo fmt --all -- --check - name: clippy run: cargo --locked clippy --all-targets -- -D warnings - name: Build run: cargo build --all-features --locked --verbose - name: Run tests run: cargo test --all-features --locked --verbose range-collections-0.4.5/.gitignore000064400000000000000000000000251046102023000152270ustar 00000000000000**/target **/*.rs.bk range-collections-0.4.5/Cargo.lock0000644000001101550000000000100124300ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "ahash" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom 0.2.10", "once_cell", "version_check", ] [[package]] name = "aho-corasick" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi 0.1.19", "libc", "winapi", ] [[package]] name = "autocfg" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" dependencies = [ "autocfg 1.1.0", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "binary-merge" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597bb81c80a54b6a4381b23faba8d7774b144c94cbd1d6fe3f1329bd776554ab" [[package]] name = "bit-set" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "bumpalo" version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytecheck" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" dependencies = [ "bytecheck_derive", "ptr_meta", "simdutf8", ] [[package]] name = "bytecheck_derive" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags 1.3.2", "textwrap", "unicode-width", ] [[package]] name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "criterion" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ "atty", "cast", "clap", "criterion-plot", "csv", "itertools", "lazy_static", "num-traits", "oorandom", "plotters", "rayon", "regex", "serde", "serde_cbor", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ "cast", "itertools", ] [[package]] name = "crossbeam-channel" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg 1.1.0", "cfg-if", "crossbeam-utils", "memoffset", "scopeguard", ] [[package]] name = "crossbeam-utils" version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] [[package]] name = "csv" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" dependencies = [ "csv-core", "itoa", "ryu", "serde", ] [[package]] name = "csv-core" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" dependencies = [ "memchr", ] [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "env_logger" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" dependencies = [ "log", "regex", ] [[package]] name = "errno" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", "windows-sys", ] [[package]] name = "errno-dragonfly" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ "cc", "libc", ] [[package]] name = "fastrand" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "getrandom" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "half" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "hermit-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "inplace-vec-builder" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf64c2edc8226891a71f127587a2861b132d2b942310843814d5001d99a1d307" dependencies = [ "smallvec", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libm" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linux-raw-sys" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memoffset" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg 1.1.0", ] [[package]] name = "num-traits" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg 1.1.0", "libm", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi 0.3.2", "libc", ] [[package]] name = "obey" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8313632bf2910fb7ce3a65714de64adb01f68e2eb8ae41ef0d82b86422071b8f" [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "oorandom" version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "plotters" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "plotters-svg" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" dependencies = [ "plotters-backend", ] [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ "unicode-xid", ] [[package]] name = "proc-macro2" version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" dependencies = [ "bit-set", "bitflags 1.3.2", "byteorder", "lazy_static", "num-traits", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift 0.3.0", "regex-syntax 0.6.29", "rusty-fork", "tempfile", "unarray", ] [[package]] name = "ptr_meta" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ "ptr_meta_derive", ] [[package]] name = "ptr_meta_derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quickcheck" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c35d9c36a562f37eca96e79f66d5fd56eefbc22560dacc4a864cabd2d277456" dependencies = [ "env_logger", "log", "rand 0.6.5", "rand_core 0.4.2", ] [[package]] name = "quickcheck_macros" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7dfc1c4a1e048f5cc7d36a4c4118dfcf31d217c79f4b9a61bad65d68185752c" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.13", "syn 0.15.44", ] [[package]] name = "quote" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" dependencies = [ "proc-macro2 0.4.30", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2 1.0.67", ] [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" dependencies = [ "autocfg 0.1.8", "libc", "rand_chacha 0.1.1", "rand_core 0.4.2", "rand_hc 0.1.0", "rand_isaac", "rand_jitter", "rand_os", "rand_pcg", "rand_xorshift 0.1.1", "winapi", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom 0.1.16", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc 0.2.0", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] [[package]] name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" dependencies = [ "autocfg 0.1.8", "rand_core 0.3.1", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", "rand_core 0.5.1", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core 0.6.4", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ "getrandom 0.1.16", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.10", ] [[package]] name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" dependencies = [ "rand_core 0.3.1", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ "rand_core 0.5.1", ] [[package]] name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" dependencies = [ "rand_core 0.3.1", ] [[package]] name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" dependencies = [ "libc", "rand_core 0.4.2", "winapi", ] [[package]] name = "rand_os" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ "cloudabi", "fuchsia-cprng", "libc", "rand_core 0.4.2", "rdrand", "winapi", ] [[package]] name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" dependencies = [ "autocfg 0.1.8", "rand_core 0.4.2", ] [[package]] name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" dependencies = [ "rand_core 0.3.1", ] [[package]] name = "rand_xorshift" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ "rand_core 0.6.4", ] [[package]] name = "range-collections" version = "0.4.5" dependencies = [ "binary-merge", "bytecheck", "criterion", "hex", "inplace-vec-builder", "num-traits", "obey", "proptest", "quickcheck", "quickcheck_macros", "rand 0.7.3", "ref-cast", "rkyv", "serde", "serde_cbor", "smallvec", "testdrop", ] [[package]] name = "rayon" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", "num_cpus", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ "rand_core 0.3.1", ] [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "ref-cast" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acde58d073e9c79da00f2b5b84eed919c8326832648a5b109b3fce1bb1175280" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "syn 2.0.37", ] [[package]] name = "regex" version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax 0.7.5", ] [[package]] name = "regex-automata" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ "aho-corasick", "memchr", "regex-syntax 0.7.5", ] [[package]] name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "rend" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" dependencies = [ "bytecheck", ] [[package]] name = "rkyv" version = "0.7.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" dependencies = [ "bitvec", "bytecheck", "hashbrown", "ptr_meta", "rend", "rkyv_derive", "seahash", "tinyvec", "uuid", ] [[package]] name = "rkyv_derive" version = "0.7.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "syn 1.0.109", ] [[package]] name = "rustix" version = "0.38.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" dependencies = [ "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "rusty-fork" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", "quick-error", "tempfile", "wait-timeout", ] [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "seahash" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "serde" version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_cbor" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", ] [[package]] name = "serde_derive" version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "syn 2.0.37", ] [[package]] name = "serde_json" version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "simdutf8" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" [[package]] name = "smallvec" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "syn" version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.13", "unicode-xid", ] [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "unicode-ident", ] [[package]] name = "syn" version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "unicode-ident", ] [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", "windows-sys", ] [[package]] name = "testdrop" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d39ee32a48eb5325bd3927d4533ac58344af21def4a43ddfc3734c43aebbeae" [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ "unicode-width", ] [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "unarray" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "uuid" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ "libc", ] [[package]] name = "walkdir" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2 1.0.67", "quote 1.0.33", "syn 2.0.37", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote 1.0.33", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2 1.0.67", "quote 1.0.33", "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "wyz" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] range-collections-0.4.5/Cargo.toml0000644000000037450000000000100124610ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "range-collections" version = "0.4.5" authors = ["Rüdiger Klaehn "] description = "Sets and maps of ranges, backed by smallvec" homepage = "https://github.com/rklaehn" readme = "README.md" keywords = [ "succinct", "array", "range", "smallvec", ] categories = ["data-structures"] license = "MIT OR Apache-2.0" repository = "https://github.com/rklaehn/range-collections" [[bench]] name = "range_set" harness = false [dependencies.binary-merge] version = "0.1.1" [dependencies.bytecheck] version = "0.6.5" optional = true [dependencies.inplace-vec-builder] version = "0.1.0" features = ["smallvec"] default-features = false [dependencies.ref-cast] version = "1.0.20" [dependencies.rkyv] version = "0.7.18" optional = true [dependencies.serde] version = "1" optional = true default-features = false [dependencies.smallvec] version = "1.0" [dev-dependencies.criterion] version = "0.3.0" [dev-dependencies.hex] version = "0.4.3" [dev-dependencies.num-traits] version = "0.2.8" [dev-dependencies.obey] version = "0.1.1" [dev-dependencies.proptest] version = "1.1.0" [dev-dependencies.quickcheck] version = "0.8" [dev-dependencies.quickcheck_macros] version = "0.8.0" [dev-dependencies.rand] version = "0.7.2" [dev-dependencies.rkyv] version = "0.7.18" features = ["validation"] [dev-dependencies.serde_cbor] version = "0.11.1" [dev-dependencies.testdrop] version = "0.1.2" [features] default = [] new_unchecked = [] rkyv_validated = [ "rkyv", "bytecheck", ] range-collections-0.4.5/Cargo.toml.orig000064400000000000000000000022121046102023000161260ustar 00000000000000[package] name = "range-collections" version = "0.4.5" authors = ["Rüdiger Klaehn "] description = "Sets and maps of ranges, backed by smallvec" repository = "https://github.com/rklaehn/range-collections" license = "MIT OR Apache-2.0" keywords = ["succinct", "array", "range", "smallvec"] categories = ["data-structures"] edition = "2018" readme = "README.md" homepage = "https://github.com/rklaehn" [dependencies] smallvec = "1.0" inplace-vec-builder = { version = "0.1.0", features = ["smallvec"], default-features = false } binary-merge = "0.1.1" serde = { version = "1", optional = true, default-features = false } rkyv = { version = "0.7.18", optional = true } bytecheck = { version = "0.6.5", optional = true } ref-cast = "1.0.20" [features] default = [] rkyv_validated = ["rkyv", "bytecheck"] new_unchecked = [] [dev-dependencies] quickcheck = "0.8" quickcheck_macros = "0.8.0" testdrop = "0.1.2" criterion = "0.3.0" rand = "0.7.2" serde_cbor = "0.11.1" rkyv = { version = "0.7.18", features = ["validation"] } hex = "0.4.3" num-traits = "0.2.8" obey = "0.1.1" proptest = "1.1.0" [[bench]] name = "range_set" harness = false range-collections-0.4.5/LICENSE-APACHE2.md000064400000000000000000000261351046102023000156560ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. range-collections-0.4.5/LICENSE-MIT.md000064400000000000000000000020601046102023000152730ustar 00000000000000MIT License Copyright (c) 2019 Rüdiger Klaehn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. range-collections-0.4.5/README.md000064400000000000000000000011131046102023000145150ustar 00000000000000 # Range-collections   [![Build Status]][status] [![Latest Version]][crates.io] [![Docs Badge]][docs.rs] [Build Status]: https://github.com/rklaehn/range-collections/actions/workflows/rust.yml/badge.svg [status]: https://github.com/rklaehn/range-collections/actions/workflows/rust.yml [Latest Version]: https://img.shields.io/crates/v/range-collections.svg [crates.io]: https://crates.io/crates/range-collections [Docs Badge]: https://img.shields.io/badge/docs-docs.rs-green [docs.rs]: https://docs.rs/range-collections # About See the [docs](https://docs.rs/range-collections). range-collections-0.4.5/benches/range_set.rs000064400000000000000000000056521046102023000171760ustar 00000000000000use core::ops::Range; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use rand::prelude::*; use range_collections::{RangeSet, RangeSet2}; type Elem = i32; fn create_messages(n: usize, delay: usize) -> Vec> { let mut rng = rand::rngs::StdRng::seed_from_u64(0); let mut msgs: Vec> = Vec::new(); let mut offset = 0; // create some random sized messages for _ in 0..n { let len = rng.gen::() % 10 + 1; msgs.push(Range { start: offset, end: offset + len, }); offset += len; } // "delay" some of them by randomly swapping with the successor for _ in 0..delay { for i in 1..msgs.len() { if rng.gen::() { msgs.swap(i - 1, i); } } } msgs } fn union_new(a: &RangeSet2, b: &RangeSet2) -> RangeSet2 { a | b } fn intersection_new(a: &RangeSet2, b: &RangeSet2) -> RangeSet2 { a & b } fn intersects_new(a: &RangeSet2, b: &RangeSet2) -> bool { !a.is_disjoint(b) } fn make_on_off_profile(n: Elem, offset: Elem, stride: Elem) -> RangeSet2 { let mut res = RangeSet::empty(); for i in 0..n { res ^= RangeSet::from((i * stride + offset)..); } res } pub fn interleaved(c: &mut Criterion) { let n = 100000; let a: RangeSet2 = make_on_off_profile(n, 0, 2); let b: RangeSet2 = make_on_off_profile(n, 1, 2); c.bench_function("union_interleaved_new", |bencher| { bencher.iter(|| union_new(black_box(&a), black_box(&b))) }); c.bench_function("intersection_interleaved_new", |bencher| { bencher.iter(|| intersection_new(black_box(&a), black_box(&b))) }); c.bench_function("intersects_interleaved_new", |bencher| { bencher.iter(|| intersects_new(black_box(&a), black_box(&b))) }); } pub fn cutoff(c: &mut Criterion) { let n = 100000; let a: RangeSet2 = make_on_off_profile(n, 0, 2); let b: RangeSet2 = make_on_off_profile(n, 1, 1000); c.bench_function("union_cutoff_new", |bencher| { bencher.iter(|| union_new(black_box(&a), black_box(&b))) }); c.bench_function("intersection_cutoff_new", |bencher| { bencher.iter(|| intersection_new(black_box(&a), black_box(&b))) }); c.bench_function("intersects_cutoff_new", |bencher| { bencher.iter(|| intersects_new(black_box(&a), black_box(&b))) }); } pub fn assemble(c: &mut Criterion) { let n = 10000; let msgs = create_messages(n, 5); c.bench_function("assemble", |bencher| { bencher.iter(|| { let mut buffer: RangeSet2 = RangeSet::from(..0); for msg in msgs.iter() { buffer |= RangeSet::from(msg.clone()); } buffer }); }); } criterion_group!(benches, interleaved, cutoff, assemble); criterion_main!(benches); range-collections-0.4.5/examples/recv_buffer.rs000064400000000000000000000033441046102023000177220ustar 00000000000000use rand::prelude::*; use range_collections::{range_set::RangeSet2, RangeSet}; use std::ops::{Bound, Range, RangeBounds}; fn create_messages(n: usize, delay: usize) -> Vec> { let mut rng = rand::rngs::StdRng::seed_from_u64(0); let mut msgs: Vec> = Vec::new(); let mut offset = 0; // create some random sized messages for _ in 0..n { let len = rng.gen::() % 10 + 1; msgs.push(Range { start: offset, end: offset + len, }); offset += len; } // "delay" some of them by randomly swapping with the successor for _ in 0..delay { for i in 1..msgs.len() { if rng.gen::() { msgs.swap(i - 1, i); } } } msgs } fn test(msgs: &[Range]) -> RangeSet2 { let mut buffer: RangeSet2 = RangeSet::from(..0); for msg in msgs.iter().cloned() { buffer |= RangeSet::from(msg); } buffer } fn main() { let msgs = create_messages(1000000, 5); // do it a few times for a nice flamegraph for _ in 0..100 { test(&msgs); } let mut buffer: RangeSet2 = RangeSet::from(..0); for (i, msg) in msgs.into_iter().enumerate() { buffer |= RangeSet::from(msg); if (i % 1000) == 0 { if let Some(r) = buffer.iter().next() { if let Bound::Excluded(end) = r.end_bound() { let end = **end; println!( "After {} msgs, the last contiguous sequence number is {:?}", i, end - 1 ); } } } } println!("{:?}", buffer); } range-collections-0.4.5/src/iterators.rs000064400000000000000000000012621046102023000164140ustar 00000000000000pub(crate) struct SliceIterator<'a, T>(pub &'a [T]); impl<'a, T> Iterator for SliceIterator<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { if self.0.is_empty() { None } else { let res: Self::Item = &self.0[0]; self.0 = &self.0[1..]; Some(res) } } } impl<'a, T> SliceIterator<'a, T> { pub fn as_slice(&self) -> &[T] { self.0 } pub(crate) fn drop_front(&mut self, n: usize) { self.0 = &self.0[n..]; } pub(crate) fn take_front(&mut self, n: usize) -> &'a [T] { let res = &self.0[..n]; self.0 = &self.0[n..]; res } } range-collections-0.4.5/src/lib.rs000064400000000000000000000004541046102023000151500ustar 00000000000000//! A set of non-overlapping ranges, backed by `SmallVec` #[cfg(test)] extern crate quickcheck; #[cfg(test)] #[macro_use(quickcheck)] extern crate quickcheck_macros; #[allow(dead_code)] mod merge_state; mod iterators; pub mod range_set; pub use range_set::{RangeSet, RangeSet2, RangeSetRef}; range-collections-0.4.5/src/merge_state.rs000064400000000000000000000177241046102023000167110ustar 00000000000000use crate::iterators::SliceIterator; use binary_merge::{MergeOperation, MergeState}; use core::fmt::Debug; use inplace_vec_builder::InPlaceSmallVecBuilder; use smallvec::{Array, SmallVec}; /// A typical write part for the merge state pub(crate) trait MergeStateMut: MergeState { // Consume 1 elements from a and b, will copy from a fn advance_both(&mut self, copy: bool) -> bool { self.advance_a(1, copy) && self.advance_b(1, false) } /// Consume n elements of a, and update ac fn advance_a(&mut self, n: usize, take: bool) -> bool; /// Consume n elements of b, and update bc fn advance_b(&mut self, n: usize, take: bool) -> bool; fn ac(&self) -> bool; fn bc(&self) -> bool; } /// An in place merge state where the rhs is an owned smallvec pub(crate) struct InPlaceMergeState<'a, A: Array, B: Array> { a: InPlaceSmallVecBuilder<'a, A>, b: smallvec::IntoIter, ac: bool, bc: bool, } impl<'a, A: Array, B: Array> InPlaceMergeState<'a, A, B> { pub fn new(a: &'a mut SmallVec, b: SmallVec) -> Self { Self { a: a.into(), b: b.into_iter(), ac: false, bc: false, } } } impl<'a, A: Array, B: Array> MergeState for InPlaceMergeState<'a, A, B> { type A = A::Item; type B = B::Item; fn a_slice(&self) -> &[A::Item] { self.a.source_slice() } fn b_slice(&self) -> &[B::Item] { self.b.as_slice() } } impl<'a, A: Array> MergeStateMut for InPlaceMergeState<'a, A, A> { #[inline] fn advance_a(&mut self, n: usize, take: bool) -> bool { self.ac ^= is_odd(n); self.a.consume(n, take); true } #[inline] fn advance_b(&mut self, n: usize, take: bool) -> bool { self.bc ^= is_odd(n); if take { self.a.extend_from_iter(&mut self.b, n); } else { for _ in 0..n { let _ = self.b.next(); } } true } fn ac(&self) -> bool { self.ac } fn bc(&self) -> bool { self.bc } } impl<'a, A: Array, B: Array> InPlaceMergeState<'a, A, B> { pub fn merge>(a: &'a mut SmallVec, b: SmallVec, o: O) { let mut state = Self::new(a, b); o.merge(&mut state); } } /// An in place merge state where the rhs is a reference pub(crate) struct InPlaceMergeStateRef<'a, A: Array, B> { a: InPlaceSmallVecBuilder<'a, A>, b: SliceIterator<'a, B>, ac: bool, bc: bool, } impl<'a, A: Array, B> InPlaceMergeStateRef<'a, A, B> { pub fn new(a: &'a mut SmallVec, b: &'a impl AsRef<[B]>) -> Self { Self { a: a.into(), b: SliceIterator(b.as_ref()), ac: false, bc: false, } } } impl<'a, A: Array, B> MergeState for InPlaceMergeStateRef<'a, A, B> { type A = A::Item; type B = B; fn a_slice(&self) -> &[A::Item] { self.a.source_slice() } fn b_slice(&self) -> &[B] { self.b.as_slice() } } impl<'a, A: Array> MergeStateMut for InPlaceMergeStateRef<'a, A, A::Item> where A::Item: Clone, { #[inline] fn advance_a(&mut self, n: usize, take: bool) -> bool { self.ac ^= is_odd(n); self.a.consume(n, take); true } #[inline] fn advance_b(&mut self, n: usize, take: bool) -> bool { self.bc ^= is_odd(n); if take { self.a.extend_from_iter((&mut self.b).cloned(), n); } else { for _ in 0..n { let _ = self.b.next(); } } true } fn ac(&self) -> bool { self.ac } fn bc(&self) -> bool { self.bc } } impl<'a, A: Array, B: 'a> InPlaceMergeStateRef<'a, A, B> { pub fn merge>(a: &'a mut SmallVec, b: &'a impl AsRef<[B]>, o: O) { let mut state = Self::new(a, b); o.merge(&mut state); } } /// A merge state where we only track if elements have been produced, and abort as soon as the first element is produced pub(crate) struct BoolOpMergeState<'a, A, B> { a: SliceIterator<'a, A>, b: SliceIterator<'a, B>, ac: bool, bc: bool, r: bool, } impl<'a, A: Debug, B: Debug> Debug for BoolOpMergeState<'a, A, B> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "a: {:?}, b: {:?} r: {}", self.a_slice(), self.b_slice(), self.r ) } } impl<'a, A, B> BoolOpMergeState<'a, A, B> { pub fn new(a: &'a [A], b: &'a [B]) -> Self { Self { a: SliceIterator(a), b: SliceIterator(b), ac: false, bc: false, r: false, } } pub fn result(self) -> bool { self.r } } impl<'a, A, B> BoolOpMergeState<'a, A, B> { pub fn merge>(a: &'a [A], b: &'a [B], o: O) -> bool { let mut state = Self::new(a, b); o.merge(&mut state); state.r } } impl<'a, A, B> MergeState for BoolOpMergeState<'a, A, B> { type A = A; type B = B; fn a_slice(&self) -> &[A] { self.a.as_slice() } fn b_slice(&self) -> &[B] { self.b.as_slice() } } impl<'a, A, B> MergeStateMut for BoolOpMergeState<'a, A, B> { fn advance_a(&mut self, n: usize, take: bool) -> bool { self.ac ^= is_odd(n); if take { self.r = true; false } else { self.a.drop_front(n); true } } fn advance_b(&mut self, n: usize, take: bool) -> bool { self.bc ^= is_odd(n); if take { self.r = true; false } else { self.b.drop_front(n); true } } fn ac(&self) -> bool { self.ac } fn bc(&self) -> bool { self.bc } } /// A merge state where we build into a new vector pub(crate) struct SmallVecMergeState<'a, A, B, Arr: Array> { a: SliceIterator<'a, A>, b: SliceIterator<'a, B>, ac: bool, bc: bool, r: SmallVec, } impl<'a, A: Debug, B: Debug, Arr: Array> Debug for SmallVecMergeState<'a, A, B, Arr> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "a: {:?}, b: {:?}", self.a_slice(), self.b_slice(),) } } impl<'a, A, B, Arr: Array> SmallVecMergeState<'a, A, B, Arr> { pub fn new(a: &'a [A], b: &'a [B], r: SmallVec) -> Self { Self { a: SliceIterator(a), b: SliceIterator(b), ac: false, bc: false, r, } } pub fn result(self) -> SmallVec { self.r } pub fn merge>(a: &'a [A], b: &'a [B], o: O) -> SmallVec { let t: SmallVec = SmallVec::new(); let mut state = Self::new(a, b, t); o.merge(&mut state); state.result() } } impl<'a, A, B, Arr: Array> MergeState for SmallVecMergeState<'a, A, B, Arr> { type A = A; type B = B; fn a_slice(&self) -> &[A] { self.a.as_slice() } fn b_slice(&self) -> &[B] { self.b.as_slice() } } impl<'a, T: Clone, Arr: Array> MergeStateMut for SmallVecMergeState<'a, T, T, Arr> { fn advance_a(&mut self, n: usize, take: bool) -> bool { self.ac ^= is_odd(n); if take { self.r.reserve(n); for e in self.a.take_front(n).iter() { self.r.push(e.clone()) } } else { self.a.drop_front(n); } true } fn advance_b(&mut self, n: usize, take: bool) -> bool { self.bc ^= is_odd(n); if take { self.r.reserve(n); for e in self.b.take_front(n).iter() { self.r.push(e.clone()) } } else { self.b.drop_front(n); } true } fn ac(&self) -> bool { self.ac } fn bc(&self) -> bool { self.bc } } #[inline] fn is_odd(x: usize) -> bool { (x & 1) != 0 } range-collections-0.4.5/src/range_set.rs000064400000000000000000001344541046102023000163610ustar 00000000000000#![deny(missing_docs)] //! A set of non-overlapping ranges use crate::merge_state::{ BoolOpMergeState, InPlaceMergeState, InPlaceMergeStateRef, MergeStateMut, SmallVecMergeState, }; use binary_merge::{MergeOperation, MergeState}; use core::cmp::Ordering; use core::fmt::Debug; use core::ops::{ BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Bound, Not, Range, RangeFrom, RangeTo, Sub, SubAssign, }; use ref_cast::{ref_cast_custom, RefCastCustom}; use smallvec::{Array, SmallVec}; use std::borrow::Borrow; use std::num::*; use std::ops::{Deref, RangeBounds, RangeFull}; #[cfg(feature = "serde")] use { core::{fmt, marker::PhantomData}, serde::{ de::{Deserialize, Deserializer, SeqAccess, Visitor}, ser::{Serialize, SerializeSeq, Serializer}, }, }; /// # A set of non-overlapping ranges /// /// ``` /// # use range_collections::{RangeSet, RangeSet2}; /// let mut a: RangeSet2 = RangeSet::from(10..); /// let b: RangeSet2 = RangeSet::from(1..5); /// /// a |= b; /// let r = !a; /// ``` /// /// A data structure to represent a set of non-overlapping ranges of element type `T: RangeSetEntry`. It uses a `SmallVec` /// of sorted boundaries internally. /// /// It can represent not just finite ranges but also ranges with unbounded end. Because it can represent /// infinite ranges, it can also represent the set of all elements, and therefore all boolean operations including negation. /// /// Adjacent ranges will be merged. /// /// It provides very fast operations for set operations (&, |, ^) as well as for intersection tests (is_disjoint, is_subset). /// /// In addition to the fast set operations that produce a new range set, it also supports the equivalent in-place operations. /// /// # Complexity /// /// Complexity is given separately for the number of comparisons and the number of copies, since sometimes you have /// a comparison operation that is basically free (any of the primitive types), whereas sometimes you have a comparison /// operation that is many orders of magnitude more expensive than a copy (long strings, arbitrary precision integers, ...) /// /// ## Number of comparisons /// /// |operation | best | worst | remark /// |-------------|-----------|-----------|-------- /// |negation | 1       | O(N)     | /// |union | O(log(N)) | O(N) | binary merge /// |intersection | O(log(N)) | O(N) | binary merge /// |difference | O(log(N)) | O(N) | binary merge /// |xor | O(log(N)) | O(N) | binary merge /// |membership | O(log(N)) | O(log(N)) | binary search /// |is_disjoint | O(log(N)) | O(N) | binary merge with cutoff /// |is_subset | O(log(N)) | O(N) | binary merge with cutoff /// /// ## Number of copies /// /// For creating new sets, obviously there needs to be at least one copy for each element of the result set, so the /// complexity is always O(N). For in-place operations it gets more interesting. In case the number of elements of /// the result being identical to the number of existing elements, there will be no copies and no allocations. /// /// E.g. if the result just has some of the ranges of the left hand side extended or truncated, but the same number of boundaries, /// there will be no allocations and no copies except for the changed boundaries themselves. /// /// If the result has fewer boundaries than then lhs, there will be some copying but no allocations. Only if the result /// is larger than the capacity of the underlying vector of the lhs will there be allocations. /// /// |operation | best | worst | /// |-------------|-----------|-----------| /// |negation | 1       | 1        | /// |union | 1 | O(N) | /// |intersection | 1 | O(N) | /// |difference | 1 | O(N) | /// |xor | 1 | O(N) | /// /// # Testing /// /// Testing is done by some simple smoke tests as well as quickcheck tests of the algebraic properties of the boolean operations. pub struct RangeSet(SmallVec); impl> Deref for RangeSet { type Target = RangeSetRef; fn deref(&self) -> &Self::Target { RangeSetRef::new_unchecked_impl(&self.0) } } impl> AsRef> for RangeSet { fn as_ref(&self) -> &RangeSetRef { RangeSetRef::new_unchecked_impl(&self.0) } } impl> Borrow> for RangeSet { fn borrow(&self) -> &RangeSetRef { RangeSetRef::new_unchecked_impl(&self.0) } } /// Range that can be part of a range set /// /// Start boundaries are always inclusive, end boundaries are exclusive. /// Therefore some ranges types are not going to appear in a range set. #[derive(Clone)] pub enum RangeSetRange { /// Closed range Range(Range), /// Range with unbounded end RangeFrom(RangeFrom), } impl RangeSetRange<&T> { /// Maps a `RangeSetRange<&T>` to a `RangeSetRange` by cloning start and end. pub fn cloned(&self) -> RangeSetRange { match self { RangeSetRange::Range(r) => RangeSetRange::Range(r.start.clone()..r.end.clone()), RangeSetRange::RangeFrom(r) => RangeSetRange::RangeFrom(r.start.clone()..), } } } impl From> for RangeSetRange { fn from(r: Range) -> Self { RangeSetRange::Range(r) } } impl From> for RangeSetRange { fn from(r: RangeFrom) -> Self { RangeSetRange::RangeFrom(r) } } impl> From> for RangeSet { fn from(value: RangeSetRange) -> Self { match value { RangeSetRange::Range(r) => RangeSet::from(r), RangeSetRange::RangeFrom(r) => RangeSet::from(r), } } } impl Debug for RangeSetRange { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RangeSetRange::Range(r) => r.fmt(f), RangeSetRange::RangeFrom(r) => r.fmt(f), } } } impl RangeBounds for RangeSetRange { fn start_bound(&self) -> Bound<&T> { match self { RangeSetRange::Range(r) => r.start_bound(), RangeSetRange::RangeFrom(r) => r.start_bound(), } } fn end_bound(&self) -> Bound<&T> { match self { RangeSetRange::Range(r) => r.end_bound(), RangeSetRange::RangeFrom(r) => r.end_bound(), } } } impl Clone for RangeSet where A::Item: Clone, { fn clone(&self) -> Self { Self(self.0.clone()) } } impl>> PartialEq for RangeSet where A::Item: RangeSetEntry, { fn eq(&self, that: &R) -> bool { self.boundaries() == that.as_ref().boundaries() } } impl Eq for RangeSet where A::Item: Eq + RangeSetEntry {} /// A range set that stores up to 2 boundaries inline pub type RangeSet2 = RangeSet<[T; 2]>; impl> Debug for RangeSet { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "RangeSet{{")?; for (i, r) in self.iter().enumerate() { if i > 0 { write!(f, ", ")?; } write!(f, "{r:?}")?; } write!(f, "}}") } } /// Iterator for the ranges in a range set pub struct Iter<'a, T>(&'a [T]); impl<'a, T> Iterator for Iter<'a, T> { type Item = RangeSetRange<&'a T>; fn next(&mut self) -> Option { let bounds = self.0; if !bounds.is_empty() { Some(if bounds.len() == 1 { self.0 = &bounds[1..]; RangeSetRange::from(&bounds[0]..) } else { self.0 = &bounds[2..]; RangeSetRange::from(&bounds[0]..&bounds[1]) }) } else { None } } } /// A reference to a range set #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, RefCastCustom)] #[repr(transparent)] pub struct RangeSetRef([T]); impl RangeSetRef { /// Create a new range set reference for an empty range set pub const fn empty() -> &'static Self { RangeSetRef::new_unchecked_impl(&[]) } /// Create a new range set reference for a single value pub const fn single(value: &T) -> &Self { RangeSetRef::new_unchecked_impl(std::slice::from_ref(value)) } /// Create a new range set reference /// /// This performs a check that the boundaries are strictly sorted. /// If you want to avoid this check, use `new_unchecked` /// (behind a feature flag because it is unsafe) pub fn new(boundaries: &[T]) -> Option<&Self> where T: Ord, { if is_strictly_sorted(boundaries) { Some(Self::new_unchecked_impl(boundaries)) } else { None } } /// Split this range set into two parts `left`, `right` at position `at`, /// so that `left` is identical to `self` for all `x < at` /// and `right` is identical to `self` for all `x >= at`. /// /// More precisely: /// contains(left, x) == contains(ranges, x) for x < at /// contains(right, x) == contains(ranges, x) for x >= at /// /// This is not the same as limiting the ranges to the left or right of /// `at`, but it is much faster. It requires just a binary search and no /// allocations. pub fn split(&self, at: T) -> (&Self, &Self) where T: Ord, { let (left, right) = split(&self.0, at); ( Self::new_unchecked_impl(left), Self::new_unchecked_impl(right), ) } /// Create a new range set reference without checking that the boundaries are /// strictly sorted. #[cfg(feature = "new_unchecked")] pub const fn new_unchecked(boundaries: &[T]) -> &Self { Self::new_unchecked_impl(boundaries) } #[ref_cast_custom] const fn new_unchecked_impl(boundaries: &[T]) -> &Self; /// The boundaries of the range set, guaranteed to be strictly sorted pub const fn boundaries(&self) -> &[T] { &self.0 } /// true if the value is contained in the range set pub fn contains(&self, value: &T) -> bool where T: Ord, { match self.boundaries().binary_search(value) { Ok(index) => !is_odd(index), Err(index) => is_odd(index), } } /// true if the range set is empty pub const fn is_empty(&self) -> bool { self.boundaries().is_empty() } /// true if the range set contains all values pub fn is_all(&self) -> bool where T: RangeSetEntry, { self.boundaries().len() == 1 && self.boundaries()[0].is_min_value() } /// true if this range set intersects from another range set /// /// This is just the opposite of `is_disjoint`, but is provided for /// better discoverability. pub fn intersects(&self, that: &RangeSetRef) -> bool where T: Ord, { !self.is_disjoint(that) } /// true if this range set is disjoint from another range set pub fn is_disjoint(&self, that: &RangeSetRef) -> bool where T: Ord, { !RangeSetBoolOpMergeState::merge(self.boundaries(), that.boundaries(), IntersectionOp::<0>) } /// true if this range set is a superset of another range set /// /// A range set is considered to be a superset of itself pub fn is_subset(&self, that: &RangeSetRef) -> bool where T: Ord, { !RangeSetBoolOpMergeState::merge(self.boundaries(), that.boundaries(), DiffOp::<0>) } /// true if this range set is a subset of another range set /// /// A range set is considered to be a subset of itself pub fn is_superset(&self, that: &RangeSetRef) -> bool where T: Ord, { !RangeSetBoolOpMergeState::merge(that.boundaries(), self.boundaries(), DiffOp::<0>) } /// iterate over all ranges in this range set pub fn iter(&self) -> Iter { Iter(self.boundaries()) } /// intersection pub fn intersection(&self, that: &RangeSetRef) -> RangeSet where A: Array, T: Ord + Clone, { RangeSet::new_unchecked_impl(VecMergeState::merge( self.boundaries(), that.boundaries(), IntersectionOp::<{ usize::MAX }>, )) } /// union pub fn union(&self, that: &RangeSetRef) -> RangeSet where A: Array, T: Ord + Clone, { RangeSet::new_unchecked_impl(VecMergeState::merge( self.boundaries(), that.boundaries(), UnionOp, )) } /// difference pub fn difference(&self, that: &RangeSetRef) -> RangeSet where A: Array, T: Ord + Clone, { RangeSet::new_unchecked_impl(VecMergeState::merge( self.boundaries(), that.boundaries(), DiffOp::<{ usize::MAX }>, )) } /// symmetric difference (xor) pub fn symmetric_difference(&self, that: &RangeSetRef) -> RangeSet where A: Array, T: Ord + Clone, { RangeSet::new_unchecked_impl(VecMergeState::merge( self.boundaries(), that.boundaries(), XorOp, )) } } #[cfg(feature = "rkyv")] impl Deref for ArchivedRangeSet { type Target = RangeSetRef; fn deref(&self) -> &Self::Target { RangeSetRef::new_unchecked(&self.0) } } #[cfg(feature = "rkyv")] impl AsRef> for ArchivedRangeSet { fn as_ref(&self) -> &RangeSetRef { RangeSetRef::new_unchecked(&self.0) } } #[cfg(feature = "rkyv")] impl Borrow> for ArchivedRangeSet { fn borrow(&self) -> &RangeSetRef { RangeSetRef::new_unchecked(&self.0) } } /// trait for types that can be entries of range sets /// /// they must have an order and a minimum value. pub trait RangeSetEntry: Ord { /// the minimum value for this type fn min_value() -> Self; /// checks if this is the minimum value /// /// this is to be able to check for minimum without having to create a value fn is_min_value(&self) -> bool; } macro_rules! entry_instance { ($t:tt) => { impl RangeSetEntry for $t { fn min_value() -> Self { $t::MIN } fn is_min_value(&self) -> bool { *self == $t::MIN } } }; ($t:tt, $($rest:tt),+) => { entry_instance!($t); entry_instance!($( $rest ),*); } } macro_rules! non_zero_u_entry_instance { ($t:tt) => { impl RangeSetEntry for $t { fn min_value() -> Self { $t::new(1).unwrap() } fn is_min_value(&self) -> bool { *self == $t::new(1).unwrap() } } }; ($t:tt, $($rest:tt),+) => { non_zero_u_entry_instance!($t); non_zero_u_entry_instance!($( $rest ),*); } } entry_instance!(u8, u16, u32, u64, u128, usize); entry_instance!(i8, i16, i32, i64, i128, isize); non_zero_u_entry_instance!( NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize ); impl RangeSetEntry for Option { fn min_value() -> Self { None } fn is_min_value(&self) -> bool { self.is_none() } } impl RangeSetEntry for String { fn min_value() -> Self { "".to_owned() } fn is_min_value(&self) -> bool { self.is_empty() } } impl RangeSetEntry for &str { fn min_value() -> Self { "" } fn is_min_value(&self) -> bool { self.is_empty() } } impl RangeSetEntry for Vec { fn min_value() -> Self { Vec::new() } fn is_min_value(&self) -> bool { self.is_empty() } } impl RangeSetEntry for &[T] { fn min_value() -> Self { &[] } fn is_min_value(&self) -> bool { self.is_empty() } } impl> RangeSet { /// create a new range set from the given boundaries /// /// This performs a check that the boundaries are strictly sorted. /// If you want to avoid this check, use `new_unchecked` /// (behind a feature flag because it is unsafe) pub fn new(boundaries: SmallVec) -> Option where A::Item: Ord, { if is_strictly_sorted(boundaries.as_ref()) { Some(Self::new_unchecked_impl(boundaries)) } else { None } } /// Create a new range set reference without checking that the boundaries are /// strictly sorted. #[cfg(feature = "new_unchecked")] pub fn new_unchecked(boundaries: SmallVec) -> Self { Self::new_unchecked_impl(boundaries) } /// note that this is private since it does not check the invariants! fn new_unchecked_impl(boundaries: SmallVec) -> Self { RangeSet(boundaries) } /// iterate over all ranges in this range set pub fn iter(&self) -> Iter { Iter(self.0.as_ref()) } /// get the boundaries in this range set as a SmallVec pub fn into_inner(self) -> SmallVec { self.0 } } impl> RangeSet { fn from_range_until(a: T) -> Self { let mut t = SmallVec::new(); if !a.is_min_value() { t.push(T::min_value()); t.push(a); } Self::new_unchecked_impl(t) } fn from_range_from(a: T) -> Self { let mut t = SmallVec::new(); t.push(a); Self::new_unchecked_impl(t) } /// the empty range set pub fn empty() -> Self { Self(SmallVec::new()) } /// a range set containing all values pub fn all() -> Self { Self::from_range_from(T::min_value()) } } impl> RangeSet { /// intersection in place pub fn intersection_with(&mut self, that: &RangeSetRef) { InPlaceMergeStateRef::merge( &mut self.0, &that.boundaries(), IntersectionOp::<{ usize::MAX }>, ); } /// union in place pub fn union_with(&mut self, that: &RangeSetRef) { InPlaceMergeStateRef::merge(&mut self.0, &that.boundaries(), UnionOp); } /// difference in place pub fn difference_with(&mut self, that: &RangeSetRef) { InPlaceMergeStateRef::merge(&mut self.0, &that.boundaries(), DiffOp::<{ usize::MAX }>); } /// symmetric difference in place (xor) pub fn symmetric_difference_with(&mut self, that: &RangeSetRef) { InPlaceMergeStateRef::merge(&mut self.0, &that.boundaries(), XorOp); } } impl> From for RangeSet { fn from(value: bool) -> Self { if value { Self::all() } else { Self::empty() } } } impl> RangeSet { fn from_range(a: Range) -> Self { if a.start < a.end { let mut t = SmallVec::new(); t.push(a.start); t.push(a.end); Self::new_unchecked_impl(t) } else { Self::empty() } } } impl> From> for RangeSet { fn from(value: Range) -> Self { Self::from_range(value) } } impl> From> for RangeSet { fn from(value: RangeFrom) -> Self { Self::from_range_from(value.start) } } impl> From> for RangeSet { fn from(value: RangeTo) -> Self { Self::from_range_until(value.end) } } impl> From for RangeSet { fn from(_: RangeFull) -> Self { Self::all() } } /// compute the intersection of this range set with another, producing a new range set /// /// ∀ t ∈ T, r(t) = a(t) & b(t) impl> BitAnd> for RangeSet { type Output = RangeSet; fn bitand(self, that: RangeSet) -> Self::Output { self.intersection(&that) } } impl> BitAnd<&RangeSet> for RangeSet { type Output = RangeSet; fn bitand(self, that: &RangeSet) -> Self::Output { self.intersection(that) } } impl> BitAnd> for &RangeSet { type Output = RangeSet; fn bitand(self, that: RangeSet) -> Self::Output { self.intersection(&that) } } impl> BitAnd<&RangeSet> for &RangeSet { type Output = RangeSet; fn bitand(self, that: &RangeSet) -> Self::Output { self.intersection(that) } } impl> BitAndAssign for RangeSet { fn bitand_assign(&mut self, that: Self) { InPlaceMergeState::merge(&mut self.0, that.0, IntersectionOp::<{ usize::MAX }>); } } /// compute the union of this range set with another, producing a new range set /// /// ∀ t ∈ T, r(t) = a(t) | b(t) impl> BitOr> for RangeSet { type Output = RangeSet; fn bitor(self, that: RangeSet) -> Self::Output { self.union(&that) } } impl> BitOr<&RangeSet> for RangeSet { type Output = RangeSet; fn bitor(self, that: &RangeSet) -> Self::Output { self.union(that) } } impl> BitOr> for &RangeSet { type Output = RangeSet; fn bitor(self, that: RangeSet) -> Self::Output { self.union(&that) } } impl> BitOr<&RangeSet> for &RangeSet { type Output = RangeSet; fn bitor(self, that: &RangeSet) -> Self::Output { self.union(that) } } impl> BitOrAssign for RangeSet { fn bitor_assign(&mut self, that: Self) { InPlaceMergeState::merge(&mut self.0, that.0, UnionOp); } } /// compute the exclusive or of this range set with another, producing a new range set /// /// ∀ t ∈ T, r(t) = a(t) ^ b(t) impl> BitXor> for RangeSet { type Output = RangeSet; fn bitxor(self, that: RangeSet) -> Self::Output { self.symmetric_difference(&that) } } impl> BitXor<&RangeSet> for RangeSet { type Output = RangeSet; fn bitxor(self, that: &RangeSet) -> Self::Output { self.symmetric_difference(that) } } impl> BitXor> for &RangeSet { type Output = RangeSet; fn bitxor(self, that: RangeSet) -> Self::Output { self.symmetric_difference(&that) } } impl> BitXor<&RangeSet> for &RangeSet { type Output = RangeSet; fn bitxor(self, that: &RangeSet) -> Self::Output { self.symmetric_difference(that) } } impl> BitXorAssign for RangeSet { fn bitxor_assign(&mut self, that: Self) { InPlaceMergeState::merge(&mut self.0, that.0, XorOp); } } /// compute the difference of this range set with another, producing a new range set /// /// ∀ t ∈ T, r(t) = a(t) & !b(t) impl> Sub> for RangeSet { type Output = RangeSet; fn sub(self, that: RangeSet) -> Self::Output { self.difference(&that) } } impl> Sub<&RangeSet> for RangeSet { type Output = RangeSet; fn sub(self, that: &RangeSet) -> Self::Output { self.difference(that) } } impl> Sub> for &RangeSet { type Output = RangeSet; fn sub(self, that: RangeSet) -> Self::Output { self.difference(&that) } } impl> Sub<&RangeSet> for &RangeSet { type Output = RangeSet; fn sub(self, that: &RangeSet) -> Self::Output { self.difference(that) } } impl> SubAssign for RangeSet { fn sub_assign(&mut self, that: Self) { InPlaceMergeState::merge(&mut self.0, that.0, DiffOp::<{ usize::MAX }>); } } /// compute the negation of this range set /// /// ∀ t ∈ T, r(t) = !a(t) impl> Not for RangeSet { type Output = RangeSet; fn not(mut self) -> Self::Output { match self.0.get(0) { Some(x) if x.is_min_value() => { self.0.remove(0); } _ => { self.0.insert(0, T::min_value()); } } self } } /// compute the negation of this range set /// /// ∀ t ∈ T, r(t) = !a(t) impl> Not for &RangeSet { type Output = RangeSet; fn not(self) -> Self::Output { self ^ &RangeSet::all() } } struct RangeSetBoolOpMergeState<'a, T> { inner: BoolOpMergeState<'a, T, T>, } impl<'a, T> RangeSetBoolOpMergeState<'a, T> { fn merge>(a: &'a [T], b: &'a [T], o: O) -> bool { let mut state = Self { inner: BoolOpMergeState::new(a, b), }; o.merge(&mut state); state.inner.result() } } impl<'a, T> MergeStateMut for RangeSetBoolOpMergeState<'a, T> { fn advance_a(&mut self, n: usize, copy: bool) -> bool { self.inner.advance_a(n, copy) } fn advance_b(&mut self, n: usize, copy: bool) -> bool { self.inner.advance_b(n, copy) } fn ac(&self) -> bool { self.inner.ac() } fn bc(&self) -> bool { self.inner.bc() } } impl<'a, T> MergeState for RangeSetBoolOpMergeState<'a, T> { type A = T; type B = T; fn a_slice(&self) -> &[T] { self.inner.a_slice() } fn b_slice(&self) -> &[T] { self.inner.b_slice() } } struct VecMergeState<'a, T, A: Array> { inner: SmallVecMergeState<'a, T, T, A>, } impl<'a, T: Clone, A: Array> VecMergeState<'a, T, A> { fn merge>(a: &'a [T], b: &'a [T], o: O) -> SmallVec { let mut state = Self { inner: SmallVecMergeState::new(a, b, SmallVec::new()), }; o.merge(&mut state); state.inner.result() } } impl<'a, T: Clone, A: Array> MergeStateMut for VecMergeState<'a, T, A> { fn advance_a(&mut self, n: usize, copy: bool) -> bool { self.inner.advance_a(n, copy) } fn advance_b(&mut self, n: usize, copy: bool) -> bool { self.inner.advance_b(n, copy) } fn ac(&self) -> bool { self.inner.ac() } fn bc(&self) -> bool { self.inner.bc() } } impl<'a, T, A: Array> MergeState for VecMergeState<'a, T, A> { type A = T; type B = T; fn a_slice(&self) -> &[T] { self.inner.a_slice() } fn b_slice(&self) -> &[T] { self.inner.b_slice() } } #[cfg(feature = "serde")] impl> Serialize for RangeSet { fn serialize(&self, serializer: S) -> Result { let mut map = serializer.serialize_seq(Some(self.0.len()))?; for x in self.0.iter() { map.serialize_element(x)?; } map.end() } } #[cfg(feature = "serde")] impl<'de, T: Deserialize<'de> + Ord, A: Array> Deserialize<'de> for RangeSet { fn deserialize>(deserializer: D) -> Result { deserializer.deserialize_seq(RangeSetVisitor { phantom: PhantomData, }) } } #[cfg(feature = "serde")] struct RangeSetVisitor { phantom: PhantomData<(T, A)>, } #[cfg(feature = "serde")] impl<'de, T, A: Array> Visitor<'de> for RangeSetVisitor where T: Deserialize<'de> + Ord, { type Value = RangeSet; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a sequence") } fn visit_seq(self, mut seq: B) -> Result where B: SeqAccess<'de>, { let len = seq.size_hint().unwrap_or(0); let mut boundaries: SmallVec = SmallVec::with_capacity(len); while let Some(value) = seq.next_element::()? { boundaries.push(value); } boundaries.sort(); boundaries.dedup(); Ok(RangeSet(boundaries)) } } #[cfg(feature = "rkyv")] impl rkyv::Archive for RangeSet where T: rkyv::Archive, A: Array, { type Archived = ArchivedRangeSet<::Archived>; type Resolver = rkyv::vec::VecResolver; unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { rkyv::vec::ArchivedVec::resolve_from_slice( self.0.as_slice(), pos, resolver, &mut (*out).0 as *mut rkyv::vec::ArchivedVec<::Archived>, ); } } #[cfg(feature = "rkyv")] impl rkyv::Serialize for RangeSet where T: rkyv::Archive + rkyv::Serialize, S: rkyv::ser::ScratchSpace + rkyv::ser::Serializer, A: Array, { fn serialize(&self, serializer: &mut S) -> Result { rkyv::vec::ArchivedVec::serialize_from_slice(self.0.as_ref(), serializer) } } #[cfg(feature = "rkyv")] impl rkyv::Deserialize, D> for ArchivedRangeSet where T: rkyv::Archive, A: Array, D: rkyv::Fallible + ?Sized, [T::Archived]: rkyv::DeserializeUnsized<[T], D>, { fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { // todo: replace this with SmallVec once smallvec support for rkyv lands on crates.io let boundaries: Vec = self.0.deserialize(deserializer)?; Ok(RangeSet(boundaries.into())) } } /// Archived version of a RangeSet #[cfg(feature = "rkyv")] #[repr(transparent)] pub struct ArchivedRangeSet(rkyv::vec::ArchivedVec); #[cfg(feature = "rkyv")] impl Debug for ArchivedRangeSet { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "ArchivedRangeSet{{")?; for (i, r) in self.iter().enumerate() { if i > 0 { write!(f, ", ")?; } write!(f, "{r:?}")?; } write!(f, "}}") } } /// Validation error for a range set #[cfg(feature = "rkyv_validated")] #[derive(Debug)] pub enum ArchivedRangeSetError { /// error with the individual fields of the ArchivedRangeSet, e.g a NonZeroU64 with a value of 0 ValueCheckError, /// boundaries were not properly ordered OrderCheckError, } #[cfg(feature = "rkyv_validated")] impl std::error::Error for ArchivedRangeSetError {} #[cfg(feature = "rkyv_validated")] impl std::fmt::Display for ArchivedRangeSetError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}", self) } } #[cfg(feature = "rkyv_validated")] impl bytecheck::CheckBytes for ArchivedRangeSet where T: Ord, bool: bytecheck::CheckBytes, rkyv::vec::ArchivedVec: bytecheck::CheckBytes, { type Error = ArchivedRangeSetError; unsafe fn check_bytes<'a>( value: *const Self, context: &mut C, ) -> Result<&'a Self, Self::Error> { let boundaries = &(*value).0; rkyv::vec::ArchivedVec::::check_bytes(boundaries, context) .map_err(|_| ArchivedRangeSetError::ValueCheckError)?; if !boundaries .iter() .zip(boundaries.iter().skip(1)) .all(|(a, b)| a < b) { return Err(ArchivedRangeSetError::OrderCheckError); }; Ok(&*value) } } struct UnionOp; struct XorOp; struct IntersectionOp; struct DiffOp; impl> MergeOperation for UnionOp { fn from_a(&self, m: &mut M, n: usize) -> bool { m.advance_a(n, !m.bc()) } fn from_b(&self, m: &mut M, n: usize) -> bool { m.advance_b(n, !m.ac()) } fn collision(&self, m: &mut M) -> bool { m.advance_both(m.ac() == m.bc()) } fn cmp(&self, a: &T, b: &T) -> Ordering { a.cmp(b) } } impl, const X: usize> MergeOperation for IntersectionOp { fn from_a(&self, m: &mut M, n: usize) -> bool { m.advance_a(n, m.bc()) } fn from_b(&self, m: &mut M, n: usize) -> bool { m.advance_b(n, m.ac()) } fn collision(&self, m: &mut M) -> bool { m.advance_both(m.ac() == m.bc()) } fn cmp(&self, a: &T, b: &T) -> Ordering { a.cmp(b) } const MCM_THRESHOLD: usize = X; } impl, const X: usize> MergeOperation for DiffOp { fn from_a(&self, m: &mut M, n: usize) -> bool { m.advance_a(n, !m.bc()) } fn from_b(&self, m: &mut M, n: usize) -> bool { m.advance_b(n, m.ac()) } fn collision(&self, m: &mut M) -> bool { m.advance_both(m.ac() != m.bc()) } fn cmp(&self, a: &T, b: &T) -> Ordering { a.cmp(b) } const MCM_THRESHOLD: usize = X; } impl> MergeOperation for XorOp { fn from_a(&self, m: &mut M, n: usize) -> bool { m.advance_a(n, true) } fn from_b(&self, m: &mut M, n: usize) -> bool { m.advance_b(n, true) } fn collision(&self, m: &mut M) -> bool { m.advance_both(false) } fn cmp(&self, a: &T, b: &T) -> Ordering { a.cmp(b) } } #[inline] fn is_odd(x: usize) -> bool { (x & 1) != 0 } #[inline] fn is_even(x: usize) -> bool { (x & 1) == 0 } fn is_strictly_sorted(ranges: &[T]) -> bool { for i in 0..ranges.len().saturating_sub(1) { if ranges[i] >= ranges[i + 1] { return false; } } true } /// Split a strictly ordered sequence of boundaries `ranges` into two parts /// `left`, `right` at position `at`, so that /// contains(left, x) == contains(ranges, x) for x < at /// contains(right, x) == contains(ranges, x) for x >= at /// /// The returned slices are guaranteed to be minimal. The left slice will contain /// no boundaries after the split point, and the right slice will contain at most /// one boundary before the split point. #[inline] fn split(ranges: &[T], at: T) -> (&[T], &[T]) { let l = ranges.len(); let res = ranges.binary_search(&at); match res { Ok(i) if is_even(i) => { // left will be an even size, so we can just cut it off (&ranges[..i], &ranges[i..]) } Err(i) if is_even(i) => { // right will be an even size, so we can just cut it off (&ranges[..i], &ranges[i..]) } Ok(i) => { // left will be an odd size, so we need to add one if possible // // since i is an odd value, it indicates going to false at the // split point, and we don't need to have it in right. let sp = i.saturating_add(1).min(l); (&ranges[..i], &ranges[sp..]) } Err(i) => { // left will be an odd size, so we add one if possible // // i is an odd value, so right is true at the split point, and // we need to add one value before the split point to right. // hence the saturating_sub(1). (&ranges[..i], &ranges[i.saturating_sub(1)..]) } } } /// For a strictly ordered sequence of boundaries `ranges`, checks if the /// value at `at` is true. #[allow(dead_code)] fn contains(boundaries: &[T], value: &T) -> bool { match boundaries.binary_search(value) { Ok(index) => !is_odd(index), Err(index) => is_odd(index), } } /// Check if a sequence of boundaries `ranges` intersects with a range #[allow(dead_code)] fn intersects(boundaries: &[T], range: Range) -> bool { let (_, remaining) = split(boundaries, range.start); let (remaining, _) = split(remaining, range.end); // remaining is not the intersection but can be larger. // But if remaining is empty, then we know that the intersection is empty. !remaining.is_empty() } #[cfg(test)] mod util_tests { use std::{collections::BTreeSet, ops::Range}; use super::*; use proptest::prelude::*; fn test_points(boundaries: impl IntoIterator) -> BTreeSet { let mut res = BTreeSet::new(); for x in boundaries { res.insert(x.saturating_sub(1)); res.insert(x); res.insert(x.saturating_add(1)); } res } fn test_boundaries() -> impl Strategy, u64)> { proptest::collection::vec(any::(), 0..100).prop_flat_map(|mut v| { v.sort(); v.dedup(); // split point should occasionally be outside of the range let max_split = v .iter() .max() .cloned() .unwrap_or_default() .saturating_add(2); (Just(v), 0..max_split) }) } proptest! { #[test] fn test_split((boundaries, at) in test_boundaries()) { let (left, right) = split(&boundaries, at); for x in test_points(boundaries.clone()) { // test that split does what it promises if x < at { prop_assert_eq!(contains(left, &x), contains(&boundaries, &x), "left must be like boundaries for x < at"); } else { prop_assert_eq!(contains(right, &x), contains(&boundaries, &x), "right must be like boundaries for x >= at"); } // test that split is not just returning the input, but minimal parts let nr = right.iter().filter(|x| x < &&at).count(); prop_assert!(nr <= 1, "there must be at most one boundary before the split point"); let nl = left.iter().filter(|x| x >= &&at).count(); prop_assert!(nl == 0, "there must be no boundaries after the split point"); } } } #[test] fn test_split_0() { #[allow(clippy::type_complexity)] let cases: Vec<(&[u64], u64, (&[u64], &[u64]))> = vec![ (&[0, 2], 0, (&[], &[0, 2])), (&[0, 2], 2, (&[0], &[])), (&[0, 2, 4], 2, (&[0], &[4])), (&[0, 2, 4], 4, (&[0, 2], &[4])), (&[0, 2, 4, 8], 2, (&[0], &[4, 8])), (&[0, 2, 4, 8], 4, (&[0, 2], &[4, 8])), (&[0, 2, 4, 8], 3, (&[0, 2], &[4, 8])), (&[0, 2, 4, 8], 6, (&[0, 2, 4], &[4, 8])), ]; for (ranges, pos, (left, right)) in cases { assert_eq!(split(ranges, pos), (left, right)); } } #[test] fn test_intersects_0() { let cases: Vec<(&[u64], Range, bool)> = vec![ (&[0, 2], 0..2, true), (&[0, 2], 2..4, false), (&[0, 2, 4, 8], 0..2, true), (&[0, 2, 4, 8], 2..4, false), (&[0, 2, 4, 8], 4..8, true), (&[0, 2, 4, 8], 8..12, false), ]; for (ranges, range, expected) in cases { assert_eq!(intersects(ranges, range), expected); } } #[test] fn contains_0() { let cases: Vec<(&[u64], u64, bool)> = vec![ (&[0, 2], 0, true), (&[0, 2], 1, true), (&[0, 2], 2, false), (&[0, 2, 4, 8], 3, false), (&[0, 2, 4, 8], 4, true), ]; for (ranges, pos, expected) in cases { assert_eq!(contains(ranges, &pos), expected); } } } #[cfg(test)] mod tests { use super::*; use num_traits::{Bounded, PrimInt}; use obey::*; use quickcheck::*; use std::collections::BTreeSet; use std::ops::RangeBounds; impl> RangeSet { fn from_range_bounds>(r: R) -> std::result::Result { match (r.start_bound(), r.end_bound()) { (Bound::Unbounded, Bound::Unbounded) => Ok(Self::all()), (Bound::Unbounded, Bound::Excluded(b)) => Ok(Self::from_range_until(b.clone())), (Bound::Included(a), Bound::Unbounded) => Ok(Self::from_range_from(a.clone())), (Bound::Included(a), Bound::Excluded(b)) => Ok(Self::from_range(Range { start: a.clone(), end: b.clone(), })), _ => Err(()), } } } impl + Clone + 'static> Arbitrary for RangeSet { fn arbitrary(g: &mut G) -> Self { let mut boundaries: Vec = Arbitrary::arbitrary(g); boundaries.truncate(4); boundaries.sort(); boundaries.dedup(); Self::new_unchecked_impl(boundaries.into()) } } /// A range set can be seen as a set of elements, even though it does not actually contain the elements impl> TestSamples for RangeSet { fn samples(&self, res: &mut BTreeSet) { res.insert(::min_value()); for x in self.0.iter().cloned() { res.insert(x.saturating_sub(E::one())); res.insert(x); res.insert(x.saturating_add(E::one())); } res.insert(E::max_value()); } fn at(&self, elem: E) -> bool { self.contains(&elem) } } type Test = RangeSet<[i64; 4]>; #[test] fn smoke_test() { let x: Test = Test::from(0..10); println!( "{:?} {:?} {:?} {:?} {:?}", x, x.contains(&0), x.contains(&1), x.contains(&9), x.contains(&10) ); let y: Test = Test::from(..10); let z: Test = Test::from(20..); let r: Test = (&x).bitor(&z); println!("{:?} {:?} {:?} {:?}", x, y, z, r); let r2: Test = &x & &y; let r3: Test = &x | &y; let r4 = y.is_disjoint(&z); let r5 = (&y).bitand(&z); println!("{:?}", r2); println!("{:?}", r3); println!("{:?} {:?}", r4, r5); } #[cfg(feature = "serde")] #[quickcheck] fn range_seq_serde(a: Test) -> bool { let bytes = serde_cbor::to_vec(&a).unwrap(); let b: Test = serde_cbor::from_slice(&bytes).unwrap(); a == b } #[cfg(feature = "rkyv")] #[quickcheck] fn range_seq_rkyv_unvalidated(a: Test) -> bool { use rkyv::*; use ser::Serializer; let mut serializer = ser::serializers::AllocSerializer::<256>::default(); serializer.serialize_value(&a).unwrap(); let bytes = serializer.into_serializer().into_inner(); let archived = unsafe { rkyv::archived_root::(&bytes) }; let deserialized: Test = archived.deserialize(&mut Infallible).unwrap(); a == deserialized } #[cfg(feature = "rkyv_validated")] #[quickcheck] fn range_seq_rkyv_validated(a: Test) -> bool { use rkyv::*; use ser::Serializer; let mut serializer = ser::serializers::AllocSerializer::<256>::default(); serializer.serialize_value(&a).unwrap(); let bytes = serializer.into_serializer().into_inner(); let archived = rkyv::check_archived_root::(&bytes).unwrap(); let deserialized: Test = archived.deserialize(&mut Infallible).unwrap(); a == deserialized } #[cfg(feature = "rkyv_validated")] #[test] fn range_seq_rkyv_errors() { use rkyv::*; use std::num::NonZeroU64; // deserialize a boolean value of 2, must produce an error! let mut bytes = AlignedVec::new(); bytes.extend_from_slice(&hex::decode("000000000000000002000000").unwrap()); assert!(rkyv::check_archived_root::(&bytes).is_err()); // deserialize wrongly ordered range set, must produce an error let mut bytes = AlignedVec::new(); bytes.extend_from_slice( &hex::decode("02000000000000000100000000000000f0ffffff0200000000000000").unwrap(), ); assert!(rkyv::check_archived_root::(&bytes).is_err()); // deserialize wrong value (0 for a NonZeroU64), must produce an error let mut bytes = AlignedVec::new(); bytes.extend_from_slice( &hex::decode("00000000000000000100000000000000f0ffffff0200000000000000").unwrap(), ); assert!(rkyv::check_archived_root::>(&bytes).is_err()); } #[quickcheck] fn ranges_consistent(a: Test) -> bool { let mut b = Test::empty(); for e in a.iter() { let e = e.cloned(); b |= Test::from_range_bounds(e).unwrap(); } a == b } #[quickcheck] fn is_disjoint_sample(a: Test, b: Test) -> bool { let res = binary_property_test(&a, &b, a.is_disjoint(&b), |a, b| !(a & b)); if !res { println!("{:?} {:?} {:?}", a, b, a.is_disjoint(&b)); } res } #[quickcheck] fn is_subset_sample(a: Test, b: Test) -> bool { binary_property_test(&a, &b, a.is_subset(&b), |a, b| !a | b) } #[quickcheck] fn negation_check(a: RangeSet2) -> bool { unary_element_test(&a, !a.clone(), |x| !x) } #[quickcheck] fn union_check(a: RangeSet2, b: RangeSet2) -> bool { binary_element_test(&a, &b, &a | &b, |a, b| a | b) } #[quickcheck] fn intersection_check(a: RangeSet2, b: RangeSet2) -> bool { binary_element_test(&a, &b, &a & &b, |a, b| a & b) } #[quickcheck] fn xor_check(a: RangeSet2, b: RangeSet2) -> bool { binary_element_test(&a, &b, &a ^ &b, |a, b| a ^ b) } #[quickcheck] fn difference_check(a: RangeSet2, b: RangeSet2) -> bool { binary_element_test(&a, &b, &a - &b, |a, b| a & !b) } bitop_assign_consistent!(Test); bitop_symmetry!(Test); bitop_empty!(Test); bitop_sub_not_all!(Test); set_predicate_consistent!(Test); }