/*	GPL3+	*/
/* Copyright (C) 2019 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/>.
 */

/*-*
@name	dq
@auther momi-g
@brief	auto growing array
@synopsys
	// dflfuncs idq/ddq/pdq corresponds to int/double/void* payload   
	#include "dq.h"

	dq_t* idq_new(void)
	void idq_free(dq_t* dq)
	void idq_frees(dq_t* dq)
	
	void idq_push(dq_t* dq, int i)		// void pdq_push(dq_t* dq, void* p)
	int idq_pop(dq_t* dq)				// double ddq_pop(dq_t* dq)
	void idq_lift(dq_t* dq, int i)
	int idq_drop(dq_t* dq)

	int idq_popn(dq_t* dq, int cnt)
	int idq_dropn(dq_t* dq, int cnt)
	void idq_reset(dq_t* dq)
	
	int idq_rep(dq_t* dq, int idx, int i)
	int idq_see(dq_t* dq, int idx)
	int* idq_2arr(dq_t* dq)
	
	// custom macros
	#define DQ_CMN		deq		// >> ideq_new()
	DQ_IMPL([scope], [type], [pfix])	// DQ_IMPL(static, int32_t, i32)
	DQ_VOIDCALL()	// stop compile nouse warning

@eg
 // lift >>                              << push
 //         | head[0] | ... | tail[-1] |
 // drop <<                              >> pop
 
 #include "dq.h"
 int main(int argc, char** argv) {
 	int v;
 	dq_t* q=idq_new();	//		|NULL|
 
 	idq_push(q,11);		//		| 11 |
 	idq_push(q,22);		//		| 11 | 22 |
 	idq_push(q,33);		//		| 11 | 22 | 33 |
 	v = idq_pop(q);		//		| 11 | 22 |		>> v=33
 
 	idq_lift(q,10);		//		| 10 | 11 | 22 |
 	idq_lift(q,20);		//		| 20 | 10 | 11 | 22 |
 	v = idq_drop(q);	//		| 10 | 11 | 22 |	>> v=20
 
 	v = idq_see(q,0);	//		| 10 | 11 | 22 |	>> v=10
 	v = idq_see(q,-1);	//		| 10 | 11 | 22 |	>> v=22 (-1: tail)
 	v = idq_len(q);		//		| 10 | 11 | 22 |	>> v=3

 	idq_dropn(q,2);		//		| 22 |		>> drop x2
//	idq_popn(q,2);		//		| 10 |		>> pop x2
//	idq_reset(q);		//		|NULL|		>> clear all
//	idq_dropn(q,-1);	//		|NULL|		>> same as above
 	v = idq_len(q);		//		| 22 |		>> v=1
 	
// conv to arr
	int* arr = idq_2arr(q);	//	dup payload. 
 	dq_free(q);		// arr[0] == 22, duped.
	free(arr);		// needs free() same as c99 strdup()
 
// works only pdq func, 'pdq_frees()'
 	dq_t* dq = pdq_new();
 	void* p = malloc(32);
 	pdq_push(dq, p);
 	pdq_frees(dq);	//... free() payload and destroy dq.
 	// free(p);		...no need.
 	
// use voidcall if you detect unused warning at compile
	// DQ_VOIDCALL();
	return 0;
 }
 // ~$ gcc src.c dq.c

@param dq	arr/deque obj. holds memsz, idxdata, arrlen etc.
@param idx	tgt index. start with 0 and tail is -1. allows, -2, -3 etc.
@param cnt	popn/dropn takes cnt. cnt== -1 works as dq_reset().
@return	?	val/len etc. rtntype depends on new() type. popn/dropn rtns lastone.
@details
 - other type payload
	dflapi is only idq/ddq/pdq. you can use DQ_IMPL() macro for your own types.
		#include "dq.h"

		typedef struct my_tag{int a, int b} my_t;
		DQ_IMPL(static, my_t, zz)
		//	...>> expand macro
		//	static dq_t* zzdq_new(void){ ..code.. }
		//	static void zzdq_push(dq_t* dq, my_t v){..code..}
		//	static my_t* zzdq_2arr(dq_t* dq){ ..code.. }
		//.. new/push/pop(n)/lift/drop(n)/len/see/rep/reset/2arr/free
		dq_t* q = zzdq_new();
		my_t v = {1,2};
		zzdq_push(q, v);
		...

 - use no prefix api 'dq_XXX()'
	dflname 'dq_XXX' is undefined. you can set dfl apiname as follows. 
		#include "dq.h"
		DQ_IMPL(static, void*, )		// 3rd arg is blank

	 	dq_t* q=pdq_new();
		dq_t* Q= dq_new();	// use dq_new() as pdq_new()

 - rename 'dq' word	
	dq() uses cmnname 'dq' in func and type, idq_new()/dq_t.
	you can change word if set macro 'DQ_CMN' before includes dq.h 
	
		#define DQ_CMN	stack
		#include "dq.h"
		...
		stack_t* stk = istack_new();		// dq_t* stk = idq_new();	...dfl
		istack_push(stk, 10);
		...
	--
		#define DQ_CMN	stk
		#include "dq.h"
		typedef struct my_tag{int a; int b;} my_t;
		DQ_IMPL(static, int, )
		DQ_IMPL(static, my_t, m)
		
		int main(int argc, char** argv){
			stk_t* stk = stk_new();
			stk_push(stk, 10);
			stk_free(stk);
		
			mstk_t* obj = mstk_new();
			mstk_push(obj, (my_t){11,22} );		// (my_t)..compound lit, c99+
			mstk_free(obj);
			return 0;
		}

 - stop compile warning
	compile warning 'unused' will raise if you doesnt use idq()/ddq()/pdq().
	you can stop warning by calling DQ_VOIDCALL(). 

		#include "dq.h"
		int main(int argc, char** argv){
			DQ_VOIDCALL();
			return 0;
		}

	..DQ_VOIDCALL() do nothing. funcs are described in the unreachable block.

@_note
	-- sloppy speedtest( -O0)
	 - read/write
	arr[2]	:	36-41 ms
	dq_rep():	560-600 ms	(15-20 times slow, -O2:250ms, -O2+inline: 190ms)
	dq_2arr():	38-41 ms
	 - write
	arr[2]	:	48-50 ms
	dq_push():	300-350 ms	(6-8 times slow)
	
	 ..overhead src: idx funccall / idx calc+errck
	 ..'inline' will not be needed in generally
	
	-- test code
	int sz= 10 * 1000*1000;
	 - read/write
	for(int i=0; i<sz;i++){ arr[0]=arr[1]+1;}	//36-41ms
	for(int i=0; i<sz;i++){ idq_rep(dq, -1, idq_see(dq,0)+1);}	//370-390ms
	for(int i=0; i<sz;i++){ d2arr[1]=d2arr[0]+1; }	//38-41ms
	
	 - write
	for(i=0; i<sz-1;i++){ arr[0]=i%10;}	//48-50ms
	for(i=0; i<sz-1;i++){ idq_push(dq, i%10); }	//300-350ms

	- inline
	DQ_IMPL(static inline, int, ii)
	for(int i=0; i<sz;i++){ iidq_rep(dq, -1, iidq_see(dq,0)+1);}	//190ms
	
@conforming c89+
@version 2021-07-10 v1.1.2
-*/
#ifndef dq_3a298c227c3b
#define dq_3a298c227c3b	dq_3a298c227c3b
/*
- support auto realloc() deque
- support any size() payload, int/double/my_t etc
- support rename apifunc,	dfl: dq_new()	>>	custom: dqmy_new() 
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/* #include "msgp.h" //*/

