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

Last change on this file since 489 was 395, checked in by Maciej Komosinski, 10 years ago

Fixed int/bool warnings

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