<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "runtime.h"

int32	debug	= 0;

static	int32	empty		= 0;
static	string	emptystring	= (string)&empty;

void
sys·printbool(bool v)
{
	if(v) {
		sys·write(1, (byte*)"true", 4);
		return;
	}
	sys·write(1, (byte*)"false", 5);
}

void
sys·printfloat(float64 v)
{
	sys·write(1, "printfloat", 10);
}

void
sys·printint(int64 v)
{
	byte buf[100];
	int32 i, s;

	s = 0;
	if(v < 0) {
		v = -v;
		s = 1;
		if(v < 0) {
			sys·write(1, (byte*)"-oo", 3);
			return;
		}
	}

	for(i=nelem(buf)-1; i>0; i--) {
		buf[i] = v%10 + '0';
		if(v < 10)
			break;
		v = v/10;
	}
	if(s) {
		i--;
		buf[i] = '-';
	}
	sys·write(1, buf+i, nelem(buf)-i);
}

void
sys·printpointer(void *p)
{
	uint64 v;
	byte buf[100];
	int32 i;

	v = (int64)p;
	for(i=nelem(buf)-1; i>0; i--) {
		buf[i] = v%16 + '0';
		if(buf[i] > '9')
			buf[i] += 'a'-'0'-10;
		if(v < 16)
			break;
		v = v/16;
	}
	sys·write(1, buf+i, nelem(buf)-i);
}

void
sys·printstring(string v)
{
	if(v != nil)
		sys·write(1, v->str, v->len);
}

int32
findnull(int8 *s)
{
	int32 l;

	for(l=0; s[l]!=0; l++)
		;
	return l;
}

void
prints(int8 *s)
{
	sys·write(1, s, findnull(s));
}

void
sys·printpc(void *p)
{
	prints("PC=0x");
	sys·printpointer(sys·getcallerpc(p));
}

/*BUG: move traceback code to architecture-dependent runtime */
void
sys·panicl(int32 lno)
{
	uint8 *sp;

	prints("\npanic on line ");
	sys·printint(lno);
	prints(" ");
	sys·printpc(&lno);
	prints("\n");
	sp = (uint8*)&lno;
	traceback(sys·getcallerpc(&lno), sp);
	sys·breakpoint();
	sys·exit(2);
}

dump(byte *p, int32 n)
{
	uint32 v;
	int32 i;

	for(i=0; i<n; i++) {
		sys·printpointer((byte*)(p[i]>>4));
		sys·printpointer((byte*)(p[i]&0xf));
		if((i&15) == 15)
			prints("\n");
		else
			prints(" ");
	}
	if(n & 15)
		prints("\n");
}

static	uint8*	hunk;
static	uint32	nhunk;
static	uint64	nmmap;
static	uint64	nmal;
enum
{
	NHUNK		= 20<<20,

	PROT_NONE	= 0x00,
	PROT_READ	= 0x01,
	PROT_WRITE	= 0x02,
	PROT_EXEC	= 0x04,

	MAP_FILE	= 0x0000,
	MAP_SHARED	= 0x0001,
	MAP_PRIVATE	= 0x0002,
	MAP_FIXED	= 0x0010,
	MAP_ANON	= 0x1000,
};

void
throw(int8 *s)
{
	prints("throw: ");
	prints(s);
	prints("\n");
	*(int32*)0 = 0;
	sys·exit(1);
}

void
mcpy(byte *t, byte *f, uint32 n)
{
	while(n > 0) {
		*t = *f;
		t++;
		f++;
		n--;
	}
}

