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

Last change on this file since 826 was 826, checked in by Maciej Komosinski, 19 months 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.