Data-Util

 view release on metacpan or  search on metacpan

lib/Data/Util.xs  view on Meta::CPAN

			my_croak(aTHX_ "Odd number of arguments for %s", GvNAME(CvGV(cv)));
		}

		for(i = 1; i < items; i += 2){
			SV* const as           = my_string(aTHX_ ST(i), "a subroutine name");
			STRLEN namelen;
			const char* const name = SvPV_const(as, namelen);
			SV* const code_ref     = ST(i+1);

			my_install_sub(aTHX_ stash, name, namelen, code_ref);
		}
	}

void
uninstall_subroutine(package, ...)
	SV* package
PREINIT:
	HV* stash;
	int i;
CODE:
	stash = gv_stashsv(my_string(aTHX_ package, "a package name"), FALSE);
	if(!stash) XSRETURN_EMPTY;

	if(items == 2 && SvROK(ST(1))){
		HV* const hv = deref_hv(ST(1));
		I32   namelen;
		char* name;
		SV* specified_code_ref;

		hv_iterinit(hv);
		while((specified_code_ref = hv_iternextsv(hv, &name, &namelen))){
			my_uninstall_sub(aTHX_ stash, name, namelen, specified_code_ref);
		}
	}
	else{
		for(i = 1; i < items; i++){
			SV* const namesv = my_string(aTHX_ ST(i), "a subroutine name");
			STRLEN namelen;
			const char* const name = SvPV_const(namesv, namelen);
			SV* specified_code_ref;

			if( (i+1) < items && SvROK(ST(i+1)) ){
				i++;
				specified_code_ref = ST(i);
			}
			else{
				specified_code_ref = &PL_sv_undef;
			}

			my_uninstall_sub(aTHX_ stash, name, namelen, specified_code_ref);
		}
	}
	mro_method_changed_in(stash);

void
get_code_info(code)
	CV* code
PREINIT:
	GV* gv;
	HV* stash;
PPCODE:
	if( (gv = CvGV(code)) && isGV_with_GP(gv)
		&& (stash = (GvSTASH(gv))) && HvNAME_get(stash) ){

		if(GIMME_V == G_ARRAY){
			EXTEND(SP, 2);
			mPUSHs(newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U));
			mPUSHs(newSVpvn_share(GvNAME(gv), GvNAMELEN(gv), 0U));
		}
		else{
			SV* const sv = newSVpvf("%s::%s", HvNAME_get(stash), GvNAME(gv));
			mXPUSHs(sv);
		}
	}


SV*
get_code_ref(package, name, ...)
	SV* package
	SV* name
INIT:
	I32 flags = 0;
	RETVAL = &PL_sv_undef;
