| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #ifndef WINPTY_STRING_BUILDER_H |
| | #define WINPTY_STRING_BUILDER_H |
| |
|
| | #include <array> |
| | #include <string> |
| | #include <type_traits> |
| |
|
| | #ifdef STRING_BUILDER_TESTING |
| | #include <assert.h> |
| | #define STRING_BUILDER_CHECK(cond) assert(cond) |
| | #else |
| | #define STRING_BUILDER_CHECK(cond) |
| | #endif |
| |
|
| | #include "WinptyAssert.h" |
| |
|
| | template <typename C, size_t sz> |
| | struct ValueString { |
| | std::array<C, sz> m_array; |
| | size_t m_offset; |
| | size_t m_size; |
| |
|
| | const C *c_str() const { return m_array.data() + m_offset; } |
| | const C *data() const { return m_array.data() + m_offset; } |
| | size_t size() const { return m_size; } |
| | std::basic_string<C> str() const { |
| | return std::basic_string<C>(data(), m_size); |
| | } |
| | }; |
| |
|
| | #ifdef _MSC_VER |
| | |
| | |
| | |
| | #define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) \ |
| | ( \ |
| | __pragma(warning(push)) \ |
| | __pragma(warning(disable:4146)) \ |
| | (x) \ |
| | __pragma(warning(pop)) \ |
| | ) |
| | #else |
| | #define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) (x) |
| | #endif |
| |
|
| | |
| | template <typename C, typename I> |
| | ValueString<C, sizeof(I) * 3 + 1 + 1> gdecOfInt(const I value) { |
| | typedef typename std::make_unsigned<I>::type U; |
| | auto unsValue = static_cast<U>(value); |
| | const bool isNegative = (value < 0); |
| | if (isNegative) { |
| | unsValue = STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(-unsValue); |
| | } |
| | decltype(gdecOfInt<C, I>(value)) out; |
| | auto &arr = out.m_array; |
| | C *const endp = arr.data() + arr.size(); |
| | C *outp = endp; |
| | *(--outp) = '\0'; |
| | STRING_BUILDER_CHECK(outp >= arr.data()); |
| | do { |
| | const int digit = unsValue % 10; |
| | unsValue /= 10; |
| | *(--outp) = '0' + digit; |
| | STRING_BUILDER_CHECK(outp >= arr.data()); |
| | } while (unsValue != 0); |
| | if (isNegative) { |
| | *(--outp) = '-'; |
| | STRING_BUILDER_CHECK(outp >= arr.data()); |
| | } |
| | out.m_offset = outp - arr.data(); |
| | out.m_size = endp - outp - 1; |
| | return out; |
| | } |
| |
|
| | template <typename I> decltype(gdecOfInt<char, I>(0)) decOfInt(I i) { |
| | return gdecOfInt<char>(i); |
| | } |
| |
|
| | template <typename I> decltype(gdecOfInt<wchar_t, I>(0)) wdecOfInt(I i) { |
| | return gdecOfInt<wchar_t>(i); |
| | } |
| |
|
| | |
| | template <typename C, bool leadingZeros=false, typename I> |
| | ValueString<C, sizeof(I) * 2 + 1> ghexOfInt(const I value) { |
| | typedef typename std::make_unsigned<I>::type U; |
| | const auto unsValue = static_cast<U>(value); |
| | static const C hex[16] = {'0','1','2','3','4','5','6','7', |
| | '8','9','a','b','c','d','e','f'}; |
| | decltype(ghexOfInt<C, leadingZeros, I>(value)) out; |
| | auto &arr = out.m_array; |
| | C *outp = arr.data(); |
| | int inIndex = 0; |
| | int shift = sizeof(I) * 8 - 4; |
| | const int len = sizeof(I) * 2; |
| | if (!leadingZeros) { |
| | for (; inIndex < len - 1; ++inIndex, shift -= 4) { |
| | STRING_BUILDER_CHECK(shift >= 0 && shift < sizeof(unsValue) * 8); |
| | const int digit = (unsValue >> shift) & 0xF; |
| | if (digit != 0) { |
| | break; |
| | } |
| | } |
| | } |
| | for (; inIndex < len; ++inIndex, shift -= 4) { |
| | const int digit = (unsValue >> shift) & 0xF; |
| | *(outp++) = hex[digit]; |
| | STRING_BUILDER_CHECK(outp <= arr.data() + arr.size()); |
| | } |
| | *(outp++) = '\0'; |
| | STRING_BUILDER_CHECK(outp <= arr.data() + arr.size()); |
| | out.m_offset = 0; |
| | out.m_size = outp - arr.data() - 1; |
| | return out; |
| | } |
| |
|
| | template <bool leadingZeros=false, typename I> |
| | decltype(ghexOfInt<char, leadingZeros, I>(0)) hexOfInt(I i) { |
| | return ghexOfInt<char, leadingZeros, I>(i); |
| | } |
| |
|
| | template <bool leadingZeros=false, typename I> |
| | decltype(ghexOfInt<wchar_t, leadingZeros, I>(0)) whexOfInt(I i) { |
| | return ghexOfInt<wchar_t, leadingZeros, I>(i); |
| | } |
| |
|
| | template <typename C> |
| | class GStringBuilder { |
| | public: |
| | typedef std::basic_string<C> StringType; |
| |
|
| | GStringBuilder() {} |
| | GStringBuilder(size_t capacity) { |
| | m_out.reserve(capacity); |
| | } |
| |
|
| | GStringBuilder &operator<<(C ch) { m_out.push_back(ch); return *this; } |
| | GStringBuilder &operator<<(const C *str) { m_out.append(str); return *this; } |
| | GStringBuilder &operator<<(const StringType &str) { m_out.append(str); return *this; } |
| |
|
| | template <size_t sz> |
| | GStringBuilder &operator<<(const ValueString<C, sz> &str) { |
| | m_out.append(str.data(), str.size()); |
| | return *this; |
| | } |
| |
|
| | private: |
| | |
| | |
| | |
| | |
| | template <typename P> |
| | typename std::enable_if< |
| | (std::is_same<P, char>::value || std::is_same<P, wchar_t>::value) && |
| | !std::is_same<C, P>::value, GStringBuilder&>::type |
| | operator<<(P ch) { |
| | ASSERT(false && "Method was not supposed to be reachable."); |
| | return *this; |
| | } |
| |
|
| | public: |
| | GStringBuilder &operator<<(short i) { return *this << gdecOfInt<C>(i); } |
| | GStringBuilder &operator<<(unsigned short i) { return *this << gdecOfInt<C>(i); } |
| | GStringBuilder &operator<<(int i) { return *this << gdecOfInt<C>(i); } |
| | GStringBuilder &operator<<(unsigned int i) { return *this << gdecOfInt<C>(i); } |
| | GStringBuilder &operator<<(long i) { return *this << gdecOfInt<C>(i); } |
| | GStringBuilder &operator<<(unsigned long i) { return *this << gdecOfInt<C>(i); } |
| | GStringBuilder &operator<<(long long i) { return *this << gdecOfInt<C>(i); } |
| | GStringBuilder &operator<<(unsigned long long i) { return *this << gdecOfInt<C>(i); } |
| |
|
| | GStringBuilder &operator<<(const void *p) { |
| | m_out.push_back(static_cast<C>('0')); |
| | m_out.push_back(static_cast<C>('x')); |
| | *this << ghexOfInt<C>(reinterpret_cast<uintptr_t>(p)); |
| | return *this; |
| | } |
| |
|
| | StringType str() { return m_out; } |
| | StringType str_moved() { return std::move(m_out); } |
| | const C *c_str() const { return m_out.c_str(); } |
| |
|
| | private: |
| | StringType m_out; |
| | }; |
| |
|
| | typedef GStringBuilder<char> StringBuilder; |
| | typedef GStringBuilder<wchar_t> WStringBuilder; |
| |
|
| | #endif |
| |
|