// generic useful stuff for any C++ program #ifndef SAUERLIB_TOOLS_HH #define SAUERLIB_TOOLS_HH #include #include #include #include #include #include #include #include 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; #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 #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(nullptr), 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; } template struct vector { static const int MINSIZE = 8; T *buf; int alen, ulen; vector() : buf(nullptr), alen(0), ulen(0) { } vector(const vector &v) : buf(nullptr), 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 = nullptr; unused = nullptr; 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(&, nullptr); } 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] = nullptr; } 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 = nullptr; 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 = nullptr); extern size_t encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry = nullptr); extern string homedir; extern char *makerelpath(const char *dir, const char *file, const char *prefix = nullptr, const char *cmd = nullptr); 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 = nullptr, int level = Z_BEST_COMPRESSION); extern stream *openutf8file(const char *filename, const char *mode, stream *file = nullptr); 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