/* Copyright (C) 2021 Momi-g

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/*SH_doc
@NAME lbc - helper macro/api to embed luajit code into C

@SYNOPSYS
<pre>
#include "lbc.h"
typedef struct struct lbc_tag {
	lua_t* L;
	char* emsg;
	int rc;
	char glname[64];
	int lpflg;
	int used;
} lbc_t;
	
typedef struct lbc_rttag {
	int inner_flg; 
	int  tp;
	int i;
	double d;
	const char* s;
	int sz;
} lbc_rt;
	
//runner
lbc_t* lbc_new(void);
void lbc_free(lbc_t* obj);
int lbc_reqbcM(lbc_t* obj, ...);
int lbc_runbcM(lbc_t* obj, int ac, char** av, FILE_IDENT );
int lbc_runstr(lbc_t* obj, int ac, char** av, const char* str);
int lbc_prunbcM(lbc_t* obj, int ac, char** av, name );
int lbc_prunstr(lbc_t* obj, int ac, char** av, const char* str);

//result-reader	
lbc_rt lbc_tbval(lbc_t* obj, ...);
int lbc_tbvalsv(int nidx, lbc_t* obj, ...);
int lbc_delsv(lbc_t* obj, int idx);
int lbc_cleansv(lbc_t* obj);
int lbc_directf(int nidx, lbc_t* obj, ...);
int lbc_pdirectf(int nidx, lbc_t* obj, ...);
#define LBC_C2P	//see NOTES. for directf/pdirectf 
#define LBC_P2C
#define LBC_P2S


//result-support
lbc_pairs(k, v, obj, ...){...}
lbc_ipairs(i, v, obj, ...){...}
int lbc_keysv(int nidx, lbc_t* obj);
int lbc_valsv(int nidx, lbc_t* obj);
	
//lhh, use luatb as hash instead of c99 hsearch()
typedef struct luahash_tag{
	lua_t* L;
	char* emsg;
	int rc;
	char glname[64];
	int lpflg;
	int cnt;
} lhh_t;
typedef lbc_rt lhh_rt;

lhh_t* lhh_new(void);
void lhh_free(lhh_t* obj);
int lhh_set(lhh_t* obj, key, val, ...);
int lhh_unset(lhh_t* obj, key);
lhh_rt lhh_get(lhh_t* obj, key);

// use 'double' args instead of 'int'
int lhh_setd(lhh_t* obj, key, val, ...);
int lhh_unsetd(lhh_t* obj, key);
lhh_rt lhh_getd(lhh_t* obj, key);
</pre>


@DESCRIPTION
lbc assists embed luajit code to C.	

<pre>
basic API:
- lbc_new() makes luajit vm
- lbc_reqbcM() imports dependent lj bytecode file as require()
- lbc_runbcM(), runstr() execute byte/str code
- lbc_tbval() gets rtn/tb val with C type, int, char* etc
- lbc_free() closes luajit vm and release memory

additional API:
- lbc_directf() executes luajit code directly as lbc_runstr()
  Only available after runbcM()/runstr()
- prunbcM(), prunstr(), pdirectf() catches assert() and rtn emsg
- lbc_tbvalsv(), delsv(), cleansv() treats rtn/tb val
- lbc_pairs(), ipairs(), keysv(), valsv() handle luatb from C.
   mimicing the syntax of lua.
</pre>
**lhh** is hash api using luatb. lhh is independet from **lbc**.
lhh can uses lbc_pairs() / lbc_ipairs() macro. see samples.
<pre>
- lhh_new() creates hashtable. setup luavm and luatb internally.
- lhh_set() sets key/val to hash.
- lhh_unset() removes key/val from hash.
- lhh_get() gets val from hash.
- lhh_free() closes hash(luavm) and releases memory.
</pre>
setd(),unsetd(),getd() uses double type instead of integer.


EXSAMPLE
======
```
--mod.lua
local M={}
function M.myf() print("from_mod"); return 10; end
return M

--run.lua
local m = require("mod")
m.myf()
return -3, "gw"
-- ~$ luajit run.lua	#>> (testrun) from_mod
-- ~$ luajit -b mod.lua mod.h	#>> prepare bytecode mod.h
-- ~$ luajit -b run.lua run.h	#>> run.h

//--src.c 
#include "lbc.h"
int main(int argc, char** argv) {
	lbc_t* obj = lbc_new();
	#include "mod.h"
	lbc_reqbcM(obj, mod);	//macro: mod >> "mod.h" strlen(mod_XX);
	#include "run.h"
	int n = lbc_runbcM(obj, argc, argv, run);	//n=len{-3, "gw"}=2
		// set argv to _G.arg, works as ~$ luajit run.lua ag1 ag2 ...
	lbc_rt val = lbc_tbval(obj, 0, 2);	// val=obj[0][2]
	printf("%s\n", val.s);	// val.tp=='s'tring, val.s== "gw"
	lbc_free(obj);
	return 0;
}
//~$ gcc src.c -static liblbc.a -lm -ldl
//(or ~$ gcc src.c -lluajit5.1 -lm -ldl liblbc.a)
//..liblbc.a holds whole libluajit5.1.a files.

----------
//--src2.c,	detail sample code
#include "lbc.h"
int main(int ac, char** av) {
	lbc_t* obj = lbc_new();
	#include "mod1.h"
	#include "mod2.h"
	#include "mod3.h"
	#include "mod4.h"
	lbc_reqbcM(obj, mod1, mod2, mod3);	// support at least 9 args
	lbc_reqbcM(obj, mod4);	// allow req many times
	int n = lbc_runstr(obj, ac, av, "return require('mod2').myf()");
//call only once lbc_runbcM() or lbc_runstr() 
	
	lbc_rt val=lbc_tbval(obj,0,1);	//obj[0]={r1,r2}, obj[0][1]=r1 etc
//luartns are saved to [0], return 1,2,{10,20} >> obj[0]={1,2,{10,20}} 
//- int val.tp='s': (n)um(s)tr(t)b(b)ool(N)il(f)c(T)hread(u)data(l)udata
//- tp='s' >> sz=bytesz, tp='t' >> sz==#tb (tb[1]-tb[n], cnt only seq)
//- tp: val.i/val.d/val.s/val.sz == int/dbl/const char* /int 
//- test yourself if needs tp check: val.d-val.i==0 (...maybe int)
//- true/false,nil is converted to int val.i 1/0
//- val cant hold non-C data, table/func etc. val.tp check only.

// allows int/str key, tbval(obj,0,"k",&p,n)==obj[0]["k"]["str"][3]
//- use as str if ag starts with "/&. char* p="str", char** p=&str
//- strkey cant holds '\0'. not "/& args are treated as int
//- dbl cant use as key, lbc_tbval(obj, 3.01, "key1") == obj[3]["key1"]

	int idx=lbc_tbvalsv(3,obj,0,2); // obj[3]=obj[0][2]={1,k="a\0z"} etc
// copy from idx[0][2] to dst idx[3]. dstidx allows only intnum.
// lbc_runXX(), directf() uses obj[0] as rtnbuff and overwrite.

	idx = lbc_tbvalsv(-1, obj, 0, 1);	//dstidx<0: use autoidx. rtn= -1
	idx = lbc_tbvalsv(-9, obj, 0,"a");	//rtn=-2,obj[-2]=obj[0]["a"]=nil
	idx = lbc_tbvalsv(-1, obj, 0, 2);	//rtn= -2 (upper obj[-2]=nil)
	lbc_delsv(obj, -2);	// obj[-2]=nil
	lbc_cleansv(obj);	// del all autoidx, obj[idx<0]
	idx = lbc_tbvalsv(-7,obj,0); //obj[-1]=obj[0],rtn= -1
// you must manage saveidx yourself if use idx>0
// you may use autoidx for local val or tmpbuff pool etc.

//---
//mimic of luatb forloop, lbc_pairs/ipairs/keysv/valsv (macro/funcs)
//(k,v,obj,0,"key") >> obj[0]["key"]	...you cant use dbl as keyidx
	lbc_pairs(k, v, obj, 0){
		printf("%c, %c\n", k.tp, v.tp);		// obj[0] must be tb
		printf("%d, %d\n", k.i, v.i);		//k,v holds lbc_rt data
	}
	lbc_ipairs(num, val, obj, -3){
		printf("%d,%c\n",num,val.tp);	//obj[-3], ipair key is int
		int idx;
		idx=lbc_keysv(-8,obj); //obj[autoidx]=keydata, no needs ag 'num'
		idx=lbc_valsv(2,obj); //obj[2]=obj[-3][keydata]
		if(num>3){break;}
	}
	lbc_rt ck=lbc_tbval(obj, 2); //ck.i==123 etc. saved at pairs/ipairs

//---
//you can use lbc_directf() after lbc_runXX()
//almost the same as lbc_runstr()
//1: no argc, argv
//2: share the luajit global env. share the _G value 
//3: lua_pushfstring() fmt, restricted printf() fmt. see lua manual
//4: rtn is saved to obj[0]
	n = lbc_directf(obj, "print('hw'); return 10,%d", 20); //>> hw, n=2
	val = lbc_tbval(obj, 0, 2);		//>> retuns to obj[0], val.i==20

//you can access/edit obj[0][2] to use obj->glname as follows
	lbc_directf(obj,"print(%s[0][2]);return 1,'gw'",obj->glname); //20
	val = lbc_tbval(obj, 0, 2);	// val.s == "gw", overwrote obj[0]

//prunbcM(), prunstr(), pdirectf() works as pcall()
//catches inner error, assert() and 'return emsg' , returns 1 str if err.
	n= lbc_pdirectf(obj,"assert(nil,'abc')"); // err: n= -1, rtnsz=1
	if(n<0){ val = lbc_tbval(obj, 0, 1); }	// val.s == "abc", errmsg.
// rc 'n' is the same as runbcM(), count of return args if noerr

	lbc_free(obj);
	
//----
//--luahash, lhh is independent from lbc, lhh->L != lbc->L
//keystr cant holds '\0' but valstr can if set ag4.
	lhh_t* rec = lhh_new();
	int sum = lhh_set(rec,1,10); // rec[1]=10, sum=1(cnt holds data)
	lhh_set(rec, "abc", -3);	// rec["abc"] = -3
	lhh_set(rec, 11, "xy") ;	// rec[11] = "xy", sum=2
	lhh_set(rec,"a","a\0b",3);	// rec["a"]=a(\0)b, sz=3 (ag4)
	const char* ky = "abc";
	lhh_set(rec, &ky, -4);	// rec["abc"] = -4, sum=4, overwrite

//args numtype is int in dfl. XXd treats args as double type.
//set the correct type/value or cast (int) (double) if use numarg 
	lhh_setd(rec, 2.2, "a");	//rec[2.2]="a", setd() uses k/v dbl
	lhh_setd(rec, (double)2, 2.7); // rec[2]=2.7, treated by the luarule
	lhh_unsetd(rec, 2.2);	//rec[2.2]=nil, unset()/unsetd()
	lhh_unset(rec, "nosetkey");	//noerr
	
//get
	lhh_rt v = lhh_get(rec, "abc");	// v.tp='n', v.i= -4, v.tp/i/d/s/sz
	v = lhh_getd(rec, (double)11);	// v.tp='s', v.s="xy", v.sz=2
	v = lhh_get(rec, "a");	// v.tp='s', v.sz=3
//lhh can borrow lbc pairloop
	lbc_pairs(k, v, rec){
		printf("%s/%d %s/%d\n", k.s?k.s:"", k.i, v.s?v.s:"", v.i);
		lhh_unset(rec, 1);	// ok, del in loop
		lhh_set(rec, 11, "xxyz");	// ok, replace in loop
		//lhh_set(rec, 99, 1);
		//NG, add newval. use other buff, lhh_set(rec2, 99, 1) etc
		//lhh_get(rec, 1);
		//NG, get() breaks stack sequence. use k.i, v.i etc
	}
	lhh_free(rec);
	return 0;
}
//~$ gcc src2.c -lluajit5.1-a -lm -ldl liblbc.a
//if you use valgrind memcheck, use -static to avoid miscount.
//~$ gcc src2.c -static liblbc.a -lm -ldl
```

@OPTIONS	-
@EXIT_STATUS	-
@RETURN_VALUE
<pre>
int lbc_reqbcM(): suc/fail == 0/not0
int lbc_delsv():	same 
int lbc_cleansv():	same

int lbc_runbcM(): cnt return args. eg) (lua)return 0,"a",{1,2} >> 3
int lbc_runstr():	same
int lbc_directf():	same
int lbc_prunbcM(): same if no err. return -1 and set one emsg if err.
int lbc_prunstr():	same
int lbc_pdirectf():	same

int lbc_tbvalsv():	savedist index
int lbc_keysv():	same	
int lbc_valsv():	same

int lhh_set(): count of all holding keys
int lhh_setd(): same
int lhh_unset(): same
int lhh_unsetd(): same
</pre>
@ERRORS output emsg and exit(1)
@NOTES
- sloppy benchmark:

<pre>
--luajit vs lbc
lj : for i=1,num do local local v=i+1 end
C  : while(num){ lbc_tbvalsv(2, obj, 0, 1); }
//lj : real 154.00ms	:	loop: 100*1000*1000: (1)
//lbc: real	2943.116 ms	:	loop:   1*1000*1000: 20x100 == (2000)

--c99 hash vs lhh
- c99 posix hsearch()
	real	46.685 ms	: c99setloop: 1000*1000
	real	44.315 ms	: c99getloop: 1000*1000
- c arr[], arr[10]=100 etc
	real	21.068 ms	: arr, setloop: 1000*1000
	real	16.977 ms	: arr, getloop: 1000*1000
- luajit, table/arr tb[123]="abc"	etc
	set/get 22ms	:loop: 1000*1000
- lhh() lhh_set(obj,"key",10) etc
	real	197.392 ms	: lhh, setloop: 1000*1000
	real	192.476 ms	: lhh, getloop: 1000*1000
- lbc_directf(), "local tb[123]=456; return" etc
	real	3936.665 ms	: .directf: 1000*1000

FAST: c_arr,lj(1) > c99hash(2) >> lhh(10) >>> lbc(200) :SLOW
</pre>
..luajit vm is very fast but lua_stack() handling cause bottlenecks.
maybe you can bypass it with luajit ffi() cdata, direct pointer access.
(https://luajit.org/ext_ffi_tutorial.html, Cast pointer to address)
```
	normal usage                  use ffi() cdata
-----+          +-----          -----+          +-----
     | push/pop |               lj() +----------+ C_func()
lj() +----------+ C_func()           +----------+ 
     +----------+                    |          | 
     |          |            cdata <--------------> arr[]
-----+          +-----          -----+          +-----
```
- bypass code: lj >>> C
```
const char* cmd = 
  " ffi = require('ffi')"		//head "(space)", lua is free format  
  " local tb = {}; for i=1,1000 do tb[#tb+1]=i end"
  " local box= ffi.new('int[?]', #tb, tb )"

  " local adrs= " LBC_C2P("box")
  //-- macro 'LBC_C2P()' works as below, cdata to ptrnum
  //" local adrs=tonumber(ffi.cast('intptr_t',ffi.cast('void *',box)))"
 
  " return adrs, box"		//holds datasrc 'box' to protect from gc.
;
lbc_directf(obj, "%s", cmd);
lbc_rt res = lbc_tbval(obj, 0, 1);	//adrs
int* arr = (int*)(intptr_t)res.d;	// adrs(number) >> arr(ptr)
printf("%d %d\n", arr[0], arr[1]);		//>>1,2
```
- bypass code: lj <<< C
```
#include <inttypes.h>
const char* s = "a\0bc";
const char* fmt = " ffi = require('ffi')"
	" local str = " LBC_P2S
	
	//-- macro 'LBC_P2S' works as below. needs ptr + sz
	// " local cdata = ffi.new('uintptr_t', %" PRIuPTR ")"
	// " cdata = ffi.cast('const char*', cdata)"
	// " local str = ffi.string(cdata, %d)"
	
	//-- macro 'LBC_P2C' works as below. needs ptr only
	// " local cdata =" LBC_P2C
	// " cdata = ffi.cast(void*, ffi.new('uintptr_t', %" PRIuPTR "))"

	" return str..'xyz'"	//gc deletes cdata. res is copied to 'str'
;
lbc_directf(obj, fmt, s, 4);	// ptr,binsz == "a\0bc", 4
res = lbc_tbval(obj, 0, 1);	
printf("%c %s %s, %d\n", res.tp,res.s,res.s+2,res.sz);
	// 's', a(\0bcxyz), bcxyz, 7
lbc_free(obj);

// num<->ptr cast allows only throught intptr_t/uintptr_t in luajit.
// printf("%p\n", p) / printf("%" PRIuPTR "\n", p) work allmost the same
// the latter is more portable (c99 defined)
// ffi.string(cdata, len) can get str/bin[len] data from C

```
- concept
```
- use luajit code as __asm__ in C
- i want to embed normal luajit src.lua directly to C src
- no glue code, glue file
- get luacode result without complex stack handling
- output C code as 1 file without dependent files (a.out, libX.so etc) 
- easy api, low learning cost
- portable, posix
```

@CONFORMING_TO POSIX.1-2001+
@BUGS \-
@COPYRIGHT Copyright 2021 momi-g, GPLv3+
@VERSION 2021-07-05 v1.1.0
@SEE_ALSO
<pre>
https://www.lua.org/
https://luajit.org/
https://stackoverflow.com/questions/2632300
https://stackoverflow.com/questions/44479282
</pre>
//SH_docE*/
#ifndef lbc_5c607fb65f2e
#define lbc_5c607fb65f2e

