############################################################################### ## ## Typemap for Memcached::libmemcached objects ## ## Copyright (c) 2007 Tim Bunce ## All rights reserved. ## ############################################################################### ## vi:et:sw=4 ts=4 TYPEMAP # --- some basic types not in the perl 5.6 typemap const char * T_PV size_t T_UV # --- simple types --- memcached_behavior T_IV memcached_callback T_IV memcached_return T_RETURN # --- generic simple types --- # general uint16_t uint16_t T_UV # XXX need to at least document this as an issue # Could also check at build time if this perl has 64bit ints and use UV if so uint64_t T_NV # --- perl api private abstraction typedefs --- lmc_key T_KEY lmc_value T_VALUE lmc_expiration T_EXPIRATION lmc_data_flags_t T_FLAGS # --- complex types (incl. objects, typedef name encodes class name) --- # XXX memory management may be reworked to store structure in scalars Memcached__libmemcached T_MEMCACHED INPUT T_HVREF if (!SvROK($arg) || !SvTYPE(SvRV($arg))==SVt_PVHV) Perl_croak(aTHX_ \"$var is not a hash reference\"); $var = (HV*)SvRV($arg); INPUT T_RETURN /* T_RETURN */ $var = (SvOK($arg)) ? ($type)SvIV($arg) : 0; OUTPUT T_RETURN:init /* T_RETURN:init */ LMC_RECORD_RETURN_ERR(\"${func_name}\", ptr, $var); T_RETURN /* T_RETURN */ if (!SvREADONLY($arg)) { if (LMC_RETURN_OK($var)) { sv_setsv($arg, &PL_sv_yes); } else if ($var == MEMCACHED_NOTFOUND) { sv_setsv($arg, &PL_sv_no); } else { SvOK_off($arg); } } INPUT T_PV /* treat undef as null pointer (output does the inverse) */ $var = (SvOK($arg)) ? ($type)SvPV_nolen($arg) : NULL; INPUT T_KEY /* T_KEY */ $var = ($type)SvPV($arg, $length_var); OUTPUT T_KEY /* T_KEY */ /* assumes the existance of a key_length variable holding the length */ if (!SvREADONLY($arg)) sv_setpvn((SV*)$arg, $var, key_length); INPUT T_VALUE /* T_VALUE - main code in T_VALUE:pre_call below (so it can access/modify flags) */ /* mention $length_var here to keep ParseXS happy for now */ T_VALUE:pre_call /* T_VALUE:pre_call */ if (SvOK(LMC_STATE_FROM_PTR(ptr)->cb_context->set_cb)) { /* XXX ignoring flags till we have a better mechanism */ SV *key_sv, *value_sv, *flags_sv; /* these SVs may get cached inside lmc_cb_context_st and reused across calls */ /* which would save the create,mortalize,destroy costs for each invocation */ key_sv = sv_2mortal(newSVpv(key, STRLEN_length_of_key)); value_sv = sv_mortalcopy($arg); /* original SV, as it may be a ref */ flags_sv = sv_2mortal(newSVuv(flags)); SvREADONLY_on(key_sv); /* just to be sure for now, may allow later */ _cb_fire_perl_set_cb(ptr, key_sv, value_sv, flags_sv); /* recover possibly modified values (except key) */ $var = SvPV(value_sv, $length_var); flags = SvUV(flags_sv); } else { $var = ($type)SvPV($arg, $length_var); } OUTPUT T_VALUE /* T_VALUE */ /* assumes the existance of a value_length variable holding the length */ if (!SvREADONLY($arg)) sv_setpvn((SV*)$arg, $var, value_length); INPUT T_FLAGS /* T_FLAGS */ $var = (SvOK($arg)) ? ($type)SvUV($arg) : 0; OUTPUT T_FLAGS /* T_FLAGS */ if (!SvREADONLY($arg)) sv_setuv($arg, (UV)$var); INPUT T_EXPIRATION /* T_EXPIRATION */ /* XXX add logic for default expiration */ $var = ($type)SvUV($arg) OUTPUT T_MEMCACHED /* T_MEMCACHED */ if (!$var) /* if null */ SvOK_off($arg); /* then return as undef instead of reaf to undef */ else { /* setup $arg as a ref to a blessed hash hv */ lmc_state_st *lmc_state; HV *hv = newHV(); char *classname = \"${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\"; /* take (sub)class name to use from class_sv if appropriate */ if (class_sv && SvOK(class_sv) && sv_derived_from(class_sv, classname)) classname = (SvROK(class_sv)) ? sv_reftype(class_sv, 0) : SvPV_nolen(class_sv); sv_setsv($arg, sv_2mortal(newRV_noinc((SV*)hv))); (void)sv_bless($arg, gv_stashpv(classname, TRUE)); /* allocate an lmc_state struct and attach via MEMCACHED_CALLBACK_USER_DATA */ lmc_state = lmc_state_new($var, hv); memcached_callback_set($var, MEMCACHED_CALLBACK_USER_DATA, lmc_state); /* now attach $var to the HV */ /* done as two steps to avoid sv_magic SvREFCNT_inc and MGf_REFCOUNTED */ sv_magic((SV*)hv, NULL, '~', NULL, 0); LMC_STATE_FROM_SV($arg) = (void*)lmc_state; } if (LMC_TRACE_LEVEL_FROM_PTR($var) >= 2) warn(\"\t<= %s(%s %s = %p)\", \"${func_name}\", \"${ntype}\", \"${var}\", (void*)$var); INPUT T_MEMCACHED /* T_MEMCACHED */ if (!SvOK($arg)) { /* undef */ $var = NULL; /* treat as null */ } else if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\")) { if (SvROK($arg)) { $var = (memcached_st*)LMC_PTR_FROM_SV($arg); } else { /* memcached_st ptr already freed or is a class name */ $var = NULL; } } else croak(\"$var is not of type ${(my $ntt=$ntype)=~s/__/::/g;\$ntt}\"); if (LMC_TRACE_LEVEL_FROM_PTR($var) >= 2) warn(\"\t=> %s(%s %s = 0x%p)\", \"${func_name}\", \"${ntype}\", \"${var}\", (void*)$var);