2020-04-15 16:39:17 +00:00
|
|
|
// generic useful stuff for any C++ program
|
|
|
|
|
|
|
|
#ifndef _TOOLS_H
|
|
|
|
#define _TOOLS_H
|
|
|
|
|
2020-04-18 02:06:25 +00:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cmath>
|
|
|
|
|
2020-04-18 00:20:17 +00:00
|
|
|
#include <zlib.h>
|
2020-04-25 03:33:51 +00:00
|
|
|
|
2020-04-18 02:06:25 +00:00
|
|
|
#ifndef STANDALONE
|
|
|
|
#include "gl.hh"
|
|
|
|
#endif
|
|
|
|
|
2020-04-15 16:39:17 +00:00
|
|
|
#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<class T>
|
|
|
|
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<class T>
|
|
|
|
static inline T max(T a, T b)
|
|
|
|
{
|
|
|
|
return a > b ? a : b;
|
|
|
|
}
|
|
|
|
template<class T>
|
|
|
|
static inline T max(T a, T b, T c)
|
|
|
|
{
|
|
|
|
return max(max(a, b), c);
|
|
|
|
}
|
|
|
|
template<class T>
|
|
|
|
static inline T min(T a, T b)
|
|
|
|
{
|
|
|
|
return a < b ? a : b;
|
|
|
|
}
|
|
|
|
template<class T>
|
|
|
|
static inline T min(T a, T b, T c)
|
|
|
|
{
|
|
|
|
return min(min(a, b), c);
|
|
|
|
}
|
|
|
|
template<class T, class U>
|
|
|
|
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<size_t N> 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<size_t N> 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<size_t N> 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<size_t N> 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<size_t N> inline void formatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
|
|
|
|
template<size_t N> 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<size_t N> inline void concformatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
|
|
|
|
template<size_t N> 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<size_t N> 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<class T> inline void memclear(T *p, size_t n) { memset((void *)p, 0, n * sizeof(T)); }
|
|
|
|
template<class T> inline void memclear(T &p) { memset((void *)&p, 0, sizeof(T)); }
|
|
|
|
template<class T, size_t N> inline void memclear(T (&p)[N]) { memset((void *)p, 0, N * sizeof(T)); }
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
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<class U>
|
|
|
|
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<maxlen) return buf[len++];
|
|
|
|
flags |= OVERREAD;
|
|
|
|
return overreadval;
|
|
|
|
}
|
|
|
|
|
|
|
|
databuf subbuf(int sz)
|
|
|
|
{
|
|
|
|
sz = clamp(sz, 0, maxlen-len);
|
|
|
|
len += sz;
|
|
|
|
return databuf(&buf[len-sz], sz);
|
|
|
|
}
|
|
|
|
|
|
|
|
T *pad(int numvals)
|
|
|
|
{
|
|
|
|
T *vals = &buf[len];
|
|
|
|
len += min(numvals, maxlen-len);
|
|
|
|
return vals;
|
|
|
|
}
|
|
|
|
|
|
|
|
void put(const T &val)
|
|
|
|
{
|
|
|
|
if(len<maxlen) buf[len++] = val;
|
|
|
|
else flags |= OVERWROTE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void put(const T *vals, int numvals)
|
|
|
|
{
|
|
|
|
if(maxlen - len < numvals)
|
|
|
|
{
|
|
|
|
numvals = maxlen - len;
|
|
|
|
flags |= OVERWROTE;
|
|
|
|
}
|
|
|
|
memcpy(&buf[len], (const void *)vals, numvals*sizeof(T));
|
|
|
|
len += numvals;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get(T *vals, int numvals)
|
|
|
|
{
|
|
|
|
if(maxlen - len < numvals)
|
|
|
|
{
|
|
|
|
numvals = maxlen - len;
|
|
|
|
flags |= OVERREAD;
|
|
|
|
}
|
|
|
|
memcpy(vals, (void *)&buf[len], numvals*sizeof(T));
|
|
|
|
len += numvals;
|
|
|
|
return numvals;
|
|
|
|
}
|
|
|
|
|
|
|
|
void offset(int n)
|
|
|
|
{
|
|
|
|
n = min(n, maxlen);
|
|
|
|
buf += n;
|
|
|
|
maxlen -= n;
|
|
|
|
len = max(len-n, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
T *getbuf() const { return buf; }
|
|
|
|
bool empty() const { return len==0; }
|
|
|
|
int length() const { return len; }
|
|
|
|
int remaining() const { return maxlen-len; }
|
|
|
|
bool overread() const { return (flags&OVERREAD)!=0; }
|
|
|
|
bool overwrote() const { return (flags&OVERWROTE)!=0; }
|
|
|
|
|
|
|
|
bool check(int n) { return remaining() >= n; }
|
|
|
|
|
|
|
|
void forceoverread()
|
|
|
|
{
|
|
|
|
len = maxlen;
|
|
|
|
flags |= OVERREAD;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef databuf<uchar> ucharbuf;
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
static inline float heapscore(const T &n) { return n; }
|
|
|
|
|
|
|
|
struct sortless
|
|
|
|
{
|
|
|
|
template<class T> 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<class T> bool operator()(const T &x, const T &y) const { return sortless()(x.name, y.name); }
|
|
|
|
template<class T> bool operator()(T *x, T *y) const { return sortless()(x->name, y->name); }
|
|
|
|
template<class T> bool operator()(const T *x, const T *y) const { return sortless()(x->name, y->name); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class T, class F>
|
|
|
|
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<class T, class F>
|
|
|
|
static inline void insertionsort(T *buf, int n, F fun)
|
|
|
|
{
|
|
|
|
insertionsort(buf, buf+n, fun);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
static inline void insertionsort(T *buf, int n)
|
|
|
|
{
|
|
|
|
insertionsort(buf, buf+n, sortless());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T, class F>
|
|
|
|
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<class T, class F>
|
|
|
|
static inline void quicksort(T *buf, int n, F fun)
|
|
|
|
{
|
|
|
|
quicksort(buf, buf+n, fun);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
static inline void quicksort(T *buf, int n)
|
|
|
|
{
|
|
|
|
quicksort(buf, buf+n, sortless());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T> struct isclass
|
|
|
|
{
|
|
|
|
template<class C> static char test(void (C::*)(void));
|
|
|
|
template<class C> static int test(...);
|
|
|
|
enum { yes = sizeof(test<T>(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<size_t N> 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef STANDALONE
|
|
|
|
static inline uint hthash(GLuint key)
|
|
|
|
{
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool htcmp(GLuint x, GLuint y)
|
|
|
|
{
|
|
|
|
return x==y;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <class T> 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<T> &operator=(const vector<T> &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<T> &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<size_t(ulen); }
|
|
|
|
bool inrange(int i) const { return i>=0 && i<ulen; }
|
|
|
|
|
|
|
|
T &pop() { return buf[--ulen]; }
|
|
|
|
T &last() { return buf[ulen-1]; }
|
|
|
|
void drop() { ulen--; buf[ulen].~T(); }
|
|
|
|
bool empty() const { return ulen==0; }
|
|
|
|
|
|
|
|
int capacity() const { return alen; }
|
|
|
|
int length() const { return ulen; }
|
|
|
|
T &operator[](int i) { ASSERT(i>=0 && i<ulen); return buf[i]; }
|
|
|
|
const T &operator[](int i) const { ASSERT(i >= 0 && i<ulen); return buf[i]; }
|
|
|
|
|
|
|
|
T *disown() { T *r = buf; buf = NULL; alen = ulen = 0; return r; }
|
|
|
|
|
|
|
|
void shrink(int i) { ASSERT(i<=ulen); if(isclass<T>::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<class F>
|
|
|
|
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<T> reserve(int sz)
|
|
|
|
{
|
|
|
|
if(alen-ulen < sz) growbuf(ulen+sz);
|
|
|
|
return databuf<T>(&buf[ulen], sz);
|
|
|
|
}
|
|
|
|
|
|
|
|
void advance(int sz)
|
|
|
|
{
|
|
|
|
ulen += sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
void addbuf(const databuf<T> &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<T> buf = reserve(n);
|
|
|
|
buf.put(v, n);
|
|
|
|
addbuf(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove(int i, int n)
|
|
|
|
{
|
|
|
|
for(int p = i+n; p<ulen; p++) buf[p-n] = buf[p];
|
|
|
|
ulen -= n;
|
|
|
|
}
|
|
|
|
|
|
|
|
T remove(int i)
|
|
|
|
{
|
|
|
|
T e = buf[i];
|
|
|
|
for(int p = i+1; p<ulen; p++) buf[p-1] = buf[p];
|
|
|
|
ulen--;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
T removeunordered(int i)
|
|
|
|
{
|
|
|
|
T e = buf[i];
|
|
|
|
ulen--;
|
|
|
|
if(ulen>0) buf[i] = buf[ulen];
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class U>
|
|
|
|
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<class K>
|
|
|
|
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<class H, class E, class K, class T> 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<class U>
|
|
|
|
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<class U>
|
|
|
|
T *access(const U &key)
|
|
|
|
{
|
|
|
|
HTFIND(&, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class U, class V>
|
|
|
|
T &access(const U &key, const V &elem)
|
|
|
|
{
|
|
|
|
HTFIND( , insert(h, key) = elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class U>
|
|
|
|
T &operator[](const U &key)
|
|
|
|
{
|
|
|
|
HTFIND( , insert(h, key));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class U>
|
|
|
|
T &find(const U &key, T ¬found)
|
|
|
|
{
|
|
|
|
HTFIND( , notfound);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class U>
|
|
|
|
const T &find(const U &key, const T ¬found)
|
|
|
|
{
|
|
|
|
HTFIND( , notfound);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class U>
|
|
|
|
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<class T> static inline void htrecycle(const T &) {}
|
|
|
|
|
|
|
|
template<class T> struct hashset : hashbase<hashset<T>, T, T, T>
|
|
|
|
{
|
|
|
|
typedef hashbase<hashset<T>, 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<class K> static inline void setkey(T &elem, const K &key) {}
|
|
|
|
|
|
|
|
template<class V>
|
|
|
|
T &add(const V &elem)
|
|
|
|
{
|
|
|
|
return basetype::access(elem, elem);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class T> struct hashnameset : hashbase<hashnameset<T>, T, const char *, T>
|
|
|
|
{
|
|
|
|
typedef hashbase<hashnameset<T>, T, const char *, T> basetype;
|
|
|
|
|
|
|
|
hashnameset(int size = basetype::DEFAULTSIZE) : basetype(size) {}
|
|
|
|
|
|
|
|
template<class U> static inline const char *getkey(const U &elem) { return elem.name; }
|
|
|
|
template<class U> static inline const char *getkey(U *elem) { return elem->name; }
|
|
|
|
static inline T &getdata(T &elem) { return elem; }
|
|
|
|
template<class K> static inline void setkey(T &elem, const K &key) {}
|
|
|
|
|
|
|
|
template<class V>
|
|
|
|
T &add(const V &elem)
|
|
|
|
{
|
|
|
|
return basetype::access(getkey(elem), elem);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class K, class T> struct hashtableentry
|
|
|
|
{
|
|
|
|
K key;
|
|
|
|
T data;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class K, class T>
|
|
|
|
static inline void htrecycle(hashtableentry<K, T> &entry)
|
|
|
|
{
|
|
|
|
htrecycle(entry.key);
|
|
|
|
htrecycle(entry.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class K, class T> struct hashtable : hashbase<hashtable<K, T>, hashtableentry<K, T>, K, T>
|
|
|
|
{
|
|
|
|
typedef hashbase<hashtable<K, T>, hashtableentry<K, T>, 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<class U> 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 <class T, int SIZE> 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<size_t(len); }
|
|
|
|
bool inrange(int i) const { return i>=0 && i<len; }
|
|
|
|
|
|
|
|
T &added() { return data[tail > 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 <class T, int SIZE> struct reversequeue : queue<T, SIZE>
|
|
|
|
{
|
|
|
|
T &operator[](int offset) { return queue<T, SIZE>::added(offset); }
|
|
|
|
const T &operator[](int offset) const { return queue<T, SIZE>::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<class T> 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>(ushort n) { return endianswap16(n); }
|
|
|
|
template<> inline short endianswap<short>(short n) { return endianswap16(n); }
|
|
|
|
template<> inline uint endianswap<uint>(uint n) { return endianswap32(n); }
|
|
|
|
template<> inline int endianswap<int>(int n) { return endianswap32(n); }
|
|
|
|
template<> inline ullong endianswap<ullong>(ullong n) { return endianswap64(n); }
|
|
|
|
template<> inline llong endianswap<llong>(llong n) { return endianswap64(n); }
|
|
|
|
template<> inline double endianswap<double>(double n) { union { double t; uint i; } conv; conv.t = n; conv.i = endianswap64(conv.i); return conv.t; }
|
|
|
|
template<class T> inline void endianswap(T *buf, size_t len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); }
|
|
|
|
template<class T> inline T endiansame(T n) { return n; }
|
|
|
|
template<class T> 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<class T> inline T lilswap(T n) { return islittleendian() ? n : endianswap(n); }
|
|
|
|
template<class T> inline void lilswap(T *buf, size_t len) { if(!islittleendian()) endianswap(buf, len); }
|
|
|
|
template<class T> inline T bigswap(T n) { return islittleendian() ? endianswap(n) : n; }
|
|
|
|
template<class T> 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<class T> size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); }
|
|
|
|
template<class T> bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
|
|
|
|
template<class T> bool putlil(T n) { return put<T>(lilswap(n)); }
|
|
|
|
template<class T> bool putbig(T n) { return put<T>(bigswap(n)); }
|
|
|
|
|
|
|
|
template<class T> size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); }
|
|
|
|
template<class T> T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
|
|
|
|
template<class T> T getlil() { return lilswap(get<T>()); }
|
|
|
|
template<class T> T getbig() { return bigswap(get<T>()); }
|
|
|
|
|
|
|
|
#ifndef STANDALONE
|
|
|
|
SDL_RWops *rwops();
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
struct streambuf
|
|
|
|
{
|
|
|
|
stream *s;
|
|
|
|
|
|
|
|
streambuf(stream *s) : s(s) {}
|
|
|
|
|
|
|
|
T get() { return s->get<T>(); }
|
|
|
|
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<char *> &files);
|
|
|
|
extern int listfiles(const char *dir, const char *ext, vector<char *> &files);
|
|
|
|
extern int listzipfiles(const char *dir, const char *ext, vector<char *> &files);
|
|
|
|
extern void seedMT(uint seed);
|
|
|
|
extern uint randomMT();
|
|
|
|
|
|
|
|
extern void putint(ucharbuf &p, int n);
|
|
|
|
extern void putint(vector<uchar> &p, int n);
|
|
|
|
extern int getint(ucharbuf &p);
|
|
|
|
extern void putuint(ucharbuf &p, int n);
|
|
|
|
extern void putuint(vector<uchar> &p, int n);
|
|
|
|
extern int getuint(ucharbuf &p);
|
|
|
|
extern void putfloat(ucharbuf &p, float f);
|
|
|
|
extern void putfloat(vector<uchar> &p, float f);
|
|
|
|
extern float getfloat(ucharbuf &p);
|
|
|
|
extern void sendstring(const char *t, ucharbuf &p);
|
|
|
|
extern void sendstring(const char *t, vector<uchar> &p);
|
|
|
|
extern void getstring(char *t, ucharbuf &p, size_t len);
|
|
|
|
template<size_t N> 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<size_t N> static inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); }
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|