static byte*
brk(uint32 n)
{
	byte* v;

	v = sys·mmap(nil, NHUNK, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
	sys·memclr(v, n);
	nmmap += n;
	return v;
}

void*
mal(uint32 n)
{
	byte* v;

	// round to keep everything 64-bit alligned
	while(n & 7)
		n++;

	nmal += n;

	// do we have enough in contiguous hunk
	if(n > nhunk) {

		// if it is big allocate it separately
		if(n > NHUNK)
			return brk(n);

		// allocate a new contiguous hunk
		hunk = brk(NHUNK);
		nhunk = NHUNK;
	}

	// allocate from the contiguous hunk
	v = hunk;
	hunk += n;
	nhunk -= n;
	return v;
}

uint32
cmpstring(string s1, string s2)
{
	uint32 i, l;
	byte c1, c2;

	if(s1 == nil)
		s1 = emptystring;
	if(s2 == nil)
		s2 = emptystring;

	l = s1->len;
	if(s2->len < l)
		l = s2->len;
	for(i=0; i<l; i++) {
		c1 = s1->str[i];
		c2 = s2->str[i];
		if(c1 < c2)
			return -1;
		if(c1 > c2)
			return +1;
	}
	if(s1->len < s2->len)
		return -1;
	if(s1->len > s2->len)
		return +1;
	return 0;
}

void
sys·mal(uint32 n, uint8 *ret)
{
	ret = mal(n);
	FLUSH(&ret);
}

void
sys·catstring(string s1, string s2, string s3)
{
	uint32 l;

	if(s1 == nil || s1->len == 0) {
		s3 = s2;
		goto out;
	}
	if(s2 == nil || s2->len == 0) {
		s3 = s1;
		goto out;
	}

	l = s1->len + s2->len;

	s3 = mal(sizeof(s3->len)+l);
	s3->len = l;
	mcpy(s3->str, s1->str, s1->len);
	mcpy(s3->str+s1->len, s2->str, s2->len);

out:
	FLUSH(&s3);
}

void
sys·cmpstring(string s1, string s2, int32 v)
{
	v = cmpstring(s1, s2);
	FLUSH(&v);
}

static int32
strcmp(byte *s1, byte *s2)
{
	uint32 i;
	byte c1, c2;

	for(i=0;; i++) {
		c1 = s1[i];
		c2 = s2[i];
		if(c1 < c2)
			return -1;
		if(c1 > c2)
			return +1;
		if(c1 == 0)
			return 0;
	}
}

static void
prbounds(int8* s, int32 a, int32 b, int32 c)
{
	int32 i;

	prints(s);
	prints(" ");
	sys·printint(a);
	prints("<");
	sys·printint(b);
	prints(">");
	sys·printint(c);
	prints("\n");
	throw("bounds");
}

void
sys·slicestring(string si, int32 lindex, int32 hindex, string so)
{
	string s, str;
	int32 l;

	if(si == nil)
		si = emptystring;

	if(lindex < 0 || lindex > si->len ||
	   hindex < lindex || hindex > si->len) {
		sys·printpc(&si);
		prints(" ");
		prbounds("slice", lindex, si->len, hindex);
	}

	l = hindex-lindex;
	so = mal(sizeof(so->len)+l);
	so->len = l;
	mcpy(so->str, si->str+lindex, l);
	FLUSH(&so);
}

void
sys·indexstring(string s, int32 i, byte b)
{
	if(s == nil)
		s = emptystring;

	if(i < 0 || i >= s->len) {
		sys·printpc(&s);
		prints(" ");
		prbounds("index", 0, i, s->len);
	}

	b = s->str[i];
	FLUSH(&b);
}

/*
 * this is the plan9 runetochar
 * extended for 36 bits in 7 bytes
 * note that it truncates to 32 bits
 * through the argument passing.
 */
static int32
runetochar(byte *str, uint32 c)
{
	int32 i, n;
	uint32 mask, mark;

	/*
	 * one character in 7 bits
	 */
	if(c <= 0x07FUL) {
		str[0] = c;
		return 1;
	}

	/*
	 * every new character picks up 5 bits
	 * one less in the first byte and
	 * six more in an extension byte
	 */
	mask = 0x7ffUL;
	mark = 0xC0UL;
	for(n=1;; n++) {
		if(c <= mask)
			break;
		mask = (mask<<5) | 0x1fUL;
		mark = (mark>>1) | 0x80UL;
	}

	/*
	 * lay down the bytes backwards
	 * n is the number of extension bytes
	 * mask is the max codepoint
	 * mark is the zeroth byte indicator
	 */
	for(i=n; i>0; i--) {
		str[i] = 0x80UL | (c&0x3fUL);
		c >>= 6;
	}

	str[0] = mark|c;
	return n+1;
}

void
sys·intstring(int64 v, string s)
{
	int32 l;

	s = mal(sizeof(s->len)+8);
	s->len = runetochar(s->str, v);
	FLUSH(&s);
}

void
sys·byteastring(byte *a, int32 l, string s)
{
	s = mal(sizeof(s->len)+l);
	s->len = l;
	mcpy(s->str, a, l);
	FLUSH(&s);
}

static	Map*	hash[1009];

static Map*
hashmap(Sigi *si, Sigs *ss)
{
	int32 ns, ni;
	uint32 ihash, h;
	byte *sname, *iname;
	Map *m;

	h = ((uint32)si + (uint32)ss) % nelem(hash);
	for(m=hash[h]; m!=nil; m=m->link) {
		if(m->si == si && m->ss == ss) {
			if(m->bad) {
				throw("bad hashmap");
				m = nil;
			}
			// prints("old hashmap\n");
			return m;
		}
	}

	ni = si[0].offset;	// first word has size
	m = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
	m->si = si;
	m->ss = ss;

	ni = 1;			// skip first word
	ns = 0;

loop1:
	// pick up next name from
	// interface signature
	iname = si[ni].name;
	if(iname == nil) {
		m->link = hash[h];
		hash[h] = m;
		// prints("new hashmap\n");
		return m;
	}
	ihash = si[ni].hash;

loop2:
	// pick up and comapre next name
	// from structure signature
	sname = ss[ns].name;
	if(sname == nil) {
		prints((int8*)iname);
		prints(": ");
		throw("hashmap: failed to find method");
		m->bad = 1;
		m->link = hash[h];
		hash[h] = m;
		return nil;
	}
	if(ihash != ss[ns].hash ||
	   strcmp(sname, iname) != 0) {
		ns++;
		goto loop2;
	}

	m->fun[si[ni].offset] = ss[ns].fun;
	ni++;
	goto loop1;
}

void
sys·ifaces2i(Sigi *si, Sigs *ss, Map *m, void *s)
{

	if(debug) {
		prints("s2i sigi=");
		sys·printpointer(si);
		prints(" sigs=");
		sys·printpointer(ss);
		prints(" s=");
		sys·printpointer(s);
	}

	if(s == nil) {
		throw("ifaces2i: nil pointer");
		m = nil;
		FLUSH(&m);
		return;
	}

	m = hashmap(si, ss);

	if(debug) {
		prints(" returning m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
		prints("\n");
		dump((byte*)m, 64);
	}

	FLUSH(&m);
}

void
sys·ifacei2i(Sigi *si, Map *m, void *s)
{

	if(debug) {
		prints("i2i sigi=");
		sys·printpointer(si);
		prints(" m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
	}

	if(m == nil) {
		throw("ifacei2i: nil map");
		s = nil;
		FLUSH(&s);
		return;
	}

	if(m->si == nil) {
		throw("ifacei2i: nil pointer");
		return;
	}

	if(m->si != si) {
		m = hashmap(si, m->ss);
		FLUSH(&m);
	}

	if(debug) {
		prints(" returning m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
		prints("\n");
		dump((byte*)m, 64);
	}
}

void
sys·ifacei2s(Sigs *ss, Map *m, void *s)
{

	if(debug) {
		prints("i2s m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
		prints("\n");
	}

	if(m == nil) {
		throw("ifacei2s: nil map");
		s = nil;
		FLUSH(&s);
		return;
	}

	if(m->ss != ss) {
		dump((byte*)m, 64);
		throw("ifacei2s: wrong pointer");
		s = nil;
		FLUSH(&s);
		return;
	}
}

enum
{
	NANEXP		= 2047<<20,
	NANMASK		= 2047<<20,
	NANSIGN		= 1<<31,
};

static	uint64	uvnan		= 0x7FF0000000000001;
static	uint64	uvinf		= 0x7FF0000000000000;
static	uint64	uvneginf	= 0xFFF0000000000000;

static int32
isInf(float64 d, int32 sign)
{
	uint64 x;

	x = *(uint64*)&d;
	if(sign == 0) {
		if(x == uvinf || x == uvneginf)
			return 1;
		return 0;
	}
	if(sign > 0) {
		if(x == uvinf)
			return 1;
		return 0;
	}
	if(x == uvneginf)
		return 1;
	return 0;
}

static float64
NaN(void)
{
	return *(float64*)&uvnan;
}

static int32
isNaN(float64 d)
{
	uint64 x;

	x = *(uint64*)&d;
	return ((uint32)x>>32)==0x7FF00000 && !isInf(d, 0);
}

static float64
Inf(int32 sign)
{
	if(sign < 0)
		return *(float64*)&uvinf;
	else
		return *(float64*)&uvneginf;
}

enum
{
	MASK	= 0x7ffL,
	SHIFT	= 64-11-1,
	BIAS	= 1022L,
};

static float64
frexp(float64 d, int32 *ep)
{
	uint64 x;

	if(d == 0) {
		*ep = 0;
		return 0;
	}
	x = *(uint64*)&d;
	*ep = (int32)((x >> SHIFT) & MASK) - BIAS;
	x &= ~((uint64)MASK << SHIFT);
	x |= (uint64)BIAS << SHIFT;
	return *(float64*)&x;
}

static float64
ldexp(float64 d, int32 e)
{
	uint64 x;

	if(d == 0)
		return 0;
	x = *(uint64*)&d;
	e += (int32)(x >> SHIFT) & MASK;
	if(e <= 0)
		return 0;	/* underflow */
	if(e >= MASK){		/* overflow */
		if(d < 0)
			return Inf(-1);
		return Inf(1);
	}
	x &= ~((uint64)MASK << SHIFT);
	x |= (uint64)e << SHIFT;
	return *(float64*)&x;
}

static float64
modf(float64 d, float64 *ip)
{
	float64 dd;
	uint64 x;
	int32 e;

	if(d < 1) {
		if(d < 0) {
			d = modf(-d, ip);
			*ip = -*ip;
			return -d;
		}
		*ip = 0;
		return d;
	}

	x = *(uint64*)&d;
	e = (int32)((x >> SHIFT) & MASK) - BIAS;

	/*
	 * Keep the top 11+e bits; clear the rest.
	 */
	if(e <= 64-11)
		x &= ~((uint64)1 << (64-11-e))-1;
	dd = *(float64*)&x;
	*ip = dd;
	return d - dd;
}

// func frexp(float64) (int32, float64); // break fp into exp,fract
void
sys·frexp(float64 din, int32 iou, float64 dou)
{
	dou = frexp(din, &iou);
	FLUSH(&dou);
}

//func	ldexp(int32, float64) float64;	// make fp from exp,fract
void
sys·ldexp(float64 din, int32 ein, float64 dou)
{
	dou = ldexp(din, ein);
	FLUSH(&dou);
}

//func	modf(float64) (float64, float64);	// break fp into double+double
float64
sys·modf(float64 din, float64 dou1, float64 dou2)
{
	dou1 = modf(din, &dou2);
	FLUSH(&dou2);
}

static int32	argc;
static uint8**	argv;
static int32	envc;
static uint8**	envv;


void
args(int32 c, uint8 **v)
{
	argc = c;
	argv = v;
	envv = v + argc + 1;  // skip 0 at end of argv
	for (envc = 0; envv[envc] != 0; envc++)
		;
}

//func argc() int32;  // return number of arguments
void
sys·argc(int32 v)
{
	v = argc;
	FLUSH(&v);
}

//func envc() int32;  // return number of environment variables
void
sys·envc(int32 v)
{
	v = envc;
	FLUSH(&v);
}

//func argv(i) string;  // return argument i
void
sys·argv(int32 i, string s)
{
	uint8* str;
	int32 l;

	if(i < 0 || i >= argc) {
		s = emptystring;
		goto out;
	}

	str = argv[i];
	l = findnull((int8*)str);
	s = mal(sizeof(s->len)+l);
	s->len = l;
	mcpy(s->str, str, l);

out:
	FLUSH(&s);
}

//func envv(i) string;  // return argument i
void
sys·envv(int32 i, string s)
{
	uint8* str;
	int32 l;

	if(i < 0 || i >= envc) {
		s = emptystring;
		goto out;
	}

	str = envv[i];
	l = findnull((int8*)str);
	s = mal(sizeof(s->len)+l);
	s->len = l;
	mcpy(s->str, str, l);

out:
	FLUSH(&s);
}

check(void)
{
	int8 a;
	uint8 b;
	int16 c;
	uint16 d;
	int32 e;
	uint32 f;
	int64 g;
	uint64 h;
	float32 i;
	float64 j;
	void* k;
	uint16* l;

	if(sizeof(a) != 1) throw("bad a");
	if(sizeof(b) != 1) throw("bad b");
	if(sizeof(c) != 2) throw("bad c");
	if(sizeof(d) != 2) throw("bad d");
	if(sizeof(e) != 4) throw("bad e");
	if(sizeof(f) != 4) throw("bad f");
	if(sizeof(g) != 8) throw("bad g");
	if(sizeof(h) != 8) throw("bad h");
	if(sizeof(i) != 4) throw("bad i");
	if(sizeof(j) != 8) throw("bad j");
	if(sizeof(k) != 8) throw("bad k");
	if(sizeof(l) != 8) throw("bad l");
//	prints(1"check ok\n");
	initsig();
}

typedef	struct	Link	Link;
typedef	struct	Hmap	Hmap;
typedef	struct	Alg	Alg;

struct	Alg
{
	uint64	(*hash)(uint32, void*);
	uint32	(*equal)(uint32, void*, void*);
	void	(*print)(uint32, void*);
	void	(*copy)(uint32, void*, void*);
};

struct	Link
{
	Link*	link;
	byte	data[8];
};

struct	Hmap
{
	uint32	len;		// must be first
	uint32	keysize;
	uint32	valsize;
	uint32	hint;
	Alg*	keyalg;
	Alg*	valalg;
	uint32	valoffset;
	uint32	ko;
	uint32	vo;
	uint32	po;
	Link*	link;
};

static uint64
memhash(uint32 s, void *a)
{
	prints("memhash\n");
	return 0x12345;
}

static uint32
memequal(uint32 s, void *a, void *b)
{
	byte *ba, *bb;
	uint32 i;

	ba = a;
	bb = b;
	for(i=0; i<s; i++)
		if(ba[i] != bb[i])
			return 0;
	return 1;
}

static void
memprint(uint32 s, void *a)
{
	uint64 v;

	v = 0xbadb00b;
	switch(s) {
	case 1:
		v = *(uint8*)a;
		break;
	case 2:
		v = *(uint16*)a;
		break;
	case 4:
		v = *(uint32*)a;
		break;
	case 8:
		v = *(uint64*)a;
		break;
	}
	sys·printint(v);
}

static void
memcopy(uint32 s, void *a, void *b)
{
	byte *ba, *bb;
	uint32 i;

	ba = a;
	bb = b;
	if(bb == nil) {
		for(i=0; i<s; i++)
			ba[i] = 0;
		return;
	}
	for(i=0; i<s; i++)
		ba[i] = bb[i];
}

static uint64
stringhash(uint32 s, string *a)
{
	prints("stringhash\n");
	return 0x12345;
}

static uint32
stringequal(uint32 s, string *a, string *b)
{
	return cmpstring(*a, *b) == 0;
}

static void
stringprint(uint32 s, string *a)
{
	sys·printstring(*a);
}

static void
stringcopy(uint32 s, string *a, string *b)
{
	if(b == nil) {
		*a = nil;
		return;
	}
	*a = *b;
}

static uint32
rnd(uint32 n, uint32 m)
{
	uint32 r;

	r = n % m;
	if(r)
		n += m-r;
	return n;
}

static	Alg
algarray[] =
{
	{	&memhash,	&memequal,	&memprint,	&memcopy	},
	{	&stringhash,	&stringequal,	&stringprint,	&stringcopy	},
};

// newmap(keysize uint32, valsize uint32,
//	keyalg uint32, valalg uint32,
//	hint uint32) (hmap *map[any]any);
void
sys·newmap(uint32 keysize, uint32 valsize,
	uint32 keyalg, uint32 valalg, uint32 hint,
	Hmap* ret)
{
	Hmap *m;

	if(keyalg >= nelem(algarray) ||
	   valalg >= nelem(algarray)) {
		prints("0<=");
		sys·printint(keyalg);
		prints("<");
		sys·printint(nelem(algarray));
		prints("\n0<=");
		sys·printint(valalg);
		prints("<");
		sys·printint(nelem(algarray));
		prints("\n");

		throw("sys·newmap: key/val algorithm out of range");
	}

	m = mal(sizeof(*m));

	m->len = 0;
	m->keysize = keysize;
	m->valsize = valsize;
	m->keyalg = &algarray[keyalg];
	m->valalg = &algarray[valalg];
	m->hint = hint;

	// these calculations are compiler dependent
	m->valoffset = rnd(keysize, valsize);
	m->ko = rnd(sizeof(m), keysize);
	m->vo = rnd(m->ko+keysize, valsize);
	m->po = rnd(m->vo+valsize, 1);

	ret = m;
	FLUSH(&ret);

	if(debug) {
		prints("newmap: map=");
		sys·printpointer(m);
		prints("; keysize=");
		sys·printint(keysize);
		prints("; valsize=");
		sys·printint(valsize);
		prints("; keyalg=");
		sys·printint(keyalg);
		prints("; valalg=");
		sys·printint(valalg);
		prints("; valoffset=");
		sys·printint(m->valoffset);
		prints("; ko=");
		sys·printint(m->ko);
		prints("; vo=");
		sys·printint(m->vo);
		prints("; po=");
		sys·printint(m->po);
		prints("\n");
	}
}

// mapaccess1(hmap *map[any]any, key any) (val any);
void
sys·mapaccess1(Hmap *m, ...)
{
	Link *l;
	byte *ak, *av;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;

	for(l=m->link; l!=nil; l=l->link) {
		if(m->keyalg->equal(m->keysize, ak, l->data)) {
			m->valalg->copy(m->valsize, av, l->data+m->valoffset);
			goto out;
		}
	}

	m->valalg->copy(m->valsize, av, 0);

out:
	if(debug) {
		prints("sys·mapaccess1: map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints("; val=");
		m->valalg->print(m->valsize, av);
		prints("\n");
	}
}

// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
void
sys·mapaccess2(Hmap *m, ...)
{
	Link *l;
	byte *ak, *av, *ap;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;
	ap = (byte*)&m + m->po;

	for(l=m->link; l!=nil; l=l->link) {
		if(m->keyalg->equal(m->keysize, ak, l->data)) {
			*ap = true;
			m->valalg->copy(m->valsize, av, l->data+m->valoffset);
			goto out;
		}
	}

	*ap = false;
	m->valalg->copy(m->valsize, av, nil);

out:
	if(debug) {
		prints("sys·mapaccess2: map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints("; val=");
		m->valalg->print(m->valsize, av);
		prints("; pres=");
		sys·printbool(*ap);
		prints("\n");
	}
}

static void
sys·mapassign(Hmap *m, byte *ak, byte *av)
{
	Link *l;

	// mapassign(hmap *map[any]any, key any, val any);

	for(l=m->link; l!=nil; l=l->link) {
		if(m->keyalg->equal(m->keysize, ak, l->data))
			goto out;
	}

	l = mal((sizeof(*l)-8) + m->keysize + m->valsize);
	l->link = m->link;
	m->link = l;
	m->keyalg->copy(m->keysize, l->data, ak);
	m->len++;

out:
	m->valalg->copy(m->valsize, l->data+m->valoffset, av);

	if(debug) {
		prints("mapassign: map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints("; val=");
		m->valalg->print(m->valsize, av);
		prints("\n");
	}
}

// mapassign1(hmap *map[any]any, key any, val any);
void
sys·mapassign1(Hmap *m, ...)
{
	Link **ll;
	byte *ak, *av;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;

	sys·mapassign(m, ak, av);
}

// mapassign2(hmap *map[any]any, key any, val any, pres bool);
void
sys·mapassign2(Hmap *m, ...)
{
	Link **ll;
	byte *ak, *av, *ap;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;
	ap = (byte*)&m + m->po;

	if(*ap == true) {
		// assign
		sys·mapassign(m, ak, av);
		return;
	}

	// delete
	for(ll=&m->link; (*ll)!=nil; ll=&(*ll)->link) {
		if(m->keyalg->equal(m->keysize, ak, (*ll)->data)) {
			m->valalg->copy(m->valsize, (*ll)->data+m->valoffset, nil);
			(*ll) = (*ll)->link;
			m->len--;
			if(debug) {
				prints("mapdelete (found): map=");
				sys·printpointer(m);
				prints("; key=");
				m->keyalg->print(m->keysize, ak);
				prints("\n");
			}
			return;
		}
	}

	if(debug) {
		prints("mapdelete (not found): map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints(" *** not found\n");
	}
}
<commit_msg>add pointer to val type of maps<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "runtime.h"

int32	debug	= 0;

static	int32	empty		= 0;
static	string	emptystring	= (string)&empty;

void
sys·printbool(bool v)
{
	if(v) {
		sys·write(1, (byte*)"true", 4);
		return;
	}
	sys·write(1, (byte*)"false", 5);
}

void
sys·printfloat(float64 v)
{
	sys·write(1, "printfloat", 10);
}

void
sys·printint(int64 v)
{
	byte buf[100];
	int32 i, s;

	s = 0;
	if(v < 0) {
		v = -v;
		s = 1;
		if(v < 0) {
			sys·write(1, (byte*)"-oo", 3);
			return;
		}
	}

	for(i=nelem(buf)-1; i>0; i--) {
		buf[i] = v%10 + '0';
		if(v < 10)
			break;
		v = v/10;
	}
	if(s) {
		i--;
		buf[i] = '-';
	}
	sys·write(1, buf+i, nelem(buf)-i);
}

void
sys·printpointer(void *p)
{
	uint64 v;
	byte buf[100];
	int32 i;

	v = (int64)p;
	for(i=nelem(buf)-1; i>0; i--) {
		buf[i] = v%16 + '0';
		if(buf[i] > '9')
			buf[i] += 'a'-'0'-10;
		if(v < 16)
			break;
		v = v/16;
	}
	sys·write(1, buf+i, nelem(buf)-i);
}

void
sys·printstring(string v)
{
	if(v != nil)
		sys·write(1, v->str, v->len);
}

int32
findnull(int8 *s)
{
	int32 l;

	for(l=0; s[l]!=0; l++)
		;
	return l;
}

void
prints(int8 *s)
{
	sys·write(1, s, findnull(s));
}

void
sys·printpc(void *p)
{
	prints("PC=0x");
	sys·printpointer(sys·getcallerpc(p));
}

/*BUG: move traceback code to architecture-dependent runtime */
void
sys·panicl(int32 lno)
{
	uint8 *sp;

	prints("\npanic on line ");
	sys·printint(lno);
	prints(" ");
	sys·printpc(&lno);
	prints("\n");
	sp = (uint8*)&lno;
	traceback(sys·getcallerpc(&lno), sp);
	sys·breakpoint();
	sys·exit(2);
}

dump(byte *p, int32 n)
{
	uint32 v;
	int32 i;

	for(i=0; i<n; i++) {
		sys·printpointer((byte*)(p[i]>>4));
		sys·printpointer((byte*)(p[i]&0xf));
		if((i&15) == 15)
			prints("\n");
		else
			prints(" ");
	}
	if(n & 15)
		prints("\n");
}

static	uint8*	hunk;
static	uint32	nhunk;
static	uint64	nmmap;
static	uint64	nmal;
enum
{
	NHUNK		= 20<<20,

	PROT_NONE	= 0x00,
	PROT_READ	= 0x01,
	PROT_WRITE	= 0x02,
	PROT_EXEC	= 0x04,

	MAP_FILE	= 0x0000,
	MAP_SHARED	= 0x0001,
	MAP_PRIVATE	= 0x0002,
	MAP_FIXED	= 0x0010,
	MAP_ANON	= 0x1000,
};

void
throw(int8 *s)
{
	prints("throw: ");
	prints(s);
	prints("\n");
	*(int32*)0 = 0;
	sys·exit(1);
}

void
mcpy(byte *t, byte *f, uint32 n)
{
	while(n > 0) {
		*t = *f;
		t++;
		f++;
		n--;
	}
}

static byte*
brk(uint32 n)
{
	byte* v;

	v = sys·mmap(nil, NHUNK, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
	sys·memclr(v, n);
	nmmap += n;
	return v;
}

void*
mal(uint32 n)
{
	byte* v;

	// round to keep everything 64-bit alligned
	while(n & 7)
		n++;

	nmal += n;

	// do we have enough in contiguous hunk
	if(n > nhunk) {

		// if it is big allocate it separately
		if(n > NHUNK)
			return brk(n);

		// allocate a new contiguous hunk
		hunk = brk(NHUNK);
		nhunk = NHUNK;
	}

	// allocate from the contiguous hunk
	v = hunk;
	hunk += n;
	nhunk -= n;
	return v;
}

uint32
cmpstring(string s1, string s2)
{
	uint32 i, l;
	byte c1, c2;

	if(s1 == nil)
		s1 = emptystring;
	if(s2 == nil)
		s2 = emptystring;

	l = s1->len;
	if(s2->len < l)
		l = s2->len;
	for(i=0; i<l; i++) {
		c1 = s1->str[i];
		c2 = s2->str[i];
		if(c1 < c2)
			return -1;
		if(c1 > c2)
			return +1;
	}
	if(s1->len < s2->len)
		return -1;
	if(s1->len > s2->len)
		return +1;
	return 0;
}

void
sys·mal(uint32 n, uint8 *ret)
{
	ret = mal(n);
	FLUSH(&ret);
}

void
sys·catstring(string s1, string s2, string s3)
{
	uint32 l;

	if(s1 == nil || s1->len == 0) {
		s3 = s2;
		goto out;
	}
	if(s2 == nil || s2->len == 0) {
		s3 = s1;
		goto out;
	}

	l = s1->len + s2->len;

	s3 = mal(sizeof(s3->len)+l);
	s3->len = l;
	mcpy(s3->str, s1->str, s1->len);
	mcpy(s3->str+s1->len, s2->str, s2->len);

out:
	FLUSH(&s3);
}

void
sys·cmpstring(string s1, string s2, int32 v)
{
	v = cmpstring(s1, s2);
	FLUSH(&v);
}

static int32
strcmp(byte *s1, byte *s2)
{
	uint32 i;
	byte c1, c2;

	for(i=0;; i++) {
		c1 = s1[i];
		c2 = s2[i];
		if(c1 < c2)
			return -1;
		if(c1 > c2)
			return +1;
		if(c1 == 0)
			return 0;
	}
}

static void
prbounds(int8* s, int32 a, int32 b, int32 c)
{
	int32 i;

	prints(s);
	prints(" ");
	sys·printint(a);
	prints("<");
	sys·printint(b);
	prints(">");
	sys·printint(c);
	prints("\n");
	throw("bounds");
}

void
sys·slicestring(string si, int32 lindex, int32 hindex, string so)
{
	string s, str;
	int32 l;

	if(si == nil)
		si = emptystring;

	if(lindex < 0 || lindex > si->len ||
	   hindex < lindex || hindex > si->len) {
		sys·printpc(&si);
		prints(" ");
		prbounds("slice", lindex, si->len, hindex);
	}

	l = hindex-lindex;
	so = mal(sizeof(so->len)+l);
	so->len = l;
	mcpy(so->str, si->str+lindex, l);
	FLUSH(&so);
}

void
sys·indexstring(string s, int32 i, byte b)
{
	if(s == nil)
		s = emptystring;

	if(i < 0 || i >= s->len) {
		sys·printpc(&s);
		prints(" ");
		prbounds("index", 0, i, s->len);
	}

	b = s->str[i];
	FLUSH(&b);
}

/*
 * this is the plan9 runetochar
 * extended for 36 bits in 7 bytes
 * note that it truncates to 32 bits
 * through the argument passing.
 */
static int32
runetochar(byte *str, uint32 c)
{
	int32 i, n;
	uint32 mask, mark;

	/*
	 * one character in 7 bits
	 */
	if(c <= 0x07FUL) {
		str[0] = c;
		return 1;
	}

	/*
	 * every new character picks up 5 bits
	 * one less in the first byte and
	 * six more in an extension byte
	 */
	mask = 0x7ffUL;
	mark = 0xC0UL;
	for(n=1;; n++) {
		if(c <= mask)
			break;
		mask = (mask<<5) | 0x1fUL;
		mark = (mark>>1) | 0x80UL;
	}

	/*
	 * lay down the bytes backwards
	 * n is the number of extension bytes
	 * mask is the max codepoint
	 * mark is the zeroth byte indicator
	 */
	for(i=n; i>0; i--) {
		str[i] = 0x80UL | (c&0x3fUL);
		c >>= 6;
	}

	str[0] = mark|c;
	return n+1;
}

void
sys·intstring(int64 v, string s)
{
	int32 l;

	s = mal(sizeof(s->len)+8);
	s->len = runetochar(s->str, v);
	FLUSH(&s);
}

void
sys·byteastring(byte *a, int32 l, string s)
{
	s = mal(sizeof(s->len)+l);
	s->len = l;
	mcpy(s->str, a, l);
	FLUSH(&s);
}

static	Map*	hash[1009];

static Map*
hashmap(Sigi *si, Sigs *ss)
{
	int32 ns, ni;
	uint32 ihash, h;
	byte *sname, *iname;
	Map *m;

	h = ((uint32)si + (uint32)ss) % nelem(hash);
	for(m=hash[h]; m!=nil; m=m->link) {
		if(m->si == si && m->ss == ss) {
			if(m->bad) {
				throw("bad hashmap");
				m = nil;
			}
			// prints("old hashmap\n");
			return m;
		}
	}

	ni = si[0].offset;	// first word has size
	m = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
	m->si = si;
	m->ss = ss;

	ni = 1;			// skip first word
	ns = 0;

loop1:
	// pick up next name from
	// interface signature
	iname = si[ni].name;
	if(iname == nil) {
		m->link = hash[h];
		hash[h] = m;
		// prints("new hashmap\n");
		return m;
	}
	ihash = si[ni].hash;

loop2:
	// pick up and comapre next name
	// from structure signature
	sname = ss[ns].name;
	if(sname == nil) {
		prints((int8*)iname);
		prints(": ");
		throw("hashmap: failed to find method");
		m->bad = 1;
		m->link = hash[h];
		hash[h] = m;
		return nil;
	}
	if(ihash != ss[ns].hash ||
	   strcmp(sname, iname) != 0) {
		ns++;
		goto loop2;
	}

	m->fun[si[ni].offset] = ss[ns].fun;
	ni++;
	goto loop1;
}

void
sys·ifaces2i(Sigi *si, Sigs *ss, Map *m, void *s)
{

	if(debug) {
		prints("s2i sigi=");
		sys·printpointer(si);
		prints(" sigs=");
		sys·printpointer(ss);
		prints(" s=");
		sys·printpointer(s);
	}

	if(s == nil) {
		throw("ifaces2i: nil pointer");
		m = nil;
		FLUSH(&m);
		return;
	}

	m = hashmap(si, ss);

	if(debug) {
		prints(" returning m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
		prints("\n");
		dump((byte*)m, 64);
	}

	FLUSH(&m);
}

void
sys·ifacei2i(Sigi *si, Map *m, void *s)
{

	if(debug) {
		prints("i2i sigi=");
		sys·printpointer(si);
		prints(" m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
	}

	if(m == nil) {
		throw("ifacei2i: nil map");
		s = nil;
		FLUSH(&s);
		return;
	}

	if(m->si == nil) {
		throw("ifacei2i: nil pointer");
		return;
	}

	if(m->si != si) {
		m = hashmap(si, m->ss);
		FLUSH(&m);
	}

	if(debug) {
		prints(" returning m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
		prints("\n");
		dump((byte*)m, 64);
	}
}

void
sys·ifacei2s(Sigs *ss, Map *m, void *s)
{

	if(debug) {
		prints("i2s m=");
		sys·printpointer(m);
		prints(" s=");
		sys·printpointer(s);
		prints("\n");
	}

	if(m == nil) {
		throw("ifacei2s: nil map");
		s = nil;
		FLUSH(&s);
		return;
	}

	if(m->ss != ss) {
		dump((byte*)m, 64);
		throw("ifacei2s: wrong pointer");
		s = nil;
		FLUSH(&s);
		return;
	}
}

enum
{
	NANEXP		= 2047<<20,
	NANMASK		= 2047<<20,
	NANSIGN		= 1<<31,
};

static	uint64	uvnan		= 0x7FF0000000000001;
static	uint64	uvinf		= 0x7FF0000000000000;
static	uint64	uvneginf	= 0xFFF0000000000000;

static int32
isInf(float64 d, int32 sign)
{
	uint64 x;

	x = *(uint64*)&d;
	if(sign == 0) {
		if(x == uvinf || x == uvneginf)
			return 1;
		return 0;
	}
	if(sign > 0) {
		if(x == uvinf)
			return 1;
		return 0;
	}
	if(x == uvneginf)
		return 1;
	return 0;
}

static float64
NaN(void)
{
	return *(float64*)&uvnan;
}

static int32
isNaN(float64 d)
{
	uint64 x;

	x = *(uint64*)&d;
	return ((uint32)x>>32)==0x7FF00000 && !isInf(d, 0);
}

static float64
Inf(int32 sign)
{
	if(sign < 0)
		return *(float64*)&uvinf;
	else
		return *(float64*)&uvneginf;
}

enum
{
	MASK	= 0x7ffL,
	SHIFT	= 64-11-1,
	BIAS	= 1022L,
};

static float64
frexp(float64 d, int32 *ep)
{
	uint64 x;

	if(d == 0) {
		*ep = 0;
		return 0;
	}
	x = *(uint64*)&d;
	*ep = (int32)((x >> SHIFT) & MASK) - BIAS;
	x &= ~((uint64)MASK << SHIFT);
	x |= (uint64)BIAS << SHIFT;
	return *(float64*)&x;
}

static float64
ldexp(float64 d, int32 e)
{
	uint64 x;

	if(d == 0)
		return 0;
	x = *(uint64*)&d;
	e += (int32)(x >> SHIFT) & MASK;
	if(e <= 0)
		return 0;	/* underflow */
	if(e >= MASK){		/* overflow */
		if(d < 0)
			return Inf(-1);
		return Inf(1);
	}
	x &= ~((uint64)MASK << SHIFT);
	x |= (uint64)e << SHIFT;
	return *(float64*)&x;
}

static float64
modf(float64 d, float64 *ip)
{
	float64 dd;
	uint64 x;
	int32 e;

	if(d < 1) {
		if(d < 0) {
			d = modf(-d, ip);
			*ip = -*ip;
			return -d;
		}
		*ip = 0;
		return d;
	}

	x = *(uint64*)&d;
	e = (int32)((x >> SHIFT) & MASK) - BIAS;

	/*
	 * Keep the top 11+e bits; clear the rest.
	 */
	if(e <= 64-11)
		x &= ~((uint64)1 << (64-11-e))-1;
	dd = *(float64*)&x;
	*ip = dd;
	return d - dd;
}

// func frexp(float64) (int32, float64); // break fp into exp,fract
void
sys·frexp(float64 din, int32 iou, float64 dou)
{
	dou = frexp(din, &iou);
	FLUSH(&dou);
}

//func	ldexp(int32, float64) float64;	// make fp from exp,fract
void
sys·ldexp(float64 din, int32 ein, float64 dou)
{
	dou = ldexp(din, ein);
	FLUSH(&dou);
}

//func	modf(float64) (float64, float64);	// break fp into double+double
float64
sys·modf(float64 din, float64 dou1, float64 dou2)
{
	dou1 = modf(din, &dou2);
	FLUSH(&dou2);
}

static int32	argc;
static uint8**	argv;
static int32	envc;
static uint8**	envv;


void
args(int32 c, uint8 **v)
{
	argc = c;
	argv = v;
	envv = v + argc + 1;  // skip 0 at end of argv
	for (envc = 0; envv[envc] != 0; envc++)
		;
}

//func argc() int32;  // return number of arguments
void
sys·argc(int32 v)
{
	v = argc;
	FLUSH(&v);
}

//func envc() int32;  // return number of environment variables
void
sys·envc(int32 v)
{
	v = envc;
	FLUSH(&v);
}

//func argv(i) string;  // return argument i
void
sys·argv(int32 i, string s)
{
	uint8* str;
	int32 l;

	if(i < 0 || i >= argc) {
		s = emptystring;
		goto out;
	}

	str = argv[i];
	l = findnull((int8*)str);
	s = mal(sizeof(s->len)+l);
	s->len = l;
	mcpy(s->str, str, l);

out:
	FLUSH(&s);
}

//func envv(i) string;  // return argument i
void
sys·envv(int32 i, string s)
{
	uint8* str;
	int32 l;

	if(i < 0 || i >= envc) {
		s = emptystring;
		goto out;
	}

	str = envv[i];
	l = findnull((int8*)str);
	s = mal(sizeof(s->len)+l);
	s->len = l;
	mcpy(s->str, str, l);

out:
	FLUSH(&s);
}

check(void)
{
	int8 a;
	uint8 b;
	int16 c;
	uint16 d;
	int32 e;
	uint32 f;
	int64 g;
	uint64 h;
	float32 i;
	float64 j;
	void* k;
	uint16* l;

	if(sizeof(a) != 1) throw("bad a");
	if(sizeof(b) != 1) throw("bad b");
	if(sizeof(c) != 2) throw("bad c");
	if(sizeof(d) != 2) throw("bad d");
	if(sizeof(e) != 4) throw("bad e");
	if(sizeof(f) != 4) throw("bad f");
	if(sizeof(g) != 8) throw("bad g");
	if(sizeof(h) != 8) throw("bad h");
	if(sizeof(i) != 4) throw("bad i");
	if(sizeof(j) != 8) throw("bad j");
	if(sizeof(k) != 8) throw("bad k");
	if(sizeof(l) != 8) throw("bad l");
//	prints(1"check ok\n");
	initsig();
}

typedef	struct	Link	Link;
typedef	struct	Hmap	Hmap;
typedef	struct	Alg	Alg;

struct	Alg
{
	uint64	(*hash)(uint32, void*);
	uint32	(*equal)(uint32, void*, void*);
	void	(*print)(uint32, void*);
	void	(*copy)(uint32, void*, void*);
};

struct	Link
{
	Link*	link;
	byte	data[8];
};

struct	Hmap
{
	uint32	len;		// must be first
	uint32	keysize;
	uint32	valsize;
	uint32	hint;
	Alg*	keyalg;
	Alg*	valalg;
	uint32	valoffset;
	uint32	ko;
	uint32	vo;
	uint32	po;
	Link*	link;
};

static uint64
memhash(uint32 s, void *a)
{
	prints("memhash\n");
	return 0x12345;
}

static uint32
memequal(uint32 s, void *a, void *b)
{
	byte *ba, *bb;
	uint32 i;

	ba = a;
	bb = b;
	for(i=0; i<s; i++)
		if(ba[i] != bb[i])
			return 0;
	return 1;
}

static void
memprint(uint32 s, void *a)
{
	uint64 v;

	v = 0xbadb00b;
	switch(s) {
	case 1:
		v = *(uint8*)a;
		break;
	case 2:
		v = *(uint16*)a;
		break;
	case 4:
		v = *(uint32*)a;
		break;
	case 8:
		v = *(uint64*)a;
		break;
	}
	sys·printint(v);
}

static void
memcopy(uint32 s, void *a, void *b)
{
	byte *ba, *bb;
	uint32 i;

	ba = a;
	bb = b;
	if(bb == nil) {
		for(i=0; i<s; i++)
			ba[i] = 0;
		return;
	}
	for(i=0; i<s; i++)
		ba[i] = bb[i];
}

static uint64
stringhash(uint32 s, string *a)
{
	prints("stringhash\n");
	return 0x12345;
}

static uint32
stringequal(uint32 s, string *a, string *b)
{
	return cmpstring(*a, *b) == 0;
}

static void
stringprint(uint32 s, string *a)
{
	sys·printstring(*a);
}

static void
stringcopy(uint32 s, string *a, string *b)
{
	if(b == nil) {
		*a = nil;
		return;
	}
	*a = *b;
}

static uint64
pointerhash(uint32 s, void **a)
{
	prints("pointerhash\n");
	return 0x12345;
}

static uint32
pointerequal(uint32 s, void **a, void **b)
{
	prints("pointerequal\n");
	return 0;
}

static void
pointerprint(uint32 s, void **a)
{
	prints("pointerprint\n");
}

static void
pointercopy(uint32 s, void **a, void **b)
{
	if(b == nil) {
		*a = nil;
		return;
	}
	*a = *b;
}

static uint32
rnd(uint32 n, uint32 m)
{
	uint32 r;

	r = n % m;
	if(r)
		n += m-r;
	return n;
}

static	Alg
algarray[] =
{
	{	&memhash,	&memequal,	&memprint,	&memcopy	},
	{	&stringhash,	&stringequal,	&stringprint,	&stringcopy	},
	{	&pointerhash,	&pointerequal,	&pointerprint,	&pointercopy	},
};

// newmap(keysize uint32, valsize uint32,
//	keyalg uint32, valalg uint32,
//	hint uint32) (hmap *map[any]any);
void
sys·newmap(uint32 keysize, uint32 valsize,
	uint32 keyalg, uint32 valalg, uint32 hint,
	Hmap* ret)
{
	Hmap *m;

	if(keyalg >= 2 ||
	   valalg >= 3) {
		prints("0<=");
		sys·printint(keyalg);
		prints("<");
		sys·printint(nelem(algarray));
		prints("\n0<=");
		sys·printint(valalg);
		prints("<");
		sys·printint(nelem(algarray));
		prints("\n");

		throw("sys·newmap: key/val algorithm out of range");
	}

	m = mal(sizeof(*m));

	m->len = 0;
	m->keysize = keysize;
	m->valsize = valsize;
	m->keyalg = &algarray[keyalg];
	m->valalg = &algarray[valalg];
	m->hint = hint;

	// these calculations are compiler dependent
	m->valoffset = rnd(keysize, valsize);
	m->ko = rnd(sizeof(m), keysize);
	m->vo = rnd(m->ko+keysize, valsize);
	m->po = rnd(m->vo+valsize, 1);

	ret = m;
	FLUSH(&ret);

	if(debug) {
		prints("newmap: map=");
		sys·printpointer(m);
		prints("; keysize=");
		sys·printint(keysize);
		prints("; valsize=");
		sys·printint(valsize);
		prints("; keyalg=");
		sys·printint(keyalg);
		prints("; valalg=");
		sys·printint(valalg);
		prints("; valoffset=");
		sys·printint(m->valoffset);
		prints("; ko=");
		sys·printint(m->ko);
		prints("; vo=");
		sys·printint(m->vo);
		prints("; po=");
		sys·printint(m->po);
		prints("\n");
	}
}

// mapaccess1(hmap *map[any]any, key any) (val any);
void
sys·mapaccess1(Hmap *m, ...)
{
	Link *l;
	byte *ak, *av;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;

	for(l=m->link; l!=nil; l=l->link) {
		if(m->keyalg->equal(m->keysize, ak, l->data)) {
			m->valalg->copy(m->valsize, av, l->data+m->valoffset);
			goto out;
		}
	}

	m->valalg->copy(m->valsize, av, 0);

out:
	if(debug) {
		prints("sys·mapaccess1: map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints("; val=");
		m->valalg->print(m->valsize, av);
		prints("\n");
	}
}

// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
void
sys·mapaccess2(Hmap *m, ...)
{
	Link *l;
	byte *ak, *av, *ap;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;
	ap = (byte*)&m + m->po;

	for(l=m->link; l!=nil; l=l->link) {
		if(m->keyalg->equal(m->keysize, ak, l->data)) {
			*ap = true;
			m->valalg->copy(m->valsize, av, l->data+m->valoffset);
			goto out;
		}
	}

	*ap = false;
	m->valalg->copy(m->valsize, av, nil);

out:
	if(debug) {
		prints("sys·mapaccess2: map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints("; val=");
		m->valalg->print(m->valsize, av);
		prints("; pres=");
		sys·printbool(*ap);
		prints("\n");
	}
}

static void
sys·mapassign(Hmap *m, byte *ak, byte *av)
{
	Link *l;

	// mapassign(hmap *map[any]any, key any, val any);

	for(l=m->link; l!=nil; l=l->link) {
		if(m->keyalg->equal(m->keysize, ak, l->data))
			goto out;
	}

	l = mal((sizeof(*l)-8) + m->keysize + m->valsize);
	l->link = m->link;
	m->link = l;
	m->keyalg->copy(m->keysize, l->data, ak);
	m->len++;

out:
	m->valalg->copy(m->valsize, l->data+m->valoffset, av);

	if(debug) {
		prints("mapassign: map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints("; val=");
		m->valalg->print(m->valsize, av);
		prints("\n");
	}
}

// mapassign1(hmap *map[any]any, key any, val any);
void
sys·mapassign1(Hmap *m, ...)
{
	Link **ll;
	byte *ak, *av;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;

	sys·mapassign(m, ak, av);
}

// mapassign2(hmap *map[any]any, key any, val any, pres bool);
void
sys·mapassign2(Hmap *m, ...)
{
	Link **ll;
	byte *ak, *av, *ap;

	ak = (byte*)&m + m->ko;
	av = (byte*)&m + m->vo;
	ap = (byte*)&m + m->po;

	if(*ap == true) {
		// assign
		sys·mapassign(m, ak, av);
		return;
	}

	// delete
	for(ll=&m->link; (*ll)!=nil; ll=&(*ll)->link) {
		if(m->keyalg->equal(m->keysize, ak, (*ll)->data)) {
			m->valalg->copy(m->valsize, (*ll)->data+m->valoffset, nil);
			(*ll) = (*ll)->link;
			m->len--;
			if(debug) {
				prints("mapdelete (found): map=");
				sys·printpointer(m);
				prints("; key=");
				m->keyalg->print(m->keysize, ak);
				prints("\n");
			}
			return;
		}
	}

	if(debug) {
		prints("mapdelete (not found): map=");
		sys·printpointer(m);
		prints("; key=");
		m->keyalg->print(m->keysize, ak);
		prints(" *** not found\n");
	}
}

{'fraction_non_alphanumeric': 0.2155895150164491, 'fraction_numerical': 0.043961583359864165, 'mean_word_length': 3.2999087383070957, 'pattern_counts': {'":': 2, '<': 105, '<?xml version=': 0, '>': 417, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5964793', 'n_tokens_mistral': 19506, 'n_tokens_neox': 17693, 'n_words': 4104}