XS_this and the argument stack.

Matt Newell <[email protected]> Mon, 10 Jan 2005 13:42:37 -0800
Newsgroups gmane.comp.kde.devel.perl
Message-ID <[email protected]>
Hello

I've recently been integrating my homegrown database class library(built on 
top of QSqlDatabase etc.) into a hacked up version of perlqt 3.008.  I've 
already gotten it working well, but now I'm in the process of converting a 
lot of existing perl code to use it, and I'm really finding that I don't like 
the fact that the this object is taken off of the arguement stack.  I was 
just wondering if there is a reason why this is required, or if it was simply 
done as convenience.  I'm pretty sure that I can remove it, but I just wanted 
to check and make sure that it wasn't going to bite me in the ass.

BTW, I've modified my version with full marshalling support for QVariant, and 
QValueList<QVariant>.  So far the marshaller supports Int, UInt, 
LongLong->Int, ULongLong->UInt, Date -> Qt::Date, DateTime ->Qt::DateTime, 
Time -> Qt::Time, and String.  I think that this would be a valueable 
contribution to perlqt, so I've attached the code.

Matt

_______________________________________________
Kde-perl mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/kde-perl
temp.cpp (text/x-c++src, 8.1 KB)
void marshall_QValueListQVariant( Marshall * m )
{
	Smoke * smoke = m->smoke();
	int dateId = smoke->idClass( "QDate" );
	int dateTimeId = smoke->idClass( "QDateTime" );
	int timeId = smoke->idClass( "QTime" );
	
	switch( m->action() ) {
		case Marshall::FromSV:
		{
			SV *sv = m->var();
			if(!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV || av_len((AV*)SvRV(sv)) < 0) {
				m->item().s_voidp = 0;
				break;
			}
			
			QValueList<QVariant> *varlist = new QValueList<QVariant>;
			m->item().s_voidp = (void*)varlist;
			
			AV *list = (AV*)SvRV(sv);
			int count = av_len(list);
			int i;
			for(i = 0; i <= count; i++) {
				SV **item = av_fetch(list, i, 0);
				if(!item || !SvOK(*item)) {
					varlist->append( QVariant( QString::null ) );
					continue;
				}
				SV * svitem = *item;
				smokeperl_object * o = 0;
				if( SvIOK(svitem) ) {
					if( SvUOK(svitem) )
						varlist->append( QVariant( (uint)SvUV(svitem) ) );
					else
						varlist->append( QVariant( (int)SvIV(svitem) ) );
				} else if( SvPOK(svitem) ) {
					COP *cop = cxstack[cxstack_ix].blk_oldcop;
					bool lc = cop->op_private & HINT_LOCALE;
					if(SvUTF8(svitem))
						varlist->append( QVariant( QString::fromUtf8(SvPV_nolen(svitem)) ) );
					else if(lc)
						varlist->append(QVariant(QString::fromLocal8Bit(SvPV_nolen(svitem))) ); 
					else
						varlist->append(QVariant(QString::fromLatin1(SvPV_nolen(svitem))));
				} else if( o=sv_obj_info(svitem) ) {
					if(!o->ptr) {
						varlist->append( QVariant( QString::null ) );
					} else {
						void *ptr = o->ptr;
						if( o->classId == timeId )
							varlist->append( QVariant( *((QTime*)ptr) ) );
						else if( o->classId == dateTimeId )
							varlist->append( QVariant( *((QDateTime*)ptr) ) );
						else if( o->classId = dateId )
							varlist->append( QVariant( *((QDate*)ptr) ) );
						else
							varlist->append( QVariant( QString::null ) );
					}
				}
			}
			
			m->next();
			if( m->cleanup() ) {
				delete varlist;
			}
			break;
		}
		case Marshall::ToSV:
		{
			QValueList<QVariant> *vvlist = (QValueList<QVariant>*)m->item().s_voidp;
			if(!vvlist) {
				sv_setsv_mg(m->var(), &PL_sv_undef);
				break;
			}
	
			AV * av = newAV();
			{
				SV * rv = newRV_noinc((SV*)av);
				sv_setsv_mg(m->var(), rv);
				SvREFCNT_dec(rv);
			}
			
			for( QValueListIterator<QVariant> it = vvlist->begin(); it != vvlist->end(); ++it )
			{
				// No need for getPointerObject, because we just created this pointer
				QVariant & v = *it;
				
				int id = 0;
				void * voidp=0;
				char * cn=0;
				switch( v.type() ) {
					case QVariant::LongLong:
					case QVariant::Int:
						{
							SV * sv = newSViv( v.toInt() );
							av_push( av, sv );
						}
						break;
					case QVariant::ULongLong:
					case QVariant::UInt:
						{
							SV * sv = newSVuv( v.toUInt() );
							av_push( av, sv );
						}
						break;
					case QVariant::Double:
						{
							SV * sv = newSVnv( v.toDouble() );
							av_push( av, sv );
						}
						break;
					case QVariant::String:
						{
							COP *cop = cxstack[cxstack_ix].blk_oldcop;
							if(!(cop->op_private & HINT_BYTES)) {
								SV *sv = newSVpv((const char *)v.toString().utf8(), 0);
								SvUTF8_on(sv);
								av_push(av, sv);
							}
							else if(cop->op_private & HINT_LOCALE) {
								SV *sv = newSVpv((const char *)v.toString().local8Bit(), 0);
								av_push(av, sv);
							}
							else {
								SV *sv = newSVpv((const char *)v.toString().latin1(), 0);
								av_push(av, sv);
							}
						}
						break;
					case QVariant::Date:
						voidp = (void*)(new QDate( v.toDate() ));
						id = dateId;
						cn = "Qt::Date";
						break;
					case QVariant::DateTime:
						voidp = (void*)(new QDateTime( v.toDateTime() ));
						id = dateTimeId;
						cn = "Qt::DateTime";
						break;
					case QVariant::Time:
						voidp = (void*)(new QTime( v.toTime() ));
						id = timeId;
						cn = "Qt::Time";
						break;
					default:
						warn( "Couldn't marshall QVariant type %s", v.typeName() );
						break;
				}
				
				if( voidp ) {
					SV *ret= newSV(0);
					HV *hv = newHV();
					SV *obj = newRV_noinc((SV*)hv);
					smokeperl_object o;
					o.smoke = smoke;
					o.classId = id;
					o.ptr = voidp;
					o.allocated = true;
					sv_bless(obj, gv_stashpv( cn, TRUE) );
					sv_magic((SV*)hv, sv_qapp, '~', (char*)&o, sizeof(o));
					MAGIC *mg = mg_find((SV*)hv, '~');
					mg->mg_virtual = &vtbl_smoke;
					sv_setsv_mg(ret, obj);
					av_push(av,ret);
					SvREFCNT_dec(obj);
				}
			}
			if( m->cleanup() )
				delete vvlist;
			break;
		}
		default:
			break;
    }
}

