diff --git a/benchmark/0011.containers/deque/.test_prop.toml b/benchmark/0011.containers/deque/.test_prop.toml new file mode 100644 index 00000000..c19ff243 --- /dev/null +++ b/benchmark/0011.containers/deque/.test_prop.toml @@ -0,0 +1,2 @@ +["0003.insert_range"] +ignore = true diff --git a/benchmark/0011.containers/deque/0003.insert_range/fast_io.cc b/benchmark/0011.containers/deque/0003.insert_range/fast_io.cc new file mode 100644 index 00000000..15d2f324 --- /dev/null +++ b/benchmark/0011.containers/deque/0003.insert_range/fast_io.cc @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"fast_io::deque"); + fast_io::deque dq; + constexpr std::size_t n{50000}; + + { + fast_io::timer t(u8"insert_range_index"); + for (std::size_t i{}; i != n; ++i) + { + ::std::size_t dqsz{dq.size()}; + std::size_t pos = dqsz ? (i % dqsz) : 0; + std::size_t tmp[4]{i, i + 1, i + 2, i + 3}; + dq.insert_range_index(pos, tmp); + } + } + + std::size_t sum{}; + { + fast_io::timer t(u8"loop"); + for (auto const e : dq) + { + sum += e; + } + } + + fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0003.insert_range/std.cc b/benchmark/0011.containers/deque/0003.insert_range/std.cc new file mode 100644 index 00000000..5fb70b6a --- /dev/null +++ b/benchmark/0011.containers/deque/0003.insert_range/std.cc @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"std::deque"); + ::std::deque dq; + constexpr std::size_t n{50000}; + + { + fast_io::timer t(u8"insert_range"); + for (std::size_t i{}; i != n; ++i) + { + ::std::size_t dqsz{dq.size()}; + std::size_t pos = dqsz ? (i % dqsz) : 0; + std::size_t tmp[4]{i, i + 1, i + 2, i + 3}; + dq.insert_range(dq.cbegin() + pos, tmp); + } + } + + std::size_t sum{}; + { + fast_io::timer t(u8"loop"); + for (auto const e : dq) + { + sum += e; + } + } + + fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0005.indexing/fast_io.cc b/benchmark/0011.containers/deque/0005.indexing/fast_io.cc new file mode 100644 index 00000000..a4ba655d --- /dev/null +++ b/benchmark/0011.containers/deque/0005.indexing/fast_io.cc @@ -0,0 +1,26 @@ +#include +#include +#include + +int main() +{ + ::fast_io::timer tm(u8"fast_io::deque"); + ::fast_io::deque deq; + constexpr std::size_t n{100000000}; + { + ::fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_back(i); + } + } + ::std::size_t sum{}; + { + ::fast_io::timer tm1(u8"indexing loop"); + for (::std::size_t i{}, sz{deq.size()}; i != sz; ++i) + { + sum += deq[i]; + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0005.indexing/fast_io_index_unchecked.cc b/benchmark/0011.containers/deque/0005.indexing/fast_io_index_unchecked.cc new file mode 100644 index 00000000..1fffc100 --- /dev/null +++ b/benchmark/0011.containers/deque/0005.indexing/fast_io_index_unchecked.cc @@ -0,0 +1,26 @@ +#include +#include +#include + +int main() +{ + ::fast_io::timer tm(u8"fast_io::deque unchecked"); + ::fast_io::deque deq; + constexpr std::size_t n{100000000}; + { + ::fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_back(i); + } + } + ::std::size_t sum{}; + { + ::fast_io::timer tm1(u8"indexing unchecked loop"); + for (::std::size_t i{}, sz{deq.size()}; i != sz; ++i) + { + sum += deq.index_unchecked(i); + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0005.indexing/fast_io_vec.cc b/benchmark/0011.containers/deque/0005.indexing/fast_io_vec.cc new file mode 100644 index 00000000..f63bc208 --- /dev/null +++ b/benchmark/0011.containers/deque/0005.indexing/fast_io_vec.cc @@ -0,0 +1,26 @@ +#include +#include +#include + +int main() +{ + ::fast_io::timer tm(u8"fast_io::vector"); + ::fast_io::vector vec; + constexpr std::size_t n{100000000}; + { + ::fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + vec.push_back(i); + } + } + ::std::size_t sum{}; + { + ::fast_io::timer tm1(u8"indexing loop"); + for (::std::size_t i{}, sz{vec.size()}; i != sz; ++i) + { + sum += vec[i]; + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0005.indexing/fast_io_vec_reserve.cc b/benchmark/0011.containers/deque/0005.indexing/fast_io_vec_reserve.cc new file mode 100644 index 00000000..c756605f --- /dev/null +++ b/benchmark/0011.containers/deque/0005.indexing/fast_io_vec_reserve.cc @@ -0,0 +1,27 @@ +#include +#include +#include + +int main() +{ + ::fast_io::timer tm(u8"fast_io::vector reserve"); + ::fast_io::vector vec; + constexpr std::size_t n{100000000}; + vec.reserve(n); + { + fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + vec.push_back(i); + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"indexing loop"); + for (::std::size_t i{}, sz{vec.size()}; i != sz; ++i) + { + sum += vec[i]; + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0005.indexing/fast_io_vec_unchecked.cc b/benchmark/0011.containers/deque/0005.indexing/fast_io_vec_unchecked.cc new file mode 100644 index 00000000..9095eea0 --- /dev/null +++ b/benchmark/0011.containers/deque/0005.indexing/fast_io_vec_unchecked.cc @@ -0,0 +1,27 @@ +#include +#include +#include + +int main() +{ + ::fast_io::timer tm(u8"fast_io::vector unchecked"); + ::fast_io::vector vec; + constexpr std::size_t n{100000000}; + vec.reserve(n); + { + fast_io::timer tm1(u8"push_back_unchecked"); + for (std::size_t i{}; i != n; ++i) + { + vec.push_back_unchecked(i); + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"indexing unchecked loop"); + for (::std::size_t i{}, sz{vec.size()}; i != sz; ++i) + { + sum += vec.index_unchecked(i); + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0005.indexing/std.cc b/benchmark/0011.containers/deque/0005.indexing/std.cc new file mode 100644 index 00000000..95b7494f --- /dev/null +++ b/benchmark/0011.containers/deque/0005.indexing/std.cc @@ -0,0 +1,26 @@ +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"std::deque"); + ::std::deque deq; + constexpr std::size_t n{100000000}; + { + fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_back(i); + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"indexing loop"); + for (::std::size_t i{}, sz{deq.size()}; i != sz; ++i) + { + sum += deq[i]; + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0006.sort/fast_io.cc b/benchmark/0011.containers/deque/0006.sort/fast_io.cc new file mode 100644 index 00000000..c6503033 --- /dev/null +++ b/benchmark/0011.containers/deque/0006.sort/fast_io.cc @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +int main() +{ + constexpr std::size_t n{1000000}; + ::std::mt19937_64 eng; + ::std::uniform_int_distribution<::std::size_t> dis(0, SIZE_MAX); + + ::fast_io::timer tm(u8"fast_io::deque"); + ::fast_io::deque deq; + { + ::fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_back(dis(eng)); + } + } + { + ::fast_io::timer tm1(u8"sort"); + ::std::ranges::sort(deq); + } + ::std::size_t sum{}; + { + ::fast_io::timer tm1(u8"loop"); + for (auto const &e : deq) + { + sum += e; + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0006.sort/fast_io_vec.cc b/benchmark/0011.containers/deque/0006.sort/fast_io_vec.cc new file mode 100644 index 00000000..946ed4c3 --- /dev/null +++ b/benchmark/0011.containers/deque/0006.sort/fast_io_vec.cc @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +int main() +{ + constexpr std::size_t n{1000000}; + ::std::mt19937_64 eng; + ::std::uniform_int_distribution<::std::size_t> dis(0, SIZE_MAX); + + ::fast_io::timer tm(u8"fast_io::vector"); + ::fast_io::vector deq; + { + ::fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_back(dis(eng)); + } + } + { + ::fast_io::timer tm1(u8"sort"); + ::std::ranges::sort(deq); + } + ::std::size_t sum{}; + { + ::fast_io::timer tm1(u8"loop"); + for (auto const &e : deq) + { + sum += e; + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/benchmark/0011.containers/deque/0006.sort/std.cc b/benchmark/0011.containers/deque/0006.sort/std.cc new file mode 100644 index 00000000..ce8262ee --- /dev/null +++ b/benchmark/0011.containers/deque/0006.sort/std.cc @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +int main() +{ + constexpr std::size_t n{1000000}; + ::std::mt19937_64 eng; + ::std::uniform_int_distribution<::std::size_t> dis(0, SIZE_MAX); + + ::fast_io::timer tm(u8"std::deque"); + ::std::deque deq; + { + ::fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_back(dis(eng)); + } + } + { + ::fast_io::timer tm1(u8"sort"); + ::std::ranges::sort(deq); + } + ::std::size_t sum{}; + { + ::fast_io::timer tm1(u8"loop"); + for (auto const &e : deq) + { + sum += e; + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/fuzzing/0007.containers/deque/fuzz_deque_insert.cc b/fuzzing/0007.containers/deque/fuzz_deque_insert.cc new file mode 100644 index 00000000..1c0e5463 --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_insert.cc @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) +{ + ::fast_io::deque dq; + std::deque ref; + + for (size_t i{}; i != size; ++i) + { + uint8_t b = data[i]; + + uint8_t op = b & 0x3u; // 4 operations + std::size_t len = (b >> 2) & 0x7u; // insert 0–7 elements + + // Always valid position: [0, size] + std::size_t pos = dq.size() == 0 ? 0 : (static_cast(b) * 37u) % (dq.size() + 1); + + // Build deterministic range + std::vector rg; + rg.reserve(len); + for (std::size_t j{}; j < len; ++j) + { + rg.push_back(i * 1315423911ull + j); + } + + switch (op) + { + case 0: // insert_range_index + { + dq.insert_range_index(pos, rg); + ref.insert(ref.begin() + pos, rg.begin(), rg.end()); + break; + } + + case 1: // insert_range using iterator + { + auto it = dq.insert_range(dq.cbegin() + pos, rg); + (void)it; + ref.insert(ref.begin() + pos, rg.begin(), rg.end()); + break; + } + + case 2: // erase single element (to keep sizes bounded) + { + if (!ref.empty()) + { + std::size_t p = pos % ref.size(); + dq.erase_index(p); + ref.erase(ref.begin() + p); + } + break; + } + + case 3: // erase small range + { + if (!ref.empty()) + { + std::size_t p = pos % ref.size(); + std::size_t rlen = len % (ref.size() - p); + dq.erase_index(p, p + rlen); + ref.erase(ref.begin() + p, ref.begin() + p + rlen); + } + break; + } + } + + // Validate correctness + if (dq.size() != ref.size()) + { + __builtin_trap(); + } + + if (!std::ranges::equal(dq, ref)) + { + __builtin_trap(); + } + } + + return 0; +} diff --git a/include/fast_io_core_impl/allocation/win32_heapalloc.h b/include/fast_io_core_impl/allocation/win32_heapalloc.h index 82596bee..ea8fa37b 100644 --- a/include/fast_io_core_impl/allocation/win32_heapalloc.h +++ b/include/fast_io_core_impl/allocation/win32_heapalloc.h @@ -154,6 +154,14 @@ class win32_heapalloc_allocator { return ::fast_io::details::win32_heapalloc_common_impl(n, 0x00000008u); } +#if __has_cpp_attribute(__gnu__::__malloc__) + [[__gnu__::__malloc__]] +#endif + static inline void *allocate_conditional_zero(::std::size_t n, bool zeroing) noexcept + { + return ::fast_io::details::win32_heapalloc_common_impl(n, zeroing ? 0x00000008u : 0u); + } + static inline void *reallocate(void *addr, ::std::size_t n) noexcept { return ::fast_io::details::win32_heaprealloc_common_impl(addr, n, 0u); @@ -162,6 +170,10 @@ class win32_heapalloc_allocator { return ::fast_io::details::win32_heaprealloc_common_impl(addr, n, 0x00000008u); } + static inline void *reallocate_conditional_zero(void *addr, ::std::size_t n, bool zeroing) noexcept + { + return ::fast_io::details::win32_heaprealloc_common_impl(addr, n, zeroing ? 0x00000008u : 0u); + } static inline void deallocate(void *addr) noexcept { if (addr == nullptr) [[unlikely]] diff --git a/include/fast_io_core_impl/freestanding/algorithm.h b/include/fast_io_core_impl/freestanding/algorithm.h index 279d67d4..cd64e6e0 100644 --- a/include/fast_io_core_impl/freestanding/algorithm.h +++ b/include/fast_io_core_impl/freestanding/algorithm.h @@ -436,7 +436,8 @@ inline constexpr output_iter non_overlapped_copy(input_iter first, input_iter la } template <::std::contiguous_iterator input_iter, ::std::contiguous_iterator output_iter> - requires(::std::same_as<::std::iter_value_t, ::std::iter_value_t>) + requires(::std::same_as<::std::iter_value_t, ::std::iter_value_t> && + ::std::is_trivially_copyable_v<::std::iter_value_t>) inline constexpr output_iter overlapped_copy(input_iter first, input_iter last, output_iter result) { if (__builtin_is_constant_evaluated()) @@ -485,7 +486,8 @@ inline constexpr output_iter overlapped_copy(input_iter first, input_iter last, } template <::std::contiguous_iterator input_iter, ::std::contiguous_iterator output_iter> - requires(::std::same_as<::std::iter_value_t, ::std::iter_value_t>) + requires(::std::same_as<::std::iter_value_t, ::std::iter_value_t> && + ::std::is_trivially_copyable_v<::std::iter_value_t>) inline output_iter overlapped_copy_n(input_iter first, ::std::size_t count, output_iter result) { if (__builtin_is_constant_evaluated()) @@ -773,9 +775,12 @@ uninitialized_copy_n(InputIt first, ::std::size_t n, NoThrowForwardIt d_first) n NoThrowForwardIt current; inline constexpr ~destroyer() noexcept { - for (; d_first != current; ++d_first) + if constexpr (!::std::is_trivially_destructible_v) { - d_first->~T(); + for (; d_first != current; ++d_first) + { + d_first->~T(); + } } } }; diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index e0746405..1ced898e 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -31,6 +31,9 @@ inline constexpr ::std::size_t deque_block_size_common{static_cast<::std::size_t template <::std::size_t sz> inline constexpr ::std::size_t deque_block_size{sz <= (deque_block_size_common / 16u) ? ::std::bit_ceil(static_cast<::std::size_t>(deque_block_size_common / sz)) : static_cast<::std::size_t>(16u)}; +template <::std::size_t sz> +inline constexpr ::std::size_t deque_block_bytes{sz * ::fast_io::containers::details::deque_block_size}; + struct #if __has_cpp_attribute(__gnu__::__may_alias__) [[__gnu__::__may_alias__]] @@ -82,31 +85,48 @@ struct }; template -inline constexpr void deque_add_assign_signed_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept +inline constexpr void deque_add_assign_signed_impl( + ::fast_io::containers::details::deque_control_block &itercontent, + ::std::ptrdiff_t pos) noexcept { - using size_type = ::std::size_t; - constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - constexpr size_type blocksizem1{blocksize - 1u}; - size_type unsignedpos{static_cast(pos)}; - auto begin_ptr{itercontent.begin_ptr}; + constexpr ::std::size_t blocksize{::fast_io::containers::details::deque_block_size}; + constexpr ::std::ptrdiff_t signedblocksize{static_cast<::std::ptrdiff_t>(blocksize)}; + auto curr_ptr{itercontent.curr_ptr}; - auto controllerptr{itercontent.controller_ptr}; - size_type diff{static_cast(curr_ptr - begin_ptr)}; - if (pos < 0) + // Signed offset inside current block + ::std::ptrdiff_t offset{pos + (curr_ptr - itercontent.begin_ptr)}; + + // Fast path: stays inside the same block + if (static_cast<::std::size_t>(offset) < blocksize) { - constexpr size_type zero{}; - size_type abspos{static_cast(zero - unsignedpos)}; - diff = (blocksizem1 + abspos) - diff; - curr_ptr = (begin_ptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + itercontent.curr_ptr = curr_ptr + pos; } else { - diff += unsignedpos; - curr_ptr = (begin_ptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + // Compute block jump with correct signed semantics + ::std::ptrdiff_t node_offset; + if (offset < 0) + { + node_offset = (offset + 1) / signedblocksize - 1; + } + else + { + node_offset = static_cast<::std::ptrdiff_t>(static_cast<::std::size_t>(offset) / blocksize); + } + + // Move to the correct block + auto begin_ptr{*(itercontent.controller_ptr += node_offset)}; + itercontent.begin_ptr = begin_ptr; + + // Normalize pointer inside the block + itercontent.curr_ptr = begin_ptr + (offset - node_offset * signedblocksize); } - itercontent.begin_ptr = begin_ptr; - itercontent.curr_ptr = curr_ptr; - itercontent.controller_ptr = controllerptr; +} + +template +inline constexpr void deque_sub_assign_signed_impl(::fast_io::containers::details::deque_control_block &it, ::std::ptrdiff_t pos) noexcept +{ + ::fast_io::containers::details::deque_add_assign_signed_impl(it, -pos); } template @@ -115,84 +135,101 @@ inline constexpr void deque_add_assign_unsigned_impl(::fast_io::containers::deta using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - size_type diff{static_cast(itercontent.curr_ptr - itercontent.begin_ptr) + unsignedpos}; - auto begin_ptr{*(itercontent.controller_ptr += diff / blocksize)}; - itercontent.begin_ptr = begin_ptr; - itercontent.curr_ptr = begin_ptr + diff % blocksize; + auto begin_ptr{itercontent.begin_ptr}; + auto curr_ptr{itercontent.curr_ptr}; + size_type diff{static_cast(curr_ptr - begin_ptr) + unsignedpos}; + if (diff < blocksize) + { + itercontent.curr_ptr = curr_ptr + unsignedpos; + } + else + { + begin_ptr = *(itercontent.controller_ptr += diff / blocksize); + itercontent.begin_ptr = begin_ptr; + itercontent.curr_ptr = begin_ptr + diff % blocksize; + } } template -inline constexpr void deque_sub_assign_signed_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept +inline constexpr void deque_sub_assign_unsigned_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; constexpr size_type blocksizem1{blocksize - 1u}; - size_type unsignedpos{static_cast(pos)}; auto begin_ptr{itercontent.begin_ptr}; auto curr_ptr{itercontent.curr_ptr}; - auto controllerptr{itercontent.controller_ptr}; - size_type diff{static_cast(curr_ptr - begin_ptr)}; - if (pos < 0) + size_type offset{static_cast(curr_ptr - begin_ptr)}; + if (unsignedpos <= offset) { - constexpr size_type zero{}; - size_type abspos{static_cast(zero - unsignedpos)}; - diff += abspos; - curr_ptr = (begin_ptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + itercontent.curr_ptr = curr_ptr - unsignedpos; } else { - diff = blocksizem1 + unsignedpos - diff; - curr_ptr = (begin_ptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + size_type diff{blocksizem1 + unsignedpos - offset}; + begin_ptr = (*(itercontent.controller_ptr -= diff / blocksize)); + itercontent.begin_ptr = begin_ptr; + itercontent.curr_ptr = begin_ptr + (blocksizem1 - diff % blocksize); } - itercontent.begin_ptr = begin_ptr; - itercontent.curr_ptr = curr_ptr; - itercontent.controller_ptr = controllerptr; } template -inline constexpr void deque_sub_assign_unsigned_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept +inline constexpr T &deque_index_signed(::fast_io::containers::details::deque_control_block const &itercontent, ::std::ptrdiff_t pos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - constexpr size_type blocksizem1{blocksize - 1u}; - size_type diff{blocksizem1 + unsignedpos - - static_cast(itercontent.curr_ptr - itercontent.begin_ptr)}; - auto begin_ptr{*(itercontent.controller_ptr -= diff / blocksize)}; - itercontent.begin_ptr = begin_ptr; - itercontent.curr_ptr = begin_ptr + (blocksizem1 - diff % blocksize); + constexpr ::std::ptrdiff_t signedblocksize{static_cast<::std::ptrdiff_t>(blocksize)}; + + auto curr_ptr{itercontent.curr_ptr}; + // Signed offset inside current block + ::std::ptrdiff_t offset{pos + (curr_ptr - itercontent.begin_ptr)}; + + // Fast path: stays inside the same block + if (static_cast<::std::size_t>(offset) < blocksize) + { + return curr_ptr[pos]; + } + else + { + // Compute block jump with correct signed semantics + ::std::ptrdiff_t node_offset; + if (offset < 0) + { + node_offset = (offset + 1) / signedblocksize - 1; + } + else + { + node_offset = static_cast<::std::ptrdiff_t>(static_cast<::std::size_t>(offset) / blocksize); + } + return itercontent.controller_ptr[node_offset][offset - node_offset * signedblocksize]; + } } template -inline constexpr T &deque_index_signed(::fast_io::containers::details::deque_control_block const &itercontent, ::std::ptrdiff_t pos) noexcept +inline constexpr T &deque_index_unsigned(::fast_io::containers::details::deque_control_block const &itercontent, ::std::size_t unsignedpos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - constexpr size_type blocksizem1{blocksize - 1u}; - size_type unsignedpos{static_cast(pos)}; - auto begin_ptr{itercontent.begin_ptr}; auto curr_ptr{itercontent.curr_ptr}; - auto controllerptr{itercontent.controller_ptr}; - size_type diff{static_cast(curr_ptr - begin_ptr)}; - if (pos < 0) + size_type const diff{static_cast(curr_ptr - itercontent.begin_ptr) + unsignedpos}; + if (diff < blocksize) { - constexpr size_type zero{}; - size_type abspos{static_cast(zero - unsignedpos)}; - diff = blocksizem1 + abspos - diff; - return (*(controllerptr - diff / blocksize))[blocksizem1 - diff % blocksize]; + // Fast path: stays inside the same block + return curr_ptr[unsignedpos]; } else { - diff += unsignedpos; - return controllerptr[diff / blocksize][diff % blocksize]; + return itercontent.controller_ptr[diff / blocksize][diff % blocksize]; } } template -inline constexpr T &deque_index_unsigned(::fast_io::containers::details::deque_control_block const &itercontent, ::std::size_t unsignedpos) noexcept +inline constexpr T &deque_index_container_unsigned(::fast_io::containers::details::deque_control_block const &itercontent, ::std::size_t unsignedpos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - size_type const diff{static_cast(itercontent.curr_ptr - itercontent.begin_ptr) + unsignedpos}; + auto curr_ptr{itercontent.curr_ptr}; + size_type const diff{static_cast(curr_ptr - itercontent.begin_ptr) + unsignedpos}; + // Container should not have fast path because container cannot have locality like iterator[] does return itercontent.controller_ptr[diff / blocksize][diff % blocksize]; } @@ -392,7 +429,6 @@ inline constexpr auto operator<=>(::fast_io::containers::details::deque_iterator return block3way; } - template inline constexpr void deque_destroy_trivial_common_align(controllerblocktype &controller, ::std::size_t aligns, ::std::size_t totalsz) noexcept { @@ -600,6 +636,7 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp #endif using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; auto [allocated_blocks_ptr, allocated_blocks_count] = block_typed_allocator::allocate_at_least(initial_allocated_block_counts_with_sentinel); + // we need a null terminator as sentinel like c style string does --allocated_blocks_count; auto &controller_block{controller.controller_block}; @@ -626,237 +663,6 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp back_block.curr_ptr = halfposptr; } -template -inline constexpr void deque_allocate_on_empty_common_impl(dequecontroltype &controller, ::std::size_t align, ::std::size_t bytes) noexcept -{ - constexpr ::std::size_t initial_allocated_block_counts{3}; - ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl(controller, align, bytes, initial_allocated_block_counts); -} - -template -inline constexpr void deque_grow_back_common_impl( - dequecontroltype &controller, - std::size_t align, - std::size_t bytes) noexcept -{ - /** - * If the deque is empty, allocate the initial controller array - * and a single data block. This sets up the initial front/back - * block pointers and the sentinel. - */ - if (controller.controller_block.controller_start_ptr == nullptr) - { - ::fast_io::containers::details:: - deque_allocate_on_empty_common_impl(controller, align, bytes); - return; - } - - using replacetype = typename dequecontroltype::replacetype; - constexpr bool isvoidplaceholder = std::same_as; - using begin_ptrtype = - std::conditional_t; - - /** - * Compute how many controller slots remain between the current - * back block and controller_after_reserved_ptr. - * - * We require at least: - * - 1 slot for the new block pointer - * - 1 slot for the sentinel nullptr - */ - std::size_t diff_to_after_ptr = - static_cast( - controller.controller_block.controller_after_reserved_ptr - - controller.back_block.controller_ptr); - if (diff_to_after_ptr < 2) - { - /** - * If controller_after_reserved_ptr == controller_after_ptr, - * the controller array is physically full. We must rebalance - * or grow the controller array before inserting anything. - */ - if (controller.controller_block.controller_after_reserved_ptr == - controller.controller_block.controller_after_ptr) - { - ::fast_io::containers::details:: - deque_rebalance_or_grow_2x_after_blocks_impl(controller); - } - std::size_t diff_to_after_ptr2 = - static_cast( - controller.controller_block.controller_after_reserved_ptr - - controller.back_block.controller_ptr); - if (diff_to_after_ptr2 < 2) - { - begin_ptrtype new_block; - - /** - * Borrow a capacity block from the front if available. - * - * A capacity block exists at the front if - * controller_start_reserved_ptr != front_block.controller_ptr. - * - * Such a block contains no constructed elements and its memory - * can be reused directly as the new back block. - */ - if (controller.controller_block.controller_start_reserved_ptr != - controller.front_block.controller_ptr) - { - auto start_reserved_ptr = - controller.controller_block.controller_start_reserved_ptr; - - /* Reuse the block memory. */ - new_block = static_cast(*start_reserved_ptr); - - /* Consume one reserved block from the front. */ - ++controller.controller_block.controller_start_reserved_ptr; - } - else - { - /** - * No front capacity block is available. Allocate a new block. - */ - new_block = - static_cast(allocator::allocate_aligned(align, bytes)); - } - - /** - * Insert the new block pointer at controller_after_reserved_ptr, - * then advance controller_after_reserved_ptr and write the sentinel. - */ - auto pos{controller.controller_block.controller_after_reserved_ptr}; - ::std::construct_at(pos, new_block); - *(controller.controller_block.controller_after_reserved_ptr = pos + 1) = nullptr; - } - } - - if (controller.back_block.controller_ptr == controller.front_block.controller_ptr && controller.front_block.curr_ptr == controller.front_end_ptr) - { - auto front_block_controller_ptr{controller.front_block.controller_ptr + 1}; - controller.front_block.controller_ptr = front_block_controller_ptr; - auto front_begin_ptr = static_cast(*front_block_controller_ptr); - controller.front_block.curr_ptr = controller.front_block.begin_ptr = front_begin_ptr; - controller.front_end_ptr = front_begin_ptr + bytes; - } - - /** - * At this point, we have guaranteed controller capacity. - * Advance back_block.controller_ptr to the new block slot. - */ - ++controller.back_block.controller_ptr; - - /** - * Load the block pointer and initialize begin/curr/end pointers. - */ - auto begin_ptr = - static_cast(*controller.back_block.controller_ptr); - - controller.back_block.begin_ptr = begin_ptr; - controller.back_block.curr_ptr = begin_ptr; - controller.back_end_ptr = begin_ptr + bytes; - -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif -} - -template -inline constexpr void deque_grow_front_common_impl( - dequecontroltype &controller, - std::size_t align, - std::size_t bytes) noexcept -{ - /** - * If the deque is empty, allocate the initial controller array - * and a single data block. This sets up the initial front/back - * block pointers and the sentinel. - */ - if (controller.controller_block.controller_start_ptr == nullptr) - { - ::fast_io::containers::details:: - deque_allocate_on_empty_common_impl(controller, align, bytes); - return; - } - - using replacetype = typename dequecontroltype::replacetype; - constexpr bool isvoidplaceholder = std::same_as; - using begin_ptrtype = - std::conditional_t; - if (controller.front_block.controller_ptr == - controller.controller_block.controller_start_reserved_ptr) - { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif - if (controller.controller_block.controller_start_reserved_ptr == - controller.controller_block.controller_start_ptr) - { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif - ::fast_io::containers::details:: - deque_rebalance_or_grow_2x_after_blocks_impl(controller); - } - if (controller.front_block.controller_ptr == - controller.controller_block.controller_start_reserved_ptr) - { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif - begin_ptrtype new_block; - auto after_reserved_ptr = - controller.controller_block.controller_after_reserved_ptr; - std::size_t diff_to_after_ptr = - static_cast( - after_reserved_ptr - - controller.back_block.controller_ptr); - if (1 < diff_to_after_ptr) - { - /* Reuse the block memory. */ - new_block = static_cast(*(--after_reserved_ptr)); - - /* Consume one reserved block from the back. */ - *(controller.controller_block.controller_after_reserved_ptr = after_reserved_ptr) = nullptr; - } - else - { - new_block = - static_cast(allocator::allocate_aligned(align, bytes)); - } - - auto pos{--controller.controller_block.controller_start_reserved_ptr}; - std::construct_at(pos, new_block); - } - } - - --controller.front_block.controller_ptr; - - auto begin_ptr = - static_cast(*controller.front_block.controller_ptr); -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current(), - "\n\tcontroller_ptr:", ::fast_io::iomnp::pointervw(controller.front_block.controller_ptr), - "\n\tbegin_ptr:", ::fast_io::iomnp::pointervw(begin_ptr), - "\n\tstart_reserved_ptr:", ::fast_io::iomnp::pointervw(controller.controller_block.controller_start_reserved_ptr), - "\n\tstart_ptr:", ::fast_io::iomnp::pointervw(controller.controller_block.controller_start_ptr)); -#endif - controller.front_block.begin_ptr = begin_ptr; - controller.front_end_ptr = (controller.front_block.curr_ptr = (begin_ptr + bytes)); -} - -template -inline constexpr void deque_grow_front_common(dequecontroltype &controller) noexcept -{ - constexpr ::std::size_t blockbytes{sz * block_size}; - ::fast_io::containers::details::deque_grow_front_common_impl(controller, align, blockbytes); -} - -template -inline constexpr void deque_grow_back_common(dequecontroltype &controller) noexcept -{ - constexpr ::std::size_t blockbytes{sz * block_size}; - ::fast_io::containers::details::deque_grow_back_common_impl(controller, align, blockbytes); -} - template inline constexpr void deque_clear_common_impl(dequecontroltype &controller, ::std::size_t blockbytes) { @@ -1032,7 +838,7 @@ inline constexpr void deque_clone_trivial_impl(dequecontroltype &controller, deq begin_ptrtype lastblockbegin; if (front_controller_ptr == back_controller_ptr) { - lastblockbegin = controller.front_block.curr_ptr; + lastblockbegin = fromcontroller.front_block.curr_ptr; } else { @@ -1100,7 +906,7 @@ deque_copy_impl(Itercontent first, Itercontent last, { tocopy = dest_block_to_end; } - ::fast_io::freestanding::overlapped_copy_n(firstcurrptr, tocopy, destcurrptr); + ::fast_io::freestanding::copy_n(firstcurrptr, tocopy, destcurrptr); if (0 < cmp) { dest.curr_ptr = (dest.begin_ptr = (*++dest.controller_ptr)); @@ -1162,8 +968,139 @@ deque_copy_backward_impl(Itercontent first, Itercontent last, { tocopy = dest_block_to_begin; } - ::fast_io::freestanding::overlapped_copy_n(lastcurrptr - tocopy, tocopy, - destcurrptr - tocopy); + ::fast_io::freestanding::copy_backward(lastcurrptr - tocopy, lastcurrptr, + destcurrptr); + if (0 < cmp) + { + dest.curr_ptr = (dest.begin_ptr = (*--dest.controller_ptr)) + blocksize; + last.curr_ptr -= tocopy; + } + else + { + if (cmp == 0) + { + if (last.controller_ptr == first.controller_ptr) + { + dest.curr_ptr = dest.begin_ptr; + break; + } + dest.curr_ptr = (dest.begin_ptr = (*--dest.controller_ptr)) + blocksize; + } + else + { + dest.curr_ptr -= tocopy; + if (last.controller_ptr == first.controller_ptr) + { + break; + } + } + last.curr_ptr = (last.begin_ptr = (*--last.controller_ptr)) + blocksize; + } + } + return dest; +} + + +template +inline constexpr Itercontent +deque_relocate_impl(Itercontent first, Itercontent last, + Itercontent dest, ::std::size_t blocksize) +{ + if (first.curr_ptr == last.curr_ptr) + { + return dest; + } + for (;;) + { + decltype(first.begin_ptr) firstend; + if (first.controller_ptr == last.controller_ptr) + { + firstend = last.curr_ptr; + } + else + { + firstend = first.begin_ptr + blocksize; + } + auto firstcurrptr{first.curr_ptr}; + ::std::size_t const curr_block_to_end{ + static_cast<::std::size_t>(firstend - firstcurrptr)}; + auto destcurrptr{dest.curr_ptr}; + ::std::size_t const dest_block_to_end{ + static_cast<::std::size_t>(dest.begin_ptr + blocksize - destcurrptr)}; + auto cmp{curr_block_to_end <=> dest_block_to_end}; + ::std::size_t tocopy; + if (cmp < 0) + { + tocopy = curr_block_to_end; + } + else + { + tocopy = dest_block_to_end; + } + ::fast_io::freestanding::uninitialized_relocate_ignore_define(firstcurrptr, firstcurrptr + tocopy, destcurrptr); + if (0 < cmp) + { + dest.curr_ptr = (dest.begin_ptr = (*++dest.controller_ptr)); + first.curr_ptr += tocopy; + } + else + { + if (cmp < 0) + { + dest.curr_ptr += tocopy; + } + else if (cmp == 0) + { + dest.curr_ptr = (dest.begin_ptr = (*++dest.controller_ptr)); + } + if (first.controller_ptr == last.controller_ptr) + { + break; + } + first.curr_ptr = (first.begin_ptr = (*++first.controller_ptr)); + } + } + return dest; +} + +template +inline constexpr Itercontent +deque_relocate_backward_impl(Itercontent first, Itercontent last, + Itercontent dest, ::std::size_t blocksize) +{ + if (first.curr_ptr == last.curr_ptr) + { + return dest; + } + for (;;) + { + decltype(first.begin_ptr) lastbegin; + if (first.controller_ptr == last.controller_ptr) + { + lastbegin = first.curr_ptr; + } + else + { + lastbegin = last.begin_ptr; + } + auto lastcurrptr{last.curr_ptr}; + ::std::size_t const curr_block_to_begin{ + static_cast<::std::size_t>(lastcurrptr - lastbegin)}; + auto destcurrptr{dest.curr_ptr}; + ::std::size_t const dest_block_to_begin{ + static_cast<::std::size_t>(destcurrptr - dest.begin_ptr)}; + auto cmp{curr_block_to_begin <=> dest_block_to_begin}; + ::std::size_t tocopy; + if (cmp < 0) + { + tocopy = curr_block_to_begin; + } + else + { + tocopy = dest_block_to_begin; + } + ::fast_io::freestanding::uninitialized_relocate_backward_ignore_define(lastcurrptr - tocopy, lastcurrptr, + destcurrptr); if (0 < cmp) { dest.curr_ptr = (dest.begin_ptr = (*--dest.controller_ptr)) + blocksize; @@ -1230,8 +1167,6 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller return first; } -#if 1 - template inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype &controller, ::std::size_t extrablocks) noexcept { @@ -1289,9 +1224,6 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype } else { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif // balance blocks auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; @@ -1301,28 +1233,21 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype static_cast<::std::size_t>(reserved_blocks_count >> 1u)}; auto reserved_pivot{start_reserved_ptr + half_reserved_blocks_count}; auto const half_used_blocks_count{ - static_cast<::std::size_t>(new_used_blocks_count >> 1u)}; + static_cast<::std::size_t>(used_blocks_count >> 1u)}; // this place needs to deal with extra block auto used_blocks_pivot{controller.front_block.controller_ptr + half_used_blocks_count}; if (used_blocks_pivot != reserved_pivot) { ::std::ptrdiff_t diff{reserved_pivot - used_blocks_pivot}; -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current(), - "\tdiff=",diff); -#endif auto rotate_pivot{diff < 0 ? start_reserved_ptr : after_reserved_ptr}; rotate_pivot -= diff; ::std::rotate(start_reserved_ptr, rotate_pivot, after_reserved_ptr); controller.front_block.controller_ptr += diff; controller.back_block.controller_ptr += diff; } - - auto slots_pivot{controller.controller_block.controller_start_ptr + half_slots_count}; + auto const half_slotsextra_count{static_cast<::std::size_t>((total_slots_count + extrablocks) >> 1u)}; + auto slots_pivot{controller.controller_block.controller_start_ptr + half_slotsextra_count}; if (slots_pivot != reserved_pivot) { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif ::std::ptrdiff_t diff{slots_pivot - reserved_pivot}; ::fast_io::freestanding::overlapped_copy(start_reserved_ptr, after_reserved_ptr, start_reserved_ptr + diff); @@ -1335,33 +1260,32 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype } template -inline constexpr void deque_reserve_back_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept { if (controller.controller_block.controller_start_ptr == nullptr) { ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( controller, align, blockbytes, nb); - return; + return false; } - using replacetype = typename dequecontroltype::replacetype; using begin_ptrtype = replacetype *; - std::size_t diff_to_after_ptr = - static_cast( + ::std::size_t diff_to_after_ptr = + static_cast<::std::size_t>( controller.controller_block.controller_after_reserved_ptr - controller.back_block.controller_ptr); if (diff_to_after_ptr <= nb) { - std::size_t distance_back_to_reserve{ - static_cast(controller.controller_block.controller_after_reserved_ptr - - controller.back_block.controller_ptr)}; - if (distance_back_to_reserve < nb) + ::std::size_t distance_back_to_after{ + static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - + controller.back_block.controller_ptr)}; + if (distance_back_to_after <= nb) { ::fast_io::containers::details::deque_rebalance_or_grow_insertation_impl(controller, nb); } - std::size_t diff_to_after_ptr2 = - static_cast( + ::std::size_t diff_to_after_ptr2 = + static_cast<::std::size_t>( controller.controller_block.controller_after_reserved_ptr - controller.back_block.controller_ptr); if (diff_to_after_ptr2 <= nb) @@ -1380,7 +1304,6 @@ inline constexpr void deque_reserve_back_blocks_impl(dequecontroltype &controlle { to_allocate_blocks -= front_borrowed_blocks_count; } - auto controller_start_reserved_ptr{ controller.controller_block.controller_start_reserved_ptr}; @@ -1391,7 +1314,6 @@ inline constexpr void deque_reserve_back_blocks_impl(dequecontroltype &controlle pos); controller.controller_block.controller_start_reserved_ptr = controller_start_reserved_ptr + front_borrowed_blocks_count; - for (auto e{pos + to_allocate_blocks}; pos != e; ++pos) { ::std::construct_at(pos, static_cast(allocator::allocate_aligned(align, blockbytes))); @@ -1410,22 +1332,268 @@ inline constexpr void deque_reserve_back_blocks_impl(dequecontroltype &controlle controller.front_end_ptr = front_begin_ptr + blockbytes; } - controller.back_block.controller_ptr += nb; - auto begin_ptr = - static_cast(*controller.back_block.controller_ptr); + return true; +} +template +inline constexpr void deque_grow_back_common_impl( + dequecontroltype &controller, + std::size_t align, + std::size_t bytes) noexcept +{ + if (!::fast_io::containers::details::deque_reserve_back_blocks_impl(controller, 1zu, align, bytes)) + { + return; + } + ++controller.back_block.controller_ptr; + auto begin_ptr{*controller.back_block.controller_ptr}; controller.back_block.begin_ptr = begin_ptr; controller.back_block.curr_ptr = begin_ptr; - controller.back_end_ptr = begin_ptr + blockbytes; + controller.back_end_ptr = begin_ptr + bytes; +} + +template +inline constexpr void deque_grow_back_common(dequecontroltype &controller) noexcept +{ + constexpr ::std::size_t blockbytes{sz * block_size}; + ::fast_io::containers::details::deque_grow_back_common_impl(controller, align, blockbytes); } -#if 0 template inline constexpr void deque_reserve_back_spaces(dequecontroltype &controller, ::std::size_t n) { + if (!n) + { + return; + } + auto back_curr_ptr{controller.back_block.curr_ptr}; + ::std::size_t blocksn{static_cast<::std::size_t>(controller.back_end_ptr - back_curr_ptr)}; + if (n <= blocksn) + { + return; + } + ::std::size_t nmblocksn{n - blocksn}; + ::std::size_t back_more_blocks{nmblocksn / block_size}; + ::std::size_t const back_more_blocks_mod{nmblocksn % block_size}; + ::std::size_t toallocate{back_more_blocks}; + if (back_more_blocks_mod) + { + ++toallocate; + } + if consteval + { + ::fast_io::containers::details::deque_reserve_back_blocks_impl(controller, + toallocate, align, block_size); + } + else + { + constexpr ::std::size_t block_bytes{block_size * sz}; + ::fast_io::containers::details::deque_reserve_back_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( + __builtin_addressof(controller)), + toallocate, align, block_bytes); + } +} + +template +inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +{ + if (controller.controller_block.controller_start_ptr == nullptr) + { + ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( + controller, align, blockbytes, nb); + return false; + } + using replacetype = typename dequecontroltype::replacetype; + using begin_ptrtype = replacetype *; + + ::std::size_t diff_to_start_ptr = + static_cast<::std::size_t>( + controller.front_block.controller_ptr - + controller.controller_block.controller_start_reserved_ptr); + if (diff_to_start_ptr < nb) + { + ::std::size_t distance_front_to_start{ + static_cast<::std::size_t>(controller.front_block.controller_ptr - + controller.controller_block.controller_start_ptr)}; + if (distance_front_to_start < nb) + { + ::fast_io::containers::details::deque_rebalance_or_grow_insertation_impl(controller, nb); + } + ::std::size_t diff_to_start_ptr2 = + static_cast<::std::size_t>( + controller.front_block.controller_ptr - + controller.controller_block.controller_start_reserved_ptr); + if (diff_to_start_ptr2 < nb) + { + ::std::size_t back_reserved_blocks{ + static_cast<::std::size_t>(controller.controller_block.controller_after_reserved_ptr - + controller.back_block.controller_ptr - 1)}; + + ::std::size_t back_borrowed_blocks_count{back_reserved_blocks}; + ::std::size_t to_allocate_blocks{nb}; + if (nb < back_reserved_blocks) + { + back_borrowed_blocks_count = nb; + to_allocate_blocks = 0u; + } + else + { + to_allocate_blocks -= back_borrowed_blocks_count; + } + + auto controller_after_reserved_ptr{ + controller.controller_block.controller_after_reserved_ptr}; + + auto controller_start_reserved_ptr{ + controller.controller_block.controller_start_reserved_ptr}; + + auto new_controller_start_reserved_ptr{ + controller_start_reserved_ptr - back_borrowed_blocks_count}; + auto new_controller_after_reserved_ptr{ + controller_after_reserved_ptr - back_borrowed_blocks_count}; + ::fast_io::freestanding::non_overlapped_copy_n(new_controller_after_reserved_ptr, + back_borrowed_blocks_count, + new_controller_start_reserved_ptr); + *(controller.controller_block.controller_after_reserved_ptr = new_controller_after_reserved_ptr) = nullptr; + // after this line Todo + + auto ed{new_controller_start_reserved_ptr}; + new_controller_start_reserved_ptr -= to_allocate_blocks; + for (auto i{new_controller_start_reserved_ptr}; i != ed; ++i) + { + ::std::construct_at(i, static_cast(allocator::allocate_aligned(align, blockbytes))); + } + controller.controller_block.controller_start_reserved_ptr = new_controller_start_reserved_ptr; + } + } + return true; +} + +template +inline constexpr void deque_reserve_front_spaces(dequecontroltype &controller, ::std::size_t n) +{ + if (!n) + { + return; + } + auto front_curr_ptr{controller.front_block.curr_ptr}; + ::std::size_t blocksn{static_cast<::std::size_t>(front_curr_ptr - controller.front_block.begin_ptr)}; + if (n <= blocksn) + { + return; + } + ::std::size_t nmblocksn{n - blocksn}; + ::std::size_t front_more_blocks{nmblocksn / block_size}; + ::std::size_t const front_more_blocks_mod{nmblocksn % block_size}; + ::std::size_t toallocate{front_more_blocks}; + if (front_more_blocks_mod) + { + ++toallocate; + } + if consteval + { + ::fast_io::containers::details::deque_reserve_front_blocks_impl(controller, + toallocate, align, block_size); + } + else + { + constexpr ::std::size_t block_bytes{block_size * sz}; + ::fast_io::containers::details::deque_reserve_front_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( + __builtin_addressof(controller)), + toallocate, align, block_bytes); + } +} + +template +inline constexpr void deque_grow_front_common_impl( + dequecontroltype &controller, + std::size_t align, + std::size_t bytes) noexcept +{ + if (!::fast_io::containers::details::deque_reserve_front_blocks_impl(controller, 1zu, align, bytes)) + { + return; + } + auto begin_ptr{*(--controller.front_block.controller_ptr)}; + controller.front_block.begin_ptr = begin_ptr; + auto end_ptr{begin_ptr + bytes}; + controller.front_block.curr_ptr = end_ptr; + controller.front_end_ptr = end_ptr; +} + +template +inline constexpr void deque_grow_front_common(dequecontroltype &controller) noexcept +{ + constexpr ::std::size_t blockbytes{sz * block_size}; + + ::fast_io::containers::details::deque_grow_front_common_impl(controller, align, blockbytes); +} + +template +struct is_fast_io_deque_iterator_impl : ::std::false_type +{}; + +template +struct is_fast_io_deque_iterator_impl< + ::fast_io::containers::details::deque_iterator> : ::std::true_type +{}; + +template +struct is_fast_io_deque_iterator_impl< + ::fast_io::containers::details::deque_iterator> : ::std::true_type +{}; + +template +concept is_fast_io_deque_iterator_v = + ::fast_io::containers::details::is_fast_io_deque_iterator_impl>::value; + +template + requires(::fast_io::containers::details::is_fast_io_deque_iterator_v) +inline constexpr Iter uninitialized_relocate_define( + ::fast_io::operations::defines::memory_algorithm_define_type, + Iter first, Iter last, Iter dest) +{ + using valtype = ::std::iter_value_t; + if constexpr (::fast_io::freestanding::is_trivially_copyable_or_relocatable_v) + { + if !consteval + { + return ::std::bit_cast( + ::fast_io::containers::details::deque_copy_impl( + ::std::bit_cast<::fast_io::containers::details::deque_control_block_common>(first.itercontent), + ::std::bit_cast<::fast_io::containers::details::deque_control_block_common>(last.itercontent), + ::std::bit_cast<::fast_io::containers::details::deque_control_block_common>(dest.itercontent), + ::fast_io::containers::details::deque_block_bytes)); + } + } + return ::std::bit_cast( + ::fast_io::containers::details::deque_relocate_impl(first.itercontent, last.itercontent, dest.itercontent, + ::fast_io::containers::details::deque_block_size)); +} + +template + requires(::fast_io::containers::details::is_fast_io_deque_iterator_v) +inline constexpr Iter uninitialized_relocate_backward_define( + ::fast_io::operations::defines::memory_algorithm_define_type, + Iter first, Iter last, Iter dest) +{ + using valtype = ::std::iter_value_t; + if constexpr (::fast_io::freestanding::is_trivially_copyable_or_relocatable_v) + { + if !consteval + { + return ::std::bit_cast( + ::fast_io::containers::details::deque_copy_backward_impl( + ::std::bit_cast<::fast_io::containers::details::deque_control_block_common>(first.itercontent), + ::std::bit_cast<::fast_io::containers::details::deque_control_block_common>(last.itercontent), + ::std::bit_cast<::fast_io::containers::details::deque_control_block_common>(dest.itercontent), + ::fast_io::containers::details::deque_block_bytes)); + } + } + return ::std::bit_cast( + ::fast_io::containers::details::deque_relocate_backward_impl(first.itercontent, last.itercontent, dest.itercontent, + ::fast_io::containers::details::deque_block_size)); } -#endif -#endif } // namespace details @@ -1824,6 +1992,9 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto front_controller_ptr{controller.front_block.controller_ptr}; if (front_controller_ptr == controller.back_block.controller_ptr) [[unlikely]] { + auto begin_ptr{controller.front_block.begin_ptr}; + constexpr ::std::size_t half_blocks_size{block_size >> 1u}; + controller.back_block.curr_ptr = (controller.front_block.curr_ptr = begin_ptr + half_blocks_size); return; } controller.front_end_ptr = (controller.front_block.curr_ptr = controller.front_block.begin_ptr = *(controller.front_block.controller_ptr = front_controller_ptr + 1)) + block_size; @@ -1831,7 +2002,15 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr void back_backspace() noexcept { - controller.back_block.curr_ptr = (controller.back_end_ptr = ((controller.back_block.begin_ptr = *--controller.back_block.controller_ptr) + block_size)); + auto back_controller_ptr{controller.back_block.controller_ptr}; + if (back_controller_ptr == controller.front_block.controller_ptr) [[unlikely]] + { + auto begin_ptr{controller.back_block.begin_ptr}; + constexpr ::std::size_t half_blocks_size{block_size >> 1u}; + controller.front_block.curr_ptr = (controller.back_block.curr_ptr = begin_ptr + half_blocks_size); + return; + } + controller.back_block.curr_ptr = (controller.back_end_ptr = ((controller.back_block.begin_ptr = *(controller.back_block.controller_ptr = back_controller_ptr - 1)) + block_size)); } public: @@ -1880,7 +2059,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::fast_io::fast_terminate(); } - pop_back_unchecked(); } @@ -2044,7 +2222,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::fast_io::fast_terminate(); } - return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); + return ::fast_io::containers::details::deque_index_container_unsigned(controller.front_block, index); } inline constexpr const_reference operator[](size_type index) const noexcept @@ -2053,17 +2231,17 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::fast_io::fast_terminate(); } - return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); + return ::fast_io::containers::details::deque_index_container_unsigned(controller.front_block, index); } inline constexpr reference index_unchecked(size_type index) noexcept { - return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); + return ::fast_io::containers::details::deque_index_container_unsigned(controller.front_block, index); } inline constexpr const_reference index_unchecked(size_type index) const noexcept { - return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); + return ::fast_io::containers::details::deque_index_container_unsigned(controller.front_block, index); } static inline constexpr size_type max_size() noexcept @@ -2189,25 +2367,54 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE requires ::std::constructible_from> inline constexpr insert_range_result insert_range_impl(size_type pos, R &&rg, size_type old_size) noexcept(::std::is_nothrow_constructible_v>) { -#if 0 - if constexpr(::std::ranges::sized_range) + if constexpr (::std::ranges::sized_range) { size_type const rgsize{::std::ranges::size(rg)}; + if (!rgsize) + { + return {pos, this->begin() + pos}; + } size_type const half_size{old_size >> 1u}; if (pos < half_size) { - + ::fast_io::containers::details::deque_reserve_front_spaces(this->controller, rgsize); + auto thisbg{this->begin()}; + auto posit{thisbg + pos}; + auto thisbgrgsize{thisbg - rgsize}; + auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg, + posit, thisbgrgsize)}; + ::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, thisbgrgsizenew); + + this->controller.front_block = thisbgrgsize.itercontent; + this->controller.front_end_ptr = thisbgrgsize.itercontent.begin_ptr + block_size; + return {pos, thisbgrgsizenew}; } else { + ::fast_io::containers::details::deque_reserve_back_spaces(this->controller, rgsize); + auto posit{this->begin() + pos}; + auto thisend{this->end()}; + auto thisendrgsize{thisend + rgsize}; + ::fast_io::freestanding::uninitialized_relocate_backward(posit, + thisend, thisendrgsize); + ::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, posit); + if (thisendrgsize.itercontent.begin_ptr == thisendrgsize.itercontent.curr_ptr) + { + thisendrgsize.itercontent.curr_ptr = + (thisendrgsize.itercontent.begin_ptr = *--thisendrgsize.itercontent.controller_ptr) + block_size; + } + this->controller.back_block = thisendrgsize.itercontent; + this->controller.back_end_ptr = thisendrgsize.itercontent.begin_ptr + block_size; + return {pos, posit}; } } else -#endif { - size_type const quarterold_size{old_size >> 2u}; size_type retpos; iterator retit, rotfirst, rotmid, rotlast; + size_type const quarterold_size{old_size >> 2u}; if (pos < quarterold_size) { this->prepend_range(rg); @@ -2240,7 +2447,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr iterator insert_range(const_iterator pos, R &&rg) noexcept(::std::is_nothrow_constructible_v>) { return this->insert_range_impl( - ::fast_io::containers::details::deque_iter_difference_unsigned_common(pos, this->cbegin()), rg, this->size()) + ::fast_io::containers::details::deque_iter_difference_unsigned_common(pos.itercontent, this->controller.front_block), rg, this->size()) .it; } diff --git a/include/fast_io_dsal/impl/freestanding.h b/include/fast_io_dsal/impl/freestanding.h index 673f385b..cbd9bd84 100644 --- a/include/fast_io_dsal/impl/freestanding.h +++ b/include/fast_io_dsal/impl/freestanding.h @@ -2,24 +2,34 @@ namespace fast_io::operations::defines { -template -concept has_uninitialized_relocate_define = requires(T *ptr) { - { uninitialized_relocate_define(ptr, ptr, ptr) } -> ::std::same_as; + +template +struct memory_algorithm_define_type +{ + explicit constexpr memory_algorithm_define_type() noexcept = default; +}; + +template +inline constexpr memory_algorithm_define_type memory_algorithm_define{}; + +template +concept has_uninitialized_relocate_define = ::std::sentinel_for && requires(Iter1 first, Snt last, Iter2 dest) { + { uninitialized_relocate_define(::fast_io::operations::defines::memory_algorithm_define, first, last, dest) } -> ::std::same_as; }; -template -concept has_uninitialized_relocate_backward_define = requires(T *ptr) { - { uninitialized_relocate_backward_define(ptr, ptr, ptr) } -> ::std::same_as; +template +concept has_uninitialized_relocate_backward_define = ::std::sentinel_for && requires(Iter1 first, Snt last, Iter2 dest) { + { uninitialized_relocate_backward_define(::fast_io::operations::defines::memory_algorithm_define, first, last, dest) } -> ::std::same_as; }; -template -concept has_uninitialized_move_define = requires(T *ptr) { - { uninitialized_move_define(ptr, ptr, ptr) } -> ::std::same_as; +template +concept has_uninitialized_move_define = ::std::sentinel_for && requires(Iter1 first, Snt last, Iter2 dest) { + { uninitialized_move_define(::fast_io::operations::defines::memory_algorithm_define, first, last, dest) } -> ::std::same_as; }; -template -concept has_uninitialized_move_backward_define = requires(T *ptr) { - { uninitialized_move_backward_define(ptr, ptr, ptr) } -> ::std::same_as; +template +concept has_uninitialized_move_backward_define = ::std::sentinel_for && requires(Iter1 first, Snt last, Iter2 dest) { + { uninitialized_move_backward_define(::fast_io::operations::defines::memory_algorithm_define, first, last, dest) } -> ::std::same_as; }; } // namespace fast_io::operations::defines @@ -30,23 +40,24 @@ namespace fast_io::freestanding /* uninitialized_relocate requires two range are not overlapped. */ -template <::std::input_or_output_iterator Iter1, ::std::input_or_output_iterator Iter2> -inline constexpr Iter2 uninitialized_relocate(Iter1 first, Iter1 last, Iter2 dest) noexcept + +template <::std::input_or_output_iterator Iter1, ::std::sentinel_for Sent, ::std::input_or_output_iterator Iter2> +inline constexpr Iter2 uninitialized_relocate_ignore_define(Iter1 first, Sent last, Iter2 dest) noexcept { if constexpr (::std::contiguous_iterator && !::std::is_pointer_v && ::std::contiguous_iterator && !::std::is_pointer_v) { - return uninitialized_relocate(::std::to_address(first), ::std::to_address(last), - ::std::to_address(dest)) - + return uninitialized_relocate_ignore_define(::std::to_address(first), ::std::to_address(last), + ::std::to_address(dest)) - ::std::to_address(dest) + dest; } else if constexpr (::std::contiguous_iterator && !::std::is_pointer_v) { - return uninitialized_relocate(::std::to_address(first), ::std::to_address(last), - dest); + return uninitialized_relocate_ignore_define(::std::to_address(first), ::std::to_address(last), + dest); } else if constexpr (::std::contiguous_iterator && !::std::is_pointer_v) { - return uninitialized_relocate(first, last, ::std::to_address(dest)) - + return uninitialized_relocate_ignore_define(first, last, ::std::to_address(dest)) - ::std::to_address(dest) + dest; } else @@ -70,10 +81,6 @@ inline constexpr Iter2 uninitialized_relocate(Iter1 first, Iter1 last, Iter2 des return reinterpret_cast(::fast_io::freestanding::bytes_copy(reinterpret_cast<::std::byte const *>(first), reinterpret_cast<::std::byte const *>(last), reinterpret_cast<::std::byte *>(dest))); } } - else if constexpr (::std::same_as && ::fast_io::operations::defines::has_uninitialized_relocate_define) - { - return uninitialized_relocate_define(first, last, dest); - } // we do not allow move constructor to throw EH. while (first != last) { @@ -97,8 +104,41 @@ inline constexpr Iter2 uninitialized_relocate(Iter1 first, Iter1 last, Iter2 des } } -template <::std::bidirectional_iterator Iter1, ::std::bidirectional_iterator Iter2> -inline constexpr Iter2 uninitialized_relocate_backward(Iter1 first, Iter1 last, Iter2 dest) noexcept +template <::std::input_or_output_iterator Iter1, ::std::sentinel_for Snt, ::std::input_or_output_iterator Iter2> +inline constexpr Iter2 uninitialized_relocate(Iter1 first, Snt last, Iter2 dest) noexcept +{ + if constexpr ( + ::std::same_as && ::std::contiguous_iterator && !::std::is_pointer_v && ::std::contiguous_iterator && !::std::is_pointer_v) + { + return uninitialized_relocate(::std::to_address(first), ::std::to_address(last), + ::std::to_address(dest)) - + ::std::to_address(dest) + dest; + } + else if constexpr (::std::same_as && ::std::contiguous_iterator && !::std::is_pointer_v) + { + return uninitialized_relocate(::std::to_address(first), ::std::to_address(last), + dest); + } + else if constexpr (::std::same_as && ::std::contiguous_iterator && !::std::is_pointer_v) + { + return uninitialized_relocate(first, last, ::std::to_address(dest)) - + ::std::to_address(dest) + dest; + } + else + { + if constexpr (::fast_io::operations::defines::has_uninitialized_relocate_define) + { + return uninitialized_relocate_define(::fast_io::operations::defines::memory_algorithm_define, first, last, dest); + } + else + { + return ::fast_io::freestanding::uninitialized_relocate_ignore_define(first, last, dest); + } + } +} + +template <::std::bidirectional_iterator Iter1, ::std::sentinel_for Snt, ::std::bidirectional_iterator Iter2> +inline constexpr Iter2 uninitialized_relocate_backward_ignore_define(Iter1 first, Snt last, Iter2 dest) noexcept { // Semantics: // Relocate the range [first, last) into the uninitialized memory ending at `dest`. @@ -109,22 +149,22 @@ inline constexpr Iter2 uninitialized_relocate_backward(Iter1 first, Iter1 last, if constexpr (::std::contiguous_iterator && !::std::is_pointer_v && ::std::contiguous_iterator && !::std::is_pointer_v) { - return uninitialized_relocate_backward(::std::to_address(first), - ::std::to_address(last), - ::std::to_address(dest)) - + return uninitialized_relocate_backward_ignore_define(::std::to_address(first), + ::std::to_address(last), + ::std::to_address(dest)) - ::std::to_address(dest) + dest; } else if constexpr (::std::contiguous_iterator && !::std::is_pointer_v) { - return uninitialized_relocate_backward(::std::to_address(first), - ::std::to_address(last), - dest); + return uninitialized_relocate_backward_ignore_define(::std::to_address(first), + ::std::to_address(last), + dest); } else if constexpr (::std::contiguous_iterator && !::std::is_pointer_v) { - return uninitialized_relocate_backward(first, - last, - ::std::to_address(dest)) - + return uninitialized_relocate_backward_ignore_define(first, + last, + ::std::to_address(dest)) - ::std::to_address(dest) + dest; } else @@ -162,13 +202,6 @@ inline constexpr Iter2 uninitialized_relocate_backward(Iter1 first, Iter1 last, return reinterpret_cast(destfirst); } } - // Custom relocate_backward hook for user-defined types - else if constexpr (::std::same_as && - ::fast_io::operations::defines::has_uninitialized_relocate_define) - { - return uninitialized_relocate_define_backward(first, last, dest); - } - // Generic slow path: // Move-construct elements in reverse order into uninitialized memory, // then destroy the original elements. @@ -196,6 +229,49 @@ inline constexpr Iter2 uninitialized_relocate_backward(Iter1 first, Iter1 last, } } +template <::std::bidirectional_iterator Iter1, ::std::sentinel_for Snt, ::std::bidirectional_iterator Iter2> +inline constexpr Iter2 uninitialized_relocate_backward(Iter1 first, Snt last, Iter2 dest) noexcept +{ + // Semantics: + // Relocate the range [first, last) into the uninitialized memory ending at `dest`. + // `dest` is treated as the end iterator (one past the last element) of the destination range. + // The function returns the begin iterator of the destination range: + // dest - (last - first) + + if constexpr (::std::contiguous_iterator && !::std::is_pointer_v && + ::std::contiguous_iterator && !::std::is_pointer_v) + { + return uninitialized_relocate_backward(::std::to_address(first), + ::std::to_address(last), + ::std::to_address(dest)) - + ::std::to_address(dest) + dest; + } + else if constexpr (::std::contiguous_iterator && !::std::is_pointer_v) + { + return uninitialized_relocate_backward(::std::to_address(first), + ::std::to_address(last), + dest); + } + else if constexpr (::std::contiguous_iterator && !::std::is_pointer_v) + { + return uninitialized_relocate_backward(first, + last, + ::std::to_address(dest)) - + ::std::to_address(dest) + dest; + } + else + { + if constexpr (::fast_io::operations::defines::has_uninitialized_relocate_backward_define) + { + return uninitialized_relocate_backward_define(::fast_io::operations::defines::memory_algorithm_define, first, last, dest); + } + else + { + return ::fast_io::freestanding::uninitialized_relocate_backward_ignore_define(first, last, dest); + } + } +} + template <::std::input_or_output_iterator Iter1, ::std::input_or_output_iterator Iter2> inline constexpr Iter2 uninitialized_move(Iter1 first, Iter1 last, Iter2 dest) noexcept { @@ -236,10 +312,12 @@ inline constexpr Iter2 uninitialized_move(Iter1 first, Iter1 last, Iter2 dest) n return reinterpret_cast(::fast_io::freestanding::bytes_copy(reinterpret_cast<::std::byte const *>(first), reinterpret_cast<::std::byte const *>(last), reinterpret_cast<::std::byte *>(dest))); } } - else if constexpr (::std::same_as && ::fast_io::operations::defines::has_uninitialized_move_backward_define) +#if 0 + else if constexpr (::fast_io::operations::defines::has_uninitialized_move_define) { - return uninitialized_move_define(first, last, dest); + return uninitialized_move_define(::fast_io::operations::defines::memory_algorithm_define, first, last, dest); } +#endif // we do not allow move constructor to throw EH. while (first != last) { @@ -294,10 +372,12 @@ inline constexpr Iter2 uninitialized_move_backward(Iter1 first, Iter1 last, Iter return d_start; } } - else if constexpr (::std::same_as && ::fast_io::operations::defines::has_uninitialized_move_backward_define) +#if 0 + else if constexpr (::fast_io::operations::defines::has_uninitialized_move_backward_define) { - return uninitialized_move_backward_define(first, last, d_last); + return uninitialized_move_backward_define(::fast_io::operations::defines::memory_algorithm_define, first, last, d_last); } +#endif while (first != last) { ::std::construct_at(--d_last, std::move(*(--last))); diff --git a/share/fast_io/fast_io.cppm b/share/fast_io/fast_io.cppm index 594f9aa4..2f6dacb6 100644 --- a/share/fast_io/fast_io.cppm +++ b/share/fast_io/fast_io.cppm @@ -28,11 +28,11 @@ export module fast_io; #ifndef FAST_IO_FREESTANDING #include "fast_io_inc/hosted.inc" -#include "fast_io_inc/host/posix.inc" +#include "fast_io_inc/hosted/posix.inc" #if defined(_WIN32) || defined(__CYGWIN__) -#include "fast_io_inc/host/nt.inc" -#include "fast_io_inc/host/win32.inc" +#include "fast_io_inc/hosted/nt.inc" +#include "fast_io_inc/hosted/win32.inc" #endif #include "fast_io_inc/legacy/c.inc" diff --git a/share/fast_io/fast_io_inc/hosted.inc b/share/fast_io/fast_io_inc/hosted.inc index 2201e2d5..a40e2241 100644 --- a/share/fast_io/fast_io_inc/hosted.inc +++ b/share/fast_io/fast_io_inc/hosted.inc @@ -128,18 +128,6 @@ using ::fast_io::posix_clock_getres; using ::fast_io::native_mutex; -using ::fast_io::native_socklen_t; - -namespace this_thread -{ -#if ((defined(_WIN32) && !defined(__WINE__)) && !defined(__CYGWIN__)) || (defined(__MSDOS__) || defined(__DJGPP__)) || defined(__wasi__) || (!defined(__SINGLE_THREAD__) && !defined(__NEWLIB__) && !defined(__MSDOS__) && __has_include()) -using ::fast_io::this_thread::get_id; -using ::fast_io::this_thread::sleep_for; -using ::fast_io::this_thread::sleep_until; -using ::fast_io::this_thread::yield; -#endif -} // namespace this_thread - using ::fast_io::native_readlinkat; using ::fast_io::native_symlinkat; using ::fast_io::native_unlinkat; @@ -150,10 +138,13 @@ using ::fast_io::native_at_flags; using ::fast_io::native_utimensat; using ::fast_io::native_linkat; +#ifndef __wasm__ +using ::fast_io::native_socklen_t; using ::fast_io::posix_accept; using ::fast_io::posix_connect; using ::fast_io::posix_bind; using ::fast_io::posix_listen; +#endif using ::fast_io::begin; using ::fast_io::end; @@ -170,15 +161,17 @@ using ::fast_io::posix_file_status; using ::fast_io::truncate; using ::fast_io::native_white_hole; -using ::fast_io::native_socket_file; -using ::fast_io::native_socket_io_observer; using ::fast_io::ipv4; using ::fast_io::ipv6; +#ifndef __wasm__ +using ::fast_io::native_socket_file; +using ::fast_io::native_socket_io_observer; using ::fast_io::native_dns_file; using ::fast_io::to_ip; using ::fast_io::to_ip_address; +#endif using ::fast_io::io_kernel; diff --git a/share/fast_io/fast_io_inc/host/nt.inc b/share/fast_io/fast_io_inc/hosted/nt.inc similarity index 100% rename from share/fast_io/fast_io_inc/host/nt.inc rename to share/fast_io/fast_io_inc/hosted/nt.inc diff --git a/share/fast_io/fast_io_inc/host/posix.inc b/share/fast_io/fast_io_inc/hosted/posix.inc similarity index 95% rename from share/fast_io/fast_io_inc/host/posix.inc rename to share/fast_io/fast_io_inc/hosted/posix.inc index 0ab9324a..f7afad8f 100644 --- a/share/fast_io/fast_io_inc/host/posix.inc +++ b/share/fast_io/fast_io_inc/hosted/posix.inc @@ -6,7 +6,7 @@ export namespace fast_io using ::fast_io::posix_stderr_number; using ::fast_io::posix_domain_value; -#if ((!defined(_WIN32) || defined(__WINE__)) || defined(__CYGWIN__)) +#if ((!defined(_WIN32) || defined(__WINE__)) || defined(__CYGWIN__)) && !defined(__wasm__) namespace posix { using ::fast_io::posix::libc_ioctl; @@ -18,7 +18,6 @@ export namespace fast_io using ::fast_io::details::sys_mprotect; using ::fast_io::details::sys_munmap; using ::fast_io::details::sys_munmap_nothrow; - } using ::fast_io::posix_socklen_t; diff --git a/share/fast_io/fast_io_inc/host/win32.inc b/share/fast_io/fast_io_inc/hosted/win32.inc similarity index 99% rename from share/fast_io/fast_io_inc/host/win32.inc rename to share/fast_io/fast_io_inc/hosted/win32.inc index 1f08c09d..4972cd0e 100644 --- a/share/fast_io/fast_io_inc/host/win32.inc +++ b/share/fast_io/fast_io_inc/hosted/win32.inc @@ -61,4 +61,4 @@ export namespace fast_io using ::fast_io::data_sync_flags; using ::fast_io::data_sync; u using ::fast_io::flush; -} \ No newline at end of file +} diff --git a/tests/0026.container/0003.deque/iterator.cc b/tests/0026.container/0003.deque/iterator.cc new file mode 100644 index 00000000..66832a5a --- /dev/null +++ b/tests/0026.container/0003.deque/iterator.cc @@ -0,0 +1,23 @@ +#include +#include +#include + +int main() +{ + ::fast_io::deque<::std::size_t> dq{30zu, 40zu, 20zu, 10zu}; + auto dq2(dq); + ::std::sort(dq.begin(), dq.end()); + ::std::sort(dq2.rbegin(), dq2.rend()); + ::fast_io::out_buf_type obf(::fast_io::out()); + using namespace ::fast_io::iomnp; + print(obf, "dq:\n"); + for (auto const &e : dq) + { + println(obf, e); + } + print(obf, "\ndq2:\n"); + for (auto const &e : dq2) + { + println(obf, e); + } +}