/* config */
#define DQ_BNAME	dq_3a298c227c3b
#define DQ_DFLLEN	32

#ifndef DQ_CMN
	#define DQ_CMN	dq
#endif

/* tools */
#define DQ_SCAT2(a,b)	DQ_SCAT2sub(a,b)
#define DQ_SCAT2sub(a,b)	a ## b

#define DQ_SCAT3	DQ_SCAT
#define DQ_SCAT(a,b,c)	DQ_SCATsub(a,b,c)
#define DQ_SCATsub(a,b,c)	a ## b ## c
#define DQ_BTYPE	DQ_SCAT2(DQ_BNAME,_t)
#define DQ_MTYPE	DQ_SCAT2(DQ_CMN,_t)
#define DQ_MTYPEDEF(mytype)	typedef DQ_BTYPE mytype;
#define DQ_CMT(a)

#if  (199901L <= __STDC_VERSION__ +0)  /* nealy 200112L, _POSIX_C_SOURCE	c99*/
#define DQ_PANIC(xpr, msg, act)	do{if(xpr){ fprintf(stderr, \
				"ERR: %s %d: %s():%s msg:%s sys:%s\n",__FILE__,__LINE__, __func__, \
				"hit(" #xpr ")", msg, strerror(errno) );act;} }while(0)