void marshall_QVariant(Marshall * m)
{
	Smoke * smoke = m->smoke();
	int dateId = smoke->idClass( "QDate" );
	int dateTimeId = smoke->idClass( "QDateTime" );
	int timeId = smoke->idClass( "QTime" );
	switch( m->action() ) {
		case Marshall::FromSV:
		{
			SV *sv = m->var();
			if( !SvOK(sv) ) {
				m->item().s_voidp = 0;
				break;
			}
			
			smokeperl_object * o = 0;
			if( SvIOK(sv) ) {
				if( SvUOK(sv) )
					m->item().s_voidp = new QVariant( (uint)SvUV(sv) );
				else
					m->item().s_voidp = new QVariant( (int)SvIV(sv) );
			} else if( SvNOK(sv) ) {
				m->item().s_voidp = new QVariant( (double)SvNV(sv) );
			} else if( SvPOK(sv) ) {
				COP *cop = cxstack[cxstack_ix].blk_oldcop;
				bool lc = cop->op_private & HINT_LOCALE;
				if(SvUTF8(sv))
					m->item().s_voidp = new QVariant( QString::fromUtf8(SvPV_nolen(sv)) );
				else if(lc)
					m->item().s_voidp = new QVariant( QString::fromLocal8Bit(SvPV_nolen(sv)) ); 
				else
					m->item().s_voidp = new QVariant( QString::fromLatin1(SvPV_nolen(sv)) );
			} else if( o = sv_obj_info(sv) ) {
				if(!o->ptr) {
					m->item().s_voidp = 0;
				} else {
					void *ptr = o->ptr;
					if( o->classId == timeId )
						m->item().s_voidp = new QVariant( *((QTime*)ptr) );
					else if( o->classId == dateTimeId )
						m->item().s_voidp = new QVariant( *((QDateTime*)ptr) );
					else if( o->classId = dateId )
						m->item().s_voidp = new QVariant( *((QDate*)ptr) );
					else
						m->item().s_voidp = 0;
				}
			}
			m->next();
			if( m->cleanup() && m->item().s_voidp ) {
				delete (QVariant*)m->item().s_voidp;
			}
			break;
		}
		case Marshall::ToSV:
		{
			QVariant *var = (QVariant*)m->item().s_voidp;
			if(!var) {
				warn( "QVariant Pointer is null" );
				sv_setsv_mg(m->var(), &PL_sv_undef);
				break;
			}
	
			int id = 0;
			void * voidp=0;
			char * cn=0;
			//warn( var->typeName() );
			switch( var->type() ) {
				case QVariant::Int:
				case QVariant::LongLong:
					sv_setiv_mg(m->var(), (IV)var->toInt() );
					break;
				case QVariant::UInt:
				case QVariant::ULongLong:
					sv_setuv_mg(m->var(), (UV)var->toUInt() );
					break;
				case QVariant::Double:
					sv_setnv_mg(m->var(), (NV)var->toDouble() );
					break;
				case QVariant::String:
					{
						COP *cop = cxstack[cxstack_ix].blk_oldcop;
						if(!(cop->op_private & HINT_BYTES)) {
							sv_setpv_mg(m->var(), (const char *)var->toString().utf8());
							SvUTF8_on(m->var());
						}
						else if(cop->op_private & HINT_LOCALE) {
							sv_setpv_mg(m->var(), (const char *)var->toString().local8Bit());
						}
						else {
							sv_setpv_mg(m->var(), (const char *)var->toString().latin1());
						}
					}
					break;
				case QVariant::Date:
					voidp = (void*)(new QDate( var->toDate() ));
					id = dateId;
					cn = " Qt::Date";
					break;
				case QVariant::DateTime:
					voidp = (void*)(new QDateTime( var->toDateTime() ));
					id = dateTimeId;
					cn = " Qt::DateTime";
					break;
				case QVariant::Time:
					voidp = (void*)(new QTime( var->toTime() ));
					id = timeId;
					cn = " Qt::Time";
					break;
				default:
					warn( "Couldn't marshall QVariant type %s", var->typeName() );
					break;
			}
				
			if( voidp ) {
				HV *hv = newHV();
				SV *obj = newRV_noinc((SV*)hv);
				smokeperl_object o;
				o.smoke = smoke;
				o.classId = id;
				o.ptr = voidp;
				o.allocated = true;
				sv_bless(obj, gv_stashpv( cn, TRUE) );
				sv_magic((SV*)hv, sv_qapp, '~', (char*)&o, sizeof(o));
				MAGIC *mg = mg_find((SV*)hv, '~');
				mg->mg_virtual = &vtbl_smoke;
				sv_setsv_mg(m->var(), obj);
				SvREFCNT_dec(obj);
			}
			if( m->cleanup() )
				delete var;
			break;
		}
		default:
			break;
    }
}