// 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 #include #define DEBUG(v) if(DEBUGCOND) { std::cout << behindpath(__FILE__) << ":" << __LINE__ << " " << __FUNCTION__ << "(..) " << v << std::endl; } #define DEBUGVAR(v) if(DEBUGCOND) { std::cout << behindpath(__FILE__) << ":" << __LINE__ << " " << __FUNCTION__ << "(..) " << #v << " = " << v << std::endl; } #else #define DEBUG(v) {} #define DEBUGVAR(v) {} #define ASSERT(c) if(c) {} #endif #ifdef swap #undef swap #endif template static inline void swap(T &a, T &b) { T t = a; a = b; b = t; } #ifdef max #undef max #endif #ifdef min #undef min #endif template static inline T max(T a, T b) { return a > b ? a : b; } template static inline T min(T a, T b) { return a < b ? a : b; } static inline float round(float x) { return floor(x + 0.5f); } #define clamp(a,b,c) (max(b, min(a, c))) #define rnd(max) (rand()%(max)) #define detrnd(s, x) ((int)(((((uint)(s))*1103515245+12345)>>16)%(x))) #define loop(v,m) for(int v = 0; v=0; i--) #define loopvjrev(v) if(false) {} else for(int j = (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 { static const int MINSIZE = 8; T *buf; int alen, ulen; vector() : buf(NULL), alen(0), ulen(0) { } vector(const vector &v) : buf(NULL), alen(0), ulen(0) { *this = v; } ~vector() { setsize(0); if(buf) delete[] (uchar *)buf; } vector &operator=(const vector &v) { setsize(0); if(v.length() > alen) vrealloc(v.length()); loopv(v) add(v[i]); return *this; } T &add(const T &x) { if(ulen==alen) vrealloc(ulen+1); new (&buf[ulen]) T(x); return buf[ulen++]; } T &add() { if(ulen==alen) vrealloc(ulen+1); new (&buf[ulen]) T; return buf[ulen++]; } T &dup() { if(ulen==alen) vrealloc(ulen+1); 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; } bool inbuf(const T *e) const { return e >= buf && e < &buf[ulen]; } 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); } template T *search(T *key, int (__cdecl *cf)(ST *, ST *), int i = 0, int n = -1) { return (T *) bsearch(key, &buf[i], n<0 ? ulen : n, sizeof(T), (int (__cdecl *)(const void *,const void *))cf); } void vrealloc(int sz) { int olen = alen; if(!alen) alen = max(MINSIZE, sz); else while(alen < sz) alen *= 2; if(alen <= olen) return; uchar *newbuf = new uchar[alen*sizeof(T)]; if(olen > 0) { memcpy(newbuf, buf, olen*sizeof(T)); delete[] (uchar *)buf; } buf = (T *)newbuf; } databuf reserve(int sz) { if(ulen+sz > alen) vrealloc(ulen+sz); return databuf(&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 chains[CHUNKSIZE]; chainchunk *next; }; int size; int numelems; chain **table; chain *enumc; chainchunk *chunks; chain *unused; hashtable(int size = 1<<10) : size(size) { numelems = 0; chunks = NULL; unused = NULL; table = new chain *[size]; loopi(size) table[i] = NULL; } ~hashtable() { DELETEA(table); deletechunks(); } void insertchains(chainchunk *emptychunk) { loopi(CHUNKSIZE-1) emptychunk->chains[i].next = &emptychunk->chains[i+1]; emptychunk->chains[CHUNKSIZE-1].next = unused; unused = emptychunk->chains; } chain *insert(const K &key, uint h) { if(!unused) { chainchunk *chunk = new chainchunk; chunk->next = chunks; chunks = chunk; insertchains(chunk); } chain *c = unused; unused = unused->next; c->key = key; c->next = table[h]; table[h] = c; numelems++; return c; } #define HTFIND(success, fail) \ uint h = hthash(key)&(size-1); \ for(chain *c = table[h]; c; c = c->next) \ { \ if(htcmp(key, c->key)) return (success); \ } \ return (fail); T *access(const K &key) { HTFIND(&c->data, NULL); } T &access(const K &key, const T &data) { HTFIND(c->data, insert(key, h)->data = data); } T &operator[](const K &key) { HTFIND(c->data, insert(key, h)->data); } #undef HTFIND bool remove(const K &key) { uint h = hthash(key)&(size-1); for(chain **p = &table[h], *c = table[h]; c; p = &c->next, c = c->next) { if(htcmp(key, c->key)) { *p = c->next; c->data.~T(); c->key.~K(); new (&c->data) T; new (&c->key) K; c->next = unused; unused = c; numelems--; return true; } } return false; } void deletechunks() { for(chainchunk *nextchunk; chunks; chunks = nextchunk) { nextchunk = chunks->next; delete chunks; } } void clear(bool del = true) { loopi(size) table[i] = NULL; numelems = 0; unused = NULL; if(del) deletechunks(); else { for(chainchunk *chunk = chunks; chunk; chunk = chunk->next) insertchains(chunk); } } }; template struct ringbuf { int index, len; T data[SIZE]; ringbuf() { clear(); } void clear() { index = len = 0; } bool empty() const { return !len; } int maxsize() const { return SIZE; } int length() const { return len; } T &remove() { int start = index - len; if(start < 0) start += SIZE; len--; return data[start]; } T &add(const T &e) { T &t = data[index]; t = e; index++; if(index>=SIZE) index = 0; if(len= SIZE) i -= SIZE; return data[i]; } const T &operator[](int i) const { int start = index - len; if(start < 0) start += SIZE; i += start; if(i >= SIZE) i -= SIZE; return data[i]; } }; #define itoa(s, i) sprintf(s, "%d", i) #define ftoa(s, f) sprintf(s, (f) == int(f) ? "%.1f" : "%.7g", f) #define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(hashtable::chain *enumc = (ht).table[i]; enumc;) { hashtable::const_key &e = enumc->key; t &f = enumc->data; enumc = enumc->next; b; } #define enumeratek(ht,k,e,b) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc;) { k &e = (ht).enumc->key; (ht).enumc = (ht).enumc->next; b; } #define enumerate(ht,t,e,b) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc;) { t &e = (ht).enumc->data; (ht).enumc = (ht).enumc->next; b; } 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() { return newstring(_MAXDEFSTR-1); } inline char *newstringbuf(const char *s) { return newstring(s, _MAXDEFSTR-1); } extern const char *filenametime(); extern char *path(char *s); extern char *path(const char *s, bool copy); extern const char *behindpath(const char *s); extern const char *parentdir(const char *directory); extern bool fileexists(const char *path, const char *mode); extern bool createdir(const char *path); extern void sethomedir(const char *dir); extern void addpackagedir(const char *dir); extern const char *findfile(const char *filename, const char *mode); extern int getfilesize(const char *filename); extern FILE *openfile(const char *filename, const char *mode); extern gzFile opengzfile(const char *filename, const char *mode); extern char *loadfile(const char *fn, int *size, const char *mode = NULL); extern bool listdir(const char *dir, const char *ext, vector &files); extern int listfiles(const char *dir, const char *ext, vector &files); extern bool delfile(const char *path); extern struct mapstats *loadmapstats(const char *filename, bool getlayout); 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 bool isbigendian(); extern void strtoupper(char *s); struct iprange { enet_uint32 lr, ur; }; extern const char *atoip(const char *s, enet_uint32 *ip); extern const char *atoipr(const char *s, iprange *ir); extern const char *iptoa(const enet_uint32 ip); extern const char *iprtoa(const struct iprange &ipr); extern const char *hiddenpwd(const char *pwd, int showchars = 0); #if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__) extern void stackdumper(unsigned int type, EXCEPTION_POINTERS *ep); #endif #endif