#else
#define DQ_PANIC(xpr, msg, act)	do{if(xpr){ fprintf(stderr, \
				"ERR: %s %d: %s():%s msg:%s sys:%s\n",__FILE__,__LINE__, "func:c99+", \
				"hit(" #xpr ")", msg, strerror(errno) );act;} }while(0)
#endif

/* main macro */
/* static dq_t* idq_new(void){...} etc */
#define DQ_IMPL(sc,tp,tpc)	DQ_IMPLsub(sc,tp,tpc,DQ_DFLLEN,DQ_CMN,DQ_MTYPE,DQ_BNAME,DQ_BTYPE)
#define DQ_IMPLsub(SCOPE, TP, TPC, DFLLEN, PFIX, MTYPE, BNAME, BTYPE)		\
static void DQ_SCAT(TPC,PFIX,BNAME)(void);									\
SCOPE MTYPE* DQ_SCAT(TPC,PFIX,_new)(void) {            			  			\
	MTYPE* rtn;																\
	int tpsz;  																\
	int memsz; 																\
	void* buf; 																\
	rtn=(MTYPE*)calloc(sizeof(MTYPE), 1);                        			\
	DQ_PANIC(rtn==NULL, "calloc() failed.", return NULL);    				\
	tpsz=sizeof(TP);                                                		\
	memsz=	DFLLEN *tpsz;              	    	                    		\
	buf= (void*)malloc( memsz );                                   			\
	DQ_PANIC(buf==NULL, "malloc() failed.", return NULL);	  				\
	memset(buf, '\0', memsz);                                           	\
																			\
	rtn->arr= buf;                                                       	\
	rtn->tp=	#TPC;                                                      	\
	rtn->tpsz= tpsz;                                                     	\
	rtn->sidx= DFLLEN-1;                                                   	\
	rtn->eidx= 0;                                                       	\
	rtn->len= 0;                                                         	\
	rtn->mlen= DFLLEN;	                                                	\
	return rtn;                                                         	\
	DQ_SCAT(TPC,PFIX,BNAME)();												\
}                                                                       	\
SCOPE void DQ_SCAT(TPC,PFIX,_push)(MTYPE* dq, TP v) {                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	if(dq->len >= dq->mlen) { DQ_SCAT2(BNAME,_extend)(dq); }            	\
	arr = (TP*)dq->arr; 	                                            	\
	arr[dq->eidx] = v;							                           	\
	dq->eidx++;                                                             \
	dq->len++;                                                              \
	if(dq->eidx==dq->mlen){dq->eidx=0;}                                     \
}                                                                       	\
SCOPE void DQ_SCAT(TPC,PFIX,_lift)(MTYPE* dq, TP v) {                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	if(dq->len >= dq->mlen) { DQ_SCAT2(BNAME,_extend)(dq); }   		    	\
	arr = (TP*)dq->arr;                                                 	\
	arr[dq->sidx] = v;							                           	\
    dq->sidx--;                                   						 	\
	dq->len++;                                                          	\
	if(dq->sidx<0){dq->sidx = dq->mlen-1;}                      			\
}                                                                       	\
SCOPE TP DQ_SCAT(TPC,PFIX,_popn)(MTYPE* dq, int cnt) {                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;                                             		\
	if(cnt== 1){                                                            \
		DQ_PANIC(dq->len==0, "dq_len()==0, tgt stack is empty", exit(1) );	\
		dq->eidx--;                                                         \
		dq->len--;															\
		if(dq->eidx<0){dq->eidx=dq->mlen-1;}                                \
	}                                                                       \
	else if(cnt<0){		                                                    \
		dq->eidx = dq->sidx+1;                                           	\
		dq->len=0;															\
		if(dq->eidx>=dq->mlen){dq->eidx=0;}                               	\
	}                                                                       \
	else {                                                                  \
		DQ_PANIC(dq->len<cnt, "popcnt is too large", exit(1) );				\
		dq->eidx -= cnt;                                                    \
		dq->len -= cnt;                                                     \
		if(dq->eidx<0){dq->eidx+=dq->mlen;}                               	\
	}                                                                       \
	return arr[dq->eidx];                                                  	\
}                                                                       	\
SCOPE TP DQ_SCAT(TPC,PFIX,_pop)(MTYPE* dq) {                                \
	return DQ_SCAT(TPC,PFIX,_popn)(dq, 1); 		                            \
}                    	                                                    \
SCOPE TP DQ_SCAT(TPC,PFIX,_reset)(MTYPE* dq) {                              \
	return DQ_SCAT(TPC,PFIX,_popn)(dq, -1);                                 \
}                    	                                                    \
SCOPE TP DQ_SCAT(TPC,PFIX,_dropn)(MTYPE* dq, int cnt) {	                   	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;                                             		\
	if(cnt== 1){                                                            \
		DQ_PANIC(dq->len==0, "dq_len()==0, tgt stack is empty", exit(1) );	\
		dq->sidx++;                                                         \
		dq->len--;															\
		if(dq->sidx>=dq->mlen){dq->sidx=0;}                                 \
	}                                                                       \
	else if(cnt<0){		                                                    \
		dq->sidx = dq->eidx-1;                                           	\
		dq->len=0;															\
		if(dq->sidx<0){dq->sidx+=dq->mlen;}                               	\
	}                                                                       \
	else {                                                                  \
		DQ_PANIC(dq->len<cnt, "dropcnt is too large", exit(1) );			\
		dq->sidx += cnt;                                                    \
		dq->len -= cnt;                                                     \
		if(dq->sidx>=dq->mlen){dq->sidx-=dq->mlen;}                        	\
	}                                                                       \
	return arr[dq->sidx];                                                  	\
}        	                                                             	\
SCOPE TP DQ_SCAT(TPC,PFIX,_drop)(MTYPE* dq) {                               \
	return DQ_SCAT(TPC,PFIX,_dropn)(dq, 1);                                 \
}                    	                                                    \
SCOPE void DQ_SCAT(TPC,PFIX,_rep)(MTYPE* dq, int idx, TP v) {	           	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;                                             		\
	arr[DQ_SCAT2(BNAME,_getidx)(dq, idx)] = v;                              \
}                                                                       	\
SCOPE TP DQ_SCAT(TPC,PFIX,_see)(MTYPE* dq, int idx) {                    	\
	TP* arr;				                                             	\
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	arr = (TP*)dq->arr;		                                           		\
	return arr[DQ_SCAT2(BNAME,_getidx)(dq, idx)];                  			\
}                                                                       	\
SCOPE TP* DQ_SCAT(TPC,PFIX,_2arr)(MTYPE* dq) {		                     	\
	TP* arr;				                                             	\
	TP* p;					                                             	\
	int sidx, eidx;                                                         \
	DQ_PANIC(!dq, "dq obj is NULL", exit(1); );	    						\
	if(dq->len==0){return NULL;}                                            \
	arr = (TP*)dq->arr;		                                           		\
	p = (TP*)calloc(dq->len, dq->tpsz);                              		\
	sidx = dq->sidx+1;      	                                            \
	eidx = dq->eidx-1;		                                                \
	if(sidx>=dq->mlen){sidx= 0;}                                            \
	if(eidx<0){eidx= dq->mlen-1;}                                           \
	if(sidx<eidx||dq->len==1){ memcpy(p,&(arr[sidx]), dq->len*dq->tpsz); }	\
	else{                                                                   \
		memcpy( p, &(arr[sidx]), (dq->mlen-sidx)*dq->tpsz);					\
		memcpy( &(p[dq->mlen-sidx]), arr, (eidx+1)*dq->tpsz);               \
	}			  								                            \
	return p;                                                               \
}		                                                                    \
SCOPE size_t DQ_SCAT(TPC,PFIX,_len)(MTYPE* dq){return DQ_SCAT2(BNAME,_len)(dq);}	\
SCOPE void DQ_SCAT(TPC,PFIX,_free)(MTYPE* dq){DQ_SCAT2(BNAME,_free)(dq);}			\
SCOPE void DQ_SCAT(TPC,PFIX,_frees)(MTYPE* dq){DQ_SCAT2(BNAME,_frees)(dq);}			\
static void DQ_SCAT(TPC,PFIX,BNAME)(void){				\
MTYPE* dmy; TP obj;		return;                        	\
DQ_SCAT(TPC,PFIX,_new)();	                            \
DQ_SCAT(TPC,PFIX,_push)		(dmy, obj);	                \
DQ_SCAT(TPC,PFIX,_lift)		(dmy, obj);                 \
DQ_SCAT(TPC,PFIX,_pop)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_popn)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_drop)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_dropn)	(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_reset)	(dmy); 	                    \
DQ_SCAT(TPC,PFIX,_rep)		(dmy, 0, obj);              \
DQ_SCAT(TPC,PFIX,_see)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_2arr)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_len)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_free)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_frees)	(dmy);                      \
}	\
/*tail_IMPL*/