#include <stdio.h>
#include <string.h>
#if ( _POSIX_C_SOURCE +0 < 200112L )
	#include "stop cc: needs compiler posix-2001 or upper(c99+)"
#endif
#ifndef	LBC_GLNAME
	#define LBC_GLNAME	"BCRUNNER_ARR"
#endif
#ifndef LBC_BCNAME
	#define LBC_BCNAME(name)	luaJIT_BC_ ## name
#endif
#define LBC_QU(...)	LBC_QUsub(__VA_ARGS__)
#define LBC_QUsub(...)	#__VA_ARGS__

typedef void lua_t;
typedef struct lbc_tag {
	lua_t* L;
	char* emsg;
	int rc;
	char glname[64];
	int lpflg;
	int used;
} lbc_t;

typedef struct lbc_rttag {
	int inner_flg;		//forloopのフラグで使う内部フラグ
	int  tp;
	int i;
	double d;
	const char* s;
	int sz;
} lbc_rt;

//--init+run
lbc_t* lbc_new(void);
void lbc_free(lbc_t* obj);

#define lbc_reqbcM(obj, ...)	lbc_reqbc_impl(obj, LBC_AG2REQ(__VA_ARGS__) )
#define lbc_runbcM(obj,ac,av,name)	\
	lbc_runbc_impl(0, obj, ac, av, LBC_BCNAME(name), (int)sizeof(LBC_BCNAME(name)), #name )
#define lbc_runstr(obj, ac, av, str)	\
	lbc_runbc_impl(0, obj,ac,av, str,strlen(str),__FILE__"_" LBC_QU(__LINE__) "_directstr" )
#define lbc_prunbcM(obj,ac,av,name)	\
	lbc_runbc_impl(1, obj, ac, av, LBC_BCNAME(name), (int)sizeof(LBC_BCNAME(name)), #name )
#define lbc_prunstr(obj, ac, av, str)	\
	lbc_runbc_impl(1, obj,ac,av, str,strlen(str),__FILE__"_" LBC_QU(__LINE__) "_directstr" )

/**/ int lbc_reqbc_impl(lbc_t* obj, ...);
/**/ int lbc_runbc_impl(int pflg, lbc_t* obj, int ac, char **av, const void* bc, int bcsz, const char* name );

#define LBC_AG2REQ(...)	LBC_EACH_MC(LBC_REQBC,LBC_REQBCE, __VA_ARGS__)
#define LBC_REQBC(n,a)	LBC_BCNAME(a), (int)sizeof(LBC_BCNAME(a)), #a
#define LBC_REQBCE(n,a)	NULL,0,NULL

//--result
#define lbc_tbval(...)	lbc_tbval_sub( LBC_AG2TB(__VA_ARGS__) )
#define lbc_tbvalsv(nidx,...) lbc_tbvalsv_sub(nidx, LBC_AG2TB(__VA_ARGS__) )
int lbc_delsv(lbc_t* obj,int idx);
int lbc_cleansv(lbc_t* obj);
#define lbc_directf(obj, ...) (lua_pushfstring(obj->L,__VA_ARGS__),lbc_directf_impl(0, obj) )
#define lbc_pdirectf(obj, ...) (lua_pushfstring(obj->L,__VA_ARGS__),lbc_directf_impl(1, obj) )
#define LBC_C2P(var) " tonumber(require('ffi').cast('intptr_t', require('ffi').cast('void *', " #var")))"
#define LBC_P2C	" require('ffi').cast('void*', require('ffi').new('uintptr_t', %" PRIuPTR "))"
#define LBC_P2S	" require('ffi').string(require('ffi').cast('const char*', require('ffi').new('uintptr_t', %" PRIuPTR ")), %d)"

#ifndef LBC_SOURCECODE
	const char* lua_pushfstring(/*nock*/);
#endif
lbc_rt lbc_tbval_impl(lbc_t* obj, const char* pidx, int idx, ...);
int lbc_tbvalsv_impl(int nidx, lbc_t* obj, const char* pidx, int idx, ...);
int lbc_directf_impl(int pflg, lbc_t* obj);
#define lbc_tbval_sub(...)	lbc_tbval_subb(__VA_ARGS__)
#define lbc_tbval_subb(lit,obj, ...)	lbc_tbval_impl(obj,__VA_ARGS__)
#define lbc_tbvalsv_sub(...)	lbc_tbvalsv_subb(__VA_ARGS__)
#define lbc_tbvalsv_subb(nidx,lit,obj,...) lbc_tbvalsv_impl(nidx,obj,__VA_ARGS__)
#define LBC_AG2TB(...)	LBC_EACH_MC(LBC_AGMC,LBC_AGMCE, __VA_ARGS__)
#define LBC_AGMC(n,a)	#a, a
#define LBC_AGMCE(n,a)	NULL, 0

//--result-support
#define lbc_pairs(k,v,...)	lbc_pairs_sub(0,k,v, LBC_AG2TB(__VA_ARGS__) )
#define lbc_ipairs(i,v,...)	lbc_ipairs_sub(1,i,v, LBC_AG2TB(__VA_ARGS__) )
#define lbc_keysv(nidx, obj)	lbc_keyvalsv_impl(nidx, obj, 'k')
#define lbc_valsv(nidx, obj)	lbc_keyvalsv_impl(nidx, obj, 'v')
int lbc_pairinit(int flg, lbc_t* obj, ...);
int lbc_pairexit(lbc_t* obj);
int lbc_isnextval(int mode, lbc_t* obj, void* k, lbc_rt* v);
int lbc_keyvalsv_impl(int nidx, lbc_t* obj, int tgt);
#define lbc_pairs_sub(mode, k,v, ...)	lbc_pairs_subb(mode,k,v,__VA_ARGS__)
#define lbc_pairs_subb(mode, k,v,lit,obj,...)	lbc_pairs_impl(mode,k,v,obj,__VA_ARGS__)
#define lbc_ipairs_sub(mode, k,v, ...)	lbc_ipairs_subb(mode,k,v,__VA_ARGS__)
#define lbc_ipairs_subb(mode, k,v,lit,obj,...)	lbc_ipairs_impl(mode,k,v,obj,__VA_ARGS__)
#define lbc_pairs_impl(mode, k,v, obj,...)	\
	for(lbc_rt k={0},v={1};lbc_pairinit(v.inner_flg, (lbc_t*)obj, __VA_ARGS__);lbc_pairexit((lbc_t*)obj) )	\
	for( ;lbc_isnextval(mode, (lbc_t*)obj, &k, &v); )
#define lbc_ipairs_impl(mode,i, v, obj, ...)	\
	for(lbc_rt v={1}; lbc_pairinit(v.inner_flg, (lbc_t*)obj, __VA_ARGS__);lbc_pairexit((lbc_t*)obj) )	\
	for( int i=0;lbc_isnextval(mode, (lbc_t*)obj, &i, &v); )

//--others, hash
typedef struct luahash_tag{
	lua_t* L;
	char* emsg;
	int rc;
	char glname[64];
	int lpflg;
	int cnt;
} lhh_t;
typedef lbc_rt lhh_rt;
#define LHH_GLNAME	"lhh_gname"

lhh_t* lhh_new(void);
void lhh_free(lhh_t* obj);
#define lhh_set(obj,k,v,...)	lhh_set_impl(0,obj,#k,k,#v,v,__VA_ARGS__+0)
#define lhh_setd(obj,k,v,...)	lhh_set_impl(1,obj,#k,k,#v,v,(double)(__VA_ARGS__+0) )

#define lhh_unset(obj, key)	lhh_unset_impl(0, obj, #key, key)
#define lhh_unsetd(obj, key)	lhh_unset_impl(1, obj, #key, key)
#define lhh_get(obj, key)	lhh_get_impl(0, obj, #key, key)
#define lhh_getd(obj, key)	lhh_get_impl(1, obj, #key, key)
/**/ int lhh_set_impl(int dmode, lhh_t* obj, const char* s, ...);
/**/ int lhh_unset_impl(int dmode, lhh_t* obj, const char* k, ...);
/**/ lhh_rt lhh_get_impl(int dmode, lhh_t* obj, const char* k, ...);

//--others, MC
// from license: cc-by-sa 2.5/3.0 (code is changed from the orig)
// https://stackoverflow.com/questions/2632300	Q: Ed Marty  ->  A: Matthew Slattery
#define LBC_EACH_MC(m,e,...)	LBC_EACH_MCsub(__VA_ARGS__,99,98,97,96,95,94,93,92,91,90 \
	,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66 \
	,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42 \
	,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18 \
	,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0) (m,e,__VA_ARGS__)
#define LBC_EACH_MCsub(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17 \
	,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35 \
	,a36,a37,a38,a39,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a50,a51,a52,a53 \
	,a54,a55,a56,a57,a58,a59,a60,a61,a62,a63,a64,a65,a66,a67,a68,a69,a70,a71 \
	,a72,a73,a74,a75,a76,a77,a78,a79,a80,a81,a82,a83,a84,a85,a86,a87,a88,a89 \
	,a90,a91,a92,a93,a94,a95,a96,a97,a98,a99,num,...)	LBC_MCN ## num

