static HV* S_thaw_fields(lucy_InStream *instream) { // Read frozen data into an SV buffer. size_t len = (size_t)LUCY_InStream_Read_C64(instream); SV *buf_sv = newSV(len + 1); SvPOK_on(buf_sv); SvCUR_set(buf_sv, len); char *buf = SvPVX(buf_sv); LUCY_InStream_Read_Bytes(instream, buf, len); // Call back to Storable to thaw the frozen hash. dSP; ENTER; SAVETMPS; EXTEND(SP, 1); PUSHMARK(SP); mPUSHs(buf_sv); PUTBACK; call_pv("Storable::thaw", G_SCALAR); SPAGAIN; SV *frozen = POPs; if (frozen && !SvROK(frozen)) { CFISH_THROW(CFISH_ERR, "thaw failed"); } HV *fields = (HV*)SvRV(frozen); (void)SvREFCNT_inc((SV*)fields); PUTBACK; FREETMPS; LEAVE; return fields; }
static SV* S_do_callback_sv(void *vobj, char *method, uint32_t num_args, va_list args) { SV *return_val; SI_push_args(vobj, args, num_args); { int num_returned = call_method(method, G_SCALAR); dSP; if (num_returned != 1) { CFISH_THROW(KINO_ERR, "Bad number of return vals from %s: %i32", method, (int32_t)num_returned); } return_val = POPs; PUTBACK; } return return_val; }
void kino_Host_callback(void *vobj, char *method, uint32_t num_args, ...) { va_list args; va_start(args, num_args); SI_push_args(vobj, args, num_args); va_end(args); { int count = call_method(method, G_VOID|G_DISCARD); if (count != 0) { CFISH_THROW(KINO_ERR, "callback '%s' returned too many values: %i32", method, (int32_t)count); } FREETMPS; LEAVE; } }
kino_Obj* kino_Obj_inc_refcount(kino_Obj *self) { switch (self->ref.count) { case 0: CFISH_THROW(KINO_ERR, "Illegal refcount of 0"); break; // useless case 1: case 2: self->ref.count++; break; case 3: S_lazy_init_host_obj(self); // fall through default: SvREFCNT_inc_simple_void_NN((SV*)self->ref.host_obj); } return self; }
uint32_t kino_Obj_dec_refcount(kino_Obj *self) { uint32_t modified_refcount = I32_MAX; switch (self->ref.count) { case 0: CFISH_THROW(KINO_ERR, "Illegal refcount of 0"); break; // useless case 1: modified_refcount = 0; Kino_Obj_Destroy(self); break; case 2: case 3: modified_refcount = --self->ref.count; break; default: modified_refcount = SvREFCNT((SV*)self->ref.host_obj) - 1; // If the SV's refcount falls to 0, DESTROY will be invoked from // Perl-space. SvREFCNT_dec((SV*)self->ref.host_obj); } return modified_refcount; }
lucy_HitDoc* lucy_DefDocReader_fetch_doc(lucy_DefaultDocReader *self, int32_t doc_id) { lucy_Schema *const schema = self->schema; lucy_InStream *const dat_in = self->dat_in; lucy_InStream *const ix_in = self->ix_in; HV *fields = newHV(); int64_t start; uint32_t num_fields; SV *field_name_sv = newSV(1); // Get data file pointer from index, read number of fields. Lucy_InStream_Seek(ix_in, (int64_t)doc_id * 8); start = Lucy_InStream_Read_U64(ix_in); Lucy_InStream_Seek(dat_in, start); num_fields = Lucy_InStream_Read_C32(dat_in); // Decode stored data and build up the doc field by field. while (num_fields--) { STRLEN field_name_len; char *field_name_ptr; SV *value_sv; lucy_FieldType *type; // Read field name. field_name_len = Lucy_InStream_Read_C32(dat_in); field_name_ptr = SvGROW(field_name_sv, field_name_len + 1); Lucy_InStream_Read_Bytes(dat_in, field_name_ptr, field_name_len); SvPOK_on(field_name_sv); SvCUR_set(field_name_sv, field_name_len); SvUTF8_on(field_name_sv); *SvEND(field_name_sv) = '\0'; // Find the Field's FieldType. lucy_ZombieCharBuf *field_name_zcb = CFISH_ZCB_WRAP_STR(field_name_ptr, field_name_len); Lucy_ZCB_Assign_Str(field_name_zcb, field_name_ptr, field_name_len); type = Lucy_Schema_Fetch_Type(schema, (lucy_CharBuf*)field_name_zcb); // Read the field value. switch (Lucy_FType_Primitive_ID(type) & lucy_FType_PRIMITIVE_ID_MASK) { case lucy_FType_TEXT: { STRLEN value_len = Lucy_InStream_Read_C32(dat_in); value_sv = newSV((value_len ? value_len : 1)); Lucy_InStream_Read_Bytes(dat_in, SvPVX(value_sv), value_len); SvCUR_set(value_sv, value_len); *SvEND(value_sv) = '\0'; SvPOK_on(value_sv); SvUTF8_on(value_sv); break; } case lucy_FType_BLOB: { STRLEN value_len = Lucy_InStream_Read_C32(dat_in); value_sv = newSV((value_len ? value_len : 1)); Lucy_InStream_Read_Bytes(dat_in, SvPVX(value_sv), value_len); SvCUR_set(value_sv, value_len); *SvEND(value_sv) = '\0'; SvPOK_on(value_sv); break; } case lucy_FType_FLOAT32: value_sv = newSVnv(Lucy_InStream_Read_F32(dat_in)); break; case lucy_FType_FLOAT64: value_sv = newSVnv(Lucy_InStream_Read_F64(dat_in)); break; case lucy_FType_INT32: value_sv = newSViv((int32_t)Lucy_InStream_Read_C32(dat_in)); break; case lucy_FType_INT64: if (sizeof(IV) == 8) { int64_t val = (int64_t)Lucy_InStream_Read_C64(dat_in); value_sv = newSViv((IV)val); } else { // (lossy) int64_t val = (int64_t)Lucy_InStream_Read_C64(dat_in); value_sv = newSVnv((double)val); } break; default: value_sv = NULL; CFISH_THROW(LUCY_ERR, "Unrecognized type: %o", type); } // Store the value. (void)hv_store_ent(fields, field_name_sv, value_sv, 0); } SvREFCNT_dec(field_name_sv); lucy_HitDoc *retval = lucy_HitDoc_new(fields, doc_id, 0.0); SvREFCNT_dec((SV*)fields); return retval; }
// Convert all arguments to Perl and place them on the Perl stack. static CHY_INLINE void SI_push_args(void *vobj, va_list args, uint32_t num_args) { kino_Obj *obj = (kino_Obj*)vobj; SV *invoker; uint32_t i; dSP; uint32_t stack_slots_needed = num_args < 2 ? num_args + 1 : (num_args * 2) + 1; EXTEND(SP, stack_slots_needed); if (Kino_Obj_Is_A(obj, KINO_VTABLE)) { kino_VTable *vtable = (kino_VTable*)obj; // TODO: Creating a new class name SV every time is wasteful. invoker = XSBind_cb_to_sv(Kino_VTable_Get_Name(vtable)); } else { invoker = (SV*)Kino_Obj_To_Host(obj); } ENTER; SAVETMPS; PUSHMARK(SP); PUSHs( sv_2mortal(invoker) ); for (i = 0; i < num_args; i++) { uint32_t arg_type = va_arg(args, uint32_t); char *label = va_arg(args, char*); if (num_args > 1) { PUSHs( sv_2mortal( newSVpvn(label, strlen(label)) ) ); } switch (arg_type & CFISH_HOST_ARGTYPE_MASK) { case CFISH_HOST_ARGTYPE_I32: { int32_t value = va_arg(args, int32_t); PUSHs( sv_2mortal( newSViv(value) ) ); } break; case CFISH_HOST_ARGTYPE_I64: { int64_t value = va_arg(args, int64_t); if (sizeof(IV) == 8) { PUSHs( sv_2mortal( newSViv((IV)value) ) ); } else { // lossy PUSHs( sv_2mortal( newSVnv((double)value) ) ); } } break; case CFISH_HOST_ARGTYPE_F32: case CFISH_HOST_ARGTYPE_F64: { // Floats are promoted to doubles by variadic calling. double value = va_arg(args, double); PUSHs( sv_2mortal( newSVnv(value) ) ); } break; case CFISH_HOST_ARGTYPE_STR: { kino_CharBuf *string = va_arg(args, kino_CharBuf*); PUSHs( sv_2mortal( XSBind_cb_to_sv(string) ) ); } break; case CFISH_HOST_ARGTYPE_OBJ: { kino_Obj* anObj = va_arg(args, kino_Obj*); SV *arg_sv = anObj == NULL ? newSV(0) : XSBind_cfish_to_perl(anObj); PUSHs( sv_2mortal(arg_sv) ); } break; default: CFISH_THROW(KINO_ERR, "Unrecognized arg type: %u32", arg_type); } } PUTBACK; }