Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion benchmark/0022.from_chars/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ FetchContent_MakeAvailable(fast_float)

add_executable(benchmark.0022.from_chars ${CMAKE_CURRENT_LIST_DIR}/atoi_vs_from_chars.cc)
target_include_directories(benchmark.0022.from_chars PRIVATE ${CMAKE_SOURCE_DIR}/include)

target_compile_features(benchmark.0022.from_chars PRIVATE cxx_std_20)

# Prefer official target if provided by fast_float; otherwise include headers directly
Expand All @@ -22,3 +21,16 @@ else()
target_include_directories(benchmark.0022.from_chars PRIVATE ${fast_float_SOURCE_DIR}/include)
endif()
endif()

add_executable(benchmark.0022.from_chars_hex ${CMAKE_CURRENT_LIST_DIR}/atoi_vs_from_chars_hex.cc)
target_include_directories(benchmark.0022.from_chars_hex PRIVATE ${CMAKE_SOURCE_DIR}/include)
target_compile_features(benchmark.0022.from_chars_hex PRIVATE cxx_std_20)

if (TARGET fast_float::fast_float)
target_link_libraries(benchmark.0022.from_chars_hex PRIVATE fast_float::fast_float)
else()
FetchContent_GetProperties(fast_float)
if (fast_float_SOURCE_DIR)
target_include_directories(benchmark.0022.from_chars_hex PRIVATE ${fast_float_SOURCE_DIR}/include)
endif()
endif()
144 changes: 144 additions & 0 deletions benchmark/0022.from_chars/atoi_vs_from_chars_hex.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include <fast_io.h>
#include <fast_io_device.h>
#include <fast_io_driver/timer.h>
#include <vector>
#include <string>
#include <fast_io_dsal/string.h>
#include <charconv>
#include <cstdlib>
#include <fast_float/fast_float.h>

using namespace fast_io::io;

static std::string make_hex_numbers_buffer(std::size_t n)
{
std::string s;
s.reserve(n * 8);
for (std::size_t i{}; i != n; ++i)
{
auto old = s.size();
s.resize(old + 32);
auto *first = s.data() + old;
auto *last = s.data() + s.size();
auto res = std::to_chars(first, last - 1, i, 16);
// mix lowercase/uppercase hex digits in the buffer
if ((i & 1u) != 0u)
{
for (auto p = first; p != res.ptr; ++p)
{
if (*p >= 'a' && *p <= 'f')
{
*p = static_cast<char>(*p - 'a' + 'A');
}
}
}
*res.ptr = '\n';
s.resize(static_cast<std::size_t>(res.ptr - s.data() + 1));
}
return s;
}

int main()
{
constexpr std::size_t N = 10'000'000;
auto buf = make_hex_numbers_buffer(N);
char const *begin = buf.data();
char const *end = buf.data() + buf.size();

{
std::size_t lines{};
for (char const *p = begin; p < end; ++p)
{
lines += (*p == '\n');
}
fast_io::println("lines=", lines);
}

// strtoul (hex)
{
fast_io::timer t(u8"strtoul_hex");
std::uint64_t sum{};
char const *p = begin;
while (p < end)
{
char *endptr{};
auto v = std::strtoul(p, &endptr, 16);
sum += static_cast<std::uint64_t>(v);
p = endptr;
if (p < end && *p == '\n')
{
++p;
}
}
std::uint64_t volatile sink = sum;
(void)sink;
}

// std::from_chars (hex)
{
fast_io::timer t(u8"std_from_chars_hex");
std::uint64_t sum{};
char const *p = begin;
while (p < end)
{
std::uint64_t v{};
auto res = std::from_chars(p, end, v, 16);
sum += v;
p = res.ptr;
if (p < end && *p == '\n')
{
++p;
}
}
std::uint64_t volatile sink = sum;
(void)sink;
}

// fast_io char_digit_to_literal (hex)
{
fast_io::timer t(u8"fastio_char_digit_to_literal_hex");
std::uint64_t sum{};
char const *p = begin;
while (p < end)
{
using UCh = std::make_unsigned_t<char>;
std::uint64_t v{};
char const *q = p;
while (q < end && *q != '\n')
{
UCh ch = static_cast<UCh>(*q);
if (fast_io::details::char_digit_to_literal<16, char>(ch))
{
break;
}
v = (v << 4) + static_cast<std::uint64_t>(ch);
++q;
}
sum += v;
p = (q < end ? q + 1 : q);
}
std::uint64_t volatile sink = sum;
(void)sink;
}

// fast_float (hex)
{
fast_io::timer t(u8"fast_float_from_chars_hex");
std::uint64_t sum{};
char const *p = begin;
while (p < end)
{
std::uint64_t v{};
auto res = fast_float::from_chars(p, end, v, 16);
sum += v;
p = res.ptr;
if (p < end && *p == '\n')
{
++p;
}
}
std::uint64_t volatile sink = sum;
(void)sink;
}
}

