//-*- Mode: C++ -*-
extern "C" {
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "thread.h"
}
#include <stdexcept>
#include <typeinfo> //-- for typeid()
#include <ConcCommon.h>
#include <QueryCompiler.h>
#include <Query.h>
using namespace std;
/*======================================================================
* refcount utilities
*/
inline UV ddcxs_obj_refcnt(ddcObject *obj)
{
return PTR2UV(obj->m_User);
}
inline void ddcxs_obj_refcnt_inc(ddcObject *obj, UV n=1)
{
obj->m_User = INT2PTR(void*, ddcxs_obj_refcnt(obj)+n);
}
inline void ddcxs_obj_refcnt_dec(ddcObject *obj, UV n=1)
{
obj->m_User = INT2PTR(void*, ddcxs_obj_refcnt(obj)-n);
}
//#define REFDEBUG(code) code
#define REFDEBUG(code)
//--------------------------------------------------------------
struct ddcxsRefcntIncVisitor
{
UV n_;
ddcxsRefcntIncVisitor(UV n=1) : n_(n) {};
inline bool operator()(ddcObject *obj) {
if (obj) {
ddcxs_obj_refcnt_inc(obj, n_);
REFDEBUG(fprintf(stderr, "[debug] RefIncVisit[n=%u]:INC(obj=%s=%p) --> refcnt=%lu\n", n_, obj->jsonClass().c_str(), obj, ddcxs_obj_refcnt(obj)));
}
return false;
};
};
//--------------------------------------------------------------
void ddcxs_refcnt_inc(ddcObject *obj, UV n=1)
{
if (obj != NULL) {
ddcxsRefcntIncVisitor visitor(n);
obj->Traverse(visitor);
}
}
//--------------------------------------------------------------
struct ddcxsRefcntDecVisitor {
UV n_;
ddcxsRefcntDecVisitor(UV n=1) : n_(n) {};
inline bool operator()(ddcObject *obj) {
if (!obj) return false;
if (ddcxs_obj_refcnt(obj) <= n_) {
//-- last reference: safely delete the object
REFDEBUG(fprintf(stderr, "[debug] RefDecVisit[n=%u]:DESTROY(obj=%s=%p) --> refcnt=%lu\n", n_, obj->jsonClass().c_str(), obj, ddcxs_obj_refcnt(obj)));
obj->DisownChildren();
delete obj;
} else {
//-- other references exist; just decrement the local reference count
ddcxs_obj_refcnt_dec(obj, n_);
REFDEBUG(fprintf(stderr, "[debug] RefDecVisit[n=%u]:DEC(obj=%s=%p) --> refcnt=%lu\n", n_, obj->jsonClass().c_str(), obj, ddcxs_obj_refcnt(obj)));
}
return false;
};
};
//--------------------------------------------------------------
void ddcxs_refcnt_dec(ddcObject *obj, UV n=1)
{
if (obj != NULL) {
ddcxsRefcntDecVisitor visitor(n);
obj->TraverseR(visitor);
}
}
//--------------------------------------------------------------
void ddcxsDumpObjectTree(ddcObject *obj, const string& prefix="") {
ddcObjectList stack(1,obj);
list<string> prefixes(1,prefix);
while (!stack.empty()) {
ddcObject *optr = stack.front();
string prfx = prefixes.front();
stack.pop_front();
prefixes.pop_front();
fprintf(stderr, "%s+ %s=%p : refcnt=%lu\n", prfx.c_str(), (optr ? optr->jsonClass().c_str() : "n/a"), optr, ddcxs_obj_refcnt(optr));
if (optr != NULL) {
ddcObjectList kids(optr->Children());
prfx += " ";
for (ddcObjectList::reverse_iterator ki = kids.rbegin(); ki != kids.rend(); ++ki) {
prefixes.push_front(prfx);
stack.push_front(*ki);
}
}
}
};
//--------------------------------------------------------------
// macros for object substructure accessors
#define ddcxs_obj_set(VAR,VAL) \
ddcxs_refcnt_inc(VAL, ddcxs_obj_refcnt(THIS)); \
ddcxs_refcnt_dec(THIS->VAR, ddcxs_obj_refcnt(THIS)); \
THIS->VAR = VAL
#define ddcxs_obj_setvec(TYP,VAR,VAL) \
for (TYP::iterator ii=VAL.begin(); ii != VAL.end(); ++ii) ddcxs_refcnt_inc(*ii, ddcxs_obj_refcnt(THIS)); \
for (TYP::iterator ii=THIS->VAR.begin(); ii != THIS->VAR.end(); ++ii) ddcxs_refcnt_dec(*ii, ddcxs_obj_refcnt(THIS)); \
THIS->VAR.swap(VAL)
/*======================================================================
* typemap utilities: typedefs
*/
typedef std::string std_string;
typedef std::set<std::string> set_string;
typedef std::vector<std::string> vector_string;
typedef std::vector<BYTE> vector_BYTE; //-- perl array of integer values in (0..255)
typedef std::vector<BYTE> vector_BYTEasCHAR; //-- perl array of single-character strings as C++ vector<BYTE>
typedef std::vector<char> vector_char; //-- perl array of single-character strings
typedef std::vector<CQToken*> vector_CQTokenPtr;
typedef std::vector<CQCountKeyExpr*> vector_CQCountKeyExprPtr;
/*======================================================================
* typemap utilities: classes
*/
//-- should be UNUSED
inline const char *ddcxs_class(const type_info& info)
{
if (info == typeid(CQueryCompiler)) return "DDC::XS::CQueryCompiler";
else if (info == typeid(CQueryOptions)) return "DDC::XS::CQueryOptions";
//... more special cases here
warn("ddcxs_class(): unknown C++ class '%s'", info.name());
string buf("DDC::XS::");
buf += info.name();
return buf.c_str();
}
/*======================================================================
* typemap utilities: atomic
*/
//--------------------------------------------------------------
// fallback
template<typename T> struct ddcxs_typemap {
inline void perl2c(SV* arg, T& var) {
throw std::runtime_error(Format("ERROR: ddcxs_typemap<%s>::perl2c() not supported", typeid(T).name()));
};
//-- CLASS argument is used for objects
inline void c2perl(T& var, SV*& arg) {
throw std::runtime_error(Format("ERROR: ddcxs_typemap<%s>::c2perl() not supported", typeid(T).name()));
};
};
//--------------------------------------------------------------
template<> struct ddcxs_typemap<char> {
inline void perl2c(SV* arg, char& var) {
if (SvOK(arg))
var = *( SvPV_nolen(arg) );
else
var = '\0';
};
inline void c2perl(char var, SV*& arg) {
sv_setpvn(arg, &var, 1);
};
};
//--------------------------------------------------------------
template<> struct ddcxs_typemap<BYTE> {
inline void perl2c(SV* arg, BYTE& var) {
var = (unsigned char)SvUV(arg);
};
inline void c2perl(BYTE var, SV*& arg) {
sv_setuv(arg, (UV)var);
};
};
//--------------------------------------------------------------
template<> struct ddcxs_typemap<int> {
inline void perl2c(SV* arg, int& var) {
var = SvIV(arg);
};
inline void c2perl(int var, SV*& arg) {
sv_setiv(arg,var);
};
};
//--------------------------------------------------------------
template<> struct ddcxs_typemap<unsigned int> {
inline void perl2c(SV* arg, unsigned int& var) {
var = SvUV(arg);
};
inline void c2perl(unsigned int var, SV*& arg) {
sv_setuv(arg,var);
};
};
//--------------------------------------------------------------
template<> struct ddcxs_typemap<float> {
inline void perl2c(SV* arg, float& var) {
var = SvNV(arg);
};
inline void c2perl(float var, SV*& arg) {
sv_setnv(arg,var);
};
};
//--------------------------------------------------------------
template<> struct ddcxs_typemap<string> {
inline void perl2c(SV* arg, string& var) {
STRLEN clen;
char *cstr = SvPV(arg, clen);
var.assign(cstr, clen);
};
inline void c2perl(const string& var, SV*& arg) {
sv_setpvn(arg, var.data(), var.length());
};
};
//--------------------------------------------------------------
template<typename T> struct ddcxs_typemap<T*> {
inline void perl2c(SV* arg, T*& var) {
if (sv_isobject(arg) && (SvTYPE(SvRV(arg)) == SVt_PVMG))
var = INT2PTR(T*, SvIV((SV*)SvRV( arg )));
else //if (!SvOK(arg))
var = NULL;
};
inline void c2perl(T* var, SV*& arg) {
if (var == NULL)
arg = &PL_sv_undef;
else {
string CLASS("DDC::XS::");
CLASS += var->jsonClass();
sv_setref_pv( arg, CLASS.c_str(), (void*)var );
ddcxs_refcnt_inc((ddcObject*)var);
REFDEBUG(fprintf(stderr, "[debug] c2perl(obj=%s=%p,refcnt=%lu):RETURN; arg.refcnt=%lu\n", ((ddcObject*)var)->jsonClass().c_str(), var, ddcxs_obj_refcnt((ddcObject*)var), SvREFCNT(arg)));
}
};
};
/*======================================================================
* typemap utilities: stl containers
*/
//--------------------------------------------------------------
// stl containers: generic
//------------------------------------------------------
// e.g. ddcxs_container_resize< int, vector<int> >
template<typename T, typename ContainerT >
struct ddcxs_container_resize {
inline void operator()(ContainerT& var, size_t newsize)
{};
};
//------------------------------------------------------
// e.g. ddcxs_container_insert< int, vector<int>, ddcxs_typemap<int> >
// + we specify typemap XT=ddcxs_typemap<T> in addition to T so we can do
// funky things like vector_BYTEasCHAR which treats vector<BYTE> as a vector
// of single-character strings by overriding the default XT=ddcxs_typemap<BYTE>
// with ddcxs_typemap<char>
template<typename T, typename ContainerT, typename XT=ddcxs_typemap<T> >
struct ddcxs_container_insert {
inline void operator()(int i, SV* sv, ContainerT& var, XT& xt)
{
throw std::runtime_error(Format("ERROR: ddcxs_container_insert<%s,%s>.insert(): not supported", typeid(T).name(), typeid(ContainerT).name(), typeid(XT).name()));
};
};
//------------------------------------------------------
template<typename T, typename ContainerT=vector<T>, typename XT=ddcxs_typemap<T> >
struct ddcxs_xtypemap {
//--------------------------------------------
inline void perl2c(SV* arg, ContainerT& var) {
if (SvROK(arg) && (SvTYPE(SvRV(arg)) == SVt_PVAV) ) {
//-- AV
AV *av = (AV*)SvRV( arg );
int _i, _avlen=av_len(av);
XT xt;
ddcxs_container_resize<T,ContainerT>()(var, _avlen+1);
for (_i=0; _i <= _avlen; _i++) {
SV **sv = av_fetch(av,_i,0);
ddcxs_container_insert<T,ContainerT,XT>()(_i, ((sv && *sv) ? *sv : &PL_sv_undef), var, xt);
}
}
else {
var.clear();
}
};
//--------------------------------------------
inline void c2perl(ContainerT& var, SV*& arg) {
AV *av = newAV();
int _i = 0;
XT xt;
av_fill(av, var.size()-1);
for (typename ContainerT::const_iterator si=var.begin(); si != var.end(); ++si, ++_i) {
SV **itemsv = av_fetch(av, _i, 1);
xt.c2perl(*si, *itemsv);
}
sv_2mortal((SV*)av);
arg = newRV((SV*)av);
sv_2mortal(arg);
};
};
//--------------------------------------------------------------
// container: set<T>
//------------------------------------------------------
template<typename T> struct ddcxs_container_insert<T, set<T>, ddcxs_typemap<T> > {
inline void operator()(int i, SV* sv, set<T>& var, ddcxs_typemap<T>& xt)
{
T item;
xt.perl2c(sv,item);
var.insert(item);
};
};
//------------------------------------------------------
template<typename T> struct ddcxs_typemap< set<T> >
{
inline void perl2c(SV* arg, set<T>& var) {
ddcxs_xtypemap< T, set<T> >().perl2c(arg,var);
};
inline void c2perl(set<T>& var, SV*& arg) {
ddcxs_xtypemap< T, set<T> >().c2perl(var,arg);
};
};
//--------------------------------------------------------------
// container: list<T>
//------------------------------------------------------
template<typename T> struct ddcxs_container_insert<T, list<T>, ddcxs_typemap<T> > {
inline void operator()(int i, SV* sv, list<T>& var, ddcxs_typemap<T>& xt)
{
T item;
xt.perl2c(sv,item);
var.push_back(item);
};
};
//------------------------------------------------------
template<typename T> struct ddcxs_typemap< list<T> >
{
inline void perl2c(SV* arg, list<T>& var) {
ddcxs_xtypemap< T, list<T> >().perl2c(arg,var);
};
inline void c2perl(list<T>& var, SV*& arg) {
ddcxs_xtypemap< T, list<T> >().c2perl(var,arg);
};
};
//--------------------------------------------------------------
// container: vector<T>
//------------------------------------------------------
template<typename T> struct ddcxs_container_insert<T, vector<T>, ddcxs_typemap<T> > {
inline void operator()(int i, SV* sv, vector<T>& var, ddcxs_typemap<T>& xt)
{
xt.perl2c(sv, var[i]);
};
};
//------------------------------------------------------
template<typename T>
struct ddcxs_container_resize<T, vector<T> > {
inline void operator()(vector<T>& var, size_t newsize)
{
var.resize(newsize);
};
};
//------------------------------------------------------
template<typename T> struct ddcxs_typemap< vector<T> >
{
inline void perl2c(SV* arg, vector<T>& var) {
ddcxs_xtypemap< T, vector<T> >().perl2c(arg,var);
};
inline void c2perl(vector<T>& var, SV*& arg) {
ddcxs_xtypemap< T, vector<T> >().c2perl(var,arg);
};
};
//--------------------------------------------------------------
// container: vector_BYTEasCHAR
//------------------------------------------------------
template<> struct ddcxs_container_insert<BYTE, vector<BYTE>, ddcxs_typemap<char> > {
inline void operator()(int i, SV* sv, vector<BYTE>& var, ddcxs_typemap<char>& xt)
{
xt.perl2c(sv, reinterpret_cast<char&>(var[i]));
};
};
/*======================================================================
* typemap utilities: high-level wrappers
*/
template<typename T>
inline void ddcxs_perl2c(SV* arg, T& var)
{
ddcxs_typemap<T>().perl2c(arg,var);
}
template<typename T>
inline void ddcxs_c2perl(T& var, SV*& arg)
{
ddcxs_typemap<T>().c2perl(var,arg);
}
bool ddcxs_object_ok(SV *arg, bool nullok=true)
{
return ((sv_isobject(arg) && (SvTYPE(SvRV(arg)) == SVt_PVMG)) || (nullok && !SvOK(arg)));
}
/*======================================================================
* constants
*/
inline const char *build_library_version()
{
return PACKAGE_VERSION;
}
inline const char *library_version()
{
return DDCVersionString();
}