def __init__(self, rtyper, r_key): self.rtyper = rtyper self.r_key = r_key fasthashfn = r_key.get_ll_fasthash_function() self.ll_keyhash = r_key.get_ll_hash_function() ll_keyeq = lltype.staticAdtMethod(r_key.get_ll_eq_function()) def ll_valid(entries, i): value = entries[i].value return bool(value) and bool(weakref_deref(rclass.OBJECTPTR, value)) def ll_everused(entries, i): return bool(entries[i].value) def ll_hash(entries, i): return fasthashfn(entries[i].key) entrymeths = { 'allocate': lltype.typeMethod(rdict._ll_malloc_entries), 'delete': rdict._ll_free_entries, 'valid': ll_valid, 'everused': ll_everused, 'hash': ll_hash, } WEAKDICTENTRY = lltype.Struct("weakdictentry", ("key", r_key.lowleveltype), ("value", llmemory.WeakRefPtr)) WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY, adtmeths=entrymeths, hints={'weakarray': 'value'}) # NB. the 'hints' is not used so far ^^^ dictmeths = { 'll_get': self.ll_get, 'll_set': self.ll_set, 'keyeq': ll_keyeq, 'paranoia': False, } self.WEAKDICT = lltype.GcStruct( "weakvaldict", ("num_items", lltype.Signed), ("num_pristine_entries", lltype.Signed), ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)), adtmeths=dictmeths) self.lowleveltype = lltype.Ptr(self.WEAKDICT) self.dict_cache = {}
def __init__(self, rtyper, r_key): self.rtyper = rtyper self.r_key = r_key fasthashfn = r_key.get_ll_fasthash_function() self.ll_keyhash = r_key.get_ll_hash_function() ll_keyeq = lltype.staticAdtMethod(r_key.get_ll_eq_function()) def ll_valid(entries, i): value = entries[i].value return bool(value) and bool(weakref_deref(rclass.OBJECTPTR, value)) def ll_everused(entries, i): return bool(entries[i].value) def ll_hash(entries, i): return fasthashfn(entries[i].key) entrymeths = { 'allocate': lltype.typeMethod(rdict._ll_malloc_entries), 'delete': rdict._ll_free_entries, 'valid': ll_valid, 'everused': ll_everused, 'hash': ll_hash, } WEAKDICTENTRY = lltype.Struct("weakdictentry", ("key", r_key.lowleveltype), ("value", llmemory.WeakRefPtr)) WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY, adtmeths=entrymeths, hints={'weakarray': 'value'}) # NB. the 'hints' is not used so far ^^^ dictmeths = { 'll_get': self.ll_get, 'll_set': self.ll_set, 'keyeq': ll_keyeq, 'paranoia': False, } self.WEAKDICT = lltype.GcStruct( "weakvaldict", ("num_items", lltype.Signed), ("resize_counter", lltype.Signed), ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)), adtmeths=dictmeths) self.lowleveltype = lltype.Ptr(self.WEAKDICT) self.dict_cache = {}
def __init__(self, rtyper, r_key): self.rtyper = rtyper self.r_key = r_key fasthashfn = r_key.get_ll_fasthash_function() self.ll_keyhash = r_key.get_ll_hash_function() ll_keyeq = lltype.staticAdtMethod(r_key.get_ll_eq_function()) def ll_valid(entries, i): value = entries[i].value return bool(value) and bool(weakref_deref(rclass.OBJECTPTR, value)) def ll_everused(entries, i): return bool(entries[i].value) def ll_hash(entries, i): return fasthashfn(entries[i].key) entrymeths = { "allocate": lltype.typeMethod(rdict._ll_malloc_entries), "delete": rdict._ll_free_entries, "valid": ll_valid, "everused": ll_everused, "hash": ll_hash, } WEAKDICTENTRY = lltype.Struct("weakdictentry", ("key", r_key.lowleveltype), ("value", llmemory.WeakRefPtr)) WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY, adtmeths=entrymeths, hints={"weakarray": "value"}) # NB. the 'hints' is not used so far ^^^ dictmeths = {"ll_get": self.ll_get, "ll_set": self.ll_set, "keyeq": ll_keyeq, "paranoia": False} self.WEAKDICT = lltype.GcStruct( "weakvaldict", ("num_items", lltype.Signed), ("resize_counter", lltype.Signed), ("entries", lltype.Ptr(WEAKDICTENTRYARRAY)), adtmeths=dictmeths, ) self.lowleveltype = lltype.Ptr(self.WEAKDICT) self.dict_cache = {}
def ll_both_none(lst1, lst2): return not lst1 and not lst2 # ____________________________________________________________ # # Accessor methods def ll_newlist(LIST, length): ll_assert(length >= 0, "negative list length") l = malloc(LIST) l.length = length l.items = malloc(LIST.items.TO, length) return l ll_newlist = typeMethod(ll_newlist) ll_newlist.oopspec = 'newlist(length)' # should empty lists start with no allocated memory, or with a preallocated # minimal number of entries? XXX compare memory usage versus speed, and # check how many always-empty lists there are in a typical pypy-c run... INITIAL_EMPTY_LIST_ALLOCATION = 0 def _ll_prebuilt_empty_array(LISTITEM): return malloc(LISTITEM, 0) _ll_prebuilt_empty_array._annspecialcase_ = 'specialize:memo' def _ll_new_empty_item_array(LIST): if INITIAL_EMPTY_LIST_ALLOCATION > 0: return malloc(LIST.items.TO, INITIAL_EMPTY_LIST_ALLOCATION) else:
# ____________________________________________________________ # # Accessor methods def ll_newlist(LIST, length): ll_assert(length >= 0, "negative list length") l = malloc(LIST) l.length = length l.items = malloc(LIST.items.TO, length) return l ll_newlist = typeMethod(ll_newlist) ll_newlist.oopspec = 'newlist(length)' def ll_newlist_hint(LIST, lengthhint): ll_assert(lengthhint >= 0, "negative list length") l = malloc(LIST) l.length = 0 l.items = malloc(LIST.items.TO, lengthhint) return l ll_newlist_hint = typeMethod(ll_newlist_hint) ll_newlist_hint.oopspec = 'newlist(lengthhint)' # should empty lists start with no allocated memory, or with a preallocated
def _setup_repr(self): if 'key_repr' not in self.__dict__: key_repr = self._key_repr_computer() self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr) if 'value_repr' not in self.__dict__: self.external_value_repr, self.value_repr = self.pickrepr(self._value_repr_computer()) if isinstance(self.DICT, lltype.GcForwardReference): self.DICTKEY = self.key_repr.lowleveltype self.DICTVALUE = self.value_repr.lowleveltype # compute the shape of the DICTENTRY structure entryfields = [] entrymeths = { 'allocate': lltype.typeMethod(_ll_malloc_entries), 'delete': _ll_free_entries, 'must_clear_key': (isinstance(self.DICTKEY, lltype.Ptr) and self.DICTKEY._needsgc()), 'must_clear_value': (isinstance(self.DICTVALUE, lltype.Ptr) and self.DICTVALUE._needsgc()), } # * the key entryfields.append(("key", self.DICTKEY)) # * if NULL is not a valid ll value for the key or the value # field of the entry, it can be used as a marker for # never-used entries. Otherwise, we need an explicit flag. s_key = self.dictkey.s_value s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) if self.force_non_null: if not nullkeymarker: rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) nullkeymarker = True if not nullvaluemarker: rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, s_value) # * the state of the entry - trying to encode it as dummy objects if nullkeymarker and dummykeyobj: # all the state can be encoded in the key entrymeths['everused'] = ll_everused_from_key entrymeths['dummy_obj'] = dummykeyobj entrymeths['valid'] = ll_valid_from_key entrymeths['mark_deleted'] = ll_mark_deleted_in_key # the key is overwritten by 'dummy' when the entry is deleted entrymeths['must_clear_key'] = False elif nullvaluemarker and dummyvalueobj: # all the state can be encoded in the value entrymeths['everused'] = ll_everused_from_value entrymeths['dummy_obj'] = dummyvalueobj entrymeths['valid'] = ll_valid_from_value entrymeths['mark_deleted'] = ll_mark_deleted_in_value # value is overwritten by 'dummy' when entry is deleted entrymeths['must_clear_value'] = False else: # we need a flag to know if the entry was ever used # (we cannot use a NULL as a marker for this, because # the key and value will be reset to NULL to clear their # reference) entryfields.append(("f_everused", lltype.Bool)) entrymeths['everused'] = ll_everused_from_flag # can we still rely on a dummy obj to mark deleted entries? if dummykeyobj: entrymeths['dummy_obj'] = dummykeyobj entrymeths['valid'] = ll_valid_from_key entrymeths['mark_deleted'] = ll_mark_deleted_in_key # key is overwritten by 'dummy' when entry is deleted entrymeths['must_clear_key'] = False elif dummyvalueobj: entrymeths['dummy_obj'] = dummyvalueobj entrymeths['valid'] = ll_valid_from_value entrymeths['mark_deleted'] = ll_mark_deleted_in_value # value is overwritten by 'dummy' when entry is deleted entrymeths['must_clear_value'] = False else: entryfields.append(("f_valid", lltype.Bool)) entrymeths['valid'] = ll_valid_from_flag entrymeths['mark_deleted'] = ll_mark_deleted_in_flag # * the value entryfields.append(("value", self.DICTVALUE)) # * the hash, if needed if self.custom_eq_hash: fasthashfn = None else: fasthashfn = self.key_repr.get_ll_fasthash_function() if fasthashfn is None: entryfields.append(("f_hash", lltype.Signed)) entrymeths['hash'] = ll_hash_from_cache else: entrymeths['hash'] = ll_hash_recomputed entrymeths['fasthashfn'] = fasthashfn # Build the lltype data structures self.DICTENTRY = lltype.Struct("dictentry", *entryfields) self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY, adtmeths=entrymeths) fields = [ ("num_items", lltype.Signed), ("resize_counter", lltype.Signed), ("entries", lltype.Ptr(self.DICTENTRYARRAY)) ] if self.custom_eq_hash: self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr() fields.extend([ ("fnkeyeq", self.r_rdict_eqfn.lowleveltype), ("fnkeyhash", self.r_rdict_hashfn.lowleveltype) ]) adtmeths = { 'keyhash': ll_keyhash_custom, 'keyeq': ll_keyeq_custom, 'r_rdict_eqfn': self.r_rdict_eqfn, 'r_rdict_hashfn': self.r_rdict_hashfn, 'paranoia': True, } else: # figure out which functions must be used to hash and compare ll_keyhash = self.key_repr.get_ll_hash_function() ll_keyeq = self.key_repr.get_ll_eq_function() # can be None ll_keyhash = lltype.staticAdtMethod(ll_keyhash) if ll_keyeq is not None: ll_keyeq = lltype.staticAdtMethod(ll_keyeq) adtmeths = { 'keyhash': ll_keyhash, 'keyeq': ll_keyeq, 'paranoia': False, } adtmeths['KEY'] = self.DICTKEY adtmeths['VALUE'] = self.DICTVALUE adtmeths['allocate'] = lltype.typeMethod(_ll_malloc_dict) self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths, *fields))
elif weakref_deref(rclass.OBJECTPTR, key): return True else: # The entry might be a dead weakref still holding a strong # reference to the value; for this case, we clear the old # value from the entry, if any. entries[i].value = NULLVALUE return False def ll_everused(entries, i): return bool(entries[i].key) entrymeths = { 'allocate': lltype.typeMethod(rdict._ll_malloc_entries), 'delete': rdict._ll_free_entries, 'valid': ll_valid, 'everused': ll_everused, 'hash': rdict.ll_hash_from_cache, 'no_direct_compare': True, } WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY, adtmeths=entrymeths, hints={'weakarray': 'key'}) # NB. the 'hints' is not used so far ^^^ @jit.dont_look_inside def ll_new_weakdict(): d = lltype.malloc(WEAKDICT)
class __extend__(pairtype(AbstractRangeRepr, ArrayRepr)): def convert_from_to((r_rng, r_array), v, llops): cARRAY = inputconst(lltype.Void, r_array.lowleveltype.TO) return llops.gendirectcall(ll_build_from_list, cARRAY, v) def ll_allocate(ARRAY, ndim): array = malloc(ARRAY) array.ndim = ndim array.data = nullptr(ARRAY.data.TO) array.dataptr = nullptr(ARRAY.dataptr.TO) return array ll_allocate = typeMethod(ll_allocate) def ll_build_from_size(ARRAY, size, _malloc): array = ARRAY.ll_allocate(1) array.shape[0] = size array.strides[0] = 1 array.data = _malloc(ARRAY.data.TO, size) array.dataptr = direct_arrayitems(array.data) return array def ll_build_from_list(ARRAY, lst): size = lst.ll_length() array = ARRAY.ll_allocate(1) array.shape[0] = size
def _setup_repr(self): if 'key_repr' not in self.__dict__: key_repr = self._key_repr_computer() self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr) if 'value_repr' not in self.__dict__: self.external_value_repr, self.value_repr = self.pickrepr( self._value_repr_computer()) if isinstance(self.DICT, lltype.GcForwardReference): self.DICTKEY = self.key_repr.lowleveltype self.DICTVALUE = self.value_repr.lowleveltype # compute the shape of the DICTENTRY structure entryfields = [] entrymeths = { 'allocate': lltype.typeMethod(_ll_malloc_entries), 'delete': _ll_free_entries, 'must_clear_key': (isinstance(self.DICTKEY, lltype.Ptr) and self.DICTKEY._needsgc()), 'must_clear_value': (isinstance(self.DICTVALUE, lltype.Ptr) and self.DICTVALUE._needsgc()), } # * the key entryfields.append(("key", self.DICTKEY)) # * if NULL is not a valid ll value for the key or the value # field of the entry, it can be used as a marker for # never-used entries. Otherwise, we need an explicit flag. s_key = self.dictkey.s_value s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj( self.rtyper, s_value) # * the state of the entry - trying to encode it as dummy objects if nullkeymarker and dummykeyobj: # all the state can be encoded in the key entrymeths['everused'] = ll_everused_from_key entrymeths['dummy_obj'] = dummykeyobj entrymeths['valid'] = ll_valid_from_key entrymeths['mark_deleted'] = ll_mark_deleted_in_key # the key is overwritten by 'dummy' when the entry is deleted entrymeths['must_clear_key'] = False elif nullvaluemarker and dummyvalueobj: # all the state can be encoded in the value entrymeths['everused'] = ll_everused_from_value entrymeths['dummy_obj'] = dummyvalueobj entrymeths['valid'] = ll_valid_from_value entrymeths['mark_deleted'] = ll_mark_deleted_in_value # value is overwritten by 'dummy' when entry is deleted entrymeths['must_clear_value'] = False else: # we need a flag to know if the entry was ever used # (we cannot use a NULL as a marker for this, because # the key and value will be reset to NULL to clear their # reference) entryfields.append(("f_everused", lltype.Bool)) entrymeths['everused'] = ll_everused_from_flag # can we still rely on a dummy obj to mark deleted entries? if dummykeyobj: entrymeths['dummy_obj'] = dummykeyobj entrymeths['valid'] = ll_valid_from_key entrymeths['mark_deleted'] = ll_mark_deleted_in_key # key is overwritten by 'dummy' when entry is deleted entrymeths['must_clear_key'] = False elif dummyvalueobj: entrymeths['dummy_obj'] = dummyvalueobj entrymeths['valid'] = ll_valid_from_value entrymeths['mark_deleted'] = ll_mark_deleted_in_value # value is overwritten by 'dummy' when entry is deleted entrymeths['must_clear_value'] = False else: entryfields.append(("f_valid", lltype.Bool)) entrymeths['valid'] = ll_valid_from_flag entrymeths['mark_deleted'] = ll_mark_deleted_in_flag # * the value entryfields.append(("value", self.DICTVALUE)) # * the hash, if needed if self.custom_eq_hash: fasthashfn = None else: fasthashfn = self.key_repr.get_ll_fasthash_function() if fasthashfn is None: entryfields.append(("f_hash", lltype.Signed)) entrymeths['hash'] = ll_hash_from_cache else: entrymeths['hash'] = ll_hash_recomputed entrymeths['fasthashfn'] = fasthashfn # Build the lltype data structures self.DICTENTRY = lltype.Struct("dictentry", *entryfields) self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY, adtmeths=entrymeths) fields = [("num_items", lltype.Signed), ("num_pristine_entries", lltype.Signed), ("entries", lltype.Ptr(self.DICTENTRYARRAY))] if self.custom_eq_hash: self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr( ) fields.extend([("fnkeyeq", self.r_rdict_eqfn.lowleveltype), ("fnkeyhash", self.r_rdict_hashfn.lowleveltype) ]) adtmeths = { 'keyhash': ll_keyhash_custom, 'keyeq': ll_keyeq_custom, 'r_rdict_eqfn': self.r_rdict_eqfn, 'r_rdict_hashfn': self.r_rdict_hashfn, 'paranoia': True, } else: # figure out which functions must be used to hash and compare ll_keyhash = self.key_repr.get_ll_hash_function() ll_keyeq = self.key_repr.get_ll_eq_function() # can be None ll_keyhash = lltype.staticAdtMethod(ll_keyhash) if ll_keyeq is not None: ll_keyeq = lltype.staticAdtMethod(ll_keyeq) adtmeths = { 'keyhash': ll_keyhash, 'keyeq': ll_keyeq, 'paranoia': False, } adtmeths['KEY'] = self.DICTKEY adtmeths['VALUE'] = self.DICTVALUE adtmeths['allocate'] = lltype.typeMethod(_ll_malloc_dict) self.DICT.become( lltype.GcStruct("dicttable", adtmeths=adtmeths, *fields))
if not key: return False elif weakref_deref(rclass.OBJECTPTR, key): return True else: # The entry might be a dead weakref still holding a strong # reference to the value; for this case, we clear the old # value from the entry, if any. entries[i].value = NULLVALUE return False def ll_everused(entries, i): return bool(entries[i].key) entrymeths = { 'allocate': lltype.typeMethod(rdict._ll_malloc_entries), 'delete': rdict._ll_free_entries, 'valid': ll_valid, 'everused': ll_everused, 'hash': rdict.ll_hash_from_cache, 'no_direct_compare': True, } WEAKDICTENTRYARRAY = lltype.GcArray(WEAKDICTENTRY, adtmeths=entrymeths, hints={'weakarray': 'key'}) # NB. the 'hints' is not used so far ^^^ @jit.dont_look_inside def ll_new_weakdict(): d = lltype.malloc(WEAKDICT) d.entries = WEAKDICT.entries.TO.allocate(rdict.DICT_INITSIZE)
def ll_both_none(lst1, lst2): return not lst1 and not lst2 # ____________________________________________________________ # # Accessor methods def ll_newlist(LIST, length): ll_assert(length >= 0, "negative list length") l = malloc(LIST) l.length = length l.items = malloc(LIST.items.TO, length) return l ll_newlist = typeMethod(ll_newlist) ll_newlist.oopspec = 'newlist(length)' def ll_newlist_hint(LIST, lengthhint): ll_assert(lengthhint >= 0, "negative list length") l = malloc(LIST) l.length = 0 l.items = malloc(LIST.items.TO, lengthhint) return l ll_newlist_hint = typeMethod(ll_newlist_hint) ll_newlist_hint.oopspec = 'newlist_hint(lengthhint)' # should empty lists start with no allocated memory, or with a preallocated # minimal number of entries? XXX compare memory usage versus speed, and # check how many always-empty lists there are in a typical pypy-c run... INITIAL_EMPTY_LIST_ALLOCATION = 0
return NotImplemented cARRAY = inputconst(lltype.Void, r_array.lowleveltype.TO) return llops.gendirectcall(ll_build_from_list, cARRAY, v) class __extend__(pairtype(AbstractRangeRepr, ArrayRepr)): def convert_from_to((r_rng, r_array), v, llops): cARRAY = inputconst(lltype.Void, r_array.lowleveltype.TO) return llops.gendirectcall(ll_build_from_list, cARRAY, v) def ll_allocate(ARRAY, ndim): array = malloc(ARRAY) array.ndim = ndim array.data = nullptr(ARRAY.data.TO) array.dataptr = nullptr(ARRAY.dataptr.TO) return array ll_allocate = typeMethod(ll_allocate) def ll_build_from_size(ARRAY, size, _malloc): array = ARRAY.ll_allocate(1) array.shape[0] = size array.strides[0] = 1 array.data = _malloc(ARRAY.data.TO, size) array.dataptr = direct_arrayitems(array.data) return array def ll_build_from_list(ARRAY, lst): size = lst.ll_length() array = ARRAY.ll_allocate(1) array.shape[0] = size array.strides[0] = 1 array.data = malloc(ARRAY.data.TO, size)