CODE:
	(void)my_string(aTHX_ package, "a package name");
	(void)my_string(aTHX_ name,    "a subroutine name");

	if(items > 2){ /* with flags */
		I32 i;
		for(i = 2; i < items; i++){
			SV* const sv = my_string(aTHX_ ST(i), "a flag");
			if(strEQ(SvPV_nolen_const(sv), "-create")){
				flags |= GV_ADD;
			}
			else{
				my_fail(aTHX_ "a flag", sv);
			}
		}
	}

	{
		HV* const stash = gv_stashsv(package, flags);

		if(stash){
			STRLEN len;
			const char* const pv = SvPV_const(name, len);
			GV** const gvp = (GV**)hv_fetch(stash, pv, len, flags);
			GV*  const gv  = gvp ? *gvp : NULL;

			if(gv){
				if(!isGV(gv)) gv_init(gv, stash, pv, len, GV_ADDMULTI);

				if(GvCVu(gv)){
					RETVAL = newRV_inc((SV*)GvCV(gv));
				}
				else if(flags & GV_ADD){
					SV* const sv = Perl_newSVpvf(aTHX_ "%"SVf"::%"SVf, package, name);

					/* from Perl_get_cvn_flags() in perl.c */
					CV* const cv = newSUB(
						start_subparse(FALSE, 0),

lib/Data/Util.xs  view on Meta::CPAN

		const char* const modifier_type = SvPV_nolen_const(mtsv);
		AV*         const          subs = deref_av(ST(i+1));
		I32         const      subs_len = av_len(subs) + 1;
		AV* av = NULL;
		I32 j;

		if(strEQ(modifier_type, "before")){
			av = before;
		}
		else if(strEQ(modifier_type, "around")){
			av = around;
		}
		else if(strEQ(modifier_type, "after")){
			av = after;
		}
		else{
			my_fail(aTHX_ "a modifier type", mtsv);
		}

		av_extend(av, AvFILLp(av) + subs_len - 1);
		for(j = 0; j < subs_len; j++){
			SV* const code_ref = newSVsv(validate(*av_fetch(subs, j, TRUE), T_CV));

			av_push(av, code_ref);
		}
	}

	modifiers = newAV();
	av_extend(modifiers, 3);

	av_store(modifiers, M_CURRENT,  my_build_around_code(aTHX_ code, around));

	av_store(modifiers, M_BEFORE, SvREFCNT_inc_simple_NN(before));
	av_store(modifiers, M_AROUND, SvREFCNT_inc_simple_NN(around));
	av_store(modifiers, M_AFTER,  SvREFCNT_inc_simple_NN(after));

	modified = newXS(NULL /* anonymous */, XS_Data__Util_modified, __FILE__);

	mg = sv_magicext((SV*)modified, (SV*)modifiers, PERL_MAGIC_ext, &modified_vtbl, NULL, 0);
	SvREFCNT_dec((SV*)modifiers); /* refcnt++ in sv_magicext() */
	CvXSUBANY(modified).any_ptr = (void*)mg;

	RETVAL = newRV_noinc((SV*)modified);
OUTPUT:
	RETVAL


void
subroutine_modifier(code, ...)
	CV* code
PREINIT:
	/* Usage:
		subroutine_modifier(code)                 # check
		subroutine_modifier(code, property)       # get
		subroutine_modifier(code, property, subs) # set
	*/
	MAGIC* mg;
	AV* modifiers; /* (before, around, after, original, current) */
	SV* property;
	const char* property_pv;
PPCODE:
	mg = mg_find_by_vtbl((SV*)code, &modified_vtbl);

	if(items == 1){ /* check only */
		ST(0) = boolSV(mg);
		XSRETURN(1);
	}

	if(!mg){
		my_fail(aTHX_ "a modified subroutine", ST(0) /* ref to code */);
	}

	modifiers = (AV*)mg->mg_obj;
	assert(modifiers);

	property = my_string(aTHX_ ST(1), "a modifier property");
	property_pv = SvPV_nolen_const(property);

	if(strEQ(property_pv, "before") || strEQ(property_pv, "around") || strEQ(property_pv, "after")){
		I32 const idx =
			  strEQ(property_pv, "before") ? M_BEFORE
			: strEQ(property_pv, "around") ? M_AROUND
			:                                M_AFTER;
		AV* const av = (AV*)*av_fetch(modifiers, idx, FALSE);
		if(items != 2){ /* add */
			I32 i;
			for(i = 2; i < items; i++){
				SV* const code_ref = newSVsv(validate(ST(i), T_CV));
				if(idx == M_AFTER){
					av_push(av, code_ref);
				}
				else{
					av_unshift(av, 1);
					av_store(av, 0, code_ref);
				}
			}

			if(idx == M_AROUND){
				AV* const around = (AV*)sv_2mortal((SV*)av_make(items-2, &ST(2)));
				SV* const current = my_build_around_code(aTHX_
						*av_fetch(modifiers, M_CURRENT, FALSE),
						around
					);
				av_store(modifiers, M_CURRENT, current);
			}
		}
		XPUSHary(AvARRAY(av), 0, AvFILLp(av)+1);
	}
	else{
		my_fail(aTHX_ "a modifier property", property);
	}



#define mkopt(opt_list, moniker, require_unique, must_be) \
		my_mkopt(aTHX_ opt_list, moniker, require_unique, must_be, T_AV)
#define mkopt_hash(opt_list, moniker, must_be) \
		my_mkopt(aTHX_ opt_list, moniker, TRUE, must_be, T_HV)


SV*



( run in 1.734 second using v1.01-cache-2.11-cpan-71847e10f99 )