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

Last change on this file since 826 was 826, checked in by Maciej Komosinski, 5 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
RevLine 
[385]1#include "sstring.h"
2#include <common/nonstd_stl.h>
3#include "extvalue.h"
4#include <assert.h>
[826]5#ifdef USE_PRINTFLOAT_DRAGON4
6#include <PrintFloat/PrintFloat.h>
7#endif
[385]8
9void SString::initEmpty()
10{
[793]11        txt = NULL; used = 0; size = 0;
[385]12}
13
14SString::SString()
15{
[793]16        initEmpty();
[385]17}
18
19SString::~SString()
20{
[793]21        resize(0);
[385]22}
23
24SString::SString(int x)
25{
[793]26        initEmpty();
27        if (x)
28                ensureSize(x + 1);
[385]29}
30
[793]31SString::SString(const char *t, int t_len)
[385]32{
[793]33        initEmpty();
34        if (!t) return;
35        copyFrom(t, t_len);
[385]36}
37
38SString::SString(const SString &from)
39{
[793]40        initEmpty();
41        operator=(from);
[385]42}
43
44SString::SString(SString&& from)
45{
[793]46        txt = from.txt; size = from.size; used = from.used;
47        from.txt = NULL; from.size = 0; from.used = 0;
[385]48}
49
50void SString::resize(int newsize)
51{
[793]52        if (newsize == size) return;
53        txt = (char*)realloc(txt, newsize);
54        size = newsize;
[385]55}
56
57void SString::ensureSize(int needed)
58{
[793]59        if (size > needed) return;
60        resize((size > 0) ? (needed + needed / 2 + 1) : (needed + 1));
[385]61}
62
63char *SString::directWrite(int ensuresize)
64{
[793]65        ensureSize(ensuresize);
66        appending = used;
67        return txt;
[385]68}
69
70char *SString::directAppend(int maxappend)
71{
[793]72        ensureSize(used + maxappend);
73        appending = used;
74        return txt + appending;
[385]75}
76
77void SString::endWrite(int newlength)
78{
[793]79        if (newlength < 0) newlength = strlen(txt);
80        else txt[newlength] = 0;
81        used = newlength;
82        assert(used < size);
[385]83}
84
85void SString::endAppend(int newappend)
86{
[793]87        if (newappend < 0) newappend = strlen(txt + appending);
88        else txt[appending + newappend] = 0;
89        used = appending + newappend;
90        assert(used < size);
[385]91}
92
93////////////// append /////////////////
94
95void SString::operator+=(const char *s)
96{
[793]97        if (!s) return;
98        int x = strlen(s);
99        if (!x) return;
100        append(s, x);
[385]101}
102
[793]103void SString::append(const char *t, int n)
[385]104{
[793]105        if (!n) return;
106        ensureSize(used + n);
107        memmove(txt + used, t, n);
108        used += n;
109        txt[used] = 0;
[385]110}
111
112void SString::operator+=(const SString&s)
113{
[793]114        append(s.c_str(), s.len());
[385]115}
116
117SString SString::operator+(const SString& s) const
118{
[793]119        SString ret(len() + s.len());
120        ret = *this;
121        ret += s;
122        return ret;
[385]123}
124
125/////////////////////////////
126
[793]127void SString::copyFrom(const char *ch, int chlen)
[385]128{
[793]129        if (!ch) chlen = 0;
130        else if (chlen < 0) chlen = strlen(ch);
131        if (chlen)
[385]132        {
[793]133                ensureSize(chlen);
134                memmove(txt, ch, chlen);
135                txt[chlen] = 0;
136                used = chlen;
[385]137        }
[793]138        else
[385]139        {
[793]140                if (txt)
[385]141                {
[793]142                        txt[0] = 0;
143                        used = 0;
[385]144                }
145        }
146}
147
148void SString::operator=(const char *ch)
149{
[793]150        copyFrom(ch);
[385]151}
152
153void SString::operator=(const SString&s)
154{
[793]155        if (&s == this) return;
156        copyFrom(s.c_str(), s.len());
[385]157}
158
159///////////////////////////////////////
160
161SString SString::substr(int begin, int length) const
162{
[793]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);
[385]168}
169
170///////////////////////////////////////
171
[395]172bool SString::equals(const SString& s) const
[385]173{
[793]174        if (this == &s) return true;
175        if (len() != s.len()) return false;
176        return strcmp(getPtr(), s.getPtr()) == 0;
[385]177}
178
179///////////////////////////////////////
180
[793]181int SString::indexOf(int character, int start) const
[385]182{
[793]183        const char *found = strchr(getPtr() + start, character);
184        return found ? found - getPtr() : -1;
[385]185}
186
[793]187int SString::indexOf(const char *substring, int start) const
[385]188{
[793]189        const char *found = strstr(getPtr() + start, substring);
190        return found ? found - getPtr() : -1;
[385]191}
192
[793]193int SString::indexOf(const SString & substring, int start) const
[385]194{
[793]195        const char *found = strstr(getPtr() + start, substring.c_str());
196        return found ? found - getPtr() : -1;
[385]197}
198
[793]199bool SString::getNextToken(int& pos, SString &token, char separator) const
[385]200{
[793]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;
[385]209}
210
[395]211bool SString::startsWith(const char *pattern) const
[385]212{
[793]213        const char *t = this->c_str();
214        for (; *pattern; pattern++, t++)
215                if (*t != *pattern) return false;
216        return true;
[385]217}
218
219SString SString::valueOf(int i)
220{
[793]221        return SString::sprintf("%d", i);
[385]222}
223SString SString::valueOf(long i)
224{
[793]225        return SString::sprintf("%d", i);
[385]226}
227SString SString::valueOf(double d)
228{
[826]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
[793]239        if ((!strchr(tmp.c_str(), '.')) && (!strchr(tmp.c_str(), 'e'))) tmp += ".0";
240        return tmp;
[385]241}
242SString SString::valueOf(const SString& s)
243{
[793]244        return s;
[385]245}
246
247SString SString::sprintf(const char* format, ...)
248{
[793]249        int n, size = 30;
250        va_list ap;
[385]251
[793]252        SString ret;
[385]253
254#ifdef USE_VSCPRINTF
[793]255        va_start(ap, format);
256        size = _vscprintf(format, ap);
257        va_end(ap);
[385]258#endif
259
[793]260        while (1)
[385]261        {
[793]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)
[385]271                {
[793]272                        ret.endWrite(n);
273                        return ret;
[385]274                }
[793]275                /* Else try again with more space. */
[385]276#ifdef VSNPRINTF_RETURNS_REQUIRED_SIZE
[793]277                if (n > -1)    /* glibc 2.1 */
278                        size = n; /* precisely what is needed */
279                else           /* glibc 2.0 */
[385]280#endif
[793]281                        size *= 2;  /* twice the old size */
[385]282        }
283}
284
285SString &SString::empty()
286{
[793]287        static SString empty;
288        return empty;
[385]289}
Note: See TracBrowser for help on using the repository browser.