diff options
Diffstat (limited to 'include/cru/common')
-rw-r--r-- | include/cru/common/Bitmask.h | 5 | ||||
-rw-r--r-- | include/cru/common/Format.h | 59 | ||||
-rw-r--r-- | include/cru/common/String.h | 32 | ||||
-rw-r--r-- | include/cru/common/StringToNumberConverter.h | 88 | ||||
-rw-r--r-- | include/cru/common/SubProcess.h | 2 | ||||
-rw-r--r-- | include/cru/common/platform/unix/UnixPipe.h | 3 |
6 files changed, 114 insertions, 75 deletions
diff --git a/include/cru/common/Bitmask.h b/include/cru/common/Bitmask.h index 23a3a069..9b6b8957 100644 --- a/include/cru/common/Bitmask.h +++ b/include/cru/common/Bitmask.h @@ -1,4 +1,5 @@ #pragma once + #include <functional> namespace cru { @@ -13,6 +14,8 @@ struct Bitmask final { return Bitmask(static_cast<TUnderlying>(1u << offset)); } + constexpr bool Has(Bitmask rhs) const { return (value & rhs.value) != 0; } + Bitmask operator|(Bitmask rhs) const { return Bitmask(value | rhs.value); } Bitmask operator&(Bitmask rhs) const { return Bitmask(value & rhs.value); } Bitmask operator^(Bitmask rhs) const { return Bitmask(value ^ rhs.value); } @@ -34,7 +37,7 @@ struct Bitmask final { bool operator!=(Bitmask rhs) const { return this->value != rhs.value; } explicit operator TUnderlying() const { return value; } - explicit operator bool() const { return value != 0; } + operator bool() const { return value != 0; } TUnderlying value; }; diff --git a/include/cru/common/Format.h b/include/cru/common/Format.h index e6935343..d5c5ed99 100644 --- a/include/cru/common/Format.h +++ b/include/cru/common/Format.h @@ -3,8 +3,10 @@ #include "Exception.h" #include "String.h" -#include <double-conversion/double-conversion.h> -#include <charconv> +#include <cassert> +#include <cstdio> +#include <type_traits> +#include <vector> namespace cru { inline String ToString(bool value) { @@ -12,31 +14,40 @@ inline String ToString(bool value) { } template <typename T> -std::enable_if_t<std::is_integral_v<T>, String> ToString(T value) { - std::array<char, 50> buffer; - auto result = - std::to_chars(buffer.data(), buffer.data() + buffer.size(), value); - - if (result.ec == std::errc{}) { - } else { - throw std::invalid_argument("Failed to convert value to chars."); - } +inline constexpr std::nullptr_t kPrintfFormatSpecifierOfType = nullptr; + +#define CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(type, specifier) \ + template <> \ + inline constexpr const char* kPrintfFormatSpecifierOfType<type> = specifier; + +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed char, "%c") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned char, "%c") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed short, "%hd") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned short, "%hu") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed int, "%d") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned int, "%u") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed long, "%ld") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned long, "%lu") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(signed long long, "%lld") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(unsigned long long, "%llu") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(float, "%f") +CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE(double, "%f") + +#undef CRU_DEFINE_PRINTF_FORMAT_SPECIFIER_OF_TYPE - auto size = result.ptr - buffer.data(); - auto b = new char16_t[size + 1]; - b[size] = 0; - std::copy(buffer.data(), result.ptr, b); - return String::FromBuffer(b, size, size); +template <typename T> +std::enable_if_t< + !std::is_null_pointer_v<decltype(kPrintfFormatSpecifierOfType<T>)>, String> +ToString(T value) { + auto size = std::snprintf(nullptr, 0, kPrintfFormatSpecifierOfType<T>, value); + assert(size > 0); + std::vector<char> buffer(size + 1); + size = std::snprintf(buffer.data(), size + 1, kPrintfFormatSpecifierOfType<T>, + value); + assert(size > 0); + return String::FromUtf8(buffer.data(), size); } -extern double_conversion::DoubleToStringConverter - kDefaultDoubleToStringConverter; - -String CRU_BASE_API ToString(float value, StringView option); -String CRU_BASE_API ToString(double value, StringView option); -inline String ToString(float value) { return ToString(value, u""); } -inline String ToString(double value) { return ToString(value, u""); } - template <typename T> String ToString(const T& value, StringView option) { CRU_UNUSED(option) diff --git a/include/cru/common/String.h b/include/cru/common/String.h index 5d9fc549..21a3db51 100644 --- a/include/cru/common/String.h +++ b/include/cru/common/String.h @@ -6,7 +6,6 @@ #include "StringToNumberConverter.h" #include "StringUtil.h" -#include <double-conversion/double-conversion.h> #include <filesystem> #include <initializer_list> #include <iterator> @@ -221,16 +220,14 @@ class CRU_BASE_API String { Index* processed_characters_count, unsigned flags, int base) const; int ParseToInt(Index* processed_characters_count = nullptr, - unsigned flags = StringToNumberFlags::kNoFlags, - int base = 0) const; + StringToNumberFlag flags = {}, int base = 0) const; long long ParseToLongLong(Index* processed_characters_count = nullptr, - unsigned flags = StringToNumberFlags::kNoFlags, - int base = 0) const; + StringToNumberFlag flags = {}, int base = 0) const; float ParseToFloat(Index* processed_characters_count = nullptr, - unsigned flags = StringToNumberFlags::kNoFlags) const; + StringToNumberFlag flags = {}) const; double ParseToDouble(Index* processed_characters_count = nullptr, - unsigned flags = StringToNumberFlags::kNoFlags) const; + StringToNumberFlag flags = {}) const; std::vector<float> ParseToFloatList(value_type separator = u' ') const; std::vector<double> ParseToDoubleList(value_type separator = u' ') const; @@ -261,6 +258,8 @@ class CRU_BASE_API String { Index capacity_ = 0; // always 1 smaller than real buffer size }; +std::ostream& CRU_BASE_API operator<<(std::ostream& os, const String& value); + class CRU_BASE_API StringView { public: using value_type = char16_t; @@ -357,23 +356,24 @@ class CRU_BASE_API StringView { 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); + Index* processed_characters_count, StringToNumberFlag flags, + int base) const { + auto utf8_string = ToUtf8(); + auto result = StringToIntegerConverter(flags, base) + .Parse(utf8_string.data(), utf8_string.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; + StringToNumberFlag flags = {}, int base = 0) const; long long ParseToLongLong(Index* processed_characters_count = nullptr, - unsigned flags = StringToNumberFlags::kNoFlags, - int base = 0) const; + StringToNumberFlag flags = {}, int base = 0) const; float ParseToFloat(Index* processed_characters_count = nullptr, - unsigned flags = StringToNumberFlags::kNoFlags) const; + StringToNumberFlag flags = {}) const; double ParseToDouble(Index* processed_characters_count = nullptr, - unsigned flags = StringToNumberFlags::kNoFlags) const; + StringToNumberFlag flags = {}) const; std::vector<float> ParseToFloatList(value_type separator = u' ') const; std::vector<double> ParseToDoubleList(value_type separator = u' ') const; diff --git a/include/cru/common/StringToNumberConverter.h b/include/cru/common/StringToNumberConverter.h index f1baafee..758b26c8 100644 --- a/include/cru/common/StringToNumberConverter.h +++ b/include/cru/common/StringToNumberConverter.h @@ -1,41 +1,63 @@ #pragma once #include "Base.h" +#include "Bitmask.h" +#include <cstddef> #include <ostream> namespace cru { -struct CRU_BASE_API StringToNumberFlags { - constexpr static unsigned kNoFlags = 0; - constexpr static unsigned kAllowLeadingSpaces = 1 << 0; - constexpr static unsigned kAllowTrailingSpaces = 1 << 1; - constexpr static unsigned kAllowTrailingJunk = 1 << 2; - constexpr static unsigned kAllowLeadingZeroForInteger = 1 << 2; - constexpr static unsigned kThrowOnError = 1 << 3; +namespace details { +struct StringToNumberFlagTag {}; +} // namespace details + +using StringToNumberFlag = Bitmask<details::StringToNumberFlagTag>; + +struct StringToNumberFlags { + constexpr static StringToNumberFlag kAllowLeadingSpaces = + StringToNumberFlag::FromOffset(0); + constexpr static StringToNumberFlag kAllowTrailingSpaces = + StringToNumberFlag::FromOffset(1); + constexpr static StringToNumberFlag kAllowTrailingJunk = + StringToNumberFlag::FromOffset(2); + constexpr static StringToNumberFlag kAllowLeadingZeroForInteger = + StringToNumberFlag::FromOffset(3); + constexpr static StringToNumberFlag kThrowOnError = + StringToNumberFlag::FromOffset(4); }; -struct CRU_BASE_API StringToIntegerConverterImplResult { - StringToIntegerConverterImplResult() = default; - StringToIntegerConverterImplResult(bool negate, unsigned long long value) +template <typename TResult> +struct IStringToNumberConverter : virtual Interface { + virtual TResult Parse(const char* str, Index size, + Index* processed_characters_count) const = 0; + + template <std::size_t Size> + TResult Parse(const char (&str)[Size], + Index* processed_characters_count) const { + return Parse(str, Size - 1, processed_characters_count); + } +}; + +struct CRU_BASE_API StringToIntegerResult { + StringToIntegerResult() = default; + StringToIntegerResult(bool negate, unsigned long long value) : negate(negate), value(value) {} bool negate; unsigned long long value; }; -inline bool CRU_BASE_API -operator==(const StringToIntegerConverterImplResult& left, - const StringToIntegerConverterImplResult& right) { +inline bool CRU_BASE_API operator==(const StringToIntegerResult& left, + const StringToIntegerResult& right) { return left.negate == right.negate && left.value == right.value; } -inline bool CRU_BASE_API -operator!=(const StringToIntegerConverterImplResult& left, - const StringToIntegerConverterImplResult& right) { +inline bool CRU_BASE_API operator!=(const StringToIntegerResult& left, + const StringToIntegerResult& right) { return !(left == right); } -inline std::ostream& operator<<( - std::ostream& stream, const StringToIntegerConverterImplResult& result) { +inline std::ostream& CRU_BASE_API +operator<<(std::ostream& stream, const StringToIntegerResult& result) { return stream << "StringToIntegerConverterImplResult(" << (result.negate ? "-" : "") << result.value << ")"; } @@ -43,9 +65,10 @@ inline std::ostream& operator<<( /** * \brief A converter that convert number into long long. */ -struct CRU_BASE_API StringToIntegerConverterImpl { +struct CRU_BASE_API StringToIntegerConverter + : IStringToNumberConverter<StringToIntegerResult> { public: - explicit StringToIntegerConverterImpl(unsigned flags, int base = 0) + explicit StringToIntegerConverter(StringToNumberFlag flags, int base = 0) : flags(flags), base(base) {} bool CheckParams() const; @@ -57,19 +80,11 @@ struct CRU_BASE_API StringToIntegerConverterImpl { * \param processed_characters_count The number of characters that were * processed. Or nullptr to not retrieve. */ - 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; + StringToIntegerResult Parse(const char* str, Index size, + Index* processed_characters_count) const override; + using IStringToNumberConverter<StringToIntegerResult>::Parse; - template <std::size_t Size> - StringToIntegerConverterImplResult Parse( - const char (&str)[Size], Index* processed_characters_count) const { - return Parse(str, Size - 1, processed_characters_count); - } - - unsigned flags; + StringToNumberFlag flags; /** * \brief The base of the number used for parse or 0 for auto detect. * \remarks Base can only be of range [2, 36] or 0. If base is 0, decimal is @@ -80,4 +95,13 @@ struct CRU_BASE_API StringToIntegerConverterImpl { */ int base; }; + +struct CRU_BASE_API StringToFloatConverter { + StringToFloatConverter(StringToNumberFlag flags) : flags(flags) {} + + double Parse(const char* str, Index size, + Index* processed_characters_count) const; + + StringToNumberFlag flags; +}; } // namespace cru diff --git a/include/cru/common/SubProcess.h b/include/cru/common/SubProcess.h index 98c272a3..fbe8ad2b 100644 --- a/include/cru/common/SubProcess.h +++ b/include/cru/common/SubProcess.h @@ -231,7 +231,7 @@ class CRU_BASE_API SubProcess : public Object { SubProcess(SubProcess&& other) = default; SubProcess& operator=(SubProcess&& other) = default; - ~SubProcess(); + ~SubProcess() override; public: void Wait(std::optional<std::chrono::milliseconds> wait_time = std::nullopt); diff --git a/include/cru/common/platform/unix/UnixPipe.h b/include/cru/common/platform/unix/UnixPipe.h index afe6024a..cf35fb11 100644 --- a/include/cru/common/platform/unix/UnixPipe.h +++ b/include/cru/common/platform/unix/UnixPipe.h @@ -43,7 +43,7 @@ class UnixPipe : public Object { Receive, }; - explicit UnixPipe(Usage usage, UnixPipeFlag flags = {}); + explicit UnixPipe(Usage usage, bool auto_close, UnixPipeFlag flags = {}); CRU_DELETE_COPY(UnixPipe) CRU_DELETE_MOVE(UnixPipe) @@ -62,6 +62,7 @@ class UnixPipe : public Object { private: Usage usage_; + bool auto_close_; UnixPipeFlag flags_; int read_fd_; int write_fd_; |