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

Last change on this file since 288 was 286, checked in by Maciej Komosinski, 9 years ago

Updated headers

  • Property svn:eol-style set to native
File size: 8.4 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        memcpy(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!
99memcpy(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// to be moved somewhere else?
114// public domain source: http://isthe.com/chongo/src/fnv
115typedef uint32_t Fnv32_t;
116
117#define FNV_32_PRIME ((Fnv32_t)0x01000193)
118#define FNV1_32_INIT ((Fnv32_t)0x811c9dc5)
119#define FNV1_32A_INIT FNV1_32_INIT
120
121Fnv32_t fnv_32a_buf(void *buf, size_t len, Fnv32_t hval)
122{
123    unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
124    unsigned char *be = bp + len;               /* beyond end of buffer */
125
126    while (bp < be) {
127
128        /* xor the bottom with the current octet */
129        hval ^= (Fnv32_t)*bp++;
130
131        /* multiply by the 32 bit FNV magic prime mod 2^32 */
132#if defined(NO_FNV_GCC_OPTIMIZATION)
133        hval *= FNV_32_PRIME;
134#else
135        hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
136#endif
137
138    }
139
140    /* return our new hash value */
141    return hval;
142}
143//////////////////////////////////////////////////
144
145uint32_t SBuf::hash() const
146{
147return fnv_32a_buf(txt,used,FNV1_32A_INIT);
148}
149
150/////////////////////////////////////////////
151
152SString::SString()
153{
154initEmpty();
155}
156
157SString::~SString()
158{
159REF_LOCK;
160detach();
161REF_UNLOCK;
162}
163
164SString::SString(int x)
165{
166buf=new SBuf(x);
167}
168
169SString::SString(const char *t,int t_len)
170{
171initEmpty();
172if (!t) return;
173copyFrom(t,t_len);
174}
175
176SString::SString(const SString &from)
177{
178if (from.buf==&SBuf::empty())
179        buf=&SBuf::empty();
180else
181        {
182        REF_LOCK;
183        buf=from.buf;
184        if (buf->size)
185                buf->refcount++;
186        REF_UNLOCK;
187        }
188}
189
190void SString::initEmpty()
191{
192buf=&SBuf::empty();
193}
194
195void SString::memoryHint(int howbig)
196{
197detachCopy(howbig);
198}
199       
200void SString::detachEmpty(int ensuresize)
201{
202if (buf==&SBuf::empty()) { buf=new SBuf(ensuresize); return; }
203if (buf->refcount<2) buf->ensureSize(ensuresize);
204else
205        {
206        buf->refcount--;
207        buf=new SBuf(ensuresize);
208        }
209}
210
211void SString::detach()
212{
213if (buf==&SBuf::empty()) return;
214if (!--buf->refcount) delete buf;
215}
216
217void SString::detachCopy(int ensuresize)
218{
219if (buf==&SBuf::empty()) { buf=new SBuf(ensuresize); return; }
220if (buf->refcount<2)
221        {
222        buf->ensureSize(ensuresize);
223        return;
224        }
225buf->refcount--;
226SBuf *newbuf=new SBuf(ensuresize);
227newbuf->copyFrom(buf->txt,min(ensuresize,buf->used));
228buf=newbuf;
229}
230
231char *SString::directWrite(int ensuresize)
232{
233if (ensuresize<0) ensuresize=len();
234REF_LOCK;
235detachCopy(ensuresize);
236REF_UNLOCK;
237appending=buf->used;
238return buf->txt;
239}
240
241/*
242char *SString::directWrite()
243{
244return directWrite(buf->used);
245}
246*/
247char *SString::directAppend(int maxappend)
248{
249REF_LOCK;
250detachCopy(buf->used+maxappend);
251REF_UNLOCK;
252appending=buf->used;
253return buf->txt+appending;
254}
255
256void SString::endWrite(int newlength)
257{
258if (newlength<0) newlength=strlen(buf->txt);
259else buf->txt[newlength]=0;
260buf->used=newlength;
261}
262
263void SString::endAppend(int newappend)
264{
265if (newappend<0) newappend=strlen(buf->txt+appending);
266else buf->txt[appending+newappend]=0;
267buf->used=appending+newappend;
268}
269
270////////////// append /////////////////
271
272void SString::operator+=(const char *s)
273{
274if (!s) return;
275int x=strlen(s);
276if (!x) return;
277append(s,x);
278}
279
280void SString::append(const char *txt,int count)
281{
282if (!count) return;
283REF_LOCK;
284detachCopy(buf->used+count);
285REF_UNLOCK;
286buf->append(txt,count);
287}
288
289void SString::operator+=(const SString&s)
290{
291append((const char*)s,s.len());
292}
293
294SString SString::operator+(const SString& s) const
295{
296SString ret(*this);
297ret+=s;
298return ret;
299}
300
301/////////////////////////////
302
303void SString::copyFrom(const char *ch,int chlen)
304{
305if (!ch) chlen=0;
306else if (chlen<0) chlen=strlen(ch);
307REF_LOCK;
308detachEmpty(chlen);
309REF_UNLOCK;
310memcpy(buf->txt,ch,chlen);
311buf->txt[chlen]=0; buf->used=chlen;
312}
313
314void SString::operator=(const char *ch)
315{
316copyFrom(ch);
317}
318
319void SString::operator=(const SString&s)
320{
321if (s.buf==buf) return;
322REF_LOCK;
323detach();
324buf=s.buf;
325if (buf->size) buf->refcount++;
326REF_UNLOCK;
327}
328///////////////////////////////////////
329
330SString SString::substr(int begin, int length) const
331{
332if (begin<0) { length+=begin; begin=0; }
333if (length>=(len()-begin)) length=len()-begin;
334if (length<=0) return SString();
335if (length==len()) return *this;
336return SString((*this)(begin),length);
337}
338
339///////////////////////////////////////
340
341bool SString::equals(const SString& s) const
342{
343if (s.buf==buf) return true;
344return strcmp(buf->txt,s.buf->txt)==0;
345}
346
347///////////////////////////////////////
348
349int SString::indexOf(int character,int start) const
350{
351const char *found=strchr(buf->txt+start,character);
352return found?found-buf->txt:-1;
353}
354
355int SString::indexOf(const char *substring,int start) const
356{
357char *found=strstr(buf->txt+start,substring);
358return found?found-buf->txt:-1;
359}
360
361int SString::indexOf(const SString & substring,int start) const
362{
363char *found=strstr(buf->txt+start,((const char*)substring));
364return found?found-buf->txt:-1;
365}
366
367int SString::getNextToken (int& pos,SString &token,char separator) const
368{
369if (pos>=len()) {token=0;return 0;}
370int p1=pos,p2;
371const char *t1=buf->txt+pos;
372const char *t2=strchr(t1,separator);
373if (t2) pos=(p2=(t2-buf->txt))+1; else p2=pos=len();
374strncpy(token.directWrite(p2-p1),t1,p2-p1);
375token.endWrite(p2-p1);
376return 1;
377}
378
379int SString::startsWith(const char *pattern) const
380{
381const char *t=(const char*)(*this);
382for (;*pattern;pattern++,t++)
383        if (*t != *pattern) return 0;
384return 1;
385}
386
387SString SString::valueOf(int i)
388{
389return SString::sprintf("%d",i);
390}
391SString SString::valueOf(long i)
392{
393return SString::sprintf("%d",i);
394}
395SString SString::valueOf(double d)
396{
397SString tmp=SString::sprintf("%.15g",d);
398if ((!strchr(tmp,'.'))&&(!strchr(tmp,'e'))) tmp+=".0";
399return tmp;
400}
401SString SString::valueOf(const SString& s)
402{
403return s;
404}
405
406#if 0 //testing _vscprintf
407#define USE_VSCPRINTF
408int _vscprintf(const char *format,va_list argptr)
409{
410return vsnprintf("",0,format,argptr);
411}
412#endif
413
414SString SString::sprintf(const char* format, ...)
415{
416int n, size = 30;
417va_list ap;
418
419SString ret;
420
421#ifdef USE_VSCPRINTF
422va_start(ap, format);
423size=_vscprintf(format, ap);
424va_end(ap);
425#endif
426
427while (1)
428        {
429        char* p=ret.directWrite(size);
430        assert(p!=NULL);
431        size=ret.directMaxLen()+1;
432        /* Try to print in the allocated space. */
433        va_start(ap, format);
434        n = vsnprintf(p, size, format, ap);
435        va_end(ap);
436        /* If that worked, return the string. */
437        if (n > -1 && n < size)
438                {
439                ret.endWrite(n);
440                return ret;
441                }
442        /* Else try again with more space. */
443#ifdef VSNPRINTF_RETURNS_REQUIRED_SIZE
444        if (n > -1)    /* glibc 2.1 */
445                size = n; /* precisely what is needed */
446        else           /* glibc 2.0 */
447#endif
448                size *= 2;  /* twice the old size */
449        }
450}
451
452SString &SString::empty()
453{
454static SString empty;
455return empty;
456}
457
458SBuf &SBuf::empty()
459{
460static SBuf empty;
461return empty;
462}
463
464#endif //#ifdef SSTRING_SIMPLE
Note: See TracBrowser for help on using the repository browser.