/* dfl global funcs, TPC+BNAME+_push(BTYPE*, TP) == idqbasic_push(dq_t*, int) */
/* len/free uses raw basicname */
#define DQ_PROTOBASE(TP, TPC)		\
DQ_BTYPE* DQ_SCAT(TPC,DQ_BNAME,_new)(void);	                	\
void	DQ_SCAT(TPC,DQ_BNAME,	_push	)	(DQ_BTYPE*,		TP	);	  	\
void	DQ_SCAT(TPC,DQ_BNAME,	_lift	)	(DQ_BTYPE*,		TP	);	  	\
TP		DQ_SCAT(TPC,DQ_BNAME,	_pop	)	(DQ_BTYPE*			);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_popn	)	(DQ_BTYPE*,	int		);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_drop	)	(DQ_BTYPE*			);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_dropn	)	(DQ_BTYPE*, int		);		\
TP		DQ_SCAT(TPC,DQ_BNAME,	_reset	)	(DQ_BTYPE*			);		\
void	DQ_SCAT(TPC,DQ_BNAME,	_rep	)	(DQ_BTYPE*,	int,TP	);   	\
TP		DQ_SCAT(TPC,DQ_BNAME,	_see	)	(DQ_BTYPE*,	int		);   	\
TP*		DQ_SCAT(TPC,DQ_BNAME,	_2arr	)	(DQ_BTYPE*			);   	\
/*tail_PROTOBASE*/


