# all these attribute readers will be bootstrapped
# away in the Class::MOP bootstrap section
- sub get_attribute_map { $_[0]->{'attributes'} }
- sub attribute_metaclass { $_[0]->{'attribute_metaclass'} }
- sub instance_metaclass { $_[0]->{'instance_metaclass'} }
- sub immutable_trait { $_[0]->{'immutable_trait'} }
- sub constructor_class { $_[0]->{'constructor_class'} }
- sub constructor_name { $_[0]->{'constructor_name'} }
- sub destructor_class { $_[0]->{'destructor_class'} }
+ #sub get_attribute_map { $_[0]->{'attributes'} }
+ #sub attribute_metaclass { $_[0]->{'attribute_metaclass'} }
-#sub method_metaclass { $_[0]->{'method_metaclass'} }
-#sub wrapped_method_metaclass { $_[0]->{'wrapped_method_metaclass'} }
+ #sub instance_metaclass { $_[0]->{'instance_metaclass'} }
+ #sub immutable_trait { $_[0]->{'immutable_trait'} }
+ #sub constructor_class { $_[0]->{'constructor_class'} }
+ #sub constructor_name { $_[0]->{'constructor_name'} }
+ #sub destructor_class { $_[0]->{'destructor_class'} }
# Instance Construction & Cloning
## accessors
- sub associated_attribute { (shift)->{'attribute'} }
- sub accessor_type { (shift)->{'accessor_type'} }
+ #sub associated_attribute { (shift)->{'attribute'} }
+ #sub accessor_type { (shift)->{'accessor_type'} }
+
+
-sub can_xs {
++sub _can_xs {
+ my($self, $method_name) = @_;
+ # don't use $method_name here, but there may be cases it is required.
+
+ # FIXME: I didn't know how to detect it properly (gfx)
+ return ref($self) eq __PACKAGE__
- && $self->associated_attribute->associated_class->instance_metaclass eq 'Class::MOP::Instance';
++ && $self->associated_metaclass->instance_metaclass eq 'Class::MOP::Instance';
+ }
-sub attribute_name{ (shift)->associated_attribute->name }
-
## factory
sub initialize_body {
my $method_name = join "_" => (
'_generate',
$self->accessor_type,
- 'method',
- ($self->is_inline ? 'inline' : ())
+ 'method'
);
+ if($self->is_inline){
- $method_name .= $self->can_xs($method_name) ? '_xs' : '_inline';
++ $method_name .= $self->_can_xs($method_name) ? '_xs' : '_inline';
+ }
+
$self->{'body'} = $self->$method_name();
}
extern SV *mop_method_metaclass;
extern SV *mop_associated_metaclass;
++extern SV *mop_associated_attribute;
extern SV *mop_wrap;
+ extern SV *mop_methods;
+ extern SV *mop_name;
+ extern SV *mop_body;
+ extern SV *mop_package;
+ extern SV *mop_package_name;
+ extern SV *mop_package_cache_flag;
+ extern SV *mop_VERSION;
+ extern SV *mop_ISA;
UV mop_check_package_cache_flag(pTHX_ HV *stash);
int mop_get_code_info (SV *coderef, char **pkg, char **name);
--- /dev/null
+ #include "mop.h"
+
-static void
-mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map)
-{
- const char *const class_name_pv = HvNAME(stash); /* must be HvNAME(stash), not SvPV_nolen_const(class_name) */
- SV *method_metaclass_name;
- char *method_name;
- I32 method_name_len;
- SV *coderef;
- HV *symbols;
- dSP;
-
- symbols = mop_get_all_package_symbols(stash, TYPE_FILTER_CODE);
- sv_2mortal((SV*)symbols);
- (void)hv_iterinit(symbols);
- while ( (coderef = hv_iternextsv(symbols, &method_name, &method_name_len)) ) {
- CV *cv = (CV *)SvRV(coderef);
- char *cvpkg_name;
- char *cv_name;
- SV *method_slot;
- SV *method_object;
-
- if (!mop_get_code_info(coderef, &cvpkg_name, &cv_name)) {
- continue;
- }
-
- /* this checks to see that the subroutine is actually from our package */
- if ( !(strEQ(cvpkg_name, "constant") && strEQ(cv_name, "__ANON__")) ) {
- if ( strNE(cvpkg_name, class_name_pv) ) {
- continue;
- }
- }
-
- method_slot = *hv_fetch(map, method_name, method_name_len, TRUE);
- if ( SvOK(method_slot) ) {
- SV *const body = mop_call0(aTHX_ method_slot, mop_body); /* $method_object->body() */
- if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) {
- continue;
- }
- }
-
- method_metaclass_name = mop_call0(aTHX_ self, mop_method_metaclass); /* $self->method_metaclass() */
-
- /*
- $method_object = $method_metaclass->wrap(
- $cv,
- associated_metaclass => $self,
- package_name => $class_name,
- name => $method_name
- );
- */
- ENTER;
- SAVETMPS;
-
- PUSHMARK(SP);
- EXTEND(SP, 8);
- PUSHs(method_metaclass_name); /* invocant */
- mPUSHs(newRV_inc((SV *)cv));
- PUSHs(mop_associated_metaclass);
- PUSHs(self);
- PUSHs(mop_package_name);
- PUSHs(class_name);
- PUSHs(mop_name);
- mPUSHs(newSVpv(method_name, method_name_len));
- PUTBACK;
-
- call_sv(mop_wrap, G_SCALAR | G_METHOD);
- SPAGAIN;
- method_object = POPs;
- PUTBACK;
- /* $map->{$method_name} = $method_object */
- sv_setsv(method_slot, method_object);
-
- FREETMPS;
- LEAVE;
- }
-}
+
+ MODULE = Class::MOP::Class PACKAGE = Class::MOP::Class
+
++PROTOTYPES: DISABLE
++
+ BOOT:
+ INSTALL_SIMPLE_READER_WITH_KEY(Class, get_attribute_map, attributes);
- /* INSTALL_SIMPLE_READER_WITH_KEY(Class, _method_map, methods); */
+ INSTALL_SIMPLE_READER(Class, attribute_metaclass);
- INSTALL_SIMPLE_READER(Class, method_metaclass);
- INSTALL_SIMPLE_READER(Class, wrapped_method_metaclass);
+ INSTALL_SIMPLE_READER(Class, instance_metaclass);
+ INSTALL_SIMPLE_READER(Class, immutable_trait);
+ INSTALL_SIMPLE_READER(Class, constructor_name);
+ INSTALL_SIMPLE_READER(Class, constructor_class);
+ INSTALL_SIMPLE_READER(Class, destructor_class);
-
-
-PROTOTYPES: DISABLE
-
-void
-get_method_map(self)
- SV *self
- PREINIT:
- HV *const obj = (HV *)SvRV(self);
- SV *const class_name = HeVAL( hv_fetch_ent(obj, mop_package, 0, 0U) );
- HV *const stash = gv_stashsv(class_name, 0);
- UV current;
- SV *cache_flag;
- SV *map_ref;
- PPCODE:
- if (!stash) {
- mXPUSHs(newRV_noinc((SV *)newHV()));
- return;
- }
-
- current = mop_check_package_cache_flag(aTHX_ stash);
- cache_flag = HeVAL( hv_fetch_ent(obj, mop_package_cache_flag, TRUE, 0U));
- map_ref = HeVAL( hv_fetch_ent(obj, mop_methods, TRUE, 0U));
-
- /* $self->{methods} does not yet exist (or got deleted) */
- if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) {
- SV *new_map_ref = newRV_noinc((SV *)newHV());
- sv_2mortal(new_map_ref);
- sv_setsv(map_ref, new_map_ref);
- }
-
- if ( !SvOK(cache_flag) || SvUV(cache_flag) != current ) {
- mop_update_method_map(aTHX_ self, class_name, stash, (HV *)SvRV(map_ref));
- sv_setuv(cache_flag, mop_check_package_cache_flag(aTHX_ stash)); /* update_cache_flag() */
- }
-
- XPUSHs(map_ref);
SV *mop_method_metaclass;
SV *mop_associated_metaclass;
++SV *mop_associated_attribute;
SV *mop_wrap;
+ SV *mop_methods;
+ SV *mop_name;
+ SV *mop_body;
+ SV *mop_package;
+ SV *mop_package_name;
+ SV *mop_package_cache_flag;
+
+ SV *mop_VERSION;
+ SV *mop_ISA;
static bool
find_method (const char *key, STRLEN keylen, SV *val, void *ud)
PROTOTYPES: DISABLE
BOOT:
- mop_prehash_keys();
-
- mop_method_metaclass = newSVpvs("method_metaclass");
- mop_wrap = newSVpvs("wrap");
- mop_associated_metaclass = newSVpvs("associated_metaclass");
+ mop_method_metaclass = MAKE_KEYSV(method_metaclass);
+ mop_wrap = MAKE_KEYSV(wrap);
+ mop_associated_metaclass = MAKE_KEYSV(associated_metaclass);
++ mop_associated_attribute = MAKE_KEYSV(associated_attribute);
+ mop_methods = MAKE_KEYSV(methods);
+ mop_name = MAKE_KEYSV(name);
+ mop_body = MAKE_KEYSV(body);
+ mop_package = MAKE_KEYSV(package);
+ mop_package_name = MAKE_KEYSV(package_name);
+ mop_package_cache_flag = MAKE_KEYSV(_package_cache_flag);
+ mop_VERSION = MAKE_KEYSV(VERSION);
+ mop_ISA = MAKE_KEYSV(ISA);
MOP_CALL_BOOT (boot_Class__MOP__Package);
+ MOP_CALL_BOOT (boot_Class__MOP__Class);
MOP_CALL_BOOT (boot_Class__MOP__Attribute);
MOP_CALL_BOOT (boot_Class__MOP__Method);
+ MOP_CALL_BOOT (boot_Class__MOP__Instance);
+ MOP_CALL_BOOT (boot_Class__MOP__Method__Accessor);
# use prototype here to be compatible with get_code_info from Sub::Identify
void
--- /dev/null
+ #include "mop.h"
+
+ static CV*
-mop_instantiate_xs_accessor(pTHX_ SV* const meta_attr, XSPROTO(accessor_impl)){
- SV* const key = mop_call0(aTHX_ meta_attr, sv_2mortal(newSVpvs("attribute_name")));
++mop_instantiate_xs_accessor(pTHX_ SV* const accessor, XSPROTO(accessor_impl)){
++ /* $key = $accessor->associated_attribute->name */
++ SV* const attr = mop_call0(aTHX_ accessor, mop_associated_attribute);
++ SV* const key = mop_call0(aTHX_ attr, mop_name);
+ STRLEN len;
+ const char* const pv = SvPV_const(key, len);
+ return mop_install_simple_accessor(aTHX_ NULL /* anonymous */, pv, len, accessor_impl);
+ }
+
+ MODULE = Class::MOP::Method::Accessor PACKAGE = Class::MOP::Method::Accessor
+
+ PROTOTYPES: DISABLE
+
+ BOOT:
+ INSTALL_SIMPLE_READER_WITH_KEY(Method::Accessor, associated_attribute, attribute);
+ INSTALL_SIMPLE_READER(Method::Accessor, accessor_type);
+
+
+ CV*
+ _generate_accessor_method_xs(SV* self)
+ CODE:
+ RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_accessor);
+ OUTPUT:
+ RETVAL
+
+ CV*
+ _generate_reader_method_xs(SV* self)
+ CODE:
+ RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_reader);
+ OUTPUT:
+ RETVAL
+
+ CV*
+ _generate_writer_method_xs(SV* self)
+ CODE:
+ RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_writer);
+ OUTPUT:
+ RETVAL
+
+ CV*
+ _generate_predicate_method_xs(SV* self)
+ CODE:
+ RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_predicate);
+ OUTPUT:
+ RETVAL
+
+ CV*
+ _generate_clearer_method_xs(SV* self)
+ CODE:
+ RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_clearer);
+ OUTPUT:
+ RETVAL
+
#include "mop.h"
+static void
+mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map)
+{
+ const char *const class_name_pv = HvNAME(stash); /* must be HvNAME(stash), not SvPV_nolen_const(class_name) */
+ SV *method_metaclass_name;
+ char *method_name;
+ I32 method_name_len;
+ SV *coderef;
+ HV *symbols;
+ dSP;
+
+ symbols = mop_get_all_package_symbols(stash, TYPE_FILTER_CODE);
+ sv_2mortal((SV*)symbols);
+ (void)hv_iterinit(symbols);
+ while ( (coderef = hv_iternextsv(symbols, &method_name, &method_name_len)) ) {
+ CV *cv = (CV *)SvRV(coderef);
+ char *cvpkg_name;
+ char *cv_name;
+ SV *method_slot;
+ SV *method_object;
+
+ if (!mop_get_code_info(coderef, &cvpkg_name, &cv_name)) {
+ continue;
+ }
+
+ /* this checks to see that the subroutine is actually from our package */
+ if ( !(strEQ(cvpkg_name, "constant") && strEQ(cv_name, "__ANON__")) ) {
+ if ( strNE(cvpkg_name, class_name_pv) ) {
+ continue;
+ }
+ }
+
+ method_slot = *hv_fetch(map, method_name, method_name_len, TRUE);
+ if ( SvOK(method_slot) ) {
- SV *const body = mop_call0(aTHX_ method_slot, KEY_FOR(body)); /* $method_object->body() */
++ SV *const body = mop_call0(aTHX_ method_slot, mop_body); /* $method_object->body() */
+ if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) {
+ continue;
+ }
+ }
+
+ method_metaclass_name = mop_call0(aTHX_ self, mop_method_metaclass); /* $self->method_metaclass() */
+
+ /*
+ $method_object = $method_metaclass->wrap(
+ $cv,
+ associated_metaclass => $self,
+ package_name => $class_name,
+ name => $method_name
+ );
+ */
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ EXTEND(SP, 8);
+ PUSHs(method_metaclass_name); /* invocant */
+ mPUSHs(newRV_inc((SV *)cv));
+ PUSHs(mop_associated_metaclass);
+ PUSHs(self);
- PUSHs(KEY_FOR(package_name));
++ PUSHs(mop_package_name);
+ PUSHs(class_name);
- PUSHs(KEY_FOR(name));
++ PUSHs(mop_name);
+ mPUSHs(newSVpv(method_name, method_name_len));
+ PUTBACK;
+
+ call_sv(mop_wrap, G_SCALAR | G_METHOD);
+ SPAGAIN;
+ method_object = POPs;
+ PUTBACK;
+ /* $map->{$method_name} = $method_object */
+ sv_setsv(method_slot, method_object);
+
+ FREETMPS;
+ LEAVE;
+ }
+}
+
MODULE = Class::MOP::Package PACKAGE = Class::MOP::Package
PROTOTYPES: DISABLE
symbols = mop_get_all_package_symbols(stash, filter);
PUSHs(sv_2mortal(newRV_noinc((SV *)symbols)));
+void
+get_method_map(self)
+ SV *self
+ PREINIT:
+ HV *const obj = (HV *)SvRV(self);
- SV *const class_name = HeVAL( hv_fetch_ent(obj, KEY_FOR(package), 0, HASH_FOR(package)) );
++ SV *const class_name = HeVAL( hv_fetch_ent(obj, mop_package, 0, 0U) );
+ HV *const stash = gv_stashsv(class_name, 0);
+ UV current;
+ SV *cache_flag;
+ SV *map_ref;
+ PPCODE:
+ if (!stash) {
+ mXPUSHs(newRV_noinc((SV *)newHV()));
+ return;
+ }
+
+ current = mop_check_package_cache_flag(aTHX_ stash);
- cache_flag = HeVAL( hv_fetch_ent(obj, KEY_FOR(package_cache_flag), TRUE, HASH_FOR(package_cache_flag)));
- map_ref = HeVAL( hv_fetch_ent(obj, KEY_FOR(methods), TRUE, HASH_FOR(methods)));
++ cache_flag = HeVAL( hv_fetch_ent(obj, mop_package_cache_flag, TRUE, 0U));
++ map_ref = HeVAL( hv_fetch_ent(obj, mop_methods, TRUE, 0U));
+
+ /* $self->{methods} does not yet exist (or got deleted) */
+ if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) {
+ SV *new_map_ref = newRV_noinc((SV *)newHV());
+ sv_2mortal(new_map_ref);
+ sv_setsv(map_ref, new_map_ref);
+ }
+
+ if ( !SvOK(cache_flag) || SvUV(cache_flag) != current ) {
+ mop_update_method_map(aTHX_ self, class_name, stash, (HV *)SvRV(map_ref));
+ sv_setuv(cache_flag, mop_check_package_cache_flag(aTHX_ stash)); /* update_cache_flag() */
+ }
+
+ XPUSHs(map_ref);
+
BOOT:
INSTALL_SIMPLE_READER_WITH_KEY(Package, name, package);
++ INSTALL_SIMPLE_READER_WITH_KEY(Package, _method_map, methods);
++ INSTALL_SIMPLE_READER(Package, method_metaclass);
++ INSTALL_SIMPLE_READER(Package, wrapped_method_metaclass);