rangemap-1.3.0/.cargo_vcs_info.json0000644000000001360000000000100126270ustar { "git": { "sha1": "9c77ce80845bf4387907e8b1bbee4561404a38ee" }, "path_in_vcs": "" }rangemap-1.3.0/.github/workflows/ci.yml000064400000000000000000000033631046102023000161370ustar 00000000000000name: CI on: push: branches: [master, staging, trying] pull_request: branches: [main] env: CARGO_TERM_COLOR: always jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: toolchain: # Don't forget to update the README when bumping MSRV. - 1.56.1 - stable - beta - nightly os: - ubuntu-latest - macos-latest - windows-latest steps: - name: checkout uses: actions/checkout@v2 - name: install toolchain uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.toolchain }} default: true profile: minimal - name: stable test without serde uses: actions-rs/cargo@v1 if: matrix.toolchain != 'nightly' with: command: test # We just need to make sure we haven't broken it in some obvious way # either with or without serde enabled, so only test with serde on stable. - name: stable test with serde uses: actions-rs/cargo@v1 if: matrix.toolchain == 'stable' with: command: test args: --features serde1 # Make sure we haven't broken the const_fn feature. - name: stable test with const_fn uses: actions-rs/cargo@v1 if: matrix.toolchain == 'stable' with: command: test args: --features const_fn - name: nightly test uses: actions-rs/cargo@v1 if: matrix.toolchain == 'nightly' with: command: test args: --features nightly ci-success: name: ci if: ${{ success() }} needs: - test runs-on: ubuntu-20.04 steps: - name: CI succeeded run: exit 0 rangemap-1.3.0/.gitignore000064400000000000000000000000361046102023000134060ustar 00000000000000/target **/*.rs.bk Cargo.lock rangemap-1.3.0/CHANGELOG.md000064400000000000000000000065011046102023000132320ustar 00000000000000### v1.3.0 (2023-01-03) - **Features**: - Add `overlapping` method to all collection types, which returns an iterator over all stored entries that completely or partially overlap a given range. - Add `overlaps` convenience method to all collection types, which returns whether any stored range completely or partially overlaps a given range. - Credit to [Rua](https://github.com/Rua) for the original implementation of these new methods. (Unfortunately I couldn't use their code directly because I made other incompatible changes.) Thanks also to [rumpuslabs](https://github.com/rumpuslabs) for their engagement. ### v1.2.0 (2022-12-27) - **Features**: - Add `clear`, `len`, and `is_empty` methods for all map and set types. - **Fixes**: - Make `const_fn` feature work again. (Previous release accidentally broke the const versions of `RangeMap::new` and `RangeSet::new`.) ### v1.1.0 (2022-11-12) - **Features**: - Implement `PartialEq`, `Eq`, `PartialOrd`, and `Ord` for all map and set types. - Make `new` functions for all map and set types `const` when `const_fn` feature is enabled. - **Changes**: - Bump minimum supported Rust version to 1.56.1. (Released a year ago.) This is for compatibility with new versions of some of rangemap's development dependencies. ### v1.0.3 (2022-06-11) - **Fixes**: - Fix `Gaps` iterator for `RangeMap` yielding an empty gap for an empty outer range. Simplified gaps logic and expanded fuzz testing to better cover this and similar cases. ### v1.0.2 (2022-05-17) - **Fixes**: - Fix empty gaps returned by `Gaps` iterator for `RangeInclusiveMap`. Added fuzz tests for `Gaps` iterators. ### v1.0.1 (2022-01-29) - **Fixes**: - Fix empty gaps returned by `Gaps` iterator for `RangeMap`, and incorrect gaps returned by `Gaps` iterator for `RangeInclusiveMap`. ### v1.0.0 (2022-01-28) It's time. (No functional change.) ### v0.1.14 (2021-11-16) - **Features**: - Expose nameable types for iterators: `Iterator`, `IntoIterator`, `Gaps` (for each collection type). - **Changes**: - Document overflow behaviour required by implementors of `StepLite` and `StepFns`. ### v0.1.13 (2021-08-25) - **Features**: - Add serde support. ### v0.1.12 (2021-08-23) - **Features**: - Implement more traits for all map and set types: `IntoIter`, `FromIter`, and `Extend`. - **Changes**: - Bump minimum supported Rust version to 1.46. ### v0.1.11 (2021-06-30) "EOFY edition" - **Features**: - Support `no_std` environments. - **Changes**: - Update all dev-dependencies to latest versions. ### v0.1.10 (2021-02-23) - **Fixes**: - Fix performance regression introduced in v0.1.9, which made inserts extremely slow for large maps. ### v0.1.9 (2021-02-23) - **Fixes**: - Fix coalescing of contiguous ranges. In some cases `RangeMap` and `RangeInclusiveMap` would leave two separate contiguous ranges with the same value instead of combining them into one. ### v0.1.8 (2020-11-22) - **Features**: - Implement `Debug` for all map and set types. ### v0.1.7 (2020-09-07) - **Features**: - Add `gaps` method to all map and set types for iterating over sub-ranges of a given outer range that are not covered by any stored range. ### v0.1.6 (2020-07-15) - **Features**: - Add `RangeInclusiveMap` and `RangeInclusiveSet` types for storing closed ranges. rangemap-1.3.0/Cargo.lock0000644000000502600000000000100106050ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bstr" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", "regex-automata", "serde", ] [[package]] name = "bumpalo" version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "cast" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ "rustc_version", ] [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ "iana-time-zone", "js-sys", "num-integer", "num-traits", "time", "wasm-bindgen", "winapi", ] [[package]] name = "clap" version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", "textwrap", "unicode-width", ] [[package]] name = "core-foundation-sys" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "criterion" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast 0.2.7", "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 0.3.0", "itertools", ] [[package]] name = "crossbeam-channel" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", "once_cell", "scopeguard", ] [[package]] name = "crossbeam-utils" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "csv" version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", "itoa 0.4.8", "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.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "getrandom" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" 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 = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "iana-time-zone" version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" dependencies = [ "android_system_properties", "core-foundation-sys", "js-sys", "once_cell", "wasm-bindgen", "winapi", ] [[package]] name = "itertools" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] [[package]] name = "itoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "js-sys" version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" 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.132" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] [[package]] name = "num" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ "num-bigint", "num-complex", "num-integer", "num-iter", "num-rational", "num-traits", ] [[package]] name = "num-bigint" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-complex" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" dependencies = [ "autocfg", "num-traits", ] [[package]] name = "num-integer" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", ] [[package]] name = "num-iter" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-rational" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg", "num-bigint", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "oorandom" version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "permutator" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9c6f38fc32835c34be344aa470f8f198b1788986eab65fc2a04d25a6f2510d6" dependencies = [ "num", ] [[package]] name = "plotters" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "716b4eeb6c4a1d3ecc956f75b43ec2e8e8ba80026413e70a3f41fd3313d3492b" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" [[package]] name = "plotters-svg" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" dependencies = [ "plotters-backend", ] [[package]] name = "ppv-lite86" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[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", ] [[package]] name = "rand_core" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] [[package]] name = "rangemap" version = "1.3.0" dependencies = [ "chrono", "criterion", "permutator", "rand", "rustc_version", "serde", "serde_json", ] [[package]] name = "rayon" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", "num_cpus", ] [[package]] name = "regex" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "regex-syntax", ] [[package]] name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] [[package]] name = "ryu" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[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.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" [[package]] name = "serde" version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" [[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.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa 1.0.3", "ryu", "serde", ] [[package]] name = "syn" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ "unicode-width", ] [[package]] name = "time" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[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 = "unicode-ident" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-width" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "walkdir" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", "winapi", "winapi-util", ] [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[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.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" [[package]] name = "web-sys" version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" 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" rangemap-1.3.0/Cargo.toml0000644000000026460000000000100106350ustar # 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" rust-version = "1.56.1" name = "rangemap" version = "1.3.0" authors = ["Jeff Parsons "] description = """ Map and set data structures whose keys are stored as ranges. Contiguous and overlapping ranges that map to the same value are coalesced into a single range. """ homepage = "https://github.com/jeffparsons/rangemap" documentation = "https://docs.rs/rangemap" readme = "README.md" categories = ["data-structures"] license = "MIT/Apache-2.0" repository = "https://github.com/jeffparsons/rangemap" [[bench]] name = "kitchen_sink" harness = false [dependencies.serde] version = "1" optional = true [dev-dependencies.chrono] version = "0.4" [dev-dependencies.criterion] version = "= 0.3.5" [dev-dependencies.permutator] version = "0.4" [dev-dependencies.rand] version = "0.8" [dev-dependencies.rustc_version] version = "0.4" [dev-dependencies.serde_json] version = "1" [features] const_fn = [] nightly = [] serde1 = ["serde"] rangemap-1.3.0/Cargo.toml.orig000064400000000000000000000025711046102023000143130ustar 00000000000000[package] name = "rangemap" version = "1.3.0" authors = ["Jeff Parsons "] edition = "2018" license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/jeffparsons/rangemap" documentation = "https://docs.rs/rangemap" homepage = "https://github.com/jeffparsons/rangemap" description = """ Map and set data structures whose keys are stored as ranges. Contiguous and overlapping ranges that map to the same value are coalesced into a single range. """ categories = ["data-structures"] rust-version = "1.56.1" [dependencies] serde = { version = "1", optional = true } [dev-dependencies] permutator = "0.4" # Criterion bumps its MSRV in 0.3.6; it is probably reasonable # to update rangemap's MSRV, too, but until I actually publish # a policy on that I'm going to avoid doing a big bump right now. # (Later problem!) criterion = "= 0.3.5" rand = "0.8" chrono = "0.4" # For examples rustc_version = "0.4" serde_json = "1" [features] serde1 = ["serde"] # So we can run doc tests from "README.md". nightly = [] # Enables `RangeMap::new()`, `RangeInclusiveMap::new()`, `RangeSet::new()`, # and `RangeInclusiveSet::new()` to be const functions. # Requires a nightly compiler because `const_btree_new` is an unstable feature, # but is soon to be stabilized: const_fn = [] [[bench]] name = "kitchen_sink" harness = false rangemap-1.3.0/LICENSE-APACHE000064400000000000000000000251251046102023000133500ustar 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 Copyright 2019-2022 Jeff Parsons, and [contributors](https://github.com/jeffparsons/rangemap/contributors) 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. rangemap-1.3.0/LICENSE-MIT000064400000000000000000000020371046102023000130550ustar 00000000000000Copyright 2019 Jeffrey Parsons 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. rangemap-1.3.0/README.fuzz.md000064400000000000000000000004741046102023000137000ustar 00000000000000# rangemap fuzz tests These fuzz tests use the [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz) tool. Run one of these: ``` cargo +nightly fuzz run rangemap_coalesce cargo +nightly fuzz run rangemap_inclusive_coalesce cargo +nightly fuzz run rangemap_gaps cargo +nightly fuzz run rangemap_inclusive_gaps ``` rangemap-1.3.0/README.md000064400000000000000000000131511046102023000126770ustar 00000000000000# rangemap [![Crate](https://img.shields.io/crates/v/rangemap.svg)](https://crates.io/crates/rangemap) [![Docs](https://docs.rs/rangemap/badge.svg)](https://docs.rs/rangemap) [![Build status](https://github.com/jeffparsons/rangemap/workflows/CI/badge.svg)](https://github.com/jeffparsons/rangemap/actions) [![Rust](https://img.shields.io/badge/rust-1.56.1%2B-blue.svg?maxAge=3600)](https://github.com/jeffparsons/rangemap) [`RangeMap`] and [`RangeInclusiveMap`] are map data structures whose keys are stored as ranges. Contiguous and overlapping ranges that map to the same value are coalesced into a single range. Corresponding [`RangeSet`] and [`RangeInclusiveSet`] structures are also provided. ## Different kinds of ranges `RangeMap` and `RangeInclusiveMap` correspond to the [`Range`] and [`RangeInclusive`] types from the standard library respectively. For some applications the choice of range type may be obvious, or even be dictated by pre-existing design decisions. For other applications the choice may seem arbitrary, and be guided instead by convenience or aesthetic preference. If the choice is not obvious in your case, consider these differences: - If your key type `K` represents points on a continuum (e.g. `f64`), and the choice of which of two adjacent ranges "owns" the value where they touch is largely arbitrary, then it may be more natural to work with half-open `Range`s like `0.0..1.0` and `1.0..2.0`. If you were to use closed `RangeInclusive`s here instead, then to represent two such adjacent ranges you would need to subtract some infinitesimal (which may depend, as it does in the case of `f64`, on the specific value of `K`) from the end of the earlier range. (See the last point below for more on this problem.) - If you need to represent ranges that _include_ the maximum value in the key domain (e.g. `255u8`) then you will probably want to use `RangeInclusive`s like `128u8..=255u8`. Sometimes it may be possible to instead work around this by using a wider key type than the values you are actually trying to represent (`K=u16` even though you are only trying to represent ranges covering `u8`) but in these cases the key domain often represents discrete objects rather than points on a continuum, and so `RangeInclusive` may be a more natural way to express these ranges anyway. - If you are using `RangeInclusive`, then it must be possible to define _successor_ and _predecessor_ functions for your key type `K`, because adjacent ranges can not be detected (and thereby coalesced) simply by testing their ends for equality. For key types that represent points on a continuum, defining these functions may be awkward and error-prone. For key types that represent discrete objects, this is usually much more straightforward. ## Example: use with Chrono ```rust use chrono::offset::TimeZone; use chrono::{Duration, Utc}; use rangemap::RangeMap; fn main() { let people = ["Alice", "Bob", "Carol"]; let mut roster = RangeMap::new(); // Set up initial roster. let start_of_roster = Utc.ymd(2019, 1, 7); let mut week_start = start_of_roster; for _ in 0..3 { for person in &people { let next_week = week_start + Duration::weeks(1); roster.insert(week_start..next_week, person); week_start = next_week; } } // Bob is covering Alice's second shift (the fourth shift overall). let fourth_shift_start = start_of_roster + Duration::weeks(3); let fourth_shift_end = fourth_shift_start + Duration::weeks(1); roster.insert(fourth_shift_start..fourth_shift_end, &"Bob"); for (range, person) in roster.iter() { println!("{} ({}): {}", range.start, range.end - range.start, person); } // Output: // 2019-01-07UTC (P7D): Alice // 2019-01-14UTC (P7D): Bob // 2019-01-21UTC (P7D): Carol // 2019-01-28UTC (P14D): Bob // 2019-02-11UTC (P7D): Carol // 2019-02-18UTC (P7D): Alice // 2019-02-25UTC (P7D): Bob // 2019-03-04UTC (P7D): Carol } ``` ## Crate features By default this crate has no dependencies on other crates. If you enable the **serde1** feature it will introduce a dependency on the _serde_ crate and provide `Serialize` and `Deserialize` implementations for all map and set types in this crate. You can enable the **serde1** feature in your _Cargo.toml_ file like so: ```toml [dependencies] rangemap = { version = "1", features = ["serde1"] } ``` ## Building without the Rust standard library This crate can work without the full standard library available (e.g. when running on bare metal without an operating system) but relies on the presence of a global allocator — i.e. it links the `core` and `alloc` crates, but not `std`. Presently there is no functionality in the crate that require the standard library. Such functionality will likely be introduced in the future, and will be gated behind a default-on `std` feature. See [The Rust Programming Language](https://doc.rust-lang.org/1.7.0/book/no-stdlib.html) book for general information about operating without the standard library. [`RangeMap`]: https://docs.rs/rangemap/latest/rangemap/struct.RangeMap.html [`RangeInclusiveMap`]: https://docs.rs/rangemap/latest/rangemap/struct.RangeInclusiveMap.html [`RangeSet`]: https://docs.rs/rangemap/latest/rangemap/struct.RangeSet.html [`RangeInclusiveSet`]: https://docs.rs/rangemap/latest/rangemap/struct.RangeInclusiveSet.html [`Range`]: https://doc.rust-lang.org/stable/std/ops/struct.Range.html [`RangeInclusive`]: https://doc.rust-lang.org/stable/std/ops/struct.RangeInclusive.html rangemap-1.3.0/benches/kitchen_sink.rs000064400000000000000000000020551046102023000160470ustar 00000000000000#[macro_use] extern crate criterion; use criterion::Criterion; use rand::prelude::*; use std::ops::Range; fn kitchen_sink(kvs: &[(Range, bool)]) { use rangemap::RangeMap; let mut range_map: RangeMap = RangeMap::new(); // Remove every second range. let mut remove = false; for (range, value) in kvs { if remove { range_map.remove(range.clone()); } else { range_map.insert(range.clone(), *value); } remove = !remove; } } fn criterion_benchmark(c: &mut Criterion) { c.bench_function("kitchen sink", |b| { let mut rng = thread_rng(); let kvs: Vec<(Range, bool)> = (0..1000) .map(|_| { let start = rng.gen_range(0..1000); let end = start + rng.gen_range(1..100); let value: bool = random(); (start..end, value) }) .collect(); b.iter(|| kitchen_sink(&kvs)) }); } criterion_group!(benches, criterion_benchmark); criterion_main!(benches); rangemap-1.3.0/bors.toml000064400000000000000000000000601046102023000132550ustar 00000000000000status = [ "ci" ] timeout_sec = 3600 # One hour rangemap-1.3.0/examples/roster.rs000064400000000000000000000020311046102023000151150ustar 00000000000000use chrono::offset::TimeZone; use chrono::{Duration, Utc}; use rangemap::RangeMap; fn main() { let people = ["Alice", "Bob", "Carol"]; let mut roster = RangeMap::new(); // Set up initial roster. let start_of_roster = Utc.ymd(2019, 1, 7); let mut week_start = start_of_roster; for _ in 0..3 { for person in &people { let next_week = week_start + Duration::weeks(1); roster.insert(week_start..next_week, person); week_start = next_week; } } // Bob is covering Alice's second shift (the fourth shift overall). let fourth_shift_start = start_of_roster + Duration::weeks(3); let fourth_shift_end = fourth_shift_start + Duration::weeks(1); roster.insert(fourth_shift_start..fourth_shift_end, &"Bob"); // Print out the roster, and observe that // the fourth and fifth shifts have been coalesced // into one range. for (range, person) in roster.iter() { println!("{} ({}): {}", range.start, range.end - range.start, person); } } rangemap-1.3.0/pre_commit.sh000075500000000000000000000005061046102023000141150ustar 00000000000000#!/bin/bash set -ex cargo test # For doc tests in "README.md". cargo +nightly test --features nightly # And just with serde1. cargo test --features serde1 # And with const functions. cargo +nightly test --features const_fn cargo run --example roster cargo fmt cargo clippy --bins --examples --tests --benches -- -D warnings rangemap-1.3.0/src/dense.rs000064400000000000000000000115731046102023000136610ustar 00000000000000use alloc::{collections::BTreeMap, vec::Vec}; use core::ops::{Range, RangeInclusive}; use super::{RangeInclusiveMap, RangeMap}; // A simple but infeasibly slow and memory-hungry // version of `RangeInclusiveMap` for testing. // // Only understands `u32` keys, so that we don't // have to be generic over `step`. This is just for // testing, so it's fine. // // Note that even though this mirrors the semantics // of `RangeInclusiveMap`, it can also be used to // test `RangeMap` just fine. #[derive(Eq, PartialEq, Debug)] pub struct DenseU32RangeMap { // Inner B-Tree map. Stores values and their keys // directly rather than as ranges. btm: BTreeMap, } impl DenseU32RangeMap where V: Eq + Clone, { pub fn new() -> DenseU32RangeMap { DenseU32RangeMap { btm: BTreeMap::new(), } } pub fn insert(&mut self, range: RangeInclusive, value: V) { for k in range { self.btm.insert(k, value.clone()); } } pub fn iter(&self) -> Iter<'_, V> { Iter { inner: self.btm.iter(), current: None, } } pub fn end_exclusive_iter(&self) -> EndExclusiveIter<'_, V> { EndExclusiveIter { inner: self.iter() } } // Vecs are easier to use for assertions than iterators, // because you don't have to consume them to compare them. pub fn to_vec(&self) -> Vec<(RangeInclusive, V)> { self.iter() .map(|(range, value)| (range, value.clone())) .collect() } pub fn to_end_exclusive_vec(&self) -> Vec<(Range, V)> { self.end_exclusive_iter() .map(|(range, value)| (range, value.clone())) .collect() } } impl From> for DenseU32RangeMap where V: Eq + Clone, { fn from(range_map: RangeMap) -> Self { let mut dense = Self::new(); for (range, value) in range_map.iter() { // Convert to inclusive end. // (This is only valid because u32 has // the "successor function".) // // NOTE: Clippy's `range_minus_one` lint is a bit overzealous here, // because we _can't_ pass an open-ended range to `insert`. #[allow(clippy::range_minus_one)] dense.insert(range.start..=(range.end - 1), value.clone()); } dense } } impl From> for DenseU32RangeMap where V: Eq + Clone, { fn from(range_inclusive_map: RangeInclusiveMap) -> Self { let mut dense = Self::new(); for (range, value) in range_inclusive_map.iter() { dense.insert(range.clone(), value.clone()); } dense } } pub struct Iter<'a, V> { inner: alloc::collections::btree_map::Iter<'a, u32, V>, // Current range being built for output. // We modify it as we iterate through the underlying // dense map. current: Option<(RangeInclusive, &'a V)>, } // Coalesce items from the underlying dense map as we go. impl<'a, V> Iterator for Iter<'a, V> where V: 'a + Eq, { type Item = (RangeInclusive, &'a V); fn next(&mut self) -> Option<(RangeInclusive, &'a V)> { if let Some(next_dense) = self.inner.next() { if let Some(current) = &mut self.current { // We're already building a range. Can we extend it? if current.0.end() + 1 == *next_dense.0 && *current.1 == *next_dense.1 { // This immediately follows the last item and the value is the same; // we can extend it. *current = (*current.0.start()..=*next_dense.0, current.1); // Recurse until we find a way to flush it. self.next() } else { // There's a gap or the value differs; flush the one we were working on and start a new one. let item_to_yield = current.clone(); *current = (*next_dense.0..=*next_dense.0, next_dense.1); Some(item_to_yield) } } else { // We're not building a range yet; start a new one. self.current = Some((*next_dense.0..=*next_dense.0, next_dense.1)); // Recurse until we find a way to flush it. self.next() } } else { // We reached the end of the underlying dense map. // Flush the item we were building, if any. self.current.take() } } } pub struct EndExclusiveIter<'a, V> { inner: Iter<'a, V>, } impl<'a, V> Iterator for EndExclusiveIter<'a, V> where V: 'a + Eq, { type Item = (Range, &'a V); fn next(&mut self) -> Option<(Range, &'a V)> { self.inner .next() .map(|(range, value)| ((*range.start())..(*range.end() + 1), value)) } } rangemap-1.3.0/src/inclusive_map.rs000064400000000000000000001647731046102023000154340ustar 00000000000000use super::range_wrapper::RangeInclusiveStartWrapper; use crate::range_wrapper::RangeInclusiveEndWrapper; use crate::std_ext::*; use alloc::collections::BTreeMap; use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::iter::FromIterator; use core::marker::PhantomData; use core::ops::{RangeFrom, RangeInclusive}; use core::prelude::v1::*; #[cfg(feature = "serde1")] use serde::{ de::{Deserialize, Deserializer, SeqAccess, Visitor}, ser::{Serialize, Serializer}, }; /// A map whose keys are stored as ranges bounded /// inclusively below and above `(start..=end)`. /// /// Contiguous and overlapping ranges that map to the same value /// are coalesced into a single range. /// /// Successor and predecessor functions must be provided for /// the key type `K`, so that we can detect adjacent but non-overlapping /// (closed) ranges. (This is not a problem for half-open ranges, /// because adjacent ranges can be detected using equality of range ends alone.) /// /// You can provide these functions either by implementing the /// [`StepLite`](crate::StepLite) trait for your key type `K`, or, /// if this is impossible because of Rust's "orphan rules", /// you can provide equivalent free functions using the `StepFnsT` type parameter. /// [`StepLite`](crate::StepLite) is implemented for all standard integer types, /// but not for any third party crate types. #[derive(Clone)] pub struct RangeInclusiveMap { // Wrap ranges so that they are `Ord`. // See `range_wrapper.rs` for explanation. pub(crate) btm: BTreeMap, V>, _phantom: PhantomData, } impl Default for RangeInclusiveMap where K: Ord + Clone + StepLite, V: Eq + Clone, { fn default() -> Self { Self::new() } } impl PartialEq for RangeInclusiveMap where K: PartialEq, V: PartialEq, { fn eq(&self, other: &RangeInclusiveMap) -> bool { self.btm == other.btm } } impl Eq for RangeInclusiveMap where K: Eq, V: Eq, { } impl PartialOrd for RangeInclusiveMap where K: PartialOrd, V: PartialOrd, { #[inline] fn partial_cmp(&self, other: &RangeInclusiveMap) -> Option { self.btm.partial_cmp(&other.btm) } } impl Ord for RangeInclusiveMap where K: Ord, V: Ord, { #[inline] fn cmp(&self, other: &RangeInclusiveMap) -> Ordering { self.btm.cmp(&other.btm) } } impl RangeInclusiveMap where K: Ord + Clone + StepLite, V: Eq + Clone, { /// Makes a new empty `RangeInclusiveMap`. #[cfg(feature = "const_fn")] pub const fn new() -> Self { Self::new_with_step_fns() } /// Makes a new empty `RangeInclusiveMap`. #[cfg(not(feature = "const_fn"))] pub fn new() -> Self { Self::new_with_step_fns() } } impl RangeInclusiveMap where K: Ord + Clone, V: Eq + Clone, StepFnsT: StepFns, { /// Makes a new empty `RangeInclusiveMap`, specifying successor and /// predecessor functions defined separately from `K` itself. /// /// This is useful as a workaround for Rust's "orphan rules", /// which prevent you from implementing `StepLite` for `K` if `K` /// is a foreign type. /// /// **NOTE:** This will likely be deprecated and then eventually /// removed once the standard library's [Step](core::iter::Step) /// trait is stabilised, as most crates will then likely implement [Step](core::iter::Step) /// for their types where appropriate. /// /// See [this issue](https://github.com/rust-lang/rust/issues/42168) /// for details about that stabilization process. #[cfg(not(feature = "const_fn"))] pub fn new_with_step_fns() -> Self { Self { btm: BTreeMap::new(), _phantom: PhantomData, } } #[cfg(feature = "const_fn")] pub const fn new_with_step_fns() -> Self { Self { btm: BTreeMap::new(), _phantom: PhantomData, } } /// Returns a reference to the value corresponding to the given key, /// if the key is covered by any range in the map. pub fn get(&self, key: &K) -> Option<&V> { self.get_key_value(key).map(|(_range, value)| value) } /// Returns the range-value pair (as a pair of references) corresponding /// to the given key, if the key is covered by any range in the map. pub fn get_key_value(&self, key: &K) -> Option<(&RangeInclusive, &V)> { use core::ops::Bound; // The only stored range that could contain the given key is the // last stored range whose start is less than or equal to this key. let key_as_start = RangeInclusiveStartWrapper::new(key.clone()..=key.clone()); self.btm .range((Bound::Unbounded, Bound::Included(key_as_start))) .next_back() .filter(|(range_start_wrapper, _value)| { // Does the only candidate range contain // the requested key? range_start_wrapper.contains(key) }) .map(|(range_start_wrapper, value)| (&range_start_wrapper.range, value)) } /// Returns `true` if any range in the map covers the specified key. pub fn contains_key(&self, key: &K) -> bool { self.get(key).is_some() } /// Gets an iterator over all pairs of key range and value, /// ordered by key range. /// /// The iterator element type is `(&'a RangeInclusive, &'a V)`. pub fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.btm.iter(), } } /// Clears the map, removing all elements. pub fn clear(&mut self) { self.btm.clear(); } /// Returns the number of elements in the map. pub fn len(&self) -> usize { self.btm.len() } /// Returns true if the map contains no elements. pub fn is_empty(&self) -> bool { self.btm.is_empty() } /// Insert a pair of key range and value into the map. /// /// If the inserted range partially or completely overlaps any /// existing range in the map, then the existing range (or ranges) will be /// partially or completely replaced by the inserted range. /// /// If the inserted range either overlaps or is immediately adjacent /// any existing range _mapping to the same value_, then the ranges /// will be coalesced into a single contiguous range. /// /// # Panics /// /// Panics if range `start > end`. pub fn insert(&mut self, range: RangeInclusive, value: V) { use core::ops::Bound; // Backwards ranges don't make sense. // `RangeInclusive` doesn't enforce this, // and we don't want weird explosions further down // if someone gives us such a range. assert!( range.start() <= range.end(), "Range start can not be after range end" ); // Wrap up the given range so that we can "borrow" // it as a wrapper reference to either its start or end. // See `range_wrapper.rs` for explanation of these hacks. let mut new_range_start_wrapper: RangeInclusiveStartWrapper = RangeInclusiveStartWrapper::new(range); let new_value = value; // Is there a stored range either overlapping the start of // the range to insert or immediately preceding it? // // If there is any such stored range, it will be the last // whose start is less than or equal to _one less than_ // the start of the range to insert, or the one before that // if both of the above cases exist. let mut candidates = self .btm .range::, ( Bound<&RangeInclusiveStartWrapper>, Bound<&RangeInclusiveStartWrapper>, )>((Bound::Unbounded, Bound::Included(&new_range_start_wrapper))) .rev() .take(2) .filter(|(stored_range_start_wrapper, _stored_value)| { // Does the candidate range either overlap // or immediately precede the range to insert? // (Remember that it might actually cover the _whole_ // range to insert and then some.) stored_range_start_wrapper .touches::(&new_range_start_wrapper.end_wrapper.range) }); if let Some(mut candidate) = candidates.next() { // Or the one before it if both cases described above exist. if let Some(another_candidate) = candidates.next() { candidate = another_candidate; } let (stored_range_start_wrapper, stored_value) = (candidate.0.clone(), candidate.1.clone()); self.adjust_touching_ranges_for_insert( stored_range_start_wrapper, stored_value, &mut new_range_start_wrapper.end_wrapper.range, &new_value, ); } // Are there any stored ranges whose heads overlap or immediately // follow the range to insert? // // If there are any such stored ranges (that weren't already caught above), // their starts will fall somewhere after the start of the range to insert, // and on, before, or _immediately after_ its end. To handle that last case // without risking arithmetic overflow, we'll consider _one more_ stored item past // the end of the end of the range to insert. // // REVISIT: Possible micro-optimisation: `impl Borrow for RangeInclusiveStartWrapper` // and use that to search here, to avoid constructing another `RangeInclusiveStartWrapper`. let second_last_possible_start = new_range_start_wrapper.end().clone(); let second_last_possible_start = RangeInclusiveStartWrapper::new( second_last_possible_start.clone()..=second_last_possible_start, ); while let Some((stored_range_start_wrapper, stored_value)) = self .btm .range::, ( Bound<&RangeInclusiveStartWrapper>, Bound<&RangeInclusiveStartWrapper>, )>(( Bound::Included(&new_range_start_wrapper), // We would use something like `Bound::Included(&last_possible_start)`, // but making `last_possible_start` might cause arithmetic overflow; // instead decide inside the loop whether we've gone too far and break. Bound::Unbounded, )) .next() { // A couple of extra exceptions are needed at the // end of the subset of stored ranges we want to consider, // in part because we use `Bound::Unbounded` above. // (See comments up there, and in the individual cases below.) let stored_start = stored_range_start_wrapper.start(); if *stored_start > *second_last_possible_start.start() { let latest_possible_start = StepFnsT::add_one(second_last_possible_start.start()); if *stored_start > latest_possible_start { // We're beyond the last stored range that could be relevant. // Avoid wasting time on irrelevant ranges, or even worse, looping forever. // (`adjust_touching_ranges_for_insert` below assumes that the given range // is relevant, and behaves very poorly if it is handed a range that it // shouldn't be touching.) break; } if *stored_start == latest_possible_start && *stored_value != new_value { // We are looking at the last stored range that could be relevant, // but it has a different value, so we don't want to merge with it. // We must explicitly break here as well, because `adjust_touching_ranges_for_insert` // below assumes that the given range is relevant, and behaves very poorly if it // is handed a range that it shouldn't be touching. break; } } let stored_range_start_wrapper = stored_range_start_wrapper.clone(); let stored_value = stored_value.clone(); self.adjust_touching_ranges_for_insert( stored_range_start_wrapper, stored_value, &mut new_range_start_wrapper.end_wrapper.range, &new_value, ); } // Insert the (possibly expanded) new range, and we're done! self.btm.insert(new_range_start_wrapper, new_value); } /// Removes a range from the map, if all or any of it was present. /// /// If the range to be removed _partially_ overlaps any ranges /// in the map, then those ranges will be contracted to no /// longer cover the removed range. /// /// /// # Panics /// /// Panics if range `start > end`. pub fn remove(&mut self, range: RangeInclusive) { use core::ops::Bound; // Backwards ranges don't make sense. // `RangeInclusive` doesn't enforce this, // and we don't want weird explosions further down // if someone gives us such a range. assert!( range.start() <= range.end(), "Range start can not be after range end" ); let range_start_wrapper: RangeInclusiveStartWrapper = RangeInclusiveStartWrapper::new(range); let range = &range_start_wrapper.range; // Is there a stored range overlapping the start of // the range to insert? // // If there is any such stored range, it will be the last // whose start is less than or equal to the start of the range to insert. if let Some((stored_range_start_wrapper, stored_value)) = self .btm .range::, ( Bound<&RangeInclusiveStartWrapper>, Bound<&RangeInclusiveStartWrapper>, )>((Bound::Unbounded, Bound::Included(&range_start_wrapper))) .next_back() .filter(|(stored_range_start_wrapper, _stored_value)| { // Does the only candidate range overlap // the range to insert? stored_range_start_wrapper.overlaps(range) }) .map(|(stored_range_start_wrapper, stored_value)| { (stored_range_start_wrapper.clone(), stored_value.clone()) }) { self.adjust_overlapping_ranges_for_remove( stored_range_start_wrapper, stored_value, range, ); } // Are there any stored ranges whose heads overlap the range to insert? // // If there are any such stored ranges (that weren't already caught above), // their starts will fall somewhere after the start of the range to insert, // and on or before its end. // // REVISIT: Possible micro-optimisation: `impl Borrow for RangeInclusiveStartWrapper` // and use that to search here, to avoid constructing another `RangeInclusiveStartWrapper`. let new_range_end_as_start = RangeInclusiveStartWrapper::new(range.end().clone()..=range.end().clone()); while let Some((stored_range_start_wrapper, stored_value)) = self .btm .range::, ( Bound<&RangeInclusiveStartWrapper>, Bound<&RangeInclusiveStartWrapper>, )>(( Bound::Excluded(&range_start_wrapper), Bound::Included(&new_range_end_as_start), )) .next() .map(|(stored_range_start_wrapper, stored_value)| { (stored_range_start_wrapper.clone(), stored_value.clone()) }) { self.adjust_overlapping_ranges_for_remove( stored_range_start_wrapper, stored_value, range, ); } } fn adjust_touching_ranges_for_insert( &mut self, stored_range_start_wrapper: RangeInclusiveStartWrapper, stored_value: V, new_range: &mut RangeInclusive, new_value: &V, ) { use core::cmp::{max, min}; if stored_value == *new_value { // The ranges have the same value, so we can "adopt" // the stored range. // // This means that no matter how big or where the stored range is, // we will expand the new range's bounds to subsume it, // and then delete the stored range. let new_start = min(new_range.start(), stored_range_start_wrapper.start()).clone(); let new_end = max(new_range.end(), stored_range_start_wrapper.end()).clone(); *new_range = new_start..=new_end; self.btm.remove(&stored_range_start_wrapper); } else { // The ranges have different values. if new_range.overlaps(&stored_range_start_wrapper.range) { // The ranges overlap. This is a little bit more complicated. // Delete the stored range, and then add back between // 0 and 2 subranges at the ends of the range to insert. self.btm.remove(&stored_range_start_wrapper); if stored_range_start_wrapper.start() < new_range.start() { // Insert the piece left of the range to insert. self.btm.insert( RangeInclusiveStartWrapper::new( stored_range_start_wrapper.start().clone() ..=StepFnsT::sub_one(new_range.start()), ), stored_value.clone(), ); } if stored_range_start_wrapper.end() > new_range.end() { // Insert the piece right of the range to insert. self.btm.insert( RangeInclusiveStartWrapper::new( StepFnsT::add_one(new_range.end()) ..=stored_range_start_wrapper.end().clone(), ), stored_value, ); } } else { // No-op; they're not overlapping, // so we can just keep both ranges as they are. } } } fn adjust_overlapping_ranges_for_remove( &mut self, stored_range_start_wrapper: RangeInclusiveStartWrapper, stored_value: V, range_to_remove: &RangeInclusive, ) { // Delete the stored range, and then add back between // 0 and 2 subranges at the ends of the range to insert. self.btm.remove(&stored_range_start_wrapper); let stored_range = stored_range_start_wrapper.end_wrapper.range; if stored_range.start() < range_to_remove.start() { // Insert the piece left of the range to insert. self.btm.insert( RangeInclusiveStartWrapper::new( stored_range.start().clone()..=StepFnsT::sub_one(range_to_remove.start()), ), stored_value.clone(), ); } if stored_range.end() > range_to_remove.end() { // Insert the piece right of the range to insert. self.btm.insert( RangeInclusiveStartWrapper::new( StepFnsT::add_one(range_to_remove.end())..=stored_range.end().clone(), ), stored_value, ); } } /// Gets an iterator over all the maximally-sized ranges /// contained in `outer_range` that are not covered by /// any range stored in the map. /// /// The iterator element type is `RangeInclusive`. pub fn gaps<'a>(&'a self, outer_range: &'a RangeInclusive) -> Gaps<'a, K, V, StepFnsT> { Gaps { done: false, outer_range, keys: self.btm.keys(), // We'll start the candidate range at the start of the outer range // without checking what's there. Each time we yield an item, // we'll skip any ranges we find before the next gap. candidate_start: outer_range.start().clone(), _phantom: PhantomData, } } /// Gets an iterator over all the stored ranges that are /// either partially or completely overlapped by the given range. pub fn overlapping<'a>(&'a self, range: &'a RangeInclusive) -> Overlapping { // Find the first matching stored range by its _end_, // using sneaky layering and `Borrow` implementation. (See `range_wrappers` module.) let start_sliver = RangeInclusiveEndWrapper::new(range.start().clone()..=range.start().clone()); let btm_range_iter = self .btm .range::, RangeFrom<&RangeInclusiveEndWrapper>>( &start_sliver.., ); Overlapping { query_range: range, btm_range_iter, } } /// Returns `true` if any range in the map completely or partially /// overlaps the given range. pub fn overlaps(&self, range: &RangeInclusive) -> bool { self.overlapping(range).next().is_some() } } /// An iterator over the entries of a `RangeInclusiveMap`, ordered by key range. /// /// The iterator element type is `(&'a RangeInclusive, &'a V)`. /// /// This `struct` is created by the [`iter`] method on [`RangeInclusiveMap`]. See its /// documentation for more. /// /// [`iter`]: RangeInclusiveMap::iter pub struct Iter<'a, K, V> { inner: alloc::collections::btree_map::Iter<'a, RangeInclusiveStartWrapper, V>, } impl<'a, K, V> Iterator for Iter<'a, K, V> where K: 'a, V: 'a, { type Item = (&'a RangeInclusive, &'a V); fn next(&mut self) -> Option<(&'a RangeInclusive, &'a V)> { self.inner.next().map(|(by_start, v)| (&by_start.range, v)) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } /// An owning iterator over the entries of a `RangeInclusiveMap`, ordered by key range. /// /// The iterator element type is `(RangeInclusive, V)`. /// /// This `struct` is created by the [`into_iter`] method on [`RangeInclusiveMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter pub struct IntoIter { inner: alloc::collections::btree_map::IntoIter, V>, } impl IntoIterator for RangeInclusiveMap { type Item = (RangeInclusive, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.btm.into_iter(), } } } impl Iterator for IntoIter { type Item = (RangeInclusive, V); fn next(&mut self) -> Option<(RangeInclusive, V)> { self.inner .next() .map(|(by_start, v)| (by_start.end_wrapper.range, v)) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // We can't just derive this automatically, because that would // expose irrelevant (and private) implementation details. // Instead implement it in the same way that the underlying BTreeMap does. impl Debug for RangeInclusiveMap where K: Ord + Clone + StepLite, V: Eq + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() } } impl FromIterator<(RangeInclusive, V)> for RangeInclusiveMap where K: Ord + Clone + StepLite, V: Eq + Clone, { fn from_iter, V)>>(iter: T) -> Self { let mut range_map = RangeInclusiveMap::new(); range_map.extend(iter); range_map } } impl Extend<(RangeInclusive, V)> for RangeInclusiveMap where K: Ord + Clone + StepLite, V: Eq + Clone, { fn extend, V)>>(&mut self, iter: T) { iter.into_iter().for_each(move |(k, v)| { self.insert(k, v); }) } } #[cfg(feature = "serde1")] impl Serialize for RangeInclusiveMap where K: Ord + Clone + StepLite + Serialize, V: Eq + Clone + Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { use serde::ser::SerializeSeq; let mut seq = serializer.serialize_seq(Some(self.btm.len()))?; for (k, v) in self.iter() { seq.serialize_element(&((k.start(), k.end()), &v))?; } seq.end() } } #[cfg(feature = "serde1")] impl<'de, K, V> Deserialize<'de> for RangeInclusiveMap where K: Ord + Clone + StepLite + Deserialize<'de>, V: Eq + Clone + Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(RangeInclusiveMapVisitor::new()) } } #[cfg(feature = "serde1")] struct RangeInclusiveMapVisitor { marker: PhantomData RangeInclusiveMap>, } #[cfg(feature = "serde1")] impl RangeInclusiveMapVisitor { fn new() -> Self { RangeInclusiveMapVisitor { marker: PhantomData, } } } #[cfg(feature = "serde1")] impl<'de, K, V> Visitor<'de> for RangeInclusiveMapVisitor where K: Ord + Clone + StepLite + Deserialize<'de>, V: Eq + Clone + Deserialize<'de>, { type Value = RangeInclusiveMap; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("RangeInclusiveMap") } fn visit_seq(self, mut access: A) -> Result where A: SeqAccess<'de>, { let mut range_inclusive_map = RangeInclusiveMap::new(); while let Some(((start, end), value)) = access.next_element()? { range_inclusive_map.insert(start..=end, value); } Ok(range_inclusive_map) } } /// An iterator over all ranges not covered by a `RangeInclusiveMap`. /// /// The iterator element type is `RangeInclusive`. /// /// This `struct` is created by the [`gaps`] method on [`RangeInclusiveMap`]. See its /// documentation for more. /// /// [`gaps`]: RangeInclusiveMap::gaps pub struct Gaps<'a, K, V, StepFnsT> { /// Would be redundant, but we need an extra flag to /// avoid overflowing when dealing with inclusive ranges. /// /// All other things here are ignored if `done` is `true`. done: bool, outer_range: &'a RangeInclusive, keys: alloc::collections::btree_map::Keys<'a, RangeInclusiveStartWrapper, V>, candidate_start: K, _phantom: PhantomData, } // `Gaps` is always fused. (See definition of `next` below.) impl<'a, K, V, StepFnsT> core::iter::FusedIterator for Gaps<'a, K, V, StepFnsT> where K: Ord + Clone, StepFnsT: StepFns, { } impl<'a, K, V, StepFnsT> Iterator for Gaps<'a, K, V, StepFnsT> where K: Ord + Clone, StepFnsT: StepFns, { type Item = RangeInclusive; fn next(&mut self) -> Option { if self.done { // We've already passed the end of the outer range; // there are no more gaps to find. return None; } for item in &mut self.keys { let range = &item.range; if *range.end() < self.candidate_start { // We're already completely past it; ignore it. } else if *range.start() <= self.candidate_start { // We're inside it; move past it. if *range.end() >= *self.outer_range.end() { // Special case: it goes all the way to the end so we // can't safely skip past it. (Might overflow.) self.done = true; return None; } self.candidate_start = StepFnsT::add_one(range.end()); } else if *range.start() <= *self.outer_range.end() { // It starts before the end of the outer range, // so move past it and then yield a gap. let gap = self.candidate_start.clone()..=StepFnsT::sub_one(range.start()); if *range.end() >= *self.outer_range.end() { // Special case: it goes all the way to the end so we // can't safely skip past it. (Might overflow.) self.done = true; } else { self.candidate_start = StepFnsT::add_one(range.end()); } return Some(gap); } } // Now that we've run out of items, the only other possible // gap is one at the end of the outer range. self.done = true; if self.candidate_start <= *self.outer_range.end() { // There's a gap at the end! Some(self.candidate_start.clone()..=self.outer_range.end().clone()) } else { None } } } /// An iterator over all stored ranges partially or completely /// overlapped by a given range. /// /// The iterator element type is `(&'a RangeInclusive, &'a V)`. /// /// This `struct` is created by the [`overlapping`] method on [`RangeInclusiveMap`]. See its /// documentation for more. /// /// [`overlapping`]: RangeInclusiveMap::overlapping pub struct Overlapping<'a, K, V> { query_range: &'a RangeInclusive, btm_range_iter: alloc::collections::btree_map::Range<'a, RangeInclusiveStartWrapper, V>, } // `Overlapping` is always fused. (See definition of `next` below.) impl<'a, K, V> core::iter::FusedIterator for Overlapping<'a, K, V> where K: Ord + Clone {} impl<'a, K, V> Iterator for Overlapping<'a, K, V> where K: Ord + Clone, { type Item = (&'a RangeInclusive, &'a V); fn next(&mut self) -> Option { if let Some((k, v)) = self.btm_range_iter.next() { if k.start() <= self.query_range.end() { Some((&k.range, v)) } else { // The rest of the items in the underlying iterator // are past the query range. We can keep taking items // from that iterator and this will remain true, // so this is enough to make the iterator fused. None } } else { None } } } #[cfg(test)] mod tests { use super::*; use alloc::{format, vec, vec::Vec}; trait RangeInclusiveMapExt { fn to_vec(&self) -> Vec<(RangeInclusive, V)>; } impl RangeInclusiveMapExt for RangeInclusiveMap where K: Ord + Clone + StepLite, V: Eq + Clone, { fn to_vec(&self) -> Vec<(RangeInclusive, V)> { self.iter().map(|(kr, v)| (kr.clone(), v.clone())).collect() } } // // Insertion tests // #[test] fn empty_map_is_empty() { let range_map: RangeInclusiveMap = RangeInclusiveMap::new(); assert_eq!(range_map.to_vec(), vec![]); } #[test] fn insert_into_empty_map() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=50, false); assert_eq!(range_map.to_vec(), vec![(0..=50, false)]); } #[test] fn new_same_value_immediately_following_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ range_map.insert(4..=6, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---------◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=6, false)]); } #[test] fn new_different_value_immediately_following_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ range_map.insert(4..=6, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=3, false), (4..=6, true)]); } #[test] fn new_same_value_overlapping_end_of_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-----● ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ●---● ◌ ◌ ◌ range_map.insert(4..=6, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---------● ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=6, false)]); } #[test] fn new_different_value_overlapping_end_of_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◆---◆ ◌ ◌ ◌ ◌ range_map.insert(3..=5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-● ◌ ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=2, false), (3..=5, true)]); } #[test] fn new_same_value_immediately_preceding_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●---● ◌ ◌ ◌ ◌ range_map.insert(3..=5, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-● ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=2, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------● ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=5, false)]); } #[test] fn new_different_value_immediately_preceding_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◆---◆ ◌ ◌ ◌ ◌ range_map.insert(3..=5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-● ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=2, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-● ◌ ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=2, false), (3..=5, true)]); } #[test] fn new_same_value_wholly_inside_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------● ◌ ◌ ◌ ◌ range_map.insert(1..=5, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..=4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------● ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=5, false)]); } #[test] fn new_different_value_wholly_inside_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------◆ ◌ ◌ ◌ ◌ range_map.insert(1..=5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..=4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ●---● ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ assert_eq!( range_map.to_vec(), vec![(1..=1, true), (2..=4, false), (5..=5, true)] ); } #[test] fn replace_at_end_of_existing_range_should_coalesce() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ●---● ◌ ◌ ◌ range_map.insert(4..=6, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ●---● ◌ ◌ ◌ range_map.insert(4..=6, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---------● ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..=6, false)]); } #[test] // Test every permutation of a bunch of touching and overlapping ranges. fn lots_of_interesting_ranges() { use crate::dense::DenseU32RangeMap; use permutator::Permutation; let mut ranges_with_values = [ (2..=3, false), // A duplicate range (2..=3, false), // Almost a duplicate, but with a different value (2..=3, true), // A few small ranges, some of them overlapping others, // some of them touching others (3..=5, true), (4..=6, true), (6..=7, true), // A really big range (2..=6, true), ]; ranges_with_values.permutation().for_each(|permutation| { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); let mut dense: DenseU32RangeMap = DenseU32RangeMap::new(); for (k, v) in permutation { // Insert it into both maps. range_map.insert(k.clone(), v); dense.insert(k, v); // At every step, both maps should contain the same stuff. let sparse = range_map.to_vec(); let dense = dense.to_vec(); assert_eq!(sparse, dense); } }); } // // Get* tests // #[test] fn get() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=50, false); assert_eq!(range_map.get(&50), Some(&false)); assert_eq!(range_map.get(&51), None); } #[test] fn get_key_value() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=50, false); assert_eq!(range_map.get_key_value(&50), Some((&(0..=50), &false))); assert_eq!(range_map.get_key_value(&51), None); } // // Removal tests // #[test] fn remove_from_empty_map() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.remove(0..=50); assert_eq!(range_map.to_vec(), vec![]); } #[test] fn remove_non_covered_range_before_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(25..=75, false); range_map.remove(0..=24); assert_eq!(range_map.to_vec(), vec![(25..=75, false)]); } #[test] fn remove_non_covered_range_after_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(25..=75, false); range_map.remove(76..=100); assert_eq!(range_map.to_vec(), vec![(25..=75, false)]); } #[test] fn remove_overlapping_start_of_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(25..=75, false); range_map.remove(0..=25); assert_eq!(range_map.to_vec(), vec![(26..=75, false)]); } #[test] fn remove_middle_of_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(25..=75, false); range_map.remove(30..=70); assert_eq!(range_map.to_vec(), vec![(25..=29, false), (71..=75, false)]); } #[test] fn remove_overlapping_end_of_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(25..=75, false); range_map.remove(75..=100); assert_eq!(range_map.to_vec(), vec![(25..=74, false)]); } #[test] fn remove_exactly_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(25..=75, false); range_map.remove(25..=75); assert_eq!(range_map.to_vec(), vec![]); } #[test] fn remove_superset_of_stored() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(25..=75, false); range_map.remove(0..=100); assert_eq!(range_map.to_vec(), vec![]); } // // Test extremes of key ranges; we do addition/subtraction in // the range domain so I want to make sure I haven't accidentally // introduced some arithmetic overflow there. // #[test] fn no_overflow_at_key_domain_extremes() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=255, false); range_map.insert(0..=10, true); range_map.insert(245..=255, true); range_map.remove(0..=5); range_map.remove(0..=5); range_map.remove(250..=255); range_map.remove(250..=255); range_map.insert(0..=255, true); range_map.remove(1..=254); range_map.insert(254..=254, true); range_map.insert(255..=255, true); range_map.insert(255..=255, false); range_map.insert(0..=0, false); range_map.insert(1..=1, true); range_map.insert(0..=0, true); } // Gaps tests #[test] fn whole_range_is_a_gap() { // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ let range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◆ ◌ let outer_range = 1..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(1..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn whole_range_is_covered_exactly() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---------● ◌ ◌ ◌ range_map.insert(1..=6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---------◆ ◌ ◌ ◌ let outer_range = 1..=6; let mut gaps = range_map.gaps(&outer_range); // Should yield no gaps. assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_before_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---● ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=3, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◆ ◌ let outer_range = 5..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(5..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_touching_start_of_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-----● ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◆ ◌ let outer_range = 5..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(5..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_overlapping_start_of_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------● ◌ ◌ ◌ ◌ range_map.insert(1..=5, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◆ ◌ let outer_range = 5..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield from just past the end of the stored item // to the end of the outer range. assert_eq!(gaps.next(), Some(6..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_starting_at_start_of_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●-● ◌ ◌ ◌ range_map.insert(5..=6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◆ ◌ let outer_range = 5..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield from just past the item onwards. assert_eq!(gaps.next(), Some(7..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn items_floating_inside_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ●-● ◌ ◌ range_map.insert(6..=7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-● ◌ ◌ ◌ ◌ ◌ range_map.insert(3..=4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◆ ◌ let outer_range = 1..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield gaps at start, between items, // and at end. assert_eq!(gaps.next(), Some(1..=2)); assert_eq!(gaps.next(), Some(5..=5)); assert_eq!(gaps.next(), Some(8..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_ending_at_end_of_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ●-● ◌ range_map.insert(7..=8, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◆ ◌ let outer_range = 5..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield from the start of the outer range // up to just before the start of the stored item. assert_eq!(gaps.next(), Some(5..=6)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_overlapping_end_of_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●---● ◌ ◌ range_map.insert(5..=6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-----◆ ◌ ◌ ◌ ◌ let outer_range = 2..=5; let mut gaps = range_map.gaps(&outer_range); // Should yield from the start of the outer range // up to the start of the stored item. assert_eq!(gaps.next(), Some(2..=4)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_touching_end_of_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●-----● ◌ range_map.insert(5..=9, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-----◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 1..=4; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(1..=4)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_after_outer_range() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ●---● ◌ range_map.insert(6..=7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-----◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 1..=4; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(1..=4)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn zero_width_outer_range_with_items_away_from_both_sides() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---◆ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=3, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆---◆ ◌ ◌ range_map.insert(5..=7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 4..=4; let mut gaps = range_map.gaps(&outer_range); // Should yield a zero-width gap. assert_eq!(gaps.next(), Some(4..=4)); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn zero_width_outer_range_with_items_touching_both_sides() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-◆ ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..=3, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆---◆ ◌ ◌ ◌ range_map.insert(5..=6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 4..=4; let mut gaps = range_map.gaps(&outer_range); // Should yield no gaps. assert_eq!(gaps.next(), Some(4..=4)); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn empty_outer_range_with_item_straddling() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-----◆ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..=5, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 4..=4; let mut gaps = range_map.gaps(&outer_range); // Should yield no gaps. assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn no_empty_gaps() { // Make two ranges different values so they don't // get coalesced. let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆-◆ ◌ ◌ ◌ ◌ range_map.insert(4..=5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-◆ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..=3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------------● ◌ let outer_range = 1..=8; let mut gaps = range_map.gaps(&outer_range); // Should yield gaps at start and end, but not between the // two touching items. assert_eq!(gaps.next(), Some(1..=1)); assert_eq!(gaps.next(), Some(6..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn no_overflow_finding_gaps_at_key_domain_extremes() { // Items and outer range both at extremes. let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=255, false); range_map.gaps(&(0..=255)); // Items at extremes with gaps in middle. let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=255, false); range_map.gaps(&(0..=5)); range_map.gaps(&(250..=255)); // Items just in from extremes. let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=255, false); range_map.gaps(&(1..=5)); range_map.gaps(&(250..=254)); // Outer range just in from extremes, // items at extremes. let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(1..=254, false); range_map.gaps(&(0..=5)); range_map.gaps(&(250..=255)); } #[test] fn adjacent_unit_width_items() { // Items two items next to each other at the start, and at the end. let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); range_map.insert(0..=0, false); range_map.insert(1..=1, true); range_map.insert(254..=254, false); range_map.insert(255..=255, true); let outer_range = 0..=255; let mut gaps = range_map.gaps(&outer_range); // Should yield one big gap in the middle. assert_eq!(gaps.next(), Some(2..=253)); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } // Overlapping tests #[test] fn overlapping_with_empty_map() { // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ let range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◆ ◌ let query_range = 1..=8; let mut overlapping = range_map.overlapping(&query_range); // Should not yield any items. assert_eq!(overlapping.next(), None); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); } #[test] fn overlapping_partial_edges_complete_middle() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ●-● ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(0..=1, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-● ◌ ◌ ◌ ◌ ◌ range_map.insert(3..=4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ●-● ◌ ◌ range_map.insert(6..=7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---------◆ ◌ ◌ ◌ let query_range = 1..=6; let mut overlapping = range_map.overlapping(&query_range); // Should yield partially overlapped range at start. assert_eq!(overlapping.next(), Some((&(0..=1), &()))); // Should yield completely overlapped range in middle. assert_eq!(overlapping.next(), Some((&(3..=4), &()))); // Should yield partially overlapped range at end. assert_eq!(overlapping.next(), Some((&(6..=7), &()))); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); assert_eq!(overlapping.next(), None); } #[test] fn overlapping_non_overlapping_edges_complete_middle() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ●-● ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(0..=1, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-● ◌ ◌ ◌ ◌ ◌ range_map.insert(3..=4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ●-● ◌ ◌ range_map.insert(6..=7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-----◆ ◌ ◌ ◌ ◌ let query_range = 2..=5; let mut overlapping = range_map.overlapping(&query_range); // Should only yield the completely overlapped range in middle. // (Not the ranges that are touched by not covered to either side.) assert_eq!(overlapping.next(), Some((&(3..=4), &()))); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); assert_eq!(overlapping.next(), None); } /// /// impl Debug /// #[test] fn map_debug_repr_looks_right() { let mut map: RangeInclusiveMap = RangeInclusiveMap::new(); // Empty assert_eq!(format!("{:?}", map), "{}"); // One entry map.insert(2..=5, ()); assert_eq!(format!("{:?}", map), "{2..=5: ()}"); // Many entries map.insert(7..=8, ()); map.insert(10..=11, ()); assert_eq!(format!("{:?}", map), "{2..=5: (), 7..=8: (), 10..=11: ()}"); } // impl Serialize #[cfg(feature = "serde1")] #[test] fn serialization() { let mut range_map: RangeInclusiveMap = RangeInclusiveMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---◆ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..=3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆---◆ ◌ ◌ range_map.insert(5..=7, true); let output = serde_json::to_string(&range_map).expect("Failed to serialize"); assert_eq!(output, "[[[1,3],false],[[5,7],true]]"); } // impl Deserialize #[cfg(feature = "serde1")] #[test] fn deserialization() { let input = "[[[1,3],false],[[5,7],true]]"; let range_map: RangeInclusiveMap = serde_json::from_str(input).expect("Failed to deserialize"); let reserialized = serde_json::to_string(&range_map).expect("Failed to re-serialize"); assert_eq!(reserialized, input); } // const fn #[cfg(feature = "const_fn")] const _MAP: RangeInclusiveMap = RangeInclusiveMap::new(); #[cfg(feature = "const_fn")] const _MAP2: RangeInclusiveMap = RangeInclusiveMap::new_with_step_fns(); } rangemap-1.3.0/src/inclusive_set.rs000064400000000000000000000374371046102023000154460ustar 00000000000000use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::iter::FromIterator; use core::ops::RangeInclusive; #[cfg(feature = "serde1")] use core::marker::PhantomData; #[cfg(feature = "serde1")] use serde::{ de::{Deserialize, Deserializer, SeqAccess, Visitor}, ser::{Serialize, Serializer}, }; use crate::std_ext::*; use crate::RangeInclusiveMap; #[derive(Clone)] /// A set whose items are stored as ranges bounded /// inclusively below and above `(start..=end)`. /// /// See [`RangeInclusiveMap`]'s documentation for more details. /// /// [`RangeInclusiveMap`]: struct.RangeInclusiveMap.html pub struct RangeInclusiveSet { rm: RangeInclusiveMap, } impl Default for RangeInclusiveSet where T: Ord + Clone + StepLite, { fn default() -> Self { Self::new() } } impl PartialEq for RangeInclusiveSet where T: PartialEq, { fn eq(&self, other: &RangeInclusiveSet) -> bool { self.rm == other.rm } } impl Eq for RangeInclusiveSet where T: Eq {} impl PartialOrd for RangeInclusiveSet where T: PartialOrd, { #[inline] fn partial_cmp(&self, other: &RangeInclusiveSet) -> Option { self.rm.partial_cmp(&other.rm) } } impl Ord for RangeInclusiveSet where T: Ord, { #[inline] fn cmp(&self, other: &RangeInclusiveSet) -> Ordering { self.rm.cmp(&other.rm) } } impl RangeInclusiveSet where T: Ord + Clone + StepLite, { /// Makes a new empty `RangeInclusiveSet`. #[cfg(feature = "const_fn")] pub const fn new() -> Self { Self::new_with_step_fns() } /// Makes a new empty `RangeInclusiveSet`. #[cfg(not(feature = "const_fn"))] pub fn new() -> Self { Self::new_with_step_fns() } } impl RangeInclusiveSet where T: Ord + Clone, StepFnsT: StepFns, { /// Makes a new empty `RangeInclusiveSet`, specifying successor and /// predecessor functions defined separately from `T` itself. /// /// This is useful as a workaround for Rust's "orphan rules", /// which prevent you from implementing `StepLite` for `T` if `T` /// is a foreign type. /// /// **NOTE:** This will likely be deprecated and then eventually /// removed once the standard library's [Step](core::iter::Step) /// trait is stabilised, as most crates will then likely implement [Step](core::iter::Step) /// for their types where appropriate. /// /// See [this issue](https://github.com/rust-lang/rust/issues/42168) /// for details about that stabilization process. #[cfg(not(feature = "const_fn"))] pub fn new_with_step_fns() -> Self { Self { rm: RangeInclusiveMap::new_with_step_fns(), } } #[cfg(feature = "const_fn")] pub const fn new_with_step_fns() -> Self { Self { rm: RangeInclusiveMap::new_with_step_fns(), } } /// Returns a reference to the range covering the given key, if any. pub fn get(&self, value: &T) -> Option<&RangeInclusive> { self.rm.get_key_value(value).map(|(range, _)| range) } /// Returns `true` if any range in the set covers the specified value. pub fn contains(&self, value: &T) -> bool { self.rm.contains_key(value) } /// Gets an ordered iterator over all ranges, /// ordered by range. pub fn iter(&self) -> Iter<'_, T> { Iter { inner: self.rm.iter(), } } /// Clears the set, removing all elements. pub fn clear(&mut self) { self.rm.clear(); } /// Returns the number of elements in the set. pub fn len(&self) -> usize { self.rm.len() } /// Returns true if the set contains no elements. pub fn is_empty(&self) -> bool { self.rm.is_empty() } /// Insert a range into the set. /// /// If the inserted range either overlaps or is immediately adjacent /// any existing range, then the ranges will be coalesced into /// a single contiguous range. /// /// # Panics /// /// Panics if range `start > end`. pub fn insert(&mut self, range: RangeInclusive) { self.rm.insert(range, ()); } /// Removes a range from the set, if all or any of it was present. /// /// If the range to be removed _partially_ overlaps any ranges /// in the set, then those ranges will be contracted to no /// longer cover the removed range. /// /// # Panics /// /// Panics if range `start > end`. pub fn remove(&mut self, range: RangeInclusive) { self.rm.remove(range); } /// Gets an iterator over all the maximally-sized ranges /// contained in `outer_range` that are not covered by /// any range stored in the set. /// /// The iterator element type is `RangeInclusive`. pub fn gaps<'a>(&'a self, outer_range: &'a RangeInclusive) -> Gaps<'a, T, StepFnsT> { Gaps { inner: self.rm.gaps(outer_range), } } /// Gets an iterator over all the stored ranges that are /// either partially or completely overlapped by the given range. /// /// The iterator element type is `RangeInclusive`. pub fn overlapping<'a>(&'a self, range: &'a RangeInclusive) -> Overlapping { Overlapping { inner: self.rm.overlapping(range), } } /// Returns `true` if any range in the set completely or partially /// overlaps the given range. pub fn overlaps(&self, range: &RangeInclusive) -> bool { self.overlapping(range).next().is_some() } } /// An iterator over the ranges of a `RangeInclusiveSet`. /// /// This `struct` is created by the [`iter`] method on [`RangeInclusiveSet`]. See its /// documentation for more. /// /// [`iter`]: RangeInclusiveSet::iter pub struct Iter<'a, T> { inner: super::inclusive_map::Iter<'a, T, ()>, } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a RangeInclusive; fn next(&mut self) -> Option<&'a RangeInclusive> { self.inner.next().map(|(range, _)| range) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } /// An owning iterator over the ranges of a `RangeInclusiveSet`. /// /// This `struct` is created by the [`into_iter`] method on [`RangeInclusiveSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter pub struct IntoIter { inner: super::inclusive_map::IntoIter, } impl IntoIterator for RangeInclusiveSet { type Item = RangeInclusive; type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.rm.into_iter(), } } } impl Iterator for IntoIter { type Item = RangeInclusive; fn next(&mut self) -> Option> { self.inner.next().map(|(range, _)| range) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // We can't just derive this automatically, because that would // expose irrelevant (and private) implementation details. // Instead implement it in the same way that the underlying BTreeSet does. impl Debug for RangeInclusiveSet where T: Ord + Clone + StepLite, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() } } impl FromIterator> for RangeInclusiveSet where T: Ord + Clone + StepLite, { fn from_iter>>(iter: I) -> Self { let mut range_set = RangeInclusiveSet::new(); range_set.extend(iter); range_set } } impl Extend> for RangeInclusiveSet where T: Ord + Clone + StepLite, { fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |range| { self.insert(range); }) } } #[cfg(feature = "serde1")] impl Serialize for RangeInclusiveSet where T: Ord + Clone + StepLite + Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { use serde::ser::SerializeSeq; let mut seq = serializer.serialize_seq(Some(self.rm.btm.len()))?; for range in self.iter() { seq.serialize_element(&(&range.start(), &range.end()))?; } seq.end() } } #[cfg(feature = "serde1")] impl<'de, T> Deserialize<'de> for RangeInclusiveSet where T: Ord + Clone + StepLite + Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(RangeInclusiveSetVisitor::new()) } } #[cfg(feature = "serde1")] struct RangeInclusiveSetVisitor { marker: PhantomData RangeInclusiveSet>, } #[cfg(feature = "serde1")] impl RangeInclusiveSetVisitor { fn new() -> Self { RangeInclusiveSetVisitor { marker: PhantomData, } } } #[cfg(feature = "serde1")] impl<'de, T> Visitor<'de> for RangeInclusiveSetVisitor where T: Ord + Clone + StepLite + Deserialize<'de>, { type Value = RangeInclusiveSet; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("RangeInclusiveSet") } fn visit_seq(self, mut access: A) -> Result where A: SeqAccess<'de>, { let mut range_inclusive_set = RangeInclusiveSet::new(); while let Some((start, end)) = access.next_element()? { range_inclusive_set.insert(start..=end); } Ok(range_inclusive_set) } } /// An iterator over all ranges not covered by a `RangeInclusiveSet`. /// /// This `struct` is created by the [`gaps`] method on [`RangeInclusiveSet`]. See its /// documentation for more. /// /// [`gaps`]: RangeInclusiveSet::gaps pub struct Gaps<'a, T, StepFnsT> { inner: crate::inclusive_map::Gaps<'a, T, (), StepFnsT>, } // `Gaps` is always fused. (See definition of `next` below.) impl<'a, T, StepFnsT> core::iter::FusedIterator for Gaps<'a, T, StepFnsT> where T: Ord + Clone, StepFnsT: StepFns, { } impl<'a, T, StepFnsT> Iterator for Gaps<'a, T, StepFnsT> where T: Ord + Clone, StepFnsT: StepFns, { type Item = RangeInclusive; fn next(&mut self) -> Option { self.inner.next() } } /// An iterator over all stored ranges partially or completely /// overlapped by a given range. /// /// This `struct` is created by the [`overlapping`] method on [`RangeInclusiveSet`]. See its /// documentation for more. /// /// [`overlapping`]: RangeInclusiveSet::overlapping pub struct Overlapping<'a, T> { inner: crate::inclusive_map::Overlapping<'a, T, ()>, } // `Overlapping` is always fused. (See definition of `next` below.) impl<'a, T> core::iter::FusedIterator for Overlapping<'a, T> where T: Ord + Clone {} impl<'a, T> Iterator for Overlapping<'a, T> where T: Ord + Clone, { type Item = &'a RangeInclusive; fn next(&mut self) -> Option { self.inner.next().map(|(k, _v)| k) } } #[cfg(test)] mod tests { use super::*; use alloc::{format, vec, vec::Vec}; trait RangeInclusiveSetExt { fn to_vec(&self) -> Vec>; } impl RangeInclusiveSetExt for RangeInclusiveSet where T: Ord + Clone + StepLite, { fn to_vec(&self) -> Vec> { self.iter().cloned().collect() } } #[test] fn empty_set_is_empty() { let range_set: RangeInclusiveSet = RangeInclusiveSet::new(); assert_eq!(range_set.to_vec(), vec![]); } #[test] fn insert_into_empty_map() { let mut range_set: RangeInclusiveSet = RangeInclusiveSet::new(); range_set.insert(0..=50); assert_eq!(range_set.to_vec(), vec![0..=50]); } #[test] fn remove_partially_overlapping() { let mut range_set: RangeInclusiveSet = RangeInclusiveSet::new(); range_set.insert(0..=50); range_set.remove(25..=75); assert_eq!(range_set.to_vec(), vec![0..=24]); } #[test] fn gaps_between_items_floating_inside_outer_range() { let mut range_set: RangeInclusiveSet = RangeInclusiveSet::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●-● ◌ ◌ ◌ range_set.insert(5..=6); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ●-● ◌ ◌ ◌ ◌ ◌ ◌ range_set.insert(2..=3); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◆ ◌ let outer_range = 1..=8; let mut gaps = range_set.gaps(&outer_range); // Should yield gaps at start, between items, // and at end. assert_eq!(gaps.next(), Some(1..=1)); assert_eq!(gaps.next(), Some(4..=4)); assert_eq!(gaps.next(), Some(7..=8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn overlapping_partial_edges_complete_middle() { let mut range_set: RangeInclusiveSet = RangeInclusiveSet::new(); // 0 1 2 3 4 5 6 7 8 9 // ●-● ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_set.insert(0..=1); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-● ◌ ◌ ◌ ◌ ◌ range_set.insert(3..=4); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ●-● ◌ ◌ range_set.insert(6..=7); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---------◆ ◌ ◌ ◌ let query_range = 1..=6; let mut overlapping = range_set.overlapping(&query_range); // Should yield partially overlapped range at start. assert_eq!(overlapping.next(), Some(&(0..=1))); // Should yield completely overlapped range in middle. assert_eq!(overlapping.next(), Some(&(3..=4))); // Should yield partially overlapped range at end. assert_eq!(overlapping.next(), Some(&(6..=7))); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); assert_eq!(overlapping.next(), None); } /// /// impl Debug /// #[test] fn set_debug_repr_looks_right() { let mut set: RangeInclusiveSet = RangeInclusiveSet::new(); // Empty assert_eq!(format!("{:?}", set), "{}"); // One entry set.insert(2..=5); assert_eq!(format!("{:?}", set), "{2..=5}"); // Many entries set.insert(7..=8); set.insert(10..=11); assert_eq!(format!("{:?}", set), "{2..=5, 7..=8, 10..=11}"); } // impl Serialize #[cfg(feature = "serde1")] #[test] fn serialization() { let mut range_set: RangeInclusiveSet = RangeInclusiveSet::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---◆ ◌ ◌ ◌ ◌ ◌ ◌ range_set.insert(1..=3); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆---◆ ◌ ◌ range_set.insert(5..=7); let output = serde_json::to_string(&range_set).expect("Failed to serialize"); assert_eq!(output, "[[1,3],[5,7]]"); } // impl Deserialize #[cfg(feature = "serde1")] #[test] fn deserialization() { let input = "[[1,3],[5,7]]"; let range_set: RangeInclusiveSet = serde_json::from_str(input).expect("Failed to deserialize"); let reserialized = serde_json::to_string(&range_set).expect("Failed to re-serialize"); assert_eq!(reserialized, input); } // const fn #[cfg(feature = "const_fn")] const _SET: RangeInclusiveSet = RangeInclusiveSet::new(); #[cfg(feature = "const_fn")] const _SET2: RangeInclusiveSet = RangeInclusiveSet::new_with_step_fns(); } rangemap-1.3.0/src/lib.rs000064400000000000000000000121541046102023000133250ustar 00000000000000/*! [`RangeMap`] and [`RangeInclusiveMap`] are map data structures whose keys are stored as ranges. Contiguous and overlapping ranges that map to the same value are coalesced into a single range. Corresponding [`RangeSet`] and [`RangeInclusiveSet`] structures are also provided. # Different kinds of ranges `RangeMap` and `RangeInclusiveMap` correspond to the [`Range`] and [`RangeInclusive`] types from the standard library respectively. For some applications the choice of range type may be obvious, or even be dictated by pre-existing design decisions. For other applications the choice may seem arbitrary, and be guided instead by convenience or aesthetic preference. If the choice is not obvious in your case, consider these differences: - If your key type `K` represents points on a continuum (e.g. `f64`), and the choice of which of two adjacent ranges "owns" the value where they touch is largely arbitrary, then it may be more natural to work with half-open `Range`s like `0.0..1.0` and `1.0..2.0`. If you were to use closed `RangeInclusive`s here instead, then to represent two such adjacent ranges you would need to subtract some infinitesimal (which may depend, as it does in the case of `f64`, on the specific value of `K`) from the end of the earlier range. (See the last point below for more on this problem.) - If you need to represent ranges that _include_ the maximum value in the key domain (e.g. `255u8`) then you will probably want to use `RangeInclusive`s like `128u8..=255u8`. Sometimes it may be possible to instead work around this by using a wider key type than the values you are actually trying to represent (`K=u16` even though you are only trying to represent ranges covering `u8`) but in these cases the key domain often represents discrete objects rather than points on a continuum, and so `RangeInclusive` may be a more natural way to express these ranges anyway. - If you are using `RangeInclusive`, then it must be possible to define _successor_ and _predecessor_ functions for your key type `K`, because adjacent ranges can not be detected (and thereby coalesced) simply by testing their ends for equality. For key types that represent points on a continuum, defining these functions may be awkward and error-prone. For key types that represent discrete objects, this is usually much more straightforward. # Example: use with Chrono ```rust use chrono::offset::TimeZone; use chrono::{Duration, Utc}; use rangemap::RangeMap; let people = ["Alice", "Bob", "Carol"]; let mut roster = RangeMap::new(); // Set up initial roster. let start_of_roster = Utc.ymd(2019, 1, 7); let mut week_start = start_of_roster; for _ in 0..3 { for person in &people { let next_week = week_start + Duration::weeks(1); roster.insert(week_start..next_week, person); week_start = next_week; } } // Bob is covering Alice's second shift (the fourth shift overall). let fourth_shift_start = start_of_roster + Duration::weeks(3); let fourth_shift_end = fourth_shift_start + Duration::weeks(1); roster.insert(fourth_shift_start..fourth_shift_end, &"Bob"); for (range, person) in roster.iter() { println!("{} ({}): {}", range.start, range.end - range.start, person); } // Output: // 2019-01-07UTC (P7D): Alice // 2019-01-14UTC (P7D): Bob // 2019-01-21UTC (P7D): Carol // 2019-01-28UTC (P14D): Bob // 2019-02-11UTC (P7D): Carol // 2019-02-18UTC (P7D): Alice // 2019-02-25UTC (P7D): Bob // 2019-03-04UTC (P7D): Carol ``` ## Crate features By default this crate has no dependencies on other crates. If you enable the **serde1** feature it will introduce a dependency on the _serde_ crate and provide `Serialize` and `Deserialize` implementations for all map and set types in this crate. You can enable the **serde1** feature in your _Cargo.toml_ file like so: ```toml [dependencies] rangemap = { version = "1", features = ["serde1"] } ``` ## Building without the Rust standard library This crate can work without the full standard library available (e.g. when running on bare metal without an operating system) but relies on the presence of a global allocator — i.e. it links the `core` and `alloc` crates, but not `std`. Presently there is no functionality in the crate that require the standard library. Such functionality will likely be introduced in the future, and will be gated behind a default-on `std` feature. See [The Rust Programming Language](https://doc.rust-lang.org/1.7.0/book/no-stdlib.html) book for general information about operating without the standard library. [`RangeMap`]: crate::RangeMap [`RangeInclusiveMap`]: crate::RangeInclusiveMap [`RangeSet`]: crate::RangeSet [`RangeInclusiveSet`]: crate::RangeInclusiveSet [`Range`]: core::ops::Range [`RangeInclusive`]: core::ops::RangeInclusive */ #![no_std] extern crate alloc; pub mod inclusive_map; pub mod inclusive_set; pub mod map; pub mod set; #[cfg(test)] mod dense; mod range_wrapper; mod std_ext; pub use inclusive_map::RangeInclusiveMap; pub use inclusive_set::RangeInclusiveSet; pub use map::RangeMap; pub use set::RangeSet; pub use std_ext::{StepFns, StepLite}; // Doc tests for README. #[cfg(feature = "nightly")] mod readme; rangemap-1.3.0/src/map.rs000064400000000000000000001460651046102023000133450ustar 00000000000000use super::range_wrapper::RangeStartWrapper; use crate::range_wrapper::RangeEndWrapper; use crate::std_ext::*; use alloc::collections::BTreeMap; use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::iter::FromIterator; use core::ops::{Bound, Range}; use core::prelude::v1::*; #[cfg(feature = "serde1")] use core::marker::PhantomData; #[cfg(feature = "serde1")] use serde::{ de::{Deserialize, Deserializer, SeqAccess, Visitor}, ser::{Serialize, Serializer}, }; /// A map whose keys are stored as (half-open) ranges bounded /// inclusively below and exclusively above `(start..end)`. /// /// Contiguous and overlapping ranges that map to the same value /// are coalesced into a single range. #[derive(Clone)] pub struct RangeMap { // Wrap ranges so that they are `Ord`. // See `range_wrapper.rs` for explanation. pub(crate) btm: BTreeMap, V>, } impl Default for RangeMap where K: Ord + Clone, V: Eq + Clone, { fn default() -> Self { Self::new() } } impl PartialEq for RangeMap where K: PartialEq, V: PartialEq, { fn eq(&self, other: &RangeMap) -> bool { self.btm == other.btm } } impl PartialOrd for RangeMap where K: PartialOrd, V: PartialOrd, { #[inline] fn partial_cmp(&self, other: &RangeMap) -> Option { self.btm.partial_cmp(&other.btm) } } impl Ord for RangeMap where K: Ord, V: Ord, { #[inline] fn cmp(&self, other: &RangeMap) -> Ordering { self.btm.cmp(&other.btm) } } impl Eq for RangeMap where K: Eq, V: Eq, { } impl RangeMap where K: Ord + Clone, V: Eq + Clone, { /// Makes a new empty `RangeMap`. #[cfg(feature = "const_fn")] pub const fn new() -> Self { RangeMap { btm: BTreeMap::new(), } } /// Makes a new empty `RangeMap`. #[cfg(not(feature = "const_fn"))] pub fn new() -> Self { RangeMap { btm: BTreeMap::new(), } } /// Returns a reference to the value corresponding to the given key, /// if the key is covered by any range in the map. pub fn get(&self, key: &K) -> Option<&V> { self.get_key_value(key).map(|(_range, value)| value) } /// Returns the range-value pair (as a pair of references) corresponding /// to the given key, if the key is covered by any range in the map. pub fn get_key_value(&self, key: &K) -> Option<(&Range, &V)> { // The only stored range that could contain the given key is the // last stored range whose start is less than or equal to this key. let key_as_start = RangeStartWrapper::new(key.clone()..key.clone()); self.btm .range((Bound::Unbounded, Bound::Included(key_as_start))) .next_back() .filter(|(start_wrapper, _value)| { // Does the only candidate range contain // the requested key? start_wrapper.end_wrapper.range.contains(key) }) .map(|(start_wrapper, value)| (&start_wrapper.end_wrapper.range, value)) } /// Returns `true` if any range in the map covers the specified key. pub fn contains_key(&self, key: &K) -> bool { self.get(key).is_some() } /// Gets an iterator over all pairs of key range and value, /// ordered by key range. /// /// The iterator element type is `(&'a Range, &'a V)`. pub fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.btm.iter(), } } /// Clears the map, removing all elements. pub fn clear(&mut self) { self.btm.clear(); } /// Returns the number of elements in the map. pub fn len(&self) -> usize { self.btm.len() } /// Returns true if the map contains no elements. pub fn is_empty(&self) -> bool { self.btm.is_empty() } /// Insert a pair of key range and value into the map. /// /// If the inserted range partially or completely overlaps any /// existing range in the map, then the existing range (or ranges) will be /// partially or completely replaced by the inserted range. /// /// If the inserted range either overlaps or is immediately adjacent /// any existing range _mapping to the same value_, then the ranges /// will be coalesced into a single contiguous range. /// /// # Panics /// /// Panics if range `start >= end`. pub fn insert(&mut self, range: Range, value: V) { // We don't want to have to make empty ranges make sense; // they don't represent anything meaningful in this structure. assert!(range.start < range.end); // Wrap up the given range so that we can "borrow" // it as a wrapper reference to either its start or end. // See `range_wrapper.rs` for explanation of these hacks. let mut new_start_wrapper: RangeStartWrapper = RangeStartWrapper::new(range); let new_value = value; // Is there a stored range either overlapping the start of // the range to insert or immediately preceding it? // // If there is any such stored range, it will be the last // whose start is less than or equal to the start of the range to insert, // or the one before that if both of the above cases exist. let mut candidates = self .btm .range::, (Bound<&RangeStartWrapper>, Bound<&RangeStartWrapper>)>(( Bound::Unbounded, Bound::Included(&new_start_wrapper), )) .rev() .take(2) .filter(|(stored_start_wrapper, _stored_value)| { // Does the candidate range either overlap // or immediately precede the range to insert? // (Remember that it might actually cover the _whole_ // range to insert and then some.) stored_start_wrapper .end_wrapper .range .touches(&new_start_wrapper.end_wrapper.range) }); if let Some(mut candidate) = candidates.next() { // Or the one before it if both cases described above exist. if let Some(another_candidate) = candidates.next() { candidate = another_candidate; } let (stored_start_wrapper, stored_value) = (candidate.0.clone(), candidate.1.clone()); self.adjust_touching_ranges_for_insert( stored_start_wrapper, stored_value, &mut new_start_wrapper.end_wrapper.range, &new_value, ); } // Are there any stored ranges whose heads overlap or immediately // follow the range to insert? // // If there are any such stored ranges (that weren't already caught above), // their starts will fall somewhere after the start of the range to insert, // and on or before its end. // // This time around, if the latter holds, it also implies // the former so we don't need to check here if they touch. // // REVISIT: Possible micro-optimisation: `impl Borrow for RangeStartWrapper` // and use that to search here, to avoid constructing another `RangeStartWrapper`. let new_range_end_as_start = RangeStartWrapper::new( new_start_wrapper.end_wrapper.range.end.clone() ..new_start_wrapper.end_wrapper.range.end.clone(), ); while let Some((stored_start_wrapper, stored_value)) = self .btm .range::, (Bound<&RangeStartWrapper>, Bound<&RangeStartWrapper>)>(( Bound::Included(&new_start_wrapper), Bound::Included(&new_range_end_as_start), )) .next() { // One extra exception: if we have different values, // and the stored range starts at the end of the range to insert, // then we don't want to keep looping forever trying to find more! #[allow(clippy::suspicious_operation_groupings)] if stored_start_wrapper.end_wrapper.range.start == new_start_wrapper.end_wrapper.range.end && *stored_value != new_value { // We're beyond the last stored range that could be relevant. // Avoid wasting time on irrelevant ranges, or even worse, looping forever. // (`adjust_touching_ranges_for_insert` below assumes that the given range // is relevant, and behaves very poorly if it is handed a range that it // shouldn't be touching.) break; } let stored_start_wrapper = stored_start_wrapper.clone(); let stored_value = stored_value.clone(); self.adjust_touching_ranges_for_insert( stored_start_wrapper, stored_value, &mut new_start_wrapper.end_wrapper.range, &new_value, ); } // Insert the (possibly expanded) new range, and we're done! self.btm.insert(new_start_wrapper, new_value); } /// Removes a range from the map, if all or any of it was present. /// /// If the range to be removed _partially_ overlaps any ranges /// in the map, then those ranges will be contracted to no /// longer cover the removed range. /// /// /// # Panics /// /// Panics if range `start >= end`. pub fn remove(&mut self, range: Range) { // We don't want to have to make empty ranges make sense; // they don't represent anything meaningful in this structure. assert!(range.start < range.end); let start_wrapper: RangeStartWrapper = RangeStartWrapper::new(range); let range = &start_wrapper.end_wrapper.range; // Is there a stored range overlapping the start of // the range to insert? // // If there is any such stored range, it will be the last // whose start is less than or equal to the start of the range to insert. if let Some((stored_start_wrapper, stored_value)) = self .btm .range::, (Bound<&RangeStartWrapper>, Bound<&RangeStartWrapper>)>((Bound::Unbounded, Bound::Included(&start_wrapper))) .next_back() .filter(|(stored_start_wrapper, _stored_value)| { // Does the only candidate range overlap // the range to insert? stored_start_wrapper .end_wrapper .range .overlaps(range) }) .map(|(stored_start_wrapper, stored_value)| { (stored_start_wrapper.clone(), stored_value.clone()) }) { self.adjust_overlapping_ranges_for_remove( stored_start_wrapper, stored_value, range, ); } // Are there any stored ranges whose heads overlap the range to insert? // // If there are any such stored ranges (that weren't already caught above), // their starts will fall somewhere after the start of the range to insert, // and before its end. // // REVISIT: Possible micro-optimisation: `impl Borrow for RangeStartWrapper` // and use that to search here, to avoid constructing another `RangeStartWrapper`. let new_range_end_as_start = RangeStartWrapper::new(range.end.clone()..range.end.clone()); while let Some((stored_start_wrapper, stored_value)) = self .btm .range::, (Bound<&RangeStartWrapper>, Bound<&RangeStartWrapper>)>(( Bound::Excluded(&start_wrapper), Bound::Excluded(&new_range_end_as_start), )) .next() .map(|(stored_start_wrapper, stored_value)| { (stored_start_wrapper.clone(), stored_value.clone()) }) { self.adjust_overlapping_ranges_for_remove( stored_start_wrapper, stored_value, range, ); } } fn adjust_touching_ranges_for_insert( &mut self, stored_start_wrapper: RangeStartWrapper, stored_value: V, new_range: &mut Range, new_value: &V, ) { use core::cmp::{max, min}; if stored_value == *new_value { // The ranges have the same value, so we can "adopt" // the stored range. // // This means that no matter how big or where the stored range is, // we will expand the new range's bounds to subsume it, // and then delete the stored range. new_range.start = min(&new_range.start, &stored_start_wrapper.start).clone(); new_range.end = max(&new_range.end, &stored_start_wrapper.end).clone(); self.btm.remove(&stored_start_wrapper); } else { // The ranges have different values. if new_range.overlaps(&stored_start_wrapper.range) { // The ranges overlap. This is a little bit more complicated. // Delete the stored range, and then add back between // 0 and 2 subranges at the ends of the range to insert. self.btm.remove(&stored_start_wrapper); if stored_start_wrapper.start < new_range.start { // Insert the piece left of the range to insert. self.btm.insert( RangeStartWrapper::new( stored_start_wrapper.end_wrapper.range.start..new_range.start.clone(), ), stored_value.clone(), ); } if stored_start_wrapper.end_wrapper.range.end > new_range.end { // Insert the piece right of the range to insert. self.btm.insert( RangeStartWrapper::new( new_range.end.clone()..stored_start_wrapper.end_wrapper.range.end, ), stored_value, ); } } else { // No-op; they're not overlapping, // so we can just keep both ranges as they are. } } } fn adjust_overlapping_ranges_for_remove( &mut self, stored: RangeStartWrapper, stored_value: V, range_to_remove: &Range, ) { // Delete the stored range, and then add back between // 0 and 2 subranges at the ends of the range to insert. self.btm.remove(&stored); let stored_range = stored.end_wrapper; if stored_range.start < range_to_remove.start { // Insert the piece left of the range to insert. self.btm.insert( RangeStartWrapper::new(stored_range.range.start..range_to_remove.start.clone()), stored_value.clone(), ); } if stored_range.range.end > range_to_remove.end { // Insert the piece right of the range to insert. self.btm.insert( RangeStartWrapper::new(range_to_remove.end.clone()..stored_range.range.end), stored_value, ); } } /// Gets an iterator over all the maximally-sized ranges /// contained in `outer_range` that are not covered by /// any range stored in the map. /// /// If the start and end of the outer range are the same /// and it does not overlap any stored range, then a single /// empty gap will be returned. /// /// The iterator element type is `Range`. pub fn gaps<'a>(&'a self, outer_range: &'a Range) -> Gaps<'a, K, V> { Gaps { outer_range, keys: self.btm.keys(), // We'll start the candidate range at the start of the outer range // without checking what's there. Each time we yield an item, // we'll skip any ranges we find before the next gap. candidate_start: &outer_range.start, } } /// Gets an iterator over all the stored ranges that are /// either partially or completely overlapped by the given range. pub fn overlapping<'a>(&'a self, range: &'a Range) -> Overlapping { // Find the first matching stored range by its _end_, // using sneaky layering and `Borrow` implementation. (See `range_wrappers` module.) let start_sliver = RangeEndWrapper::new(range.start.clone()..range.start.clone()); let btm_range_iter = self .btm .range::, (Bound<&RangeEndWrapper>, Bound<_>)>(( Bound::Excluded(&start_sliver), Bound::Unbounded, )); Overlapping { query_range: range, btm_range_iter, } } /// Returns `true` if any range in the map completely or partially /// overlaps the given range. pub fn overlaps(&self, range: &Range) -> bool { self.overlapping(range).next().is_some() } } /// An iterator over the entries of a `RangeMap`, ordered by key range. /// /// The iterator element type is `(&'a Range, &'a V)`. /// /// This `struct` is created by the [`iter`] method on [`RangeMap`]. See its /// documentation for more. /// /// [`iter`]: RangeMap::iter pub struct Iter<'a, K, V> { inner: alloc::collections::btree_map::Iter<'a, RangeStartWrapper, V>, } impl<'a, K, V> Iterator for Iter<'a, K, V> where K: 'a, V: 'a, { type Item = (&'a Range, &'a V); fn next(&mut self) -> Option<(&'a Range, &'a V)> { self.inner .next() .map(|(by_start, v)| (&by_start.end_wrapper.range, v)) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } /// An owning iterator over the entries of a `RangeMap`, ordered by key range. /// /// The iterator element type is `(Range, V)`. /// /// This `struct` is created by the [`into_iter`] method on [`RangeMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter pub struct IntoIter { inner: alloc::collections::btree_map::IntoIter, V>, } impl IntoIterator for RangeMap { type Item = (Range, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.btm.into_iter(), } } } impl Iterator for IntoIter { type Item = (Range, V); fn next(&mut self) -> Option<(Range, V)> { self.inner .next() .map(|(by_start, v)| (by_start.end_wrapper.range, v)) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // We can't just derive this automatically, because that would // expose irrelevant (and private) implementation details. // Instead implement it in the same way that the underlying BTreeMap does. impl Debug for RangeMap where K: Ord + Clone, V: Eq + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() } } impl FromIterator<(Range, V)> for RangeMap where K: Ord + Clone, V: Eq + Clone, { fn from_iter, V)>>(iter: T) -> Self { let mut range_map = RangeMap::new(); range_map.extend(iter); range_map } } impl Extend<(Range, V)> for RangeMap where K: Ord + Clone, V: Eq + Clone, { fn extend, V)>>(&mut self, iter: T) { iter.into_iter().for_each(move |(k, v)| { self.insert(k, v); }) } } #[cfg(feature = "serde1")] impl Serialize for RangeMap where K: Ord + Clone + Serialize, V: Eq + Clone + Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { use serde::ser::SerializeSeq; let mut seq = serializer.serialize_seq(Some(self.btm.len()))?; for (k, v) in self.iter() { seq.serialize_element(&((&k.start, &k.end), &v))?; } seq.end() } } #[cfg(feature = "serde1")] impl<'de, K, V> Deserialize<'de> for RangeMap where K: Ord + Clone + Deserialize<'de>, V: Eq + Clone + Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(RangeMapVisitor::new()) } } #[cfg(feature = "serde1")] struct RangeMapVisitor { marker: PhantomData RangeMap>, } #[cfg(feature = "serde1")] impl RangeMapVisitor { fn new() -> Self { RangeMapVisitor { marker: PhantomData, } } } #[cfg(feature = "serde1")] impl<'de, K, V> Visitor<'de> for RangeMapVisitor where K: Ord + Clone + Deserialize<'de>, V: Eq + Clone + Deserialize<'de>, { type Value = RangeMap; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("RangeMap") } fn visit_seq(self, mut access: A) -> Result where A: SeqAccess<'de>, { let mut range_map = RangeMap::new(); while let Some(((start, end), value)) = access.next_element()? { range_map.insert(start..end, value); } Ok(range_map) } } /// An iterator over all ranges not covered by a `RangeMap`. /// /// The iterator element type is `Range`. /// /// This `struct` is created by the [`gaps`] method on [`RangeMap`]. See its /// documentation for more. /// /// [`gaps`]: RangeMap::gaps pub struct Gaps<'a, K, V> { outer_range: &'a Range, keys: alloc::collections::btree_map::Keys<'a, RangeStartWrapper, V>, candidate_start: &'a K, } // `Gaps` is always fused. (See definition of `next` below.) impl<'a, K, V> core::iter::FusedIterator for Gaps<'a, K, V> where K: Ord + Clone {} impl<'a, K, V> Iterator for Gaps<'a, K, V> where K: Ord + Clone, { type Item = Range; fn next(&mut self) -> Option { for item in &mut self.keys { let range = &item.range; if range.end <= *self.candidate_start { // We're already completely past it; ignore it. } else if range.start <= *self.candidate_start { // We're inside it; move past it. self.candidate_start = &range.end; } else if range.start < self.outer_range.end { // It starts before the end of the outer range, // so move past it and then yield a gap. let gap = self.candidate_start.clone()..range.start.clone(); self.candidate_start = &range.end; return Some(gap); } } // Now that we've run out of items, the only other possible // gap is at the end of the outer range. if *self.candidate_start < self.outer_range.end { // There's a gap at the end! let gap = self.candidate_start.clone()..self.outer_range.end.clone(); // We're done; skip to the end so we don't try to find any more. self.candidate_start = &self.outer_range.end; Some(gap) } else { // We got to the end; there can't be any more gaps. None } } } /// An iterator over all stored ranges partially or completely /// overlapped by a given range. /// /// The iterator element type is `(&'a Range, &'a V)`. /// /// This `struct` is created by the [`overlapping`] method on [`RangeMap`]. See its /// documentation for more. /// /// [`overlapping`]: RangeMap::overlapping pub struct Overlapping<'a, K, V> { query_range: &'a Range, btm_range_iter: alloc::collections::btree_map::Range<'a, RangeStartWrapper, V>, } // `Overlapping` is always fused. (See definition of `next` below.) impl<'a, K, V> core::iter::FusedIterator for Overlapping<'a, K, V> where K: Ord + Clone {} impl<'a, K, V> Iterator for Overlapping<'a, K, V> where K: Ord + Clone, { type Item = (&'a Range, &'a V); fn next(&mut self) -> Option { if let Some((k, v)) = self.btm_range_iter.next() { if k.start < self.query_range.end { Some((&k.range, v)) } else { // The rest of the items in the underlying iterator // are past the query range. We can keep taking items // from that iterator and this will remain true, // so this is enough to make the iterator fused. None } } else { None } } } #[cfg(test)] mod tests { use super::*; use alloc::{format, vec, vec::Vec}; trait RangeMapExt { fn to_vec(&self) -> Vec<(Range, V)>; } impl RangeMapExt for RangeMap where K: Ord + Clone, V: Eq + Clone, { fn to_vec(&self) -> Vec<(Range, V)> { self.iter().map(|(kr, v)| (kr.clone(), v.clone())).collect() } } // // Insertion tests // #[test] fn empty_map_is_empty() { let range_map: RangeMap = RangeMap::new(); assert_eq!(range_map.to_vec(), vec![]); } #[test] fn insert_into_empty_map() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..50, false); assert_eq!(range_map.to_vec(), vec![(0..50, false)]); } #[test] fn new_same_value_immediately_following_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ range_map.insert(3..5, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------◌ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..5, false)]); } #[test] fn new_different_value_immediately_following_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ range_map.insert(3..5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..3, false), (3..5, true)]); } #[test] fn new_same_value_overlapping_end_of_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-----◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ range_map.insert(3..5, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------◌ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..5, false)]); } #[test] fn new_different_value_overlapping_end_of_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-----◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ range_map.insert(3..5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..3, false), (3..5, true)]); } #[test] fn new_same_value_immediately_preceding_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ range_map.insert(3..5, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------◌ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..5, false)]); } #[test] fn new_different_value_immediately_preceding_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ range_map.insert(3..5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..3, false), (3..5, true)]); } #[test] fn new_same_value_wholly_inside_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------◌ ◌ ◌ ◌ ◌ range_map.insert(1..5, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------◌ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..5, false)]); } #[test] fn new_different_value_wholly_inside_stored() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------◇ ◌ ◌ ◌ ◌ range_map.insert(1..5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌ // ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ assert_eq!( range_map.to_vec(), vec![(1..2, true), (2..4, false), (4..5, true)] ); } #[test] fn replace_at_end_of_existing_range_should_coalesce() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ range_map.insert(3..5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ range_map.insert(3..5, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------◌ ◌ ◌ ◌ ◌ assert_eq!(range_map.to_vec(), vec![(1..5, false)]); } #[test] // Test every permutation of a bunch of touching and overlapping ranges. fn lots_of_interesting_ranges() { use crate::dense::DenseU32RangeMap; use permutator::Permutation; let mut ranges_with_values = [ (2..3, false), // A duplicate duplicates (2..3, false), // Almost a duplicate, but with a different value (2..3, true), // A few small ranges, some of them overlapping others, // some of them touching others (3..5, true), (4..6, true), (5..7, true), // A really big range (2..6, true), ]; ranges_with_values.permutation().for_each(|permutation| { let mut range_map: RangeMap = RangeMap::new(); let mut dense: DenseU32RangeMap = DenseU32RangeMap::new(); for (k, v) in permutation { // Insert it into both maps. range_map.insert(k.clone(), v); // NOTE: Clippy's `range_minus_one` lint is a bit overzealous here, // because we _can't_ pass an open-ended range to `insert`. #[allow(clippy::range_minus_one)] dense.insert(k.start..=(k.end - 1), v); // At every step, both maps should contain the same stuff. let sparse = range_map.to_vec(); let dense = dense.to_end_exclusive_vec(); assert_eq!(sparse, dense); } }); } // // Get* tests // #[test] fn get() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..50, false); assert_eq!(range_map.get(&49), Some(&false)); assert_eq!(range_map.get(&50), None); } #[test] fn get_key_value() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..50, false); assert_eq!(range_map.get_key_value(&49), Some((&(0..50), &false))); assert_eq!(range_map.get_key_value(&50), None); } // // Removal tests // #[test] fn remove_from_empty_map() { let mut range_map: RangeMap = RangeMap::new(); range_map.remove(0..50); assert_eq!(range_map.to_vec(), vec![]); } #[test] fn remove_non_covered_range_before_stored() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(25..75, false); range_map.remove(0..25); assert_eq!(range_map.to_vec(), vec![(25..75, false)]); } #[test] fn remove_non_covered_range_after_stored() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(25..75, false); range_map.remove(75..100); assert_eq!(range_map.to_vec(), vec![(25..75, false)]); } #[test] fn remove_overlapping_start_of_stored() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(25..75, false); range_map.remove(0..30); assert_eq!(range_map.to_vec(), vec![(30..75, false)]); } #[test] fn remove_middle_of_stored() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(25..75, false); range_map.remove(30..70); assert_eq!(range_map.to_vec(), vec![(25..30, false), (70..75, false)]); } #[test] fn remove_overlapping_end_of_stored() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(25..75, false); range_map.remove(70..100); assert_eq!(range_map.to_vec(), vec![(25..70, false)]); } #[test] fn remove_exactly_stored() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(25..75, false); range_map.remove(25..75); assert_eq!(range_map.to_vec(), vec![]); } #[test] fn remove_superset_of_stored() { let mut range_map: RangeMap = RangeMap::new(); range_map.insert(25..75, false); range_map.remove(0..100); assert_eq!(range_map.to_vec(), vec![]); } // Gaps tests #[test] fn whole_range_is_a_gap() { // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ let range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◇ ◌ let outer_range = 1..8; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(1..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn whole_range_is_covered_exactly() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---------◌ ◌ ◌ ◌ range_map.insert(1..6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---------◇ ◌ ◌ ◌ let outer_range = 1..6; let mut gaps = range_map.gaps(&outer_range); // Should yield no gaps. assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_before_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌ let outer_range = 5..8; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(5..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_touching_start_of_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●-------◌ ◌ ◌ ◌ ◌ range_map.insert(1..5, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌ let outer_range = 5..8; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(5..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_overlapping_start_of_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ●---------◌ ◌ ◌ ◌ range_map.insert(1..6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌ let outer_range = 5..8; let mut gaps = range_map.gaps(&outer_range); // Should yield from the end of the stored item // to the end of the outer range. assert_eq!(gaps.next(), Some(6..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_starting_at_start_of_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ range_map.insert(5..6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌ let outer_range = 5..8; let mut gaps = range_map.gaps(&outer_range); // Should yield from the item onwards. assert_eq!(gaps.next(), Some(6..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn items_floating_inside_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ range_map.insert(5..6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(3..4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◇ ◌ let outer_range = 1..8; let mut gaps = range_map.gaps(&outer_range); // Should yield gaps at start, between items, // and at end. assert_eq!(gaps.next(), Some(1..3)); assert_eq!(gaps.next(), Some(4..5)); assert_eq!(gaps.next(), Some(6..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_ending_at_end_of_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ●-◌ ◌ range_map.insert(7..8, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌ let outer_range = 5..8; let mut gaps = range_map.gaps(&outer_range); // Should yield from the start of the outer range // up to the start of the stored item. assert_eq!(gaps.next(), Some(5..7)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_overlapping_end_of_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ range_map.insert(4..6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-----◇ ◌ ◌ ◌ ◌ let outer_range = 2..5; let mut gaps = range_map.gaps(&outer_range); // Should yield from the start of the outer range // up to the start of the stored item. assert_eq!(gaps.next(), Some(2..4)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_touching_end_of_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ●-------◌ ◌ range_map.insert(4..8, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-----◇ ◌ ◌ ◌ ◌ ◌ let outer_range = 1..4; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(1..4)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn item_after_outer_range() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ●---◌ ◌ range_map.insert(6..7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-----◇ ◌ ◌ ◌ ◌ ◌ let outer_range = 1..4; let mut gaps = range_map.gaps(&outer_range); // Should yield the entire outer range. assert_eq!(gaps.next(), Some(1..4)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn empty_outer_range_with_items_away_from_both_sides() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌ range_map.insert(5..7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 4..4; let mut gaps = range_map.gaps(&outer_range); // Should not yield any gaps, because a zero-width outer range covers no values. assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); } #[test] fn empty_outer_range_with_items_touching_both_sides() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ range_map.insert(4..6, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 4..4; let mut gaps = range_map.gaps(&outer_range); // Should yield no gaps. assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn empty_outer_range_with_item_straddling() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-----◇ ◌ ◌ ◌ ◌ ◌ range_map.insert(2..5, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌ let outer_range = 4..4; let mut gaps = range_map.gaps(&outer_range); // Should yield no gaps. assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn no_empty_gaps() { // Make two ranges different values so they don't // get coalesced. let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ range_map.insert(4..5, true); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(3..4, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◇ ◌ let outer_range = 1..8; let mut gaps = range_map.gaps(&outer_range); // Should yield gaps at start and end, but not between the // two touching items. (4 is covered, so there should be no gap.) assert_eq!(gaps.next(), Some(1..3)); assert_eq!(gaps.next(), Some(5..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn adjacent_small_items() { // Items two items next to each other at the start, and at the end. let mut range_map: RangeMap = RangeMap::new(); range_map.insert(0..1, false); range_map.insert(1..2, true); range_map.insert(253..254, false); range_map.insert(254..255, true); let outer_range = 0..255; let mut gaps = range_map.gaps(&outer_range); // Should yield one big gap in the middle. assert_eq!(gaps.next(), Some(2..253)); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } // This test fails in v1.0.2 #[test] fn outer_range_lies_within_first_of_two_stored_ranges() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◆----------◇ ◌ ◌ ◌ ◌ range_map.insert(0..5, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌◌ ◌ ◆---◇ ◌ range_map.insert(6..8, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆--◇ ◌ ◌ ◌ ◌ ◌ let outer_range: Range = 1..3; let mut gaps = range_map.gaps(&outer_range); assert_eq!(gaps.next(), None); } // Overlapping tests #[test] fn overlapping_with_empty_map() { // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ let range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◇ ◌ let query_range = 1..8; let mut overlapping = range_map.overlapping(&query_range); // Should not yield any items. assert_eq!(overlapping.next(), None); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); } #[test] fn overlapping_partial_edges_complete_middle() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(0..2, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(3..4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●---◌ ◌ ◌ range_map.insert(5..7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---------◇ ◌ ◌ ◌ let query_range = 1..6; let mut overlapping = range_map.overlapping(&query_range); // Should yield partially overlapped range at start. assert_eq!(overlapping.next(), Some((&(0..2), &()))); // Should yield completely overlapped range in middle. assert_eq!(overlapping.next(), Some((&(3..4), &()))); // Should yield partially overlapped range at end. assert_eq!(overlapping.next(), Some((&(5..7), &()))); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); assert_eq!(overlapping.next(), None); } #[test] fn overlapping_non_overlapping_edges_complete_middle() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(0..2, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(3..4, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●---◌ ◌ ◌ range_map.insert(5..7, ()); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◆-----◇ ◌ ◌ ◌ ◌ let query_range = 2..5; let mut overlapping = range_map.overlapping(&query_range); // Should only yield the completely overlapped range in middle. // (Not the ranges that are touched by not covered to either side.) assert_eq!(overlapping.next(), Some((&(3..4), &()))); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); assert_eq!(overlapping.next(), None); } /// /// impl Debug /// #[test] fn map_debug_repr_looks_right() { let mut map: RangeMap = RangeMap::new(); // Empty assert_eq!(format!("{:?}", map), "{}"); // One entry map.insert(2..5, ()); assert_eq!(format!("{:?}", map), "{2..5: ()}"); // Many entries map.insert(6..7, ()); map.insert(8..9, ()); assert_eq!(format!("{:?}", map), "{2..5: (), 6..7: (), 8..9: ()}"); } // Iterator Tests #[test] fn into_iter_matches_iter() { // Just use vec since that's the same implementation we'd expect let mut range_map: RangeMap = RangeMap::new(); range_map.insert(1..3, false); range_map.insert(3..5, true); let cloned = range_map.to_vec(); let consumed = range_map.into_iter().collect::>(); // Correct value assert_eq!(cloned, vec![(1..3, false), (3..5, true)]); // Equality assert_eq!(cloned, consumed); } // impl Serialize #[cfg(feature = "serde1")] #[test] fn serialization() { let mut range_map: RangeMap = RangeMap::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(1..3, false); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌ range_map.insert(5..7, true); let output = serde_json::to_string(&range_map).expect("Failed to serialize"); assert_eq!(output, "[[[1,3],false],[[5,7],true]]"); } // impl Deserialize #[cfg(feature = "serde1")] #[test] fn deserialization() { let input = "[[[1,3],false],[[5,7],true]]"; let range_map: RangeMap = serde_json::from_str(input).expect("Failed to deserialize"); let reserialized = serde_json::to_string(&range_map).expect("Failed to re-serialize"); assert_eq!(reserialized, input); } // const fn #[cfg(feature = "const_fn")] const _MAP: RangeMap = RangeMap::new(); } rangemap-1.3.0/src/range_wrapper.rs000064400000000000000000000144101046102023000154100ustar 00000000000000// Wrappers to allow storing (and sorting/searching) // ranges as the keys of a `BTreeMap`. // // This wraps the range in two layers: one that lets us // order ranges by their start (`RangeStartWrapper`), // and then within that, one that lets us order them by // their end (`RangeEndWrapper`). Ordinarily we'll use // the former, but there are a couple of cases where we // want to be able to do the latter for performance/convenience. // // This is made possible by a sneaky `Borrow` implementation // which skirts the law about the borrowed representation // having identical implementations of `Ord` etc., but shouldn't // be a problem in practice because users of the crate can't // access these special wrappers, and we are careful to uphold // invariants that prevent observing any states where the // differing implementations would produce different results. // // Specifically, we maintain the invariants // that the order of range starts is the same as the order // of range ends, and that no two stored ranges have the // same start or end as each other. // // NOTE: Be very careful not to accidentally use these // if you really do want to compare equality of the // inner range! use core::cmp::Ordering; use core::ops::{Deref, Range, RangeInclusive}; // // Range start wrapper // #[derive(Debug, Clone)] pub struct RangeStartWrapper { pub end_wrapper: RangeEndWrapper, } impl RangeStartWrapper { pub fn new(range: Range) -> RangeStartWrapper { RangeStartWrapper { end_wrapper: RangeEndWrapper::new(range), } } } impl PartialEq for RangeStartWrapper where T: PartialEq, { fn eq(&self, other: &RangeStartWrapper) -> bool { self.start == other.start } } impl Eq for RangeStartWrapper where T: Eq {} impl Ord for RangeStartWrapper where T: Ord, { fn cmp(&self, other: &RangeStartWrapper) -> Ordering { self.start.cmp(&other.start) } } impl PartialOrd for RangeStartWrapper where T: PartialOrd, { fn partial_cmp(&self, other: &RangeStartWrapper) -> Option { self.start.partial_cmp(&other.start) } } impl core::borrow::Borrow> for RangeStartWrapper { fn borrow(&self) -> &RangeEndWrapper { &self.end_wrapper } } // Avoid the need to tediously plumb through the layers of wrapper structs // when you're just trying to access members of the inner range itself. impl Deref for RangeStartWrapper { type Target = RangeEndWrapper; fn deref(&self) -> &Self::Target { &self.end_wrapper } } // // Range end wrapper // #[derive(Debug, Clone)] pub struct RangeEndWrapper { pub range: Range, } impl RangeEndWrapper { pub fn new(range: Range) -> RangeEndWrapper { RangeEndWrapper { range } } } impl PartialEq for RangeEndWrapper where T: PartialEq, { fn eq(&self, other: &RangeEndWrapper) -> bool { self.end == other.end } } impl Eq for RangeEndWrapper where T: Eq {} impl Ord for RangeEndWrapper where T: Ord, { fn cmp(&self, other: &RangeEndWrapper) -> Ordering { self.end.cmp(&other.end) } } impl PartialOrd for RangeEndWrapper where T: PartialOrd, { fn partial_cmp(&self, other: &RangeEndWrapper) -> Option { self.end.partial_cmp(&other.end) } } // Avoid the need to tediously plumb through the layers of wrapper structs // when you're just trying to access members of the inner range itself. impl Deref for RangeEndWrapper { type Target = Range; fn deref(&self) -> &Self::Target { &self.range } } // // RangeInclusive start wrapper // #[derive(Eq, Debug, Clone)] pub struct RangeInclusiveStartWrapper { pub end_wrapper: RangeInclusiveEndWrapper, } impl RangeInclusiveStartWrapper { pub fn new(range: RangeInclusive) -> RangeInclusiveStartWrapper { RangeInclusiveStartWrapper { end_wrapper: RangeInclusiveEndWrapper::new(range), } } } impl PartialEq for RangeInclusiveStartWrapper where T: PartialEq, { fn eq(&self, other: &RangeInclusiveStartWrapper) -> bool { self.start() == other.start() } } impl Ord for RangeInclusiveStartWrapper where T: Ord, { fn cmp(&self, other: &RangeInclusiveStartWrapper) -> Ordering { self.start().cmp(other.start()) } } impl PartialOrd for RangeInclusiveStartWrapper where T: PartialOrd, { fn partial_cmp(&self, other: &RangeInclusiveStartWrapper) -> Option { self.start().partial_cmp(other.start()) } } impl core::borrow::Borrow> for RangeInclusiveStartWrapper { fn borrow(&self) -> &RangeInclusiveEndWrapper { &self.end_wrapper } } // Avoid the need to tediously plumb through the layers of wrapper structs // when you're just trying to access members of the inner range itself. impl Deref for RangeInclusiveStartWrapper { type Target = RangeInclusiveEndWrapper; fn deref(&self) -> &Self::Target { &self.end_wrapper } } // // RangeInclusive end wrapper // #[derive(Eq, Debug, Clone)] pub struct RangeInclusiveEndWrapper { pub range: RangeInclusive, } impl RangeInclusiveEndWrapper { pub fn new(range: RangeInclusive) -> RangeInclusiveEndWrapper { RangeInclusiveEndWrapper { range } } } impl PartialEq for RangeInclusiveEndWrapper where T: PartialEq, { fn eq(&self, other: &RangeInclusiveEndWrapper) -> bool { self.end() == other.end() } } impl Ord for RangeInclusiveEndWrapper where T: Ord, { fn cmp(&self, other: &RangeInclusiveEndWrapper) -> Ordering { self.end().cmp(other.end()) } } impl PartialOrd for RangeInclusiveEndWrapper where T: PartialOrd, { fn partial_cmp(&self, other: &RangeInclusiveEndWrapper) -> Option { self.end().partial_cmp(other.end()) } } // Avoid the need to tediously plumb through the layers of wrapper structs // when you're just trying to access members of the inner range itself. impl Deref for RangeInclusiveEndWrapper { type Target = RangeInclusive; fn deref(&self) -> &Self::Target { &self.range } } rangemap-1.3.0/src/readme.rs000064400000000000000000000000701046102023000140060ustar 00000000000000#[doc = include_str!("../README.md")] struct _Readme {} rangemap-1.3.0/src/set.rs000064400000000000000000000332241046102023000133530ustar 00000000000000use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::iter::FromIterator; use core::ops::Range; use core::prelude::v1::*; #[cfg(feature = "serde1")] use core::marker::PhantomData; #[cfg(feature = "serde1")] use serde::{ de::{Deserialize, Deserializer, SeqAccess, Visitor}, ser::{Serialize, Serializer}, }; use crate::RangeMap; #[derive(Clone)] /// A set whose items are stored as (half-open) ranges bounded /// inclusively below and exclusively above `(start..end)`. /// /// See [`RangeMap`]'s documentation for more details. /// /// [`RangeMap`]: struct.RangeMap.html pub struct RangeSet { rm: RangeMap, } impl Default for RangeSet where T: Ord + Clone, { fn default() -> Self { RangeSet::new() } } impl PartialEq for RangeSet where T: PartialEq, { fn eq(&self, other: &RangeSet) -> bool { self.rm == other.rm } } impl Eq for RangeSet where T: Eq {} impl PartialOrd for RangeSet where T: PartialOrd, { #[inline] fn partial_cmp(&self, other: &RangeSet) -> Option { self.rm.partial_cmp(&other.rm) } } impl Ord for RangeSet where T: Ord, { #[inline] fn cmp(&self, other: &RangeSet) -> Ordering { self.rm.cmp(&other.rm) } } impl RangeSet where T: Ord + Clone, { /// Makes a new empty `RangeSet`. #[cfg(feature = "const_fn")] pub const fn new() -> Self { RangeSet { rm: RangeMap::new(), } } /// Makes a new empty `RangeSet`. #[cfg(not(feature = "const_fn"))] pub fn new() -> Self { RangeSet { rm: RangeMap::new(), } } /// Returns a reference to the range covering the given key, if any. pub fn get(&self, value: &T) -> Option<&Range> { self.rm.get_key_value(value).map(|(range, _)| range) } /// Returns `true` if any range in the set covers the specified value. pub fn contains(&self, value: &T) -> bool { self.rm.contains_key(value) } /// Gets an ordered iterator over all ranges, /// ordered by range. pub fn iter(&self) -> Iter<'_, T> { Iter { inner: self.rm.iter(), } } /// Clears the set, removing all elements. pub fn clear(&mut self) { self.rm.clear(); } /// Returns the number of elements in the set. pub fn len(&self) -> usize { self.rm.len() } /// Returns true if the set contains no elements. pub fn is_empty(&self) -> bool { self.rm.is_empty() } /// Insert a range into the set. /// /// If the inserted range either overlaps or is immediately adjacent /// any existing range, then the ranges will be coalesced into /// a single contiguous range. /// /// # Panics /// /// Panics if range `start >= end`. pub fn insert(&mut self, range: Range) { self.rm.insert(range, ()); } /// Removes a range from the set, if all or any of it was present. /// /// If the range to be removed _partially_ overlaps any ranges /// in the set, then those ranges will be contracted to no /// longer cover the removed range. /// /// # Panics /// /// Panics if range `start >= end`. pub fn remove(&mut self, range: Range) { self.rm.remove(range); } /// Gets an iterator over all the maximally-sized ranges /// contained in `outer_range` that are not covered by /// any range stored in the set. /// /// If the start and end of the outer range are the same /// and it does not overlap any stored range, then a single /// empty gap will be returned. /// /// The iterator element type is `Range`. pub fn gaps<'a>(&'a self, outer_range: &'a Range) -> Gaps<'a, T> { Gaps { inner: self.rm.gaps(outer_range), } } /// Gets an iterator over all the stored ranges that are /// either partially or completely overlapped by the given range. /// /// The iterator element type is `&Range`. pub fn overlapping<'a>(&'a self, range: &'a Range) -> Overlapping { Overlapping { inner: self.rm.overlapping(range), } } /// Returns `true` if any range in the set completely or partially /// overlaps the given range. pub fn overlaps(&self, range: &Range) -> bool { self.overlapping(range).next().is_some() } } /// An iterator over the ranges of a `RangeSet`. /// /// This `struct` is created by the [`iter`] method on [`RangeSet`]. See its /// documentation for more. /// /// [`iter`]: RangeSet::iter pub struct Iter<'a, T> { inner: super::map::Iter<'a, T, ()>, } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a Range; fn next(&mut self) -> Option<&'a Range> { self.inner.next().map(|(range, _)| range) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } /// An owning iterator over the ranges of a `RangeSet`. /// /// This `struct` is created by the [`into_iter`] method on [`RangeSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter pub struct IntoIter { inner: super::map::IntoIter, } impl IntoIterator for RangeSet { type Item = Range; type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.rm.into_iter(), } } } impl Iterator for IntoIter { type Item = Range; fn next(&mut self) -> Option> { self.inner.next().map(|(range, _)| range) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // We can't just derive this automatically, because that would // expose irrelevant (and private) implementation details. // Instead implement it in the same way that the underlying BTreeSet does. impl Debug for RangeSet where T: Ord + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() } } impl FromIterator> for RangeSet where T: Ord + Clone, { fn from_iter>>(iter: I) -> Self { let mut range_set = RangeSet::new(); range_set.extend(iter); range_set } } impl Extend> for RangeSet where T: Ord + Clone, { fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |range| { self.insert(range); }) } } #[cfg(feature = "serde1")] impl Serialize for RangeSet where T: Ord + Clone + Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { use serde::ser::SerializeSeq; let mut seq = serializer.serialize_seq(Some(self.rm.btm.len()))?; for range in self.iter() { seq.serialize_element(&(&range.start, &range.end))?; } seq.end() } } #[cfg(feature = "serde1")] impl<'de, T> Deserialize<'de> for RangeSet where T: Ord + Clone + Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(RangeSetVisitor::new()) } } #[cfg(feature = "serde1")] struct RangeSetVisitor { marker: PhantomData RangeSet>, } #[cfg(feature = "serde1")] impl RangeSetVisitor { fn new() -> Self { RangeSetVisitor { marker: PhantomData, } } } #[cfg(feature = "serde1")] impl<'de, T> Visitor<'de> for RangeSetVisitor where T: Ord + Clone + Deserialize<'de>, { type Value = RangeSet; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("RangeSet") } fn visit_seq(self, mut access: A) -> Result where A: SeqAccess<'de>, { let mut range_set = RangeSet::new(); while let Some((start, end)) = access.next_element()? { range_set.insert(start..end); } Ok(range_set) } } /// An iterator over all ranges not covered by a `RangeSet`. /// /// This `struct` is created by the [`gaps`] method on [`RangeSet`]. See its /// documentation for more. /// /// [`gaps`]: RangeSet::gaps pub struct Gaps<'a, T> { inner: crate::map::Gaps<'a, T, ()>, } // `Gaps` is always fused. (See definition of `next` below.) impl<'a, T> core::iter::FusedIterator for Gaps<'a, T> where T: Ord + Clone {} impl<'a, T> Iterator for Gaps<'a, T> where T: Ord + Clone, { type Item = Range; fn next(&mut self) -> Option { self.inner.next() } } /// An iterator over all stored ranges partially or completely /// overlapped by a given range. /// /// This `struct` is created by the [`overlapping`] method on [`RangeSet`]. See its /// documentation for more. /// /// [`overlapping`]: RangeSet::overlapping pub struct Overlapping<'a, T> { inner: crate::map::Overlapping<'a, T, ()>, } // `Overlapping` is always fused. (See definition of `next` below.) impl<'a, T> core::iter::FusedIterator for Overlapping<'a, T> where T: Ord + Clone {} impl<'a, T> Iterator for Overlapping<'a, T> where T: Ord + Clone, { type Item = &'a Range; fn next(&mut self) -> Option { self.inner.next().map(|(k, _v)| k) } } #[cfg(test)] mod tests { use super::*; use alloc::{format, vec, vec::Vec}; trait RangeSetExt { fn to_vec(&self) -> Vec>; } impl RangeSetExt for RangeSet where T: Ord + Clone, { fn to_vec(&self) -> Vec> { self.iter().cloned().collect() } } #[test] fn empty_set_is_empty() { let range_set: RangeSet = RangeSet::new(); assert_eq!(range_set.to_vec(), vec![]); } #[test] fn insert_into_empty_map() { let mut range_set: RangeSet = RangeSet::new(); range_set.insert(0..50); assert_eq!(range_set.to_vec(), vec![0..50]); } #[test] fn remove_partially_overlapping() { let mut range_set: RangeSet = RangeSet::new(); range_set.insert(0..50); range_set.remove(25..75); assert_eq!(range_set.to_vec(), vec![0..25]); } #[test] fn gaps_between_items_floating_inside_outer_range() { let mut range_set: RangeSet = RangeSet::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ range_set.insert(5..6); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ range_set.insert(3..4); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆-------------◇ ◌ let outer_range = 1..8; let mut gaps = range_set.gaps(&outer_range); // Should yield gaps at start, between items, // and at end. assert_eq!(gaps.next(), Some(1..3)); assert_eq!(gaps.next(), Some(4..5)); assert_eq!(gaps.next(), Some(6..8)); assert_eq!(gaps.next(), None); // Gaps iterator should be fused. assert_eq!(gaps.next(), None); assert_eq!(gaps.next(), None); } #[test] fn overlapping_partial_edges_complete_middle() { let mut range_map: RangeSet = RangeSet::new(); // 0 1 2 3 4 5 6 7 8 9 // ●---◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(0..2); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ range_map.insert(3..4); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ●---◌ ◌ ◌ range_map.insert(5..7); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---------◇ ◌ ◌ ◌ let query_range = 1..6; let mut overlapping = range_map.overlapping(&query_range); // Should yield partially overlapped range at start. assert_eq!(overlapping.next(), Some(&(0..2))); // Should yield completely overlapped range in middle. assert_eq!(overlapping.next(), Some(&(3..4))); // Should yield partially overlapped range at end. assert_eq!(overlapping.next(), Some(&(5..7))); // Gaps iterator should be fused. assert_eq!(overlapping.next(), None); assert_eq!(overlapping.next(), None); } /// /// impl Debug /// #[test] fn set_debug_repr_looks_right() { let mut set: RangeSet = RangeSet::new(); // Empty assert_eq!(format!("{:?}", set), "{}"); // One entry set.insert(2..5); assert_eq!(format!("{:?}", set), "{2..5}"); // Many entries set.insert(7..8); set.insert(10..11); assert_eq!(format!("{:?}", set), "{2..5, 7..8, 10..11}"); } // impl Serialize #[cfg(feature = "serde1")] #[test] fn serialization() { let mut range_set: RangeSet = RangeSet::new(); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌ ◌ range_set.insert(1..3); // 0 1 2 3 4 5 6 7 8 9 // ◌ ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌ range_set.insert(5..7); let output = serde_json::to_string(&range_set).expect("Failed to serialize"); assert_eq!(output, "[[1,3],[5,7]]"); } // impl Deserialize #[cfg(feature = "serde1")] #[test] fn deserialization() { let input = "[[1,3],[5,7]]"; let range_set: RangeSet = serde_json::from_str(input).expect("Failed to deserialize"); let reserialized = serde_json::to_string(&range_set).expect("Failed to re-serialize"); assert_eq!(reserialized, input); } // const fn #[cfg(feature = "const_fn")] const _SET: RangeSet = RangeSet::new(); } rangemap-1.3.0/src/std_ext.rs000064400000000000000000000140751046102023000142350ustar 00000000000000use core::ops::{Add, Range, RangeInclusive, Sub}; pub trait RangeExt { fn overlaps(&self, other: &Self) -> bool; fn touches(&self, other: &Self) -> bool; } impl RangeExt for Range where T: Ord, { fn overlaps(&self, other: &Self) -> bool { use core::cmp::{max, min}; // Strictly less than, because ends are excluded. max(&self.start, &other.start) < min(&self.end, &other.end) } fn touches(&self, other: &Self) -> bool { use core::cmp::{max, min}; // Less-than-or-equal-to because if one end is excluded, the other is included. // I.e. the two could be joined into a single range, because they're overlapping // or immediately adjacent. max(&self.start, &other.start) <= min(&self.end, &other.end) } } pub trait RangeInclusiveExt { fn overlaps(&self, other: &Self) -> bool; fn touches(&self, other: &Self) -> bool where StepFnsT: StepFns; } impl RangeInclusiveExt for RangeInclusive where T: Ord + Clone, { fn overlaps(&self, other: &Self) -> bool { use core::cmp::{max, min}; // Less than or equal, because ends are included. max(self.start(), other.start()) <= min(self.end(), other.end()) } fn touches(&self, other: &Self) -> bool where StepFnsT: StepFns, { use core::cmp::{max, min}; // Touching for end-inclusive ranges is equivalent to touching of // slightly longer end-inclusive ranges. // // We need to do a small dance to avoid arithmetic overflow // at the extremes of the key space. And to do this without // needing to bound our key type on something like `num::Bounded` // (https://docs.rs/num/0.3.0/num/trait.Bounded.html), // we'll just extend the end of the _earlier_ range iff // its end is already earlier than the latter range's start. let max_start = max(self.start(), other.start()); let min_range_end = min(self.end(), other.end()); let min_range_end_extended = if min_range_end < max_start { StepFnsT::add_one(min_range_end) } else { min_range_end.clone() }; *max_start <= min_range_end_extended } } /// Minimal version of unstable [`Step`](core::iter::Step) trait /// from the Rust standard library. /// /// This is needed for [`RangeInclusiveMap`](crate::RangeInclusiveMap) /// because ranges stored as its keys interact with each other /// when the start of one is _adjacent_ the end of another. /// I.e. we need a concept of successor values rather than just /// equality, and that is what `Step` will /// eventually provide once it is stabilized. /// /// **NOTE:** This will likely be deprecated and then eventually /// removed once the standard library's `Step` /// trait is stabilised, as most crates will then likely implement `Step` /// for their types where appropriate. /// /// See [this issue](https://github.com/rust-lang/rust/issues/42168) /// for details about that stabilization process. pub trait StepLite { /// Returns the _successor_ of `self`. /// /// If this would overflow the range of values supported by `Self`, /// this function is allowed to panic, wrap, or saturate. /// The suggested behavior is to panic when debug assertions are enabled, /// and to wrap or saturate otherwise. fn add_one(&self) -> Self; /// Returns the _predecessor_ of `self`. /// /// If this would overflow the range of values supported by `Self`, /// this function is allowed to panic, wrap, or saturate. /// The suggested behavior is to panic when debug assertions are enabled, /// and to wrap or saturate otherwise. fn sub_one(&self) -> Self; } // Implement for all common integer types. macro_rules! impl_step_lite { ($($t:ty)*) => ($( impl StepLite for $t { #[inline] fn add_one(&self) -> Self { Add::add(*self, 1) } #[inline] fn sub_one(&self) -> Self { Sub::sub(*self, 1) } } )*) } impl_step_lite!(usize u8 u16 u32 u64 u128 i8 i16 i32 i64 i128); // TODO: When on nightly, a blanket implementation for // all types that implement `core::iter::Step` instead // of the auto-impl above. /// Successor and predecessor functions defined for `T`, /// but as free functions rather than methods on `T` itself. /// /// This is useful as a workaround for Rust's "orphan rules", /// which prevent you from implementing [`StepLite`](crate::StepLite) for `T` if `T` /// is a foreign type. /// /// **NOTE:** This will likely be deprecated and then eventually /// removed once the standard library's [`Step`](core::iter::Step) /// trait is stabilised, as most crates will then likely implement `Step` /// for their types where appropriate. /// /// See [this issue](https://github.com/rust-lang/rust/issues/42168) /// for details about that stabilization process. /// /// There is also a blanket implementation of `StepFns` for all /// types implementing `StepLite`. Consumers of this crate should /// prefer to implement `StepLite` for their own types, and only /// fall back to `StepFns` when dealing with foreign types. pub trait StepFns { /// Returns the _successor_ of value `start`. /// /// If this would overflow the range of values supported by `Self`, /// this function is allowed to panic, wrap, or saturate. /// The suggested behavior is to panic when debug assertions are enabled, /// and to wrap or saturate otherwise. fn add_one(start: &T) -> T; /// Returns the _predecessor_ of value `start`. /// /// If this would overflow the range of values supported by `Self`, /// this function is allowed to panic, wrap, or saturate. /// The suggested behavior is to panic when debug assertions are enabled, /// and to wrap or saturate otherwise. fn sub_one(start: &T) -> T; } impl StepFns for T where T: StepLite, { fn add_one(start: &T) -> T { start.add_one() } fn sub_one(start: &T) -> T { start.sub_one() } }