installed pty
[VSoRC/.git] / node_modules / node-pty / deps / winpty / src / shared / StringBuilder.h
1 // Copyright (c) 2016 Ryan Prichard
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to
5 // deal in the Software without restriction, including without limitation the
6 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 // sell copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 // IN THE SOFTWARE.
20
21 // Efficient integer->string conversion and string concatenation.  The
22 // hexadecimal conversion may optionally have leading zeros.  Other ways to
23 // convert integers to strings in C++ suffer these drawbacks:
24 //
25 //  * std::stringstream: Inefficient, even more so than stdio.
26 //
27 //  * std::to_string: No hexadecimal output, tends to use heap allocation, not
28 //    supported on Cygwin.
29 //
30 //  * stdio routines: Requires parsing a format string (inefficient).  The
31 //    caller *must* know how large the content is for correctness.  The
32 //    string-printf functions are extremely inconsistent on Windows.  In
33 //    particular, 64-bit integers, wide strings, and return values are
34 //    problem areas.
35 //
36 // StringBuilderTest.cc is a standalone program that tests this header.
37
38 #ifndef WINPTY_STRING_BUILDER_H
39 #define WINPTY_STRING_BUILDER_H
40
41 #include <array>
42 #include <string>
43 #include <type_traits>
44
45 #ifdef STRING_BUILDER_TESTING
46 #include <assert.h>
47 #define STRING_BUILDER_CHECK(cond) assert(cond)
48 #else
49 #define STRING_BUILDER_CHECK(cond)
50 #endif // STRING_BUILDER_TESTING
51
52 #include "WinptyAssert.h"
53
54 template <typename C, size_t sz>
55 struct ValueString {
56     std::array<C, sz> m_array;
57     size_t m_offset;
58     size_t m_size;
59
60     const C *c_str() const { return m_array.data() + m_offset; }
61     const C *data() const { return m_array.data() + m_offset; }
62     size_t size() const { return m_size; }
63     std::basic_string<C> str() const {
64         return std::basic_string<C>(data(), m_size);
65     }
66 };
67
68 #ifdef _MSC_VER
69 // Disable an MSVC /SDL error that forbids unsigned negation.  Signed negation
70 // invokes undefined behavior for INTxx_MIN, so unsigned negation is simpler to
71 // reason about.  (We assume twos-complement in any case.)
72 #define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) \
73     (                                           \
74         __pragma(warning(push))                 \
75         __pragma(warning(disable:4146))         \
76         (x)                                     \
77         __pragma(warning(pop))                  \
78     )
79 #else
80 #define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) (x)
81 #endif
82
83 // Formats an integer as decimal without leading zeros.
84 template <typename C, typename I>
85 ValueString<C, sizeof(I) * 3 + 1 + 1> gdecOfInt(const I value) {
86     typedef typename std::make_unsigned<I>::type U;
87     auto unsValue = static_cast<U>(value);
88     const bool isNegative = (value < 0);
89     if (isNegative) {
90         unsValue = STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(-unsValue);
91     }
92     decltype(gdecOfInt<C, I>(value)) out;
93     auto &arr = out.m_array;
94     C *const endp = arr.data() + arr.size();
95     C *outp = endp;
96     *(--outp) = '\0';
97     STRING_BUILDER_CHECK(outp >= arr.data());
98     do {
99         const int digit = unsValue % 10;
100         unsValue /= 10;
101         *(--outp) = '0' + digit;
102         STRING_BUILDER_CHECK(outp >= arr.data());
103     } while (unsValue != 0);
104     if (isNegative) {
105         *(--outp) = '-';
106         STRING_BUILDER_CHECK(outp >= arr.data());
107     }
108     out.m_offset = outp - arr.data();
109     out.m_size = endp - outp - 1;
110     return out;
111 }
112
113 template <typename I> decltype(gdecOfInt<char, I>(0)) decOfInt(I i) {
114     return gdecOfInt<char>(i);
115 }
116
117 template <typename I> decltype(gdecOfInt<wchar_t, I>(0)) wdecOfInt(I i) {
118     return gdecOfInt<wchar_t>(i);
119 }
120
121 // Formats an integer as hexadecimal, with or without leading zeros.
122 template <typename C, bool leadingZeros=false, typename I>
123 ValueString<C, sizeof(I) * 2 + 1> ghexOfInt(const I value) {
124     typedef typename std::make_unsigned<I>::type U;
125     const auto unsValue = static_cast<U>(value);
126     static const C hex[16] = {'0','1','2','3','4','5','6','7',
127                               '8','9','a','b','c','d','e','f'};
128     decltype(ghexOfInt<C, leadingZeros, I>(value)) out;
129     auto &arr = out.m_array;
130     C *outp = arr.data();
131     int inIndex = 0;
132     int shift = sizeof(I) * 8 - 4;
133     const int len = sizeof(I) * 2;
134     if (!leadingZeros) {
135         for (; inIndex < len - 1; ++inIndex, shift -= 4) {
136             STRING_BUILDER_CHECK(shift >= 0 && shift < sizeof(unsValue) * 8);
137             const int digit = (unsValue >> shift) & 0xF;
138             if (digit != 0) {
139                 break;
140             }
141         }
142     }
143     for (; inIndex < len; ++inIndex, shift -= 4) {
144         const int digit = (unsValue >> shift) & 0xF;
145         *(outp++) = hex[digit];
146         STRING_BUILDER_CHECK(outp <= arr.data() + arr.size());
147     }
148     *(outp++) = '\0';
149     STRING_BUILDER_CHECK(outp <= arr.data() + arr.size());
150     out.m_offset = 0;
151     out.m_size = outp - arr.data() - 1;
152     return out;
153 }
154
155 template <bool leadingZeros=false, typename I>
156 decltype(ghexOfInt<char, leadingZeros, I>(0)) hexOfInt(I i) {
157     return ghexOfInt<char, leadingZeros, I>(i);
158 }
159
160 template <bool leadingZeros=false, typename I>
161 decltype(ghexOfInt<wchar_t, leadingZeros, I>(0)) whexOfInt(I i) {
162     return ghexOfInt<wchar_t, leadingZeros, I>(i);
163 }
164
165 template <typename C>
166 class GStringBuilder {
167 public:
168     typedef std::basic_string<C> StringType;
169
170     GStringBuilder() {}
171     GStringBuilder(size_t capacity) {
172         m_out.reserve(capacity);
173     }
174
175     GStringBuilder &operator<<(C ch) { m_out.push_back(ch); return *this; }
176     GStringBuilder &operator<<(const C *str) { m_out.append(str); return *this; }
177     GStringBuilder &operator<<(const StringType &str) { m_out.append(str); return *this; }
178
179     template <size_t sz>
180     GStringBuilder &operator<<(const ValueString<C, sz> &str) {
181         m_out.append(str.data(), str.size());
182         return *this;
183     }
184
185 private:
186     // Forbid output of char/wchar_t for GStringBuilder if the type doesn't
187     // exactly match the builder element type.  The code still allows
188     // signed char and unsigned char, but I'm a little worried about what
189     // happens if a user tries to output int8_t or uint8_t.
190     template <typename P>
191     typename std::enable_if<
192         (std::is_same<P, char>::value || std::is_same<P, wchar_t>::value) &&
193         !std::is_same<C, P>::value, GStringBuilder&>::type
194     operator<<(P ch) {
195         ASSERT(false && "Method was not supposed to be reachable.");
196         return *this;
197     }
198
199 public:
200     GStringBuilder &operator<<(short i)              { return *this << gdecOfInt<C>(i); }
201     GStringBuilder &operator<<(unsigned short i)     { return *this << gdecOfInt<C>(i); }
202     GStringBuilder &operator<<(int i)                { return *this << gdecOfInt<C>(i); }
203     GStringBuilder &operator<<(unsigned int i)       { return *this << gdecOfInt<C>(i); }
204     GStringBuilder &operator<<(long i)               { return *this << gdecOfInt<C>(i); }
205     GStringBuilder &operator<<(unsigned long i)      { return *this << gdecOfInt<C>(i); }
206     GStringBuilder &operator<<(long long i)          { return *this << gdecOfInt<C>(i); }
207     GStringBuilder &operator<<(unsigned long long i) { return *this << gdecOfInt<C>(i); }
208
209     GStringBuilder &operator<<(const void *p) {
210         m_out.push_back(static_cast<C>('0'));
211         m_out.push_back(static_cast<C>('x'));
212         *this << ghexOfInt<C>(reinterpret_cast<uintptr_t>(p));
213         return *this;
214     }
215
216     StringType str() { return m_out; }
217     StringType str_moved() { return std::move(m_out); }
218     const C *c_str() const { return m_out.c_str(); }
219
220 private:
221     StringType m_out;
222 };
223
224 typedef GStringBuilder<char> StringBuilder;
225 typedef GStringBuilder<wchar_t> WStringBuilder;
226
227 #endif // WINPTY_STRING_BUILDER_H