Affix
view release on metacpan or search on metacpan
lib/Affix/marshal.c view on Meta::CPAN
.bit_width = bit_width,
.readonly = readonly,
.absolute = absolute,
.destructor = nullptr,
.destructor_lib_sv = nullptr};
MGVTBL * v = nullptr;
int is_wide = 0;
if (bit_width > 0)
v = &vtbl_bitfield;
else if (cat == INFIX_TYPE_ENUM)
v = &vtbl_enum;
else if (cat == INFIX_TYPE_PRIMITIVE) {
if (res->meta.primitive_id == INFIX_PRIMITIVE_SINT128)
v = &vtbl_sint128;
else if (res->meta.primitive_id == INFIX_PRIMITIVE_UINT128)
v = &vtbl_uint128;
else
v = get_primitive_vtable(res);
}
else if (cat == INFIX_TYPE_POINTER || cat == INFIX_TYPE_REVERSE_TRAMPOLINE)
v = &vtbl_pointer;
else if (cat == INFIX_TYPE_VOID)
v = &vtbl_void;
else if (is_string_array(aTHX_ type, &is_wide)) {
if (is_wide) {
v = &wstring_vtable;
}
else {
/* Resolve the element type to check signedness */
const infix_type * el = resolve_type(aTHX_ type->meta.array_info.element_type);
if (el->meta.primitive_id == INFIX_PRIMITIVE_UINT8)
v = &vtbl_buffer; /* Array[UInt8] -> Binary */
else
v = &string_vtable; /* Array[Char] -> String */
}
}
else
v = &vtbl_lazy_aggregate;
sv_magicext(sv, owner, PERL_MAGIC_ext, v, (char *)&m, sizeof(Affix_Pin_2_Point_Oh));
SvMAGICAL_on(sv);
SvGMAGICAL_on(sv);
SvSMAGICAL_on(sv);
/* FIX 3: Never prime a lazy aggregate placeholder; let it vivify on first use. */
if (prime && v != &vtbl_lazy_aggregate && v != &vtbl_void)
v->svt_get(aTHX_ sv, mg_find(sv, PERL_MAGIC_ext));
}
#define LAZY_ARRAY_THRESHOLD 100
/**
* @brief Internal helper to build the actual Perl Hash/Array structure.
* @param ptr The raw C memory address (may be nullptr).
* @param type The infix_type definition.
* @param owner The root SV lifeline.
* @param arena The local arena for anonymous types (if any).
* @param eager If false, large arrays return a magical scalar placeholder.
* @param readonly If true, mutations via the resulting aggregate are blocked.
*/
static SV * _bind_aggregate_internal(
pTHX_ void * ptr, const infix_type * type, SV * owner, infix_arena_t * arena, bool eager, bool readonly) {
const infix_type * res = resolve_type(aTHX_ type);
infix_type_category cat = infix_type_get_category(res);
if (cat == INFIX_TYPE_STRUCT || cat == INFIX_TYPE_UNION) {
HV * hv = newHV();
Affix_Pin_2_Point_Oh m = {.ptr = ptr, .type = type, .arena = arena, .readonly = readonly};
sv_magicext((SV *)hv, owner, PERL_MAGIC_ext, &vtbl_lazy_aggregate, (char *)&m, sizeof(Affix_Pin_2_Point_Oh));
size_t count = infix_type_get_member_count(res);
for (size_t i = 0; i < count; i++) {
const infix_struct_member * m = infix_type_get_member(res, i);
SV * v = newSV(0);
/* Propagate nullptr safely so getters don't read from 0x0 + offset */
void * child_ptr = ptr ? ((char *)ptr + m->offset) : nullptr;
// Don't read the memory now. Wait until the user accesses the hash key.
// NOTE: member pins borrow the *external* lifeline (`owner`), never the
// freshly created parent HV. Referencing the parent here creates a strong
// reference cycle (HV owns the members, each member's mg_obj owns the HV)
// that Perl's refcounting cannot collect, leaking the whole pin tree and
// its arena on every bind/cast.
bind_placeholder(
aTHX_ v, child_ptr, m->type, m->bit_offset, m->bit_width, false, owner, NULL, readonly, false);
hv_store(hv, m->name ? m->name : "", strlen(m->name ? m->name : ""), v, 0);
}
return newRV_noinc((SV *)hv);
}
else if (cat == INFIX_TYPE_ARRAY || cat == INFIX_TYPE_VECTOR || cat == INFIX_TYPE_COMPLEX) {
if (is_string_array(aTHX_ type, nullptr)) {
SV * sv = newSV(0);
bind_placeholder(aTHX_ sv, ptr, type, 0, 0, true, owner, arena, readonly, false);
/* WRAP IN REFERENCE to ensure magic persists across assignments */
return newRV_noinc(sv);
}
size_t n, step;
const infix_type * el_type;
if (cat == INFIX_TYPE_COMPLEX) {
n = 2;
el_type = res->meta.complex_info.base_type;
step = el_type->size;
}
else if (cat == INFIX_TYPE_ARRAY) {
n = res->meta.array_info.num_elements;
el_type = res->meta.array_info.element_type;
step = resolve_type(aTHX_ el_type)->size;
}
else {
n = res->meta.vector_info.num_elements;
el_type = res->meta.vector_info.element_type;
step = el_type->size;
}
if (!eager && n > LAZY_ARRAY_THRESHOLD) {
SV * lazy_placeholder = newSV(0);
bind_placeholder(aTHX_ lazy_placeholder, ptr, type, 0, 0, false, owner, arena, readonly, false);
return lazy_placeholder;
}
( run in 0.556 second using v1.01-cache-2.11-cpan-800906f7e73 )