OctaCore/src/sauerlib/tools.cc

183 lines
4.3 KiB
C++

// implementation of generic tools
#include "tools.hh"
#include "encoding.hh"
#include "endian.hh"
#include <ctime>
////////////////////////// strings ////////////////////////////////////////
static string tmpstr[4];
static int tmpidx = 0;
char *tempformatstring(const char *fmt, ...)
{
tmpidx = (tmpidx+1)%4;
va_list v;
va_start(v, fmt);
vformatstring(tmpstr[tmpidx], fmt, v);
va_end(v);
return tmpstr[tmpidx];
}
////////////////////////// rnd numbers ////////////////////////////////////////
#define N (624)
#define M (397)
#define K (0x9908B0DFU)
static uint state[N];
static int next = N;
void seedMT(uint seed)
{
state[0] = seed;
for(uint i = 1; i < N; i++)
state[i] = seed = 1812433253U * (seed ^ (seed >> 30)) + i;
next = 0;
}
uint randomMT()
{
int cur = next;
if(++next >= N)
{
if(next > N) { seedMT(5489U + time(nullptr)); cur = next++; }
else next = 0;
}
uint y = (state[cur] & 0x80000000U) | (state[next] & 0x7FFFFFFFU);
state[cur] = y = state[cur < N-M ? cur + M : cur + M-N] ^ (y >> 1) ^ (-int(y & 1U) & K);
y ^= (y >> 11);
y ^= (y << 7) & 0x9D2C5680U;
y ^= (y << 15) & 0xEFC60000U;
y ^= (y >> 18);
return y;
}
#undef N
#undef M
#undef K
///////////////////////// network ///////////////////////
// all network traffic is in 32bit ints, which are then compressed using the following simple scheme (assumes that most values are small).
template<class T>
static inline void putint_(T &p, int n)
{
if(n<128 && n>-127) p.put(n);
else if(n<0x8000 && n>=-0x8000) { p.put(0x80); p.put(n); p.put(n>>8); }
else { p.put(0x81); p.put(n); p.put(n>>8); p.put(n>>16); p.put(n>>24); }
}
void putint(ucharbuf &p, int n) { putint_(p, n); }
void putint(vector<uchar> &p, int n) { putint_(p, n); }
int getint(ucharbuf &p)
{
int c = (signed char)p.get();
if(c==-128) { int n = p.get(); n |= ((signed char)p.get())<<8; return n; }
else if(c==-127) { int n = p.get(); n |= p.get()<<8; n |= p.get()<<16; return n|(p.get()<<24); }
else return c;
}
// much smaller encoding for unsigned integers up to 28 bits, but can handle signed
template<class T>
static inline void putuint_(T &p, int n)
{
if(n < 0 || n >= (1<<21))
{
p.put(0x80 | (n & 0x7F));
p.put(0x80 | ((n >> 7) & 0x7F));
p.put(0x80 | ((n >> 14) & 0x7F));
p.put(n >> 21);
}
else if(n < (1<<7)) p.put(n);
else if(n < (1<<14))
{
p.put(0x80 | (n & 0x7F));
p.put(n >> 7);
}
else
{
p.put(0x80 | (n & 0x7F));
p.put(0x80 | ((n >> 7) & 0x7F));
p.put(n >> 14);
}
}
void putuint(ucharbuf &p, int n) { putuint_(p, n); }
void putuint(vector<uchar> &p, int n) { putuint_(p, n); }
int getuint(ucharbuf &p)
{
int n = p.get();
if(n & 0x80)
{
n += (p.get() << 7) - 0x80;
if(n & (1<<14)) n += (p.get() << 14) - (1<<14);
if(n & (1<<21)) n += (p.get() << 21) - (1<<21);
if(n & (1<<28)) n |= ~0U<<28;
}
return n;
}
template<class T>
static inline void putfloat_(T &p, float f)
{
lilswap(&f, 1);
p.put((uchar *)&f, sizeof(float));
}
void putfloat(ucharbuf &p, float f) { putfloat_(p, f); }
void putfloat(vector<uchar> &p, float f) { putfloat_(p, f); }
float getfloat(ucharbuf &p)
{
float f;
p.get((uchar *)&f, sizeof(float));
return lilswap(f);
}
template<class T>
static inline void sendstring_(const char *t, T &p)
{
while(*t) putint(p, *t++);
putint(p, 0);
}
void sendstring(const char *t, ucharbuf &p) { sendstring_(t, p); }
void sendstring(const char *t, vector<uchar> &p) { sendstring_(t, p); }
void getstring(char *text, ucharbuf &p, size_t len)
{
char *t = text;
do
{
if(t>=&text[len]) { text[len-1] = 0; return; }
if(!p.remaining()) { *t = 0; return; }
*t = getint(p);
}
while(*t++);
}
void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len)
{
for(int c = uchar(*src); c; c = uchar(*++src))
{
if(c == '\f')
{
if(!*++src) break;
continue;
}
if(!iscubeprint(c))
{
if(!iscubespace(c) || !whitespace) continue;
if(forcespace) c = ' ';
}
*dst++ = c;
if(!--len) break;
}
*dst = '\0';
}