source: cpp/frams/util/sstring.cpp @ 808

Last change on this file since 808 was 793, checked in by Maciej Komosinski, 7 years ago

Code formatting

  • Property svn:eol-style set to native
File size: 9.1 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
[109]4
5#include "sstring.h"
[222]6#include <common/nonstd.h> //to be sure the vsnprintf-related stuff gets included
[109]7
8#ifdef SSTRING_SIMPLE
9
10// simple sstring implementation using direct character arrays
11// - duplicate = copy all characters
12// - no mutex needed
13
14#include "sstring-simple.cpp"
15
16#else
17///////////////////////////////////////////////////////////////////////////
18// old sstring implementation using SBuf references
19// - duplicate = copy buffer pointer
20// - mutex required to be thread safe
21
22#include <common/nonstd_stl.h>
23#include "extvalue.h"
24#include <assert.h>
25
26#ifdef MULTITHREADED
27#include <pthread.h>
[793]28static pthread_mutex_t sstring_ref_lock = PTHREAD_MUTEX_INITIALIZER;
[109]29#define REF_LOCK pthread_mutex_lock(&sstring_ref_lock);
30#define REF_UNLOCK pthread_mutex_unlock(&sstring_ref_lock)
31#else
32#define REF_LOCK
33#define REF_UNLOCK
34#endif
35
36static int guessMemSize(int request)
37{
[793]38        return request + min(request / 2, 10000) + 8;
[109]39}
40
41SBuf::SBuf()
42{
[793]43        txt = (char*)"";
44        size = used = 0;
45        refcount = 1;
[109]46}
47
48SBuf::SBuf(int initsize)
49{
[793]50        size = guessMemSize(initsize);
51        if (size > 0)   { txt = (char*)malloc(size + 1); txt[0] = 0; }
52        else    txt = (char*)"";
53        used = 0;
54        refcount = 1;
[109]55}
56
57SBuf::~SBuf()
58{
[793]59        freeBuf();
[109]60}
61
62void SBuf::initEmpty()
63{
[793]64        txt = (char*)"";
65        used = size = 0;
66        refcount = 1;
[109]67}
68
69void SBuf::freeBuf()
70{
[793]71        if (!size) return;
72        free(txt); used = 0;
[109]73}
74
[793]75void SBuf::copyFrom(const char *ch, int chlen)
[109]76{
[793]77        if (chlen == -1) chlen = strlen(ch);
78        if (chlen > 0)
[109]79        {
[793]80                if (chlen < size)
81                {
82                        memmove(txt, ch, chlen);
83                }
84                else
85                {
86                        size = guessMemSize(chlen);
87                        char *newtxt = (char*)malloc(size + 1);
88                        memcpy(newtxt, ch, chlen);
89                        free(txt);
90                        txt = newtxt;
91                }
[109]92        }
[793]93        txt[chlen] = 0;
94        used = chlen;
[109]95}
96
[793]97void SBuf::append(const char *ch, int chlen)
[109]98{ // doesn't check anything!
[793]99        memmove(txt + used, ch, chlen);
100        used += chlen;
101        txt[used] = 0;
[109]102}
103
104void SBuf::ensureSize(int needed)
105{
[793]106        if (size >= needed) return;
107        needed = guessMemSize(needed);
108        txt = (char*)realloc(txt, needed + 1);
109        size = needed;
[109]110}
111
112/////////////////////////////////////////////
113
114SString::SString()
115{
[793]116        initEmpty();
[109]117}
118
119SString::~SString()
120{
[793]121        REF_LOCK;
122        detach();
123        REF_UNLOCK;
[109]124}
125
126SString::SString(int x)
127{
[793]128        buf = new SBuf(x);
[109]129}
130
[793]131SString::SString(const char *t, int t_len)
[109]132{
[793]133        initEmpty();
134        if (!t) return;
135        copyFrom(t, t_len);
[109]136}
137
[367]138SString::SString(SString&& from)
139{
[793]140        buf = from.buf;
141        from.buf = &SBuf::empty();
[367]142}
143
[109]144SString::SString(const SString &from)
145{
[793]146        if (from.buf == &SBuf::empty())
147                buf = &SBuf::empty();
148        else
[109]149        {
[793]150                REF_LOCK;
151                buf = from.buf;
152                if (buf->size)
153                        buf->refcount++;
154                REF_UNLOCK;
[109]155        }
156}
157
158void SString::initEmpty()
159{
[793]160        buf = &SBuf::empty();
[109]161}
162
163void SString::memoryHint(int howbig)
164{
[793]165        detachCopy(howbig);
[109]166}
[793]167
[109]168void SString::detachEmpty(int ensuresize)
169{
[793]170        if (buf == &SBuf::empty()) { buf = new SBuf(ensuresize); return; }
171        if (buf->refcount < 2) buf->ensureSize(ensuresize);
172        else
[109]173        {
[793]174                buf->refcount--;
175                buf = new SBuf(ensuresize);
[109]176        }
177}
178
179void SString::detach()
180{
[793]181        if (buf == &SBuf::empty()) return;
182        if (!--buf->refcount) delete buf;
[109]183}
184
185void SString::detachCopy(int ensuresize)
186{
[793]187        if (buf == &SBuf::empty()) { buf = new SBuf(ensuresize); return; }
188        if (buf->refcount < 2)
[109]189        {
[793]190                buf->ensureSize(ensuresize);
191                return;
[109]192        }
[793]193        buf->refcount--;
194        SBuf *newbuf = new SBuf(ensuresize);
195        newbuf->copyFrom(buf->txt, min(ensuresize, buf->used));
196        buf = newbuf;
[109]197}
198
199char *SString::directWrite(int ensuresize)
200{
[793]201        if (ensuresize < 0) ensuresize = len();
202        REF_LOCK;
203        detachCopy(ensuresize);
204        REF_UNLOCK;
205        appending = buf->used;
206        return buf->txt;
[109]207}
208
209/*
210char *SString::directWrite()
211{
212return directWrite(buf->used);
213}
214*/
215char *SString::directAppend(int maxappend)
216{
[793]217        REF_LOCK;
218        detachCopy(buf->used + maxappend);
219        REF_UNLOCK;
220        appending = buf->used;
221        return buf->txt + appending;
[109]222}
223
224void SString::endWrite(int newlength)
225{
[793]226        if (newlength < 0) newlength = strlen(buf->txt);
227        else buf->txt[newlength] = 0;
228        buf->used = newlength;
[109]229}
230
231void SString::endAppend(int newappend)
232{
[793]233        if (newappend < 0) newappend = strlen(buf->txt + appending);
234        else buf->txt[appending + newappend] = 0;
235        buf->used = appending + newappend;
[109]236}
237
238////////////// append /////////////////
239
240void SString::operator+=(const char *s)
241{
[793]242        if (!s) return;
243        int x = strlen(s);
244        if (!x) return;
245        append(s, x);
[109]246}
247
[793]248void SString::append(const char *txt, int count)
[109]249{
[793]250        if (!count) return;
251        REF_LOCK;
252        detachCopy(buf->used + count);
253        REF_UNLOCK;
254        buf->append(txt, count);
[109]255}
256
257void SString::operator+=(const SString&s)
258{
[793]259        append(s.c_str(), s.len());
[109]260}
261
262SString SString::operator+(const SString& s) const
263{
[793]264        SString ret(*this);
265        ret += s;
266        return ret;
[109]267}
268
269/////////////////////////////
270
[793]271void SString::copyFrom(const char *ch, int chlen)
[109]272{
[793]273        if (!ch) chlen = 0;
274        else if (chlen < 0) chlen = strlen(ch);
275        REF_LOCK;
276        detachEmpty(chlen);
277        REF_UNLOCK;
278        memmove(buf->txt, ch, chlen);
279        buf->txt[chlen] = 0; buf->used = chlen;
[109]280}
281
282void SString::operator=(const char *ch)
283{
[793]284        copyFrom(ch);
[109]285}
286
287void SString::operator=(const SString&s)
288{
[793]289        if (s.buf == buf) return;
290        REF_LOCK;
291        detach();
292        buf = s.buf;
293        if (buf->size) buf->refcount++;
294        REF_UNLOCK;
[109]295}
296///////////////////////////////////////
297
298SString SString::substr(int begin, int length) const
299{
[793]300        if (begin < 0) { length += begin; begin = 0; }
301        if (length >= (len() - begin)) length = len() - begin;
302        if (length <= 0) return SString();
303        if (length == len()) return *this;
304        return SString((*this)(begin), length);
[109]305}
306
307///////////////////////////////////////
308
[247]309bool SString::equals(const SString& s) const
[109]310{
[793]311        if (s.buf == buf) return true;
312        return strcmp(buf->txt, s.buf->txt) == 0;
[109]313}
314
315///////////////////////////////////////
316
[793]317int SString::indexOf(int character, int start) const
[109]318{
[793]319        const char *found = strchr(buf->txt + start, character);
320        return found ? found - buf->txt : -1;
[109]321}
322
[793]323int SString::indexOf(const char *substring, int start) const
[109]324{
[793]325        char *found = strstr(buf->txt + start, substring);
326        return found ? found - buf->txt : -1;
[109]327}
328
[793]329int SString::indexOf(const SString & substring, int start) const
[109]330{
[793]331        char *found = strstr(buf->txt + start, substring.c_str());
332        return found ? found - buf->txt : -1;
[109]333}
334
[793]335bool SString::getNextToken(int& pos, SString &token, char separator) const
[109]336{
[793]337        if (pos >= len()) { token = 0; return false; }
338        int p1 = pos, p2;
339        const char *t1 = buf->txt + pos;
340        const char *t2 = strchr(t1, separator);
341        if (t2) pos = (p2 = (t2 - buf->txt)) + 1; else p2 = pos = len();
342        strncpy(token.directWrite(p2 - p1), t1, p2 - p1);
343        token.endWrite(p2 - p1);
344        return true;
[109]345}
346
[395]347bool SString::startsWith(const char *pattern) const
[109]348{
[793]349        const char *t = this->c_str();
350        for (; *pattern; pattern++, t++)
351                if (*t != *pattern) return false;
352        return true;
[109]353}
354
355SString SString::valueOf(int i)
356{
[793]357        return SString::sprintf("%d", i);
[109]358}
359SString SString::valueOf(long i)
360{
[793]361        return SString::sprintf("%d", i);
[109]362}
363SString SString::valueOf(double d)
364{
[793]365        SString tmp = SString::sprintf("%.15g", d);
366        if ((!strchr(tmp.c_str(), '.')) && (!strchr(tmp.c_str(), 'e'))) tmp += ".0";
367        return tmp;
[109]368}
369SString SString::valueOf(const SString& s)
370{
[793]371        return s;
[109]372}
373
374#if 0 //testing _vscprintf
375#define USE_VSCPRINTF
[793]376int _vscprintf(const char *format, va_list argptr)
[109]377{
[793]378        return vsnprintf("", 0, format, argptr);
[109]379}
380#endif
381
382SString SString::sprintf(const char* format, ...)
383{
[793]384        int n, size = 30;
385        va_list ap;
[109]386
[793]387        SString ret;
[109]388
389#ifdef USE_VSCPRINTF
[793]390        va_start(ap, format);
391        size = _vscprintf(format, ap);
392        va_end(ap);
[109]393#endif
394
[793]395        while (1)
[109]396        {
[793]397                char* p = ret.directWrite(size);
398                assert(p != NULL);
399                size = ret.directMaxLen() + 1;
400                /* Try to print in the allocated space. */
401                va_start(ap, format);
402                n = vsnprintf(p, size, format, ap);
403                va_end(ap);
404                /* If that worked, return the string. */
405                if (n > -1 && n < size)
[109]406                {
[793]407                        ret.endWrite(n);
408                        return ret;
[109]409                }
[793]410                /* Else try again with more space. */
[109]411#ifdef VSNPRINTF_RETURNS_REQUIRED_SIZE
[793]412                if (n > -1)    /* glibc 2.1 */
413                        size = n; /* precisely what is needed */
414                else           /* glibc 2.0 */
[109]415#endif
[793]416                        size *= 2;  /* twice the old size */
[109]417        }
418}
419
420SString &SString::empty()
421{
[793]422        static SString empty;
423        return empty;
[109]424}
425
426SBuf &SBuf::empty()
427{
[793]428        static SBuf empty;
429        return empty;
[109]430}
431
432#endif //#ifdef SSTRING_SIMPLE
[347]433
434//////////////////////////////////////////////////
435// to be moved somewhere else?
436// public domain source: http://isthe.com/chongo/src/fnv
437typedef uint32_t Fnv32_t;
438
439#define FNV_32_PRIME ((Fnv32_t)0x01000193)
440#define FNV1_32_INIT ((Fnv32_t)0x811c9dc5)
441#define FNV1_32A_INIT FNV1_32_INIT
442
443Fnv32_t fnv_32a_buf(void *buf, size_t len, Fnv32_t hval)
444{
[793]445        unsigned char *bp = (unsigned char *)buf;       /* start of buffer */
446        unsigned char *be = bp + len;           /* beyond end of buffer */
[347]447
[793]448        while (bp < be) {
[347]449
[793]450                /* xor the bottom with the current octet */
451                hval ^= (Fnv32_t)*bp++;
[347]452
[793]453                /* multiply by the 32 bit FNV magic prime mod 2^32 */
[347]454#if defined(NO_FNV_GCC_OPTIMIZATION)
[793]455                hval *= FNV_32_PRIME;
[347]456#else
[793]457                hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
[347]458#endif
459
[793]460        }
[347]461
[793]462        /* return our new hash value */
463        return hval;
[347]464}
465//////////////////////////////////////////////////
466
467#ifdef SSTRING_SIMPLE
468uint32_t SString::hash() const
469{
[793]470        return fnv_32a_buf(txt, used, FNV1_32A_INIT);
[347]471}
472#else
473uint32_t SBuf::hash() const
474{
[793]475        return fnv_32a_buf(txt, used, FNV1_32A_INIT);
[347]476}
477#endif
Note: See TracBrowser for help on using the repository browser.