From dc27d1296dce46f1f5a2c095a0abc1e880c869c0 Mon Sep 17 00:00:00 2001 From: q66 Date: Thu, 30 Jul 2020 02:58:53 +0200 Subject: [PATCH] move tools.{cc,hh} into sauerlib/ this will be gradually split up and refactored so that things can move to using libostd over time --- src/client/meson.build | 2 +- src/{shared => sauerlib}/tools.cc | 0 src/sauerlib/tools.hh | 1346 +++++++++++++++++++++++++++++ src/shared/tools.hh | 1342 +--------------------------- 4 files changed, 1348 insertions(+), 1342 deletions(-) rename src/{shared => sauerlib}/tools.cc (100%) create mode 100644 src/sauerlib/tools.hh diff --git a/src/client/meson.build b/src/client/meson.build index 524ca3a..388ad4d 100644 --- a/src/client/meson.build +++ b/src/client/meson.build @@ -1,8 +1,8 @@ client_src = [ + '../sauerlib/tools.cc', '../shared/geom.cc', '../shared/glemu.cc', '../shared/stream.cc', - '../shared/tools.cc', '../shared/zip.cc', '../engine/aa.cc', '../engine/bih.cc', diff --git a/src/shared/tools.cc b/src/sauerlib/tools.cc similarity index 100% rename from src/shared/tools.cc rename to src/sauerlib/tools.cc diff --git a/src/sauerlib/tools.hh b/src/sauerlib/tools.hh new file mode 100644 index 0000000..3e8588d --- /dev/null +++ b/src/sauerlib/tools.hh @@ -0,0 +1,1346 @@ +// generic useful stuff for any C++ program + +#ifndef SAUERLIB_TOOLS_HH +#define SAUERLIB_TOOLS_HH + +#include +#include +#include +#include + +#include +#include + +#ifdef NULL +#undef NULL +#endif +#define NULL 0 + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef signed long long int llong; +typedef unsigned long long int ullong; + +#ifdef _DEBUG +#define ASSERT(c) assert(c) +#else +#define ASSERT(c) if(c) {} +#endif + +#if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1400) +#define RESTRICT __restrict +#else +#define RESTRICT +#endif + +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + +void *operator new(size_t, bool); +void *operator new[](size_t, bool); +inline void *operator new(size_t, void *p) { return p; } +inline void *operator new[](size_t, void *p) { return p; } +inline void operator delete(void *, void *) {} +inline void operator delete[](void *, void *) {} + +#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 max(T a, T b, T c) +{ + return max(max(a, b), c); +} +template +static inline T min(T a, T b) +{ + return a < b ? a : b; +} +template +static inline T min(T a, T b, T c) +{ + return min(min(a, b), c); +} +template +static inline T clamp(T a, U b, U c) +{ + return max(T(b), min(a, T(c))); +} + +#ifdef __GNUC__ +#define bitscan(mask) (__builtin_ffs(mask)-1) +#else +#ifdef WIN32 +#pragma intrinsic(_BitScanForward) +static inline int bitscan(uint mask) +{ + ulong i; + return _BitScanForward(&i, mask) ? i : -1; +} +#else +static inline int bitscan(uint mask) +{ + if(!mask) return -1; + int i = 1; + if(!(mask&0xFFFF)) { i += 16; mask >>= 16; } + if(!(mask&0xFF)) { i += 8; mask >>= 8; } + if(!(mask&0xF)) { i += 4; mask >>= 4; } + if(!(mask&3)) { i += 2; mask >>= 2; } + return i - (mask&1); +} +#endif +#endif + +#define rnd(x) ((int)(randomMT()&0x7FFFFFFF)%(x)) +#define rndscale(x) (float((randomMT()&0x7FFFFFFF)*double(x)/double(0x7FFFFFFF))) +#define detrnd(s, x) ((int)(((((uint)(s))*1103515245+12345)>>16)%(x))) + +#define loop(v,m) for(int v = 0; v < int(m); ++v) +#define loopi(m) loop(i,m) +#define loopj(m) loop(j,m) +#define loopk(m) loop(k,m) +#define loopl(m) loop(l,m) +#define looprev(v,m) for(int v = int(m); --v >= 0;) +#define loopirev(m) looprev(i,m) +#define loopjrev(m) looprev(j,m) +#define loopkrev(m) looprev(k,m) +#define looplrev(m) looprev(l,m) + +#define DELETEP(p) if(p) { delete p; p = 0; } +#define DELETEA(p) if(p) { delete[] p; p = 0; } + +#define PI (3.14159265358979f) +#define SQRT2 (1.4142135623731f) +#define SQRT3 (1.73205080756888f) +#define SQRT5 (2.23606797749979f) +#define RAD (PI / 180.0f) + +#ifdef WIN32 +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_LN2 +#define M_LN2 0.693147180559945309417 +#endif + +#ifndef __GNUC__ +#pragma warning (3: 4189) // local variable is initialized but not referenced +#pragma warning (disable: 4244) // conversion from 'int' to 'float', possible loss of data +#pragma warning (disable: 4267) // conversion from 'size_t' to 'int', possible loss of data +#pragma warning (disable: 4355) // 'this' : used in base member initializer list +#pragma warning (disable: 4996) // 'strncpy' was declared deprecated +#endif + +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define PATHDIV '\\' + +#else +#define __cdecl +#define _vsnprintf vsnprintf +#define PATHDIV '/' +#endif + +#ifdef __GNUC__ +#define PRINTFARGS(fmt, args) __attribute__((format(printf, fmt, args))) +#else +#define PRINTFARGS(fmt, args) +#endif + +// easy safe strings + +#define MAXSTRLEN 260 +typedef char string[MAXSTRLEN]; + +inline void vformatstring(char *d, const char *fmt, va_list v, int len) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; } +template inline void vformatstring(char (&d)[N], const char *fmt, va_list v) { vformatstring(d, fmt, v, N); } + +inline char *copystring(char *d, const char *s, size_t len) +{ + size_t slen = min(strlen(s), len-1); + memcpy(d, s, slen); + d[slen] = 0; + return d; +} +template inline char *copystring(char (&d)[N], const char *s) { return copystring(d, s, N); } + +inline char *concatstring(char *d, const char *s, size_t len) { size_t used = strlen(d); return used < len ? copystring(d+used, s, len-used) : d; } +template inline char *concatstring(char (&d)[N], const char *s) { return concatstring(d, s, N); } + +inline char *prependstring(char *d, const char *s, size_t len) +{ + size_t slen = min(strlen(s), len); + memmove(&d[slen], d, min(len - slen, strlen(d) + 1)); + memcpy(d, s, slen); + d[len-1] = 0; + return d; +} +template inline char *prependstring(char (&d)[N], const char *s) { return prependstring(d, s, N); } + +inline void nformatstring(char *d, int len, const char *fmt, ...) PRINTFARGS(3, 4); +inline void nformatstring(char *d, int len, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + vformatstring(d, fmt, v, len); + va_end(v); +} + +template inline void formatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3); +template inline void formatstring(char (&d)[N], const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + vformatstring(d, fmt, v, int(N)); + va_end(v); +} + +template inline void concformatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3); +template inline void concformatstring(char (&d)[N], const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + int len = strlen(d); + vformatstring(d + len, fmt, v, int(N) - len); + va_end(v); +} + +extern char *tempformatstring(const char *fmt, ...) PRINTFARGS(1, 2); + +#define defformatstring(d,...) string d; formatstring(d, __VA_ARGS__) +#define defvformatstring(d,last,fmt) string d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); } + +template inline bool matchstring(const char *s, size_t len, const char (&d)[N]) +{ + return len == N-1 && !memcmp(s, d, N-1); +} + +inline char *newstring(size_t l) { return new char[l+1]; } +inline char *newstring(const char *s, size_t l) { return copystring(newstring(l), s, l+1); } +inline char *newstring(const char *s) { size_t l = strlen(s); char *d = newstring(l); memcpy(d, s, l+1); return d; } + +inline char *newconcatstring(const char *s, const char *t) +{ + size_t slen = strlen(s), tlen = strlen(t); + char *r = newstring(slen + tlen); + memcpy(r, s, slen); + memcpy(&r[slen], t, tlen); + r[slen+tlen] = '\0'; + return r; +} + +#define loopv(v) for(int i = 0; i<(v).length(); i++) +#define loopvj(v) for(int j = 0; j<(v).length(); j++) +#define loopvk(v) for(int k = 0; k<(v).length(); k++) +#define loopvrev(v) for(int i = (v).length()-1; i>=0; i--) + +template inline void memclear(T *p, size_t n) { memset((void *)p, 0, n * sizeof(T)); } +template inline void memclear(T &p) { memset((void *)&p, 0, sizeof(T)); } +template inline void memclear(T (&p)[N]) { memset((void *)p, 0, N * sizeof(T)); } + +template +struct databuf +{ + enum + { + OVERREAD = 1<<0, + OVERWROTE = 1<<1 + }; + + T *buf; + int len, maxlen; + uchar flags; + + databuf() : buf(NULL), len(0), maxlen(0), flags(0) {} + + template + databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {} + + void reset() + { + len = 0; + flags = 0; + } + + void reset(T *buf_, int maxlen_) + { + reset(); + buf = buf_; + maxlen = maxlen_; + } + + const T &get() + { + static const T overreadval = 0; + if(len= n; } + + void forceoverread() + { + len = maxlen; + flags |= OVERREAD; + } +}; + +typedef databuf ucharbuf; + +template +static inline float heapscore(const T &n) { return n; } + +struct sortless +{ + template bool operator()(const T &x, const T &y) const { return x < y; } + bool operator()(char *x, char *y) const { return strcmp(x, y) < 0; } + bool operator()(const char *x, const char *y) const { return strcmp(x, y) < 0; } +}; + +struct sortnameless +{ + template bool operator()(const T &x, const T &y) const { return sortless()(x.name, y.name); } + template bool operator()(T *x, T *y) const { return sortless()(x->name, y->name); } + template bool operator()(const T *x, const T *y) const { return sortless()(x->name, y->name); } +}; + +template +static inline void insertionsort(T *start, T *end, F fun) +{ + for(T *i = start+1; i < end; i++) + { + if(fun(*i, i[-1])) + { + T tmp = *i; + *i = i[-1]; + T *j = i-1; + for(; j > start && fun(tmp, j[-1]); --j) + *j = j[-1]; + *j = tmp; + } + } + +} + +template +static inline void insertionsort(T *buf, int n, F fun) +{ + insertionsort(buf, buf+n, fun); +} + +template +static inline void insertionsort(T *buf, int n) +{ + insertionsort(buf, buf+n, sortless()); +} + +template +static inline void quicksort(T *start, T *end, F fun) +{ + while(end-start > 10) + { + T *mid = &start[(end-start)/2], *i = start+1, *j = end-2, pivot; + if(fun(*start, *mid)) /* start < mid */ + { + if(fun(end[-1], *start)) { pivot = *start; *start = end[-1]; end[-1] = *mid; } /* end < start < mid */ + else if(fun(end[-1], *mid)) { pivot = end[-1]; end[-1] = *mid; } /* start <= end < mid */ + else { pivot = *mid; } /* start < mid <= end */ + } + else if(fun(*start, end[-1])) { pivot = *start; *start = *mid; } /*mid <= start < end */ + else if(fun(*mid, end[-1])) { pivot = end[-1]; end[-1] = *start; *start = *mid; } /* mid < end <= start */ + else { pivot = *mid; swap(*start, end[-1]); } /* end <= mid <= start */ + *mid = end[-2]; + do + { + while(fun(*i, pivot)) if(++i >= j) goto partitioned; + while(fun(pivot, *--j)) if(i >= j) goto partitioned; + swap(*i, *j); + } + while(++i < j); + partitioned: + end[-2] = *i; + *i = pivot; + + if(i-start < end-(i+1)) + { + quicksort(start, i, fun); + start = i+1; + } + else + { + quicksort(i+1, end, fun); + end = i; + } + } + + insertionsort(start, end, fun); +} + +template +static inline void quicksort(T *buf, int n, F fun) +{ + quicksort(buf, buf+n, fun); +} + +template +static inline void quicksort(T *buf, int n) +{ + quicksort(buf, buf+n, sortless()); +} + +template struct isclass +{ + template static char test(void (C::*)(void)); + template static int test(...); + enum { yes = sizeof(test(0)) == 1 ? 1 : 0, no = yes^1 }; +}; + +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); +} + +struct stringslice +{ + const char *str; + int len; + stringslice() {} + stringslice(const char *str, int len) : str(str), len(len) {} + stringslice(const char *str, const char *end) : str(str), len(int(end-str)) {} + + const char *end() const { return &str[len]; } +}; + +inline char *newstring(const stringslice &s) { return newstring(s.str, s.len); } +inline const char *stringptr(const char *s) { return s; } +inline const char *stringptr(const stringslice &s) { return s.str; } +inline int stringlen(const char *s) { return int(strlen(s)); } +inline int stringlen(const stringslice &s) { return s.len; } + +inline char *copystring(char *d, const stringslice &s, size_t len) +{ + size_t slen = min(size_t(s.len), len-1); + memcpy(d, s.str, slen); + d[slen] = 0; + return d; +} +template inline char *copystring(char (&d)[N], const stringslice &s) { return copystring(d, s, N); } + +static inline uint memhash(const void *ptr, int len) +{ + const uchar *data = (const uchar *)ptr; + uint h = 5381; + loopi(len) h = ((h<<5)+h)^data[i]; + return h; +} + +static inline uint hthash(const stringslice &s) { return memhash(s.str, s.len); } + +static inline bool htcmp(const stringslice &x, const char *y) +{ + return x.len == (int)strlen(y) && !memcmp(x.str, y, x.len); +} + +static inline uint hthash(int key) +{ + return key; +} + +static inline bool htcmp(int x, int y) +{ + return x==y; +} + +#ifdef GL_HH +static inline uint hthash(GLuint key) +{ + return key; +} + +static inline bool htcmp(GLuint x, GLuint y) +{ + return x==y; +} +#endif + +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() { shrink(0); if(buf) delete[] (uchar *)buf; } + + vector &operator=(const vector &v) + { + shrink(0); + if(v.length() > alen) growbuf(v.length()); + loopv(v) add(v[i]); + return *this; + } + + T &add(const T &x) + { + if(ulen==alen) growbuf(ulen+1); + new (&buf[ulen]) T(x); + return buf[ulen++]; + } + + T &add() + { + if(ulen==alen) growbuf(ulen+1); + new (&buf[ulen]) T; + return buf[ulen++]; + } + + T &dup() + { + if(ulen==alen) growbuf(ulen+1); + new (&buf[ulen]) T(buf[ulen-1]); + return buf[ulen++]; + } + + void move(vector &v) + { + if(!ulen) + { + swap(buf, v.buf); + swap(ulen, v.ulen); + swap(alen, v.alen); + } + else + { + growbuf(ulen+v.ulen); + if(v.ulen) memcpy(&buf[ulen], (void *)v.buf, v.ulen*sizeof(T)); + ulen += v.ulen; + v.ulen = 0; + } + } + + bool inrange(size_t i) const { return i=0 && i=0 && i= 0 && i::no) ulen = i; else while(ulen>i) drop(); } + void setsize(int i) { ASSERT(i<=ulen); ulen = i; } + + void deletecontents(int n = 0) { while(ulen > n) delete pop(); } + void deletearrays(int n = 0) { while(ulen > n) 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(F fun, int i = 0, int n = -1) + { + quicksort(&buf[i], n < 0 ? ulen-i : n, fun); + } + + void sort() { sort(sortless()); } + void sortname() { sort(sortnameless()); } + + void growbuf(int sz) + { + int olen = alen; + if(alen <= 0) alen = max(MINSIZE, sz); + else while(alen < sz) alen += alen/2; + if(alen <= olen) return; + uchar *newbuf = new uchar[alen*sizeof(T)]; + if(olen > 0) + { + if(ulen > 0) memcpy(newbuf, (void *)buf, ulen*sizeof(T)); + delete[] (uchar *)buf; + } + buf = (T *)newbuf; + } + + databuf reserve(int sz) + { + if(alen-ulen < sz) growbuf(ulen+sz); + return databuf(&buf[ulen], sz); + } + + void advance(int sz) + { + ulen += sz; + } + + void addbuf(const databuf &p) + { + advance(p.length()); + } + + T *pad(int n) + { + T *buf = reserve(n).buf; + advance(n); + return buf; + } + + void put(const T &v) { add(v); } + + void put(const T *v, int n) + { + databuf buf = reserve(n); + buf.put(v, n); + addbuf(buf); + } + + void remove(int i, int n) + { + for(int p = i+n; p0) buf[i] = buf[ulen]; + return e; + } + + template + int find(const U &o) + { + loopi(ulen) if(buf[i]==o) return i; + return -1; + } + + void addunique(const T &o) + { + if(find(o) < 0) add(o); + } + + void removeobj(const T &o) + { + loopi(ulen) if(buf[i] == o) + { + int dst = i; + for(int j = i+1; j < ulen; j++) if(!(buf[j] == o)) buf[dst++] = buf[j]; + setsize(dst); + break; + } + } + + void replacewithlast(const T &o) + { + if(!ulen) return; + loopi(ulen-1) if(buf[i]==o) + { + buf[i] = buf[ulen-1]; + break; + } + ulen--; + } + + T &insert(int i, const T &e) + { + add(T()); + for(int p = ulen-1; p>i; p--) buf[p] = buf[p-1]; + buf[i] = e; + return buf[i]; + } + + T *insert(int i, const T *e, int n) + { + if(alen-ulen < n) growbuf(ulen+n); + loopj(n) add(T()); + for(int p = ulen-1; p>=i+n; p--) buf[p] = buf[p-n]; + loopj(n) buf[i+j] = e[j]; + return &buf[i]; + } + + void reverse() + { + loopi(ulen/2) swap(buf[i], buf[ulen-1-i]); + } + + static int heapparent(int i) { return (i - 1) >> 1; } + static int heapchild(int i) { return (i << 1) + 1; } + + void buildheap() + { + for(int i = ulen/2; i >= 0; i--) downheap(i); + } + + int upheap(int i) + { + float score = heapscore(buf[i]); + while(i > 0) + { + int pi = heapparent(i); + if(score >= heapscore(buf[pi])) break; + swap(buf[i], buf[pi]); + i = pi; + } + return i; + } + + T &addheap(const T &x) + { + add(x); + return buf[upheap(ulen-1)]; + } + + int downheap(int i) + { + float score = heapscore(buf[i]); + for(;;) + { + int ci = heapchild(i); + if(ci >= ulen) break; + float cscore = heapscore(buf[ci]); + if(score > cscore) + { + if(ci+1 < ulen && heapscore(buf[ci+1]) < cscore) { swap(buf[ci+1], buf[i]); i = ci+1; } + else { swap(buf[ci], buf[i]); i = ci; } + } + else if(ci+1 < ulen && heapscore(buf[ci+1]) < score) { swap(buf[ci+1], buf[i]); i = ci+1; } + else break; + } + return i; + } + + T removeheap() + { + T e = removeunordered(0); + if(ulen) downheap(0); + return e; + } + + template + int htfind(const K &key) + { + loopi(ulen) if(htcmp(key, buf[i])) return i; + return -1; + } + + #define UNIQUE(overwrite, cleanup) \ + for(int i = 1; i < ulen; i++) if(htcmp(buf[i-1], buf[i])) \ + { \ + int n = i; \ + while(++i < ulen) if(!htcmp(buf[n-1], buf[i])) { overwrite; n++; } \ + cleanup; \ + break; \ + } + void unique() // contents must be initially sorted + { + UNIQUE(buf[n] = buf[i], setsize(n)); + } + void uniquedeletecontents() + { + UNIQUE(swap(buf[n], buf[i]), deletecontents(n)); + } + void uniquedeletearrays() + { + UNIQUE(swap(buf[n], buf[i]), deletearrays(n)); + } + #undef UNIQUE +}; + +template struct hashbase +{ + typedef E elemtype; + typedef K keytype; + typedef T datatype; + + enum { CHUNKSIZE = 64 }; + + struct chain { E elem; chain *next; }; + struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; }; + + int size; + int numelems; + chain **chains; + + chainchunk *chunks; + chain *unused; + + enum { DEFAULTSIZE = 1<<10 }; + + hashbase(int size = DEFAULTSIZE) + : size(size) + { + numelems = 0; + chunks = NULL; + unused = NULL; + chains = new chain *[size]; + memset(chains, 0, size*sizeof(chain *)); + } + + ~hashbase() + { + DELETEA(chains); + deletechunks(); + } + + chain *insert(uint h) + { + if(!unused) + { + chainchunk *chunk = new chainchunk; + chunk->next = chunks; + chunks = chunk; + loopi(CHUNKSIZE-1) chunk->chains[i].next = &chunk->chains[i+1]; + chunk->chains[CHUNKSIZE-1].next = unused; + unused = chunk->chains; + } + chain *c = unused; + unused = unused->next; + c->next = chains[h]; + chains[h] = c; + numelems++; + return c; + } + + template + T &insert(uint h, const U &key) + { + chain *c = insert(h); + H::setkey(c->elem, key); + return H::getdata(c->elem); + } + + #define HTFIND(success, fail) \ + uint h = hthash(key)&(this->size-1); \ + for(chain *c = this->chains[h]; c; c = c->next) \ + { \ + if(htcmp(key, H::getkey(c->elem))) return success H::getdata(c->elem); \ + } \ + return (fail); + + template + T *access(const U &key) + { + HTFIND(&, NULL); + } + + template + T &access(const U &key, const V &elem) + { + HTFIND( , insert(h, key) = elem); + } + + template + T &operator[](const U &key) + { + HTFIND( , insert(h, key)); + } + + template + T &find(const U &key, T ¬found) + { + HTFIND( , notfound); + } + + template + const T &find(const U &key, const T ¬found) + { + HTFIND( , notfound); + } + + template + bool remove(const U &key) + { + uint h = hthash(key)&(size-1); + for(chain **p = &chains[h], *c = chains[h]; c; p = &c->next, c = c->next) + { + if(htcmp(key, H::getkey(c->elem))) + { + *p = c->next; + c->elem.~E(); + new (&c->elem) E; + c->next = unused; + unused = c; + numelems--; + return true; + } + } + return false; + } + + void recycle() + { + if(!numelems) return; + loopi(size) + { + chain *c = chains[i]; + if(!c) continue; + for(;;) + { + htrecycle(c->elem); + if(!c->next) break; + c = c->next; + } + c->next = unused; + unused = chains[i]; + chains[i] = NULL; + } + numelems = 0; + } + + void deletechunks() + { + for(chainchunk *nextchunk; chunks; chunks = nextchunk) + { + nextchunk = chunks->next; + delete chunks; + } + } + + void clear() + { + if(!numelems) return; + memset(chains, 0, size*sizeof(chain *)); + numelems = 0; + unused = NULL; + deletechunks(); + } + + static inline chain *enumnext(void *i) { return ((chain *)i)->next; } + static inline K &enumkey(void *i) { return H::getkey(((chain *)i)->elem); } + static inline T &enumdata(void *i) { return H::getdata(((chain *)i)->elem); } +}; + +template static inline void htrecycle(const T &) {} + +template struct hashset : hashbase, T, T, T> +{ + typedef hashbase, T, T, T> basetype; + + hashset(int size = basetype::DEFAULTSIZE) : basetype(size) {} + + static inline const T &getkey(const T &elem) { return elem; } + static inline T &getdata(T &elem) { return elem; } + template static inline void setkey(T &elem, const K &key) {} + + template + T &add(const V &elem) + { + return basetype::access(elem, elem); + } +}; + +template struct hashnameset : hashbase, T, const char *, T> +{ + typedef hashbase, T, const char *, T> basetype; + + hashnameset(int size = basetype::DEFAULTSIZE) : basetype(size) {} + + template static inline const char *getkey(const U &elem) { return elem.name; } + template static inline const char *getkey(U *elem) { return elem->name; } + static inline T &getdata(T &elem) { return elem; } + template static inline void setkey(T &elem, const K &key) {} + + template + T &add(const V &elem) + { + return basetype::access(getkey(elem), elem); + } +}; + +template struct hashtableentry +{ + K key; + T data; +}; + +template +static inline void htrecycle(hashtableentry &entry) +{ + htrecycle(entry.key); + htrecycle(entry.data); +} + +template struct hashtable : hashbase, hashtableentry, K, T> +{ + typedef hashbase, hashtableentry, K, T> basetype; + typedef typename basetype::elemtype elemtype; + + hashtable(int size = basetype::DEFAULTSIZE) : basetype(size) {} + + static inline K &getkey(elemtype &elem) { return elem.key; } + static inline T &getdata(elemtype &elem) { return elem.data; } + template static inline void setkey(elemtype &elem, const U &key) { elem.key = key; } +}; + +#define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { k &e = (ht).enumkey(ec); t &f = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; } +#define enumerate(ht,t,e,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { t &e = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; } + +template struct queue +{ + int head, tail, len; + T data[SIZE]; + + queue() { clear(); } + + void clear() { head = tail = len = 0; } + + int length() const { return len; } + bool empty() const { return !len; } + bool full() const { return len == SIZE; } + + bool inrange(size_t i) const { return i=0 && i 0 ? tail-1 : SIZE-1]; } + T &added(int offset) { return data[tail-offset > 0 ? tail-offset-1 : tail-offset-1 + SIZE]; } + T &adding() { return data[tail]; } + T &adding(int offset) { return data[tail+offset >= SIZE ? tail+offset - SIZE : tail+offset]; } + T &add() + { + T &t = data[tail]; + tail++; + if(tail >= SIZE) tail -= SIZE; + if(len < SIZE) len++; + return t; + } + T &add(const T &e) { return add() = e; } + + T &pop() + { + tail--; + if(tail < 0) tail += SIZE; + len--; + return data[tail]; + } + + T &removing() { return data[head]; } + T &removing(int offset) { return data[head+offset >= SIZE ? head+offset - SIZE : head+offset]; } + T &remove() + { + T &t = data[head]; + head++; + if(head >= SIZE) head -= SIZE; + len--; + return t; + } + + T &operator[](int offset) { return removing(offset); } + const T &operator[](int offset) const { return removing(offset); } +}; + +template struct reversequeue : queue +{ + T &operator[](int offset) { return queue::added(offset); } + const T &operator[](int offset) const { return queue::added(offset); } +}; + +static inline bool islittleendian() { union { int i; uchar b[sizeof(int)]; } conv; conv.i = 1; return conv.b[0] != 0; } +#ifdef SDL_BYTEORDER +#define endianswap16 SDL_Swap16 +#define endianswap32 SDL_Swap32 +#define endianswap64 SDL_Swap64 +#else +inline ushort endianswap16(ushort n) { return (n<<8) | (n>>8); } +inline uint endianswap32(uint n) { return (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000); } +inline ullong endianswap64(ullong n) { return endianswap32(uint(n >> 32)) | ((ullong)endianswap32(uint(n)) << 32); } +#endif +template inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = endianswap32(conv.i); return conv.t; } +template<> inline ushort endianswap(ushort n) { return endianswap16(n); } +template<> inline short endianswap(short n) { return endianswap16(n); } +template<> inline uint endianswap(uint n) { return endianswap32(n); } +template<> inline int endianswap(int n) { return endianswap32(n); } +template<> inline ullong endianswap(ullong n) { return endianswap64(n); } +template<> inline llong endianswap(llong n) { return endianswap64(n); } +template<> inline double endianswap(double n) { union { double t; uint i; } conv; conv.t = n; conv.i = endianswap64(conv.i); return conv.t; } +template inline void endianswap(T *buf, size_t len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); } +template inline T endiansame(T n) { return n; } +template inline void endiansame(T *buf, size_t len) {} +#ifdef SDL_BYTEORDER +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define lilswap endiansame +#define bigswap endianswap +#else +#define lilswap endianswap +#define bigswap endiansame +#endif +#elif defined(__BYTE_ORDER__) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define lilswap endiansame +#define bigswap endianswap +#else +#define lilswap endianswap +#define bigswap endiansame +#endif +#else +template inline T lilswap(T n) { return islittleendian() ? n : endianswap(n); } +template inline void lilswap(T *buf, size_t len) { if(!islittleendian()) endianswap(buf, len); } +template inline T bigswap(T n) { return islittleendian() ? endianswap(n) : n; } +template inline void bigswap(T *buf, size_t len) { if(islittleendian()) endianswap(buf, len); } +#endif + +/* workaround for some C platforms that have these two functions as macros - not used anywhere */ +#ifdef getchar +#undef getchar +#endif +#ifdef putchar +#undef putchar +#endif + +struct stream +{ +#ifdef WIN32 +#if defined(__GNUC__) && !defined(__MINGW32__) + typedef off64_t offset; +#else + typedef __int64 offset; +#endif +#else + typedef off_t offset; +#endif + + virtual ~stream() {} + virtual void close() = 0; + virtual bool end() = 0; + virtual offset tell() { return -1; } + virtual offset rawtell() { return tell(); } + virtual bool seek(offset pos, int whence = SEEK_SET) { return false; } + virtual offset size(); + virtual offset rawsize() { return size(); } + virtual size_t read(void *buf, size_t len) { return 0; } + virtual size_t write(const void *buf, size_t len) { return 0; } + virtual bool flush() { return true; } + virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; } + virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; } + virtual bool getline(char *str, size_t len); + virtual bool putstring(const char *str) { size_t len = strlen(str); return write(str, len) == len; } + virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); } + virtual size_t printf(const char *fmt, ...) PRINTFARGS(2, 3); + virtual uint getcrc() { return 0; } + + template size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); } + template bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); } + template bool putlil(T n) { return put(lilswap(n)); } + template bool putbig(T n) { return put(bigswap(n)); } + + template size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); } + template T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; } + template T getlil() { return lilswap(get()); } + template T getbig() { return bigswap(get()); } + +#ifndef STANDALONE + SDL_RWops *rwops(); +#endif +}; + +template +struct streambuf +{ + stream *s; + + streambuf(stream *s) : s(s) {} + + T get() { return s->get(); } + size_t get(T *vals, size_t numvals) { return s->get(vals, numvals); } + void put(const T &val) { s->put(&val, 1); } + void put(const T *vals, size_t numvals) { s->put(vals, numvals); } + size_t length() { return s->size(); } +}; + +enum +{ + CT_PRINT = 1<<0, + CT_SPACE = 1<<1, + CT_DIGIT = 1<<2, + CT_ALPHA = 1<<3, + CT_LOWER = 1<<4, + CT_UPPER = 1<<5, + CT_UNICODE = 1<<6 +}; +extern const uchar cubectype[256]; +static inline int iscubeprint(uchar c) { return cubectype[c]&CT_PRINT; } +static inline int iscubespace(uchar c) { return cubectype[c]&CT_SPACE; } +static inline int iscubealpha(uchar c) { return cubectype[c]&CT_ALPHA; } +static inline int iscubealnum(uchar c) { return cubectype[c]&(CT_ALPHA|CT_DIGIT); } +static inline int iscubelower(uchar c) { return cubectype[c]&CT_LOWER; } +static inline int iscubeupper(uchar c) { return cubectype[c]&CT_UPPER; } +static inline int iscubepunct(uchar c) { return cubectype[c] == CT_PRINT; } +static inline int cube2uni(uchar c) +{ + extern const int cube2unichars[256]; + return cube2unichars[c]; +} +static inline uchar uni2cube(int c) +{ + extern const int uni2cubeoffsets[8]; + extern const uchar uni2cubechars[]; + return uint(c) <= 0x7FF ? uni2cubechars[uni2cubeoffsets[c>>8] + (c&0xFF)] : 0; +} +static inline uchar cubelower(uchar c) +{ + extern const uchar cubelowerchars[256]; + return cubelowerchars[c]; +} +static inline uchar cubeupper(uchar c) +{ + extern const uchar cubeupperchars[256]; + return cubeupperchars[c]; +} +extern size_t decodeutf8(uchar *dst, size_t dstlen, const uchar *src, size_t srclen, size_t *carry = NULL); +extern size_t encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry = NULL); + +extern string homedir; + +extern char *makerelpath(const char *dir, const char *file, const char *prefix = NULL, const char *cmd = NULL); +extern char *path(char *s); +extern char *path(const char *s, bool copy); +extern const char *parentdir(const char *directory); +extern bool fileexists(const char *path, const char *mode); +extern bool createdir(const char *path); +extern size_t fixpackagedir(char *dir); +extern const char *sethomedir(const char *dir); +extern const char *addpackagedir(const char *dir); +extern const char *findfile(const char *filename, const char *mode); +extern bool findzipfile(const char *filename); +extern stream *openrawfile(const char *filename, const char *mode); +extern stream *openzipfile(const char *filename, const char *mode); +extern stream *openfile(const char *filename, const char *mode); +extern stream *opentempfile(const char *filename, const char *mode); +extern stream *opengzfile(const char *filename, const char *mode, stream *file = NULL, int level = Z_BEST_COMPRESSION); +extern stream *openutf8file(const char *filename, const char *mode, stream *file = NULL); +extern char *loadfile(const char *fn, size_t *size, bool utf8 = true); +extern bool listdir(const char *dir, bool rel, const char *ext, vector &files); +extern int listfiles(const char *dir, const char *ext, vector &files); +extern int listzipfiles(const char *dir, const char *ext, vector &files); +extern void seedMT(uint seed); +extern uint randomMT(); + +extern void putint(ucharbuf &p, int n); +extern void putint(vector &p, int n); +extern int getint(ucharbuf &p); +extern void putuint(ucharbuf &p, int n); +extern void putuint(vector &p, int n); +extern int getuint(ucharbuf &p); +extern void putfloat(ucharbuf &p, float f); +extern void putfloat(vector &p, float f); +extern float getfloat(ucharbuf &p); +extern void sendstring(const char *t, ucharbuf &p); +extern void sendstring(const char *t, vector &p); +extern void getstring(char *t, ucharbuf &p, size_t len); +template static inline void getstring(char (&t)[N], ucharbuf &p) { getstring(t, p, N); } +extern void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len); +template static inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); } + +#endif + diff --git a/src/shared/tools.hh b/src/shared/tools.hh index db6c8ed..0188b0a 100644 --- a/src/shared/tools.hh +++ b/src/shared/tools.hh @@ -1,1346 +1,6 @@ -// generic useful stuff for any C++ program - #ifndef _TOOLS_H #define _TOOLS_H -#include -#include -#include -#include - -#include -#include - -#ifdef NULL -#undef NULL -#endif -#define NULL 0 - -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; -typedef signed long long int llong; -typedef unsigned long long int ullong; - -#ifdef _DEBUG -#define ASSERT(c) assert(c) -#else -#define ASSERT(c) if(c) {} -#endif - -#if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1400) -#define RESTRICT __restrict -#else -#define RESTRICT -#endif - -#ifdef __GNUC__ -#define UNUSED __attribute__((unused)) -#else -#define UNUSED -#endif - -void *operator new(size_t, bool); -void *operator new[](size_t, bool); -inline void *operator new(size_t, void *p) { return p; } -inline void *operator new[](size_t, void *p) { return p; } -inline void operator delete(void *, void *) {} -inline void operator delete[](void *, void *) {} - -#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 max(T a, T b, T c) -{ - return max(max(a, b), c); -} -template -static inline T min(T a, T b) -{ - return a < b ? a : b; -} -template -static inline T min(T a, T b, T c) -{ - return min(min(a, b), c); -} -template -static inline T clamp(T a, U b, U c) -{ - return max(T(b), min(a, T(c))); -} - -#ifdef __GNUC__ -#define bitscan(mask) (__builtin_ffs(mask)-1) -#else -#ifdef WIN32 -#pragma intrinsic(_BitScanForward) -static inline int bitscan(uint mask) -{ - ulong i; - return _BitScanForward(&i, mask) ? i : -1; -} -#else -static inline int bitscan(uint mask) -{ - if(!mask) return -1; - int i = 1; - if(!(mask&0xFFFF)) { i += 16; mask >>= 16; } - if(!(mask&0xFF)) { i += 8; mask >>= 8; } - if(!(mask&0xF)) { i += 4; mask >>= 4; } - if(!(mask&3)) { i += 2; mask >>= 2; } - return i - (mask&1); -} -#endif -#endif - -#define rnd(x) ((int)(randomMT()&0x7FFFFFFF)%(x)) -#define rndscale(x) (float((randomMT()&0x7FFFFFFF)*double(x)/double(0x7FFFFFFF))) -#define detrnd(s, x) ((int)(((((uint)(s))*1103515245+12345)>>16)%(x))) - -#define loop(v,m) for(int v = 0; v < int(m); ++v) -#define loopi(m) loop(i,m) -#define loopj(m) loop(j,m) -#define loopk(m) loop(k,m) -#define loopl(m) loop(l,m) -#define looprev(v,m) for(int v = int(m); --v >= 0;) -#define loopirev(m) looprev(i,m) -#define loopjrev(m) looprev(j,m) -#define loopkrev(m) looprev(k,m) -#define looplrev(m) looprev(l,m) - -#define DELETEP(p) if(p) { delete p; p = 0; } -#define DELETEA(p) if(p) { delete[] p; p = 0; } - -#define PI (3.14159265358979f) -#define SQRT2 (1.4142135623731f) -#define SQRT3 (1.73205080756888f) -#define SQRT5 (2.23606797749979f) -#define RAD (PI / 180.0f) - -#ifdef WIN32 -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif -#ifndef M_LN2 -#define M_LN2 0.693147180559945309417 -#endif - -#ifndef __GNUC__ -#pragma warning (3: 4189) // local variable is initialized but not referenced -#pragma warning (disable: 4244) // conversion from 'int' to 'float', possible loss of data -#pragma warning (disable: 4267) // conversion from 'size_t' to 'int', possible loss of data -#pragma warning (disable: 4355) // 'this' : used in base member initializer list -#pragma warning (disable: 4996) // 'strncpy' was declared deprecated -#endif - -#define strcasecmp _stricmp -#define strncasecmp _strnicmp -#define PATHDIV '\\' - -#else -#define __cdecl -#define _vsnprintf vsnprintf -#define PATHDIV '/' -#endif - -#ifdef __GNUC__ -#define PRINTFARGS(fmt, args) __attribute__((format(printf, fmt, args))) -#else -#define PRINTFARGS(fmt, args) -#endif - -// easy safe strings - -#define MAXSTRLEN 260 -typedef char string[MAXSTRLEN]; - -inline void vformatstring(char *d, const char *fmt, va_list v, int len) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; } -template inline void vformatstring(char (&d)[N], const char *fmt, va_list v) { vformatstring(d, fmt, v, N); } - -inline char *copystring(char *d, const char *s, size_t len) -{ - size_t slen = min(strlen(s), len-1); - memcpy(d, s, slen); - d[slen] = 0; - return d; -} -template inline char *copystring(char (&d)[N], const char *s) { return copystring(d, s, N); } - -inline char *concatstring(char *d, const char *s, size_t len) { size_t used = strlen(d); return used < len ? copystring(d+used, s, len-used) : d; } -template inline char *concatstring(char (&d)[N], const char *s) { return concatstring(d, s, N); } - -inline char *prependstring(char *d, const char *s, size_t len) -{ - size_t slen = min(strlen(s), len); - memmove(&d[slen], d, min(len - slen, strlen(d) + 1)); - memcpy(d, s, slen); - d[len-1] = 0; - return d; -} -template inline char *prependstring(char (&d)[N], const char *s) { return prependstring(d, s, N); } - -inline void nformatstring(char *d, int len, const char *fmt, ...) PRINTFARGS(3, 4); -inline void nformatstring(char *d, int len, const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - vformatstring(d, fmt, v, len); - va_end(v); -} - -template inline void formatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3); -template inline void formatstring(char (&d)[N], const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - vformatstring(d, fmt, v, int(N)); - va_end(v); -} - -template inline void concformatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3); -template inline void concformatstring(char (&d)[N], const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - int len = strlen(d); - vformatstring(d + len, fmt, v, int(N) - len); - va_end(v); -} - -extern char *tempformatstring(const char *fmt, ...) PRINTFARGS(1, 2); - -#define defformatstring(d,...) string d; formatstring(d, __VA_ARGS__) -#define defvformatstring(d,last,fmt) string d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); } - -template inline bool matchstring(const char *s, size_t len, const char (&d)[N]) -{ - return len == N-1 && !memcmp(s, d, N-1); -} - -inline char *newstring(size_t l) { return new char[l+1]; } -inline char *newstring(const char *s, size_t l) { return copystring(newstring(l), s, l+1); } -inline char *newstring(const char *s) { size_t l = strlen(s); char *d = newstring(l); memcpy(d, s, l+1); return d; } - -inline char *newconcatstring(const char *s, const char *t) -{ - size_t slen = strlen(s), tlen = strlen(t); - char *r = newstring(slen + tlen); - memcpy(r, s, slen); - memcpy(&r[slen], t, tlen); - r[slen+tlen] = '\0'; - return r; -} - -#define loopv(v) for(int i = 0; i<(v).length(); i++) -#define loopvj(v) for(int j = 0; j<(v).length(); j++) -#define loopvk(v) for(int k = 0; k<(v).length(); k++) -#define loopvrev(v) for(int i = (v).length()-1; i>=0; i--) - -template inline void memclear(T *p, size_t n) { memset((void *)p, 0, n * sizeof(T)); } -template inline void memclear(T &p) { memset((void *)&p, 0, sizeof(T)); } -template inline void memclear(T (&p)[N]) { memset((void *)p, 0, N * sizeof(T)); } - -template -struct databuf -{ - enum - { - OVERREAD = 1<<0, - OVERWROTE = 1<<1 - }; - - T *buf; - int len, maxlen; - uchar flags; - - databuf() : buf(NULL), len(0), maxlen(0), flags(0) {} - - template - databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {} - - void reset() - { - len = 0; - flags = 0; - } - - void reset(T *buf_, int maxlen_) - { - reset(); - buf = buf_; - maxlen = maxlen_; - } - - const T &get() - { - static const T overreadval = 0; - if(len= n; } - - void forceoverread() - { - len = maxlen; - flags |= OVERREAD; - } -}; - -typedef databuf ucharbuf; - -template -static inline float heapscore(const T &n) { return n; } - -struct sortless -{ - template bool operator()(const T &x, const T &y) const { return x < y; } - bool operator()(char *x, char *y) const { return strcmp(x, y) < 0; } - bool operator()(const char *x, const char *y) const { return strcmp(x, y) < 0; } -}; - -struct sortnameless -{ - template bool operator()(const T &x, const T &y) const { return sortless()(x.name, y.name); } - template bool operator()(T *x, T *y) const { return sortless()(x->name, y->name); } - template bool operator()(const T *x, const T *y) const { return sortless()(x->name, y->name); } -}; - -template -static inline void insertionsort(T *start, T *end, F fun) -{ - for(T *i = start+1; i < end; i++) - { - if(fun(*i, i[-1])) - { - T tmp = *i; - *i = i[-1]; - T *j = i-1; - for(; j > start && fun(tmp, j[-1]); --j) - *j = j[-1]; - *j = tmp; - } - } - -} - -template -static inline void insertionsort(T *buf, int n, F fun) -{ - insertionsort(buf, buf+n, fun); -} - -template -static inline void insertionsort(T *buf, int n) -{ - insertionsort(buf, buf+n, sortless()); -} - -template -static inline void quicksort(T *start, T *end, F fun) -{ - while(end-start > 10) - { - T *mid = &start[(end-start)/2], *i = start+1, *j = end-2, pivot; - if(fun(*start, *mid)) /* start < mid */ - { - if(fun(end[-1], *start)) { pivot = *start; *start = end[-1]; end[-1] = *mid; } /* end < start < mid */ - else if(fun(end[-1], *mid)) { pivot = end[-1]; end[-1] = *mid; } /* start <= end < mid */ - else { pivot = *mid; } /* start < mid <= end */ - } - else if(fun(*start, end[-1])) { pivot = *start; *start = *mid; } /*mid <= start < end */ - else if(fun(*mid, end[-1])) { pivot = end[-1]; end[-1] = *start; *start = *mid; } /* mid < end <= start */ - else { pivot = *mid; swap(*start, end[-1]); } /* end <= mid <= start */ - *mid = end[-2]; - do - { - while(fun(*i, pivot)) if(++i >= j) goto partitioned; - while(fun(pivot, *--j)) if(i >= j) goto partitioned; - swap(*i, *j); - } - while(++i < j); - partitioned: - end[-2] = *i; - *i = pivot; - - if(i-start < end-(i+1)) - { - quicksort(start, i, fun); - start = i+1; - } - else - { - quicksort(i+1, end, fun); - end = i; - } - } - - insertionsort(start, end, fun); -} - -template -static inline void quicksort(T *buf, int n, F fun) -{ - quicksort(buf, buf+n, fun); -} - -template -static inline void quicksort(T *buf, int n) -{ - quicksort(buf, buf+n, sortless()); -} - -template struct isclass -{ - template static char test(void (C::*)(void)); - template static int test(...); - enum { yes = sizeof(test(0)) == 1 ? 1 : 0, no = yes^1 }; -}; - -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); -} - -struct stringslice -{ - const char *str; - int len; - stringslice() {} - stringslice(const char *str, int len) : str(str), len(len) {} - stringslice(const char *str, const char *end) : str(str), len(int(end-str)) {} - - const char *end() const { return &str[len]; } -}; - -inline char *newstring(const stringslice &s) { return newstring(s.str, s.len); } -inline const char *stringptr(const char *s) { return s; } -inline const char *stringptr(const stringslice &s) { return s.str; } -inline int stringlen(const char *s) { return int(strlen(s)); } -inline int stringlen(const stringslice &s) { return s.len; } - -inline char *copystring(char *d, const stringslice &s, size_t len) -{ - size_t slen = min(size_t(s.len), len-1); - memcpy(d, s.str, slen); - d[slen] = 0; - return d; -} -template inline char *copystring(char (&d)[N], const stringslice &s) { return copystring(d, s, N); } - -static inline uint memhash(const void *ptr, int len) -{ - const uchar *data = (const uchar *)ptr; - uint h = 5381; - loopi(len) h = ((h<<5)+h)^data[i]; - return h; -} - -static inline uint hthash(const stringslice &s) { return memhash(s.str, s.len); } - -static inline bool htcmp(const stringslice &x, const char *y) -{ - return x.len == (int)strlen(y) && !memcmp(x.str, y, x.len); -} - -static inline uint hthash(int key) -{ - return key; -} - -static inline bool htcmp(int x, int y) -{ - return x==y; -} - -#ifdef GL_HH -static inline uint hthash(GLuint key) -{ - return key; -} - -static inline bool htcmp(GLuint x, GLuint y) -{ - return x==y; -} -#endif - -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() { shrink(0); if(buf) delete[] (uchar *)buf; } - - vector &operator=(const vector &v) - { - shrink(0); - if(v.length() > alen) growbuf(v.length()); - loopv(v) add(v[i]); - return *this; - } - - T &add(const T &x) - { - if(ulen==alen) growbuf(ulen+1); - new (&buf[ulen]) T(x); - return buf[ulen++]; - } - - T &add() - { - if(ulen==alen) growbuf(ulen+1); - new (&buf[ulen]) T; - return buf[ulen++]; - } - - T &dup() - { - if(ulen==alen) growbuf(ulen+1); - new (&buf[ulen]) T(buf[ulen-1]); - return buf[ulen++]; - } - - void move(vector &v) - { - if(!ulen) - { - swap(buf, v.buf); - swap(ulen, v.ulen); - swap(alen, v.alen); - } - else - { - growbuf(ulen+v.ulen); - if(v.ulen) memcpy(&buf[ulen], (void *)v.buf, v.ulen*sizeof(T)); - ulen += v.ulen; - v.ulen = 0; - } - } - - bool inrange(size_t i) const { return i=0 && i=0 && i= 0 && i::no) ulen = i; else while(ulen>i) drop(); } - void setsize(int i) { ASSERT(i<=ulen); ulen = i; } - - void deletecontents(int n = 0) { while(ulen > n) delete pop(); } - void deletearrays(int n = 0) { while(ulen > n) 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(F fun, int i = 0, int n = -1) - { - quicksort(&buf[i], n < 0 ? ulen-i : n, fun); - } - - void sort() { sort(sortless()); } - void sortname() { sort(sortnameless()); } - - void growbuf(int sz) - { - int olen = alen; - if(alen <= 0) alen = max(MINSIZE, sz); - else while(alen < sz) alen += alen/2; - if(alen <= olen) return; - uchar *newbuf = new uchar[alen*sizeof(T)]; - if(olen > 0) - { - if(ulen > 0) memcpy(newbuf, (void *)buf, ulen*sizeof(T)); - delete[] (uchar *)buf; - } - buf = (T *)newbuf; - } - - databuf reserve(int sz) - { - if(alen-ulen < sz) growbuf(ulen+sz); - return databuf(&buf[ulen], sz); - } - - void advance(int sz) - { - ulen += sz; - } - - void addbuf(const databuf &p) - { - advance(p.length()); - } - - T *pad(int n) - { - T *buf = reserve(n).buf; - advance(n); - return buf; - } - - void put(const T &v) { add(v); } - - void put(const T *v, int n) - { - databuf buf = reserve(n); - buf.put(v, n); - addbuf(buf); - } - - void remove(int i, int n) - { - for(int p = i+n; p0) buf[i] = buf[ulen]; - return e; - } - - template - int find(const U &o) - { - loopi(ulen) if(buf[i]==o) return i; - return -1; - } - - void addunique(const T &o) - { - if(find(o) < 0) add(o); - } - - void removeobj(const T &o) - { - loopi(ulen) if(buf[i] == o) - { - int dst = i; - for(int j = i+1; j < ulen; j++) if(!(buf[j] == o)) buf[dst++] = buf[j]; - setsize(dst); - break; - } - } - - void replacewithlast(const T &o) - { - if(!ulen) return; - loopi(ulen-1) if(buf[i]==o) - { - buf[i] = buf[ulen-1]; - break; - } - ulen--; - } - - T &insert(int i, const T &e) - { - add(T()); - for(int p = ulen-1; p>i; p--) buf[p] = buf[p-1]; - buf[i] = e; - return buf[i]; - } - - T *insert(int i, const T *e, int n) - { - if(alen-ulen < n) growbuf(ulen+n); - loopj(n) add(T()); - for(int p = ulen-1; p>=i+n; p--) buf[p] = buf[p-n]; - loopj(n) buf[i+j] = e[j]; - return &buf[i]; - } - - void reverse() - { - loopi(ulen/2) swap(buf[i], buf[ulen-1-i]); - } - - static int heapparent(int i) { return (i - 1) >> 1; } - static int heapchild(int i) { return (i << 1) + 1; } - - void buildheap() - { - for(int i = ulen/2; i >= 0; i--) downheap(i); - } - - int upheap(int i) - { - float score = heapscore(buf[i]); - while(i > 0) - { - int pi = heapparent(i); - if(score >= heapscore(buf[pi])) break; - swap(buf[i], buf[pi]); - i = pi; - } - return i; - } - - T &addheap(const T &x) - { - add(x); - return buf[upheap(ulen-1)]; - } - - int downheap(int i) - { - float score = heapscore(buf[i]); - for(;;) - { - int ci = heapchild(i); - if(ci >= ulen) break; - float cscore = heapscore(buf[ci]); - if(score > cscore) - { - if(ci+1 < ulen && heapscore(buf[ci+1]) < cscore) { swap(buf[ci+1], buf[i]); i = ci+1; } - else { swap(buf[ci], buf[i]); i = ci; } - } - else if(ci+1 < ulen && heapscore(buf[ci+1]) < score) { swap(buf[ci+1], buf[i]); i = ci+1; } - else break; - } - return i; - } - - T removeheap() - { - T e = removeunordered(0); - if(ulen) downheap(0); - return e; - } - - template - int htfind(const K &key) - { - loopi(ulen) if(htcmp(key, buf[i])) return i; - return -1; - } - - #define UNIQUE(overwrite, cleanup) \ - for(int i = 1; i < ulen; i++) if(htcmp(buf[i-1], buf[i])) \ - { \ - int n = i; \ - while(++i < ulen) if(!htcmp(buf[n-1], buf[i])) { overwrite; n++; } \ - cleanup; \ - break; \ - } - void unique() // contents must be initially sorted - { - UNIQUE(buf[n] = buf[i], setsize(n)); - } - void uniquedeletecontents() - { - UNIQUE(swap(buf[n], buf[i]), deletecontents(n)); - } - void uniquedeletearrays() - { - UNIQUE(swap(buf[n], buf[i]), deletearrays(n)); - } - #undef UNIQUE -}; - -template struct hashbase -{ - typedef E elemtype; - typedef K keytype; - typedef T datatype; - - enum { CHUNKSIZE = 64 }; - - struct chain { E elem; chain *next; }; - struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; }; - - int size; - int numelems; - chain **chains; - - chainchunk *chunks; - chain *unused; - - enum { DEFAULTSIZE = 1<<10 }; - - hashbase(int size = DEFAULTSIZE) - : size(size) - { - numelems = 0; - chunks = NULL; - unused = NULL; - chains = new chain *[size]; - memset(chains, 0, size*sizeof(chain *)); - } - - ~hashbase() - { - DELETEA(chains); - deletechunks(); - } - - chain *insert(uint h) - { - if(!unused) - { - chainchunk *chunk = new chainchunk; - chunk->next = chunks; - chunks = chunk; - loopi(CHUNKSIZE-1) chunk->chains[i].next = &chunk->chains[i+1]; - chunk->chains[CHUNKSIZE-1].next = unused; - unused = chunk->chains; - } - chain *c = unused; - unused = unused->next; - c->next = chains[h]; - chains[h] = c; - numelems++; - return c; - } - - template - T &insert(uint h, const U &key) - { - chain *c = insert(h); - H::setkey(c->elem, key); - return H::getdata(c->elem); - } - - #define HTFIND(success, fail) \ - uint h = hthash(key)&(this->size-1); \ - for(chain *c = this->chains[h]; c; c = c->next) \ - { \ - if(htcmp(key, H::getkey(c->elem))) return success H::getdata(c->elem); \ - } \ - return (fail); - - template - T *access(const U &key) - { - HTFIND(&, NULL); - } - - template - T &access(const U &key, const V &elem) - { - HTFIND( , insert(h, key) = elem); - } - - template - T &operator[](const U &key) - { - HTFIND( , insert(h, key)); - } - - template - T &find(const U &key, T ¬found) - { - HTFIND( , notfound); - } - - template - const T &find(const U &key, const T ¬found) - { - HTFIND( , notfound); - } - - template - bool remove(const U &key) - { - uint h = hthash(key)&(size-1); - for(chain **p = &chains[h], *c = chains[h]; c; p = &c->next, c = c->next) - { - if(htcmp(key, H::getkey(c->elem))) - { - *p = c->next; - c->elem.~E(); - new (&c->elem) E; - c->next = unused; - unused = c; - numelems--; - return true; - } - } - return false; - } - - void recycle() - { - if(!numelems) return; - loopi(size) - { - chain *c = chains[i]; - if(!c) continue; - for(;;) - { - htrecycle(c->elem); - if(!c->next) break; - c = c->next; - } - c->next = unused; - unused = chains[i]; - chains[i] = NULL; - } - numelems = 0; - } - - void deletechunks() - { - for(chainchunk *nextchunk; chunks; chunks = nextchunk) - { - nextchunk = chunks->next; - delete chunks; - } - } - - void clear() - { - if(!numelems) return; - memset(chains, 0, size*sizeof(chain *)); - numelems = 0; - unused = NULL; - deletechunks(); - } - - static inline chain *enumnext(void *i) { return ((chain *)i)->next; } - static inline K &enumkey(void *i) { return H::getkey(((chain *)i)->elem); } - static inline T &enumdata(void *i) { return H::getdata(((chain *)i)->elem); } -}; - -template static inline void htrecycle(const T &) {} - -template struct hashset : hashbase, T, T, T> -{ - typedef hashbase, T, T, T> basetype; - - hashset(int size = basetype::DEFAULTSIZE) : basetype(size) {} - - static inline const T &getkey(const T &elem) { return elem; } - static inline T &getdata(T &elem) { return elem; } - template static inline void setkey(T &elem, const K &key) {} - - template - T &add(const V &elem) - { - return basetype::access(elem, elem); - } -}; - -template struct hashnameset : hashbase, T, const char *, T> -{ - typedef hashbase, T, const char *, T> basetype; - - hashnameset(int size = basetype::DEFAULTSIZE) : basetype(size) {} - - template static inline const char *getkey(const U &elem) { return elem.name; } - template static inline const char *getkey(U *elem) { return elem->name; } - static inline T &getdata(T &elem) { return elem; } - template static inline void setkey(T &elem, const K &key) {} - - template - T &add(const V &elem) - { - return basetype::access(getkey(elem), elem); - } -}; - -template struct hashtableentry -{ - K key; - T data; -}; - -template -static inline void htrecycle(hashtableentry &entry) -{ - htrecycle(entry.key); - htrecycle(entry.data); -} - -template struct hashtable : hashbase, hashtableentry, K, T> -{ - typedef hashbase, hashtableentry, K, T> basetype; - typedef typename basetype::elemtype elemtype; - - hashtable(int size = basetype::DEFAULTSIZE) : basetype(size) {} - - static inline K &getkey(elemtype &elem) { return elem.key; } - static inline T &getdata(elemtype &elem) { return elem.data; } - template static inline void setkey(elemtype &elem, const U &key) { elem.key = key; } -}; - -#define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { k &e = (ht).enumkey(ec); t &f = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; } -#define enumerate(ht,t,e,b) loopi((ht).size) for(void *ec = (ht).chains[i]; ec;) { t &e = (ht).enumdata(ec); ec = (ht).enumnext(ec); b; } - -template struct queue -{ - int head, tail, len; - T data[SIZE]; - - queue() { clear(); } - - void clear() { head = tail = len = 0; } - - int length() const { return len; } - bool empty() const { return !len; } - bool full() const { return len == SIZE; } - - bool inrange(size_t i) const { return i=0 && i 0 ? tail-1 : SIZE-1]; } - T &added(int offset) { return data[tail-offset > 0 ? tail-offset-1 : tail-offset-1 + SIZE]; } - T &adding() { return data[tail]; } - T &adding(int offset) { return data[tail+offset >= SIZE ? tail+offset - SIZE : tail+offset]; } - T &add() - { - T &t = data[tail]; - tail++; - if(tail >= SIZE) tail -= SIZE; - if(len < SIZE) len++; - return t; - } - T &add(const T &e) { return add() = e; } - - T &pop() - { - tail--; - if(tail < 0) tail += SIZE; - len--; - return data[tail]; - } - - T &removing() { return data[head]; } - T &removing(int offset) { return data[head+offset >= SIZE ? head+offset - SIZE : head+offset]; } - T &remove() - { - T &t = data[head]; - head++; - if(head >= SIZE) head -= SIZE; - len--; - return t; - } - - T &operator[](int offset) { return removing(offset); } - const T &operator[](int offset) const { return removing(offset); } -}; - -template struct reversequeue : queue -{ - T &operator[](int offset) { return queue::added(offset); } - const T &operator[](int offset) const { return queue::added(offset); } -}; - -static inline bool islittleendian() { union { int i; uchar b[sizeof(int)]; } conv; conv.i = 1; return conv.b[0] != 0; } -#ifdef SDL_BYTEORDER -#define endianswap16 SDL_Swap16 -#define endianswap32 SDL_Swap32 -#define endianswap64 SDL_Swap64 -#else -inline ushort endianswap16(ushort n) { return (n<<8) | (n>>8); } -inline uint endianswap32(uint n) { return (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000); } -inline ullong endianswap64(ullong n) { return endianswap32(uint(n >> 32)) | ((ullong)endianswap32(uint(n)) << 32); } -#endif -template inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = endianswap32(conv.i); return conv.t; } -template<> inline ushort endianswap(ushort n) { return endianswap16(n); } -template<> inline short endianswap(short n) { return endianswap16(n); } -template<> inline uint endianswap(uint n) { return endianswap32(n); } -template<> inline int endianswap(int n) { return endianswap32(n); } -template<> inline ullong endianswap(ullong n) { return endianswap64(n); } -template<> inline llong endianswap(llong n) { return endianswap64(n); } -template<> inline double endianswap(double n) { union { double t; uint i; } conv; conv.t = n; conv.i = endianswap64(conv.i); return conv.t; } -template inline void endianswap(T *buf, size_t len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); } -template inline T endiansame(T n) { return n; } -template inline void endiansame(T *buf, size_t len) {} -#ifdef SDL_BYTEORDER -#if SDL_BYTEORDER == SDL_LIL_ENDIAN -#define lilswap endiansame -#define bigswap endianswap -#else -#define lilswap endianswap -#define bigswap endiansame -#endif -#elif defined(__BYTE_ORDER__) -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define lilswap endiansame -#define bigswap endianswap -#else -#define lilswap endianswap -#define bigswap endiansame -#endif -#else -template inline T lilswap(T n) { return islittleendian() ? n : endianswap(n); } -template inline void lilswap(T *buf, size_t len) { if(!islittleendian()) endianswap(buf, len); } -template inline T bigswap(T n) { return islittleendian() ? endianswap(n) : n; } -template inline void bigswap(T *buf, size_t len) { if(islittleendian()) endianswap(buf, len); } -#endif - -/* workaround for some C platforms that have these two functions as macros - not used anywhere */ -#ifdef getchar -#undef getchar -#endif -#ifdef putchar -#undef putchar -#endif - -struct stream -{ -#ifdef WIN32 -#if defined(__GNUC__) && !defined(__MINGW32__) - typedef off64_t offset; -#else - typedef __int64 offset; -#endif -#else - typedef off_t offset; -#endif - - virtual ~stream() {} - virtual void close() = 0; - virtual bool end() = 0; - virtual offset tell() { return -1; } - virtual offset rawtell() { return tell(); } - virtual bool seek(offset pos, int whence = SEEK_SET) { return false; } - virtual offset size(); - virtual offset rawsize() { return size(); } - virtual size_t read(void *buf, size_t len) { return 0; } - virtual size_t write(const void *buf, size_t len) { return 0; } - virtual bool flush() { return true; } - virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; } - virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; } - virtual bool getline(char *str, size_t len); - virtual bool putstring(const char *str) { size_t len = strlen(str); return write(str, len) == len; } - virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); } - virtual size_t printf(const char *fmt, ...) PRINTFARGS(2, 3); - virtual uint getcrc() { return 0; } - - template size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); } - template bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); } - template bool putlil(T n) { return put(lilswap(n)); } - template bool putbig(T n) { return put(bigswap(n)); } - - template size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); } - template T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; } - template T getlil() { return lilswap(get()); } - template T getbig() { return bigswap(get()); } - -#ifndef STANDALONE - SDL_RWops *rwops(); -#endif -}; - -template -struct streambuf -{ - stream *s; - - streambuf(stream *s) : s(s) {} - - T get() { return s->get(); } - size_t get(T *vals, size_t numvals) { return s->get(vals, numvals); } - void put(const T &val) { s->put(&val, 1); } - void put(const T *vals, size_t numvals) { s->put(vals, numvals); } - size_t length() { return s->size(); } -}; - -enum -{ - CT_PRINT = 1<<0, - CT_SPACE = 1<<1, - CT_DIGIT = 1<<2, - CT_ALPHA = 1<<3, - CT_LOWER = 1<<4, - CT_UPPER = 1<<5, - CT_UNICODE = 1<<6 -}; -extern const uchar cubectype[256]; -static inline int iscubeprint(uchar c) { return cubectype[c]&CT_PRINT; } -static inline int iscubespace(uchar c) { return cubectype[c]&CT_SPACE; } -static inline int iscubealpha(uchar c) { return cubectype[c]&CT_ALPHA; } -static inline int iscubealnum(uchar c) { return cubectype[c]&(CT_ALPHA|CT_DIGIT); } -static inline int iscubelower(uchar c) { return cubectype[c]&CT_LOWER; } -static inline int iscubeupper(uchar c) { return cubectype[c]&CT_UPPER; } -static inline int iscubepunct(uchar c) { return cubectype[c] == CT_PRINT; } -static inline int cube2uni(uchar c) -{ - extern const int cube2unichars[256]; - return cube2unichars[c]; -} -static inline uchar uni2cube(int c) -{ - extern const int uni2cubeoffsets[8]; - extern const uchar uni2cubechars[]; - return uint(c) <= 0x7FF ? uni2cubechars[uni2cubeoffsets[c>>8] + (c&0xFF)] : 0; -} -static inline uchar cubelower(uchar c) -{ - extern const uchar cubelowerchars[256]; - return cubelowerchars[c]; -} -static inline uchar cubeupper(uchar c) -{ - extern const uchar cubeupperchars[256]; - return cubeupperchars[c]; -} -extern size_t decodeutf8(uchar *dst, size_t dstlen, const uchar *src, size_t srclen, size_t *carry = NULL); -extern size_t encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry = NULL); - -extern string homedir; - -extern char *makerelpath(const char *dir, const char *file, const char *prefix = NULL, const char *cmd = NULL); -extern char *path(char *s); -extern char *path(const char *s, bool copy); -extern const char *parentdir(const char *directory); -extern bool fileexists(const char *path, const char *mode); -extern bool createdir(const char *path); -extern size_t fixpackagedir(char *dir); -extern const char *sethomedir(const char *dir); -extern const char *addpackagedir(const char *dir); -extern const char *findfile(const char *filename, const char *mode); -extern bool findzipfile(const char *filename); -extern stream *openrawfile(const char *filename, const char *mode); -extern stream *openzipfile(const char *filename, const char *mode); -extern stream *openfile(const char *filename, const char *mode); -extern stream *opentempfile(const char *filename, const char *mode); -extern stream *opengzfile(const char *filename, const char *mode, stream *file = NULL, int level = Z_BEST_COMPRESSION); -extern stream *openutf8file(const char *filename, const char *mode, stream *file = NULL); -extern char *loadfile(const char *fn, size_t *size, bool utf8 = true); -extern bool listdir(const char *dir, bool rel, const char *ext, vector &files); -extern int listfiles(const char *dir, const char *ext, vector &files); -extern int listzipfiles(const char *dir, const char *ext, vector &files); -extern void seedMT(uint seed); -extern uint randomMT(); - -extern void putint(ucharbuf &p, int n); -extern void putint(vector &p, int n); -extern int getint(ucharbuf &p); -extern void putuint(ucharbuf &p, int n); -extern void putuint(vector &p, int n); -extern int getuint(ucharbuf &p); -extern void putfloat(ucharbuf &p, float f); -extern void putfloat(vector &p, float f); -extern float getfloat(ucharbuf &p); -extern void sendstring(const char *t, ucharbuf &p); -extern void sendstring(const char *t, vector &p); -extern void getstring(char *t, ucharbuf &p, size_t len); -template static inline void getstring(char (&t)[N], ucharbuf &p) { getstring(t, p, N); } -extern void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len); -template static inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); } +#include #endif -