// https://stackoverflow.com/questions/44479282 Q: user1150609 -> A: H Walters
#define LBC_MCN0( m,e,a, ...)	e(0 ,a)
#define LBC_MCN1( m,e,a, ...)	m(1 ,a), LBC_MCN0( m,e, __VA_ARGS__ )
#define LBC_MCN2( m,e,a, ...)	m(2 ,a), LBC_MCN1( m,e, __VA_ARGS__ )
#define LBC_MCN3( m,e,a, ...)	m(3 ,a), LBC_MCN2( m,e, __VA_ARGS__ )
#define LBC_MCN4( m,e,a, ...)	m(4 ,a), LBC_MCN3( m,e, __VA_ARGS__ )
#define LBC_MCN5( m,e,a, ...)	m(5 ,a), LBC_MCN4( m,e, __VA_ARGS__ )
#define LBC_MCN6( m,e,a, ...)	m(6 ,a), LBC_MCN5( m,e, __VA_ARGS__ )
#define LBC_MCN7( m,e,a, ...)	m(7 ,a), LBC_MCN6( m,e, __VA_ARGS__ )
#define LBC_MCN8( m,e,a, ...)	m(8 ,a), LBC_MCN7( m,e, __VA_ARGS__ )
#define LBC_MCN9( m,e,a, ...)	m(9 ,a), LBC_MCN8( m,e, __VA_ARGS__ )
#define LBC_MCN10(m,e,a, ...)	m(10,a), LBC_MCN9( m,e, __VA_ARGS__ )
#define LBC_MCN11(m,e,a, ...)	m(11,a), LBC_MCN10(m,e, __VA_ARGS__ )
#define LBC_MCN12(m,e,a, ...)	m(12,a), LBC_MCN11(m,e, __VA_ARGS__ )
#define LBC_MCN13(m,e,a, ...)	m(13,a), LBC_MCN12(m,e, __VA_ARGS__ )
#define LBC_MCN14(m,e,a, ...)	m(14,a), LBC_MCN13(m,e, __VA_ARGS__ )
#define LBC_MCN15(m,e,a, ...)	m(15,a), LBC_MCN14(m,e, __VA_ARGS__ )
#define LBC_MCN16(m,e,a, ...)	m(16,a), LBC_MCN15(m,e, __VA_ARGS__ )
#define LBC_MCN17(m,e,a, ...)	m(17,a), LBC_MCN16(m,e, __VA_ARGS__ )
#define LBC_MCN18(m,e,a, ...)	m(18,a), LBC_MCN17(m,e, __VA_ARGS__ )
#define LBC_MCN19(m,e,a, ...)	m(19,a), LBC_MCN18(m,e, __VA_ARGS__ )
#define LBC_MCN20(m,e,a, ...)	m(20,a), LBC_MCN19(m,e, __VA_ARGS__ )
#define LBC_MCN21(m,e,a, ...)	m(21,a), LBC_MCN20(m,e, __VA_ARGS__ )
#define LBC_MCN22(m,e,a, ...)	m(22,a), LBC_MCN21(m,e, __VA_ARGS__ )
#define LBC_MCN23(m,e,a, ...)	m(23,a), LBC_MCN22(m,e, __VA_ARGS__ )
#define LBC_MCN24(m,e,a, ...)	m(24,a), LBC_MCN23(m,e, __VA_ARGS__ )
#define LBC_MCN25(m,e,a, ...)	m(25,a), LBC_MCN24(m,e, __VA_ARGS__ )
#define LBC_MCN26(m,e,a, ...)	m(26,a), LBC_MCN25(m,e, __VA_ARGS__ )
#define LBC_MCN27(m,e,a, ...)	m(27,a), LBC_MCN26(m,e, __VA_ARGS__ )
#define LBC_MCN28(m,e,a, ...)	m(28,a), LBC_MCN27(m,e, __VA_ARGS__ )
#define LBC_MCN29(m,e,a, ...)	m(29,a), LBC_MCN28(m,e, __VA_ARGS__ )
#define LBC_MCN30(m,e,a, ...)	m(30,a), LBC_MCN29(m,e, __VA_ARGS__ )
#define LBC_MCN31(m,e,a, ...)	m(31,a), LBC_MCN30(m,e, __VA_ARGS__ )
#define LBC_MCN32(m,e,a, ...)	m(32,a), LBC_MCN31(m,e, __VA_ARGS__ )
#define LBC_MCN33(m,e,a, ...)	m(33,a), LBC_MCN32(m,e, __VA_ARGS__ )
#define LBC_MCN34(m,e,a, ...)	m(34,a), LBC_MCN33(m,e, __VA_ARGS__ )
#define LBC_MCN35(m,e,a, ...)	m(35,a), LBC_MCN34(m,e, __VA_ARGS__ )
#define LBC_MCN36(m,e,a, ...)	m(36,a), LBC_MCN35(m,e, __VA_ARGS__ )
#define LBC_MCN37(m,e,a, ...)	m(37,a), LBC_MCN36(m,e, __VA_ARGS__ )
#define LBC_MCN38(m,e,a, ...)	m(38,a), LBC_MCN37(m,e, __VA_ARGS__ )
#define LBC_MCN39(m,e,a, ...)	m(39,a), LBC_MCN38(m,e, __VA_ARGS__ )
#define LBC_MCN40(m,e,a, ...)	m(40,a), LBC_MCN39(m,e, __VA_ARGS__ )
#define LBC_MCN41(m,e,a, ...)	m(41,a), LBC_MCN40(m,e, __VA_ARGS__ )
#define LBC_MCN42(m,e,a, ...)	m(42,a), LBC_MCN41(m,e, __VA_ARGS__ )
#define LBC_MCN43(m,e,a, ...)	m(43,a), LBC_MCN42(m,e, __VA_ARGS__ )
#define LBC_MCN44(m,e,a, ...)	m(44,a), LBC_MCN43(m,e, __VA_ARGS__ )
#define LBC_MCN45(m,e,a, ...)	m(45,a), LBC_MCN44(m,e, __VA_ARGS__ )
#define LBC_MCN46(m,e,a, ...)	m(46,a), LBC_MCN45(m,e, __VA_ARGS__ )
#define LBC_MCN47(m,e,a, ...)	m(47,a), LBC_MCN46(m,e, __VA_ARGS__ )
#define LBC_MCN48(m,e,a, ...)	m(48,a), LBC_MCN47(m,e, __VA_ARGS__ )
#define LBC_MCN49(m,e,a, ...)	m(49,a), LBC_MCN48(m,e, __VA_ARGS__ )
#define LBC_MCN50(m,e,a, ...)	m(50,a), LBC_MCN49(m,e, __VA_ARGS__ )
#define LBC_MCN51(m,e,a, ...)	m(51,a), LBC_MCN50(m,e, __VA_ARGS__ )
#define LBC_MCN52(m,e,a, ...)	m(52,a), LBC_MCN51(m,e, __VA_ARGS__ )
#define LBC_MCN53(m,e,a, ...)	m(53,a), LBC_MCN52(m,e, __VA_ARGS__ )
#define LBC_MCN54(m,e,a, ...)	m(54,a), LBC_MCN53(m,e, __VA_ARGS__ )
#define LBC_MCN55(m,e,a, ...)	m(55,a), LBC_MCN54(m,e, __VA_ARGS__ )
#define LBC_MCN56(m,e,a, ...)	m(56,a), LBC_MCN55(m,e, __VA_ARGS__ )
#define LBC_MCN57(m,e,a, ...)	m(57,a), LBC_MCN56(m,e, __VA_ARGS__ )
#define LBC_MCN58(m,e,a, ...)	m(58,a), LBC_MCN57(m,e, __VA_ARGS__ )
#define LBC_MCN59(m,e,a, ...)	m(59,a), LBC_MCN58(m,e, __VA_ARGS__ )
#define LBC_MCN60(m,e,a, ...)	m(60,a), LBC_MCN59(m,e, __VA_ARGS__ )
#define LBC_MCN61(m,e,a, ...)	m(61,a), LBC_MCN60(m,e, __VA_ARGS__ )
#define LBC_MCN62(m,e,a, ...)	m(62,a), LBC_MCN61(m,e, __VA_ARGS__ )
#define LBC_MCN63(m,e,a, ...)	m(63,a), LBC_MCN62(m,e, __VA_ARGS__ )
#define LBC_MCN64(m,e,a, ...)	m(64,a), LBC_MCN63(m,e, __VA_ARGS__ )
#define LBC_MCN65(m,e,a, ...)	m(65,a), LBC_MCN64(m,e, __VA_ARGS__ )
#define LBC_MCN66(m,e,a, ...)	m(66,a), LBC_MCN65(m,e, __VA_ARGS__ )
#define LBC_MCN67(m,e,a, ...)	m(67,a), LBC_MCN66(m,e, __VA_ARGS__ )
#define LBC_MCN68(m,e,a, ...)	m(68,a), LBC_MCN67(m,e, __VA_ARGS__ )
#define LBC_MCN69(m,e,a, ...)	m(69,a), LBC_MCN68(m,e, __VA_ARGS__ )
#define LBC_MCN70(m,e,a, ...)	m(70,a), LBC_MCN69(m,e, __VA_ARGS__ )
#define LBC_MCN71(m,e,a, ...)	m(71,a), LBC_MCN70(m,e, __VA_ARGS__ )
#define LBC_MCN72(m,e,a, ...)	m(72,a), LBC_MCN71(m,e, __VA_ARGS__ )
#define LBC_MCN73(m,e,a, ...)	m(73,a), LBC_MCN72(m,e, __VA_ARGS__ )
#define LBC_MCN74(m,e,a, ...)	m(74,a), LBC_MCN73(m,e, __VA_ARGS__ )
#define LBC_MCN75(m,e,a, ...)	m(75,a), LBC_MCN74(m,e, __VA_ARGS__ )
#define LBC_MCN76(m,e,a, ...)	m(76,a), LBC_MCN75(m,e, __VA_ARGS__ )
#define LBC_MCN77(m,e,a, ...)	m(77,a), LBC_MCN76(m,e, __VA_ARGS__ )
#define LBC_MCN78(m,e,a, ...)	m(78,a), LBC_MCN77(m,e, __VA_ARGS__ )
#define LBC_MCN79(m,e,a, ...)	m(79,a), LBC_MCN78(m,e, __VA_ARGS__ )
#define LBC_MCN80(m,e,a, ...)	m(80,a), LBC_MCN79(m,e, __VA_ARGS__ )
#define LBC_MCN81(m,e,a, ...)	m(81,a), LBC_MCN80(m,e, __VA_ARGS__ )
#define LBC_MCN82(m,e,a, ...)	m(82,a), LBC_MCN81(m,e, __VA_ARGS__ )
#define LBC_MCN83(m,e,a, ...)	m(83,a), LBC_MCN82(m,e, __VA_ARGS__ )
#define LBC_MCN84(m,e,a, ...)	m(84,a), LBC_MCN83(m,e, __VA_ARGS__ )
#define LBC_MCN85(m,e,a, ...)	m(85,a), LBC_MCN84(m,e, __VA_ARGS__ )
#define LBC_MCN86(m,e,a, ...)	m(86,a), LBC_MCN85(m,e, __VA_ARGS__ )
#define LBC_MCN87(m,e,a, ...)	m(87,a), LBC_MCN86(m,e, __VA_ARGS__ )
#define LBC_MCN88(m,e,a, ...)	m(88,a), LBC_MCN87(m,e, __VA_ARGS__ )
#define LBC_MCN89(m,e,a, ...)	m(89,a), LBC_MCN88(m,e, __VA_ARGS__ )
#define LBC_MCN90(m,e,a, ...)	m(90,a), LBC_MCN89(m,e, __VA_ARGS__ )
#define LBC_MCN91(m,e,a, ...)	m(91,a), LBC_MCN90(m,e, __VA_ARGS__ )
#define LBC_MCN92(m,e,a, ...)	m(92,a), LBC_MCN91(m,e, __VA_ARGS__ )
#define LBC_MCN93(m,e,a, ...)	m(93,a), LBC_MCN92(m,e, __VA_ARGS__ )
#define LBC_MCN94(m,e,a, ...)	m(94,a), LBC_MCN93(m,e, __VA_ARGS__ )
#define LBC_MCN95(m,e,a, ...)	m(95,a), LBC_MCN94(m,e, __VA_ARGS__ )
#define LBC_MCN96(m,e,a, ...)	m(96,a), LBC_MCN95(m,e, __VA_ARGS__ )
#define LBC_MCN97(m,e,a, ...)	m(97,a), LBC_MCN96(m,e, __VA_ARGS__ )
#define LBC_MCN98(m,e,a, ...)	m(98,a), LBC_MCN97(m,e, __VA_ARGS__ )
#define LBC_MCN99(m,e,a, ...)	m(99,a), LBC_MCN98(m,e, __VA_ARGS__ )
// end license:	cc-by-sa 2.5/3.0

#endif /* lbc_5c607fb65f2e */
