static inline void attr_delete_from_vhash(SV *self, SV *value) { hrattr_simple *attr = attr_from_sv(SvRV((self))); //UN_del_action(value, SvRV(self)); SV *vaddr = newSVuv((UV)SvRV(value)); SV *rlookup; SV *vhash; char *astr = attr_strkey(attr, attr_getsize(attr)); get_hashes((HR_Table_t)attr_parent_tbl(attr), HR_HKEY_LOOKUP_REVERSE, &rlookup, HR_HKEY_LOOKUP_NULL); vhash = get_vhash_from_rlookup(rlookup, vaddr, 0); U32 old_refcount = refcnt_ka_begin(value); if(vhash) { HR_DEBUG("vhash has %d keys", HvKEYS(REF2HASH(vhash))); HR_DEBUG("Deleting '%s' from vhash=%p", astr, SvRV(vhash)); hv_delete(REF2HASH(vhash), astr, strlen(astr), G_DISCARD); if(!HvKEYS(REF2HASH(vhash))) { HR_DEBUG("Vhash empty"); HR_PL_del_action_container(value, rlookup); hv_delete_ent(REF2HASH(rlookup), vaddr, G_DISCARD, 0); } else { HR_DEBUG("Vhash still has %d keys", HvKEYS(REF2HASH(vhash))); } } refcnt_ka_end(value, old_refcount); }
bool LUCY_Doc_Equals_IMP(lucy_Doc *self, cfish_Obj *other) { if ((lucy_Doc*)other == self) { return true; } if (!cfish_Obj_is_a(other, LUCY_DOC)) { return false; } lucy_DocIVARS *const ivars = lucy_Doc_IVARS(self); lucy_DocIVARS *const ovars = lucy_Doc_IVARS((lucy_Doc*)other); if (!ivars->doc_id == ovars->doc_id) { return false; } if (!!ivars->fields ^ !!ovars->fields) { return false; } // Verify fields. Don't allow any deep data structures. dTHX; HV *my_fields = (HV*)ivars->fields; HV *other_fields = (HV*)ovars->fields; if (HvKEYS(my_fields) != HvKEYS(other_fields)) { return false; } I32 num_fields = hv_iterinit(my_fields); while (num_fields--) { HE *my_entry = hv_iternext(my_fields); SV *my_val_sv = HeVAL(my_entry); STRLEN key_len; char *key; if (HeKLEN(my_entry) == HEf_SVKEY) { SV *key_sv = HeKEY_sv(my_entry); key = SvPV(key_sv, key_len); if (SvUTF8(key_sv)) { key_len = -key_len; } } else { key_len = HeKLEN(my_entry); key = key_len ? HeKEY(my_entry) : Nullch; if (HeKUTF8(my_entry)) { key_len = -key_len; } } SV **const other_val = hv_fetch(other_fields, key, key_len, 0); if (!other_val) { return false; } if (!sv_eq(my_val_sv, *other_val)) { return false; } } return true; }
uint32_t lucy_Doc_get_size(lucy_Doc *self) { return self->fields ? HvKEYS((HV*)self->fields) : 0; }
void HRA_store_a(SV *self, SV *attr, char *t, SV *value, ...) { SV *vstring = newSVuv((UV)SvRV(value)); //reverse lookup key SV *aobj = NULL; //primary attribute entry, from attr_lookup SV *vref = NULL; //value's entry in attribute hash SV *attrhash_ref = NULL; //reference for attribute hash, for adding actions SV **a_r_ent = NULL; //lval-type HE for looking/storing attr in vhash char *astring = NULL; hrattr_simple *aptr; //our private attribute structure int options = STORE_OPT_O_CREAT; int i; dXSARGS; if ((items-4) % 2) { die("Expected hash options or nothing (got %d)", items-3); } for(i=4;i<items;i+=2) { _chkopt(STRONG_ATTR, i, options); _chkopt(STRONG_VALUE, i, options); } aobj = attr_get(self, attr, t, options); if(!aobj) { die("attr_get() failed to return anything"); } aptr = attr_from_sv(SvRV(aobj)); assert(SvROK(aobj)); astring = attr_strkey(aptr, attr_getsize(aptr)); if(!insert_into_vhash(value, aobj, astring, REF2TABLE(self), NULL)) { goto GT_RET; /*No new insertions*/ } if(!HvKEYS(aptr->attrhash)) { /*First entry and we've already inserted our reverse entry*/ SvREFCNT_dec(SvRV(aobj)); } vref = newSVsv(value); if(hv_store_ent(aptr->attrhash, vstring, vref, 0)) { if( (options & STORE_OPT_STRONG_VALUE) == 0) { sv_rvweaken(vref); } } else { SvREFCNT_dec(vref); } RV_Newtmp(attrhash_ref, (SV*)aptr->attrhash); HR_Action v_actions[] = { HR_DREF_FLDS_ptr_from_hv(SvRV(value), attrhash_ref), HR_ACTION_LIST_TERMINATOR }; HR_add_actions_real(value, v_actions); GT_RET: SvREFCNT_dec(vstring); if(attrhash_ref) { RV_Freetmp(attrhash_ref); } XSRETURN(0); }
uint32_t LUCY_Doc_Get_Size_IMP(lucy_Doc *self) { lucy_DocIVARS *const ivars = lucy_Doc_IVARS(self); return ivars->fields ? HvKEYS((HV*)ivars->fields) : 0; }