40 changes: 35 additions & 5 deletions include/fast_io_hosted/platforms/posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -1211,17 +1211,47 @@ struct posix_file_factory FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
{
using native_handle_type = int;
int fd{-1};
inline explicit constexpr posix_file_factory(int v) noexcept
: fd(v) {};
inline posix_file_factory(posix_file_factory const &) = delete;
inline posix_file_factory &operator=(posix_file_factory const &) = delete;
inline ~posix_file_factory()
inline constexpr posix_file_factory() noexcept = default;
inline explicit constexpr posix_file_factory(int v) noexcept : fd(v)
{}
inline constexpr posix_file_factory(posix_file_factory const &) = delete;
inline constexpr posix_file_factory &operator=(posix_file_factory const &) = delete;
inline constexpr posix_file_factory(posix_file_factory &&other) noexcept
: fd(other.fd)
{
other.fd = -1;
}
inline constexpr posix_file_factory &operator=(posix_file_factory &&other) noexcept
{
if (__builtin_addressof(other) == this) [[unlikely]]
{
return *this;
}
if (this->fd != -1) [[likely]]
{
::fast_io::details::sys_close(this->fd);
}
this->fd = other.fd;
other.fd = -1;
return *this;
}
inline constexpr ~posix_file_factory()
{
if (fd != -1) [[likely]]
{
::fast_io::details::sys_close(fd);
}
}
inline constexpr native_handle_type native_handle() const noexcept
{
return this->fd;
}
inline constexpr native_handle_type release() noexcept
{
auto curr_fd{this->fd};
this->fd = -1;
return curr_fd;
}
};

template <::fast_io::posix_family family, ::std::integral ch_type>
Expand Down
42 changes: 36 additions & 6 deletions include/fast_io_hosted/platforms/win32_network/socket_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct win32_socket_event_guard_t
return *this;
}

if(curr_handle) [[likely]]
if (curr_handle) [[likely]]
{
::fast_io::win32::WSACloseEvent(curr_handle);
}
Expand Down Expand Up @@ -534,19 +534,49 @@ inline ::std::size_t open_win32_socket_impl(sock_family d, sock_type t, open_mod
struct win32_socket_factory FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
{
using native_handle_type = ::std::size_t;
::std::size_t hsocket{};
::std::size_t hsocket{SIZE_MAX};
inline constexpr win32_socket_factory() noexcept = default;
inline explicit constexpr win32_socket_factory(::std::size_t v) noexcept
: hsocket(v)
{}
inline win32_socket_factory(win32_socket_factory const &) = delete;
inline win32_socket_factory &operator=(win32_socket_factory const &) = delete;
inline ~win32_socket_factory()
inline constexpr win32_socket_factory(win32_socket_factory const &) = delete;
inline constexpr win32_socket_factory &operator=(win32_socket_factory const &) = delete;
inline constexpr win32_socket_factory(win32_socket_factory &&other) noexcept
: hsocket(other.hsocket)
{
other.hsocket = SIZE_MAX;
}
inline constexpr win32_socket_factory &operator=(win32_socket_factory &&other) noexcept
{
if (__builtin_addressof(other) == this) [[unlikely]]
{
return *this;
}
if (hsocket != SIZE_MAX) [[likely]]
{
::fast_io::win32::closesocket(hsocket);
}
hsocket = other.hsocket;
other.hsocket = SIZE_MAX;
return *this;
}
inline constexpr ~win32_socket_factory()
{
if (hsocket) [[likely]]
if (hsocket != SIZE_MAX) [[likely]]
{
::fast_io::win32::closesocket(hsocket);
}
}
inline constexpr native_handle_type native_handle() const noexcept
{
return hsocket;
}
inline constexpr native_handle_type release() noexcept
{
native_handle_type temp{hsocket};
hsocket = SIZE_MAX;
return temp;
}
};

template <win32_family family, ::std::integral ch_type>
Expand Down