/* LINK,sub,VOID: make VOIDCALL(). call i/d/p funcs from yoursrc to stop warn */
/* DQ_LINKBASE() >>
	static idq_new(){return idqbase_new(); }
	static idq_push(){return idqbase_push(); }
	// static izz_push(){return ddqbase_push();  }	//if DQ_CMN==zz
	...
	void voidcall(){ return;
		idq_new();
		//izz_new();
		...
	}
*/
#define DQ_VOIDCALL	DQ_CMT(*** write DQ_VOIDCALL(); to yoursrc.c to del warning ***) DQ_SCAT(_voidcall, _unused_warn_stopper_, DQ_BNAME)
#define DQ_LINKBASE(dmy)					\
	DQ_LINKBASEsub(int, i, DQ_CMN)			\
	DQ_LINKBASEsub(double, d, DQ_CMN)		\
	DQ_LINKBASEsub(void*, p, DQ_CMN)		\
static void DQ_VOIDCALL(void){ return;		\
	DQ_SCAT(i,dmycall,DQ_BNAME)();			\
	DQ_SCAT(d,dmycall,DQ_BNAME)();			\
	DQ_SCAT(p,dmycall,DQ_BNAME)();			\
}	\
/*tail_LINKBASE*/

#define DQ_LINKBASEsub(TP, TPC, PFIX)		\
static void DQ_SCAT(TPC,dmycall,DQ_BNAME)(void);	\
static DQ_MTYPE* DQ_SCAT(TPC,PFIX,_new)		(void)						{return DQ_SCAT(TPC,DQ_BNAME,_new		)	();DQ_SCAT(TPC,dmycall,DQ_BNAME)();} \
static void		DQ_SCAT(TPC,PFIX,_push)		(DQ_MTYPE* a,	TP b)		{/**/		DQ_SCAT(TPC,DQ_BNAME,_push		)	(a,b)	;} \
static void		DQ_SCAT(TPC,PFIX,_lift)		(DQ_MTYPE* a,	TP b)		{/**/	DQ_SCAT(TPC,DQ_BNAME,_lift		)	(a,b)	;} \
static TP		DQ_SCAT(TPC,PFIX,_pop)		(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_popn		)	(a,1)	;} \
static TP		DQ_SCAT(TPC,PFIX,_popn)		(DQ_MTYPE* a, int b )		{return DQ_SCAT(TPC,DQ_BNAME,_popn		)	(a,b)	;} \
static TP		DQ_SCAT(TPC,PFIX,_drop)		(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_dropn		)	(a,1)	;} \
static TP		DQ_SCAT(TPC,PFIX,_dropn)	(DQ_MTYPE* a, int b )		{return DQ_SCAT(TPC,DQ_BNAME,_dropn		)	(a,b)	;} \
static TP		DQ_SCAT(TPC,PFIX,_reset)	(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_popn		)	(a,-1)	;} \
static void		DQ_SCAT(TPC,PFIX,_rep)		(DQ_MTYPE* a,int b,TP c)	{/**/	DQ_SCAT(TPC,DQ_BNAME,_rep		)	(a,b,c)	;} \
static TP		DQ_SCAT(TPC,PFIX,_see)		(DQ_MTYPE* a, int b	)		{return DQ_SCAT(TPC,DQ_BNAME,_see		)	(a,b)	;} \
static TP*		DQ_SCAT(TPC,PFIX,_2arr)		(DQ_MTYPE* a		)		{return DQ_SCAT(TPC,DQ_BNAME,_2arr		)	(a)		;} \
static size_t	DQ_SCAT(TPC,PFIX,_len)		(DQ_MTYPE* a)        	{return DQ_SCAT2(DQ_BNAME,_len		)	(a)		;} \
static void		DQ_SCAT(TPC,PFIX,_free)		(DQ_MTYPE* a)         	{/**/	DQ_SCAT2(DQ_BNAME,_free		)	(a)		;} \
static void		DQ_SCAT(TPC,PFIX,_frees)	(DQ_MTYPE* a)         	{/**/	DQ_SCAT2(DQ_BNAME,_frees	)	(a)		;} \
static void DQ_SCAT(TPC,dmycall,DQ_BNAME)(void){		\
DQ_MTYPE* dmy; TP obj; return;                          \
DQ_SCAT(TPC,PFIX,_new)();	                            \
DQ_SCAT(TPC,PFIX,_push)		(dmy, obj);	                \
DQ_SCAT(TPC,PFIX,_lift)		(dmy, obj);                 \
DQ_SCAT(TPC,PFIX,_pop)		(dmy);	                    \
DQ_SCAT(TPC,PFIX,_popn)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_drop)		(dmy);		                \
DQ_SCAT(TPC,PFIX,_dropn)	(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_reset)	(dmy);	                    \
DQ_SCAT(TPC,PFIX,_rep)		(dmy, 0, obj);              \
DQ_SCAT(TPC,PFIX,_see)		(dmy, 0);                   \
DQ_SCAT(TPC,PFIX,_2arr)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_len)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_free)		(dmy);                      \
DQ_SCAT(TPC,PFIX,_frees)	(dmy);                      \
}	\
/*tail_DQ_LINKBASEsub*/

