// generic useful stuff for any C++ program #ifndef _TOOLS_H #define _TOOLS_H #ifdef NULL #undef NULL #endif #define NULL 0 typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; #ifdef _DEBUG #ifdef __GNUC__ #define ASSERT(c) if(!(c)) { asm("int $3"); } #else #define ASSERT(c) if(!(c)) { __asm int 3 } #endif #else #define ASSERT(c) if(c) {} #endif #define swap(t,a,b) { t m=a; a=b; b=m; } #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif #define rnd(max) (rand()%(max)) #define rndreset() (srand(1)) #define rndtime() { loopi(lastmillis&0xF) rnd(i+1); } #define loop(v,m) for(int v = 0; v void _swap(T &a, T &b) { T t = a; a = b; b = t; } extern char *path(char *s); extern char *parentdir(char *directory); extern char *loadfile(char *fn, int *size); extern bool cmpb(void *b, int n, enet_uint32 c); extern bool cmpf(char *fn, enet_uint32 c); extern void endianswap(void *, int, int); extern void seedMT(uint seed); extern uint randomMT(void); #if SDL_BYTEORDER == SDL_BIG_ENDIAN #define CMPB(b, c) (true) #else #define CMPB(b, c) (cmpb(b, sizeof(b), ENET_HOST_TO_NET_32(c))) #endif #define loopv(v) if(false) {} else for(int i = 0; i<(v).length(); i++) #define loopvj(v) if(false) {} else for(int j = 0; j<(v).length(); j++) #define loopvk(v) if(false) {} else for(int k = 0; k<(v).length(); k++) #define loopvrev(v) if(false) {} else for(int i = (v).length()-1; i>=0; i--) template struct databuf { enum { OVERREAD = 1<<0, OVERWROTE = 1<<1 }; T *buf; int len, maxlen; uchar flags; template databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {} const T &get() { static T overreadval; if(len charbuf; typedef databuf ucharbuf; template struct vector { T *buf; int alen; int ulen; vector() { alen = 8; buf = (T *)new uchar[alen*sizeof(T)]; ulen = 0; } vector(const vector &v) { alen = v.length(); buf = (T *)new uchar[alen*sizeof(T)]; ulen = 0; *this = v; } ~vector() { setsize(0); delete[] (uchar *)buf; } vector &operator=(const vector &v) { setsize(0); loopv(v) add(v[i]); return *this; } T &add(const T &x) { if(ulen==alen) vrealloc(); new (&buf[ulen]) T(x); return buf[ulen++]; } T &add() { if(ulen==alen) vrealloc(); new (&buf[ulen]) T; return buf[ulen++]; } T &dup() { if(ulen==alen) vrealloc(); new (&buf[ulen]) T(buf[ulen-1]); return buf[ulen++]; } bool inrange(size_t i) const { return i=0 && i=0 && i= 0 && ii) drop(); } void setsizenodelete(int i) { ASSERT(i<=ulen); ulen = i; } void deletecontentsp() { while(!empty()) delete pop(); } void deletecontentsa() { while(!empty()) delete[] pop(); } T *getbuf() { return buf; } const T *getbuf() const { return buf; } template void sort(int (__cdecl *cf)(ST *, ST *), int i = 0, int n = -1) { qsort(&buf[i], n<0?ulen:n, sizeof(T), (int (__cdecl *)(const void *,const void *))cf); } void *_realloc(void *p, int oldsize, int newsize) { void *np = new uchar[newsize]; memcpy(np, p, newsize>oldsize ? oldsize : newsize); delete[] (uchar *)p; return np; } void vrealloc() { int olen = alen; buf = (T *)_realloc(buf, olen*sizeof(T), (alen *= 2)*sizeof(T)); } databuf reserve(int sz) { while(alen-ulen(&buf[ulen], sz); } void addbuf(const databuf &p) { ulen += p.length(); } void remove(int i, int n) { for(int p = i+n; pi; p--) buf[p] = buf[p-1]; buf[i] = e; return buf[i]; } }; typedef vector cvector; typedef vector ivector; typedef vector usvector; static inline uint hthash(const char *key) { uint h = 5381; for(int i = 0, k; (k = key[i]); i++) h = ((h<<5)+h)^k; // bernstein k=33 xor return h; } static inline bool htcmp(const char *x, const char *y) { return !strcmp(x, y); } static inline uint hthash(int key) { return key; } static inline bool htcmp(int x, int y) { return x==y; } static inline uint hthash(uint key) { return key; } static inline bool htcmp(uint x, uint y) { return x==y; } template struct hashtable { typedef K key; typedef const K const_key; typedef T value; typedef const T const_value; enum { CHUNKSIZE = 16 }; struct chain { T data; K key; chain *next; }; struct chainchunk { chain chunks[CHUNKSIZE]; chainchunk *next; }; int size; int numelems; chain **table; chain *enumc; int chunkremain; chainchunk *lastchunk; hashtable(int size = 1<<10) : size(size) { numelems = 0; chunkremain = 0; lastchunk = NULL; table = new chain *[size]; loopi(size) table[i] = NULL; } ~hashtable() { DELETEA(table); } chain *insert(const K &key, uint h) { if(!chunkremain) { chainchunk *chunk = new chainchunk; chunk->next = lastchunk; lastchunk = chunk; chunkremain = CHUNKSIZE; } chain *c = &lastchunk->chunks[--chunkremain]; c->key = key; c->next = table[h]; table[h] = c; numelems++; return c; } chain *find(const K &key, bool doinsert) { uint h = hthash(key)&(size-1); for(chain *c = table[h]; c; c = c->next) { if(htcmp(key, c->key)) return c; } if(doinsert) return insert(key, h); return NULL; } T *access(const K &key, const T *data = NULL) { chain *c = find(key, data != NULL); if(data) c->data = *data; if(c) return &c->data; return NULL; } T &operator[](const K &key) { return find(key, true)->data; } void clear() { loopi(size) { /* for(chain *c = table[i], *next; c; c = next) { next = c->next; delete c; }*/ table[i] = NULL; } numelems = 0; chunkremain = 0; for(chainchunk *chunk; lastchunk; lastchunk = chunk) { chunk = lastchunk->next; delete lastchunk; } } }; #define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(hashtable::chain *enumc = (ht).table[i]; enumc; enumc = enumc->next) { hashtable::const_key &e = enumc->key; t &f = enumc->data; b; } #define enumerate(ht,t,e,b) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc; (ht).enumc = (ht).enumc->next) { t &e = (ht).enumc->data; b; } #define enumerateht(ht) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc; (ht).enumc = (ht).enumc->next) inline char *newstring(size_t l) { return new char[l+1]; } inline char *newstring(const char *s, size_t l) { return s_strncpy(newstring(l), s, l+1); } inline char *newstring(const char *s) { return newstring(s, strlen(s)); } inline char *newstringbuf(const char *s) { return newstring(s, _MAXDEFSTR-1); } #endif