From 3c713e07b9c4adb12bce0a7f0a87e4042b640c6d Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 6 Apr 2025 18:11:27 -0400 Subject: [PATCH 01/16] move print_freestanding to impl.h --- include/fast_io_core_impl/operations/impl.h | 2 +- .../operations/printimpl/impl.h | 3 + .../operations/printimpl/print_freestanding.h | 1396 +++++++++++++++++ 3 files changed, 1400 insertions(+), 1 deletion(-) create mode 100644 include/fast_io_core_impl/operations/printimpl/impl.h create mode 100644 include/fast_io_core_impl/operations/printimpl/print_freestanding.h diff --git a/include/fast_io_core_impl/operations/impl.h b/include/fast_io_core_impl/operations/impl.h index dddbe9740..6938b69a7 100644 --- a/include/fast_io_core_impl/operations/impl.h +++ b/include/fast_io_core_impl/operations/impl.h @@ -9,7 +9,7 @@ #include "writeimpl/impl.h" #include "readimpl/impl.h" #include "transcodeimpl/impl.h" -#include "print_freestanding.h" +#include "printimpl/impl.h" #include "scan_freestanding.h" #include "transmitimpl/impl.h" #include "strlike_reference_wrapper.h" diff --git a/include/fast_io_core_impl/operations/printimpl/impl.h b/include/fast_io_core_impl/operations/printimpl/impl.h new file mode 100644 index 000000000..4a16a6683 --- /dev/null +++ b/include/fast_io_core_impl/operations/printimpl/impl.h @@ -0,0 +1,3 @@ +#pragma once + +#include "print_freestanding.h" \ No newline at end of file diff --git a/include/fast_io_core_impl/operations/printimpl/print_freestanding.h b/include/fast_io_core_impl/operations/printimpl/print_freestanding.h new file mode 100644 index 000000000..92633ef6e --- /dev/null +++ b/include/fast_io_core_impl/operations/printimpl/print_freestanding.h @@ -0,0 +1,1396 @@ +#pragma once + +namespace fast_io +{ + +namespace details::decay +{ + +template <::std::integral char_type, typename T = char_type> +inline constexpr basic_io_scatter_t line_scatter_common{__builtin_addressof(char_literal_v), + ::std::same_as ? sizeof(char_type) : 1}; + +struct contiguous_scatter_result +{ + ::std::size_t position{}; + ::std::size_t neededscatters{}; + ::std::size_t neededspace{}; + bool lastisreserve{}; + bool hasscatters{}; + bool hasreserve{}; + bool hasdynamicreserve{}; +}; + +template <::std::integral char_type, typename Arg, typename... Args> +inline constexpr contiguous_scatter_result find_continuous_scatters_n() +{ + contiguous_scatter_result ret{}; + if constexpr (::fast_io::scatter_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + ++ret.position; + ret.hasscatters = true; + ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, + static_cast<::std::size_t>(1)); + } + else if constexpr (::fast_io::reserve_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + else + { + ret.lastisreserve = true; + } + constexpr ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; + static_assert(sz != 0); + ++ret.position; + ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, + static_cast<::std::size_t>(1)); + ret.neededspace = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededspace, sz); + ret.hasreserve = true; + } + else if constexpr (::fast_io::dynamic_reserve_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + else + { + ret.lastisreserve = true; + } + ++ret.position; + ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, + static_cast<::std::size_t>(1)); + ret.hasdynamicreserve = true; + } + else if constexpr (::fast_io::reserve_scatters_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + constexpr auto scatszres{print_reserve_scatters_size(::fast_io::io_reserve_type)}; + static_assert(scatszres.scatters_size != 0); + ret.hasscatters = true; + ret.hasreserve = true; + ++ret.position; + ret.neededspace = + ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededspace, scatszres.reserve_size); + ret.neededscatters = + ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, scatszres.scatters_size); + } + return ret; +} + +struct scatter_rsv_result +{ + ::std::size_t position{}; + ::std::size_t neededspace{}; +}; + +template +inline constexpr scatter_rsv_result find_continuous_scatters_reserve_n() +{ + if constexpr (::fast_io::reserve_printable && !findscatter) + { + constexpr ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; + if constexpr (sizeof...(Args) == 0) + { + return {1, sz}; + } + else + { + auto res{find_continuous_scatters_reserve_n()}; + return {res.position + 1, ::fast_io::details::intrinsics::add_or_overflow_die_chain(res.neededspace, sz)}; + } + } + else if constexpr (::fast_io::scatter_printable && findscatter) + { + if constexpr (sizeof...(Args) == 0) + { + return {1, 0}; + } + else + { + auto res{find_continuous_scatters_reserve_n()}; + return {res.position + 1, 0}; + } + } + else + { + return {0, 0}; + } +} + +template +inline constexpr bool minimum_buffer_output_stream_require_size_constant_impl = + (N < obuffer_minimum_size_define(::fast_io::io_reserve_type)); + +template +concept minimum_buffer_output_stream_require_size_impl = + ::fast_io::operations::decay::defines::has_obuffer_minimum_size_operations && + minimum_buffer_output_stream_require_size_constant_impl; + +template <::std::size_t sz> + requires(sz != 0) +inline constexpr void scatter_rsv_update_times(::fast_io::io_scatter_t *first, ::fast_io::io_scatter_t *last) noexcept +{ + if constexpr (sz != 1) + { + for (; first != last; ++first) + { + first->len *= sz; + } + } +} + +template <::std::integral char_type> +struct basic_reserve_scatters_define_byte_result +{ + io_scatter_t *scatters_pos_ptr; + char_type *reserve_pos_ptr; +}; + +template <::std::integral char_type, typename T> +inline ::fast_io::details::decay::basic_reserve_scatters_define_byte_result +prrsvsct_byte_common_rsvsc_impl(io_scatter_t *pscatters, char_type *buffer, T t) +{ + using basicioscattertypealiasptr +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = basic_io_scatter_t *; + using scatterioscattertypealiasptr +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = io_scatter_t *; + auto result{print_reserve_scatters_define(::fast_io::io_reserve_type>, + reinterpret_cast(pscatters), buffer, t)}; + scatterioscattertypealiasptr ptr{reinterpret_cast(result.scatters_pos_ptr)}; + if constexpr (sizeof(char_type) != 1) + { + scatter_rsv_update_times(pscatters, ptr); + } + return {ptr, result.reserve_pos_ptr}; +} + +template <::std::integral char_type, typename T> +inline auto prrsvsct_byte_common_impl(io_scatter_t *pscatters, char_type *buffer, T t) +{ + return ::fast_io::details::decay::prrsvsct_byte_common_rsvsc_impl(pscatters, buffer, t).scatters_pos_ptr; +} + +template + requires(::std::is_trivially_copyable_v && ::std::is_trivially_copyable_v) +inline constexpr void print_control_single(output outstm, T t) +{ + using char_type = typename output::output_char_type; + using value_type = ::std::remove_cvref_t; + constexpr bool asan_activated{::fast_io::details::asan_state::current == ::fast_io::details::asan_state::activate}; + constexpr auto lfch{char_literal_v}; + if constexpr (scatter_printable) + { +#if 0 + basic_io_scatter_t scatter; + if constexpr(::std::same_as>) + { + scatter=t; + } + else + { + scatter=print_scatter_define(::fast_io::io_reserve_type,t); + } + if constexpr(line) + { + if constexpr(contiguous_output_stream) + { + auto curr=obuffer_curr(out); + auto end=obuffer_end(out); + ::std::ptrdiff_t sz(end-curr-1); + ::std::size_t const len{scatter.len}; + if(sz(len)) + fast_terminate(); + curr=non_overlapped_copy_n(scatter.base,scatter.len,curr); + *curr=lfch; + ++curr; + obuffer_set_curr(outstm,curr); + } + else if constexpr(::fast_io::operations::decay::defines::has_obuffer_basic_operations) + { + auto curr=obuffer_curr(out); + auto end=obuffer_end(out); + ::std::size_t const len{scatter.len}; + ::std::ptrdiff_t sz(end-curr-1); + if(static_cast<::std::ptrdiff_t>(len)) + { + ::fast_io::io_scatter_t scatters[2]{ + {t.base, t.len * sizeof(char_type)}, + {__builtin_addressof(char_literal_v), sizeof(char_type)}}; + ::fast_io::operations::decay::scatter_write_all_bytes_decay(outstm, scatters, 2); + } + else + { + ::fast_io::basic_io_scatter_t scatters[2]{ + t, {__builtin_addressof(char_literal_v), 1}}; + ::fast_io::operations::decay::scatter_write_all_decay(outstm, scatters, 2); + } + } + else + { + ::fast_io::operations::decay::write_all_decay(outstm, t.base, t.base + t.len); + } + } + else if constexpr (reserve_printable) + { + constexpr ::std::size_t real_size{print_reserve_size(::fast_io::io_reserve_type)}; + constexpr ::std::size_t size{real_size + static_cast<::std::size_t>(line)}; + static_assert(real_size < PTRDIFF_MAX); +#if 0 + if constexpr(contiguous_output_stream) + { + auto bcurr{obuffer_curr(outstm)}; + auto bend{obuffer_end(outstm)}; + ::std::size_t diff{static_cast<::std::size_t>(bend-bcurr)}; + if(diff,bcurr,t)}; + if constexpr(line) + { + *it=lfch; + ++it; + } + obuffer_set_curr(outstm,it); + } + else +#endif + { + if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations && + !asan_activated) + { + char_type *bcurr{obuffer_curr(outstm)}; + char_type *bend{obuffer_end(outstm)}; + ::std::ptrdiff_t const diff(bend - bcurr); + bool smaller{static_cast<::std::ptrdiff_t>(size) < diff}; + if constexpr (minimum_buffer_output_stream_require_size_impl) + { + if (!smaller) [[unlikely]] + { + obuffer_minimum_size_flush_prepare_define(outstm); + bcurr = obuffer_curr(outstm); + } + bcurr = print_reserve_define(::fast_io::io_reserve_type, bcurr, t); + if constexpr (line) + { + *bcurr = lfch; + ++bcurr; + } + obuffer_set_curr(outstm, bcurr); + } + else + { + char_type buffer[size]; + if (!smaller) [[unlikely]] + { + bcurr = buffer; + } + bcurr = print_reserve_define(::fast_io::io_reserve_type, bcurr, t); + if constexpr (line) + { + *bcurr = lfch; + ++bcurr; + } + if (smaller) [[likely]] + { + obuffer_set_curr(outstm, bcurr); + } + else [[unlikely]] + { + ::fast_io::operations::decay::write_all_decay(outstm, buffer, bcurr); + } + } + } + else + { + char_type buffer[size]; + char_type *i{print_reserve_define(::fast_io::io_reserve_type, buffer, t)}; + if constexpr (line) + { + *i = lfch; + ++i; + } + ::fast_io::operations::decay::write_all_decay(outstm, buffer, i); + } + } + } + else if constexpr (dynamic_reserve_printable) + { + ::std::size_t size{print_reserve_size(::fast_io::io_reserve_type, t)}; + if constexpr (line) + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::ptrdiff_t>::max() - 1}; + if (size >= mx) + { + fast_terminate(); + } + ++size; + } + else + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::ptrdiff_t>::max()}; + if (mx < size) + { + fast_terminate(); + } + } +#if 0 + if constexpr(contiguous_output_stream) + { + auto bcurr{obuffer_curr(outstm)}; + auto bend{obuffer_end(outstm)}; + auto it{print_reserve_define(::fast_io::io_reserve_type,bcurr,t,size)}; + ::std::size_t diff{static_cast<::std::size_t>(bend-bcurr)}; + if(diff && + !asan_activated) + { + auto curr{obuffer_curr(outstm)}; + auto ed{obuffer_end(outstm)}; + ::std::ptrdiff_t diff(ed - curr); + auto toptr{curr}; + bool smaller{static_cast<::std::ptrdiff_t>(size) < diff}; + ::fast_io::details::local_operator_new_array_ptr newptr; + if (!smaller) +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + newptr.ptr = toptr = ::fast_io::details::allocate_iobuf_space< + char_type, + typename ::fast_io::details::local_operator_new_array_ptr::allocator_type>(size); + newptr.size = size; + } + + auto it{print_reserve_define(::fast_io::io_reserve_type, toptr, t)}; + if constexpr (line) + { + *it = lfch; + ++it; + } + if (smaller) + { + obuffer_set_curr(outstm, it); + } + else +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + ::fast_io::operations::decay::write_all_decay(outstm, toptr, it); + } + } + else + { + ::fast_io::details::local_operator_new_array_ptr newptr(size); + auto it{print_reserve_define(::fast_io::io_reserve_type, newptr.ptr, t)}; + if constexpr (line) + { + *it = lfch; + ++it; + } + ::fast_io::operations::decay::write_all_decay(outstm, newptr.ptr, it); + } + } + } + else if constexpr (reserve_scatters_printable) + { + constexpr auto sz{print_reserve_scatters_size(::fast_io::io_reserve_type)}; + static_assert(!line || sz.scatters_size != SIZE_MAX); + constexpr ::std::size_t scattersnum{sz.scatters_size + static_cast<::std::size_t>(line)}; +#if __cpp_if_consteval >= 202106L + if !consteval +#else + if (!__builtin_is_constant_evaluated()) +#endif + { + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + output>) + { + ::fast_io::io_scatter_t scattersbuffer[scattersnum]; + char_type buffer[sz.reserve_size]; + ::fast_io::io_scatter_t *ptr{ + ::fast_io::details::decay::prrsvsct_byte_common_impl(scattersbuffer, buffer, t)}; + if constexpr (line) + { + *ptr = ::fast_io::details::decay::line_scatter_common; + ++ptr; + } + ::fast_io::operations::decay::scatter_write_all_bytes_decay(outstm, scattersbuffer, static_cast<::std::size_t>(ptr - scattersbuffer)); + return; + } + } + ::fast_io::basic_io_scatter_t scattersbuffer[scattersnum]; + char_type buffer[sz.reserve_size]; + auto ptr{print_reserve_scatters_define(::fast_io::io_reserve_type>, + scattersbuffer, buffer, t) + .scatters_pos_ptr}; + if constexpr (line) + { + *ptr = ::fast_io::details::decay::line_scatter_common; + ++ptr; + } + ::fast_io::operations::decay::scatter_write_all_decay(outstm, scattersbuffer, static_cast<::std::size_t>(ptr - scattersbuffer)); + } + else if constexpr (::fast_io::transcode_imaginary_printable) + { + // todo? + } + else if constexpr (context_printable) + { + typename ::std::remove_cvref_t))>::type st; + constexpr ::std::size_t reserved_size{32u}; + constexpr ::std::ptrdiff_t reserved_size_no_line{ + static_cast<::std::ptrdiff_t>(reserved_size - static_cast<::std::size_t>(line))}; + if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations) + { + for (;;) + { + auto bcurr{obuffer_curr(outstm)}; + auto bed{obuffer_end(outstm)}; + if (bed <= bcurr) +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + if constexpr (minimum_buffer_output_stream_require_size_impl) + { + obuffer_minimum_size_flush_prepare_define(outstm); + bcurr = obuffer_curr(outstm); + bed = obuffer_end(outstm); + } + else + { + ::fast_io::operations::decay::output_stream_buffer_flush_decay(outstm); + bcurr = obuffer_curr(outstm); + bed = obuffer_end(outstm); + if (bed - bcurr < reserved_size_no_line) +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + char_type buffer[reserved_size]; + char_type *buffered{buffer + reserved_size_no_line}; + for (;;) + { + auto [resit, done] = st.print_context_define(t, buffer, buffered); + if constexpr (line) + { + if (done) + { + *resit = lfch; + ++resit; + } + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + else + { + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + } + return; + } + } + } + else + { + auto [resit, done] = st.print_context_define(t, bcurr, bed); + obuffer_set_curr(outstm, resit); + if (done) +#if __has_cpp_attribute(likely) + [[likely]] +#endif + { + if constexpr (line) + { + ::fast_io::operations::decay::char_put_decay(outstm, lfch); + } + return; + } + } + } + } + else + { + char_type buffer[reserved_size]; + char_type *buffered{buffer + reserved_size_no_line}; + for (;;) + { + auto [resit, done] = st.print_context_define(t, buffer, buffered); + if constexpr (line) + { + if (done) + { + *resit = lfch; + ++resit; + } + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + else + { + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + } + return; + } + } + else if constexpr (printable) + { + print_define(::fast_io::io_reserve_type, outstm, t); + if constexpr (line) + { + ::fast_io::operations::decay::char_put_decay(outstm, lfch); + } + } + else + { + constexpr bool no{printable}; + static_assert(no, "type not printable"); + } +} + +#if 0 +template +inline constexpr char_type* printrsvcontiguousimpl(char_type* iter,Arg arg,Args... args) +{ + if constexpr(sizeof...(Args)!=0) + { + ret = find_continuous_scatters_n(); + } + if constexpr(::fast_io::scatter_printable) + { + return {ret.position+1,ret.neededspace,ret.hasdynamicreserve}; + } + else if constexpr(::fast_io::reserve_printable) + { + constexpr + ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; + return {ret.position+1, + ::fast_io::details::add_overflow(ret.neededspace,sz), + ret.hasdynamicreserve}; + } + else if constexpr(::fast_io::dynamic_reserve_printable) + { + return {ret.position+1,ret.neededspace,true}; + } +} +#endif + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr void print_controls_line(output outstm, T t, Args... args) +{ + if constexpr (sizeof...(Args) == 0) + { + print_control_single(outstm, t); + } + else + { +#if (defined(__OPTIMIZE__) || defined(__OPTIMIZE_SIZE__)) && 0 + print_controls_line_multi_impl(outstm, t, args...); +#else + if constexpr (ln) + { + print_control_single(outstm, t); + print_controls_line(outstm, args...); + } + else + { + print_control_single(outstm, t); + (print_control(outstm, args), ...); + } +#endif + } +} + +template <::std::size_t n, ::std::integral char_type, typename T, typename... Args> +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr char_type *print_n_reserve(char_type *ptr, T t, Args... args) +{ + if constexpr (n == 0) + { + return ptr; + } + else + { + ptr = print_reserve_define(::fast_io::io_reserve_type>, ptr, t); + if constexpr (sizeof...(Args) == 0 || n < 2) + { + return ptr; + } + else + { + return print_n_reserve(ptr, args...); + } + } +} + +template <::std::size_t n, ::std::integral char_type, typename scattertype, typename T, typename... Args> +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr void print_n_scatters(basic_io_scatter_t *pscatters, +#if __has_cpp_attribute(maybe_unused) + [[maybe_unused]] +#endif + T t, +#if __has_cpp_attribute(maybe_unused) + [[maybe_unused]] +#endif + Args... args) +{ + if constexpr (n != 0) + { + if constexpr (::std::same_as<::std::remove_cvref_t, basic_io_scatter_t>) + { + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{t.base, t.len * sizeof(char_type)}; + } + else + { + *pscatters = t; + } + } + else + { + basic_io_scatter_t sct{print_scatter_define(::fast_io::io_reserve_type, t)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{sct.base, sct.len * sizeof(char_type)}; + } + else + { + *pscatters = sct; + } + } + if constexpr (1 < n) + { + ++pscatters; + return print_n_scatters(pscatters, args...); + } + } +} + +template <::std::size_t n, ::std::integral char_type, typename T, typename... Args> +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr ::std::size_t ndynamic_print_reserve_size(T t, Args... args) +{ + using nocvreft = ::std::remove_cvref_t; + if constexpr (n == 0) + { + return 0; + } + else if constexpr (n == 1) + { + if constexpr (::fast_io::dynamic_reserve_printable) + { + return print_reserve_size(::fast_io::io_reserve_type, t); + } + else + { + return 0; + } + } + else + { + if constexpr (::fast_io::dynamic_reserve_printable) + { + return ::fast_io::details::intrinsics::add_or_overflow_die( + print_reserve_size(::fast_io::io_reserve_type, t), + ::fast_io::details::decay::ndynamic_print_reserve_size(args...)); + } + else + { + return ::fast_io::details::decay::ndynamic_print_reserve_size(args...); + } + } +} + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr auto print_n_scatters_reserve(basic_io_scatter_t *pscatters, char_type *ptr, T t, + Args... args); + +template <::std::integral char_type, typename T, typename... Args> +inline constexpr bool print_next_is_reserve() noexcept +{ + using nocvreft = ::std::remove_cvref_t; + if constexpr (::fast_io::reserve_printable || + ::fast_io::dynamic_reserve_printable) + { + return true; + } + else + { + return false; + } +} + +template <::std::integral char_type> +inline constexpr bool print_next_is_reserve() noexcept +{ + return false; +} + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr auto print_n_scatters_reserve_cont(basic_io_scatter_t *pscatters, char_type *base, + char_type *ptr, T t, Args... args) +{ + if constexpr (n != 0) + { + using nocvreft = ::std::remove_cvref_t; + if constexpr (reserve_printable || dynamic_reserve_printable) + { + ptr = print_reserve_define(::fast_io::io_reserve_type, ptr, t); + if constexpr (::fast_io::details::decay::print_next_is_reserve()) + { + return ::fast_io::details::decay::print_n_scatters_reserve_cont( + pscatters, base, ptr, args...); + } + else + { + if constexpr (n == 1 && needprintlf) + { + *ptr = char_literal_v; + ++ptr; + } + ::std::size_t const sz{static_cast<::std::size_t>(ptr - base)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{base, sz * sizeof(char_type)}; + } + else + { + *pscatters = basic_io_scatter_t{base, sz}; + } + ++pscatters; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pscatters, ptr, args...); + } + } + } + else + { + ::std::size_t const sz{static_cast<::std::size_t>(ptr - base)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{base, sz * sizeof(char_type)}; + } + else + { + *pscatters = basic_io_scatter_t{base, sz}; + } + ++pscatters; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pscatters, ptr, t, args...); + } + } + } + return pscatters; +} + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr auto print_n_scatters_reserve(basic_io_scatter_t *pscatters, char_type *ptr, T t, + Args... args) +{ + if constexpr (n != 0) + { + using nocvreft = ::std::remove_cvref_t; + if constexpr (::fast_io::reserve_printable || + ::fast_io::dynamic_reserve_printable) + { + auto ptred{print_reserve_define(::fast_io::io_reserve_type, ptr, t)}; + if constexpr (sizeof...(Args) != 0 && + ::fast_io::details::decay::print_next_is_reserve()) + { + return ::fast_io::details::decay::print_n_scatters_reserve_cont( + pscatters, ptr, ptred, args...); + } + else + { + if constexpr (n == 1 && needprintlf) + { + *ptred = char_literal_v; + ++ptred; + } + ::std::size_t const sz{static_cast<::std::size_t>(ptred - ptr)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{ptr, sz * sizeof(char_type)}; + } + else + { + *pscatters = basic_io_scatter_t{ptr, sz}; + } + ++pscatters; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pscatters, ptred, args...); + } + } + } + else if constexpr (::fast_io::scatter_printable) + { + if constexpr (::std::same_as>) + { + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{t.base, t.len * sizeof(char_type)}; + } + else + { + *pscatters = t; + } + } + else + { + basic_io_scatter_t sct{print_scatter_define(::fast_io::io_reserve_type, t)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{sct.base, sct.len * sizeof(char_type)}; + } + else + { + *pscatters = sct; + } + } + ++pscatters; + if constexpr (n == 1 && needprintlf) + { + *pscatters = ::fast_io::details::decay::line_scatter_common; + ++pscatters; + } + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve(pscatters, + ptr, args...); + } + } + else if constexpr (::fast_io::reserve_scatters_printable) + { + if constexpr (::std::same_as) + { + auto pit{::fast_io::details::decay::prrsvsct_byte_common_rsvsc_impl(pscatters, ptr, t)}; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pit.scatters_pos_ptr, pit.reserve_pos_ptr, args...); + } + else if constexpr (n == 1 && needprintlf) + { + *pit.scatters_pos_ptr = ::fast_io::details::decay::line_scatter_common; + ++pit.scatters_pos_ptr; + } + return pit.scatters_pos_ptr; + } + else + { + auto pit{ + print_reserve_scatters_define(::fast_io::io_reserve_type, pscatters, ptr, t)}; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pit.scatters_pos_ptr, pit.reserve_pos_ptr, args...); + } + else if constexpr (n == 1 && needprintlf) + { + *pit = ::fast_io::details::decay::line_scatter_common; + ++pit; + } + return pit; + } + } + } + return pscatters; +} + +template +inline constexpr void print_controls_impl(outputstmtype optstm, T t, Args... args) +{ + using char_type = typename outputstmtype::output_char_type; + using scatter_type = ::std::conditional_t< + ::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations, + io_scatter_t, basic_io_scatter_t>; + constexpr contiguous_scatter_result res{ + ::fast_io::details::decay::find_continuous_scatters_n()}; + if constexpr (skippings != 0) + { + print_controls_impl(optstm, args...); + } + else if constexpr (sizeof...(Args) == 0) + { + print_control_single(optstm, t); + } + else if constexpr (res.position == 0) + { + print_control_single(optstm, t); + print_controls_impl(optstm, args...); + } + else + { + if constexpr (line) + { + static_assert(res.neededscatters != SIZE_MAX); + } + static_assert(SIZE_MAX != sizeof...(Args)); + constexpr ::std::size_t n{sizeof...(Args) + static_cast<::std::size_t>(1)}; + constexpr bool needprintlf{n == res.position && line}; + if constexpr (res.hasscatters && !res.hasreserve && !res.hasdynamicreserve) + { + constexpr ::std::size_t scatterscount{res.neededscatters + static_cast<::std::size_t>(needprintlf)}; + { + scatter_type scatters[scatterscount]; + ::fast_io::details::decay::print_n_scatters(scatters, t, args...); + if constexpr (needprintlf) + { + scatters[n] = ::fast_io::details::decay::line_scatter_common< + char_type, ::std::conditional_t<::std::same_as, void, char_type>>; + } + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, scatterscount); + } + else + { + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, scatterscount); + } + } + } + else + { + constexpr ::std::size_t mxsize{ + static_cast<::std::size_t>(res.neededspace + static_cast<::std::size_t>(needprintlf))}; + if constexpr (!res.hasscatters) + { + static_assert(!needprintlf || res.neededspace != SIZE_MAX); + if constexpr (res.hasdynamicreserve) + { + ::std::size_t dynsz{ + ::fast_io::details::decay::ndynamic_print_reserve_size(t, args...)}; + ::std::size_t totalsz{::fast_io::details::intrinsics::add_or_overflow_die(mxsize, dynsz)}; + ::fast_io::details::local_operator_new_array_ptr newptr(totalsz); + char_type *buffer{newptr.ptr}; + char_type *ptred{ + ::fast_io::details::decay::print_n_reserve(buffer, t, args...)}; + if constexpr (needprintlf) + { + *ptred = ::fast_io::char_literal_v; + ++ptred; + } + ::fast_io::operations::decay::write_all_decay(optstm, buffer, ptred); + } + else if constexpr (res.hasreserve) + { + if constexpr (res.neededspace == 0) + { + if constexpr (needprintlf) + { + ::fast_io::operations::decay::char_put_decay(optstm, + ::fast_io::char_literal_v); + } + } + else + { + char_type buffer[mxsize]; + char_type *ptred{ + ::fast_io::details::decay::print_n_reserve(buffer, t, args...)}; + if constexpr (needprintlf) + { + *ptred = ::fast_io::char_literal_v; + ++ptred; + } + ::fast_io::operations::decay::write_all_decay(optstm, buffer, ptred); + } + } + } + else if constexpr (res.hasreserve && !res.hasdynamicreserve) + { + constexpr ::std::size_t scatterscount{res.neededscatters + + static_cast<::std::size_t>(line && res.position == n)}; + scatter_type scatters[scatterscount]; + char_type buffer[mxsize]; + + auto ptr{::fast_io::details::decay::print_n_scatters_reserve( + scatters, buffer, t, args...)}; + ::std::size_t diff{static_cast<::std::size_t>(ptr - scatters)}; + + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, diff); + } + else + { + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, diff); + } + } + else if constexpr (res.hasdynamicreserve) + { + constexpr ::std::size_t scatterscount{res.neededscatters + + static_cast<::std::size_t>(line && res.position == n)}; + ::std::size_t dynsz{ + ::fast_io::details::decay::ndynamic_print_reserve_size(t, args...)}; + ::std::size_t totalsz{::fast_io::details::intrinsics::add_or_overflow_die(mxsize, dynsz)}; + ::fast_io::details::local_operator_new_array_ptr newptr(totalsz); + scatter_type scatters[scatterscount]; + char_type *buffer{newptr.ptr}; + auto ptr{::fast_io::details::decay::print_n_scatters_reserve( + scatters, buffer, t, args...)}; + ::std::size_t diff{static_cast<::std::size_t>(ptr - scatters)}; + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, diff); + } + else + { + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, diff); + } + } + if constexpr (res.position != n) + { + print_controls_impl(optstm, args...); + } + } + } +} + +template +inline constexpr void print_controls_buffer_impl(outputstmtype optstm, T t, Args... args) +{ + if constexpr (skippings != 0) + { + ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + else if constexpr (sizeof...(Args) == 0) + { + print_control_single(optstm, t); + } + else + { + using char_type = typename outputstmtype::output_char_type; + static_assert(SIZE_MAX != sizeof...(Args)); + constexpr ::std::size_t n{sizeof...(Args) + static_cast<::std::size_t>(1)}; + constexpr auto scatters_result{ + ::fast_io::details::decay::find_continuous_scatters_reserve_n()}; + using scatter_type = ::std::conditional_t< + ::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations, + io_scatter_t, basic_io_scatter_t>; + if constexpr (scatters_result.position != 0) + { + if constexpr (line) + { + static_assert(scatters_result.position != SIZE_MAX); + } + constexpr bool needprintlf{n == scatters_result.position && line}; + constexpr ::std::size_t scatterscount{scatters_result.position + static_cast<::std::size_t>(needprintlf)}; + scatter_type scatters[scatterscount]; + ::fast_io::details::decay::print_n_scatters(scatters, t, args...); + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + if constexpr (needprintlf) + { + scatters[scatterscount - 1] = ::fast_io::details::decay::line_scatter_common; + } + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, scatterscount); + } + else + { + if constexpr (needprintlf) + { + scatters[scatterscount - 1] = ::fast_io::details::decay::line_scatter_common; + } + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, scatterscount); + } + if constexpr (scatters_result.position != n) + { + ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + } + else + { + constexpr auto rsvresult{ + ::fast_io::details::decay::find_continuous_scatters_reserve_n()}; + if constexpr (1 < rsvresult.position) + { + constexpr bool needprintlf{n == rsvresult.position && line}; + constexpr ::std::size_t buffersize{rsvresult.neededspace + static_cast<::std::size_t>(needprintlf)}; + char_type *bcurr{obuffer_curr(optstm)}; + char_type *bend{obuffer_end(optstm)}; + ::std::ptrdiff_t const diff(bend - bcurr); + bool smaller{static_cast<::std::ptrdiff_t>(buffersize) < diff}; + if constexpr (minimum_buffer_output_stream_require_size_impl) + { + if (!smaller) [[unlikely]] + { + obuffer_minimum_size_flush_prepare_define(optstm); + bcurr = obuffer_curr(optstm); + } + bcurr = + ::fast_io::details::decay::print_n_reserve(bcurr, t, args...); + if constexpr (needprintlf) + { + *bcurr = ::fast_io::char_literal_v; + ++bcurr; + } + obuffer_set_curr(optstm, bcurr); + } + else + { + char_type buffer[buffersize]; + if (!smaller) [[unlikely]] + { + bcurr = buffer; + } + bcurr = + ::fast_io::details::decay::print_n_reserve(bcurr, t, args...); + if constexpr (needprintlf) + { + *bcurr = ::fast_io::char_literal_v; + ++bcurr; + } + if (smaller) [[likely]] + { + obuffer_set_curr(optstm, bcurr); + } + else [[unlikely]] + { + ::fast_io::operations::decay::write_all_decay(optstm, buffer, bcurr); + } + } + if constexpr (rsvresult.position != n) + { + ::fast_io::details::decay::print_controls_buffer_impl( + optstm, args...); + } + } + else + { + ::fast_io::details::decay::print_control_single(optstm, t); + if constexpr (sizeof...(args) != 0) + { + ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + } + } + } +} + +} // namespace details::decay + +namespace operations +{ + +namespace decay +{ + +template +inline constexpr decltype(auto) print_freestanding_decay(outputstmtype optstm, Args... args) +{ + if constexpr (::fast_io::operations::decay::defines::has_status_print_define) + { + return status_print_define(optstm, args...); + } + else if constexpr (sizeof...(Args) == 0) + { + if constexpr (line) + { + using char_type = typename outputstmtype::output_char_type; + return ::fast_io::operations::decay::char_put_decay(optstm, char_literal_v); + } + else + { + return; + } + } + else if constexpr (::fast_io::operations::decay::defines::has_output_or_io_stream_mutex_ref_define) + { + ::fast_io::operations::decay::stream_ref_decay_lock_guard lg{ + ::fast_io::operations::decay::output_stream_mutex_ref_decay(optstm)}; + return ::fast_io::operations::decay::print_freestanding_decay( + ::fast_io::operations::decay::output_stream_unlocked_ref_decay(optstm), args...); + } + else if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations) + { + return ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + else + { + return ::fast_io::details::decay::print_controls_impl(optstm, args...); + } +} + +template +#if __has_cpp_attribute(__gnu__::__cold__) +[[__gnu__::__cold__]] +#endif +inline constexpr decltype(auto) print_freestanding_decay_cold(outputstmtype optstm, Args... args) +{ +#if !__has_cpp_attribute(__gnu__::__cold__) && __has_cpp_attribute(unlikely) + if (true) [[unlikely]] +#endif + return ::fast_io::operations::decay::print_freestanding_decay(optstm, args...); +} + +} // namespace decay + +namespace decay::defines +{ + +template +concept print_freestanding_params_okay = + ::std::integral && + ((::fast_io::printable || ::fast_io::reserve_printable || + ::fast_io::dynamic_reserve_printable || ::fast_io::scatter_printable || + ::fast_io::reserve_scatters_printable || ::fast_io::context_printable || + ::fast_io::transcode_imaginary_printable) && + ...); + +template +concept print_freestanding_okay = + ::fast_io::operations::decay::defines::print_freestanding_params_okay; + +} // namespace decay::defines + +namespace defines +{ + +template +concept print_freestanding_params_okay = ::fast_io::operations::decay::defines::print_freestanding_params_okay(::fast_io::io_print_alias(::std::declval())))...>; + +template +concept print_freestanding_okay = ::fast_io::operations::decay::defines::print_freestanding_okay< + decltype(::fast_io::operations::output_stream_ref(::std::declval())), + decltype(::fast_io::io_print_forward()))::output_char_type>(::fast_io::io_print_alias(::std::declval())))...>; + +} // namespace defines + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr void print_freestanding(output &&outstm, Args &&...args) +{ + ::fast_io::operations::decay::print_freestanding_decay( + ::fast_io::operations::output_stream_ref(outstm), + io_print_forward( + io_print_alias(args))...); +} + +} // namespace operations + +} // namespace fast_io From 941baa864c9dd6a695ab5c2f955b7fd9d543049f Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 6 Apr 2025 18:13:21 -0400 Subject: [PATCH 02/16] impl --- .../operations/printimpl/impl.h | 2 +- ...estanding.h => print_freestanding_cxx20.h} | 0 .../printimpl/print_freestanding_cxx26.h | 1396 +++++++++++++++++ 3 files changed, 1397 insertions(+), 1 deletion(-) rename include/fast_io_core_impl/operations/printimpl/{print_freestanding.h => print_freestanding_cxx20.h} (100%) create mode 100644 include/fast_io_core_impl/operations/printimpl/print_freestanding_cxx26.h diff --git a/include/fast_io_core_impl/operations/printimpl/impl.h b/include/fast_io_core_impl/operations/printimpl/impl.h index 4a16a6683..89ebababc 100644 --- a/include/fast_io_core_impl/operations/printimpl/impl.h +++ b/include/fast_io_core_impl/operations/printimpl/impl.h @@ -1,3 +1,3 @@ #pragma once -#include "print_freestanding.h" \ No newline at end of file +#include "print_freestanding_cxx20.h" \ No newline at end of file diff --git a/include/fast_io_core_impl/operations/printimpl/print_freestanding.h b/include/fast_io_core_impl/operations/printimpl/print_freestanding_cxx20.h similarity index 100% rename from include/fast_io_core_impl/operations/printimpl/print_freestanding.h rename to include/fast_io_core_impl/operations/printimpl/print_freestanding_cxx20.h diff --git a/include/fast_io_core_impl/operations/printimpl/print_freestanding_cxx26.h b/include/fast_io_core_impl/operations/printimpl/print_freestanding_cxx26.h new file mode 100644 index 000000000..92633ef6e --- /dev/null +++ b/include/fast_io_core_impl/operations/printimpl/print_freestanding_cxx26.h @@ -0,0 +1,1396 @@ +#pragma once + +namespace fast_io +{ + +namespace details::decay +{ + +template <::std::integral char_type, typename T = char_type> +inline constexpr basic_io_scatter_t line_scatter_common{__builtin_addressof(char_literal_v), + ::std::same_as ? sizeof(char_type) : 1}; + +struct contiguous_scatter_result +{ + ::std::size_t position{}; + ::std::size_t neededscatters{}; + ::std::size_t neededspace{}; + bool lastisreserve{}; + bool hasscatters{}; + bool hasreserve{}; + bool hasdynamicreserve{}; +}; + +template <::std::integral char_type, typename Arg, typename... Args> +inline constexpr contiguous_scatter_result find_continuous_scatters_n() +{ + contiguous_scatter_result ret{}; + if constexpr (::fast_io::scatter_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + ++ret.position; + ret.hasscatters = true; + ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, + static_cast<::std::size_t>(1)); + } + else if constexpr (::fast_io::reserve_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + else + { + ret.lastisreserve = true; + } + constexpr ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; + static_assert(sz != 0); + ++ret.position; + ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, + static_cast<::std::size_t>(1)); + ret.neededspace = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededspace, sz); + ret.hasreserve = true; + } + else if constexpr (::fast_io::dynamic_reserve_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + else + { + ret.lastisreserve = true; + } + ++ret.position; + ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, + static_cast<::std::size_t>(1)); + ret.hasdynamicreserve = true; + } + else if constexpr (::fast_io::reserve_scatters_printable) + { + if constexpr (sizeof...(Args) != 0) + { + ret = find_continuous_scatters_n(); + } + constexpr auto scatszres{print_reserve_scatters_size(::fast_io::io_reserve_type)}; + static_assert(scatszres.scatters_size != 0); + ret.hasscatters = true; + ret.hasreserve = true; + ++ret.position; + ret.neededspace = + ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededspace, scatszres.reserve_size); + ret.neededscatters = + ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, scatszres.scatters_size); + } + return ret; +} + +struct scatter_rsv_result +{ + ::std::size_t position{}; + ::std::size_t neededspace{}; +}; + +template +inline constexpr scatter_rsv_result find_continuous_scatters_reserve_n() +{ + if constexpr (::fast_io::reserve_printable && !findscatter) + { + constexpr ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; + if constexpr (sizeof...(Args) == 0) + { + return {1, sz}; + } + else + { + auto res{find_continuous_scatters_reserve_n()}; + return {res.position + 1, ::fast_io::details::intrinsics::add_or_overflow_die_chain(res.neededspace, sz)}; + } + } + else if constexpr (::fast_io::scatter_printable && findscatter) + { + if constexpr (sizeof...(Args) == 0) + { + return {1, 0}; + } + else + { + auto res{find_continuous_scatters_reserve_n()}; + return {res.position + 1, 0}; + } + } + else + { + return {0, 0}; + } +} + +template +inline constexpr bool minimum_buffer_output_stream_require_size_constant_impl = + (N < obuffer_minimum_size_define(::fast_io::io_reserve_type)); + +template +concept minimum_buffer_output_stream_require_size_impl = + ::fast_io::operations::decay::defines::has_obuffer_minimum_size_operations && + minimum_buffer_output_stream_require_size_constant_impl; + +template <::std::size_t sz> + requires(sz != 0) +inline constexpr void scatter_rsv_update_times(::fast_io::io_scatter_t *first, ::fast_io::io_scatter_t *last) noexcept +{ + if constexpr (sz != 1) + { + for (; first != last; ++first) + { + first->len *= sz; + } + } +} + +template <::std::integral char_type> +struct basic_reserve_scatters_define_byte_result +{ + io_scatter_t *scatters_pos_ptr; + char_type *reserve_pos_ptr; +}; + +template <::std::integral char_type, typename T> +inline ::fast_io::details::decay::basic_reserve_scatters_define_byte_result +prrsvsct_byte_common_rsvsc_impl(io_scatter_t *pscatters, char_type *buffer, T t) +{ + using basicioscattertypealiasptr +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = basic_io_scatter_t *; + using scatterioscattertypealiasptr +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = io_scatter_t *; + auto result{print_reserve_scatters_define(::fast_io::io_reserve_type>, + reinterpret_cast(pscatters), buffer, t)}; + scatterioscattertypealiasptr ptr{reinterpret_cast(result.scatters_pos_ptr)}; + if constexpr (sizeof(char_type) != 1) + { + scatter_rsv_update_times(pscatters, ptr); + } + return {ptr, result.reserve_pos_ptr}; +} + +template <::std::integral char_type, typename T> +inline auto prrsvsct_byte_common_impl(io_scatter_t *pscatters, char_type *buffer, T t) +{ + return ::fast_io::details::decay::prrsvsct_byte_common_rsvsc_impl(pscatters, buffer, t).scatters_pos_ptr; +} + +template + requires(::std::is_trivially_copyable_v && ::std::is_trivially_copyable_v) +inline constexpr void print_control_single(output outstm, T t) +{ + using char_type = typename output::output_char_type; + using value_type = ::std::remove_cvref_t; + constexpr bool asan_activated{::fast_io::details::asan_state::current == ::fast_io::details::asan_state::activate}; + constexpr auto lfch{char_literal_v}; + if constexpr (scatter_printable) + { +#if 0 + basic_io_scatter_t scatter; + if constexpr(::std::same_as>) + { + scatter=t; + } + else + { + scatter=print_scatter_define(::fast_io::io_reserve_type,t); + } + if constexpr(line) + { + if constexpr(contiguous_output_stream) + { + auto curr=obuffer_curr(out); + auto end=obuffer_end(out); + ::std::ptrdiff_t sz(end-curr-1); + ::std::size_t const len{scatter.len}; + if(sz(len)) + fast_terminate(); + curr=non_overlapped_copy_n(scatter.base,scatter.len,curr); + *curr=lfch; + ++curr; + obuffer_set_curr(outstm,curr); + } + else if constexpr(::fast_io::operations::decay::defines::has_obuffer_basic_operations) + { + auto curr=obuffer_curr(out); + auto end=obuffer_end(out); + ::std::size_t const len{scatter.len}; + ::std::ptrdiff_t sz(end-curr-1); + if(static_cast<::std::ptrdiff_t>(len)) + { + ::fast_io::io_scatter_t scatters[2]{ + {t.base, t.len * sizeof(char_type)}, + {__builtin_addressof(char_literal_v), sizeof(char_type)}}; + ::fast_io::operations::decay::scatter_write_all_bytes_decay(outstm, scatters, 2); + } + else + { + ::fast_io::basic_io_scatter_t scatters[2]{ + t, {__builtin_addressof(char_literal_v), 1}}; + ::fast_io::operations::decay::scatter_write_all_decay(outstm, scatters, 2); + } + } + else + { + ::fast_io::operations::decay::write_all_decay(outstm, t.base, t.base + t.len); + } + } + else if constexpr (reserve_printable) + { + constexpr ::std::size_t real_size{print_reserve_size(::fast_io::io_reserve_type)}; + constexpr ::std::size_t size{real_size + static_cast<::std::size_t>(line)}; + static_assert(real_size < PTRDIFF_MAX); +#if 0 + if constexpr(contiguous_output_stream) + { + auto bcurr{obuffer_curr(outstm)}; + auto bend{obuffer_end(outstm)}; + ::std::size_t diff{static_cast<::std::size_t>(bend-bcurr)}; + if(diff,bcurr,t)}; + if constexpr(line) + { + *it=lfch; + ++it; + } + obuffer_set_curr(outstm,it); + } + else +#endif + { + if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations && + !asan_activated) + { + char_type *bcurr{obuffer_curr(outstm)}; + char_type *bend{obuffer_end(outstm)}; + ::std::ptrdiff_t const diff(bend - bcurr); + bool smaller{static_cast<::std::ptrdiff_t>(size) < diff}; + if constexpr (minimum_buffer_output_stream_require_size_impl) + { + if (!smaller) [[unlikely]] + { + obuffer_minimum_size_flush_prepare_define(outstm); + bcurr = obuffer_curr(outstm); + } + bcurr = print_reserve_define(::fast_io::io_reserve_type, bcurr, t); + if constexpr (line) + { + *bcurr = lfch; + ++bcurr; + } + obuffer_set_curr(outstm, bcurr); + } + else + { + char_type buffer[size]; + if (!smaller) [[unlikely]] + { + bcurr = buffer; + } + bcurr = print_reserve_define(::fast_io::io_reserve_type, bcurr, t); + if constexpr (line) + { + *bcurr = lfch; + ++bcurr; + } + if (smaller) [[likely]] + { + obuffer_set_curr(outstm, bcurr); + } + else [[unlikely]] + { + ::fast_io::operations::decay::write_all_decay(outstm, buffer, bcurr); + } + } + } + else + { + char_type buffer[size]; + char_type *i{print_reserve_define(::fast_io::io_reserve_type, buffer, t)}; + if constexpr (line) + { + *i = lfch; + ++i; + } + ::fast_io::operations::decay::write_all_decay(outstm, buffer, i); + } + } + } + else if constexpr (dynamic_reserve_printable) + { + ::std::size_t size{print_reserve_size(::fast_io::io_reserve_type, t)}; + if constexpr (line) + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::ptrdiff_t>::max() - 1}; + if (size >= mx) + { + fast_terminate(); + } + ++size; + } + else + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::ptrdiff_t>::max()}; + if (mx < size) + { + fast_terminate(); + } + } +#if 0 + if constexpr(contiguous_output_stream) + { + auto bcurr{obuffer_curr(outstm)}; + auto bend{obuffer_end(outstm)}; + auto it{print_reserve_define(::fast_io::io_reserve_type,bcurr,t,size)}; + ::std::size_t diff{static_cast<::std::size_t>(bend-bcurr)}; + if(diff && + !asan_activated) + { + auto curr{obuffer_curr(outstm)}; + auto ed{obuffer_end(outstm)}; + ::std::ptrdiff_t diff(ed - curr); + auto toptr{curr}; + bool smaller{static_cast<::std::ptrdiff_t>(size) < diff}; + ::fast_io::details::local_operator_new_array_ptr newptr; + if (!smaller) +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + newptr.ptr = toptr = ::fast_io::details::allocate_iobuf_space< + char_type, + typename ::fast_io::details::local_operator_new_array_ptr::allocator_type>(size); + newptr.size = size; + } + + auto it{print_reserve_define(::fast_io::io_reserve_type, toptr, t)}; + if constexpr (line) + { + *it = lfch; + ++it; + } + if (smaller) + { + obuffer_set_curr(outstm, it); + } + else +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + ::fast_io::operations::decay::write_all_decay(outstm, toptr, it); + } + } + else + { + ::fast_io::details::local_operator_new_array_ptr newptr(size); + auto it{print_reserve_define(::fast_io::io_reserve_type, newptr.ptr, t)}; + if constexpr (line) + { + *it = lfch; + ++it; + } + ::fast_io::operations::decay::write_all_decay(outstm, newptr.ptr, it); + } + } + } + else if constexpr (reserve_scatters_printable) + { + constexpr auto sz{print_reserve_scatters_size(::fast_io::io_reserve_type)}; + static_assert(!line || sz.scatters_size != SIZE_MAX); + constexpr ::std::size_t scattersnum{sz.scatters_size + static_cast<::std::size_t>(line)}; +#if __cpp_if_consteval >= 202106L + if !consteval +#else + if (!__builtin_is_constant_evaluated()) +#endif + { + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + output>) + { + ::fast_io::io_scatter_t scattersbuffer[scattersnum]; + char_type buffer[sz.reserve_size]; + ::fast_io::io_scatter_t *ptr{ + ::fast_io::details::decay::prrsvsct_byte_common_impl(scattersbuffer, buffer, t)}; + if constexpr (line) + { + *ptr = ::fast_io::details::decay::line_scatter_common; + ++ptr; + } + ::fast_io::operations::decay::scatter_write_all_bytes_decay(outstm, scattersbuffer, static_cast<::std::size_t>(ptr - scattersbuffer)); + return; + } + } + ::fast_io::basic_io_scatter_t scattersbuffer[scattersnum]; + char_type buffer[sz.reserve_size]; + auto ptr{print_reserve_scatters_define(::fast_io::io_reserve_type>, + scattersbuffer, buffer, t) + .scatters_pos_ptr}; + if constexpr (line) + { + *ptr = ::fast_io::details::decay::line_scatter_common; + ++ptr; + } + ::fast_io::operations::decay::scatter_write_all_decay(outstm, scattersbuffer, static_cast<::std::size_t>(ptr - scattersbuffer)); + } + else if constexpr (::fast_io::transcode_imaginary_printable) + { + // todo? + } + else if constexpr (context_printable) + { + typename ::std::remove_cvref_t))>::type st; + constexpr ::std::size_t reserved_size{32u}; + constexpr ::std::ptrdiff_t reserved_size_no_line{ + static_cast<::std::ptrdiff_t>(reserved_size - static_cast<::std::size_t>(line))}; + if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations) + { + for (;;) + { + auto bcurr{obuffer_curr(outstm)}; + auto bed{obuffer_end(outstm)}; + if (bed <= bcurr) +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + if constexpr (minimum_buffer_output_stream_require_size_impl) + { + obuffer_minimum_size_flush_prepare_define(outstm); + bcurr = obuffer_curr(outstm); + bed = obuffer_end(outstm); + } + else + { + ::fast_io::operations::decay::output_stream_buffer_flush_decay(outstm); + bcurr = obuffer_curr(outstm); + bed = obuffer_end(outstm); + if (bed - bcurr < reserved_size_no_line) +#if __has_cpp_attribute(unlikely) + [[unlikely]] +#endif + { + char_type buffer[reserved_size]; + char_type *buffered{buffer + reserved_size_no_line}; + for (;;) + { + auto [resit, done] = st.print_context_define(t, buffer, buffered); + if constexpr (line) + { + if (done) + { + *resit = lfch; + ++resit; + } + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + else + { + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + } + return; + } + } + } + else + { + auto [resit, done] = st.print_context_define(t, bcurr, bed); + obuffer_set_curr(outstm, resit); + if (done) +#if __has_cpp_attribute(likely) + [[likely]] +#endif + { + if constexpr (line) + { + ::fast_io::operations::decay::char_put_decay(outstm, lfch); + } + return; + } + } + } + } + else + { + char_type buffer[reserved_size]; + char_type *buffered{buffer + reserved_size_no_line}; + for (;;) + { + auto [resit, done] = st.print_context_define(t, buffer, buffered); + if constexpr (line) + { + if (done) + { + *resit = lfch; + ++resit; + } + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + else + { + ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); + if (done) + { + return; + } + } + } + return; + } + } + else if constexpr (printable) + { + print_define(::fast_io::io_reserve_type, outstm, t); + if constexpr (line) + { + ::fast_io::operations::decay::char_put_decay(outstm, lfch); + } + } + else + { + constexpr bool no{printable}; + static_assert(no, "type not printable"); + } +} + +#if 0 +template +inline constexpr char_type* printrsvcontiguousimpl(char_type* iter,Arg arg,Args... args) +{ + if constexpr(sizeof...(Args)!=0) + { + ret = find_continuous_scatters_n(); + } + if constexpr(::fast_io::scatter_printable) + { + return {ret.position+1,ret.neededspace,ret.hasdynamicreserve}; + } + else if constexpr(::fast_io::reserve_printable) + { + constexpr + ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; + return {ret.position+1, + ::fast_io::details::add_overflow(ret.neededspace,sz), + ret.hasdynamicreserve}; + } + else if constexpr(::fast_io::dynamic_reserve_printable) + { + return {ret.position+1,ret.neededspace,true}; + } +} +#endif + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr void print_controls_line(output outstm, T t, Args... args) +{ + if constexpr (sizeof...(Args) == 0) + { + print_control_single(outstm, t); + } + else + { +#if (defined(__OPTIMIZE__) || defined(__OPTIMIZE_SIZE__)) && 0 + print_controls_line_multi_impl(outstm, t, args...); +#else + if constexpr (ln) + { + print_control_single(outstm, t); + print_controls_line(outstm, args...); + } + else + { + print_control_single(outstm, t); + (print_control(outstm, args), ...); + } +#endif + } +} + +template <::std::size_t n, ::std::integral char_type, typename T, typename... Args> +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr char_type *print_n_reserve(char_type *ptr, T t, Args... args) +{ + if constexpr (n == 0) + { + return ptr; + } + else + { + ptr = print_reserve_define(::fast_io::io_reserve_type>, ptr, t); + if constexpr (sizeof...(Args) == 0 || n < 2) + { + return ptr; + } + else + { + return print_n_reserve(ptr, args...); + } + } +} + +template <::std::size_t n, ::std::integral char_type, typename scattertype, typename T, typename... Args> +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr void print_n_scatters(basic_io_scatter_t *pscatters, +#if __has_cpp_attribute(maybe_unused) + [[maybe_unused]] +#endif + T t, +#if __has_cpp_attribute(maybe_unused) + [[maybe_unused]] +#endif + Args... args) +{ + if constexpr (n != 0) + { + if constexpr (::std::same_as<::std::remove_cvref_t, basic_io_scatter_t>) + { + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{t.base, t.len * sizeof(char_type)}; + } + else + { + *pscatters = t; + } + } + else + { + basic_io_scatter_t sct{print_scatter_define(::fast_io::io_reserve_type, t)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{sct.base, sct.len * sizeof(char_type)}; + } + else + { + *pscatters = sct; + } + } + if constexpr (1 < n) + { + ++pscatters; + return print_n_scatters(pscatters, args...); + } + } +} + +template <::std::size_t n, ::std::integral char_type, typename T, typename... Args> +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr ::std::size_t ndynamic_print_reserve_size(T t, Args... args) +{ + using nocvreft = ::std::remove_cvref_t; + if constexpr (n == 0) + { + return 0; + } + else if constexpr (n == 1) + { + if constexpr (::fast_io::dynamic_reserve_printable) + { + return print_reserve_size(::fast_io::io_reserve_type, t); + } + else + { + return 0; + } + } + else + { + if constexpr (::fast_io::dynamic_reserve_printable) + { + return ::fast_io::details::intrinsics::add_or_overflow_die( + print_reserve_size(::fast_io::io_reserve_type, t), + ::fast_io::details::decay::ndynamic_print_reserve_size(args...)); + } + else + { + return ::fast_io::details::decay::ndynamic_print_reserve_size(args...); + } + } +} + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr auto print_n_scatters_reserve(basic_io_scatter_t *pscatters, char_type *ptr, T t, + Args... args); + +template <::std::integral char_type, typename T, typename... Args> +inline constexpr bool print_next_is_reserve() noexcept +{ + using nocvreft = ::std::remove_cvref_t; + if constexpr (::fast_io::reserve_printable || + ::fast_io::dynamic_reserve_printable) + { + return true; + } + else + { + return false; + } +} + +template <::std::integral char_type> +inline constexpr bool print_next_is_reserve() noexcept +{ + return false; +} + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr auto print_n_scatters_reserve_cont(basic_io_scatter_t *pscatters, char_type *base, + char_type *ptr, T t, Args... args) +{ + if constexpr (n != 0) + { + using nocvreft = ::std::remove_cvref_t; + if constexpr (reserve_printable || dynamic_reserve_printable) + { + ptr = print_reserve_define(::fast_io::io_reserve_type, ptr, t); + if constexpr (::fast_io::details::decay::print_next_is_reserve()) + { + return ::fast_io::details::decay::print_n_scatters_reserve_cont( + pscatters, base, ptr, args...); + } + else + { + if constexpr (n == 1 && needprintlf) + { + *ptr = char_literal_v; + ++ptr; + } + ::std::size_t const sz{static_cast<::std::size_t>(ptr - base)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{base, sz * sizeof(char_type)}; + } + else + { + *pscatters = basic_io_scatter_t{base, sz}; + } + ++pscatters; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pscatters, ptr, args...); + } + } + } + else + { + ::std::size_t const sz{static_cast<::std::size_t>(ptr - base)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{base, sz * sizeof(char_type)}; + } + else + { + *pscatters = basic_io_scatter_t{base, sz}; + } + ++pscatters; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pscatters, ptr, t, args...); + } + } + } + return pscatters; +} + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr auto print_n_scatters_reserve(basic_io_scatter_t *pscatters, char_type *ptr, T t, + Args... args) +{ + if constexpr (n != 0) + { + using nocvreft = ::std::remove_cvref_t; + if constexpr (::fast_io::reserve_printable || + ::fast_io::dynamic_reserve_printable) + { + auto ptred{print_reserve_define(::fast_io::io_reserve_type, ptr, t)}; + if constexpr (sizeof...(Args) != 0 && + ::fast_io::details::decay::print_next_is_reserve()) + { + return ::fast_io::details::decay::print_n_scatters_reserve_cont( + pscatters, ptr, ptred, args...); + } + else + { + if constexpr (n == 1 && needprintlf) + { + *ptred = char_literal_v; + ++ptred; + } + ::std::size_t const sz{static_cast<::std::size_t>(ptred - ptr)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{ptr, sz * sizeof(char_type)}; + } + else + { + *pscatters = basic_io_scatter_t{ptr, sz}; + } + ++pscatters; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pscatters, ptred, args...); + } + } + } + else if constexpr (::fast_io::scatter_printable) + { + if constexpr (::std::same_as>) + { + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{t.base, t.len * sizeof(char_type)}; + } + else + { + *pscatters = t; + } + } + else + { + basic_io_scatter_t sct{print_scatter_define(::fast_io::io_reserve_type, t)}; + if constexpr (::std::same_as) + { + *pscatters = io_scatter_t{sct.base, sct.len * sizeof(char_type)}; + } + else + { + *pscatters = sct; + } + } + ++pscatters; + if constexpr (n == 1 && needprintlf) + { + *pscatters = ::fast_io::details::decay::line_scatter_common; + ++pscatters; + } + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve(pscatters, + ptr, args...); + } + } + else if constexpr (::fast_io::reserve_scatters_printable) + { + if constexpr (::std::same_as) + { + auto pit{::fast_io::details::decay::prrsvsct_byte_common_rsvsc_impl(pscatters, ptr, t)}; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pit.scatters_pos_ptr, pit.reserve_pos_ptr, args...); + } + else if constexpr (n == 1 && needprintlf) + { + *pit.scatters_pos_ptr = ::fast_io::details::decay::line_scatter_common; + ++pit.scatters_pos_ptr; + } + return pit.scatters_pos_ptr; + } + else + { + auto pit{ + print_reserve_scatters_define(::fast_io::io_reserve_type, pscatters, ptr, t)}; + if constexpr (1 < n) + { + return ::fast_io::details::decay::print_n_scatters_reserve( + pit.scatters_pos_ptr, pit.reserve_pos_ptr, args...); + } + else if constexpr (n == 1 && needprintlf) + { + *pit = ::fast_io::details::decay::line_scatter_common; + ++pit; + } + return pit; + } + } + } + return pscatters; +} + +template +inline constexpr void print_controls_impl(outputstmtype optstm, T t, Args... args) +{ + using char_type = typename outputstmtype::output_char_type; + using scatter_type = ::std::conditional_t< + ::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations, + io_scatter_t, basic_io_scatter_t>; + constexpr contiguous_scatter_result res{ + ::fast_io::details::decay::find_continuous_scatters_n()}; + if constexpr (skippings != 0) + { + print_controls_impl(optstm, args...); + } + else if constexpr (sizeof...(Args) == 0) + { + print_control_single(optstm, t); + } + else if constexpr (res.position == 0) + { + print_control_single(optstm, t); + print_controls_impl(optstm, args...); + } + else + { + if constexpr (line) + { + static_assert(res.neededscatters != SIZE_MAX); + } + static_assert(SIZE_MAX != sizeof...(Args)); + constexpr ::std::size_t n{sizeof...(Args) + static_cast<::std::size_t>(1)}; + constexpr bool needprintlf{n == res.position && line}; + if constexpr (res.hasscatters && !res.hasreserve && !res.hasdynamicreserve) + { + constexpr ::std::size_t scatterscount{res.neededscatters + static_cast<::std::size_t>(needprintlf)}; + { + scatter_type scatters[scatterscount]; + ::fast_io::details::decay::print_n_scatters(scatters, t, args...); + if constexpr (needprintlf) + { + scatters[n] = ::fast_io::details::decay::line_scatter_common< + char_type, ::std::conditional_t<::std::same_as, void, char_type>>; + } + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, scatterscount); + } + else + { + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, scatterscount); + } + } + } + else + { + constexpr ::std::size_t mxsize{ + static_cast<::std::size_t>(res.neededspace + static_cast<::std::size_t>(needprintlf))}; + if constexpr (!res.hasscatters) + { + static_assert(!needprintlf || res.neededspace != SIZE_MAX); + if constexpr (res.hasdynamicreserve) + { + ::std::size_t dynsz{ + ::fast_io::details::decay::ndynamic_print_reserve_size(t, args...)}; + ::std::size_t totalsz{::fast_io::details::intrinsics::add_or_overflow_die(mxsize, dynsz)}; + ::fast_io::details::local_operator_new_array_ptr newptr(totalsz); + char_type *buffer{newptr.ptr}; + char_type *ptred{ + ::fast_io::details::decay::print_n_reserve(buffer, t, args...)}; + if constexpr (needprintlf) + { + *ptred = ::fast_io::char_literal_v; + ++ptred; + } + ::fast_io::operations::decay::write_all_decay(optstm, buffer, ptred); + } + else if constexpr (res.hasreserve) + { + if constexpr (res.neededspace == 0) + { + if constexpr (needprintlf) + { + ::fast_io::operations::decay::char_put_decay(optstm, + ::fast_io::char_literal_v); + } + } + else + { + char_type buffer[mxsize]; + char_type *ptred{ + ::fast_io::details::decay::print_n_reserve(buffer, t, args...)}; + if constexpr (needprintlf) + { + *ptred = ::fast_io::char_literal_v; + ++ptred; + } + ::fast_io::operations::decay::write_all_decay(optstm, buffer, ptred); + } + } + } + else if constexpr (res.hasreserve && !res.hasdynamicreserve) + { + constexpr ::std::size_t scatterscount{res.neededscatters + + static_cast<::std::size_t>(line && res.position == n)}; + scatter_type scatters[scatterscount]; + char_type buffer[mxsize]; + + auto ptr{::fast_io::details::decay::print_n_scatters_reserve( + scatters, buffer, t, args...)}; + ::std::size_t diff{static_cast<::std::size_t>(ptr - scatters)}; + + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, diff); + } + else + { + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, diff); + } + } + else if constexpr (res.hasdynamicreserve) + { + constexpr ::std::size_t scatterscount{res.neededscatters + + static_cast<::std::size_t>(line && res.position == n)}; + ::std::size_t dynsz{ + ::fast_io::details::decay::ndynamic_print_reserve_size(t, args...)}; + ::std::size_t totalsz{::fast_io::details::intrinsics::add_or_overflow_die(mxsize, dynsz)}; + ::fast_io::details::local_operator_new_array_ptr newptr(totalsz); + scatter_type scatters[scatterscount]; + char_type *buffer{newptr.ptr}; + auto ptr{::fast_io::details::decay::print_n_scatters_reserve( + scatters, buffer, t, args...)}; + ::std::size_t diff{static_cast<::std::size_t>(ptr - scatters)}; + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, diff); + } + else + { + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, diff); + } + } + if constexpr (res.position != n) + { + print_controls_impl(optstm, args...); + } + } + } +} + +template +inline constexpr void print_controls_buffer_impl(outputstmtype optstm, T t, Args... args) +{ + if constexpr (skippings != 0) + { + ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + else if constexpr (sizeof...(Args) == 0) + { + print_control_single(optstm, t); + } + else + { + using char_type = typename outputstmtype::output_char_type; + static_assert(SIZE_MAX != sizeof...(Args)); + constexpr ::std::size_t n{sizeof...(Args) + static_cast<::std::size_t>(1)}; + constexpr auto scatters_result{ + ::fast_io::details::decay::find_continuous_scatters_reserve_n()}; + using scatter_type = ::std::conditional_t< + ::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations, + io_scatter_t, basic_io_scatter_t>; + if constexpr (scatters_result.position != 0) + { + if constexpr (line) + { + static_assert(scatters_result.position != SIZE_MAX); + } + constexpr bool needprintlf{n == scatters_result.position && line}; + constexpr ::std::size_t scatterscount{scatters_result.position + static_cast<::std::size_t>(needprintlf)}; + scatter_type scatters[scatterscount]; + ::fast_io::details::decay::print_n_scatters(scatters, t, args...); + if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< + outputstmtype>) + { + if constexpr (needprintlf) + { + scatters[scatterscount - 1] = ::fast_io::details::decay::line_scatter_common; + } + ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, scatterscount); + } + else + { + if constexpr (needprintlf) + { + scatters[scatterscount - 1] = ::fast_io::details::decay::line_scatter_common; + } + ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, scatterscount); + } + if constexpr (scatters_result.position != n) + { + ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + } + else + { + constexpr auto rsvresult{ + ::fast_io::details::decay::find_continuous_scatters_reserve_n()}; + if constexpr (1 < rsvresult.position) + { + constexpr bool needprintlf{n == rsvresult.position && line}; + constexpr ::std::size_t buffersize{rsvresult.neededspace + static_cast<::std::size_t>(needprintlf)}; + char_type *bcurr{obuffer_curr(optstm)}; + char_type *bend{obuffer_end(optstm)}; + ::std::ptrdiff_t const diff(bend - bcurr); + bool smaller{static_cast<::std::ptrdiff_t>(buffersize) < diff}; + if constexpr (minimum_buffer_output_stream_require_size_impl) + { + if (!smaller) [[unlikely]] + { + obuffer_minimum_size_flush_prepare_define(optstm); + bcurr = obuffer_curr(optstm); + } + bcurr = + ::fast_io::details::decay::print_n_reserve(bcurr, t, args...); + if constexpr (needprintlf) + { + *bcurr = ::fast_io::char_literal_v; + ++bcurr; + } + obuffer_set_curr(optstm, bcurr); + } + else + { + char_type buffer[buffersize]; + if (!smaller) [[unlikely]] + { + bcurr = buffer; + } + bcurr = + ::fast_io::details::decay::print_n_reserve(bcurr, t, args...); + if constexpr (needprintlf) + { + *bcurr = ::fast_io::char_literal_v; + ++bcurr; + } + if (smaller) [[likely]] + { + obuffer_set_curr(optstm, bcurr); + } + else [[unlikely]] + { + ::fast_io::operations::decay::write_all_decay(optstm, buffer, bcurr); + } + } + if constexpr (rsvresult.position != n) + { + ::fast_io::details::decay::print_controls_buffer_impl( + optstm, args...); + } + } + else + { + ::fast_io::details::decay::print_control_single(optstm, t); + if constexpr (sizeof...(args) != 0) + { + ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + } + } + } +} + +} // namespace details::decay + +namespace operations +{ + +namespace decay +{ + +template +inline constexpr decltype(auto) print_freestanding_decay(outputstmtype optstm, Args... args) +{ + if constexpr (::fast_io::operations::decay::defines::has_status_print_define) + { + return status_print_define(optstm, args...); + } + else if constexpr (sizeof...(Args) == 0) + { + if constexpr (line) + { + using char_type = typename outputstmtype::output_char_type; + return ::fast_io::operations::decay::char_put_decay(optstm, char_literal_v); + } + else + { + return; + } + } + else if constexpr (::fast_io::operations::decay::defines::has_output_or_io_stream_mutex_ref_define) + { + ::fast_io::operations::decay::stream_ref_decay_lock_guard lg{ + ::fast_io::operations::decay::output_stream_mutex_ref_decay(optstm)}; + return ::fast_io::operations::decay::print_freestanding_decay( + ::fast_io::operations::decay::output_stream_unlocked_ref_decay(optstm), args...); + } + else if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations) + { + return ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); + } + else + { + return ::fast_io::details::decay::print_controls_impl(optstm, args...); + } +} + +template +#if __has_cpp_attribute(__gnu__::__cold__) +[[__gnu__::__cold__]] +#endif +inline constexpr decltype(auto) print_freestanding_decay_cold(outputstmtype optstm, Args... args) +{ +#if !__has_cpp_attribute(__gnu__::__cold__) && __has_cpp_attribute(unlikely) + if (true) [[unlikely]] +#endif + return ::fast_io::operations::decay::print_freestanding_decay(optstm, args...); +} + +} // namespace decay + +namespace decay::defines +{ + +template +concept print_freestanding_params_okay = + ::std::integral && + ((::fast_io::printable || ::fast_io::reserve_printable || + ::fast_io::dynamic_reserve_printable || ::fast_io::scatter_printable || + ::fast_io::reserve_scatters_printable || ::fast_io::context_printable || + ::fast_io::transcode_imaginary_printable) && + ...); + +template +concept print_freestanding_okay = + ::fast_io::operations::decay::defines::print_freestanding_params_okay; + +} // namespace decay::defines + +namespace defines +{ + +template +concept print_freestanding_params_okay = ::fast_io::operations::decay::defines::print_freestanding_params_okay(::fast_io::io_print_alias(::std::declval())))...>; + +template +concept print_freestanding_okay = ::fast_io::operations::decay::defines::print_freestanding_okay< + decltype(::fast_io::operations::output_stream_ref(::std::declval())), + decltype(::fast_io::io_print_forward()))::output_char_type>(::fast_io::io_print_alias(::std::declval())))...>; + +} // namespace defines + +template +#if __has_cpp_attribute(__gnu__::__always_inline__) +[[__gnu__::__always_inline__]] +#elif __has_cpp_attribute(msvc::forceinline) +[[msvc::forceinline]] +#endif +inline constexpr void print_freestanding(output &&outstm, Args &&...args) +{ + ::fast_io::operations::decay::print_freestanding_decay( + ::fast_io::operations::output_stream_ref(outstm), + io_print_forward( + io_print_alias(args))...); +} + +} // namespace operations + +} // namespace fast_io From 6a5c6513db3f2edaa67b207309cef945ca0ff238 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 6 Apr 2025 18:13:35 -0400 Subject: [PATCH 03/16] [print] move print_freestanding to a seperate directory to revamp it --- .../operations/print_freestanding.h | 1396 ----------------- 1 file changed, 1396 deletions(-) delete mode 100644 include/fast_io_core_impl/operations/print_freestanding.h diff --git a/include/fast_io_core_impl/operations/print_freestanding.h b/include/fast_io_core_impl/operations/print_freestanding.h deleted file mode 100644 index 92633ef6e..000000000 --- a/include/fast_io_core_impl/operations/print_freestanding.h +++ /dev/null @@ -1,1396 +0,0 @@ -#pragma once - -namespace fast_io -{ - -namespace details::decay -{ - -template <::std::integral char_type, typename T = char_type> -inline constexpr basic_io_scatter_t line_scatter_common{__builtin_addressof(char_literal_v), - ::std::same_as ? sizeof(char_type) : 1}; - -struct contiguous_scatter_result -{ - ::std::size_t position{}; - ::std::size_t neededscatters{}; - ::std::size_t neededspace{}; - bool lastisreserve{}; - bool hasscatters{}; - bool hasreserve{}; - bool hasdynamicreserve{}; -}; - -template <::std::integral char_type, typename Arg, typename... Args> -inline constexpr contiguous_scatter_result find_continuous_scatters_n() -{ - contiguous_scatter_result ret{}; - if constexpr (::fast_io::scatter_printable) - { - if constexpr (sizeof...(Args) != 0) - { - ret = find_continuous_scatters_n(); - } - ++ret.position; - ret.hasscatters = true; - ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, - static_cast<::std::size_t>(1)); - } - else if constexpr (::fast_io::reserve_printable) - { - if constexpr (sizeof...(Args) != 0) - { - ret = find_continuous_scatters_n(); - } - else - { - ret.lastisreserve = true; - } - constexpr ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; - static_assert(sz != 0); - ++ret.position; - ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, - static_cast<::std::size_t>(1)); - ret.neededspace = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededspace, sz); - ret.hasreserve = true; - } - else if constexpr (::fast_io::dynamic_reserve_printable) - { - if constexpr (sizeof...(Args) != 0) - { - ret = find_continuous_scatters_n(); - } - else - { - ret.lastisreserve = true; - } - ++ret.position; - ret.neededscatters = ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, - static_cast<::std::size_t>(1)); - ret.hasdynamicreserve = true; - } - else if constexpr (::fast_io::reserve_scatters_printable) - { - if constexpr (sizeof...(Args) != 0) - { - ret = find_continuous_scatters_n(); - } - constexpr auto scatszres{print_reserve_scatters_size(::fast_io::io_reserve_type)}; - static_assert(scatszres.scatters_size != 0); - ret.hasscatters = true; - ret.hasreserve = true; - ++ret.position; - ret.neededspace = - ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededspace, scatszres.reserve_size); - ret.neededscatters = - ::fast_io::details::intrinsics::add_or_overflow_die_chain(ret.neededscatters, scatszres.scatters_size); - } - return ret; -} - -struct scatter_rsv_result -{ - ::std::size_t position{}; - ::std::size_t neededspace{}; -}; - -template -inline constexpr scatter_rsv_result find_continuous_scatters_reserve_n() -{ - if constexpr (::fast_io::reserve_printable && !findscatter) - { - constexpr ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; - if constexpr (sizeof...(Args) == 0) - { - return {1, sz}; - } - else - { - auto res{find_continuous_scatters_reserve_n()}; - return {res.position + 1, ::fast_io::details::intrinsics::add_or_overflow_die_chain(res.neededspace, sz)}; - } - } - else if constexpr (::fast_io::scatter_printable && findscatter) - { - if constexpr (sizeof...(Args) == 0) - { - return {1, 0}; - } - else - { - auto res{find_continuous_scatters_reserve_n()}; - return {res.position + 1, 0}; - } - } - else - { - return {0, 0}; - } -} - -template -inline constexpr bool minimum_buffer_output_stream_require_size_constant_impl = - (N < obuffer_minimum_size_define(::fast_io::io_reserve_type)); - -template -concept minimum_buffer_output_stream_require_size_impl = - ::fast_io::operations::decay::defines::has_obuffer_minimum_size_operations && - minimum_buffer_output_stream_require_size_constant_impl; - -template <::std::size_t sz> - requires(sz != 0) -inline constexpr void scatter_rsv_update_times(::fast_io::io_scatter_t *first, ::fast_io::io_scatter_t *last) noexcept -{ - if constexpr (sz != 1) - { - for (; first != last; ++first) - { - first->len *= sz; - } - } -} - -template <::std::integral char_type> -struct basic_reserve_scatters_define_byte_result -{ - io_scatter_t *scatters_pos_ptr; - char_type *reserve_pos_ptr; -}; - -template <::std::integral char_type, typename T> -inline ::fast_io::details::decay::basic_reserve_scatters_define_byte_result -prrsvsct_byte_common_rsvsc_impl(io_scatter_t *pscatters, char_type *buffer, T t) -{ - using basicioscattertypealiasptr -#if __has_cpp_attribute(__gnu__::__may_alias__) - [[__gnu__::__may_alias__]] -#endif - = basic_io_scatter_t *; - using scatterioscattertypealiasptr -#if __has_cpp_attribute(__gnu__::__may_alias__) - [[__gnu__::__may_alias__]] -#endif - = io_scatter_t *; - auto result{print_reserve_scatters_define(::fast_io::io_reserve_type>, - reinterpret_cast(pscatters), buffer, t)}; - scatterioscattertypealiasptr ptr{reinterpret_cast(result.scatters_pos_ptr)}; - if constexpr (sizeof(char_type) != 1) - { - scatter_rsv_update_times(pscatters, ptr); - } - return {ptr, result.reserve_pos_ptr}; -} - -template <::std::integral char_type, typename T> -inline auto prrsvsct_byte_common_impl(io_scatter_t *pscatters, char_type *buffer, T t) -{ - return ::fast_io::details::decay::prrsvsct_byte_common_rsvsc_impl(pscatters, buffer, t).scatters_pos_ptr; -} - -template - requires(::std::is_trivially_copyable_v && ::std::is_trivially_copyable_v) -inline constexpr void print_control_single(output outstm, T t) -{ - using char_type = typename output::output_char_type; - using value_type = ::std::remove_cvref_t; - constexpr bool asan_activated{::fast_io::details::asan_state::current == ::fast_io::details::asan_state::activate}; - constexpr auto lfch{char_literal_v}; - if constexpr (scatter_printable) - { -#if 0 - basic_io_scatter_t scatter; - if constexpr(::std::same_as>) - { - scatter=t; - } - else - { - scatter=print_scatter_define(::fast_io::io_reserve_type,t); - } - if constexpr(line) - { - if constexpr(contiguous_output_stream) - { - auto curr=obuffer_curr(out); - auto end=obuffer_end(out); - ::std::ptrdiff_t sz(end-curr-1); - ::std::size_t const len{scatter.len}; - if(sz(len)) - fast_terminate(); - curr=non_overlapped_copy_n(scatter.base,scatter.len,curr); - *curr=lfch; - ++curr; - obuffer_set_curr(outstm,curr); - } - else if constexpr(::fast_io::operations::decay::defines::has_obuffer_basic_operations) - { - auto curr=obuffer_curr(out); - auto end=obuffer_end(out); - ::std::size_t const len{scatter.len}; - ::std::ptrdiff_t sz(end-curr-1); - if(static_cast<::std::ptrdiff_t>(len)) - { - ::fast_io::io_scatter_t scatters[2]{ - {t.base, t.len * sizeof(char_type)}, - {__builtin_addressof(char_literal_v), sizeof(char_type)}}; - ::fast_io::operations::decay::scatter_write_all_bytes_decay(outstm, scatters, 2); - } - else - { - ::fast_io::basic_io_scatter_t scatters[2]{ - t, {__builtin_addressof(char_literal_v), 1}}; - ::fast_io::operations::decay::scatter_write_all_decay(outstm, scatters, 2); - } - } - else - { - ::fast_io::operations::decay::write_all_decay(outstm, t.base, t.base + t.len); - } - } - else if constexpr (reserve_printable) - { - constexpr ::std::size_t real_size{print_reserve_size(::fast_io::io_reserve_type)}; - constexpr ::std::size_t size{real_size + static_cast<::std::size_t>(line)}; - static_assert(real_size < PTRDIFF_MAX); -#if 0 - if constexpr(contiguous_output_stream) - { - auto bcurr{obuffer_curr(outstm)}; - auto bend{obuffer_end(outstm)}; - ::std::size_t diff{static_cast<::std::size_t>(bend-bcurr)}; - if(diff,bcurr,t)}; - if constexpr(line) - { - *it=lfch; - ++it; - } - obuffer_set_curr(outstm,it); - } - else -#endif - { - if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations && - !asan_activated) - { - char_type *bcurr{obuffer_curr(outstm)}; - char_type *bend{obuffer_end(outstm)}; - ::std::ptrdiff_t const diff(bend - bcurr); - bool smaller{static_cast<::std::ptrdiff_t>(size) < diff}; - if constexpr (minimum_buffer_output_stream_require_size_impl) - { - if (!smaller) [[unlikely]] - { - obuffer_minimum_size_flush_prepare_define(outstm); - bcurr = obuffer_curr(outstm); - } - bcurr = print_reserve_define(::fast_io::io_reserve_type, bcurr, t); - if constexpr (line) - { - *bcurr = lfch; - ++bcurr; - } - obuffer_set_curr(outstm, bcurr); - } - else - { - char_type buffer[size]; - if (!smaller) [[unlikely]] - { - bcurr = buffer; - } - bcurr = print_reserve_define(::fast_io::io_reserve_type, bcurr, t); - if constexpr (line) - { - *bcurr = lfch; - ++bcurr; - } - if (smaller) [[likely]] - { - obuffer_set_curr(outstm, bcurr); - } - else [[unlikely]] - { - ::fast_io::operations::decay::write_all_decay(outstm, buffer, bcurr); - } - } - } - else - { - char_type buffer[size]; - char_type *i{print_reserve_define(::fast_io::io_reserve_type, buffer, t)}; - if constexpr (line) - { - *i = lfch; - ++i; - } - ::fast_io::operations::decay::write_all_decay(outstm, buffer, i); - } - } - } - else if constexpr (dynamic_reserve_printable) - { - ::std::size_t size{print_reserve_size(::fast_io::io_reserve_type, t)}; - if constexpr (line) - { - constexpr ::std::size_t mx{::std::numeric_limits<::std::ptrdiff_t>::max() - 1}; - if (size >= mx) - { - fast_terminate(); - } - ++size; - } - else - { - constexpr ::std::size_t mx{::std::numeric_limits<::std::ptrdiff_t>::max()}; - if (mx < size) - { - fast_terminate(); - } - } -#if 0 - if constexpr(contiguous_output_stream) - { - auto bcurr{obuffer_curr(outstm)}; - auto bend{obuffer_end(outstm)}; - auto it{print_reserve_define(::fast_io::io_reserve_type,bcurr,t,size)}; - ::std::size_t diff{static_cast<::std::size_t>(bend-bcurr)}; - if(diff && - !asan_activated) - { - auto curr{obuffer_curr(outstm)}; - auto ed{obuffer_end(outstm)}; - ::std::ptrdiff_t diff(ed - curr); - auto toptr{curr}; - bool smaller{static_cast<::std::ptrdiff_t>(size) < diff}; - ::fast_io::details::local_operator_new_array_ptr newptr; - if (!smaller) -#if __has_cpp_attribute(unlikely) - [[unlikely]] -#endif - { - newptr.ptr = toptr = ::fast_io::details::allocate_iobuf_space< - char_type, - typename ::fast_io::details::local_operator_new_array_ptr::allocator_type>(size); - newptr.size = size; - } - - auto it{print_reserve_define(::fast_io::io_reserve_type, toptr, t)}; - if constexpr (line) - { - *it = lfch; - ++it; - } - if (smaller) - { - obuffer_set_curr(outstm, it); - } - else -#if __has_cpp_attribute(unlikely) - [[unlikely]] -#endif - { - ::fast_io::operations::decay::write_all_decay(outstm, toptr, it); - } - } - else - { - ::fast_io::details::local_operator_new_array_ptr newptr(size); - auto it{print_reserve_define(::fast_io::io_reserve_type, newptr.ptr, t)}; - if constexpr (line) - { - *it = lfch; - ++it; - } - ::fast_io::operations::decay::write_all_decay(outstm, newptr.ptr, it); - } - } - } - else if constexpr (reserve_scatters_printable) - { - constexpr auto sz{print_reserve_scatters_size(::fast_io::io_reserve_type)}; - static_assert(!line || sz.scatters_size != SIZE_MAX); - constexpr ::std::size_t scattersnum{sz.scatters_size + static_cast<::std::size_t>(line)}; -#if __cpp_if_consteval >= 202106L - if !consteval -#else - if (!__builtin_is_constant_evaluated()) -#endif - { - if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< - output>) - { - ::fast_io::io_scatter_t scattersbuffer[scattersnum]; - char_type buffer[sz.reserve_size]; - ::fast_io::io_scatter_t *ptr{ - ::fast_io::details::decay::prrsvsct_byte_common_impl(scattersbuffer, buffer, t)}; - if constexpr (line) - { - *ptr = ::fast_io::details::decay::line_scatter_common; - ++ptr; - } - ::fast_io::operations::decay::scatter_write_all_bytes_decay(outstm, scattersbuffer, static_cast<::std::size_t>(ptr - scattersbuffer)); - return; - } - } - ::fast_io::basic_io_scatter_t scattersbuffer[scattersnum]; - char_type buffer[sz.reserve_size]; - auto ptr{print_reserve_scatters_define(::fast_io::io_reserve_type>, - scattersbuffer, buffer, t) - .scatters_pos_ptr}; - if constexpr (line) - { - *ptr = ::fast_io::details::decay::line_scatter_common; - ++ptr; - } - ::fast_io::operations::decay::scatter_write_all_decay(outstm, scattersbuffer, static_cast<::std::size_t>(ptr - scattersbuffer)); - } - else if constexpr (::fast_io::transcode_imaginary_printable) - { - // todo? - } - else if constexpr (context_printable) - { - typename ::std::remove_cvref_t))>::type st; - constexpr ::std::size_t reserved_size{32u}; - constexpr ::std::ptrdiff_t reserved_size_no_line{ - static_cast<::std::ptrdiff_t>(reserved_size - static_cast<::std::size_t>(line))}; - if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations) - { - for (;;) - { - auto bcurr{obuffer_curr(outstm)}; - auto bed{obuffer_end(outstm)}; - if (bed <= bcurr) -#if __has_cpp_attribute(unlikely) - [[unlikely]] -#endif - { - if constexpr (minimum_buffer_output_stream_require_size_impl) - { - obuffer_minimum_size_flush_prepare_define(outstm); - bcurr = obuffer_curr(outstm); - bed = obuffer_end(outstm); - } - else - { - ::fast_io::operations::decay::output_stream_buffer_flush_decay(outstm); - bcurr = obuffer_curr(outstm); - bed = obuffer_end(outstm); - if (bed - bcurr < reserved_size_no_line) -#if __has_cpp_attribute(unlikely) - [[unlikely]] -#endif - { - char_type buffer[reserved_size]; - char_type *buffered{buffer + reserved_size_no_line}; - for (;;) - { - auto [resit, done] = st.print_context_define(t, buffer, buffered); - if constexpr (line) - { - if (done) - { - *resit = lfch; - ++resit; - } - ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); - if (done) - { - return; - } - } - else - { - ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); - if (done) - { - return; - } - } - } - return; - } - } - } - else - { - auto [resit, done] = st.print_context_define(t, bcurr, bed); - obuffer_set_curr(outstm, resit); - if (done) -#if __has_cpp_attribute(likely) - [[likely]] -#endif - { - if constexpr (line) - { - ::fast_io::operations::decay::char_put_decay(outstm, lfch); - } - return; - } - } - } - } - else - { - char_type buffer[reserved_size]; - char_type *buffered{buffer + reserved_size_no_line}; - for (;;) - { - auto [resit, done] = st.print_context_define(t, buffer, buffered); - if constexpr (line) - { - if (done) - { - *resit = lfch; - ++resit; - } - ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); - if (done) - { - return; - } - } - else - { - ::fast_io::operations::decay::write_all_decay(outstm, buffer, resit); - if (done) - { - return; - } - } - } - return; - } - } - else if constexpr (printable) - { - print_define(::fast_io::io_reserve_type, outstm, t); - if constexpr (line) - { - ::fast_io::operations::decay::char_put_decay(outstm, lfch); - } - } - else - { - constexpr bool no{printable}; - static_assert(no, "type not printable"); - } -} - -#if 0 -template -inline constexpr char_type* printrsvcontiguousimpl(char_type* iter,Arg arg,Args... args) -{ - if constexpr(sizeof...(Args)!=0) - { - ret = find_continuous_scatters_n(); - } - if constexpr(::fast_io::scatter_printable) - { - return {ret.position+1,ret.neededspace,ret.hasdynamicreserve}; - } - else if constexpr(::fast_io::reserve_printable) - { - constexpr - ::std::size_t sz{print_reserve_size(::fast_io::io_reserve_type)}; - return {ret.position+1, - ::fast_io::details::add_overflow(ret.neededspace,sz), - ret.hasdynamicreserve}; - } - else if constexpr(::fast_io::dynamic_reserve_printable) - { - return {ret.position+1,ret.neededspace,true}; - } -} -#endif - -template -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr void print_controls_line(output outstm, T t, Args... args) -{ - if constexpr (sizeof...(Args) == 0) - { - print_control_single(outstm, t); - } - else - { -#if (defined(__OPTIMIZE__) || defined(__OPTIMIZE_SIZE__)) && 0 - print_controls_line_multi_impl(outstm, t, args...); -#else - if constexpr (ln) - { - print_control_single(outstm, t); - print_controls_line(outstm, args...); - } - else - { - print_control_single(outstm, t); - (print_control(outstm, args), ...); - } -#endif - } -} - -template <::std::size_t n, ::std::integral char_type, typename T, typename... Args> -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr char_type *print_n_reserve(char_type *ptr, T t, Args... args) -{ - if constexpr (n == 0) - { - return ptr; - } - else - { - ptr = print_reserve_define(::fast_io::io_reserve_type>, ptr, t); - if constexpr (sizeof...(Args) == 0 || n < 2) - { - return ptr; - } - else - { - return print_n_reserve(ptr, args...); - } - } -} - -template <::std::size_t n, ::std::integral char_type, typename scattertype, typename T, typename... Args> -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr void print_n_scatters(basic_io_scatter_t *pscatters, -#if __has_cpp_attribute(maybe_unused) - [[maybe_unused]] -#endif - T t, -#if __has_cpp_attribute(maybe_unused) - [[maybe_unused]] -#endif - Args... args) -{ - if constexpr (n != 0) - { - if constexpr (::std::same_as<::std::remove_cvref_t, basic_io_scatter_t>) - { - if constexpr (::std::same_as) - { - *pscatters = io_scatter_t{t.base, t.len * sizeof(char_type)}; - } - else - { - *pscatters = t; - } - } - else - { - basic_io_scatter_t sct{print_scatter_define(::fast_io::io_reserve_type, t)}; - if constexpr (::std::same_as) - { - *pscatters = io_scatter_t{sct.base, sct.len * sizeof(char_type)}; - } - else - { - *pscatters = sct; - } - } - if constexpr (1 < n) - { - ++pscatters; - return print_n_scatters(pscatters, args...); - } - } -} - -template <::std::size_t n, ::std::integral char_type, typename T, typename... Args> -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr ::std::size_t ndynamic_print_reserve_size(T t, Args... args) -{ - using nocvreft = ::std::remove_cvref_t; - if constexpr (n == 0) - { - return 0; - } - else if constexpr (n == 1) - { - if constexpr (::fast_io::dynamic_reserve_printable) - { - return print_reserve_size(::fast_io::io_reserve_type, t); - } - else - { - return 0; - } - } - else - { - if constexpr (::fast_io::dynamic_reserve_printable) - { - return ::fast_io::details::intrinsics::add_or_overflow_die( - print_reserve_size(::fast_io::io_reserve_type, t), - ::fast_io::details::decay::ndynamic_print_reserve_size(args...)); - } - else - { - return ::fast_io::details::decay::ndynamic_print_reserve_size(args...); - } - } -} - -template -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr auto print_n_scatters_reserve(basic_io_scatter_t *pscatters, char_type *ptr, T t, - Args... args); - -template <::std::integral char_type, typename T, typename... Args> -inline constexpr bool print_next_is_reserve() noexcept -{ - using nocvreft = ::std::remove_cvref_t; - if constexpr (::fast_io::reserve_printable || - ::fast_io::dynamic_reserve_printable) - { - return true; - } - else - { - return false; - } -} - -template <::std::integral char_type> -inline constexpr bool print_next_is_reserve() noexcept -{ - return false; -} - -template -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr auto print_n_scatters_reserve_cont(basic_io_scatter_t *pscatters, char_type *base, - char_type *ptr, T t, Args... args) -{ - if constexpr (n != 0) - { - using nocvreft = ::std::remove_cvref_t; - if constexpr (reserve_printable || dynamic_reserve_printable) - { - ptr = print_reserve_define(::fast_io::io_reserve_type, ptr, t); - if constexpr (::fast_io::details::decay::print_next_is_reserve()) - { - return ::fast_io::details::decay::print_n_scatters_reserve_cont( - pscatters, base, ptr, args...); - } - else - { - if constexpr (n == 1 && needprintlf) - { - *ptr = char_literal_v; - ++ptr; - } - ::std::size_t const sz{static_cast<::std::size_t>(ptr - base)}; - if constexpr (::std::same_as) - { - *pscatters = io_scatter_t{base, sz * sizeof(char_type)}; - } - else - { - *pscatters = basic_io_scatter_t{base, sz}; - } - ++pscatters; - if constexpr (1 < n) - { - return ::fast_io::details::decay::print_n_scatters_reserve( - pscatters, ptr, args...); - } - } - } - else - { - ::std::size_t const sz{static_cast<::std::size_t>(ptr - base)}; - if constexpr (::std::same_as) - { - *pscatters = io_scatter_t{base, sz * sizeof(char_type)}; - } - else - { - *pscatters = basic_io_scatter_t{base, sz}; - } - ++pscatters; - if constexpr (1 < n) - { - return ::fast_io::details::decay::print_n_scatters_reserve( - pscatters, ptr, t, args...); - } - } - } - return pscatters; -} - -template -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr auto print_n_scatters_reserve(basic_io_scatter_t *pscatters, char_type *ptr, T t, - Args... args) -{ - if constexpr (n != 0) - { - using nocvreft = ::std::remove_cvref_t; - if constexpr (::fast_io::reserve_printable || - ::fast_io::dynamic_reserve_printable) - { - auto ptred{print_reserve_define(::fast_io::io_reserve_type, ptr, t)}; - if constexpr (sizeof...(Args) != 0 && - ::fast_io::details::decay::print_next_is_reserve()) - { - return ::fast_io::details::decay::print_n_scatters_reserve_cont( - pscatters, ptr, ptred, args...); - } - else - { - if constexpr (n == 1 && needprintlf) - { - *ptred = char_literal_v; - ++ptred; - } - ::std::size_t const sz{static_cast<::std::size_t>(ptred - ptr)}; - if constexpr (::std::same_as) - { - *pscatters = io_scatter_t{ptr, sz * sizeof(char_type)}; - } - else - { - *pscatters = basic_io_scatter_t{ptr, sz}; - } - ++pscatters; - if constexpr (1 < n) - { - return ::fast_io::details::decay::print_n_scatters_reserve( - pscatters, ptred, args...); - } - } - } - else if constexpr (::fast_io::scatter_printable) - { - if constexpr (::std::same_as>) - { - if constexpr (::std::same_as) - { - *pscatters = io_scatter_t{t.base, t.len * sizeof(char_type)}; - } - else - { - *pscatters = t; - } - } - else - { - basic_io_scatter_t sct{print_scatter_define(::fast_io::io_reserve_type, t)}; - if constexpr (::std::same_as) - { - *pscatters = io_scatter_t{sct.base, sct.len * sizeof(char_type)}; - } - else - { - *pscatters = sct; - } - } - ++pscatters; - if constexpr (n == 1 && needprintlf) - { - *pscatters = ::fast_io::details::decay::line_scatter_common; - ++pscatters; - } - if constexpr (1 < n) - { - return ::fast_io::details::decay::print_n_scatters_reserve(pscatters, - ptr, args...); - } - } - else if constexpr (::fast_io::reserve_scatters_printable) - { - if constexpr (::std::same_as) - { - auto pit{::fast_io::details::decay::prrsvsct_byte_common_rsvsc_impl(pscatters, ptr, t)}; - if constexpr (1 < n) - { - return ::fast_io::details::decay::print_n_scatters_reserve( - pit.scatters_pos_ptr, pit.reserve_pos_ptr, args...); - } - else if constexpr (n == 1 && needprintlf) - { - *pit.scatters_pos_ptr = ::fast_io::details::decay::line_scatter_common; - ++pit.scatters_pos_ptr; - } - return pit.scatters_pos_ptr; - } - else - { - auto pit{ - print_reserve_scatters_define(::fast_io::io_reserve_type, pscatters, ptr, t)}; - if constexpr (1 < n) - { - return ::fast_io::details::decay::print_n_scatters_reserve( - pit.scatters_pos_ptr, pit.reserve_pos_ptr, args...); - } - else if constexpr (n == 1 && needprintlf) - { - *pit = ::fast_io::details::decay::line_scatter_common; - ++pit; - } - return pit; - } - } - } - return pscatters; -} - -template -inline constexpr void print_controls_impl(outputstmtype optstm, T t, Args... args) -{ - using char_type = typename outputstmtype::output_char_type; - using scatter_type = ::std::conditional_t< - ::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations, - io_scatter_t, basic_io_scatter_t>; - constexpr contiguous_scatter_result res{ - ::fast_io::details::decay::find_continuous_scatters_n()}; - if constexpr (skippings != 0) - { - print_controls_impl(optstm, args...); - } - else if constexpr (sizeof...(Args) == 0) - { - print_control_single(optstm, t); - } - else if constexpr (res.position == 0) - { - print_control_single(optstm, t); - print_controls_impl(optstm, args...); - } - else - { - if constexpr (line) - { - static_assert(res.neededscatters != SIZE_MAX); - } - static_assert(SIZE_MAX != sizeof...(Args)); - constexpr ::std::size_t n{sizeof...(Args) + static_cast<::std::size_t>(1)}; - constexpr bool needprintlf{n == res.position && line}; - if constexpr (res.hasscatters && !res.hasreserve && !res.hasdynamicreserve) - { - constexpr ::std::size_t scatterscount{res.neededscatters + static_cast<::std::size_t>(needprintlf)}; - { - scatter_type scatters[scatterscount]; - ::fast_io::details::decay::print_n_scatters(scatters, t, args...); - if constexpr (needprintlf) - { - scatters[n] = ::fast_io::details::decay::line_scatter_common< - char_type, ::std::conditional_t<::std::same_as, void, char_type>>; - } - if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< - outputstmtype>) - { - ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, scatterscount); - } - else - { - ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, scatterscount); - } - } - } - else - { - constexpr ::std::size_t mxsize{ - static_cast<::std::size_t>(res.neededspace + static_cast<::std::size_t>(needprintlf))}; - if constexpr (!res.hasscatters) - { - static_assert(!needprintlf || res.neededspace != SIZE_MAX); - if constexpr (res.hasdynamicreserve) - { - ::std::size_t dynsz{ - ::fast_io::details::decay::ndynamic_print_reserve_size(t, args...)}; - ::std::size_t totalsz{::fast_io::details::intrinsics::add_or_overflow_die(mxsize, dynsz)}; - ::fast_io::details::local_operator_new_array_ptr newptr(totalsz); - char_type *buffer{newptr.ptr}; - char_type *ptred{ - ::fast_io::details::decay::print_n_reserve(buffer, t, args...)}; - if constexpr (needprintlf) - { - *ptred = ::fast_io::char_literal_v; - ++ptred; - } - ::fast_io::operations::decay::write_all_decay(optstm, buffer, ptred); - } - else if constexpr (res.hasreserve) - { - if constexpr (res.neededspace == 0) - { - if constexpr (needprintlf) - { - ::fast_io::operations::decay::char_put_decay(optstm, - ::fast_io::char_literal_v); - } - } - else - { - char_type buffer[mxsize]; - char_type *ptred{ - ::fast_io::details::decay::print_n_reserve(buffer, t, args...)}; - if constexpr (needprintlf) - { - *ptred = ::fast_io::char_literal_v; - ++ptred; - } - ::fast_io::operations::decay::write_all_decay(optstm, buffer, ptred); - } - } - } - else if constexpr (res.hasreserve && !res.hasdynamicreserve) - { - constexpr ::std::size_t scatterscount{res.neededscatters + - static_cast<::std::size_t>(line && res.position == n)}; - scatter_type scatters[scatterscount]; - char_type buffer[mxsize]; - - auto ptr{::fast_io::details::decay::print_n_scatters_reserve( - scatters, buffer, t, args...)}; - ::std::size_t diff{static_cast<::std::size_t>(ptr - scatters)}; - - if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< - outputstmtype>) - { - ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, diff); - } - else - { - ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, diff); - } - } - else if constexpr (res.hasdynamicreserve) - { - constexpr ::std::size_t scatterscount{res.neededscatters + - static_cast<::std::size_t>(line && res.position == n)}; - ::std::size_t dynsz{ - ::fast_io::details::decay::ndynamic_print_reserve_size(t, args...)}; - ::std::size_t totalsz{::fast_io::details::intrinsics::add_or_overflow_die(mxsize, dynsz)}; - ::fast_io::details::local_operator_new_array_ptr newptr(totalsz); - scatter_type scatters[scatterscount]; - char_type *buffer{newptr.ptr}; - auto ptr{::fast_io::details::decay::print_n_scatters_reserve( - scatters, buffer, t, args...)}; - ::std::size_t diff{static_cast<::std::size_t>(ptr - scatters)}; - if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< - outputstmtype>) - { - ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, diff); - } - else - { - ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, diff); - } - } - if constexpr (res.position != n) - { - print_controls_impl(optstm, args...); - } - } - } -} - -template -inline constexpr void print_controls_buffer_impl(outputstmtype optstm, T t, Args... args) -{ - if constexpr (skippings != 0) - { - ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); - } - else if constexpr (sizeof...(Args) == 0) - { - print_control_single(optstm, t); - } - else - { - using char_type = typename outputstmtype::output_char_type; - static_assert(SIZE_MAX != sizeof...(Args)); - constexpr ::std::size_t n{sizeof...(Args) + static_cast<::std::size_t>(1)}; - constexpr auto scatters_result{ - ::fast_io::details::decay::find_continuous_scatters_reserve_n()}; - using scatter_type = ::std::conditional_t< - ::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations, - io_scatter_t, basic_io_scatter_t>; - if constexpr (scatters_result.position != 0) - { - if constexpr (line) - { - static_assert(scatters_result.position != SIZE_MAX); - } - constexpr bool needprintlf{n == scatters_result.position && line}; - constexpr ::std::size_t scatterscount{scatters_result.position + static_cast<::std::size_t>(needprintlf)}; - scatter_type scatters[scatterscount]; - ::fast_io::details::decay::print_n_scatters(scatters, t, args...); - if constexpr (::fast_io::operations::decay::defines::has_any_of_write_or_seek_pwrite_bytes_operations< - outputstmtype>) - { - if constexpr (needprintlf) - { - scatters[scatterscount - 1] = ::fast_io::details::decay::line_scatter_common; - } - ::fast_io::operations::decay::scatter_write_all_bytes_decay(optstm, scatters, scatterscount); - } - else - { - if constexpr (needprintlf) - { - scatters[scatterscount - 1] = ::fast_io::details::decay::line_scatter_common; - } - ::fast_io::operations::decay::scatter_write_all_decay(optstm, scatters, scatterscount); - } - if constexpr (scatters_result.position != n) - { - ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); - } - } - else - { - constexpr auto rsvresult{ - ::fast_io::details::decay::find_continuous_scatters_reserve_n()}; - if constexpr (1 < rsvresult.position) - { - constexpr bool needprintlf{n == rsvresult.position && line}; - constexpr ::std::size_t buffersize{rsvresult.neededspace + static_cast<::std::size_t>(needprintlf)}; - char_type *bcurr{obuffer_curr(optstm)}; - char_type *bend{obuffer_end(optstm)}; - ::std::ptrdiff_t const diff(bend - bcurr); - bool smaller{static_cast<::std::ptrdiff_t>(buffersize) < diff}; - if constexpr (minimum_buffer_output_stream_require_size_impl) - { - if (!smaller) [[unlikely]] - { - obuffer_minimum_size_flush_prepare_define(optstm); - bcurr = obuffer_curr(optstm); - } - bcurr = - ::fast_io::details::decay::print_n_reserve(bcurr, t, args...); - if constexpr (needprintlf) - { - *bcurr = ::fast_io::char_literal_v; - ++bcurr; - } - obuffer_set_curr(optstm, bcurr); - } - else - { - char_type buffer[buffersize]; - if (!smaller) [[unlikely]] - { - bcurr = buffer; - } - bcurr = - ::fast_io::details::decay::print_n_reserve(bcurr, t, args...); - if constexpr (needprintlf) - { - *bcurr = ::fast_io::char_literal_v; - ++bcurr; - } - if (smaller) [[likely]] - { - obuffer_set_curr(optstm, bcurr); - } - else [[unlikely]] - { - ::fast_io::operations::decay::write_all_decay(optstm, buffer, bcurr); - } - } - if constexpr (rsvresult.position != n) - { - ::fast_io::details::decay::print_controls_buffer_impl( - optstm, args...); - } - } - else - { - ::fast_io::details::decay::print_control_single(optstm, t); - if constexpr (sizeof...(args) != 0) - { - ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); - } - } - } - } -} - -} // namespace details::decay - -namespace operations -{ - -namespace decay -{ - -template -inline constexpr decltype(auto) print_freestanding_decay(outputstmtype optstm, Args... args) -{ - if constexpr (::fast_io::operations::decay::defines::has_status_print_define) - { - return status_print_define(optstm, args...); - } - else if constexpr (sizeof...(Args) == 0) - { - if constexpr (line) - { - using char_type = typename outputstmtype::output_char_type; - return ::fast_io::operations::decay::char_put_decay(optstm, char_literal_v); - } - else - { - return; - } - } - else if constexpr (::fast_io::operations::decay::defines::has_output_or_io_stream_mutex_ref_define) - { - ::fast_io::operations::decay::stream_ref_decay_lock_guard lg{ - ::fast_io::operations::decay::output_stream_mutex_ref_decay(optstm)}; - return ::fast_io::operations::decay::print_freestanding_decay( - ::fast_io::operations::decay::output_stream_unlocked_ref_decay(optstm), args...); - } - else if constexpr (::fast_io::operations::decay::defines::has_obuffer_basic_operations) - { - return ::fast_io::details::decay::print_controls_buffer_impl(optstm, args...); - } - else - { - return ::fast_io::details::decay::print_controls_impl(optstm, args...); - } -} - -template -#if __has_cpp_attribute(__gnu__::__cold__) -[[__gnu__::__cold__]] -#endif -inline constexpr decltype(auto) print_freestanding_decay_cold(outputstmtype optstm, Args... args) -{ -#if !__has_cpp_attribute(__gnu__::__cold__) && __has_cpp_attribute(unlikely) - if (true) [[unlikely]] -#endif - return ::fast_io::operations::decay::print_freestanding_decay(optstm, args...); -} - -} // namespace decay - -namespace decay::defines -{ - -template -concept print_freestanding_params_okay = - ::std::integral && - ((::fast_io::printable || ::fast_io::reserve_printable || - ::fast_io::dynamic_reserve_printable || ::fast_io::scatter_printable || - ::fast_io::reserve_scatters_printable || ::fast_io::context_printable || - ::fast_io::transcode_imaginary_printable) && - ...); - -template -concept print_freestanding_okay = - ::fast_io::operations::decay::defines::print_freestanding_params_okay; - -} // namespace decay::defines - -namespace defines -{ - -template -concept print_freestanding_params_okay = ::fast_io::operations::decay::defines::print_freestanding_params_okay(::fast_io::io_print_alias(::std::declval())))...>; - -template -concept print_freestanding_okay = ::fast_io::operations::decay::defines::print_freestanding_okay< - decltype(::fast_io::operations::output_stream_ref(::std::declval())), - decltype(::fast_io::io_print_forward()))::output_char_type>(::fast_io::io_print_alias(::std::declval())))...>; - -} // namespace defines - -template -#if __has_cpp_attribute(__gnu__::__always_inline__) -[[__gnu__::__always_inline__]] -#elif __has_cpp_attribute(msvc::forceinline) -[[msvc::forceinline]] -#endif -inline constexpr void print_freestanding(output &&outstm, Args &&...args) -{ - ::fast_io::operations::decay::print_freestanding_decay( - ::fast_io::operations::output_stream_ref(outstm), - io_print_forward( - io_print_alias(args))...); -} - -} // namespace operations - -} // namespace fast_io From 86f120570bb28b9f6cb8726d60c2a35c595224c9 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 13 May 2025 17:03:23 +0800 Subject: [PATCH 04/16] special --- examples/0014.random/specialpassword.cc | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 examples/0014.random/specialpassword.cc diff --git a/examples/0014.random/specialpassword.cc b/examples/0014.random/specialpassword.cc new file mode 100644 index 000000000..9fd5534ad --- /dev/null +++ b/examples/0014.random/specialpassword.cc @@ -0,0 +1,49 @@ +#include +#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"specialpassword.txt"); + fast_io::ibuf_white_hole_engine eng; + std::uniform_int_distribution ud(0, 77); // Expanded range for special characters + std::uniform_int_distribution rlen(8, 20); + + // Use constexpr fast_io::array for compile-time safety + constexpr fast_io::array special_chars{u8'!', u8'@', u8'#', u8'$', u8'%', u8'^', u8'&', u8'*', + u8'(', u8')', u8'-', u8'_', u8'=', u8'+', u8'[', u8']'}; + + for (std::size_t i{}; i != n; ++i) + { + for (std::size_t j{}, s(rlen(eng)); j != s; ++j) + { + char8_t ch(static_cast(ud(eng))); + if (ch < 10u) + { + ch += u8'0'; + } + else if (ch < 36u) + { + ch = ch - 10u + u8'a'; + } + else if (ch < 62u) + { + ch = ch - 36u + u8'A'; + } + else + { + ch = special_chars[ch - 62u]; // Bounds-checked access using fast_io::array + } + print(obf, fast_io::mnp::chvw(ch)); + } + println(obf); + } +} From 6fa8b501fd3edff22041980c690308e204a1413b Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 21 May 2025 19:50:18 +0800 Subject: [PATCH 05/16] add license and license-zhCN.txt for anti-tivoization --- license-zhCN.txt | 36 ++++++++++++++++++++++++++++++++++++ license.txt | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 license-zhCN.txt diff --git a/license-zhCN.txt b/license-zhCN.txt new file mode 100644 index 000000000..85944a587 --- /dev/null +++ b/license-zhCN.txt @@ -0,0 +1,36 @@ +反提沃化许可证 (ATL) v1.0 +版权所有 © cppfastio 2025 + +1. 许可授予 +本软件根据 反提沃化许可证 (ATL) 提供,允许 商业使用,并且 无需公开源代码,除非满足第 2 条的特定条件。 + +2. 提沃化设备限制 +任何使用本软件的设备 必须 满足以下条件: + +如果设备包含 应用商店,则 必须 允许用户安装修改后的软件版本,不得施加限制。 + +设备制造商 不得 采用加密签名、硬件验证或其他技术手段阻止用户修改和重新安装本软件。 + +若设备 不符合 以上条件,则该软件 必须 采用 GPLv3 许可证,确保开源原则得到完全遵守。 + +3. 跨平台技术优先使用 +当 PWA(渐进式网络应用) 或 Wine 等跨平台技术可以使用时,开发者和厂商 应优先考虑 采用这些技术,以保持软件的开放性和可移植性。 + +如果某平台 故意破坏开放互联网的使用(例如通过封闭框架限制 渐进式网络应用 (PWA) 的运行),则该平台上的软件 必须 采用 GPLv3 许可证,确保用户拥有完整的修改和安装权利。 + +4. 例外情况 +以下类别的设备 可免除 第 2 条和第 3 条的限制,可使用本软件而无需满足修改要求: + +医疗设备:用于生命支持、医疗诊断或其他关键医疗用途的设备。 + +汽车系统:用于自动驾驶、车辆控制或安全关键功能的软件。 + +5. 执行与非强制性行动 +版权持有人 保留执行本许可证的权利,但 无义务 进行强制执行。 + +可针对 违反第 2 条或第 3 条的实体 采取执行行动,尤其是涉及 提沃化设备 或 故意破坏开放互联网 的情况。 + +本许可证 不受任何政府管辖,包括但不限于 美国政府。 + +6. 免责声明 +本软件按 “现状” 提供,不提供任何明示或暗示的保证。开发者 不承担 因使用本软件而导致的任何损害或责任。 \ No newline at end of file diff --git a/license.txt b/license.txt index b2e80c3cf..262f4726c 100644 --- a/license.txt +++ b/license.txt @@ -1,8 +1,36 @@ -The MIT License (MIT) -Copyright © 2022 cqwrteur +Anti-Tivo License (ATL) v1.0 +Copyright © cppfastio 2025 -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +1. License Grant +This software is provided under the Anti-Tivo License (ATL), allowing unrestricted commercial use without requiring source code disclosure, except under specific conditions outlined in Section 2. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +2. Restrictions on Tivoized Hardware +Any device using this software must comply with the following: -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +If the device includes an app store, it must allow users to install modified versions of this software without restrictions. + +Manufacturers must not use cryptographic signatures, hardware verification, or other technical measures to prevent users from modifying and reinstalling the software. + +If a device does not meet these conditions, the software must be licensed under GPLv3, ensuring full compliance with open-source principles. + +3. Prioritization of Cross-Platform Technologies +When PWA (Progressive Web Applications) or Wine and other cross-platform technologies are available, developers and vendors should prioritize their use to maintain openness and portability. + +If a platform deliberately undermines open internet access (e.g., restricting the use of Progressive Web Applications (PWA) through a closed framework), then all software on that platform must be licensed under GPLv3, ensuring users have full modification and installation rights. + +4. Exceptions +The following categories of devices are exempt from Sections 2 and 3 and may use this software without modification requirements: + +Medical Equipment: Devices used for life support, diagnostics, or critical healthcare applications. + +Automotive Systems: Software used in autonomous driving, vehicle control, or safety-critical functions. + +5. Enforcement & Non-Mandatory Action +The copyright holder reserves the right to enforce this license but is not obligated to do so. + +Enforcement actions may be taken against entities violating Section 2 or Section 3, particularly those engaging in Tivoization or deliberate internet restrictions. + +This license is not subject to any government control, including but not limited to the United States government. + +6. Liability Disclaimer +This software is provided "as is", without warranties of any kind. The author is not liable for any damages resulting from its use. From 4a9db4f02412f7aa31df9140592d87053f3c4a9a Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 30 May 2025 13:22:26 +0800 Subject: [PATCH 06/16] [core] Fix warnings for codecvt for clang for charxx_t --- include/fast_io_core_impl/codecvt/general.h | 4 ++-- include/fast_io_core_impl/literals/literal.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/fast_io_core_impl/codecvt/general.h b/include/fast_io_core_impl/codecvt/general.h index 9a4a36519..e68b4eb4f 100644 --- a/include/fast_io_core_impl/codecvt/general.h +++ b/include/fast_io_core_impl/codecvt/general.h @@ -184,7 +184,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - dst += get_utf_code_units(code, dst); + dst += get_utf_code_units(static_cast(code), dst); } } } @@ -278,7 +278,7 @@ general_code_cvt(src_char_type const *src_first, src_char_type const *src_last, } else { - *dst = static_cast(*src_first); + *dst = static_cast(static_cast(*src_first)); } if constexpr (sizeof(dest_char_type) != 1 && encoding_is_utf(encoding) && !is_native_scheme(encoding)) diff --git a/include/fast_io_core_impl/literals/literal.h b/include/fast_io_core_impl/literals/literal.h index 4ac8a837b..bf163b4f7 100644 --- a/include/fast_io_core_impl/literals/literal.h +++ b/include/fast_io_core_impl/literals/literal.h @@ -86,21 +86,21 @@ inline constexpr char_type char_literal_add(T offs) noexcept } #endif using unsigned_char_type = ::std::make_unsigned_t; - using unsigned_result_type = - ::std::make_unsigned_t<::std::remove_cvref_t + offs)>>; + using common_chtype = ::std::common_type_t; + using unsigned_result_type = ::std::make_unsigned_t<::std::remove_cvref_t(arithmetic_char_literal_v) + offs)>>; if constexpr (::std::same_as && ::fast_io::details::wide_is_none_utf_endian) { static_assert(::std::numeric_limits<::std::uint_least8_t>::digits <= ::std::numeric_limits::digits); constexpr unsigned leftshift_offset{static_cast(::std::numeric_limits::digits - ::std::numeric_limits<::std::uint_least8_t>::digits)}; return static_cast(static_cast(static_cast( - arithmetic_char_literal_v + offs)) + static_cast(arithmetic_char_literal_v) + offs)) << leftshift_offset); } else { return static_cast(static_cast( - static_cast(arithmetic_char_literal_v + offs))); + static_cast(static_cast(arithmetic_char_literal_v) + offs))); } } From 2039ab760f2083efe40ef69e8d5876c5b6616ff3 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 31 May 2025 21:45:15 +0800 Subject: [PATCH 07/16] Add trim to string Overhual entire char_category apis Todo. Implement trim for string_view --- fuzzing/0007.containers/string/string/trim.cc | 47 +++ include/fast_io_core.h | 2 +- .../{ => char_category}/char_category.h | 38 ++- .../char_category/char_category_traits.h | 289 ++++++++++++++++++ .../fast_io_core_impl/char_category/impl.h | 4 + include/fast_io_dsal/impl/string.h | 99 ++++++ tests/0026.container/0004.string/trim.cc | 23 ++ 7 files changed, 496 insertions(+), 6 deletions(-) create mode 100644 fuzzing/0007.containers/string/string/trim.cc rename include/fast_io_core_impl/{ => char_category}/char_category.h (96%) create mode 100644 include/fast_io_core_impl/char_category/char_category_traits.h create mode 100644 include/fast_io_core_impl/char_category/impl.h create mode 100644 tests/0026.container/0004.string/trim.cc diff --git a/fuzzing/0007.containers/string/string/trim.cc b/fuzzing/0007.containers/string/string/trim.cc new file mode 100644 index 000000000..b3b2be5a9 --- /dev/null +++ b/fuzzing/0007.containers/string/string/trim.cc @@ -0,0 +1,47 @@ +#include + +extern "C" int LLVMFuzzerTestOneInput(char const *data, size_t size) +{ + // Convert fuzzer input data into three separate basic_string copies + ::fast_io::string str1(data, data + size); + ::fast_io::string str2(str1); + ::fast_io::string str3(str1); + + // Apply different trim orders to maximize variation in testing + str1.trim(fast_io::char_category::c_space{}) + .trim_prefix(fast_io::char_category::c_space{}) + .trim_suffix(fast_io::char_category::c_space{}); + + str2.trim_prefix(fast_io::char_category::c_space{}) + .trim_suffix(fast_io::char_category::c_space{}) + .trim(fast_io::char_category::c_space{}); + + str3.trim_suffix(fast_io::char_category::c_space{}) + .trim(fast_io::char_category::c_space{}) + .trim_prefix(fast_io::char_category::c_space{}); + + using char32_may_alias +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = char32_t; + ::fast_io::u32string str4(reinterpret_cast(data), + reinterpret_cast(data) + (size / sizeof(char32_t))); + ::fast_io::u32string str5(str4); + ::fast_io::u32string str6(str4); + + // Apply different trim orders to maximize variation in testing + str4.trim(fast_io::char_category::c_space{}) + .trim_prefix(fast_io::char_category::c_space{}) + .trim_suffix(fast_io::char_category::c_space{}); + + str5.trim_prefix(fast_io::char_category::c_space{}) + .trim_suffix(fast_io::char_category::c_space{}) + .trim(fast_io::char_category::c_space{}); + + str6.trim_suffix(fast_io::char_category::c_space{}) + .trim(fast_io::char_category::c_space{}) + .trim_prefix(fast_io::char_category::c_space{}); + + return 0; // Indicate successful execution +} diff --git a/include/fast_io_core.h b/include/fast_io_core.h index 1c4ed4290..1e1ab9930 100644 --- a/include/fast_io_core.h +++ b/include/fast_io_core.h @@ -42,7 +42,7 @@ #include "fast_io_core_impl/ebcdic.h" #include "fast_io_core_impl/literals/literal.h" -#include "fast_io_core_impl/char_category.h" +#include "fast_io_core_impl/char_category/impl.h" #if __cpp_lib_three_way_comparison >= 201907L #include "fast_io_core_impl/compare.h" diff --git a/include/fast_io_core_impl/char_category.h b/include/fast_io_core_impl/char_category/char_category.h similarity index 96% rename from include/fast_io_core_impl/char_category.h rename to include/fast_io_core_impl/char_category/char_category.h index cdc5bd8af..e704f91b9 100644 --- a/include/fast_io_core_impl/char_category.h +++ b/include/fast_io_core_impl/char_category/char_category.h @@ -3,6 +3,10 @@ namespace fast_io::char_category { +enum class c_is_ctype_family +{ +}; + template <::std::integral char_type> inline constexpr bool is_c_alnum(char_type ch) noexcept { @@ -1935,31 +1939,54 @@ inline constexpr bool is_c_space(char_type ch) noexcept { if constexpr (::fast_io::details::is_ebcdic) { - return details::is_c_space_tb[static_cast<::std::make_unsigned_t>(ch)]; + return ::fast_io::char_category::details::is_c_space_tb[static_cast<::std::make_unsigned_t>(ch)]; } else { - return details::is_c_space_tb[static_cast<::std::make_unsigned_t>(ch)]; + return ::fast_io::char_category::details::is_c_space_tb[static_cast<::std::make_unsigned_t>(ch)]; } } else { if constexpr (::fast_io::details::is_ebcdic) { - return details::is_c_space_impl(ch); + return ::fast_io::char_category::details::is_c_space_impl(ch); } else if constexpr (::std::same_as && ::fast_io::details::wide_is_none_utf_endian) { - return details::is_c_space_wide_impl(ch); + return ::fast_io::char_category::details::is_c_space_wide_impl(ch); } else { - return details::is_c_space_impl( + return ::fast_io::char_category::details::is_c_space_impl( static_cast(static_cast<::std::make_unsigned_t>(ch))); } } } +template <::std::integral char_type> +inline constexpr bool is_c_blank(char_type ch) noexcept +{ + return (ch == ::fast_io::char_literal_v) | + (ch == ::fast_io::char_literal_v); +} + +template <::std::integral char_type> +inline constexpr bool is_c_cntrl(char_type ch) noexcept +{ + using uchar_type = ::std::make_unsigned_t; + if constexpr (::fast_io::details::is_ebcdic) + { + // Convert to unsigned type before checking EBCDIC control characters + return (static_cast(ch) <= 0x3F) | (static_cast(ch) == 0xFF); + } + else + { + // Convert to unsigned type before checking ASCII control characters + return (static_cast(ch) <= 0x1F) | (static_cast(ch) == 0x7F); + } +} + /* https://www.gnu.org/software/gcc/gcc-11/changes.html @@ -2225,6 +2252,7 @@ inline constexpr bool is_dos_path_invalid_prefix_character(T ch) noexcept return ::fast_io::char_category::details::is_dos_path_invalid_prefix_character_impl(static_cast(ch)); } } + } // namespace fast_io::char_category namespace fast_io 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 new file mode 100644 index 000000000..f42962bae --- /dev/null +++ b/include/fast_io_core_impl/char_category/char_category_traits.h @@ -0,0 +1,289 @@ +#pragma once + +namespace fast_io::char_category +{ + +enum class char_category_family : ::std::uint_least32_t +{ + c_alnum, // Alphanumeric characters (letters and digits) + c_alpha, // Alphabetic Character + c_blank, // Space or tab + c_cntrl, // Control characters (ASCII 0x00-0x1F, 0x7F or EBCDIC equivalents) + c_digit, // Numeric digits (0-9) + c_fullwidth, // Full-width character + c_graph, // Graphical characters (alphanumeric + punctuation) + c_halfwidth, // Half-width character + c_lower, // Lowercase alphabetic characters + c_print, // Printable characters (includes space) + c_punct, // Punctuation characters + c_space, // Whitespace characters (space, tab, newline, etc.) + c_upper, // Uppercase alphabetic characters + c_xdigit, // Hexadecimal digits (0-9, A-F, a-f) + dos_path_invalid_character, // DOS Path invalid character + html_whitespace // HTML whitespace +}; + +template <::fast_io::char_category::char_category_family fam, bool negate> + requires(static_cast>(fam) <= + static_cast>( + ::fast_io::char_category::char_category_family::html_whitespace)) +class char_category_traits +{ +public: + static inline constexpr ::fast_io::char_category::char_category_family family{fam}; + static inline constexpr bool is_negate{negate}; + template <::std::integral char_type> + static inline constexpr bool char_is(char_type ch) noexcept + { + bool ret; + if constexpr (fam == ::fast_io::char_category::char_category_family::c_alpha) + { + ret = ::fast_io::char_category::is_c_alpha(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_blank) + { + ret = ::fast_io::char_category::is_c_blank(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_punct) + { + ret = ::fast_io::char_category::is_c_punct(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_graph) + { + ret = ::fast_io::char_category::is_c_graph(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_print) + { + ret = ::fast_io::char_category::is_c_print(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_xdigit) + { + ret = ::fast_io::char_category::is_c_xdigit(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_cntrl) + { + ret = ::fast_io::char_category::is_c_cntrl(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_alnum) + { + ret = ::fast_io::char_category::is_c_alnum(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_lower) + { + ret = ::fast_io::char_category::is_c_lower(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_upper) + { + ret = ::fast_io::char_category::is_c_upper(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_digit) + { + ret = ::fast_io::char_category::is_c_digit(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_space) + { + ret = ::fast_io::char_category::is_c_space(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::html_whitespace) + { + ret = ::fast_io::char_category::is_html_whitespace(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_halfwidth) + { + ret = ::fast_io::char_category::is_c_halfwidth(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_fullwidth) + { + ret = ::fast_io::char_category::is_c_fullwidth(ch); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::dos_path_invalid_character) + { + ret = ::fast_io::char_category::is_dos_path_invalid_character(ch); + } + if constexpr (negate) + { + return !ret; + } + else + { + return ret; + } + } + template <::std::integral char_type> + static inline constexpr bool operator()(char_type ch) noexcept + { + return char_is(ch); + } + + template <::std::forward_iterator Iter> + static inline constexpr Iter find(Iter first, Iter last) noexcept + { + for (; first != last && !char_is(*first); ++first) + { + } + return first; + } + + template <::std::forward_iterator Iter> + static inline constexpr Iter find_not(Iter first, Iter last) noexcept + { + for (; first != last && char_is(*first); ++first) + { + } + return first; + } + + template <::std::bidirectional_iterator Iter> + static inline constexpr Iter find_last(Iter first, Iter last) noexcept + { + while (first != last) + { + auto lastprev{last}; + --lastprev; + if (char_is(*lastprev)) + { + return last; + } + last = lastprev; + } + return last; + } + + template <::std::bidirectional_iterator Iter> + static inline constexpr Iter find_last_not(Iter first, Iter last) noexcept + { + while (first != last) + { + auto lastprev{last}; + --lastprev; + if (!char_is(*lastprev)) + { + return last; + } + last = lastprev; + } + return last; + } + template <::std::forward_iterator Iter> + static inline constexpr bool is(Iter first, Iter last) noexcept + { + return find_first_not(first, last) == last; + } + + template <::std::integral char_type> + static inline constexpr bool char_to_lower(char_type ch) noexcept + requires(!negate && fam == ::fast_io::char_category::char_category_family::c_lower) + { + if constexpr (fam == ::fast_io::char_category::char_category_family::c_upper) + { + return ::fast_io::char_category::to_c_lower(ch); + } + else + { + return ch; + } + } + template <::std::integral char_type> + static inline constexpr bool char_to_upper(char_type ch) noexcept + requires(!negate && fam == ::fast_io::char_category::char_category_family::c_lower) + { + if constexpr (fam == ::fast_io::char_category::char_category_family::c_lower) + { + return ::fast_io::char_category::to_c_upper(ch); + } + else + { + return ch; + } + } + template <::std::forward_iterator Iter> + static inline constexpr Iter to_lower(Iter first, Iter last) noexcept + requires(!negate && fam == ::fast_io::char_category::char_category_family::c_upper) + { + if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_upper) + { + for (; first != last; ++first) + { + *last = ::fast_io::char_category::to_c_lower(first); + } + } + return last; + } + template <::std::forward_iterator Iter> + static inline constexpr Iter to_upper(Iter first, Iter last) noexcept + requires(!negate && fam == ::fast_io::char_category::char_category_family::c_lower) + { + if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_lower) + { + for (; first != last; ++first) + { + *last = ::fast_io::char_category::to_c_upper(first); + } + } + return last; + } + + template <::std::integral char_type> + static inline constexpr bool char_to_halfwidth(char_type ch) noexcept + requires(!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) + { + if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) + { + return ::fast_io::char_category::to_c_halfwidth(ch); + } + else + { + return ch; + } + } + template <::std::forward_iterator Iter> + static inline constexpr Iter to_halfwidth(Iter first, Iter last) noexcept + requires(!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) + { + if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) + { + for (; first != last; ++first) + { + *last = ::fast_io::char_category::to_c_halfwidth(first); + } + } + return last; + } +}; + +using c_alnum = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_alnum, false>; +using c_alpha = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_alpha, false>; +using c_blank = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_blank, false>; +using c_cntrl = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_cntrl, false>; +using c_digit = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_digit, false>; +using c_fullwidth = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_fullwidth, false>; +using c_graph = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_graph, false>; +using c_halfwidth = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_halfwidth, false>; +using c_lower = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_lower, false>; +using c_print = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_print, false>; +using c_punct = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_punct, false>; +using c_space = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_space, false>; +using c_upper = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_upper, false>; +using c_xdigit = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_xdigit, false>; +using dos_path_invalid_character = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::dos_path_invalid_character, false>; +using html_whitespace = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::html_whitespace, false>; + + +using not_c_alnum = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_alnum, true>; +using not_c_alpha = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_alpha, true>; +using not_c_blank = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_blank, true>; +using not_c_cntrl = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_cntrl, true>; +using not_c_digit = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_digit, true>; +using not_c_fullwidth = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_fullwidth, true>; +using not_c_graph = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_graph, true>; +using not_c_halfwidth = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_halfwidth, true>; +using not_c_lower = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_lower, true>; +using not_c_print = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_print, true>; +using not_c_punct = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_punct, true>; +using not_c_space = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_space, true>; +using not_c_upper = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_upper, true>; +using not_c_xdigit = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_xdigit, true>; +using not_dos_path_invalid_character = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::dos_path_invalid_character, true>; +using not_html_whitespace = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::html_whitespace, true>; + +} // namespace fast_io::char_category diff --git a/include/fast_io_core_impl/char_category/impl.h b/include/fast_io_core_impl/char_category/impl.h new file mode 100644 index 000000000..8647826fa --- /dev/null +++ b/include/fast_io_core_impl/char_category/impl.h @@ -0,0 +1,4 @@ +#pragma once + +#include "char_category.h" +#include "char_category_traits.h" diff --git a/include/fast_io_dsal/impl/string.h b/include/fast_io_dsal/impl/string.h index 774e74aa6..490cf1200 100644 --- a/include/fast_io_dsal/impl/string.h +++ b/include/fast_io_dsal/impl/string.h @@ -1412,6 +1412,105 @@ class basic_string FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { this->resize(count, 0); } + /* + String trimming functions are a common feature in languages like Java and C#. + We are implementing similar functionality to remove unwanted characters from the beginning and end of strings. + */ + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_not(beginptr, currptr) } -> ::std::convertible_to; + { traits.find_last_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr basic_string &trim(charcate traits) noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + + if (beginptr == currptr) [[unlikely]] + { + return *this; + } + + auto frontit{traits.find_not(beginptr, currptr)}; + auto backit{traits.find_last_not(frontit, currptr)}; + + if (frontit != beginptr) + { + backit = ::fast_io::freestanding::overlapped_copy(frontit, backit, beginptr); + } + + if (backit != beginptr) // Safety check before modifying memory + { + *backit = 0; + this->imp.curr_ptr = backit; + } + return *this; + } + + inline constexpr basic_string &trim_c_space() noexcept + { + return this->trim(::fast_io::char_category::c_space{}); + } + + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr basic_string &trim_prefix(charcate traits) noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + + auto frontit{traits.find_not(beginptr, currptr)}; + if (frontit != beginptr) + { + if (frontit != currptr) // Prevent unnecessary copying + { + currptr = ::fast_io::freestanding::overlapped_copy(frontit, currptr, beginptr); + } + + // Ensure safe null termination + *currptr = 0; + this->imp.curr_ptr = currptr; + } + + return *this; + } + + inline constexpr basic_string &trim_prefix_c_space() noexcept + { + return this->trim_prefix(::fast_io::char_category::c_space{}); + } + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_last_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr basic_string &trim_suffix(charcate traits) noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + + if (beginptr == currptr) [[unlikely]] + { + return *this; + } + + // Ensure we correctly initialize backit using valid iterators + auto backit{traits.find_last_not(beginptr, currptr)}; + + // Boundary check to prevent dereferencing invalid memory + if (backit != currptr) + { + *backit = 0; + this->imp.curr_ptr = backit; + } + + return *this; + } + inline constexpr basic_string &trim_suffix_c_space() noexcept + { + return this->trim_suffix(::fast_io::char_category::c_space{}); + } }; template <::std::integral chtype, typename allocator1, typename U> diff --git a/tests/0026.container/0004.string/trim.cc b/tests/0026.container/0004.string/trim.cc new file mode 100644 index 000000000..7cf79ad68 --- /dev/null +++ b/tests/0026.container/0004.string/trim.cc @@ -0,0 +1,23 @@ +#include +#include + +int main() +{ + ::fast_io::u8string str(u8" \n\n\t sdgsdg sdgsds \n\t \n"), + str1(str), str2(str), str3(str); + + // Apply different trim methods + str.trim_c_space(); // Trim both prefix and suffix spaces + str1.trim_prefix_c_space(); // Trim only leading spaces + str2.trim_suffix_c_space(); // Trim only trailing spaces + str3.trim(::fast_io::char_category::c_blank{}); // Trim blank characters + + // Print results + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Original: ", str3); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Full): ", str, u8" | Size: ", str.size()); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Prefix): ", str1, u8" | Size: ", str1.size()); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Suffix): ", str2, u8" | Size: ", str2.size()); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Blank Only): ", str3, u8" | Size: ", str3.size()); + + return 0; +} From e4fa2272b79de8335ade63cb0196ee0f294f39e7 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 31 May 2025 22:00:55 +0800 Subject: [PATCH 08/16] add __cpp_static_call_operator to char_category_traits.h --- .../fast_io_core_impl/char_category/char_category_traits.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 f42962bae..761992d0a 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 @@ -110,7 +110,10 @@ class char_category_traits } } template <::std::integral char_type> - static inline constexpr bool operator()(char_type ch) noexcept +#ifdef __cpp_static_call_operator + static +#endif + inline constexpr bool operator()(char_type ch) noexcept { return char_is(ch); } From 025f9fb8940eab09789f1ae80eab3cd9de648f64 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 01:14:43 +0800 Subject: [PATCH 09/16] [edit] add string_view for trim, trim.cc string.h --- include/fast_io_dsal/impl/cstring_view.h | 18 ++++++++ include/fast_io_dsal/impl/string.h | 52 ++++++++++++++++++++++++ include/fast_io_dsal/impl/string_view.h | 48 ++++++++++++++++++++++ tests/0026.container/0004.string/trim.cc | 31 +++++++------- 4 files changed, 135 insertions(+), 14 deletions(-) diff --git a/include/fast_io_dsal/impl/cstring_view.h b/include/fast_io_dsal/impl/cstring_view.h index 78b4b0e2a..9b1e446c3 100644 --- a/include/fast_io_dsal/impl/cstring_view.h +++ b/include/fast_io_dsal/impl/cstring_view.h @@ -158,6 +158,24 @@ class basic_cstring_view : private ::fast_io::containers::basic_string_view + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr basic_cstring_view trim_prefix_subview(charcate traits) const noexcept + { + using string_view_type::trim_prefix_subview; + auto csvw{string_view_type::trim_prefix_subview(traits)}; + return basic_cstring_view(csvw.ptr, csvw.n); + } + inline constexpr basic_cstring_view trim_prefix_subview_c_space() const noexcept + { + return trim_prefix_subview(::fast_io::char_category::c_space{}); + } + using string_view_type::trim_suffix_subview; + using string_view_type::trim_suffix_subview_c_space; }; template <::std::integral char_type> diff --git a/include/fast_io_dsal/impl/string.h b/include/fast_io_dsal/impl/string.h index 490cf1200..62b6eff5c 100644 --- a/include/fast_io_dsal/impl/string.h +++ b/include/fast_io_dsal/impl/string.h @@ -1511,6 +1511,58 @@ class basic_string FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { return this->trim_suffix(::fast_io::char_category::c_space{}); } + + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_not(beginptr, currptr) } -> ::std::convertible_to; + { traits.find_last_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr string_view_type trim_subview(charcate traits) const noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + return string_view_type(beginptr, static_cast(currptr - beginptr)).trim_subview(traits); + } + inline constexpr string_view_type trim_subview_c_space() const noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + return string_view_type(beginptr, static_cast(currptr - beginptr)).trim_subview_c_space(); + } + + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr cstring_view_type trim_prefix_subview(charcate traits) const noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + return cstring_view_type(beginptr, static_cast(currptr - beginptr)).trim_prefix_subview(traits); + } + inline constexpr cstring_view_type trim_prefix_subview_c_space() const noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + return cstring_view_type(beginptr, static_cast(currptr - beginptr)).trim_prefix_subview_c_space(); + } + + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_last_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr string_view_type trim_suffix_subview(charcate traits) const noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + return string_view_type(beginptr, static_cast(currptr - beginptr)).trim_suffix_subview(traits); + } + inline constexpr string_view_type trim_suffix_subview_c_space() const noexcept + { + auto beginptr{this->imp.begin_ptr}; + auto currptr{this->imp.curr_ptr}; + return string_view_type(beginptr, static_cast(currptr - beginptr)).trim_suffix_subview_c_space(); + } }; template <::std::integral chtype, typename allocator1, typename U> diff --git a/include/fast_io_dsal/impl/string_view.h b/include/fast_io_dsal/impl/string_view.h index f4528ced0..ac377d3c0 100644 --- a/include/fast_io_dsal/impl/string_view.h +++ b/include/fast_io_dsal/impl/string_view.h @@ -612,6 +612,54 @@ class basic_string_view this->ptr = 0; this->n = 0; } + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_not(beginptr, currptr) } -> ::std::convertible_to; + { traits.find_last_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr basic_string_view trim_subview(charcate traits) const noexcept + { + auto beginptr{this->ptr}; + auto currptr{this->ptr + this->n}; + auto frontit{traits.find_not(beginptr, currptr)}; + auto backit{traits.find_last_not(frontit, currptr)}; + return basic_string_view(frontit, static_cast(backit - frontit)); + } + inline constexpr basic_string_view trim_subview_c_space() noexcept + { + return trim_subview(::fast_io::char_category::c_space{}); + } + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr basic_string_view trim_prefix_subview(charcate traits) const noexcept + { + auto beginptr{this->ptr}; + auto currptr{this->ptr + this->n}; + auto frontit{traits.find_not(beginptr, currptr)}; + return basic_string_view(frontit, static_cast(currptr - frontit)); + } + inline constexpr basic_string_view trim_prefix_subview_c_space() const noexcept + { + return trim_prefix_subview(::fast_io::char_category::c_space{}); + } + + template + requires requires(charcate traits, const_pointer beginptr, const_pointer currptr) { + { traits.find_last_not(beginptr, currptr) } -> ::std::convertible_to; + } + inline constexpr basic_string_view trim_suffix_subview(charcate traits) const noexcept + { + auto beginptr{this->ptr}; + auto currptr{this->ptr + this->n}; + auto backit{traits.find_last_not(beginptr, currptr)}; + return basic_string_view(beginptr, static_cast(backit - beginptr)); + } + inline constexpr basic_string_view trim_suffix_subview_c_space() const noexcept + { + return trim_suffix_subview(::fast_io::char_category::c_space{}); + } }; template <::std::integral char_type> diff --git a/tests/0026.container/0004.string/trim.cc b/tests/0026.container/0004.string/trim.cc index 7cf79ad68..2211fa22a 100644 --- a/tests/0026.container/0004.string/trim.cc +++ b/tests/0026.container/0004.string/trim.cc @@ -1,23 +1,26 @@ #include #include +#include int main() { - ::fast_io::u8string str(u8" \n\n\t sdgsdg sdgsds \n\t \n"), - str1(str), str2(str), str3(str); + ::fast_io::u8string str(u8" \n\n\t sdgsdg sdgsds \n\t \n"), + str1(str), str2(str), str3(str); - // Apply different trim methods - str.trim_c_space(); // Trim both prefix and suffix spaces - str1.trim_prefix_c_space(); // Trim only leading spaces - str2.trim_suffix_c_space(); // Trim only trailing spaces - str3.trim(::fast_io::char_category::c_blank{}); // Trim blank characters + // Apply different trim methods + str.trim_c_space(); // Trim both prefix and suffix spaces + str1.trim_prefix_c_space(); // Trim only leading spaces + str2.trim_suffix_c_space(); // Trim only trailing spaces + str3.trim(::fast_io::char_category::c_blank{}); // Trim blank characters - // Print results - ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Original: ", str3); - ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Full): ", str, u8" | Size: ", str.size()); - ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Prefix): ", str1, u8" | Size: ", str1.size()); - ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Suffix): ", str2, u8" | Size: ", str2.size()); - ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Blank Only): ", str3, u8" | Size: ", str3.size()); + // Print results + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Original: ", str3); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Full): ", str, u8" | Size: ", str.size()); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Prefix): ", str1, u8" | Size: ", str1.size()); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Suffix): ", str2, u8" | Size: ", str2.size()); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8"Trimmed (Blank Only): ", str3, u8" | Size: ", str3.size()); - return 0; + ::fast_io::u8string_view u8strvw(u8" testing trim view \n\t\n"); + ::fast_io::io::println(::fast_io::u8c_stdout(), u8strvw.trim_prefix_subview_c_space()); + return 0; } From 533be3664bf6fda15015c2bce375f5e0477c6451 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 09:52:40 +0800 Subject: [PATCH 10/16] [string] trim_subview_prefix should have fast_io::containers::null_terminated --- include/fast_io_dsal/impl/string.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_io_dsal/impl/string.h b/include/fast_io_dsal/impl/string.h index 62b6eff5c..2430e6a5e 100644 --- a/include/fast_io_dsal/impl/string.h +++ b/include/fast_io_dsal/impl/string.h @@ -1538,13 +1538,13 @@ class basic_string FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { auto beginptr{this->imp.begin_ptr}; auto currptr{this->imp.curr_ptr}; - return cstring_view_type(beginptr, static_cast(currptr - beginptr)).trim_prefix_subview(traits); + return cstring_view_type(::fast_io::containers::null_terminated, beginptr, static_cast(currptr - beginptr)).trim_prefix_subview(traits); } inline constexpr cstring_view_type trim_prefix_subview_c_space() const noexcept { auto beginptr{this->imp.begin_ptr}; auto currptr{this->imp.curr_ptr}; - return cstring_view_type(beginptr, static_cast(currptr - beginptr)).trim_prefix_subview_c_space(); + return cstring_view_type(::fast_io::containers::null_terminated, beginptr, static_cast(currptr - beginptr)).trim_prefix_subview_c_space(); } template From 715ed246480112a5bb8c7105c532e614c0132eee Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 12:46:30 +0800 Subject: [PATCH 11/16] [char_category] add to_c_lower upper ranges support --- .../char_category/char_category.h | 306 ------------ .../char_category/char_category_traits.h | 455 +++++++++++++++--- .../0004.string/to_c_lower_upper.cc | 30 ++ 3 files changed, 405 insertions(+), 386 deletions(-) create mode 100644 tests/0026.container/0004.string/to_c_lower_upper.cc 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 e704f91b9..db94a543b 100644 --- a/include/fast_io_core_impl/char_category/char_category.h +++ b/include/fast_io_core_impl/char_category/char_category.h @@ -1578,268 +1578,6 @@ inline constexpr char32_t to_c_lower_ascii_impl(char32_t ch) noexcept } // namespace details -template <::std::integral char_type> -inline constexpr char_type to_c_lower(char_type ch) noexcept -{ - using unsigned_char_type = ::std::make_unsigned_t; - if constexpr (!::fast_io::details::is_ebcdic) - { - return static_cast( - static_cast(details::to_c_lower_ascii_impl(static_cast(ch)))); - } - else if constexpr (::std::same_as) - { - switch (ch) - { - case 'A': - return 'a'; - case 'B': - return 'b'; - case 'C': - return 'c'; - case 'D': - return 'd'; - case 'E': - return 'e'; - case 'F': - return 'f'; - case 'G': - return 'g'; - case 'H': - return 'h'; - case 'I': - return 'i'; - case 'J': - return 'j'; - case 'K': - return 'k'; - case 'L': - return 'l'; - case 'M': - return 'm'; - case 'N': - return 'n'; - case 'O': - return 'o'; - case 'P': - return 'p'; - case 'Q': - return 'q'; - case 'R': - return 'r'; - case 'S': - return 's'; - case 'T': - return 't'; - case 'U': - return 'u'; - case 'V': - return 'v'; - case 'W': - return 'w'; - case 'X': - return 'x'; - case 'Y': - return 'y'; - case 'Z': - return 'z'; - default: - return ch; - } - } - else if constexpr (::std::same_as) - { - switch (ch) - { - case L'A': - return L'a'; - case L'B': - return L'b'; - case L'C': - return L'c'; - case L'D': - return L'd'; - case L'E': - return L'e'; - case L'F': - return L'f'; - case L'G': - return L'g'; - case L'H': - return L'h'; - case L'I': - return L'i'; - case L'J': - return L'j'; - case L'K': - return L'k'; - case L'L': - return L'l'; - case L'M': - return L'm'; - case L'N': - return L'n'; - case L'O': - return L'o'; - case L'P': - return L'p'; - case L'Q': - return L'q'; - case L'R': - return L'r'; - case L'S': - return L's'; - case L'T': - return L't'; - case L'U': - return L'u'; - case L'V': - return L'v'; - case L'W': - return L'w'; - case L'X': - return L'x'; - case L'Y': - return L'y'; - case L'Z': - return L'z'; - default: - return ch; - } - } -} - -template <::std::integral char_type> -inline constexpr char_type to_c_upper(char_type ch) noexcept -{ - using unsigned_char_type = ::std::make_unsigned_t; - if constexpr (!::fast_io::details::is_ebcdic) - { - return static_cast( - static_cast(details::to_c_upper_ascii_impl(static_cast(ch)))); - } - else if constexpr (::std::same_as) - { - switch (ch) - { - case 'a': - return 'A'; - case 'b': - return 'B'; - case 'c': - return 'C'; - case 'd': - return 'D'; - case 'e': - return 'E'; - case 'f': - return 'F'; - case 'g': - return 'G'; - case 'h': - return 'H'; - case 'i': - return 'I'; - case 'j': - return 'J'; - case 'k': - return 'K'; - case 'l': - return 'L'; - case 'm': - return 'M'; - case 'n': - return 'N'; - case 'o': - return 'O'; - case 'p': - return 'P'; - case 'q': - return 'Q'; - case 'r': - return 'R'; - case 's': - return 'S'; - case 't': - return 'T'; - case 'u': - return 'U'; - case 'v': - return 'V'; - case 'w': - return 'W'; - case 'x': - return 'X'; - case 'y': - return 'Y'; - case 'z': - return 'Z'; - default: - return ch; - } - } - else if constexpr (::std::same_as) - { - switch (ch) - { - case L'a': - return L'A'; - case L'b': - return L'B'; - case L'c': - return L'C'; - case L'd': - return L'D'; - case L'e': - return L'E'; - case L'f': - return L'F'; - case L'g': - return L'G'; - case L'h': - return L'H'; - case L'i': - return L'I'; - case L'j': - return L'J'; - case L'k': - return L'K'; - case L'l': - return L'L'; - case L'm': - return L'M'; - case L'n': - return L'N'; - case L'o': - return L'O'; - case L'p': - return L'P'; - case L'q': - return L'Q'; - case L'r': - return L'R'; - case L's': - return L'S'; - case L't': - return L'T'; - case L'u': - return L'U'; - case L'v': - return L'V'; - case L'w': - return L'W'; - case L'x': - return L'X'; - case L'y': - return L'Y'; - case L'z': - return L'Z'; - default: - return ch; - } - } -} - /* All Ascii based charset, only 6 character is supported space (0x20, ' ') @@ -2183,50 +1921,6 @@ inline constexpr bool is_c_fullwidth(char_type ch) noexcept To do: to_c_fullwidth */ -template <::std::integral char_type> -inline constexpr char_type to_c_halfwidth(char_type ch) noexcept -{ - using unsigned_char_type = ::std::make_unsigned_t; - if constexpr (sizeof(char_type) < sizeof(char32_t)) - { - return ch; - } - else if constexpr (!::std::same_as && sizeof(char_type) == sizeof(char32_t)) - { - return static_cast(to_c_halfwidth(static_cast(ch))); - } - else if constexpr (::std::signed_integral) - { - return static_cast(to_c_halfwidth(static_cast(ch))); - } - else if constexpr (::std::same_as && ::fast_io::details::wide_is_none_utf_endian) - { - constexpr unsigned_char_type fullwidth_exclaimation_mark_val{0xFF01}; - constexpr unsigned_char_type num{94}; - constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'}; - unsigned_char_type cht{ch}; - cht = ::fast_io::byte_swap(cht); - unsigned_char_type const umav{static_cast(cht - fullwidth_exclaimation_mark_val)}; - if (umav < num) - { - return static_cast(umav + halfwidth_exclaimation_mark_val); - } - return cht; - } - else - { - constexpr unsigned_char_type fullwidth_exclaimation_mark_val{0xFF01}; - constexpr unsigned_char_type num{94}; - constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'}; - unsigned_char_type const umav{static_cast(ch - fullwidth_exclaimation_mark_val)}; - if (umav < num) - { - return static_cast(umav + halfwidth_exclaimation_mark_val); - } - return ch; - } -} - template <::std::integral T> inline constexpr bool is_dos_path_invalid_character(T ch) noexcept { 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 761992d0a..7d76c5259 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 @@ -172,86 +172,6 @@ class char_category_traits { return find_first_not(first, last) == last; } - - template <::std::integral char_type> - static inline constexpr bool char_to_lower(char_type ch) noexcept - requires(!negate && fam == ::fast_io::char_category::char_category_family::c_lower) - { - if constexpr (fam == ::fast_io::char_category::char_category_family::c_upper) - { - return ::fast_io::char_category::to_c_lower(ch); - } - else - { - return ch; - } - } - template <::std::integral char_type> - static inline constexpr bool char_to_upper(char_type ch) noexcept - requires(!negate && fam == ::fast_io::char_category::char_category_family::c_lower) - { - if constexpr (fam == ::fast_io::char_category::char_category_family::c_lower) - { - return ::fast_io::char_category::to_c_upper(ch); - } - else - { - return ch; - } - } - template <::std::forward_iterator Iter> - static inline constexpr Iter to_lower(Iter first, Iter last) noexcept - requires(!negate && fam == ::fast_io::char_category::char_category_family::c_upper) - { - if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_upper) - { - for (; first != last; ++first) - { - *last = ::fast_io::char_category::to_c_lower(first); - } - } - return last; - } - template <::std::forward_iterator Iter> - static inline constexpr Iter to_upper(Iter first, Iter last) noexcept - requires(!negate && fam == ::fast_io::char_category::char_category_family::c_lower) - { - if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_lower) - { - for (; first != last; ++first) - { - *last = ::fast_io::char_category::to_c_upper(first); - } - } - return last; - } - - template <::std::integral char_type> - static inline constexpr bool char_to_halfwidth(char_type ch) noexcept - requires(!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) - { - if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) - { - return ::fast_io::char_category::to_c_halfwidth(ch); - } - else - { - return ch; - } - } - template <::std::forward_iterator Iter> - static inline constexpr Iter to_halfwidth(Iter first, Iter last) noexcept - requires(!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) - { - if constexpr (!negate && fam == ::fast_io::char_category::char_category_family::c_fullwidth) - { - for (; first != last; ++first) - { - *last = ::fast_io::char_category::to_c_halfwidth(first); - } - } - return last; - } }; using c_alnum = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::c_alnum, false>; @@ -289,4 +209,379 @@ using not_c_xdigit = ::fast_io::char_category::char_category_traits<::fast_io::c using not_dos_path_invalid_character = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::dos_path_invalid_character, true>; using not_html_whitespace = ::fast_io::char_category::char_category_traits<::fast_io::char_category::char_category_family::html_whitespace, true>; +namespace details +{ +template <::fast_io::char_category::char_category_family fam> +struct to_c_common_fn_impl +{ + template <::std::integral char_type> +#ifdef __cpp_static_call_operator + static +#endif + inline constexpr char_type operator()(char_type ch) noexcept + { + using unsigned_char_type = ::std::make_unsigned_t; + if constexpr (fam == ::fast_io::char_category::char_category_family::c_lower) + { + if constexpr (!::fast_io::details::is_ebcdic) + { + return static_cast( + static_cast(::fast_io::char_category::details::to_c_lower_ascii_impl(static_cast(ch)))); + } + else if constexpr (::std::same_as) + { + switch (ch) + { + case 'A': + return 'a'; + case 'B': + return 'b'; + case 'C': + return 'c'; + case 'D': + return 'd'; + case 'E': + return 'e'; + case 'F': + return 'f'; + case 'G': + return 'g'; + case 'H': + return 'h'; + case 'I': + return 'i'; + case 'J': + return 'j'; + case 'K': + return 'k'; + case 'L': + return 'l'; + case 'M': + return 'm'; + case 'N': + return 'n'; + case 'O': + return 'o'; + case 'P': + return 'p'; + case 'Q': + return 'q'; + case 'R': + return 'r'; + case 'S': + return 's'; + case 'T': + return 't'; + case 'U': + return 'u'; + case 'V': + return 'v'; + case 'W': + return 'w'; + case 'X': + return 'x'; + case 'Y': + return 'y'; + case 'Z': + return 'z'; + default: + return ch; + } + } + else if constexpr (::std::same_as) + { + switch (ch) + { + case L'A': + return L'a'; + case L'B': + return L'b'; + case L'C': + return L'c'; + case L'D': + return L'd'; + case L'E': + return L'e'; + case L'F': + return L'f'; + case L'G': + return L'g'; + case L'H': + return L'h'; + case L'I': + return L'i'; + case L'J': + return L'j'; + case L'K': + return L'k'; + case L'L': + return L'l'; + case L'M': + return L'm'; + case L'N': + return L'n'; + case L'O': + return L'o'; + case L'P': + return L'p'; + case L'Q': + return L'q'; + case L'R': + return L'r'; + case L'S': + return L's'; + case L'T': + return L't'; + case L'U': + return L'u'; + case L'V': + return L'v'; + case L'W': + return L'w'; + case L'X': + return L'x'; + case L'Y': + return L'y'; + case L'Z': + return L'z'; + default: + return ch; + } + } + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_upper) + { + if constexpr (!::fast_io::details::is_ebcdic) + { + return static_cast( + static_cast(::fast_io::char_category::details::to_c_upper_ascii_impl(static_cast(ch)))); + } + else if constexpr (::std::same_as) + { + switch (ch) + { + case 'a': + return 'A'; + case 'b': + return 'B'; + case 'c': + return 'C'; + case 'd': + return 'D'; + case 'e': + return 'E'; + case 'f': + return 'F'; + case 'g': + return 'G'; + case 'h': + return 'H'; + case 'i': + return 'I'; + case 'j': + return 'J'; + case 'k': + return 'K'; + case 'l': + return 'L'; + case 'm': + return 'M'; + case 'n': + return 'N'; + case 'o': + return 'O'; + case 'p': + return 'P'; + case 'q': + return 'Q'; + case 'r': + return 'R'; + case 's': + return 'S'; + case 't': + return 'T'; + case 'u': + return 'U'; + case 'v': + return 'V'; + case 'w': + return 'W'; + case 'x': + return 'X'; + case 'y': + return 'Y'; + case 'z': + return 'Z'; + default: + return ch; + } + } + else if constexpr (::std::same_as) + { + switch (ch) + { + case L'a': + return L'A'; + case L'b': + return L'B'; + case L'c': + return L'C'; + case L'd': + return L'D'; + case L'e': + return L'E'; + case L'f': + return L'F'; + case L'g': + return L'G'; + case L'h': + return L'H'; + case L'i': + return L'I'; + case L'j': + return L'J'; + case L'k': + return L'K'; + case L'l': + return L'L'; + case L'm': + return L'M'; + case L'n': + return L'N'; + case L'o': + return L'O'; + case L'p': + return L'P'; + case L'q': + return L'Q'; + case L'r': + return L'R'; + case L's': + return L'S'; + case L't': + return L'T'; + case L'u': + return L'U'; + case L'v': + return L'V'; + case L'w': + return L'W'; + case L'x': + return L'X'; + case L'y': + return L'Y'; + case L'z': + return L'Z'; + default: + return ch; + } + } + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_halfwidth) + { + using unsigned_char_type = ::std::make_unsigned_t; + if constexpr (sizeof(char_type) < sizeof(char32_t)) + { + return ch; + } + else if constexpr (!::std::same_as && sizeof(char_type) == sizeof(char32_t)) + { + return static_cast(to_c_halfwidth(static_cast(ch))); + } + else if constexpr (::std::signed_integral) + { + return static_cast(to_c_halfwidth(static_cast(ch))); + } + else if constexpr (::std::same_as && ::fast_io::details::wide_is_none_utf_endian) + { + constexpr unsigned_char_type fullwidth_exclaimation_mark_val{0xFF01}; + constexpr unsigned_char_type num{94}; + constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'}; + unsigned_char_type cht{ch}; + cht = ::fast_io::byte_swap(cht); + unsigned_char_type const umav{static_cast(cht - fullwidth_exclaimation_mark_val)}; + if (umav < num) + { + return static_cast(umav + halfwidth_exclaimation_mark_val); + } + return cht; + } + else + { + constexpr unsigned_char_type fullwidth_exclaimation_mark_val{0xFF01}; + constexpr unsigned_char_type num{94}; + constexpr unsigned_char_type halfwidth_exclaimation_mark_val{u8'!'}; + unsigned_char_type const umav{static_cast(ch - fullwidth_exclaimation_mark_val)}; + if (umav < num) + { + return static_cast(umav + halfwidth_exclaimation_mark_val); + } + return ch; + } + } + } +}; + +} // namespace details + +inline constexpr ::fast_io::char_category::details::to_c_common_fn_impl<::fast_io::char_category::char_category_family::c_lower> to_c_lower{}; +inline constexpr ::fast_io::char_category::details::to_c_common_fn_impl<::fast_io::char_category::char_category_family::c_upper> to_c_upper{}; +inline constexpr ::fast_io::char_category::details::to_c_common_fn_impl<::fast_io::char_category::char_category_family::c_halfwidth> to_c_halfwidth{}; + +namespace ranges +{ +namespace details +{ +template <::fast_io::char_category::char_category_family fam> +struct to_c_common_rg_fn +{ + + template <::std::input_iterator Iter, ::std::sentinel_for S, typename Proj = ::std::identity> + requires ::std::integral<::std::iter_value_t> +#ifdef __cpp_static_call_operator + static +#endif + inline constexpr Iter operator()(Iter first, S last, Proj proj = {}) +#ifndef __cpp_static_call_operator + const +#endif + noexcept + { + for (; first != last; ++first) + { + if constexpr (fam == ::fast_io::char_category::char_category_family::c_lower) + { + *first = ::fast_io::char_category::to_c_lower(proj(*first)); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_upper) + { + *first = ::fast_io::char_category::to_c_upper(proj(*first)); + } + else if constexpr (fam == ::fast_io::char_category::char_category_family::c_halfwidth) + { + *first = ::fast_io::char_category::to_c_halfwidth(proj(*first)); + } + } + return first; + } + template <::std::ranges::input_range R, typename Proj = ::std::identity> + requires ::std::integral<::std::ranges::range_value_t> +#ifdef __cpp_static_call_operator + static +#endif + inline constexpr ::std::ranges::borrowed_iterator_t operator()(R &&r, Proj proj = {}) +#ifndef __cpp_static_call_operator + const +#endif + noexcept + { + return operator()(::std::ranges::begin(r), ::std::ranges::end(r), ::std::move(proj)); + } +}; +} // namespace details + +inline constexpr ::fast_io::char_category::ranges::details::to_c_common_rg_fn<::fast_io::char_category::char_category_family::c_lower> to_c_lower{}; +inline constexpr ::fast_io::char_category::ranges::details::to_c_common_rg_fn<::fast_io::char_category::char_category_family::c_upper> to_c_upper{}; +inline constexpr ::fast_io::char_category::ranges::details::to_c_common_rg_fn<::fast_io::char_category::char_category_family::c_halfwidth> to_c_halfwidth{}; +} // namespace ranges } // namespace fast_io::char_category diff --git a/tests/0026.container/0004.string/to_c_lower_upper.cc b/tests/0026.container/0004.string/to_c_lower_upper.cc new file mode 100644 index 000000000..98e1c0e4d --- /dev/null +++ b/tests/0026.container/0004.string/to_c_lower_upper.cc @@ -0,0 +1,30 @@ +#include +#include + +int main() +{ + ::fast_io::u8string ustr(u8"abcdefwegeABCDwgwasfsa 325235 fhasdfhsdh"), + ustr_upper(ustr), + ustr_lower(ustr), + numbers(u8"1234567890"), + symbols(u8"!@#$%^&*()"), + empty; + + // Apply transformations + ::fast_io::char_category::ranges::to_c_upper(ustr_upper); + ::fast_io::char_category::ranges::to_c_lower(ustr_lower); + ::fast_io::char_category::ranges::to_c_upper(numbers); + ::fast_io::char_category::ranges::to_c_upper(symbols); + ::fast_io::char_category::ranges::to_c_upper(empty); + + // Print all results in one println + ::fast_io::io::println(::fast_io::u8c_stdout(), + u8"Original: ", ustr, + u8"\nUppercase: ", ustr_upper, + u8"\nLowercase: ", ustr_lower, + u8"\nNumbers (unchanged): ", numbers, + u8"\nSymbols (unchanged): ", symbols, + u8"\nEmpty string: ", empty); + + return 0; +} From 849e3dbbdf27b42d27daffba358c4723f1d23916 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 12:48:52 +0800 Subject: [PATCH 12/16] [char_category_traits.h] fix to_c_halfwidth --- .../fast_io_core_impl/char_category/char_category_traits.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7d76c5259..03d6408bd 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 @@ -486,11 +486,11 @@ struct to_c_common_fn_impl } else if constexpr (!::std::same_as && sizeof(char_type) == sizeof(char32_t)) { - return static_cast(to_c_halfwidth(static_cast(ch))); + return static_cast(operator()(static_cast(ch))); } else if constexpr (::std::signed_integral) { - return static_cast(to_c_halfwidth(static_cast(ch))); + return static_cast(operator()(static_cast(ch))); } else if constexpr (::std::same_as && ::fast_io::details::wide_is_none_utf_endian) { From 118c83f402c83cca80b168576cf624e7778a94d6 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 12:58:27 +0800 Subject: [PATCH 13/16] fix issues with shadow --- include/fast_io_core_impl/char_category/char_category_traits.h | 1 - 1 file changed, 1 deletion(-) 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 03d6408bd..f9d946ec6 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 @@ -479,7 +479,6 @@ struct to_c_common_fn_impl } else if constexpr (fam == ::fast_io::char_category::char_category_family::c_halfwidth) { - using unsigned_char_type = ::std::make_unsigned_t; if constexpr (sizeof(char_type) < sizeof(char32_t)) { return ch; From 4c481f395fa7ee6669cf27cd833c6afb58857e7a Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 13:02:30 +0800 Subject: [PATCH 14/16] [nt] fix shadow in alpc_nt.h --- .../fast_io_hosted/process/ipc/win32/alpc_nt.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/fast_io_hosted/process/ipc/win32/alpc_nt.h b/include/fast_io_hosted/process/ipc/win32/alpc_nt.h index 8fe9bd246..d6c310a31 100644 --- a/include/fast_io_hosted/process/ipc/win32/alpc_nt.h +++ b/include/fast_io_hosted/process/ipc/win32/alpc_nt.h @@ -240,24 +240,24 @@ struct nt_alpc_handle FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { constexpr bool zw{family == nt_family::zw}; - ::std::uint_least32_t status; // No initialization required + ::std::uint_least32_t ntstatus; // No initialization required if (section_handle) { - status = ::fast_io::win32::nt::nt_alpc_disconnect_port(section_handle, 0); - if (status) [[unlikely]] + ntstatus = ::fast_io::win32::nt::nt_alpc_disconnect_port(section_handle, 0); + if (ntstatus) [[unlikely]] { - throw_nt_error(status); + throw_nt_error(ntstatus); } section_handle = nullptr; } if (port_handle) { - status = ::fast_io::win32::nt::nt_alpc_disconnect_port(port_handle, 0); - if (status) [[unlikely]] + ntstatus = ::fast_io::win32::nt::nt_alpc_disconnect_port(port_handle, 0); + if (ntstatus) [[unlikely]] { - throw_nt_error(status); + throw_nt_error(ntstatus); } port_handle = nullptr; } @@ -698,7 +698,7 @@ inline ::fast_io::win32::nt::alpc_message_attributes *nt_family_create_alpc_ipc_ } template -inline void *nt_family_ipc_alpc_client_connect_impl(nt_alpc_char_type const *server_name, ::std::size_t server_name_size, [[maybe_unused]] ::fast_io::ipc_mode mode, +inline void *nt_family_ipc_alpc_client_connect_impl(nt_alpc_char_type const *server_name, ::std::size_t server_name_size, [[maybe_unused]] ::fast_io::ipc_mode mode, ::std::byte const *message_begin, ::std::byte const *message_end, ::fast_io::win32::nt::alpc_message_attributes *__restrict message_attribute, nt_alpc_byte_vector &connect_recv_message) { @@ -904,7 +904,7 @@ inline ::std::byte const *nt_alpc_write_or_pwrite_some_bytes_common_impl(void *_ port_message_p->u1.s1.DataLength = static_cast<::std::uint_least16_t>(message_data_size); port_message_p->u1.s1.TotalLength = static_cast<::std::uint_least16_t>(send_size); - // There is a bug and it cannot be sent. + // There is a bug and it cannot be sent. // At present, the known usage of alpc is only synchronous mode, and the message flow mode has not been found yet // https://github.com/csandker/InterProcessCommunication-Samples/issues/7 From 5c4339c2135349d977cfcce2e1b01d4adbe64e6c Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 13:12:39 +0800 Subject: [PATCH 15/16] [char_category] fix api before C++23 --- .../fast_io_core_impl/char_category/char_category_traits.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 f9d946ec6..c3648db56 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 @@ -218,7 +218,11 @@ struct to_c_common_fn_impl #ifdef __cpp_static_call_operator static #endif - inline constexpr char_type operator()(char_type ch) noexcept + inline constexpr char_type operator()(char_type ch) +#ifndef __cpp_static_call_operator + const +#endif + noexcept { using unsigned_char_type = ::std::make_unsigned_t; if constexpr (fam == ::fast_io::char_category::char_category_family::c_lower) From 10d6074219525524104e7956e9bba61cfa54f0d1 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 1 Jun 2025 17:26:17 +0800 Subject: [PATCH 16/16] [to_c_lower_upper.cc] clang-format --- .../0004.string/to_c_lower_upper.cc | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/0026.container/0004.string/to_c_lower_upper.cc b/tests/0026.container/0004.string/to_c_lower_upper.cc index 98e1c0e4d..7b0b2595b 100644 --- a/tests/0026.container/0004.string/to_c_lower_upper.cc +++ b/tests/0026.container/0004.string/to_c_lower_upper.cc @@ -3,28 +3,28 @@ int main() { - ::fast_io::u8string ustr(u8"abcdefwegeABCDwgwasfsa 325235 fhasdfhsdh"), - ustr_upper(ustr), - ustr_lower(ustr), - numbers(u8"1234567890"), - symbols(u8"!@#$%^&*()"), - empty; + ::fast_io::u8string ustr(u8"abcdefwegeABCDwgwasfsa 325235 fhasdfhsdh"), + ustr_upper(ustr), + ustr_lower(ustr), + numbers(u8"1234567890"), + symbols(u8"!@#$%^&*()"), + empty; - // Apply transformations - ::fast_io::char_category::ranges::to_c_upper(ustr_upper); - ::fast_io::char_category::ranges::to_c_lower(ustr_lower); - ::fast_io::char_category::ranges::to_c_upper(numbers); - ::fast_io::char_category::ranges::to_c_upper(symbols); - ::fast_io::char_category::ranges::to_c_upper(empty); + // Apply transformations + ::fast_io::char_category::ranges::to_c_upper(ustr_upper); + ::fast_io::char_category::ranges::to_c_lower(ustr_lower); + ::fast_io::char_category::ranges::to_c_upper(numbers); + ::fast_io::char_category::ranges::to_c_upper(symbols); + ::fast_io::char_category::ranges::to_c_upper(empty); - // Print all results in one println - ::fast_io::io::println(::fast_io::u8c_stdout(), - u8"Original: ", ustr, - u8"\nUppercase: ", ustr_upper, - u8"\nLowercase: ", ustr_lower, - u8"\nNumbers (unchanged): ", numbers, - u8"\nSymbols (unchanged): ", symbols, - u8"\nEmpty string: ", empty); + // Print all results in one println + ::fast_io::io::println(::fast_io::u8c_stdout(), + u8"Original: ", ustr, + u8"\nUppercase: ", ustr_upper, + u8"\nLowercase: ", ustr_lower, + u8"\nNumbers (unchanged): ", numbers, + u8"\nSymbols (unchanged): ", symbols, + u8"\nEmpty string: ", empty); - return 0; + return 0; }