source: cpp/frams/util/sstring-simple.cpp @ 826

Last change on this file since 826 was 826, checked in by Maciej Komosinski, 2 years ago

Used the Dragon4 algorithm to print floating point values with full precision instead of "%.17g"

  • Property svn:eol-style set to native
File size: 5.6 KB
Line 
1#include "sstring.h"
2#include <common/nonstd_stl.h>
3#include "extvalue.h"
4#include <assert.h>
5#ifdef USE_PRINTFLOAT_DRAGON4
6#include <PrintFloat/PrintFloat.h>
7#endif
8
9void SString::initEmpty()
10{
11        txt = NULL; used = 0; size = 0;
12}
13
14SString::SString()
15{
16        initEmpty();
17}
18
19SString::~SString()
20{
21        resize(0);
22}
23
24SString::SString(int x)
25{
26        initEmpty();
27        if (x)
28                ensureSize(x + 1);
29}
30
31SString::SString(const char *t, int t_len)
32{
33        initEmpty();
34        if (!t) return;
35        copyFrom(t, t_len);
36}
37
38SString::SString(const SString &from)
39{
40        initEmpty();
41        operator=(from);
42}
43
44SString::SString(SString&& from)
45{
46        txt = from.txt; size = from.size; used = from.used;
47        from.txt = NULL; from.size = 0; from.used = 0;
48}
49
50void SString::resize(int newsize)
51{
52        if (newsize == size) return;
53        txt = (char*)realloc(txt, newsize);
54        size = newsize;
55}
56
57void SString::ensureSize(int needed)
58{
59        if (size > needed) return;
60        resize((size > 0) ? (needed + needed / 2 + 1) : (needed + 1));
61}
62
63char *SString::directWrite(int ensuresize)
64{
65        ensureSize(ensuresize);
66        appending = used;
67        return txt;
68}
69
70char *SString::directAppend(int maxappend)
71{
72        ensureSize(used + maxappend);
73        appending = used;
74        return txt + appending;
75}
76
77void SString::endWrite(int newlength)
78{
79        if (newlength < 0) newlength = strlen(txt);
80        else txt[newlength] = 0;
81        used = newlength;
82        assert(used < size);
83}
84
85void SString::endAppend(int newappend)
86{
87        if (newappend < 0) newappend = strlen(txt + appending);
88        else txt[appending + newappend] = 0;
89        used = appending + newappend;
90        assert(used < size);
91}
92
93////////////// append /////////////////
94
95void SString::operator+=(const char *s)
96{
97        if (!s) return;
98        int x = strlen(s);
99        if (!x) return;
100        append(s, x);
101}
102
103void SString::append(const char *t, int n)
104{
105        if (!n) return;
106        ensureSize(used + n);
107        memmove(txt + used, t, n);
108        used += n;
109        txt[used] = 0;
110}
111
112void SString::operator+=(const SString&s)
113{
114        append(s.c_str(), s.len());
115}
116
117SString SString::operator+(const SString& s) const
118{
119        SString ret(len() + s.len());
120        ret = *this;
121        ret += s;
122        return ret;
123}
124
125/////////////////////////////
126
127void SString::copyFrom(const char *ch, int chlen)
128{
129        if (!ch) chlen = 0;
130        else if (chlen < 0) chlen = strlen(ch);
131        if (chlen)
132        {
133                ensureSize(chlen);
134                memmove(txt, ch, chlen);
135                txt[chlen] = 0;
136                used = chlen;
137        }
138        else
139        {
140                if (txt)
141                {
142                        txt[0] = 0;
143                        used = 0;
144                }
145        }
146}
147
148void SString::operator=(const char *ch)
149{
150        copyFrom(ch);
151}
152
153void SString::operator=(const SString&s)
154{
155        if (&s == this) return;
156        copyFrom(s.c_str(), s.len());
157}
158
159///////////////////////////////////////
160
161SString SString::substr(int begin, int length) const
162{
163        if (begin < 0) { length += begin; begin = 0; }
164        if (length >= (len() - begin)) length = len() - begin;
165        if (length <= 0) return SString();
166        if (length == len()) return *this;
167        return SString((*this)(begin), length);
168}
169
170///////////////////////////////////////
171
172bool SString::equals(const SString& s) const
173{
174        if (this == &s) return true;
175        if (len() != s.len()) return false;
176        return strcmp(getPtr(), s.getPtr()) == 0;
177}
178
179///////////////////////////////////////
180
181int SString::indexOf(int character, int start) const
182{
183        const char *found = strchr(getPtr() + start, character);
184        return found ? found - getPtr() : -1;
185}
186
187int SString::indexOf(const char *substring, int start) const
188{
189        const char *found = strstr(getPtr() + start, substring);
190        return found ? found - getPtr() : -1;
191}
192
193int SString::indexOf(const SString & substring, int start) const
194{
195        const char *found = strstr(getPtr() + start, substring.c_str());
196        return found ? found - getPtr() : -1;
197}
198
199bool SString::getNextToken(int& pos, SString &token, char separator) const
200{
201        if (pos >= len()) { token = 0; return false; }
202        int p1 = pos, p2;
203        const char *t1 = getPtr() + pos;
204        const char *t2 = strchr(t1, separator);
205        if (t2) pos = (p2 = (t2 - getPtr())) + 1; else p2 = pos = len();
206        strncpy(token.directWrite(p2 - p1), t1, p2 - p1);
207        token.endWrite(p2 - p1);
208        return true;
209}
210
211bool SString::startsWith(const char *pattern) const
212{
213        const char *t = this->c_str();
214        for (; *pattern; pattern++, t++)
215                if (*t != *pattern) return false;
216        return true;
217}
218
219SString SString::valueOf(int i)
220{
221        return SString::sprintf("%d", i);
222}
223SString SString::valueOf(long i)
224{
225        return SString::sprintf("%d", i);
226}
227SString SString::valueOf(double d)
228{
229#ifdef USE_PRINTFLOAT_DRAGON4
230        SString tmp;
231        char* here = tmp.directWrite(30);
232        tmp.endWrite(PrintFloat64(here, 30, d,
233                ((d < -1e17) || (d > 1e17) || ((d < 1e-4) && (d > -1e-4) && (d != 0.0)))
234                ? PrintFloatFormat_Scientific : PrintFloatFormat_Positional,
235                -1));//http://www.ryanjuckett.com/programming/printing-floating-point-numbers/
236#else
237        SString tmp = SString::sprintf("%.17g", d); //https://stackoverflow.com/questions/16839658/printf-width-specifier-to-maintain-precision-of-floating-point-value
238#endif
239        if ((!strchr(tmp.c_str(), '.')) && (!strchr(tmp.c_str(), 'e'))) tmp += ".0";
240        return tmp;
241}
242SString SString::valueOf(const SString& s)
243{
244        return s;
245}
246
247SString SString::sprintf(const char* format, ...)
248{
249        int n, size = 30;
250        va_list ap;
251
252        SString ret;
253
254#ifdef USE_VSCPRINTF
255        va_start(ap, format);
256        size = _vscprintf(format, ap);
257        va_end(ap);
258#endif
259
260        while (1)
261        {
262                char* p = ret.directWrite(size);
263                assert(p != NULL);
264                size = ret.directMaxLen() + 1;
265                /* Try to print in the allocated space. */
266                va_start(ap, format);
267                n = vsnprintf(p, size, format, ap);
268                va_end(ap);
269                /* If that worked, return the string. */
270                if (n > -1 && n < size)
271                {
272                        ret.endWrite(n);
273                        return ret;
274                }
275                /* Else try again with more space. */
276#ifdef VSNPRINTF_RETURNS_REQUIRED_SIZE
277                if (n > -1)    /* glibc 2.1 */
278                        size = n; /* precisely what is needed */
279                else           /* glibc 2.0 */
280#endif
281                        size *= 2;  /* twice the old size */
282        }
283}
284
285SString &SString::empty()
286{
287        static SString empty;
288        return empty;
289}
Note: See TracBrowser for help on using the repository browser.