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

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

"Distributed" deserializable class registry, so that ExtValue? does not depend on so many other classes

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