mirror of https://github.com/orefkov/simstr.git
Доработана конвертация в числа. Обновлена версия и результаты бенчмарков.
This commit is contained in:
parent
573ffd247e
commit
13b31fdc4b
|
|
@ -5,8 +5,8 @@ include(FetchContent)
|
||||||
|
|
||||||
project(
|
project(
|
||||||
simstr
|
simstr
|
||||||
VERSION 1.2.5
|
VERSION 1.2.6
|
||||||
DESCRIPTION "Yet another string library"
|
DESCRIPTION "Yet another modern C++ string library"
|
||||||
HOMEPAGE_URL "https://github.com/orefkov/simstr"
|
HOMEPAGE_URL "https://github.com/orefkov/simstr"
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -176,9 +176,6 @@ void ToIntStr0(benchmark::State& state, const std::string& s, int c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToIntFromChars10(benchmark::State& state, const std::string_view& s, int c) {
|
void ToIntFromChars10(benchmark::State& state, const std::string_view& s, int c) {
|
||||||
//#ifdef __EMSCRIPTEN__
|
|
||||||
//state.SkipWithError("not implemented");
|
|
||||||
//#else
|
|
||||||
for (auto _: state) {
|
for (auto _: state) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
std::from_chars(s.data(), s.data() + s.size(), res, 10);
|
std::from_chars(s.data(), s.data() + s.size(), res, 10);
|
||||||
|
|
@ -190,13 +187,9 @@ void ToIntFromChars10(benchmark::State& state, const std::string_view& s, int c)
|
||||||
#endif
|
#endif
|
||||||
benchmark::DoNotOptimize(res);
|
benchmark::DoNotOptimize(res);
|
||||||
}
|
}
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToIntFromChars16(benchmark::State& state, const std::string_view& s, int c) {
|
void ToIntFromChars16(benchmark::State& state, const std::string_view& s, int c) {
|
||||||
//#ifdef __EMSCRIPTEN__
|
|
||||||
// state.SkipWithError("not implemented");
|
|
||||||
//#else
|
|
||||||
for (auto _: state) {
|
for (auto _: state) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
std::from_chars(s.data(), s.data() + s.size(), res, 16);
|
std::from_chars(s.data(), s.data() + s.size(), res, 16);
|
||||||
|
|
@ -208,13 +201,12 @@ void ToIntFromChars16(benchmark::State& state, const std::string_view& s, int c)
|
||||||
#endif
|
#endif
|
||||||
benchmark::DoNotOptimize(res);
|
benchmark::DoNotOptimize(res);
|
||||||
}
|
}
|
||||||
//#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void ToIntSimStr10(benchmark::State& state, T t, int c) {
|
void ToIntSimStr10(benchmark::State& state, T t, int c) {
|
||||||
for (auto _: state) {
|
for (auto _: state) {
|
||||||
int res = std::get<0>(t. template to_int<int, true, 10, false, false>());
|
int res = t. template to_int<int, true, 10, false, false>().value;
|
||||||
#ifdef CHECK_RESULT
|
#ifdef CHECK_RESULT
|
||||||
if (res != c) {
|
if (res != c) {
|
||||||
state.SkipWithError("not equal");
|
state.SkipWithError("not equal");
|
||||||
|
|
@ -229,7 +221,7 @@ void ToIntSimStr10(benchmark::State& state, T t, int c) {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void ToIntSimStr16(benchmark::State& state, T t, int c) {
|
void ToIntSimStr16(benchmark::State& state, T t, int c) {
|
||||||
for (auto _: state) {
|
for (auto _: state) {
|
||||||
int res = std::get<0>(t. template to_int<int, true, 16, false, false>());
|
int res = t. template to_int<int, true, 16, false, false>().value;
|
||||||
#ifdef CHECK_RESULT
|
#ifdef CHECK_RESULT
|
||||||
if (res != c) {
|
if (res != c) {
|
||||||
state.SkipWithError("not equal");
|
state.SkipWithError("not equal");
|
||||||
|
|
@ -244,7 +236,7 @@ void ToIntSimStr16(benchmark::State& state, T t, int c) {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void ToIntSimStr0(benchmark::State& state, T t, int c) {
|
void ToIntSimStr0(benchmark::State& state, T t, int c) {
|
||||||
for (auto _: state) {
|
for (auto _: state) {
|
||||||
int res = std::get<0>(t. template to_int<int>());
|
int res = t. template to_int<int>().value;
|
||||||
#ifdef CHECK_RESULT
|
#ifdef CHECK_RESULT
|
||||||
if (res != c) {
|
if (res != c) {
|
||||||
state.SkipWithError("not equal");
|
state.SkipWithError("not equal");
|
||||||
|
|
@ -258,7 +250,7 @@ void ToIntSimStr0(benchmark::State& state, T t, int c) {
|
||||||
|
|
||||||
void ToIntNoOverflow(benchmark::State& state, ssa t, int c) {
|
void ToIntNoOverflow(benchmark::State& state, ssa t, int c) {
|
||||||
for (auto _: state) {
|
for (auto _: state) {
|
||||||
int res = std::get<0>(t.to_int<int, false>());
|
int res = t.to_int<int, false>().value;
|
||||||
#ifdef CHECK_RESULT
|
#ifdef CHECK_RESULT
|
||||||
if (res != c) {
|
if (res != c) {
|
||||||
state.SkipWithError("not equal");
|
state.SkipWithError("not equal");
|
||||||
|
|
@ -287,6 +279,63 @@ BENCHMARK_CAPTURE(ToIntStr0, , std::string{" 123456789"}, 123456789)
|
||||||
BENCHMARK_CAPTURE(ToIntSimStr0, , stringa{" 123456789"}, 123456789) ->Name("stringa s = \" 123456789\"; int res = s.to_int<int>; // Check overflow");
|
BENCHMARK_CAPTURE(ToIntSimStr0, , stringa{" 123456789"}, 123456789) ->Name("stringa s = \" 123456789\"; int res = s.to_int<int>; // Check overflow");
|
||||||
BENCHMARK_CAPTURE(ToIntNoOverflow, , ssa{" 123456789"}, 123456789) ->Name("ssa s = \" 123456789\"; int res = s.to_int<int, false>; // No check overflow");
|
BENCHMARK_CAPTURE(ToIntNoOverflow, , ssa{" 123456789"}, 123456789) ->Name("ssa s = \" 123456789\"; int res = s.to_int<int, false>; // No check overflow");
|
||||||
|
|
||||||
|
void ToDoubleStr(benchmark::State& state, const std::string& s, double c) {
|
||||||
|
for (auto _: state) {
|
||||||
|
char* ptr = nullptr;
|
||||||
|
double res = std::strtod(s.c_str(), &ptr);
|
||||||
|
if (ptr == s.c_str()) {
|
||||||
|
state.SkipWithError("not equal");
|
||||||
|
}
|
||||||
|
#ifdef CHECK_RESULT
|
||||||
|
if (res != c) {
|
||||||
|
state.SkipWithError("not equal");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
benchmark::DoNotOptimize(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToDoubleFromChars(benchmark::State& state, const std::string_view& s, double c) {
|
||||||
|
for (auto _: state) {
|
||||||
|
double res = 0;
|
||||||
|
if (std::from_chars(s.data(), s.data() + s.size(), res).ec != std::errc{}) {
|
||||||
|
state.SkipWithError("not equal");
|
||||||
|
}
|
||||||
|
#ifdef CHECK_RESULT
|
||||||
|
if (res != c) {
|
||||||
|
state.SkipWithError("not equal");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
benchmark::DoNotOptimize(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void ToDoubleSimStr(benchmark::State& state, T t, double c) {
|
||||||
|
for (auto _: state) {
|
||||||
|
auto r = t.template to_double<false>();
|
||||||
|
if (!r) {
|
||||||
|
state.SkipWithError("not equal");
|
||||||
|
}
|
||||||
|
double res = *r;
|
||||||
|
#ifdef CHECK_RESULT
|
||||||
|
if (res != c) {
|
||||||
|
state.SkipWithError("not equal");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
benchmark::DoNotOptimize(res);
|
||||||
|
benchmark::DoNotOptimize(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK(__)->Name("----- Convert to double '1234.567e10' ---------")->Repetitions(1);
|
||||||
|
BENCHMARK_CAPTURE(ToDoubleStr, , std::string{"1234.567e10"}, 1234.567e10) ->Name("std::string s = \"1234.567e10\"; double res = std::strtod(s.c_str(), nullptr);");
|
||||||
|
BENCHMARK_CAPTURE(ToDoubleFromChars, , std::string_view{"1234.567e10"}, 1234.567e10) ->Name("std::string_view s = \"1234.567e10\"; std::from_chars(s.data(), s.data() + s.size(), res);");
|
||||||
|
BENCHMARK_CAPTURE(ToDoubleSimStr, , ssa{"1234.567e10"}, 1234.567e10) ->Name("ssa s = \"1234.567e10\"; double res = *s.to_double()");
|
||||||
|
|
||||||
void AppendStreamConstLiteral(benchmark::State& state) {
|
void AppendStreamConstLiteral(benchmark::State& state) {
|
||||||
for (auto _: state) {
|
for (auto _: state) {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,9 @@ results_vector get_results_infos() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results_vector results;
|
results_vector results;
|
||||||
|
|
||||||
if (fileNames.size()) {
|
if (fileNames.size()) {
|
||||||
std::sort(fileNames.begin(), fileNames.end());
|
std::sort(fileNames.begin(), fileNames.end());
|
||||||
results.reserve(fileNames.size());
|
results.reserve(fileNames.size());
|
||||||
|
|
@ -95,7 +95,7 @@ results_vector get_results_infos() {
|
||||||
// В начале имени файла может идти число и дефис, для сортировки, уберём их
|
// В начале имени файла может идти число и дефис, для сортировки, уберём их
|
||||||
// At the beginning of the file name there can be a number and a hyphen, for sorting, remove them
|
// At the beginning of the file name there can be a number and a hyphen, for sorting, remove them
|
||||||
if (auto delimeter = fileName.find('-'); delimeter + 1 > 1) {
|
if (auto delimeter = fileName.find('-'); delimeter + 1 > 1) {
|
||||||
if (std::get<1>(fileName(0, delimeter).to_int<unsigned, false, 10, false, false>()) == IntConvertResult::Success) {
|
if (fileName(0, delimeter).to_int<unsigned, false, 10, false, false>().ec == IntConvertResult::Success) {
|
||||||
fileName.remove_prefix(delimeter + 1);
|
fileName.remove_prefix(delimeter + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +187,7 @@ ssa extract_source_for_benchmark(ssa benchName, ssa sourceText) {
|
||||||
static hashStrMapA<stringa> textes;
|
static hashStrMapA<stringa> textes;
|
||||||
|
|
||||||
size_t delim = benchName.find_last('/');
|
size_t delim = benchName.find_last('/');
|
||||||
if (delim != str::npos && std::get<1>(benchName(delim + 1).to_int<unsigned, false, 10, false, false>()) == IntConvertResult::Success) {
|
if (delim != str::npos && benchName(delim + 1).to_int<unsigned, false, 10, false, false>().ec == IntConvertResult::Success) {
|
||||||
benchName.len = delim;
|
benchName.len = delim;
|
||||||
}
|
}
|
||||||
auto [it, not_exist] = textes.try_emplace(benchName);
|
auto [it, not_exist] = textes.try_emplace(benchName);
|
||||||
|
|
@ -326,6 +326,9 @@ void write_benchmarks(out_t& out, const results_vector& results, ssa sourceText,
|
||||||
throw std::runtime_error{"Not expected end of file"};
|
throw std::runtime_error{"Not expected end of file"};
|
||||||
}
|
}
|
||||||
line = splitters[idx].next();
|
line = splitters[idx].next();
|
||||||
|
if (line.starts_with("std::unordered_map<std::string, size_t> emplace & find std::string_view;_cv")) {
|
||||||
|
int t = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needFooter) {
|
if (needFooter) {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -293,6 +293,13 @@ constexpr unsigned digit_width() {
|
||||||
template<typename T, unsigned Base>
|
template<typename T, unsigned Base>
|
||||||
constexpr unsigned max_overflow_digits = (sizeof(T) * CHAR_BIT) / digit_width<Base>();
|
constexpr unsigned max_overflow_digits = (sizeof(T) * CHAR_BIT) / digit_width<Base>();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct convert_result {
|
||||||
|
T value;
|
||||||
|
IntConvertResult ec;
|
||||||
|
size_t read;
|
||||||
|
};
|
||||||
|
|
||||||
struct int_convert { // NOLINT
|
struct int_convert { // NOLINT
|
||||||
inline static const uint8_t NUMBERS[] = {
|
inline static const uint8_t NUMBERS[] = {
|
||||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
|
@ -322,7 +329,7 @@ struct int_convert { // NOLINT
|
||||||
|
|
||||||
template<typename K, ToIntNumber T, unsigned Base, bool CheckOverflow>
|
template<typename K, ToIntNumber T, unsigned Base, bool CheckOverflow>
|
||||||
requires(Base != 0)
|
requires(Base != 0)
|
||||||
static std::tuple<T, IntConvertResult, size_t> parse(const K* start, const K* current, const K* end, bool negate) {
|
static convert_result<T> parse(const K* start, const K* current, const K* end, bool negate) {
|
||||||
using u_type = std::make_unsigned_t<T>;
|
using u_type = std::make_unsigned_t<T>;
|
||||||
#ifndef HAS_BUILTIN_OVERFLOW
|
#ifndef HAS_BUILTIN_OVERFLOW
|
||||||
u_type maxMult = 0, maxAdd = 0;
|
u_type maxMult = 0, maxAdd = 0;
|
||||||
|
|
@ -406,7 +413,7 @@ struct int_convert { // NOLINT
|
||||||
if (error == IntConvertResult::NotNumber && current > from) {
|
if (error == IntConvertResult::NotNumber && current > from) {
|
||||||
error = IntConvertResult::BadSymbolAtTail;
|
error = IntConvertResult::BadSymbolAtTail;
|
||||||
}
|
}
|
||||||
return {result, error, current - start};
|
return {result, error, size_t(current - start)};
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// Если Base = 0 - то пытается определить основание по префиксу 0[xX] как 16, 0 как 8, иначе 10
|
// Если Base = 0 - то пытается определить основание по префиксу 0[xX] как 16, 0 как 8, иначе 10
|
||||||
|
|
@ -415,7 +422,7 @@ public:
|
||||||
// If Base = -1 - then tries to determine the base by the prefix 0[xX] as 16, 0[bB] as 2, 0[oO] or 0 as 8, otherwise 10
|
// If Base = -1 - then tries to determine the base by the prefix 0[xX] as 16, 0[bB] as 2, 0[oO] or 0 as 8, otherwise 10
|
||||||
template<typename K, ToIntNumber T, unsigned Base = 0, bool CheckOverflow = true, bool SkipWs = true, bool AllowSign = true>
|
template<typename K, ToIntNumber T, unsigned Base = 0, bool CheckOverflow = true, bool SkipWs = true, bool AllowSign = true>
|
||||||
requires(Base == -1 || (Base < 37 && Base != 1))
|
requires(Base == -1 || (Base < 37 && Base != 1))
|
||||||
static std::tuple<T, IntConvertResult, size_t> to_integer(const K* start, size_t len) noexcept {
|
static convert_result<T> to_integer(const K* start, size_t len) noexcept {
|
||||||
const K *ptr = start, *end = ptr + len;
|
const K *ptr = start, *end = ptr + len;
|
||||||
bool negate = false;
|
bool negate = false;
|
||||||
if constexpr (SkipWs) {
|
if constexpr (SkipWs) {
|
||||||
|
|
@ -467,13 +474,13 @@ public:
|
||||||
}
|
}
|
||||||
return parse<K, T, 8, CheckOverflow>(start, --ptr, end, negate);
|
return parse<K, T, 8, CheckOverflow>(start, --ptr, end, negate);
|
||||||
}
|
}
|
||||||
return {0, IntConvertResult::Success, ptr - start};
|
return {0, IntConvertResult::Success, size_t(ptr - start)};
|
||||||
}
|
}
|
||||||
return parse<K, T, 10, CheckOverflow>(start, ptr, end, negate);
|
return parse<K, T, 10, CheckOverflow>(start, ptr, end, negate);
|
||||||
} else
|
} else
|
||||||
return parse<K, T, Base, CheckOverflow>(start, ptr, end, negate);
|
return parse<K, T, Base, CheckOverflow>(start, ptr, end, negate);
|
||||||
}
|
}
|
||||||
return {0, IntConvertResult::NotNumber, ptr - start};
|
return {0, IntConvertResult::NotNumber, size_t(ptr - start)};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1439,7 +1446,7 @@ public:
|
||||||
* - в остальных случаях 10.
|
* - в остальных случаях 10.
|
||||||
* @tparam SkipWs - пропускать пробельные символы в начале строки. Пропускаются все символы с ASCII кодами <= 32.
|
* @tparam SkipWs - пропускать пробельные символы в начале строки. Пропускаются все символы с ASCII кодами <= 32.
|
||||||
* @tparam AllowSign - допустим ли знак '+' перед числом.
|
* @tparam AllowSign - допустим ли знак '+' перед числом.
|
||||||
* @return std::tuple<T, IntConvertResult, size_t> - кортеж из полученного числа, успешности преобразования и количестве обработанных символов.
|
* @return convert_result<T> - кортеж из полученного числа, успешности преобразования и количестве обработанных символов.
|
||||||
* @en @brief Convert a string to a number of the given type.
|
* @en @brief Convert a string to a number of the given type.
|
||||||
* @tparam T - the desired number type.
|
* @tparam T - the desired number type.
|
||||||
* @tparam CheckOverflow - check for overflow.
|
* @tparam CheckOverflow - check for overflow.
|
||||||
|
|
@ -1452,10 +1459,10 @@ public:
|
||||||
* - in other cases 10.
|
* - in other cases 10.
|
||||||
* @tparam SkipWs - skip whitespace characters at the beginning of the line. All characters with ASCII codes <= 32 are skipped.
|
* @tparam SkipWs - skip whitespace characters at the beginning of the line. All characters with ASCII codes <= 32 are skipped.
|
||||||
* @tparam AllowSign - whether the '+' sign is allowed before a number.
|
* @tparam AllowSign - whether the '+' sign is allowed before a number.
|
||||||
* @return std::tuple<T, IntConvertResult, size_t> - a tuple of the received number, the success of the conversion and the number of characters processed.
|
* @return convert_result<T> - a tuple of the received number, the success of the conversion and the number of characters processed.
|
||||||
*/
|
*/
|
||||||
template<ToIntNumber T, bool CheckOverflow = true, unsigned Base = 0, bool SkipWs = true, bool AllowSign = true>
|
template<ToIntNumber T, bool CheckOverflow = true, unsigned Base = 0, bool SkipWs = true, bool AllowSign = true>
|
||||||
std::tuple<T, IntConvertResult, size_t> to_int() const noexcept {
|
convert_result<T> to_int() const noexcept {
|
||||||
return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
|
return int_convert::to_integer<K, T, Base, CheckOverflow, SkipWs, AllowSign>(_str(), _len());
|
||||||
}
|
}
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -1464,7 +1471,7 @@ public:
|
||||||
* @en @brief Convert string to double.
|
* @en @brief Convert string to double.
|
||||||
* @return std::optional<double>.
|
* @return std::optional<double>.
|
||||||
*/
|
*/
|
||||||
template<bool SkipWS = true>
|
template<bool SkipWS = true, bool AllowPlus = true>
|
||||||
std::optional<double> to_double() const noexcept {
|
std::optional<double> to_double() const noexcept {
|
||||||
size_t len = _len();
|
size_t len = _len();
|
||||||
const K* ptr = _str();
|
const K* ptr = _str();
|
||||||
|
|
@ -1474,15 +1481,30 @@ public:
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (len) {
|
if constexpr (AllowPlus) {
|
||||||
return impl_to_double(ptr, ptr + len);
|
if (len && *ptr == K('+')) {
|
||||||
|
ptr++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {};
|
if (!len) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
#ifdef __linux__
|
||||||
|
if constexpr(sizeof(K) == 1) {
|
||||||
|
double d{};
|
||||||
|
if (std::from_chars(ptr, ptr + len, d).ec == std::errc{}) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return impl_to_double(ptr, ptr + len);
|
||||||
}
|
}
|
||||||
/*!
|
/*!
|
||||||
* @ru @brief Преобразовать строку в double.
|
* @ru @brief Преобразовать строку в 16ричной записи в double. Пока работает только для char.
|
||||||
* @return std::optional<double>.
|
* @return std::optional<double>.
|
||||||
* @en @brief Convert string to double.
|
* @en @brief Convert string in hex form to double.
|
||||||
* @return std::optional<double>.
|
* @return std::optional<double>.
|
||||||
*/
|
*/
|
||||||
template<bool SkipWS = true> requires (sizeof(K) == 1)
|
template<bool SkipWS = true> requires (sizeof(K) == 1)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
# simstr - String object and function library
|
# simstr - String object and function library
|
||||||
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
|
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
|
||||||
|
|
||||||
Version 1.2.5.
|
Version 1.2.6.
|
||||||
|
|
||||||
<span class="obfuscator"><a href="readme_ru.md">On Russian | По-русски</a></span>
|
<span class="obfuscator"><a href="readme_ru.md">On Russian | По-русски</a></span>
|
||||||
|
|
||||||
This library contains the implementation of several types of string objects and various algorithms for working with strings.
|
This library contains the modern implementation of several types of string objects and various algorithms for working with strings.
|
||||||
|
|
||||||
The goal of the library is to make working with strings in C++ as simple and easy as in many other languages, especially
|
The goal of the library is to make working with strings in C++ as simple and easy as in many other languages, especially
|
||||||
scripting languages, while maintaining optimality and performance at the level of C and C++, and even improving them.
|
scripting languages, while maintaining optimality and performance at the level of C and C++, and even improving them.
|
||||||
|
|
@ -47,8 +47,7 @@ then the simstr approach will also be clear to you.
|
||||||
- Parsing integers with the possibility of "fine" tuning during compilation - you can set options for checking overflow,
|
- Parsing integers with the possibility of "fine" tuning during compilation - you can set options for checking overflow,
|
||||||
skipping whitespace characters, a specific radix or auto-selection by prefixes `0x`, `0`, `0b`, `0o`,
|
skipping whitespace characters, a specific radix or auto-selection by prefixes `0x`, `0`, `0b`, `0o`,
|
||||||
admissibility of the `+` sign. Parsing is implemented for all types of strings and characters.
|
admissibility of the `+` sign. Parsing is implemented for all types of strings and characters.
|
||||||
- Parsing double is currently implemented by calling the standard library and only works for `char`, `wchar_t` strings and types compatible with
|
- Parsing doubles for all types of characters.
|
||||||
`wchar_t` in size.
|
|
||||||
- Minimal Unicode support is included when converting `upper`, `lower` and case-insensitive string comparison.
|
- Minimal Unicode support is included when converting `upper`, `lower` and case-insensitive string comparison.
|
||||||
It only works for characters in the first plane of Unicode (up to 0xFFFF), and when changing case, it does not take into account cases where one code point
|
It only works for characters in the first plane of Unicode (up to 0xFFFF), and when changing case, it does not take into account cases where one code point
|
||||||
can be converted into several, that is, the case conversion of characters corresponds to `std::towupper`, `std::towlower` for the unicode locale, only faster and can work with any type of characters.
|
can be converted into several, that is, the case conversion of characters corresponds to `std::towupper`, `std::towlower` for the unicode locale, only faster and can work with any type of characters.
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
# simstr - библиотека строковых объектов и функций
|
# simstr - библиотека строковых объектов и функций
|
||||||
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
|
[](https://github.com/orefkov/simstr/actions/workflows/cmake-multi-platform.yml)
|
||||||
|
|
||||||
Версия 1.2.5.
|
Версия 1.2.6.
|
||||||
|
|
||||||
<span class="obfuscator"><a href="readme.md">On English | По-английски</a></span>
|
<span class="obfuscator"><a href="readme.md">On English | По-английски</a></span>
|
||||||
|
|
||||||
В этой библиотеке содержится реализация нескольких видов строковых объектов и различных алгоритмов для работы со строками.
|
В этой библиотеке содержится современная реализация нескольких видов строковых объектов и различных алгоритмов для работы со строками.
|
||||||
|
|
||||||
Цель библиотеки - сделать работу со строками в С++ такой же простой и лёгкой, как во множестве других языков, особенно
|
Цель библиотеки - сделать работу со строками в С++ такой же простой и лёгкой, как во множестве других языков, особенно
|
||||||
скриптовых, но при этом сохранив оптимальность и производительность на уровне С и C++, и даже улучшив их.
|
скриптовых, но при этом сохранив оптимальность и производительность на уровне С и C++, и даже улучшив их.
|
||||||
|
|
@ -47,8 +47,7 @@
|
||||||
- Парсинг целых чисел с возможностью "тонкой" настройки при компиляции - можно задавать опции проверки переполнения,
|
- Парсинг целых чисел с возможностью "тонкой" настройки при компиляции - можно задавать опции проверки переполнения,
|
||||||
пропуск пробельных символов, конкретное основание счисления либо автовыбор по префиксам `0x`, `0`, `0b`, `0o`,
|
пропуск пробельных символов, конкретное основание счисления либо автовыбор по префиксам `0x`, `0`, `0b`, `0o`,
|
||||||
допустимость знака `+`. Парсинг реализован для всех видов строк и символов.
|
допустимость знака `+`. Парсинг реализован для всех видов строк и символов.
|
||||||
- Парсинг double пока реализован вызовом стандартной библиотеки и работает только для строк `char`, `wchar_t` и совместимых с
|
- Парсинг double для всех типов символов.
|
||||||
`wchar_t` по размеру типов.
|
|
||||||
- Содержится минимальная поддержка Unicode при преобразовании `upper`, `lower` и регистро-независимом сравнении строк.
|
- Содержится минимальная поддержка Unicode при преобразовании `upper`, `lower` и регистро-независимом сравнении строк.
|
||||||
Работает только для символов первой плоскости Unicode (до 0xFFFF), а при смене регистра не учитываются случаи, когда один code point
|
Работает только для символов первой плоскости Unicode (до 0xFFFF), а при смене регистра не учитываются случаи, когда один code point
|
||||||
может преобразовываться в несколько, то есть преобразование регистра символов соответствует `std::towupper`, `std::towlower` для unicode локали, только быстрее и может работать с любым видом символов.
|
может преобразовываться в несколько, то есть преобразование регистра символов соответствует `std::towupper`, `std::towlower` для unicode локали, только быстрее и может работать с любым видом символов.
|
||||||
|
|
|
||||||
|
|
@ -544,6 +544,7 @@ SIMSTR_API size_t unicode_traits<u32s>::hashiu(const u32s* src, size_t l) {
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Based on simdjson sources https://github.com/simdjson/simdjson/blob/667d0ed3c77f55cbda2082b034168d69898d1f88/include/simdjson/compile_time_json-inl.h#L189
|
// Based on simdjson sources https://github.com/simdjson/simdjson/blob/667d0ed3c77f55cbda2082b034168d69898d1f88/include/simdjson/compile_time_json-inl.h#L189
|
||||||
|
|
||||||
|
|
@ -1385,18 +1386,22 @@ SIMSTR_API std::optional<double> impl_to_double(const K* start, const K* end) {
|
||||||
return *pointer;
|
return *pointer;
|
||||||
};
|
};
|
||||||
const K* srcinit = start;
|
const K* srcinit = start;
|
||||||
bool negative = false;
|
bool negative = (get_value(start) == '-');
|
||||||
if (get_value(start) == '+') {
|
start += (uint8_t)negative;
|
||||||
start++;
|
if (end - start == 3) {
|
||||||
} else {
|
if (!negative && (start[0] | 0x20) == K('n')) {
|
||||||
negative = (get_value(start) == '-');
|
if ((start[1] | 0x20) == K('a') && (start[2] | 0x20) == K('n')) {
|
||||||
|
return std::nan("0");
|
||||||
|
}
|
||||||
|
} else if ((start[0] | 0x20) == K('i') && (start[1] | 0x20) == K('n') && (start[2] | 0x20) == K('f')) {
|
||||||
|
return negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
start += uint8_t(negative);
|
uint64_t digits = 0;
|
||||||
uint64_t i = 0;
|
|
||||||
const K* p = start;
|
const K* p = start;
|
||||||
p += parse_digit(get_value(p), i);
|
p += parse_digit(get_value(p), digits);
|
||||||
bool leading_zero = (i == 0);
|
bool leading_zero = (digits == 0);
|
||||||
while (parse_digit(get_value(p), i)) {
|
while (parse_digit(get_value(p), digits)) {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if (p == start) {
|
if (p == start) {
|
||||||
|
|
@ -1411,11 +1416,11 @@ SIMSTR_API std::optional<double> impl_to_double(const K* start, const K* end) {
|
||||||
if (get_value(p) == '.') {
|
if (get_value(p) == '.') {
|
||||||
p++;
|
p++;
|
||||||
const K* start_decimal_digits = p;
|
const K* start_decimal_digits = p;
|
||||||
if (!parse_digit(get_value(p), i)) {
|
if (!parse_digit(get_value(p), digits)) {
|
||||||
return {};
|
return {};
|
||||||
} // no decimal digits
|
} // no decimal digits
|
||||||
p++;
|
p++;
|
||||||
while (parse_digit(get_value(p), i)) {
|
while (parse_digit(get_value(p), digits)) {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
exponent = -(p - start_decimal_digits);
|
exponent = -(p - start_decimal_digits);
|
||||||
|
|
@ -1448,11 +1453,11 @@ SIMSTR_API std::optional<double> impl_to_double(const K* start, const K* end) {
|
||||||
exponent += exp_neg ? 0 - exp : exp;
|
exponent += exp_neg ? 0 - exp : exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exponent < smallest_power || exponent > largest_power) {
|
if (exponent < smallest_power || exponent > largest_power || p != end) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
double d;
|
double d;
|
||||||
if (!compute_float_64(exponent, i, negative, d)) {
|
if (!compute_float_64(exponent, digits, negative, d)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue