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

Last change on this file since 198 was 198, checked in by Maciej Komosinski, 6 years ago

Hashing function for strings

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