/* header_main */
typedef struct DQ_SCAT2(DQ_BNAME,_tag){  		  
	void* arr;                           		  
	const char* tp;                      		  
	int tpsz;                            		  
	int sidx;
	int eidx;                            		  
	int len;                             		  
	int mlen;                            		  
} DQ_BTYPE;
typedef DQ_BTYPE	DQ_SCAT2(DQ_CMN,_t);		

/* dfl funcs */                          		  
/*	dq123z* dq123z_new(void) etc. basicfunc. impl is wrote in dq.c.	*/
DQ_PROTOBASE(int, i)
DQ_PROTOBASE(double, d)
DQ_PROTOBASE(void*, p)

/* cmn_basicfuncs, prototype */
size_t	DQ_SCAT2(DQ_BNAME,	_len	)	(DQ_BTYPE*);              	
void	DQ_SCAT2(DQ_BNAME,	_free	)	(DQ_BTYPE*);              	
void	DQ_SCAT2(DQ_BNAME,	_frees	)	(DQ_BTYPE*);              	
void	DQ_SCAT2(DQ_BNAME,	_extend	)	(DQ_BTYPE*);              	
int		DQ_SCAT2(DQ_BNAME,	_getidx	)	(DQ_BTYPE*, int		);

/* link renamed dflfc to global fc. static my_t* imy_new(void){return ibase_new();} */
DQ_LINKBASE(dmy)
#endif
