aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-03-10 16:43:04 +0800
committercrupest <crupest@outlook.com>2022-03-10 16:43:04 +0800
commit51f87e3ff980e62f9cb5ee656e5591412e2766eb (patch)
tree4101a0c00fd77dfc694c377ae2b69178a77cdb63
parent0b5c16f6b35f7144b34996d8c77f370bcbcf150c (diff)
downloadcru-51f87e3ff980e62f9cb5ee656e5591412e2766eb.tar.gz
cru-51f87e3ff980e62f9cb5ee656e5591412e2766eb.tar.bz2
cru-51f87e3ff980e62f9cb5ee656e5591412e2766eb.zip
...
-rw-r--r--include/cru/common/String.h34
-rw-r--r--include/cru/common/StringToNumberConverter.h19
-rw-r--r--src/common/String.cpp31
-rw-r--r--src/common/StringToNumberConverter.cpp41
4 files changed, 106 insertions, 19 deletions
diff --git a/include/cru/common/String.h b/include/cru/common/String.h
index 7bbbecfb..c1ea839c 100644
--- a/include/cru/common/String.h
+++ b/include/cru/common/String.h
@@ -11,6 +11,7 @@
#include <iterator>
#include <string>
#include <string_view>
+#include <type_traits>
#include <vector>
namespace cru {
@@ -212,6 +213,17 @@ class CRU_BASE_API String {
Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const;
Range RangeFromCodePointToCodeUnit(Range code_point_range) const;
+ template <typename TInteger>
+ std::enable_if_t<std::is_signed_v<TInteger>, TInteger> ParseToInteger(
+ Index* processed_characters_count, unsigned flags, int base) const;
+
+ int ParseToInt(Index* processed_characters_count = nullptr,
+ unsigned flags = StringToNumberFlags::kNoFlags,
+ int base = 0) const;
+ long long ParseToLongLong(Index* processed_characters_count = nullptr,
+ unsigned flags = StringToNumberFlags::kNoFlags,
+ int base = 0) const;
+
float ParseToFloat(Index* processed_characters_count = nullptr,
unsigned flags = StringToNumberFlags::kNoFlags) const;
double ParseToDouble(Index* processed_characters_count = nullptr,
@@ -339,6 +351,21 @@ class CRU_BASE_API StringView {
Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const;
Range RangeFromCodePointToCodeUnit(Range code_point_range) const;
+ template <typename TInteger>
+ std::enable_if_t<std::is_signed_v<TInteger>, TInteger> ParseToInteger(
+ Index* processed_characters_count, unsigned flags, int base) const {
+ auto result = StringToIntegerConverterImpl(flags, base)
+ .Parse(data(), size(), processed_characters_count);
+ return result.negate ? -result.value : result.value;
+ }
+
+ int ParseToInt(Index* processed_characters_count = nullptr,
+ unsigned flags = StringToNumberFlags::kNoFlags,
+ int base = 0) const;
+ long long ParseToLongLong(Index* processed_characters_count = nullptr,
+ unsigned flags = StringToNumberFlags::kNoFlags,
+ int base = 0) const;
+
float ParseToFloat(Index* processed_characters_count = nullptr,
unsigned flags = StringToNumberFlags::kNoFlags) const;
double ParseToDouble(Index* processed_characters_count = nullptr,
@@ -434,6 +461,13 @@ inline Index Utf16NextWord(StringView str, Index position,
String CRU_BASE_API ToLower(StringView s);
String CRU_BASE_API ToUpper(StringView s);
+
+template <typename TInteger>
+std::enable_if_t<std::is_signed_v<TInteger>, TInteger> String::ParseToInteger(
+ Index* processed_characters_count, unsigned flags, int base) const {
+ View().ParseToInteger<TInteger>(processed_characters_count, flags, base);
+}
+
} // namespace cru
template <>
diff --git a/include/cru/common/StringToNumberConverter.h b/include/cru/common/StringToNumberConverter.h
index b5118de6..f1baafee 100644
--- a/include/cru/common/StringToNumberConverter.h
+++ b/include/cru/common/StringToNumberConverter.h
@@ -4,7 +4,7 @@
#include <ostream>
namespace cru {
-struct StringToNumberFlags {
+struct CRU_BASE_API StringToNumberFlags {
constexpr static unsigned kNoFlags = 0;
constexpr static unsigned kAllowLeadingSpaces = 1 << 0;
constexpr static unsigned kAllowTrailingSpaces = 1 << 1;
@@ -13,7 +13,7 @@ struct StringToNumberFlags {
constexpr static unsigned kThrowOnError = 1 << 3;
};
-struct StringToIntegerConverterImplResult {
+struct CRU_BASE_API StringToIntegerConverterImplResult {
StringToIntegerConverterImplResult() = default;
StringToIntegerConverterImplResult(bool negate, unsigned long long value)
: negate(negate), value(value) {}
@@ -22,13 +22,15 @@ struct StringToIntegerConverterImplResult {
unsigned long long value;
};
-inline bool operator==(const StringToIntegerConverterImplResult& left,
- const StringToIntegerConverterImplResult& right) {
+inline bool CRU_BASE_API
+operator==(const StringToIntegerConverterImplResult& left,
+ const StringToIntegerConverterImplResult& right) {
return left.negate == right.negate && left.value == right.value;
}
-inline bool operator!=(const StringToIntegerConverterImplResult& left,
- const StringToIntegerConverterImplResult& right) {
+inline bool CRU_BASE_API
+operator!=(const StringToIntegerConverterImplResult& left,
+ const StringToIntegerConverterImplResult& right) {
return !(left == right);
}
@@ -41,7 +43,7 @@ inline std::ostream& operator<<(
/**
* \brief A converter that convert number into long long.
*/
-struct StringToIntegerConverterImpl {
+struct CRU_BASE_API StringToIntegerConverterImpl {
public:
explicit StringToIntegerConverterImpl(unsigned flags, int base = 0)
: flags(flags), base(base) {}
@@ -58,6 +60,9 @@ struct StringToIntegerConverterImpl {
StringToIntegerConverterImplResult Parse(
const char* str, Index size, Index* processed_characters_count) const;
+ StringToIntegerConverterImplResult Parse(
+ const char16_t* str, Index size, Index* processed_characters_count) const;
+
template <std::size_t Size>
StringToIntegerConverterImplResult Parse(
const char (&str)[Size], Index* processed_characters_count) const {
diff --git a/src/common/String.cpp b/src/common/String.cpp
index 908f64b6..bb31b987 100644
--- a/src/common/String.cpp
+++ b/src/common/String.cpp
@@ -2,6 +2,7 @@
#include <double-conversion/double-conversion.h>
#include <double-conversion/string-to-double.h>
#include "cru/common/Exception.h"
+#include "cru/common/StringToNumberConverter.h"
#include "cru/common/StringUtil.h"
#include <cmath>
@@ -313,6 +314,16 @@ Range String::RangeFromCodePointToCodeUnit(Range code_point_range) const {
return View().RangeFromCodePointToCodeUnit(code_point_range);
}
+int String::ParseToInt(Index* processed_characters_count, unsigned flags,
+ int base) const {
+ return View().ParseToInt(processed_characters_count, flags, base);
+}
+
+long long String::ParseToLongLong(Index* processed_characters_count,
+ unsigned flags, int base) const {
+ return View().ParseToLongLong(processed_characters_count, flags, base);
+}
+
float String::ParseToFloat(Index* processed_characters_count,
unsigned flags) const {
return View().ParseToFloat(processed_characters_count, flags);
@@ -517,6 +528,16 @@ std::string StringView::ToUtf8() const {
return result;
}
+int StringView::ParseToInt(Index* processed_characters_count, unsigned flags,
+ int base) const {
+ return ParseToInteger<int>(processed_characters_count, flags, base);
+}
+
+long long StringView::ParseToLongLong(Index* processed_characters_count,
+ unsigned flags, int base) const {
+ return ParseToInteger<long long>(processed_characters_count, flags, base);
+}
+
static int MapStringToDoubleFlags(int flags) {
int f = double_conversion::StringToDoubleConverter::ALLOW_CASE_INSENSIBILITY;
if (flags & StringToNumberFlags::kAllowLeadingSpaces) {
@@ -544,6 +565,11 @@ float StringView::ParseToFloat(Index* processed_characters_count,
if (processed_characters_count != nullptr) {
*processed_characters_count = pcc;
}
+
+ if (flags & StringToNumberFlags::kThrowOnError && std::isnan(result)) {
+ throw Exception(u"Result of string to float conversion is NaN");
+ }
+
return result;
}
@@ -555,6 +581,11 @@ double StringView::ParseToDouble(Index* processed_characters_count,
if (processed_characters_count != nullptr) {
*processed_characters_count = pcc;
}
+
+ if (flags & StringToNumberFlags::kThrowOnError && std::isnan(result)) {
+ throw Exception(u"Result of string to double conversion is NaN");
+ }
+
return result;
}
diff --git a/src/common/StringToNumberConverter.cpp b/src/common/StringToNumberConverter.cpp
index 526c2712..e20e436c 100644
--- a/src/common/StringToNumberConverter.cpp
+++ b/src/common/StringToNumberConverter.cpp
@@ -10,20 +10,24 @@ static bool IsSpace(char c) {
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
-StringToIntegerConverterImplResult StringToIntegerConverterImpl::Parse(
- const char* const str, const Index size,
- Index* processed_characters_count) const {
+namespace {
+template <typename T>
+StringToIntegerConverterImplResult GenericParseInteger(
+ const StringToIntegerConverterImpl* converter, const T* const str,
+ const Index size, Index* processed_characters_count) {
if (str == nullptr) throw std::invalid_argument("Invalid str.");
if (size < 0) throw std::invalid_argument("Invalid size.");
- if (!CheckParams()) throw std::invalid_argument("Invalid parsing flags.");
+ if (!converter->CheckParams())
+ throw std::invalid_argument("Invalid parsing flags.");
- const bool throw_on_error = (flags & StringToNumberFlags::kThrowOnError) != 0;
+ const bool throw_on_error =
+ (converter->flags & StringToNumberFlags::kThrowOnError) != 0;
- const char* const end = str + size;
+ auto const end = str + size;
- const char* current = str;
+ auto current = str;
- if (flags & StringToNumberFlags::kAllowLeadingSpaces) {
+ if (converter->flags & StringToNumberFlags::kAllowLeadingSpaces) {
while (current != end && IsSpace(*current)) {
current++;
}
@@ -60,7 +64,7 @@ StringToIntegerConverterImplResult StringToIntegerConverterImpl::Parse(
}
}
- int base = this->base;
+ int base = converter->base;
if (base == 0) {
if (*current == '0') {
@@ -96,7 +100,7 @@ StringToIntegerConverterImplResult StringToIntegerConverterImpl::Parse(
}
const bool allow_leading_zero =
- flags & StringToNumberFlags::kAllowLeadingZeroForInteger;
+ converter->flags & StringToNumberFlags::kAllowLeadingZeroForInteger;
while (current != end && *current == '0') {
current++;
@@ -110,9 +114,9 @@ StringToIntegerConverterImplResult StringToIntegerConverterImpl::Parse(
}
const bool allow_trailing_junk =
- flags & StringToNumberFlags::kAllowTrailingJunk;
+ converter->flags & StringToNumberFlags::kAllowTrailingJunk;
const bool allow_trailing_spaces =
- flags & StringToNumberFlags::kAllowTrailingSpaces;
+ converter->flags & StringToNumberFlags::kAllowTrailingSpaces;
unsigned long long result = 0;
while (current != end) {
@@ -165,4 +169,17 @@ StringToIntegerConverterImplResult StringToIntegerConverterImpl::Parse(
return {negate, result};
}
+} // namespace
+
+StringToIntegerConverterImplResult StringToIntegerConverterImpl::Parse(
+ const char* const str, const Index size,
+ Index* processed_characters_count) const {
+ return GenericParseInteger(this, str, size, processed_characters_count);
+}
+
+StringToIntegerConverterImplResult StringToIntegerConverterImpl::Parse(
+ const char16_t* const str, const Index size,
+ Index* processed_characters_count) const {
+ return GenericParseInteger(this, str, size, processed_characters_count);
+}
} // namespace cru