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

Last change on this file since 224 was 222, checked in by Maciej Komosinski, 11 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.