diff --git a/benchmark/0011.containers/.test_prop.toml b/benchmark/0011.containers/.test_prop.toml new file mode 100644 index 000000000..3d86d282b --- /dev/null +++ b/benchmark/0011.containers/.test_prop.toml @@ -0,0 +1,3 @@ +["str_btree_set"] +ignore = true + diff --git a/benchmark/0011.containers/str_btree_set/abseil_btree_set.cc b/benchmark/0011.containers/str_btree_set/abseil_btree_set.cc new file mode 100644 index 000000000..20f78a132 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/abseil_btree_set.cc @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include "gentest.h" + +int main() +{ + auto vec{::gentest<::std::string>()}; + ::fast_io::timer t(u8"str_btree_set"); + ::absl::btree_set bset; + { + ::fast_io::timer t(u8"insert"); + for (auto const &e : vec) + { + bset.insert(e); + } + } + { + ::std::size_t count{}; + { + ::fast_io::timer t(u8"contains"); + for (auto const &e : vec) + { + count += static_cast<::std::size_t>(bset.contains(e)); + } + } + ::fast_io::io::perrln("count=", count); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"iteration"); + for (auto const &e : bset) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"reverse iteration"); + for (auto const &e : ::std::ranges::reverse_view(bset)) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } +} diff --git a/benchmark/0011.containers/str_btree_set/abseil_btree_set_fast_io.cc b/benchmark/0011.containers/str_btree_set/abseil_btree_set_fast_io.cc new file mode 100644 index 000000000..ed8df2844 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/abseil_btree_set_fast_io.cc @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include "gentest.h" + +int main() +{ + auto vec{::gentest()}; + ::fast_io::timer t(u8"str_btree_set"); + ::absl::btree_set<::fast_io::string> bset; + { + ::fast_io::timer t(u8"insert"); + for (auto const &e : vec) + { + bset.insert(e); + } + } + { + ::std::size_t count{}; + { + ::fast_io::timer t(u8"contains"); + for (auto const &e : vec) + { + count += static_cast<::std::size_t>(bset.contains(e)); + } + } + ::fast_io::io::perrln("count=", count); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"iteration"); + for (auto const &e : bset) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"reverse iteration"); + for (auto const &e : ::std::ranges::reverse_view(bset)) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } +} \ No newline at end of file diff --git a/benchmark/0011.containers/str_btree_set/gentest.h b/benchmark/0011.containers/str_btree_set/gentest.h new file mode 100644 index 000000000..fd04bb9e1 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/gentest.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +template +inline ::fast_io::vector gentest() +{ + ::fast_io::vector vec; + ::std::mt19937_64 eng; + ::std::uniform_int_distribution ud(0, 61); + ::std::uniform_int_distribution rlen(25, 30); + for (::std::size_t i{}; i != 1000000; ++i) + { + T tempstr; + ::std::size_t n{rlen(eng)}; + tempstr.reserve(n); + for (::std::size_t j{}; j != n; ++j) + { + char8_t ch(static_cast(ud(eng))); + if (ch < 10u) + { + ch += u8'0'; + } + else if (ch < 36u) + { + ch = ch - 10u + u8'a'; + } + else + { + ch = ch - 36u + u8'A'; + } + tempstr.push_back(ch); + } + vec.emplace_back(::std::move(tempstr)); + } + return vec; +} diff --git a/benchmark/0011.containers/str_btree_set/rustbtree/Cargo.toml b/benchmark/0011.containers/str_btree_set/rustbtree/Cargo.toml new file mode 100644 index 000000000..4e55cdbb2 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/rustbtree/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rustbtree" +version = "0.1.0" +edition = "2024" + +[dependencies] +rand = "0.9.1" diff --git a/benchmark/0011.containers/str_btree_set/rustbtree/src/main.rs b/benchmark/0011.containers/str_btree_set/rustbtree/src/main.rs new file mode 100644 index 000000000..cf61a68b3 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/rustbtree/src/main.rs @@ -0,0 +1,77 @@ +use rand::rngs::StdRng; +use rand::{Rng, SeedableRng}; +use std::collections::BTreeSet; +use std::time::Instant; + +fn generate_test_data() -> Vec { + let mut vec = Vec::with_capacity(1_000_000); + let mut rng = StdRng::seed_from_u64(0xDEADBEEF); // deterministic seed + + for _ in 0..1_000_000 { + let len = rng.random_range(25..=30); // replaces Uniform(8, 20) + let mut s = String::with_capacity(len); + + for _ in 0..len { + let x = rng.random_range(0..=61); // replaces Uniform(0, 61) + let ch = match x { + x if x < 10 => (b'0' + x as u8) as char, + x if x < 36 => (b'a' + (x - 10) as u8) as char, + _ => (b'A' + (x - 36) as u8) as char, + }; + s.push(ch); + } + + vec.push(s); + } + + vec +} + +fn main() { + let vec = generate_test_data(); + let start_total = Instant::now(); + println!("str_btree_set test started"); + + let mut bset = BTreeSet::new(); + + let start_insert = Instant::now(); + for s in &vec { + bset.insert(s.clone()); // cloning to move into BTreeSet + } + println!("insert_key: {:.2?}", start_insert.elapsed()); + + let mut count = 0; + let start_contains = Instant::now(); + for s in &vec { + if bset.contains(s) { + count += 1; + } + } + println!("contains: {:.2?}", start_contains.elapsed()); + // 🚀 Forward iteration benchmark + let mut total_size = 0; + let start_iter = Instant::now(); + for s in &bset { + total_size += s.len(); + } + println!( + "forward iteration total_size = {}, elapsed: {:.2?}", + total_size, + start_iter.elapsed() + ); + + // 🔄 Reverse iteration benchmark + let mut total_size = 0; + let start_rev_iter = Instant::now(); + for s in bset.iter().rev() { + total_size += s.len(); + } + println!( + "reverse iteration total_size = {}, elapsed: {:.2?}", + total_size, + start_rev_iter.elapsed() + ); + + println!("count = {}", count); + println!("total time: {:.2?}", start_total.elapsed()); +} diff --git a/benchmark/0011.containers/str_btree_set/std_set.cc b/benchmark/0011.containers/str_btree_set/std_set.cc new file mode 100644 index 000000000..cf79e6e05 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/std_set.cc @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include "gentest.h" + +int main() +{ + auto vec{::gentest<::std::string>()}; + ::fast_io::timer t(u8"str_btree_set"); + ::std::set bset; + { + ::fast_io::timer t(u8"insert"); + for (auto const &e : vec) + { + bset.insert(e); + } + } + { + ::std::size_t count{}; + { + ::fast_io::timer t(u8"contains"); + for (auto const &e : vec) + { + count += static_cast<::std::size_t>(bset.contains(e)); + } + } + ::fast_io::io::perrln("count=", count); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"iteration"); + for (auto const &e : bset) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"reverse iteration"); + for (auto const &e : ::std::ranges::reverse_view(bset)) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } +} diff --git a/benchmark/0011.containers/str_btree_set/std_set_fast_io.cc b/benchmark/0011.containers/str_btree_set/std_set_fast_io.cc new file mode 100644 index 000000000..373708101 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/std_set_fast_io.cc @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include "gentest.h" + +int main() +{ + auto vec{::gentest()}; + ::fast_io::timer t(u8"str_btree_set"); + ::std::set<::fast_io::string> bset; + { + ::fast_io::timer t(u8"insert"); + for (auto const &e : vec) + { + bset.insert(e); + } + } + { + ::std::size_t count{}; + { + ::fast_io::timer t(u8"contains"); + for (auto const &e : vec) + { + count += static_cast<::std::size_t>(bset.contains(e)); + } + } + ::fast_io::io::perrln("count=", count); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"iteration"); + for (auto const &e : bset) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"reverse iteration"); + for (auto const &e : ::std::ranges::reverse_view(bset)) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } +} \ No newline at end of file diff --git a/benchmark/0011.containers/str_btree_set/std_unordered_set.cc b/benchmark/0011.containers/str_btree_set/std_unordered_set.cc new file mode 100644 index 000000000..429a977f3 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/std_unordered_set.cc @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include "gentest.h" + +int main() +{ + auto vec{::gentest()}; + ::fast_io::timer t(u8"str_btree_set"); + ::std::unordered_set<::std::string> bset; + { + ::fast_io::timer t(u8"insert"); + for (auto const &e : vec) + { + bset.insert(e); + } + } + { + ::std::size_t count{}; + { + ::fast_io::timer t(u8"contains"); + for (auto const &e : vec) + { + count += static_cast<::std::size_t>(bset.contains(e)); + } + } + ::fast_io::io::perrln("count=", count); + } +} \ No newline at end of file diff --git a/benchmark/0011.containers/str_btree_set/str_btree_set.cc b/benchmark/0011.containers/str_btree_set/str_btree_set.cc new file mode 100644 index 000000000..659b03db0 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/str_btree_set.cc @@ -0,0 +1,51 @@ +#include +#include +#include +#include "gentest.h" + +int main() +{ + auto vec{::gentest()}; + ::fast_io::timer t(u8"str_btree_set"); + ::fast_io::str_btree_set bset; + { + ::fast_io::timer t(u8"insert_key"); + for (auto const &e : vec) + { + bset.insert_key(::fast_io::mnp::os_c_str(e)); + } + } + { + ::std::size_t count{}; + { + ::fast_io::timer t(u8"contains"); + for (auto const &e : vec) + { + count += static_cast<::std::size_t>(bset.contains(::fast_io::mnp::os_c_str(e))); + } + } + ::fast_io::io::perrln("count=", count); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"iteration"); + for (auto const &e : bset) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } + { + ::std::size_t total_size{}; + { + ::fast_io::timer t(u8"reverse iteration"); + for (auto const &e : ::std::ranges::reverse_view(bset)) + { + total_size += e.size(); + } + } + ::fast_io::io::perrln("total_size=", total_size); + } +} \ No newline at end of file diff --git a/benchmark/0011.containers/str_btree_set/u8str_btree_set.cc b/benchmark/0011.containers/str_btree_set/u8str_btree_set.cc new file mode 100644 index 000000000..1a4956309 --- /dev/null +++ b/benchmark/0011.containers/str_btree_set/u8str_btree_set.cc @@ -0,0 +1,29 @@ +#include +#include +#include +#include "gentest.h" + +int main() +{ + auto vec{::gentest<::fast_io::u8string>()}; + ::fast_io::timer t(u8"str_btree_set"); + ::fast_io::u8str_btree_set bset; + { + ::fast_io::timer t(u8"insert_key"); + for (auto const &e : vec) + { + bset.insert_key(::fast_io::mnp::os_c_str(e)); + } + } + { + ::std::size_t count{}; + { + ::fast_io::timer t(u8"contains"); + for (auto const &e : vec) + { + count += static_cast<::std::size_t>(bset.contains(::fast_io::mnp::os_c_str(e))); + } + } + ::fast_io::io::perrln("count=", count); + } +} diff --git a/examples/.test_prop.toml b/examples/.test_prop.toml index bc8d292b2..405e56a33 100644 --- a/examples/.test_prop.toml +++ b/examples/.test_prop.toml @@ -39,3 +39,6 @@ interactive = true ["0039.gen_win32_mangling"] ignore = true + +["0040.wifianalyzer"] +ignore = true diff --git a/examples/0014.random/pin12.cc b/examples/0014.random/pin12.cc new file mode 100644 index 000000000..af04f0aec --- /dev/null +++ b/examples/0014.random/pin12.cc @@ -0,0 +1,27 @@ +#include +#include +#include + +using namespace fast_io::io; + +int main(int argc, char **argv) +{ + std::size_t n{100}; + if (1 < argc) + { + n = fast_io::to(fast_io::mnp::os_c_str(argv[1])); + } + fast_io::u8obuf_file obf(u"pin12.txt"); + fast_io::ibuf_white_hole_engine eng; + std::uniform_int_distribution ud(0, 9); + for (std::size_t i{}; i != n; ++i) + { + for (std::size_t j{}; j != 12u; ++j) + { + char8_t ch(static_cast(ud(eng))); + ch += u8'0'; + print(obf, fast_io::mnp::chvw(ch)); + } + println(obf); + } +} diff --git a/examples/0040.wifianalyzer/win32.cc b/examples/0040.wifianalyzer/win32.cc new file mode 100644 index 000000000..88e48962f --- /dev/null +++ b/examples/0040.wifianalyzer/win32.cc @@ -0,0 +1,213 @@ +#define NOMINMAX 1 +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#include +#include +#pragma comment(lib, "wlanapi.lib") + +class win32_wlan_file { +public: + explicit constexpr win32_wlan_file() noexcept = default; + + explicit win32_wlan_file(::std::uint_least32_t version) { + ::std::uint_least32_t negotiated_version{}; + if (WlanOpenHandle(version, nullptr, reinterpret_cast(::std::addressof(negotiated_version)), reinterpret_cast(&handle)) != ERROR_SUCCESS) { + ::fast_io::io::panic("WlanOpenHandle failed\n"); + } + } + + ~win32_wlan_file() { + if (handle) WlanCloseHandle(reinterpret_cast(handle), nullptr); + } + + void* handle = nullptr; + + win32_wlan_file(const win32_wlan_file&) = delete; + win32_wlan_file& operator=(const win32_wlan_file&) = delete; + + constexpr win32_wlan_file(win32_wlan_file&& other) noexcept : handle(other.handle) { + other.handle = nullptr; + } + + win32_wlan_file& operator=(win32_wlan_file&& other) noexcept { + if (this != &other) { + if (handle) WlanCloseHandle(reinterpret_cast(handle), nullptr); + handle = other.handle; + other.handle = nullptr; + } + return *this; + } +}; + +class win32_wlan_memory_file { +public: + explicit constexpr win32_wlan_memory_file() noexcept = default; + + ~win32_wlan_memory_file() { + if (hd) WlanFreeMemory(hd); + } + + void* hd = nullptr; + + win32_wlan_memory_file(const win32_wlan_memory_file&) = delete; + win32_wlan_memory_file& operator=(const win32_wlan_memory_file&) = delete; + + constexpr win32_wlan_memory_file(win32_wlan_memory_file&& other) noexcept : hd(other.hd) { + other.hd = nullptr; + } + + win32_wlan_memory_file& operator=(win32_wlan_memory_file&& other) noexcept { + if (this != &other) { + if (hd) WlanFreeMemory(hd); + hd = other.hd; + other.hd = nullptr; + } + return *this; + } +}; + +inline void WINAPI wlan_notification_callback(PWLAN_NOTIFICATION_DATA data, void* ctx) { + if (!data || !ctx) return; + if (data->NotificationCode == wlan_notification_acm_scan_complete) { + ::fast_io::io::print("[+] Scan complete\n"); + } else if (data->NotificationCode == wlan_notification_acm_scan_fail) { + ::fast_io::io::print("[-] Scan failed\n"); + } + if(!SetEvent(ctx)) + { + ::fast_io::io::panic("SetEvent failure\n"); + } +} +inline ::fast_io::cstring_view signal_quality(::std::int_least32_t rssi_dbm) noexcept { + if (rssi_dbm >= -55) return ::fast_io::cstring_view("Excellent"); + if (rssi_dbm >= -65) return ::fast_io::cstring_view("Good"); + if (rssi_dbm >= -75) return ::fast_io::cstring_view("Fair"); + if (rssi_dbm >= -85) return ::fast_io::cstring_view("Weak"); + return ::fast_io::cstring_view("Very Weak"); +} +inline constexpr ::std::uint_least32_t frequency_to_channel(::std::uint_least32_t freq_khz) noexcept { + ::std::uint_least32_t freq_mhz = freq_khz / 1000u; + if (freq_mhz >= 2412 && freq_mhz <= 2472) { + return (freq_mhz - 2407) / 5; // Channels 1–13 + } else if (freq_mhz == 2484) { + return 14; + } else if (freq_mhz >= 5180 && freq_mhz <= 5825) { + return (freq_mhz - 5000) / 5; // Channels 36–165 + } else if (freq_mhz >= 5955 && freq_mhz <= 7115) { + return (freq_mhz - 5950) / 5; // Wi-Fi 6E channels + } + return 0; // Unknown or unsupported +} +inline constexpr ::fast_io::cstring_view frequency_to_band(::std::uint_least32_t freq_khz) noexcept { + std::uint_least32_t freq_mhz = freq_khz / 1000u; + if (freq_mhz >= 2400 && freq_mhz <= 2500) { + return ::fast_io::cstring_view("2.4 GHz"); + } else if (freq_mhz >= 5000 && freq_mhz <= 5900) { + return ::fast_io::cstring_view("5 GHz"); + } else if (freq_mhz >= 5925 && freq_mhz <= 7125) { + return ::fast_io::cstring_view("6 GHz"); + } + return ::fast_io::cstring_view("Unknown"); +} + +int main() { + win32_wlan_file wlan(2); + HANDLE scan_event = CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (!scan_event) { + ::fast_io::io::panic("CreateEvent failed\n"); + } + ::fast_io::win32_file scan_event_file(scan_event); + + // Get interface + win32_wlan_memory_file if_mem; + WlanEnumInterfaces(wlan.handle, nullptr, + reinterpret_cast(&if_mem.hd)); + { + auto* if_list = reinterpret_cast(if_mem.hd); + GUID interface_guid = if_list->InterfaceInfo[0].InterfaceGuid; + + // Register callback + WlanRegisterNotification(wlan.handle, WLAN_NOTIFICATION_SOURCE_ACM, TRUE, + wlan_notification_callback, scan_event, nullptr, nullptr); + + // Trigger scan + WlanScan(wlan.handle, &interface_guid, nullptr, nullptr, nullptr); + } + // Wait for scan to complete (e.g., Sleep or message loop) + auto start_time {::fast_io::posix_clock_gettime(::fast_io::posix_clock_id::realtime)}; + DWORD wait_result = WaitForSingleObject(scan_event, 10000); // 10s timeout + if (wait_result != WAIT_OBJECT_0) { + ::fast_io::io::perrln("Scan did not complete in time"); + } + ::fast_io::io::print("Elapsed time for scanning: ", + ::fast_io::posix_clock_gettime(::fast_io::posix_clock_id::realtime)-start_time, "s\n"); + auto* if_list = reinterpret_cast(if_mem.hd); + for (::std::uint_least32_t i{}; i != if_list->dwNumberOfItems; ++i) { + GUID guid = if_list->InterfaceInfo[i].InterfaceGuid; + + win32_wlan_memory_file bss_mem; + if (WlanGetNetworkBssList(wlan.handle, ::std::addressof(guid), nullptr, + dot11_BSS_type_any, FALSE, nullptr, + reinterpret_cast(::std::addressof(bss_mem.hd))) != ERROR_SUCCESS) { + ::fast_io::io::perrln("WlanGetNetworkBssList failed:", i ); + continue; + } + + auto* bss_list{reinterpret_cast(bss_mem.hd)}; + for (::std::uint_least32_t j{}; j != bss_list->dwNumberOfItems; ++j) { + WLAN_BSS_ENTRY const& entry = bss_list->wlanBssEntries[j]; + ::fast_io::string_view ssid(reinterpret_cast(entry.dot11Ssid.ucSSID), entry.dot11Ssid.uSSIDLength); + if (ssid.is_empty()) { + ssid = ::fast_io::string_view("[Hidden]"); + } + + // Default to 20 MHz if no IE is found + std::uint_least32_t channel_width_mhz = 20; + + // Parse IEs to determine actual channel width + std::uint_least8_t const* ie_data = reinterpret_cast(&entry) + entry.ulIeOffset; + for (std::uint_least32_t i{}; i + 2 < entry.ulIeSize;) { + std::uint_least8_t id = ie_data[i]; + std::uint_least8_t len = ie_data[i + 1]; + if (i + 2 + len > entry.ulIeSize) break; // prevent overflow + + std::uint_least8_t const* data = &ie_data[i + 2]; + + // HT Operation IE (ID 0x3D) + if (id == 0x3D && len >= 3) { + std::uint_least8_t ht_info = data[1]; + std::uint_least8_t channel_width_flag = data[2]; // bit 0: 0 = 20 MHz, 1 = 40 MHz + if (channel_width_flag & 0x01) { + channel_width_mhz = 40; + } + } + + // VHT Operation IE (ID 0xC0) + else if (id == 0xC0 && len >= 1) { + std::uint_least8_t vht_channel_width = data[0]; // 0 = 20/40, 1 = 80, 2 = 160 or 80+80 + if (vht_channel_width == 1) channel_width_mhz = 80; + else if (vht_channel_width == 2) channel_width_mhz = 160; + } + + // You can add HE parsing here if needed + + i += 2 + len; + } + + // Estimate channel range based on actual width + std::uint_least32_t center_channel = frequency_to_channel(entry.ulChCenterFrequency); + std::uint_least32_t ch_span = channel_width_mhz / 20; + std::uint_least32_t ch_start = center_channel >= ch_span ? center_channel - ch_span : center_channel; + std::uint_least32_t ch_end = center_channel + ch_span; + + ::fast_io::io::print("SSID:", ssid, "\t", + "Signal:", entry.lRssi, " dBm (Quality:", signal_quality(entry.lRssi), ")\t" + "Frequency:", entry.ulChCenterFrequency, "kHz\t", + "Band:", frequency_to_band(entry.ulChCenterFrequency), "\t" + "Channel:", center_channel, " " + "(width:", channel_width_mhz, " MHz, covers:", ch_start, "-", ch_end, ")\n"); + } + } +} diff --git a/fuzzing/0007.containers/btree/str_btree_set.cc b/fuzzing/0007.containers/btree/str_btree_set.cc new file mode 100644 index 000000000..4da4e2e43 --- /dev/null +++ b/fuzzing/0007.containers/btree/str_btree_set.cc @@ -0,0 +1,17 @@ +#include +#include + +thread_local ::fast_io::containers::basic_str_btree_set bset; +thread_local ::std::size_t n{}; + +extern "C" int LLVMFuzzerTestOneInput(::std::uint8_t *data, ::std::size_t size) +{ + if (n == 100000) + { + bset.clear_destroy(); + n = 0; + } + bset.insert_key(::fast_io::containers::basic_string_view(reinterpret_cast(data), size)); + ++n; + return 0; +} \ No newline at end of file diff --git a/include/fast_io_core_impl/char_category/char_category.h b/include/fast_io_core_impl/char_category/char_category.h index f525a4470..9c8055b76 100644 --- a/include/fast_io_core_impl/char_category/char_category.h +++ b/include/fast_io_core_impl/char_category/char_category.h @@ -1556,7 +1556,7 @@ namespace details { inline constexpr char32_t to_c_upper_ascii_impl(char32_t ch) noexcept { - constexpr char32_t alphanum{static_cast(26u)}; + constexpr char32_t alphanum{static_cast(static_cast<::std::uint_least32_t>(26u))}; char32_t res{ch - U'a'}; if (res < alphanum) { @@ -1567,7 +1567,7 @@ inline constexpr char32_t to_c_upper_ascii_impl(char32_t ch) noexcept inline constexpr char32_t to_c_lower_ascii_impl(char32_t ch) noexcept { - constexpr char32_t alphanum{static_cast(26u)}; + constexpr char32_t alphanum{static_cast(static_cast<::std::uint_least32_t>(26u))}; char32_t res{ch - U'A'}; if (res < alphanum) { @@ -1797,7 +1797,7 @@ inline constexpr bool is_html_whitespace_wide_impl(wchar_t ch) noexcept inline constexpr bool is_dos_path_invalid_character_impl(char32_t ch) noexcept { - if (ch < static_cast(32u)) + if (ch < static_cast(static_cast<::std::uint_least32_t>(32u))) { return true; } @@ -1865,7 +1865,7 @@ inline constexpr bool is_c_halfwidth(char_type ch) noexcept } else if constexpr (!::std::same_as && sizeof(char_type) == sizeof(char32_t)) { - return is_c_halfwidth(static_cast(ch)); + return is_c_halfwidth(static_cast(static_cast<::std::uint_least32_t>(ch))); } else if constexpr (::std::signed_integral) { @@ -1899,7 +1899,7 @@ inline constexpr bool is_c_fullwidth(char_type ch) noexcept } else if constexpr (!::std::same_as && sizeof(char_type) == sizeof(char32_t)) { - return is_c_fullwidth(static_cast(ch)); + return is_c_fullwidth(static_cast(static_cast<::std::uint_least32_t>(ch))); } else if constexpr (::std::signed_integral) { @@ -1934,7 +1934,7 @@ inline constexpr bool is_dos_path_invalid_character(T ch) noexcept } else { - return ::fast_io::char_category::details::is_dos_path_invalid_character_impl(static_cast(ch)); + return ::fast_io::char_category::details::is_dos_path_invalid_character_impl(static_cast(static_cast<::std::uint_least32_t>(ch))); } } @@ -1947,7 +1947,7 @@ inline constexpr bool is_dos_path_invalid_prefix_character(T ch) noexcept } else { - return ::fast_io::char_category::details::is_dos_path_invalid_prefix_character_impl(static_cast(ch)); + return ::fast_io::char_category::details::is_dos_path_invalid_prefix_character_impl(static_cast(static_cast<::std::uint_least32_t>(ch))); } } diff --git a/include/fast_io_core_impl/char_category/char_category_traits.h b/include/fast_io_core_impl/char_category/char_category_traits.h index fd637cea7..c2dc3973b 100644 --- a/include/fast_io_core_impl/char_category/char_category_traits.h +++ b/include/fast_io_core_impl/char_category/char_category_traits.h @@ -493,7 +493,7 @@ struct to_c_common_fn_impl } else if constexpr (!::std::same_as && sizeof(char_type) == sizeof(char32_t)) { - return static_cast(operator()(static_cast(ch))); + return static_cast(operator()(static_cast(static_cast<::std::uint_least32_t>(ch)))); } else if constexpr (::std::signed_integral) { diff --git a/include/fast_io_core_impl/codecvt/general.h b/include/fast_io_core_impl/codecvt/general.h index 2165601fc..bd4105eb7 100644 --- a/include/fast_io_core_impl/codecvt/general.h +++ b/include/fast_io_core_impl/codecvt/general.h @@ -107,7 +107,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, static_assert(src_encoding == encoding_scheme::utf_be || src_encoding == encoding_scheme::utf_le); for (; src_first != src_last; ++src_first) { - dst += get_utf_code_units(static_cast(*src_first), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(*src_first)), dst); } return {src_last, dst}; } @@ -186,7 +186,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } } } @@ -204,7 +204,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, constexpr ::std::size_t m128i_size{16}; while (m128i_size < static_cast<::std::size_t>(src_last - src_first)) { - if (static_cast(*src_first) < 0x80) + if (static_cast(static_cast<::std::uint_least8_t>(*src_first)) < 0x80) { auto [new_src, new_dst] = convert_ascii_with_sse(src_first, dst); src_first = new_src; @@ -223,7 +223,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } } else @@ -237,7 +237,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } } } @@ -251,7 +251,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, if constexpr (src_encoding == encoding_scheme::utf_ebcdic) { auto [code, adv] = general_advance(src_first, src_last - src_first); - if (adv == static_cast(-1)) + if (adv == static_cast(static_cast<::std::uint_least8_t>(-1))) { break; } @@ -267,12 +267,12 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } } else { - if (static_cast(*src_first) < 0x80) + if (static_cast(static_cast<::std::uint_least8_t>(*src_first)) < 0x80) { if constexpr (encoding_scheme::utf_ebcdic == encoding) { @@ -280,7 +280,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - *dst = static_cast(static_cast(*src_first)); + *dst = static_cast(static_cast(static_cast<::std::uint_least8_t>(*src_first))); } if constexpr (sizeof(dest_char_type) != 1 && encoding_is_utf(encoding) && !is_native_scheme(encoding)) @@ -295,7 +295,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, if constexpr (src_encoding != encoding_scheme::utf) { auto [code, adv] = general_advance(src_first, src_last - src_first); - if (adv == static_cast(-1)) + if (adv == static_cast(static_cast<::std::uint_least8_t>(-1))) { break; } @@ -311,7 +311,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } } else @@ -333,7 +333,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } } } @@ -457,7 +457,7 @@ inline constexpr dest_char_type *general_code_cvt(state_type &__restrict state, if (failed) { non_overlapped_copy_n(bytes, state_bytesm1, state.bytes); - state.size = static_cast(total_bytes); + state.size = static_cast(static_cast<::std::uint_least8_t>(total_bytes)); return dst; } if constexpr (sizeof(dest_char_type) == 4) @@ -471,17 +471,17 @@ inline constexpr dest_char_type *general_code_cvt(state_type &__restrict state, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } src_first += static_cast<::std::size_t>(bytes_src - bytes - state_size); } else { auto [code, adv] = general_advance(bytes, total_bytes); - if (adv == static_cast(-1)) + if (adv == static_cast(static_cast<::std::uint_least8_t>(-1))) { non_overlapped_copy_n(bytes, state_bytesm1, state.bytes); - state.size = static_cast(total_bytes); + state.size = static_cast(static_cast<::std::uint_least8_t>(total_bytes)); return dst; } if constexpr (sizeof(dest_char_type) == 4) @@ -495,14 +495,14 @@ inline constexpr dest_char_type *general_code_cvt(state_type &__restrict state, } else { - dst += get_utf_code_units(static_cast(code), dst); + dst += get_utf_code_units(static_cast(static_cast<::std::uint_least32_t>(code)), dst); } src_first += static_cast<::std::size_t>(static_cast<::std::size_t>(adv) - state_size); } } auto [new_src, new_dst] = general_code_cvt(src_first, src_last, dst); ::std::size_t diff{static_cast<::std::size_t>(src_last - new_src)}; - state.size = static_cast(diff); + state.size = static_cast(static_cast<::std::uint_least8_t>(diff)); non_overlapped_copy_n(new_src, diff, state.bytes); return new_dst; } diff --git a/include/fast_io_core_impl/codecvt/utf.h b/include/fast_io_core_impl/codecvt/utf.h index c38fc042c..c907bf20a 100644 --- a/include/fast_io_core_impl/codecvt/utf.h +++ b/include/fast_io_core_impl/codecvt/utf.h @@ -633,7 +633,7 @@ template <::std::integral T> inline constexpr advance_with_big_table_unchecked_result advance_with_big_table_unchecked(T const *it) noexcept { char8_t const *info{first_unit_info[static_cast(*it)]}; - char32_t cdpt{static_cast(*info)}; //- From it, get the initial code point value + char32_t cdpt{static_cast(static_cast<::std::uint_least32_t>(*info))}; //- From it, get the initial code point value ::std::int_least32_t curr{info[1]}; //- From it, get the second state for (++it; 12 < curr;) { @@ -663,7 +663,7 @@ template <::std::integral T> inline constexpr advance_with_big_table_result advance_with_big_table(T const *first, T const *last) noexcept { char8_t const *info{first_unit_info[static_cast(*first)]}; - char32_t cdpt{static_cast(*info)}; //- From it, get the initial code point value + char32_t cdpt{static_cast(static_cast<::std::uint_least32_t>(*info))}; //- From it, get the initial code point value ::std::int_least32_t curr{info[1]}; //- From it, get the second state auto it{first}; for (++it; 12 < curr;) diff --git a/include/fast_io_core_impl/codecvt/utf_ebcdic.h b/include/fast_io_core_impl/codecvt/utf_ebcdic.h index 260adf80f..8103e439a 100644 --- a/include/fast_io_core_impl/codecvt/utf_ebcdic.h +++ b/include/fast_io_core_impl/codecvt/utf_ebcdic.h @@ -73,42 +73,42 @@ inline constexpr ::std::size_t get_utf_ebcdic_code_units(char32_t code, T *dst) } else if (code < 0x400) { - *dst = static_cast(bm_i8_to_ebcdic[static_cast(0b11000000) | (code >> 5)]); + *dst = static_cast(bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b11000000)) | (code >> 5)]); dst[1] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | (code & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | (code & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); return 2; } else if (code < 0x4000) { - *dst = static_cast(bm_i8_to_ebcdic[static_cast(0b11100000) | (code >> 10)]); + *dst = static_cast(bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b11100000)) | (code >> 10)]); dst[1] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | ((code >> 5) & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | ((code >> 5) & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); dst[2] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | (code & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | (code & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); return 3; } else if (code < 0x40000) { - *dst = static_cast(bm_i8_to_ebcdic[static_cast(0b11110000) | (code >> 15)]); + *dst = static_cast(bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b11110000)) | (code >> 15)]); dst[1] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | ((code >> 10) & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | ((code >> 10) & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); dst[2] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | ((code >> 5) & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | ((code >> 5) & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); dst[3] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | (code & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | (code & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); return 4; } else if (code < 0x110000) { - *dst = static_cast(bm_i8_to_ebcdic[static_cast(0b11111000) | (code >> 20)]); + *dst = static_cast(bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b11111000)) | (code >> 20)]); dst[1] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | ((code >> 15) & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | ((code >> 15) & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); dst[2] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | ((code >> 10) & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | ((code >> 10) & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); dst[3] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | ((code >> 5) & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | ((code >> 5) & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); dst[4] = static_cast( - bm_i8_to_ebcdic[static_cast(0b10100000) | (code & static_cast(0b11111))]); + bm_i8_to_ebcdic[static_cast(static_cast<::std::uint_least32_t>(0b10100000)) | (code & static_cast(static_cast<::std::uint_least32_t>(0b11111)))]); return 5; } return get_utf_ebcdic_invalid_code_units(dst); @@ -124,11 +124,11 @@ template <::std::integral T> requires(sizeof(T) == 1) inline constexpr from_ebcdic_result utf_ebcdic_advance(T *src_first, ::std::size_t sz) noexcept { - char8_t src0(static_cast(*src_first)); + char8_t src0(static_cast(static_cast<::std::uint_least8_t>(*src_first))); char8_t shadow{utfebcdic_shadow_flags[src0]}; if (shadow < 2) { - return {static_cast(bm_ebcdic_to_i8[src0]), 1}; + return {static_cast(static_cast<::std::uint_least32_t>(bm_ebcdic_to_i8[src0])), 1}; } if (shadow == 9) { @@ -136,12 +136,12 @@ inline constexpr from_ebcdic_result utf_ebcdic_advance(T *src_first, ::std::size } if (sz < shadow) { - return {0, static_cast(-1)}; + return {0, static_cast(static_cast<::std::uint_least8_t>(-1))}; } char32_t res{}; for (char8_t i{1}; i != shadow; ++i) { - char8_t code(bm_ebcdic_to_i8[static_cast(src_first[i])]); + char8_t code(bm_ebcdic_to_i8[static_cast(static_cast<::std::uint_least8_t>(src_first[i]))]); if ((code >> 5) != 0b101) [[unlikely]] { return {0xFFFD, i}; @@ -152,13 +152,13 @@ inline constexpr from_ebcdic_result utf_ebcdic_advance(T *src_first, ::std::size switch (shadow) { case 2: - return {((static_cast(src0i18 & 0b11111)) << 5) | res, 2}; + return {((static_cast(static_cast<::std::uint_least32_t>(src0i18 & 0b11111))) << 5) | res, 2}; case 3: - return {((static_cast(src0i18 & 0b1111)) << 10) | res, 3}; + return {((static_cast(static_cast<::std::uint_least32_t>(src0i18 & 0b1111))) << 10) | res, 3}; case 4: - return {((static_cast(src0i18 & 0b111)) << 15) | res, 4}; + return {((static_cast(static_cast<::std::uint_least32_t>(src0i18 & 0b111))) << 15) | res, 4}; case 5: - return {((static_cast(src0i18 & 0b1)) << 20) | res, 5}; + return {((static_cast(static_cast<::std::uint_least32_t>(src0i18 & 0b1))) << 20) | res, 5}; default: return {0xFFFD, shadow}; }; diff --git a/include/fast_io_core_impl/concepts/type.h b/include/fast_io_core_impl/concepts/type.h index 30eb7dd11..3021f1d3a 100644 --- a/include/fast_io_core_impl/concepts/type.h +++ b/include/fast_io_core_impl/concepts/type.h @@ -32,7 +32,7 @@ struct basic_message_hdr T const *control; /* Ancillary data, see below */ ::std::size_t controllen; /* Ancillary data buffer len */ int flags; /* Flags (unused) */ - + inline operator basic_message_hdr() const noexcept requires(!::std::same_as) { @@ -110,7 +110,7 @@ struct deco_result out_char_type *output_result_ptr{}; }; -enum class seekdir +enum class seekdir : ::std::uint_least8_t { beg = 0, // SEEK_SET cur = 1, // SEEK_CUR diff --git a/include/fast_io_core_impl/ebcdic.h b/include/fast_io_core_impl/ebcdic.h index 8eb67e09b..af09e92cc 100644 --- a/include/fast_io_core_impl/ebcdic.h +++ b/include/fast_io_core_impl/ebcdic.h @@ -20,13 +20,13 @@ inline constexpr bool exec_charset_is_ebcdic() noexcept } else if constexpr (sizeof(wchar_t) == sizeof(char32_t)) { - constexpr char32_t value{static_cast(L'A')}; + constexpr char32_t value{static_cast(static_cast<::std::uint_least32_t>(L'A'))}; constexpr char32_t swapped{::fast_io::byte_swap(value)}; return value != U'A' && swapped != U'A'; } else { - return static_cast(L'A') != U'A'; + return static_cast(static_cast<::std::uint_least32_t>(L'A')) != U'A'; } } else @@ -48,7 +48,7 @@ inline constexpr bool wexec_charset_is_utf_none_native_endian() noexcept } else { - constexpr char32_t value{static_cast(L'A')}; + constexpr char32_t value{static_cast(static_cast<::std::uint_least32_t>(L'A'))}; constexpr char32_t swapped{::fast_io::byte_swap(value)}; return value != U'A' && swapped == U'A'; } diff --git a/include/fast_io_core_impl/socket/sock_family.h b/include/fast_io_core_impl/socket/sock_family.h index abdd32dfc..e0c6ea38e 100644 --- a/include/fast_io_core_impl/socket/sock_family.h +++ b/include/fast_io_core_impl/socket/sock_family.h @@ -89,6 +89,7 @@ enum class sock_family wanpipe, /* Wanpipe API sockets. */ x25, /* Reserved for X.25 project. */ xdp, /* XDP sockets. */ + quic, /* QUIC */ }; } // namespace fast_io diff --git a/include/fast_io_core_impl/socket/sock_protocol.h b/include/fast_io_core_impl/socket/sock_protocol.h index c99387525..0a88a93d3 100644 --- a/include/fast_io_core_impl/socket/sock_protocol.h +++ b/include/fast_io_core_impl/socket/sock_protocol.h @@ -60,7 +60,8 @@ enum class sock_protocol tp, /* SO Transport Protocol Class 4. */ udp, /* User Datagram Protocol. */ udplite, /* UDP-Lite protocol. */ - vrrp + vrrp, + quic /* QUIC protocol */ }; } // namespace fast_io diff --git a/include/fast_io_driver/qt_impl/qiodevice.h b/include/fast_io_driver/qt_impl/qiodevice.h index aa72aae58..35e816f8c 100644 --- a/include/fast_io_driver/qt_impl/qiodevice.h +++ b/include/fast_io_driver/qt_impl/qiodevice.h @@ -92,22 +92,18 @@ inline ::std::uintmax_t qio_device_seek_impl(QIODevice *__restrict qdevice, ::st } // namespace details -template <::std::integral ch_type, typename T, ::std::contiguous_iterator Iter> -inline Iter write(basic_general_qdevice_io_observer qiob, Iter begin, Iter end) +template <::std::integral ch_type, typename T> +inline ::std::byte const *write_some_bytes_define(basic_general_qdevice_io_observer qiob, ::std::byte const *begin, ::std::byte const *end) { - return begin + details::qio_device_write_impl( - qiob.qdevice, ::std::to_address(begin), - static_cast<::std::size_t>(::std::to_address(end) - ::std::to_address(begin)) * sizeof(*begin)) / - sizeof(*begin); + return begin + ::fast_io::details::qio_device_write_impl( + qiob.qdevice, begin, static_cast<::std::size_t>(end - begin)); } -template <::std::integral ch_type, typename T, ::std::contiguous_iterator Iter> -inline Iter read(basic_general_qdevice_io_observer qiob, Iter begin, Iter end) +template <::std::integral ch_type, typename T> +inline ::std::byte *read_some_bytes_define(basic_general_qdevice_io_observer qiob, , ::std::byte *begin, ::std::byte *end) { - return begin + details::qio_device_read_impl( - qiob.qdevice, ::std::to_address(begin), - static_cast<::std::size_t>(::std::to_address(end) - ::std::to_address(begin)) * sizeof(*begin)) / - sizeof(*begin); + return begin + ::fast_io::details::qio_device_read_impl( + qiob.qdevice, begin, static_cast<::std::size_t>(end - begin)); } template <::std::integral ch_type, typename T> @@ -139,7 +135,7 @@ using basic_qt_io_observer = basic_general_qdevice_io_observer template <::std::integral ch_type, typename T> inline constexpr basic_qiodevice_io_observer -io_value_handle(basic_general_qdevice_io_observer gqiob) noexcept +io_stream_ref_define(basic_general_qdevice_io_observer gqiob) noexcept { return {gqiob.qdevice}; } diff --git a/include/fast_io_dsal/impl/associative_string.h b/include/fast_io_dsal/impl/associative_string.h new file mode 100644 index 000000000..882248a86 --- /dev/null +++ b/include/fast_io_dsal/impl/associative_string.h @@ -0,0 +1,43 @@ +#pragma once + +namespace fast_io::details +{ +/* +The string is null terminated +*/ +template <::std::integral chtype> +struct associative_string +{ + using char_type = chtype; + using size_type = ::std::size_t; + char_type const *ptr; + size_type n; + constexpr ::fast_io::containers::basic_cstring_view strvw() const noexcept + { + return ::fast_io::containers::basic_cstring_view(::fast_io::null_terminated, ptr, n); + } +}; + +template +inline constexpr ::fast_io::details::associative_string create_associative_string(char_type const *p, ::std::size_t n) noexcept +{ + using typed_allocator_type = ::fast_io::typed_generic_allocator_adapter; + if (n == SIZE_MAX) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + ::std::size_t const np1{static_cast<::std::size_t>(n + 1u)}; + char_type *newp{typed_allocator_type::allocate(np1)}; + *::fast_io::details::non_overlapped_copy_n(p, n, newp) = 0; + return {newp, n}; +} + +template +inline constexpr void deallocate_associative_string(void const *p, ::std::size_t n) noexcept +{ + using typed_allocator_type = ::fast_io::typed_generic_allocator_adapter; + ::std::size_t const np1{static_cast<::std::size_t>(n + 1u)}; + typed_allocator_type::deallocate_n(static_cast(const_cast(p)), np1); +} + +} // namespace fast_io::details diff --git a/include/fast_io_dsal/impl/str_btree_set.h b/include/fast_io_dsal/impl/str_btree_set.h new file mode 100644 index 000000000..1c6945238 --- /dev/null +++ b/include/fast_io_dsal/impl/str_btree_set.h @@ -0,0 +1,939 @@ +#pragma once + +namespace fast_io::containers +{ + +namespace details +{ +struct btree_imp +{ + void *root; + void *leftmost; + void *rightmost; +}; + +template <::std::integral chtype, ::std::size_t keys_number> +struct str_btree_set_node +{ + using char_type = chtype; + ::std::size_t size; // Number of keys currently stored + bool leaf; // Indicates whether the node is a leaf + ::fast_io::details::associative_string keys[keys_number]; // Array of keys + str_btree_set_node *childrens[keys_number + 1u]; // Array of child pointers + str_btree_set_node *parent; // Pointer to parent node + ::std::size_t parent_pos; // Position in Parent +}; + +template <::std::size_t keys_number> +struct +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + str_btree_set_common +{ + ::std::size_t size; + bool leaf; + ::fast_io::io_scatter_t keys[keys_number]; + void *childrens[keys_number + 1u]; + void *parent; + ::std::size_t parent_pos; +}; + +struct find_btree_node_insert_position_result +{ + ::std::size_t pos{}; + bool found{}; +}; + +template +inline constexpr ::fast_io::containers::details::find_btree_node_insert_position_result find_str_btree_node_insert_position(nodetype *node, + typename nodetype::char_type const *keystrptr, ::std::size_t keystrn) noexcept +{ + using char_type = typename nodetype::char_type; + auto *b{node->keys}, *i{b}, *e{b + node->size}; + + ::fast_io::containers::basic_string_view newkey(keystrptr, keystrn); + + bool found{}; + for (; i != e; ++i) + { + auto cmpres{newkey <=> i->strvw()}; + if (cmpres <= 0) + { + found = (cmpres == 0); + break; + } + } + return {static_cast<::std::size_t>(i - b), found}; +} + + +struct find_btree_insert_result +{ + void *node{}; + ::std::size_t pos{}; +}; + +template +inline constexpr ::fast_io::containers::details::find_btree_insert_result str_btree_find(nodetype *node, typename nodetype::char_type const *keystrptr, ::std::size_t keystrn) noexcept +{ + if (node == nullptr) + { + return {}; + } + // **Find the correct position for insertion** + for (;;) + { + auto [postemp, found] = ::fast_io::containers::details::find_str_btree_node_insert_position(node, keystrptr, keystrn); + // **If the key already exists, return false (no duplicate keys)** + if (found) + { + return {node, postemp}; + } + // **If the node is a leaf** + if (node->leaf) + { + break; + } + node = node->childrens[postemp]; + } + return {}; +} + +template +inline constexpr bool str_btree_contains(nodetype *node, typename nodetype::char_type const *keystrptr, ::std::size_t keystrn) noexcept +{ + if (node == nullptr) + { + return false; + } + // **Find the correct position for insertion** + for (;;) + { + auto [postemp, found] = ::fast_io::containers::details::find_str_btree_node_insert_position(node, keystrptr, keystrn); + // **If the key already exists, return false (no duplicate keys)** + if (found) + { + return true; + } + // **If the node is a leaf** + if (node->leaf) + { + break; + } + node = node->childrens[postemp]; + } + return false; +} + +template +#if __has_cpp_attribute(__gnu__::__cold__) +[[__gnu__::__cold__]] +#endif +inline constexpr bool str_btree_insert_key_cold(nodetype *node, ::std::size_t pos, + typename nodetype::char_type const *tempkeystrptr, ::std::size_t tempkeystrn, + ::fast_io::containers::details::btree_imp &imp) noexcept +{ + using char_type = typename nodetype::char_type; + using typed_allocator_type = ::fast_io::typed_generic_allocator_adapter; + + + auto keys{node->keys}; + auto keysit{keys + pos}; + auto keysed{keys + keys_number}; + + constexpr ::std::size_t keys_number_half{keys_number >> (1u)}; + constexpr ::std::size_t keys_number_half_p1{keys_number_half + 1u}; + // ** Split now + auto rightchild{typed_allocator_type::allocate(1)}; + if (node == imp.rightmost) + { + imp.rightmost = rightchild; + } + node->leaf = rightchild->leaf = true; + node->size = rightchild->size = keys_number_half; + + auto rightchildkeys{rightchild->keys}; + // auto rightchildchildrens{rightchild->childrens}; + char_type const *movekeystrptr{}; + ::std::size_t movekeystrn{}; + auto midptr{keys + keys_number_half}; + auto poskeys_number_halfcmp{pos <=> keys_number_half}; + + if (poskeys_number_halfcmp < 0) + { + auto &keystrptrkeysnumber{midptr[-1]}; + movekeystrptr = keystrptrkeysnumber.ptr; + movekeystrn = keystrptrkeysnumber.n; + + ::fast_io::details::non_overlapped_copy_n(midptr, keys_number_half, rightchildkeys); + ::fast_io::freestanding::overlapped_copy(keys + pos, keys + keys_number_half, keys + pos + 1); + + keys[pos] = {tempkeystrptr, tempkeystrn}; + } + else if (poskeys_number_halfcmp == 0) + { + ::fast_io::details::non_overlapped_copy_n(midptr, keys_number_half, rightchildkeys); + movekeystrptr = tempkeystrptr; + movekeystrn = tempkeystrn; + } + else + { + auto &keystrptrkeysnumber{*midptr}; + movekeystrptr = keystrptrkeysnumber.ptr; + movekeystrn = keystrptrkeysnumber.n; + auto it{::fast_io::details::non_overlapped_copy(midptr + 1, keysit, rightchildkeys)}; + *it = {tempkeystrptr, tempkeystrn}; + ++it; + ::fast_io::details::non_overlapped_copy(keysit, keysed, it); + } + ::std::size_t child_pos{node->parent_pos}; + for (auto j{node->parent}; j; j = j->parent) + { + auto jkeys{j->keys}; + auto jchildrens{j->childrens}; + auto jn{j->size}; + + // If parent node has space, insert the promoted key and return + if (jn != keys_number) + { + // Shift keys and children to make room for the promoted key and new child + ::fast_io::freestanding::overlapped_copy(jkeys + child_pos, jkeys + jn, jkeys + child_pos + 1); + auto &jkeyschildpos{jkeys[child_pos]}; + jkeyschildpos.ptr = movekeystrptr; + jkeyschildpos.n = movekeystrn; + ::fast_io::freestanding::overlapped_copy(jchildrens + child_pos + 1, jchildrens + jn + 1, jchildrens + child_pos + 2); + jchildrens[child_pos + 1] = rightchild; + rightchild->parent = j; + rightchild->parent_pos = child_pos + 1; + + for (auto k{jchildrens + (child_pos + 2)}, ked{jchildrens + (jn + 2)}; k != ked; ++k) + { + (*k)->parent_pos = static_cast<::std::size_t>(k - jchildrens); + } + ++j->size; + + return true; + } + // Parent is full, must split upward + auto new_right = typed_allocator_type::allocate(1); + j->leaf = new_right->leaf = false; + j->size = new_right->size = keys_number_half; + + auto jmidptr = jkeys + keys_number_half; + + auto new_right_keys{new_right->keys}; + auto new_right_childrens{new_right->childrens}; + auto child_poskeys_number_halfcmp{child_pos <=> keys_number_half}; + // CASE 1: promoted child is in the left half (before the mid key) + if (child_poskeys_number_halfcmp < 0) + { + + auto &jmidkey = jmidptr[-1]; + auto tmpptr{jmidkey.ptr}; + auto tmpn{jmidkey.n}; + + ::fast_io::details::non_overlapped_copy_n(jmidptr, keys_number_half, new_right_keys); + ::fast_io::freestanding::overlapped_copy(jkeys + child_pos, jmidptr, jkeys + child_pos + 1); + auto &jkeyschildpos{jkeys[child_pos]}; + jkeyschildpos.ptr = movekeystrptr; + jkeyschildpos.n = movekeystrn; + movekeystrptr = tmpptr; + movekeystrn = tmpn; + + ::fast_io::details::non_overlapped_copy_n(jchildrens + keys_number_half, keys_number_half_p1, new_right_childrens); + ::fast_io::freestanding::overlapped_copy(jchildrens + child_pos + 1, jchildrens + keys_number_half_p1, jchildrens + child_pos + 2); + jchildrens[child_pos + 1] = rightchild; + rightchild->parent = j; + rightchild->parent_pos = child_pos + 1; + + for (::std::size_t i{child_pos + 2}; i != keys_number_half_p1; ++i) + { + jchildrens[i]->parent_pos = i; + } + } + else if (child_poskeys_number_halfcmp == 0) + { + ::fast_io::details::non_overlapped_copy_n(jmidptr, keys_number_half, new_right_keys); + *new_right_childrens = rightchild; + ::fast_io::details::non_overlapped_copy_n(jchildrens + keys_number_half_p1, keys_number_half, new_right_childrens + 1); + } + else + { + auto jkeysit{jkeys + child_pos}; + auto jkeysed{jkeys + keys_number}; + auto it{::fast_io::details::non_overlapped_copy(jmidptr + 1, jkeysit, new_right_keys)}; + it->ptr = movekeystrptr; + it->n = movekeystrn; + ++it; + ::fast_io::details::non_overlapped_copy(jkeysit, jkeysed, it); + + auto &jkeystrptrkeysnumber{*jmidptr}; + movekeystrptr = jkeystrptrkeysnumber.ptr; + movekeystrn = jkeystrptrkeysnumber.n; + + auto jchildrensit{jchildrens + child_pos + 1}; + auto jchildrensed{jchildrens + keys_number + 1}; + auto kit{::fast_io::details::non_overlapped_copy(jchildrens + keys_number_half_p1, jchildrensit, new_right_childrens)}; + *kit = rightchild; + ++kit; + ::fast_io::details::non_overlapped_copy(jchildrensit, jchildrensed, kit); + } + + for (auto k{new_right_childrens}, ked{new_right_childrens + keys_number_half_p1}; k != ked; ++k) + { + auto &kref{**k}; + kref.parent = new_right; + kref.parent_pos = static_cast<::std::size_t>(k - new_right_childrens); + } + rightchild = new_right; + child_pos = j->parent_pos; + node = j; + } + auto new_root = typed_allocator_type::allocate(1); + new_root->leaf = false; + new_root->size = 1; + new_root->keys->ptr = movekeystrptr; + new_root->keys->n = movekeystrn; + new_root->parent = nullptr; + new_root->parent_pos = 0; + *(new_root->childrens) = node; + new_root->childrens[1] = rightchild; + node->parent = new_root; + node->parent_pos = 0; + rightchild->parent = new_root; + rightchild->parent_pos = 1; + imp.root = new_root; + + return true; +} + +template +inline constexpr bool str_btree_insert_key_with_root(::fast_io::containers::details::btree_imp &imp, + typename nodetype::char_type const *keystrptr, ::std::size_t keystrn) noexcept +{ + using char_type = typename nodetype::char_type; + using typed_allocator_type = ::fast_io::typed_generic_allocator_adapter; + + auto node{static_cast<::fast_io::containers::details::str_btree_set_node *>(imp.root)}; + + // **If the tree is empty, allocate a new root** + if (node == nullptr) + { + node = typed_allocator_type::allocate(1); + node->size = 1; + node->leaf = true; + node->parent = nullptr; + node->parent_pos = 0; + *(node->keys) = ::fast_io::details::create_associative_string(keystrptr, keystrn); + imp.rightmost = imp.leftmost = imp.root = node; + return true; + } + + ::std::size_t pos; + // **Find the correct position for insertion** + for (;;) + { + auto [postemp, found] = ::fast_io::containers::details::find_str_btree_node_insert_position(node, keystrptr, keystrn); + pos = postemp; + // **If the key already exists, return false (no duplicate keys)** + if (found) + { + return false; + } + // **If the node is a leaf** + if (node->leaf) + { + break; + } + node = node->childrens[pos]; + } + + auto tempkey = ::fast_io::details::create_associative_string(keystrptr, keystrn); + auto n{node->size}; + // **If there is space, insert the key directly** + if (n != keys_number) + { + auto keys{node->keys}; + auto keysit{keys + pos}; + ::fast_io::freestanding::overlapped_copy(keysit, keys + n, keysit + 1); + *keysit = tempkey; + ++node->size; + return true; + } + return ::fast_io::containers::details::str_btree_insert_key_cold(node, pos, tempkey.ptr, tempkey.n, imp); +} + +template +inline constexpr bool str_btree_erase(::fast_io::containers::details::btree_imp &imp, + typename nodetype::char_type const *keystrptr, ::std::size_t keystrn) noexcept +{ + // unfinished + using char_type = typename nodetype::char_type; + using typed_allocator_type = ::fast_io::typed_generic_allocator_adapter>; + using nodeptr +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = ::fast_io::containers::details::str_btree_set_common *; + auto node{static_cast<::fast_io::containers::details::str_btree_set_node *>(imp.root)}; + + auto [it, pos] = ::fast_io::containers::details::str_btree_find(node, keystrptr, keystrn); + if (it == nullptr) + { + return false; + } + constexpr ::std::size_t keys_number_half{keys_number >> 1u}; + auto itv{static_cast(it)}; + auto keys{itv->keys}; + auto keyspos{keys + pos}; + ::fast_io::details::deallocate_associative_string(keyspos->base, keyspos->len); + ::std::size_t n{itv->size}; + + auto parent{static_cast(itv->parent)}; + if (itv->leaf) + { +#ifdef TESTING_STR_BTREE_SET + __builtin_printf("hello world: %s %d\n",__FILE__,__LINE__); +#endif + if (keys_number_half < n) + { + ::fast_io::freestanding::overlapped_copy(keyspos + 1, keys + n, keyspos); + --itv->size; + + return true; + } + else if (parent == nullptr) + { + ::fast_io::freestanding::overlapped_copy(keyspos + 1, keys + n, keyspos); + if (!(--itv->size)) + { + // **Deallocate the node using the allocator** + typed_allocator_type::deallocate_n(itv, 1); + imp = {}; + } + return true; + } + ::std::size_t parpos{itv->parent_pos}; + ::std::size_t parent_size{parent->size}; +#ifdef TESTING_STR_BTREE_SET + __builtin_printf("hello world: %s %d\n",__FILE__,__LINE__); +#endif + nodeptr rightbrother{}; + if (parpos != parent_size) + { + rightbrother = static_cast(parent->childrens[parpos + 1]); + ::std::size_t rightbrothern{rightbrother->size}; + if (rightbrothern < keys_number_half) + { + // Borrow from right brother's leftmost key + auto rightbrotherkeys{rightbrother->keys}; + auto &borrowed_key = *rightbrotherkeys; + auto &parent_key = parent->keys[parpos]; + + // Move borrowed key to current node + keys[n] = parent_key; + ++itv->size; + + // Update parent key + parent_key = borrowed_key; + + // Shift right brother's keys left + ::fast_io::freestanding::overlapped_copy( + rightbrotherkeys + 1, + rightbrotherkeys + rightbrothern, + rightbrotherkeys); + --rightbrother->size; + + return true; + } + } +#ifdef TESTING_STR_BTREE_SET + __builtin_printf("hello world: %s %d\n",__FILE__,__LINE__); +#endif + // Try left brother if right failed + nodeptr leftbrother{}; + if (parpos != 0) + { + leftbrother = static_cast(parent->childrens[parpos - 1]); + ::std::size_t leftbrothern{leftbrother->size}; + if (keys_number_half < leftbrothern) + { + // Borrow from left brother's rightmost key + auto &borrowed_key = leftbrother->keys[leftbrothern - 1]; + auto &parent_key = parent->keys[parpos - 1]; + + // Shift current keys right + ::fast_io::freestanding::overlapped_copy( + keyspos, + keys + n, + keyspos + 1); + + // Insert parent key + *keys = parent_key; + ++itv->size; + + // Update parent key + parent_key = borrowed_key; + --leftbrother->size; +#ifdef TESTING_STR_BTREE_SET + __builtin_printf("hello world: %s %d\n",__FILE__,__LINE__); +#endif + return true; + } + } + // Merge with sibling (prefer right if possible) + if (parpos != parent_size) + { + // Merge with right brother + keys[n] = parent->keys[parpos]; + ::fast_io::freestanding::non_overlapped_copy( + rightbrother->keys, + rightbrother->keys + rightbrother->size, + keys + n + 1); + itv->size += rightbrother->size + 1; + + // Deallocate right brother + typed_allocator_type::deallocate_n(rightbrother, 1); + + // Shift parent's keys and children + ::fast_io::freestanding::overlapped_copy( + parent->keys + parpos + 1, + parent->keys + parent_size, + parent->keys + parpos); + ::fast_io::freestanding::overlapped_copy( + parent->childrens + parpos + 2, + parent->childrens + parent_size + 1, + parent->childrens + parpos + 1); + --parent->size; +#ifdef TESTING_STR_BTREE_SET + __builtin_printf("hello world: %s %d\n",__FILE__,__LINE__); +#endif + return true; + } + else + { + // Merge with left brother + auto &merge_key = parent->keys[parpos - 1]; + ::fast_io::freestanding::non_overlapped_copy( + keys, + keys + n, + leftbrother->keys + leftbrother->size + 1); + leftbrother->keys[leftbrother->size] = merge_key; + leftbrother->size += n + 1; + + // Deallocate current node + typed_allocator_type::deallocate_n(itv, 1); + + // Shift parent's keys and children + ::fast_io::freestanding::overlapped_copy( + parent->keys + parpos, + parent->keys + parent_size, + parent->keys + parpos - 1); + ::fast_io::freestanding::overlapped_copy( + parent->childrens + parpos + 1, + parent->childrens + parent_size + 1, + parent->childrens + parpos); + --parent->size; + + return true; + } + } +#ifdef TESTING_STR_BTREE_SET + __builtin_printf("hello world: %s %d\n",__FILE__,__LINE__); +#endif + +#if 0 + ::fast_io::io::debug_println(::std::source_location::current(),"\t", ::fast_io::mnp::os_c_str_with_known_size(keystrptr, keystrn)); + + + for (auto j{parent}; j; j = static_cast<::fast_io::containers::details::str_btree_set_common *>(j->parent)) + { + bool isroot{itv==imp.root}; + + ::std::size_t parent_size{parent->size}, + parentsizep1{static_cast<::std::size_t>(parent_size+1u)};; + ::std::size_t parent_pos{itv->parent_pos}; + ::std::size_t parent_pos_p1{static_cast<::std::size_t>(parent_pos+1u)}; + auto parentchildrens{parent->childrens}; + if(parent_pos!=parentsizep1) + { + auto nextnode{static_cast(parentchildrens[parent_pos_p1])}; + ::std::size_t const nextsize{nextnode->size}; + if(keys_number_half <= nextsize) + { + + } + else + { + + } + } + else + { + } + } + + else + { + } +#endif + return true; +} + +/* Common structure used for str_btree_set iterator. +Holds the current node pointer, position within node, and optional 'last' for reversed iteration fallback. */ +struct str_btree_set_iterator_common +{ + void const *ptr{}; // Pointer to current node + std::size_t pos{}; // Position within current node + void const *last{}; // Pointer to last node (used for -- from end) +}; + +/* Advances the iterator to the next key in str_btree_set. +Traverses leaf nodes linearly, and climbs up the parent chain when leaf ends. +For internal nodes, descends leftmost into the right child. */ +template <::std::size_t keys_number> +inline constexpr void str_btree_set_next_node(str_btree_set_iterator_common &c) noexcept +{ + auto ptrv{static_cast<::fast_io::containers::details::str_btree_set_common const *>(c.ptr)}; + + if (ptrv->leaf) + { + // Move to next key inside leaf + if (++c.pos == ptrv->size) + { + // Reached end of leaf, climb parent chain to find next sibling + auto parent{ptrv->parent}; + auto parent_pos{static_cast<::fast_io::containers::details::str_btree_set_common const *>(ptrv)->parent_pos}; + while (parent) + { + auto parentn{static_cast<::fast_io::containers::details::str_btree_set_common const *>(parent)->size}; + if (parent_pos != parentn) + { + break; // Found next available key in parent + } + parent_pos = static_cast<::fast_io::containers::details::str_btree_set_common const *>(parent)->parent_pos; + parent = static_cast<::fast_io::containers::details::str_btree_set_common const *>(parent)->parent; + } + c.ptr = parent; + c.pos = parent_pos; + } + } + else + { + // Internal node: descend into leftmost key of right child + auto nextptr{ptrv->childrens[c.pos + 1]}; + while (!static_cast<::fast_io::containers::details::str_btree_set_common const *>(nextptr)->leaf) + { + nextptr = *(static_cast<::fast_io::containers::details::str_btree_set_common const *>(nextptr)->childrens); + } + c.ptr = nextptr; + c.pos = 0; + } +} + +/* Moves the iterator to the previous key in str_btree_set. +From null (end), restores last node. In leaf, moves left or climbs parent. +For internal node, descends rightmost into the left child. */ +template <::std::size_t keys_number> +inline constexpr void str_btree_set_prev_node(str_btree_set_iterator_common &c) noexcept +{ + if (c.ptr == nullptr) + { + // Iterator was at end(); fallback to last node if known + c.ptr = c.last; + // c.ptr must not be nullptr or it is on empty container which is undefined behavior + c.pos = static_cast<::std::size_t>(static_cast<::fast_io::containers::details::str_btree_set_common const *>(c.ptr)->size - 1u); + return; + } + + auto ptrv{static_cast<::fast_io::containers::details::str_btree_set_common const *>(c.ptr)}; + + if (ptrv->leaf) + { + if (!c.pos) + { + // Start of leaf, need to go up to parent and find left sibling + auto parent{ptrv->parent}; + auto parent_pos{static_cast<::fast_io::containers::details::str_btree_set_common const *>(ptrv)->parent_pos}; + while (parent) + { + if (parent_pos) + { + break; // Found non-zero position in parent + } + parent_pos = static_cast<::std::size_t>(static_cast<::fast_io::containers::details::str_btree_set_common const *>(parent)->parent_pos); + parent = static_cast<::fast_io::containers::details::str_btree_set_common const *>(parent)->parent; + } + c.ptr = parent; + c.pos = 0; + if (parent) + { + c.pos = static_cast<::std::size_t>(parent_pos - 1u); + } + return; + } + --c.pos; // Move left inside leaf + } + else + { + // Internal node: descend into rightmost key of left child + auto prevptr{ptrv->childrens[c.pos]}; + while (!static_cast<::fast_io::containers::details::str_btree_set_common const *>(prevptr)->leaf) + { + auto e{static_cast<::fast_io::containers::details::str_btree_set_common const *>(prevptr)}; + prevptr = e->childrens[e->size]; + } + c.ptr = prevptr; + c.pos = static_cast<::std::size_t>(static_cast<::fast_io::containers::details::str_btree_set_common const *>(c.ptr)->size - 1u); + } +} + +template <::std::integral chtype, ::std::size_t keys_number> +class str_btree_set_iterator +{ +public: + using value_type = ::fast_io::containers::basic_cstring_view; + using iterator_tag = ::std::bidirectional_iterator_tag; + using difference_type = ::std::ptrdiff_t; + ::fast_io::containers::details::str_btree_set_iterator_common node; + + constexpr str_btree_set_iterator &operator++() noexcept + { + ::fast_io::containers::details::str_btree_set_next_node(this->node); + return *this; + } + constexpr str_btree_set_iterator operator++(int) noexcept + { + auto tmp{*this}; + ++*this; + return tmp; + } + constexpr str_btree_set_iterator &operator--() noexcept + { + ::fast_io::containers::details::str_btree_set_prev_node(this->node); + return *this; + } + constexpr str_btree_set_iterator operator--(int) noexcept + { + auto tmp{*this}; + --*this; + return tmp; + } + constexpr value_type operator*() const noexcept + { + return static_cast<::fast_io::containers::details::str_btree_set_node const *>(node.ptr)->keys[node.pos].strvw(); + } +}; + +template <::std::integral chtype, ::std::size_t keys_number> +inline constexpr bool operator==(::fast_io::containers::details::str_btree_set_iterator const &a, + ::fast_io::containers::details::str_btree_set_iterator const &b) noexcept +{ + return a.node.ptr == b.node.ptr && a.node.pos == b.node.pos; +} + +template <::std::integral chtype, ::std::size_t keys_number> +inline constexpr bool operator!=(::fast_io::containers::details::str_btree_set_iterator const &a, + ::fast_io::containers::details::str_btree_set_iterator const &b) noexcept +{ + return !operator==(a, b); +} + +} // namespace details + +template <::std::integral chtype, typename Allocator, ::std::size_t keys_number = 16> + requires((keys_number != 0) && ((keys_number & 1) == 0)) +class basic_str_btree_set +{ + using node_type = ::fast_io::containers::details::str_btree_set_node; + using untyped_allocator_type = Allocator; + using typed_allocator_type = ::fast_io::typed_generic_allocator_adapter; + +public: + using char_type = chtype; + using string_view_type = ::fast_io::containers::basic_string_view; + using cstring_view_type = ::fast_io::containers::basic_cstring_view; + using allocator_type = Allocator; + using const_iterator = ::fast_io::containers::details::str_btree_set_iterator; + using iterator = const_iterator; + using const_reverse_iterator = ::std::reverse_iterator; + using reverse_iterator = const_reverse_iterator; + using size_type = ::std::size_t; + using difference_type = ::std::ptrdiff_t; + + ::fast_io::containers::details::btree_imp imp{nullptr, nullptr, nullptr}; + + constexpr basic_str_btree_set() noexcept = default; + + explicit constexpr basic_str_btree_set(::std::initializer_list ilist) noexcept + { + for (auto const &e : ilist) + { + this->insert_key(e); + } + } + + constexpr bool contains(string_view_type key) const noexcept + { + return ::fast_io::containers::details::str_btree_contains(static_cast(this->imp.root), key.ptr, key.n); + } + constexpr size_type count(string_view_type key) const noexcept + { + return static_cast(this->contains(key)); + } + constexpr const_iterator find(string_view_type key) const noexcept + { + auto [ptr, pos] = ::fast_io::containers::details::str_btree_find(static_cast(this->imp.root), key.ptr, key.n); + return {ptr, pos, this->imp.rightmost}; + } + constexpr bool is_empty() const noexcept + { + return this->imp.root == nullptr; + } + constexpr size_type erase_key(string_view_type key) noexcept + { + return ::fast_io::containers::details::str_btree_erase(this->imp, key.ptr, key.n); + } + constexpr bool insert_key(string_view_type key) noexcept + { + return ::fast_io::containers::details::str_btree_insert_key_with_root(this->imp, key.ptr, key.n); + } + +private: + static inline constexpr void clear_node(void *nodev) noexcept + { + auto node{static_cast(nodev)}; + if (node == nullptr) + { + return; + } + ::std::size_t const n{node->size}; + for (::std::size_t i{}; i != n; ++i) + { + if (!node->leaf) + { + clear_node(node->childrens[i]); + } + auto ki{node->keys[i]}; + ::fast_io::typed_generic_allocator_adapter::deallocate_n(const_cast(ki.ptr), + static_cast<::std::size_t>(ki.n + 1u)); + } + if (!node->leaf) + { + clear_node(node->childrens[n]); + } + // **Deallocate the node using the allocator** + typed_allocator_type::deallocate_n(node, 1); + } + +public: + constexpr void clear() noexcept + { + clear_node(this->imp.root); + this->imp = {nullptr, nullptr, nullptr}; + } + + constexpr void clear_destroy() noexcept + { + this->clear(); + } + + constexpr basic_str_btree_set(basic_str_btree_set const &) noexcept = delete; + constexpr basic_str_btree_set &operator=(basic_str_btree_set const &) noexcept = delete; + + constexpr basic_str_btree_set(basic_str_btree_set &&other) noexcept : imp(other.imp) + { + other.imp = {nullptr, nullptr, nullptr}; + } + constexpr basic_str_btree_set &operator=(basic_str_btree_set &&other) noexcept + { + if (__builtin_addressof(other) == this) + { + return *this; + } + this->imp = other.imp; + other.imp = {nullptr, nullptr, nullptr}; + return *this; + } + constexpr const_iterator cbegin() const noexcept + { + return {this->imp.leftmost, 0, this->imp.rightmost}; + } + + constexpr const_iterator cend() const noexcept + { + return {nullptr, 0, this->imp.rightmost}; + } + constexpr const_iterator begin() const noexcept + { + return this->cbegin(); + } + constexpr const_iterator end() const noexcept + { + return this->cend(); + } + + constexpr const_reverse_iterator crbegin() const noexcept + { + return reverse_iterator(cend()); + } + + static inline constexpr size_type max_size() noexcept + { + constexpr size_type mx{::std::numeric_limits::max() / sizeof(node_type)}; + return mx; + } + + static inline constexpr size_type max_size_bytes() noexcept + { + constexpr size_type mx{::std::numeric_limits::max() / sizeof(node_type) * sizeof(node_type)}; + return mx; + } + + constexpr const_reverse_iterator crend() const noexcept + { + return reverse_iterator(cbegin()); + } + constexpr const_reverse_iterator rbegin() const noexcept + { + return this->crbegin(); + } + constexpr const_reverse_iterator rend() const noexcept + { + return this->crend(); + } + constexpr cstring_view_type front() const noexcept + { + if (this->imp.leftmost == nullptr) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + return this->front_unchecked(); + } + constexpr cstring_view_type back() const noexcept + { + if (this->imp.rightmost == nullptr) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + return this->back_unchecked(); + } + constexpr cstring_view_type front_unchecked() const noexcept + { + return static_cast<::fast_io::containers::details::str_btree_set_node const *>(this->imp.leftmost)->keys->strvw(); + } + constexpr cstring_view_type back_unchecked() const noexcept + { + auto &e{*static_cast<::fast_io::containers::details::str_btree_set_node const *>(this->imp.rightmost)}; + return e.keys[e.size - 1u].strvw(); + } + constexpr ~basic_str_btree_set() + { + clear_node(this->imp.root); + } +}; + +} // namespace fast_io::containers diff --git a/include/fast_io_dsal/str_btree_set.h b/include/fast_io_dsal/str_btree_set.h new file mode 100644 index 000000000..33a891c99 --- /dev/null +++ b/include/fast_io_dsal/str_btree_set.h @@ -0,0 +1,78 @@ +#pragma once + +#if !defined(__cplusplus) +#error "You must be using a C++ compiler" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "impl/misc/push_macros.h" +#include "impl/misc/push_warnings.h" +#include "../fast_io_core_impl/freestanding/impl.h" +#include "../fast_io_core_impl/terminate.h" +#include "../fast_io_core_impl/intrinsics/msvc/impl.h" +#include "../fast_io_core_impl/allocation/impl.h" + +#include "impl/freestanding.h" +#include "impl/common.h" +#include "string_view.h" +#include "impl/associative_string.h" +#include "impl/str_btree_set.h" + +#if ((__STDC_HOSTED__ == 1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED == 1) && \ + !defined(_LIBCPP_FREESTANDING)) || \ + defined(FAST_IO_ENABLE_HOSTED_FEATURES)) + +namespace fast_io +{ + +template <::std::integral T, typename Alloc = ::fast_io::native_global_allocator> +using basic_str_btree_set = ::fast_io::containers::basic_str_btree_set; + +using str_btree_set = ::fast_io::basic_str_btree_set; +using wstr_btree_set = ::fast_io::basic_str_btree_set; +using u8str_btree_set = ::fast_io::basic_str_btree_set; +using u16str_btree_set = ::fast_io::basic_str_btree_set; +using u32str_btree_set = ::fast_io::basic_str_btree_set; + +namespace containers +{ + +#if 0 +template <::std::input_iterator InputIt> +basic_str_btree_set(InputIt, InputIt) -> basic_str_btree_set::value_type, ::fast_io::native_global_allocator>; + +#ifdef __cpp_lib_containers_ranges +template <::std::ranges::input_range R> +basic_str_btree_set(::std::from_range_t, R &&) -> basic_str_btree_set<::std::ranges::range_value_t, ::fast_io::native_global_allocator>; +#endif +#endif +} // namespace containers + +namespace tlc +{ +template +using basic_str_btree_set = ::fast_io::containers::basic_str_btree_set; + +using str_btree_set = ::fast_io::tlc::basic_str_btree_set; +using wstr_btree_set = ::fast_io::tlc::basic_str_btree_set; +using u8str_btree_set = ::fast_io::tlc::basic_str_btree_set; +using u16str_btree_set = ::fast_io::tlc::basic_str_btree_set; +using u32str_btree_set = ::fast_io::tlc::basic_str_btree_set; +} // namespace tlc + +} // namespace fast_io + +#endif + +#include "impl/misc/pop_macros.h" +#include "impl/misc/pop_warnings.h" diff --git a/include/fast_io_hosted/platforms/posix_netmode.h b/include/fast_io_hosted/platforms/posix_netmode.h index 101693dd6..a7aabcd8a 100644 --- a/include/fast_io_hosted/platforms/posix_netmode.h +++ b/include/fast_io_hosted/platforms/posix_netmode.h @@ -555,6 +555,10 @@ inline constexpr int to_posix_sock_protocol(sock_protocol dom) noexcept #ifdef IPPROTO_VRRP case sock_protocol::vrrp: return IPPROTO_VRRP; +#endif +#ifdef IPPROTO_QUIC + case sock_protocol::quic: + return IPPROTO_QUIC; #endif default: return -1; diff --git a/include/fast_io_unit/gb18030.h b/include/fast_io_unit/gb18030.h index 5c6342d56..cd40c76b5 100644 --- a/include/fast_io_unit/gb18030.h +++ b/include/fast_io_unit/gb18030.h @@ -14,7 +14,7 @@ namespace details::codecvt::gb18030 inline constexpr char32_t linear_18030(char32_t a, char32_t b, char32_t c, char32_t d) noexcept { - return ((a * static_cast(10) + b) * static_cast(126) + c) * static_cast(10) + d; + return ((a * static_cast(static_cast<::std::uint_least32_t>(10)) + b) * static_cast(static_cast<::std::uint_least32_t>(126)) + c) * static_cast(static_cast<::std::uint_least32_t>(10))tic_cast<::std::uint_least32_t>(10)) + d; } inline constexpr char32_t linear_18030_base{linear_18030(0x81, 0x30, 0x81, 0x30)}; @@ -66,7 +66,7 @@ inline constexpr ::std::size_t lookup_uni_to_gb18030(char32_t cdpt, T *p_dst) no { char32_t v{lookup_uni_to_gb18030_tb[cdpt]}; char16_t v2{static_cast(v)}; - if (static_cast(v2) == v) + if (static_cast(static_cast<::std::uint_least32_t>(v2)) == v) { if constexpr ((!::std::is_volatile_v) && (::std::endian::native == ::std::endian::little || ::std::endian::native == ::std::endian::big)) @@ -141,9 +141,9 @@ inline constexpr ::std::size_t get_gb18030_code_units_unhappy(char32_t cdpt, T * auto const &e{gb18030_ranges[i]}; auto const e0{e[0]}; auto const e1{e[1]}; - char32_t diff{static_cast(e1 - e0)}; + char32_t diff{static_cast(static_cast<::std::uint_least32_t>(e1 - e0))}; sum += diff; - if (static_cast(cdpt - e0) < diff) + if (static_cast(static_cast<::std::uint_least32_t>(cdpt - e0)) < diff) { char32_t e2{e[2]}; char32_t gb{cdpt - e0 + e2}; @@ -157,7 +157,7 @@ inline constexpr ::std::size_t get_gb18030_code_units_unhappy(char32_t cdpt, T * *p_dst = static_cast(0x81 + gb); return 4; } - else if (static_cast(cdpt - e1) < static_cast(gb18030_ranges[i + 1][0] - e1)) + else if (static_cast(static_cast<::std::uint_least32_t>(cdpt - e1)) < static_cast(static_cast<::std::uint_least32_t>(gb18030_ranges[i + 1][0] - e1))) { return lookup_uni_to_gb18030(cdpt - sum, p_dst); } @@ -172,7 +172,7 @@ inline constexpr ::std::size_t lookup_uni_to_gb18030_pdsz(char32_t cdpt, T *p_ds { char32_t v{lookup_uni_to_gb18030_tb[cdpt]}; char16_t v2{static_cast(v)}; - if (static_cast(v2) == v) + if (static_cast(static_cast<::std::uint_least32_t>(v2)) == v) { if (pdstsz < 2) { @@ -254,9 +254,9 @@ inline constexpr ::std::size_t get_gb18030_code_units_unhappy_pdstsz(char32_t u3 auto const &e{gb18030_ranges[i]}; auto const e0{e[0]}; auto const e1{e[1]}; - char32_t diff{static_cast(e1 - e0)}; + char32_t diff{static_cast(static_cast<::std::uint_least32_t>(e1 - e0))}; sum += diff; - if (static_cast(u32 - e0) < diff) + if (static_cast(static_cast<::std::uint_least32_t>(u32 - e0)) < diff) { char32_t e2{e[2]}; char32_t gb{u32 - e0 + e2}; @@ -274,7 +274,7 @@ inline constexpr ::std::size_t get_gb18030_code_units_unhappy_pdstsz(char32_t u3 *p_dst = static_cast(0x81 + gb); return 4; } - else if (static_cast(u32 - e1) < static_cast(gb18030_ranges[i + 1][0] - e1)) + else if (static_cast(static_cast<::std::uint_least32_t>(u32 - e1)) < static_cast(static_cast<::std::uint_least32_t>(gb18030_ranges[i + 1][0] - e1))) { return lookup_uni_to_gb18030(u32 - sum, p_dst); } @@ -315,11 +315,11 @@ inline constexpr char32_t utf32cp_by_gb18030_index(char32_t index) noexcept auto const &e{gb18030_ranges[i]}; auto const e0{e[0]}; auto const e1{e[1]}; - sum += static_cast(e1 - e0); + sum += static_cast(static_cast<::std::uint_least32_t>(e1 - e0)); auto const e2{e[2]}; auto const e3{e[3]}; - char32_t diff{static_cast(e3 - e2)}; - if (static_cast(index - e2) <= diff) + char32_t diff{static_cast(static_cast<::std::uint_least32_t>(e3 - e2))}; + if (static_cast(static_cast<::std::uint_least32_t>(index - e2)) <= diff) { return index - e[2] + e[0]; } @@ -361,7 +361,7 @@ inline constexpr gb18030_advance_unchecked_result gb18030_advance_unchecked(T --c; } return { - lookup_gb18030_to_uni2_tb[static_cast((static_cast(src0) - 0x81) * 190u + (c - 0x40))], + lookup_gb18030_to_uni2_tb[static_cast((static_cast(static_cast<::std::uint_least32_t>(src0)) - 0x81) * 190u + (c - 0x40))], 2}; } else if ((src1 < 0x30) | (src1 == 0xFF)) @@ -415,7 +415,7 @@ inline constexpr gb18030_advance_unchecked_result gb18030_advance(T const *sr --c; } return { - lookup_gb18030_to_uni2_tb[static_cast((static_cast(src0) - 0x81) * 190u + (c - 0x40))], + lookup_gb18030_to_uni2_tb[static_cast((static_cast(static_cast<::std::uint_least32_t>(src0)) - 0x81) * 190u + (c - 0x40))], 2}; } else if ((src1 < 0x30) | (src1 == 0xFF)) diff --git a/tests/0026.container/0013.str_btree_set/str_btree_set.cc b/tests/0026.container/0013.str_btree_set/str_btree_set.cc new file mode 100644 index 000000000..11c49ddb7 --- /dev/null +++ b/tests/0026.container/0013.str_btree_set/str_btree_set.cc @@ -0,0 +1,82 @@ + +#include +#include + +int main() +{ + ::fast_io::str_btree_set bset; + constexpr ::fast_io::string_view fruits[]{ + ::fast_io::string_view("kiwi"), + ::fast_io::string_view("ugli"), + ::fast_io::string_view("lemon"), + ::fast_io::string_view("fig"), + ::fast_io::string_view("zucchini"), + ::fast_io::string_view("honeydew"), + ::fast_io::string_view("raspberry"), + ::fast_io::string_view("orange"), + ::fast_io::string_view("vanilla"), + ::fast_io::string_view("yellowfruit"), + ::fast_io::string_view("date"), + ::fast_io::string_view("grape"), + ::fast_io::string_view("strawberry"), + ::fast_io::string_view("cherry"), + ::fast_io::string_view("quince"), + ::fast_io::string_view("apple"), + ::fast_io::string_view("elderberry"), + ::fast_io::string_view("banana"), + ::fast_io::string_view("nectarine"), + ::fast_io::string_view("watermelon"), + ::fast_io::string_view("xigua"), + ::fast_io::string_view("papaya"), + ::fast_io::string_view("mango")}; + + for (auto const &e : fruits) + { + bset.insert_key(e); + } + + for (auto const &e : bset) + { + ::fast_io::io::println(e); + } + + ::fast_io::io::print("\nreverse:\n"); +/* +// ::std::ranges::reverse_view does not pass CI + for (auto const &e : ::std::ranges::reverse_view(bset)) +*/ + for(auto i{bset.crbegin()},ed{bset.crend()};i!=ed;++i) + { + auto const& e{*i}; + ::fast_io::io::println(e); + } + + ::fast_io::io::print("\nfront()=", bset.front(), "\tback()=", bset.back(), "\nbset.find(\"xigua\"):\n"); + { + auto it{bset.find("xigua")}; + if (it == bset.cend()) + { + ::fast_io::io::print("not found\n"); + } + else + { + ::fast_io::io::println("found: ", *it); + } + } + + ::fast_io::io::print("bset.find(\"buffalo\"):\n"); + { + auto it{bset.find("buffalo")}; + if (it == bset.cend()) + { + ::fast_io::io::print("not found\n"); + } + else + { + ::fast_io::io::println("found: ", *it); + } + } + + bset.erase_key("apple"); + //bset.erase_key("banana"); +}