From deee577c1fe016d693073789180d064f915752ea Mon Sep 17 00:00:00 2001 From: ado Date: Mon, 7 Aug 2023 14:11:06 +0200 Subject: [PATCH 1/2] Update conversion for integral values to use std::from_chars --- include/ss/extract.hpp | 193 ++--------------------------------------- 1 file changed, 7 insertions(+), 186 deletions(-) diff --git a/include/ss/extract.hpp b/include/ss/extract.hpp index f630477..246ea9a 100644 --- a/include/ss/extract.hpp +++ b/include/ss/extract.hpp @@ -3,11 +3,11 @@ #include "type_traits.hpp" #include #include -#include #include #include #include #include +#include #ifndef SSP_DISABLE_FAST_FLOAT #include @@ -73,195 +73,16 @@ std::enable_if_t, std::optional> to_num( #endif -inline std::optional from_char(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - return std::nullopt; -} - -#if defined(__clang__) && defined(__MINGW32__) && !defined(__MINGW64__) -#define MINGW32_CLANG -#endif - -// mingw32 clang does not support some of the builtin functions -#if (defined(__clang__) || defined(__GNUC__) || defined(__GUNG__)) && \ - !defined(MINGW32_CLANG) -//////////////// -// mul overflow detection -//////////////// -template -bool mul_overflow(T& result, T operand) { - return __builtin_mul_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(int& result, int operand) { - return __builtin_smul_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(long& result, long operand) { - return __builtin_smull_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(long long& result, long long operand) { - return __builtin_smulll_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(unsigned int& result, unsigned int operand) { - return __builtin_umul_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(unsigned long& result, unsigned long operand) { - return __builtin_umull_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(unsigned long long& result, - unsigned long long operand) { - return __builtin_umulll_overflow(result, operand, &result); -} - -//////////////// -// addition overflow detection -//////////////// - -template -inline bool add_overflow(T& result, T operand) { - return __builtin_add_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(int& result, int operand) { - return __builtin_sadd_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(long& result, long operand) { - return __builtin_saddl_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(long long& result, long long operand) { - return __builtin_saddll_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(unsigned int& result, unsigned int operand) { - return __builtin_uadd_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(unsigned long& result, unsigned long operand) { - return __builtin_uaddl_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(unsigned long long& result, - unsigned long long operand) { - return __builtin_uaddll_overflow(result, operand, &result); -} - -//////////////// -// substraction overflow detection -//////////////// -template -inline bool sub_overflow(T& result, T operand) { - return __builtin_sub_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(int& result, int operand) { - return __builtin_ssub_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(long& result, long operand) { - return __builtin_ssubl_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(long long& result, long long operand) { - return __builtin_ssubll_overflow(result, operand, &result); -} - -// Note: sub_overflow function should be unreachable for unsigned values -template <> -inline bool sub_overflow(unsigned int& result, unsigned int operand) { - return __builtin_usub_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(unsigned long& result, unsigned long operand) { - return __builtin_usubl_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(unsigned long long& result, - unsigned long long operand) { - return __builtin_usubll_overflow(result, operand, &result); -} - -template -bool shift_and_add_overflow(T& value, T digit, F add_last_digit_overflow) { - if (mul_overflow(value, 10) || add_last_digit_overflow(value, digit)) { - return true; - } - return false; -} -#else - -template -bool shift_and_add_overflow(T& value, T digit, U is_negative) { - digit = (is_negative) ? -digit : digit; - T old_value = value; - value = 10 * value + digit; - - T expected_old_value = (value - digit) / 10; - if (old_value != expected_old_value) { - return true; - } - return false; -} - -#endif - template std::enable_if_t, std::optional> to_num( - const char* begin, const char* end) { - if (begin == end) { + const char* const begin, const char* const end) { + T ret; + auto [ptr, ec] = std::from_chars(begin, end, ret); + + if (ec != std::errc() || ptr != end) { return std::nullopt; } - bool is_negative = false; - if constexpr (std::is_signed_v) { - is_negative = *begin == '-'; - if (is_negative) { - ++begin; - } - } - -#if (defined(__clang__) || defined(__GNUC__) || defined(__GUNG__)) && \ - !defined(MINGW32_CLANG) - auto add_last_digit_overflow = - (is_negative) ? sub_overflow : add_overflow; -#else - auto add_last_digit_overflow = is_negative; -#endif - - T value = 0; - for (auto i = begin; i != end; ++i) { - if (auto digit = from_char(*i); - !digit || shift_and_add_overflow(value, digit.value(), - add_last_digit_overflow)) { - return std::nullopt; - } - } - - return value; + return ret; } //////////////// From 7b16f24d036e218df1f517f069ceb5236b115ba3 Mon Sep 17 00:00:00 2001 From: ado Date: Mon, 7 Aug 2023 15:29:50 +0200 Subject: [PATCH 2/2] [skip ci] Update version and spp.hpp --- CMakeLists.txt | 2 +- meson.build | 2 +- ssp.hpp | 193 ++----------------------------------------------- 3 files changed, 9 insertions(+), 188 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 67a3dd5..81e739a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.14) project( ssp - VERSION 1.5.0 + VERSION 1.6.0 DESCRIPTION "csv parser" HOMEPAGE_URL "https://github.com/red0124/ssp" LANGUAGES CXX diff --git a/meson.build b/meson.build index f8475c8..094c8e2 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ project( 'cpp_std=c++17', 'buildtype=debugoptimized', 'wrap_mode=forcefallback'], - version: '1.5.0', + version: '1.6.0', meson_version:'>=0.54.0') fast_float_dep = dependency('fast_float') diff --git a/ssp.hpp b/ssp.hpp index de0b8ba..e6fbdba 100644 --- a/ssp.hpp +++ b/ssp.hpp @@ -1,12 +1,12 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -1522,195 +1522,16 @@ std::enable_if_t, std::optional> to_num( #endif -inline std::optional from_char(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - return std::nullopt; -} - -#if defined(__clang__) && defined(__MINGW32__) && !defined(__MINGW64__) -#define MINGW32_CLANG -#endif - -// mingw32 clang does not support some of the builtin functions -#if (defined(__clang__) || defined(__GNUC__) || defined(__GUNG__)) && \ - !defined(MINGW32_CLANG) -//////////////// -// mul overflow detection -//////////////// -template -bool mul_overflow(T& result, T operand) { - return __builtin_mul_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(int& result, int operand) { - return __builtin_smul_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(long& result, long operand) { - return __builtin_smull_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(long long& result, long long operand) { - return __builtin_smulll_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(unsigned int& result, unsigned int operand) { - return __builtin_umul_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(unsigned long& result, unsigned long operand) { - return __builtin_umull_overflow(result, operand, &result); -} - -template <> -inline bool mul_overflow(unsigned long long& result, - unsigned long long operand) { - return __builtin_umulll_overflow(result, operand, &result); -} - -//////////////// -// addition overflow detection -//////////////// - -template -inline bool add_overflow(T& result, T operand) { - return __builtin_add_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(int& result, int operand) { - return __builtin_sadd_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(long& result, long operand) { - return __builtin_saddl_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(long long& result, long long operand) { - return __builtin_saddll_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(unsigned int& result, unsigned int operand) { - return __builtin_uadd_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(unsigned long& result, unsigned long operand) { - return __builtin_uaddl_overflow(result, operand, &result); -} - -template <> -inline bool add_overflow(unsigned long long& result, - unsigned long long operand) { - return __builtin_uaddll_overflow(result, operand, &result); -} - -//////////////// -// substraction overflow detection -//////////////// -template -inline bool sub_overflow(T& result, T operand) { - return __builtin_sub_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(int& result, int operand) { - return __builtin_ssub_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(long& result, long operand) { - return __builtin_ssubl_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(long long& result, long long operand) { - return __builtin_ssubll_overflow(result, operand, &result); -} - -// Note: sub_overflow function should be unreachable for unsigned values -template <> -inline bool sub_overflow(unsigned int& result, unsigned int operand) { - return __builtin_usub_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(unsigned long& result, unsigned long operand) { - return __builtin_usubl_overflow(result, operand, &result); -} - -template <> -inline bool sub_overflow(unsigned long long& result, - unsigned long long operand) { - return __builtin_usubll_overflow(result, operand, &result); -} - -template -bool shift_and_add_overflow(T& value, T digit, F add_last_digit_overflow) { - if (mul_overflow(value, 10) || add_last_digit_overflow(value, digit)) { - return true; - } - return false; -} -#else - -template -bool shift_and_add_overflow(T& value, T digit, U is_negative) { - digit = (is_negative) ? -digit : digit; - T old_value = value; - value = 10 * value + digit; - - T expected_old_value = (value - digit) / 10; - if (old_value != expected_old_value) { - return true; - } - return false; -} - -#endif - template std::enable_if_t, std::optional> to_num( - const char* begin, const char* end) { - if (begin == end) { + const char* const begin, const char* const end) { + T ret; + auto [ptr, ec] = std::from_chars(begin, end, ret); + + if (ec != std::errc() || ptr != end) { return std::nullopt; } - bool is_negative = false; - if constexpr (std::is_signed_v) { - is_negative = *begin == '-'; - if (is_negative) { - ++begin; - } - } - -#if (defined(__clang__) || defined(__GNUC__) || defined(__GUNG__)) && \ - !defined(MINGW32_CLANG) - auto add_last_digit_overflow = - (is_negative) ? sub_overflow : add_overflow; -#else - auto add_last_digit_overflow = is_negative; -#endif - - T value = 0; - for (auto i = begin; i != end; ++i) { - if (auto digit = from_char(*i); - !digit || shift_and_add_overflow(value, digit.value(), - add_last_digit_overflow)) { - return std::nullopt; - } - } - - return value; + return ret; } ////////////////