From 2b4aeab092ecd41e47e1c9ddb4eb7540bb92816b Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Thu, 27 Jun 2024 16:24:48 -0500 Subject: [PATCH] wip --- .gitignore | 2 + Cargo.lock | 618 +++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 + rustfmt.toml | 1 + src/lib.rs | 160 +++++++++++ src/rbtree.rs | 153 +++++++++++ src/rbtree_mem.rs | 80 ++++++ src/rbtree_sqlite.rs | 1 + src/util.rs | 15 ++ test.sh | 5 + test.sql | 9 + 11 files changed, 1056 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 rustfmt.toml create mode 100644 src/lib.rs create mode 100644 src/rbtree.rs create mode 100644 src/rbtree_mem.rs create mode 100644 src/rbtree_sqlite.rs create mode 100644 src/util.rs create mode 100755 test.sh create mode 100644 test.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54466f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target + diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..93b9e42 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,618 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bindgen" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cc" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_lex", + "indexmap", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "contracts" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d1429e3bd78171c65aa010eabcdf8f863ba3254728dbfb0ad4b1545beac15c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "interval-tree" +version = "0.1.0" +dependencies = [ + "contracts", + "itertools", + "sqlite-loadable", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "serde_json" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "sqlite-loadable" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a916b7bb8738eef189dea88731b619b80bf3f62b3acf05138fa43fbf8621cc94" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde_json", + "sqlite-loadable-macros", + "sqlite3ext-sys", +] + +[[package]] +name = "sqlite-loadable-macros" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98bc75a8d6fd24f6a2cfea34f28758780fa17279d3051eec926efa381971e48" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sqlite3ext-sys" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afdc2b3dc08f16d6eecf8aa07d19975a268603ab1cca67d3f9b4172c507cf16" +dependencies = [ + "bindgen", + "cc", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..37213f2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "interval-tree" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type=["cdylib"] + +[dependencies] +contracts = { version = "0.6.3", features = ["mirai_assertions"] } +itertools = "0.13.0" +sqlite-loadable = "0.0.5" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..6f2e075 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +tab_spaces = 2 \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c7dde4a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,160 @@ +#[macro_use] +extern crate contracts; + +// #[macro_use] +// pub mod util; + +// pub mod rbtree; +// pub mod rbtree_mem; +// pub mod rbtree_sqlite; + +use std::os::raw::{c_char, c_int, c_uint}; +use std::ptr::{null, null_mut}; + +use itertools::Itertools; +use sqlite_loadable::define_virtual_table_writeable; +use sqlite_loadable::prelude::{ + register_entrypoint, sqlite3, sqlite3_api_routines, sqlite3_context, sqlite3_value, sqlite3_vtab, + sqlite3_vtab_cursor, sqlite_entrypoint, +}; +use sqlite_loadable::table::{ + IndexInfo, UpdateOperation, VTab, VTabArguments, VTabCursor, VTabWriteable, +}; +use sqlite_loadable::{api, BestIndexError, Result as SqResult}; + +#[sqlite_entrypoint] +pub fn sqlite3_intervaltree_init(db: *mut sqlite3) -> SqResult<()> { + define_virtual_table_writeable::(db, "interval_tree", Some(()))?; + + // define_virtual_table_writeable_with_transactions::( + // db, + // "interval_tree", + // Some(()), + // )?; + + Ok(()) +} + +#[repr(C)] +struct IntervalTreeTable { + base: sqlite3_vtab, +} + +impl IntervalTreeTable { + fn init( + db: *mut sqlite3, + aux: Option<&::Aux>, + args: VTabArguments, + is_create: bool, + ) -> SqResult<(String, Self)> { + println!("SHIET {aux:?} {:?}", args.arguments); + let table = Self { + base: sqlite3_vtab { + pModule: null(), + nRef: 0, + zErrMsg: null_mut(), + }, + }; + let create_sql = if is_create { + format!( + " + CREATE TABLE {orig}_values ({}); + CREATE TABLE {orig}_rbtree ( + rowid INTEGER PRIMARY KEY AUTOINCREMENT, + parent INTEGER, + left_child INTEGER, + right_child INTEGER + ); + ", + args + .arguments + .into_iter() + .map(|arg| format!("{arg}")) + .join(", "), + orig = args.table_name, + ) + } else { + String::new() + }; + println!("SQL: {}", create_sql); + Ok((create_sql, table)) + } +} + +impl<'a> VTab<'a> for IntervalTreeTable { + type Aux = (); + + type Cursor = IntervalTreeTableCursor; + + fn create( + db: *mut sqlite3, + aux: Option<&Self::Aux>, + args: VTabArguments, + ) -> SqResult<(String, Self)> { + Self::init(db, aux, args, true) + } + + fn connect( + db: *mut sqlite3, + aux: Option<&Self::Aux>, + args: VTabArguments, + ) -> SqResult<(String, Self)> { + Self::init(db, aux, args, false) + } + + fn best_index(&self, info: IndexInfo) -> Result<(), BestIndexError> { + todo!() + } + + fn open(&'a mut self) -> SqResult { + Ok(IntervalTreeTableCursor::new()) + } +} + +impl<'a> VTabWriteable<'a> for IntervalTreeTable { + fn update(&'a mut self, operation: UpdateOperation, p_rowid: *mut i64) -> SqResult<()> { + println!("Operation: {:?}", operation); + println!("Rowid: {}", unsafe { *p_rowid }); + todo!() + } +} + +#[repr(C)] +struct IntervalTreeTableCursor { + base: sqlite3_vtab_cursor, +} + +impl IntervalTreeTableCursor { + pub fn new() -> Self { + IntervalTreeTableCursor { + base: sqlite3_vtab_cursor { pVtab: null_mut() }, + } + } +} + +impl VTabCursor for IntervalTreeTableCursor { + fn filter( + &mut self, + idx_num: c_int, + idx_str: Option<&str>, + values: &[*mut sqlite3_value], + ) -> SqResult<()> { + todo!() + } + + fn next(&mut self) -> SqResult<()> { + todo!() + } + + fn eof(&self) -> bool { + todo!() + } + + fn column(&self, ctx: *mut sqlite3_context, i: c_int) -> SqResult<()> { + todo!() + } + + fn rowid(&self) -> SqResult { + todo!() + } +} diff --git a/src/rbtree.rs b/src/rbtree.rs new file mode 100644 index 0000000..41561f5 --- /dev/null +++ b/src/rbtree.rs @@ -0,0 +1,153 @@ +pub trait Bool { + fn mk_true() -> Self; + fn mk_false() -> Self; + fn if_then_else(&self, a: T, b: T) -> T; + fn value(&self) -> bool; +} + +pub trait Color { + fn is_red(&self) -> Bool; + fn is_black(&self) -> Bool; +} + +#[contract_trait] +pub trait Tree: Sized { + type Bool: Bool; + type NodeId: Clone; + type NodeIter: NodeIter; + type Color: Color; + + #[ensures(self.property2().value())] + #[ensures(self.property3().value())] + #[ensures(self.property4().value())] + #[ensures(self.property5().value())] + fn root(&self) -> Option; + + fn node_color(&self, id: &Self::NodeId) -> Self::Color; + + fn node_parent(&self, id: &Self::NodeId) -> Option; + + fn node_get_left(&self, id: &Self::NodeId) -> Option; + + fn node_get_right(&self, id: &Self::NodeId) -> Option; + + fn node_set_left(&mut self, id: &Self::NodeId, child: Option); + + fn node_set_right(&mut self, id: &Self::NodeId, child: Option); + + #[inline] + fn node_is_leaf(&self, id: &Self::NodeId) -> bool { + self.node_get_left(id).is_none() && self.node_get_right(id).is_none() + } + + #[inline] + fn node_is_red(&self, id: &Self::NodeId) -> Self::Bool { + self.node_color(id).is_red() + } + + #[inline] + fn node_is_black(&self, id: &Self::NodeId) -> Self::Bool { + self.node_color(id).is_black() + } + + #[inline] + fn node_path_length(&self, id: Self::NodeId) -> usize { + let mut ctr = 0; + let mut curr = id; + + while let Some(parent) = self.node_parent(&curr) { + ctr += 1; + curr = parent; + } + + ctr + } + + // #[inline] + // fn node_iter<'a>(&'a self) -> NodeIter<'a, Self> { + // let mut queue = VecDeque::new(); + // if let Some(root) = self.root() { + // queue.push_back(root); + // } + // NodeIter { tree: self, queue } + // } + + /// Property 2: The root is black + fn property2(&self) -> Self::Bool { + self + .root() + .map(|root| self.node_is_black(&root)) + .unwrap_or(true) + } + + /// Property 3: Every leaf is black + fn property3(&self) -> Self::Bool { + self + .node_iter() + .filter(|node| self.node_is_leaf(node)) + .all(|node| self.node_is_black(&node)) + } + + /// Property 4: If a node is red, then both its children are black + fn property4(&self) -> Self::Bool { + self + .node_iter() + .filter(|node| self.node_is_red(node)) + .all(|node| { + self + .node_get_left(&node) + .map(|node| self.node_is_black(&node)) + .unwrap_or(true) + && self + .node_get_right(&node) + .map(|node| self.node_is_black(&node)) + .unwrap_or(true) + }) + } + + /// Property 5: all paths take the same number of black nodes + fn property5(&self) -> Self::Bool { + let mut iter = self + .node_iter() + .filter(|node| self.node_is_leaf(node)) + .map(|node| self.node_path_length(node)); + + let first = match iter.next() { + Some(n) => n, + None => return true, + }; + + iter.all(|m| m == first) + } +} + +pub trait NodeIter { + fn next(&mut self) -> Option; +} + +// pub struct NodeIter<'a, T: Tree + Sized> { +// tree: &'a T, +// queue: VecDeque, +// } + +// impl<'a, T: Tree + Sized> Iterator for NodeIter<'a, T> { +// type Item = T::NodeId; + +// #[inline] +// fn next(&mut self) -> Option { +// let node = match self.queue.pop_front() { +// Some(n) => n, +// None => return None, +// }; + +// if let Some(left) = self.tree.node_get_left(&node) { +// self.queue.push_back(left); +// } + +// if let Some(right) = self.tree.node_get_right(&node) { +// self.queue.push_back(right); +// } + +// Some(node) +// } +// } diff --git a/src/rbtree_mem.rs b/src/rbtree_mem.rs new file mode 100644 index 0000000..32cd6f8 --- /dev/null +++ b/src/rbtree_mem.rs @@ -0,0 +1,80 @@ +use crate::rbtree::{self, Tree}; + +pub struct RbTreeMem { + root: Option, + nodes: Vec>, +} + +struct RbNodeMem { + parent: Option, + left_child: Option, + right_child: Option, + color: Color, + data: T, +} + +impl RbTreeMem { + pub fn node_data(&self, id: &usize) -> &T { + &self.nodes[*id].data + } +} + +#[contract_trait] +impl Tree for RbTreeMem { + type NodeId = usize; + + fn root(&self) -> Option { + self.root + } + + fn node_color(&self, id: &usize) -> Color { + self.nodes[*id].color + } + + fn node_parent(&self, id: &usize) -> Option { + self.nodes[*id].parent + } + + fn node_get_left(&self, id: &usize) -> Option { + self.nodes[*id].left_child + } + + fn node_get_right(&self, id: &usize) -> Option { + self.nodes[*id].right_child + } + + fn node_set_left(&mut self, id: &usize, child: Option) { + self.nodes[*id].left_child = child; + } + + fn node_set_right(&mut self, id: &usize, child: Option) { + self.nodes[*id].right_child = child; + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test() {} +} + +pub enum Color { + Red, + Black, +} + +impl rbtree::Color for Color { + fn is_red(&self) -> B { + match self { + Color::Red => B::mk_true(), + Color::Black => B::mk_false(), + } + } + + fn is_black(&self) -> B { + match self { + Color::Red => B::mk_false(), + Color::Black => B::mk_true(), + } + } +} diff --git a/src/rbtree_sqlite.rs b/src/rbtree_sqlite.rs new file mode 100644 index 0000000..7dc0480 --- /dev/null +++ b/src/rbtree_sqlite.rs @@ -0,0 +1 @@ +pub struct RbTreeSqlite {} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..412e291 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,15 @@ +macro_rules! debug_checked_precondition { + ($condition:expr, $($arg:tt)*) => ( debug_assert!($condition, $($arg)*); ); +} + +macro_rules! debug_checked_postcondition { + ($condition:expr, $($arg:tt)*) => ( debug_assert!($condition, $($arg)*); ); +} + +macro_rules! checked_precondition { + ($condition:expr, $($arg:tt)*) => ( assert!($condition, $($arg)*); ); +} + +macro_rules! checked_postcondition { + ($condition:expr, $($arg:tt)*) => ( assert!($condition, $($arg)*); ); +} diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..1ae7309 --- /dev/null +++ b/test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +cargo build -q + +sqlite3 ':memory:' '.read test.sql' \ No newline at end of file diff --git a/test.sql b/test.sql new file mode 100644 index 0000000..c5ffb4f --- /dev/null +++ b/test.sql @@ -0,0 +1,9 @@ +.header on + +.load target/debug/libinterval_tree + +CREATE VIRTUAL TABLE helloge USING interval_tree(id, start, end); + +INSERT INTO helloge (start, end) VALUES (10, 20); + +SELECT * FROM helloge_rbtree; \ No newline at end of file