class IdentityDictStrategy(BaseDictStrategy, TypedDictStrategyMixin): erase, unerase = new_static_erasing_pair("IdentityDictStrategy") iter_erase, iter_unerase = new_static_erasing_pair("IdentityDictStrategyIterator") def get_empty_storage(self, space): return self.erase(OrderedDict()) def wrap(self, w_key): return w_key def unwrap(self, w_key): return w_key
class ObjectDictStrategy(BaseDictStrategy, TypedDictStrategyMixin): erase, unerase = new_static_erasing_pair("ObjectDictStrategy") iter_erase, iter_unerase = new_static_erasing_pair("ObjectDictStrategyIterator") def get_empty_storage(self, space): return self.erase(OrderedDict(space.eq_w, space.hash_w)) def wrap(self, w_key): return w_key def unwrap(self, w_key): return w_key
class SymbolHashmapStrategy(HashmapStrategy): import_from_mixin(UnwrappedHashmapStrategyMixin) erase, unerase = rerased.new_static_erasing_pair("symbol-hashmap-strategy") def is_correct_type(self, w_obj): return isinstance(w_obj, values.W_Symbol) def wrap(self, val): assert isinstance(val, values.W_Symbol) return val def unwrap(self, w_val): assert isinstance(w_val, values.W_Symbol) return w_val def rem(self, w_dict, w_key, env, cont): from pycket.interpreter import return_value if not w_dict.immutable(): raise Exception("Expected an immutable hash table") new_keys = [] new_vals = [] for (k, v) in w_dict.hash_items(): if k is w_key: continue new_keys.append(k) new_vals.append(v) assert isinstance(w_dict, W_EqualHashTable) new_table = W_EqualHashTable(new_keys, new_vals, True) return return_value(new_table, env, cont)
class ConstantStringStrategy(StringStrategy): erase, unerase = new_static_erasing_pair("constant") def str_w(self, storage): return self.unerase(storage) def liststr_w(self, storage): strvalue = self.unerase(storage) return [c for c in strvalue] def length(self, storage): return len(self.unerase(storage)) def getitem(self, storage, idx): return self.unerase(storage)[idx] def getslice(self, space, storage, start, end): return space.newstr_fromstr(self.unerase(storage)[start:end]) def hash(self, storage): return compute_hash(self.unerase(storage)) def copy(self, storage): return storage def to_mutable(self, space, s): s.strategy = strategy = space.fromcache(MutableStringStrategy) s.str_storage = strategy.erase(self.liststr_w(s.str_storage)) def extend_into(self, src_storage, dst_storage): dst_storage += self.unerase(src_storage) def mul(self, space, storage, times): return space.newstr_fromstr(self.unerase(storage) * times)
class ObjectHashmapStrategy(HashmapStrategy): erase, unerase = rerased.new_static_erasing_pair( "object-hashmap-strategry") def get(self, w_dict, w_key, env, cont): return equal_hash_ref_loop(self.unerase(w_dict.hstorage), 0, w_key, env, cont) def set(self, w_dict, w_key, w_val, env, cont): return equal_hash_set_loop(self.unerase(w_dict.hstorage), 0, w_key, w_val, env, cont) def items(self, w_dict): return self.unerase(w_dict.hstorage) def get_item(self, w_dict, i): try: return self.unerase(w_dict.hstorage)[i] except IndexError: raise def length(self, w_dict): return len(self.unerase(w_dict.hstorage)) def create_storage(self, keys, vals): return self.erase([(k, vals[i]) for i, k in enumerate(keys)])
class EmptyHashmapStrategy(HashmapStrategy): erase, unerase = rerased.new_static_erasing_pair("object-hashmap-strategy") def get(self, w_dict, w_key, env, cont): from pycket.interpreter import return_value return return_value(w_missing, env, cont) # contains nothing def set(self, w_dict, w_key, w_val, env, cont): self.switch_to_correct_strategy(w_dict, w_key) return w_dict.hash_set(w_key, w_val, env, cont) def rem(self, w_dict, w_key, env, cont): from pycket.interpreter import return_value return return_value(w_dict, env, cont) # there's nothing to remove def _set(self, w_dict, w_key, w_val): self.switch_to_correct_strategy(w_dict, w_key) return w_dict._set(w_key, w_val) def rem_inplace(self, w_dict, w_key, env, cont): from pycket.interpreter import return_value return return_value(values.w_void, env, cont) # there's nothing to remove def items(self, w_dict): return [] def get_item(self, w_dict, i): raise IndexError def length(self, w_dict): return 0 def create_storage(self, keys, vals): assert not keys assert not vals return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): if type(w_key) is values.W_Fixnum: strategy = FixnumHashmapStrategy.singleton elif type(w_key) is values.W_Symbol: strategy = SymbolHashmapStrategy.singleton elif isinstance(w_key, values_string.W_String): strategy = StringHashmapStrategy.singleton elif isinstance(w_key, values.W_ImmutableBytes): strategy = ImmutableByteHashmapStrategy.singleton elif isinstance(w_key, values.W_MutableBytes): strategy = MutableByteHashmapStrategy.singleton else: strategy = ObjectHashmapStrategy.singleton storage = strategy.create_storage([], []) w_dict.strategy = strategy w_dict.hstorage = storage
class UnicodeStringStrategy(ImmutableStringStrategy): erase, unerase = rerased.new_static_erasing_pair("unicode-string-strategy") def make_mutable(self, w_str): strategy = UnicodeMutableStringStrategy.singleton storage = strategy.erase(self.as_unicharlist(w_str)) w_str.change_strategy(strategy, storage) def as_str_ascii(self, w_str): raise ValueError # XXX or check? def as_str_utf8(self, w_str): s = self.unerase(w_str.get_storage()) assert s is not None return s.encode("utf-8") def as_unicode(self, w_str): return self.unerase(w_str.get_storage()) # string operations def length(self, w_str): return len(self.unerase(w_str.get_storage())) def getitem(self, w_str, index): return self.unerase(w_str.get_storage())[index] def getslice(self, w_str, start, stop): v = self.unerase(w_str.get_storage())[start:stop] return W_MutableString(self, self.erase(v)) def eq(self, w_str, w_other): if w_other.get_strategy() is self: return self.unerase(w_str.get_storage()) == self.unerase( w_other.get_storage()) return ImmutableStringStrategy.eq(self, w_str, w_other) def upper(self, w_str): value = self.unerase(w_str.get_storage()) builder = UnicodeBuilder(len(value)) for i, ch in enumerate(value): builder.append(unichr(unicodedb.toupper(ord(ch)))) return W_MutableString(self, self.erase(builder.build())) def lower(self, w_str): value = self.unerase(w_str.get_storage()) builder = UnicodeBuilder(len(value)) for i, ch in enumerate(value): builder.append(unichr(unicodedb.tolower(ord(ch)))) return W_MutableString(self, self.erase(builder.build()))
class SymbolHashmapStrategy(HashmapStrategy): import_from_mixin(UnwrappedHashmapStrategyMixin) erase, unerase = rerased.new_static_erasing_pair("symbol-hashmap-strategry") def is_correct_type(self, w_obj): return isinstance(w_obj, values.W_Symbol) def wrap(self, val): assert isinstance(val, values.W_Symbol) return val def unwrap(self, w_val): assert isinstance(w_val, values.W_Symbol) return w_val
class FixnumHashmapStrategy(HashmapStrategy): import_from_mixin(UnwrappedHashmapStrategyMixin) erase, unerase = rerased.new_static_erasing_pair("fixnum-hashmap-strategy") def is_correct_type(self, w_obj): return isinstance(w_obj, values.W_Fixnum) def wrap(self, val): assert isinstance(val, int) return values.W_Fixnum(val) def unwrap(self, w_val): assert isinstance(w_val, values.W_Fixnum) return w_val.value
class StringHashmapStrategy(HashmapStrategy): import_from_mixin(UnwrappedHashmapStrategyMixin) erase, unerase = rerased.new_static_erasing_pair("string-hashmap-strategry") def is_correct_type(self, w_obj): return isinstance(w_obj, values_string.W_String) def wrap(self, w_val): return w_val def unwrap(self, w_val): return w_val def _create_empty_dict(self): return r_dict(cmp_strings, hash_strings)
class ImmutableByteHashmapStrategy(HashmapStrategy): import_from_mixin(UnwrappedHashmapStrategyMixin) erase, unerase = rerased.new_static_erasing_pair("byte-hashmap-strategry") def is_correct_type(self, w_obj): return isinstance(w_obj, values.W_ImmutableBytes) def wrap(self, val): return val def unwrap(self, w_val): assert isinstance(w_val, values.W_ImmutableBytes) return w_val def _create_empty_dict(self): return r_dict(cmp_immutable_bytes, hash_immutable_bytes)
class AsciiStringStrategy(ImmutableStringStrategy): erase, unerase = rerased.new_static_erasing_pair("ascii-string-strategy") def make_mutable(self, w_str): strategy = AsciiMutableStringStrategy.singleton storage = strategy.erase(self.as_charlist_ascii(w_str)) w_str.change_strategy(strategy, storage) def as_str_utf8(self, w_str): return self.unerase(w_str.get_storage()) as_str_ascii = as_str_utf8 def as_unicode(self, w_str): return unicode(self.unerase(w_str.get_storage())) # change strategy? # string operations def length(self, w_str): return len(self.unerase(w_str.get_storage())) def getitem(self, w_str, index): return unichr(ord(self.unerase(w_str.get_storage())[index])) def getslice(self, w_str, start, stop): v = self.unerase(w_str.get_storage())[start:stop] return W_MutableString(self, self.erase(v)) def eq(self, w_str, w_other): if w_other.get_strategy() is self: return self.unerase(w_str.get_storage()) == self.unerase( w_other.get_storage()) return ImmutableStringStrategy.eq(self, w_str, w_other) def hash(self, w_str): return compute_hash(w_str.as_str_ascii()) def upper(self, w_str): return W_String.fromascii(w_str.as_str_ascii().upper()) def lower(self, w_str): return W_String.fromascii(w_str.as_str_ascii().lower())
class UnicodeMutableStringStrategy(MutableStringStrategy): erase, unerase = rerased.new_static_erasing_pair( "unicode-mutable-string-strategy") def as_charlist_ascii(self, w_str): raise ValueError("can't convert") def as_charlist_utf8(self, w_str): return list(self.as_str_utf8(w_str)) def as_str_utf8(self, w_str): return u''.join(self.unerase(w_str.get_storage())).encode('utf-8') def as_unicharlist(self, w_str): return self.unerase(w_str.get_storage())[:] def as_unicode(self, w_str): return u"".join(self.unerase(w_str.get_storage())) # string operations def length(self, w_str): return len(self.unerase(w_str.get_storage())) def getitem(self, w_str, index): return self.unerase(w_str.get_storage())[index] def getslice(self, w_str, start, stop): v = self.unerase(w_str.get_storage())[start:stop] return W_MutableString(self, self.erase(v)) def eq(self, w_str, w_other): if w_other.get_strategy() is self: return self.unerase(w_str.get_storage()) == self.unerase( w_other.get_storage()) return MutableStringStrategy.eq(self, w_str, w_other) # mutation operations def setitem(self, w_str, index, unichar): self.unerase(w_str.get_storage())[index] = unichar.value def setslice(self, w_str, index, w_from, fromstart, fromend): target = self.unerase(w_str.get_storage()) # XXX inefficient for sourceindex in range(fromstart, fromend): target[index] = w_from.getitem(sourceindex) index += 1 def upper(self, w_str): # copy paste from above, but the types are different value = self.unerase(w_str.get_storage()) builder = UnicodeBuilder(len(value)) for i, ch in enumerate(value): builder.append(unichr(unicodedb.toupper(ord(ch)))) return W_MutableString(self, self.erase(list(builder.build()))) def lower(self, w_str): value = self.unerase(w_str.get_storage()) builder = UnicodeBuilder(len(value)) for i, ch in enumerate(value): builder.append(unichr(unicodedb.tolower(ord(ch)))) return W_MutableString(self, self.erase(list(builder.build())))
class AsciiMutableStringStrategy(MutableStringStrategy): erase, unerase = rerased.new_static_erasing_pair( "ascii-mutable-string-strategy") def make_unicode(self, w_str): strategy = UnicodeMutableStringStrategy.singleton storage = strategy.erase(self.as_unicharlist(w_str)) w_str.change_strategy(strategy, storage) def as_charlist_utf8(self, w_str): return self.unerase(w_str.get_storage())[:] def as_unicharlist(self, w_str): return [unichr(ord(c)) for c in self.unerase(w_str.get_storage())] def as_str_utf8(self, w_str): return "".join(self.unerase(w_str.get_storage())) as_str_ascii = as_str_utf8 # string operations def length(self, w_str): return len(self.unerase(w_str.get_storage())) def getitem(self, w_str, index): return unichr(ord(self.unerase(w_str.get_storage())[index])) def getslice(self, w_str, start, stop): v = self.unerase(w_str.get_storage())[start:stop] return W_MutableString(self, self.erase(v)) def eq(self, w_str, w_other): if w_other.get_strategy() is self: return self.unerase(w_str.get_storage()) == self.unerase( w_other.get_storage()) return MutableStringStrategy.eq(self, w_str, w_other) # mutation operations def setitem(self, w_str, index, unichar): val = ord(unichar.value) if val < 128: self.unerase(w_str.get_storage())[index] = chr(val) else: self.make_unicode(w_str) return w_str.setitem(index, unichar) def setslice(self, w_str, index, w_from, fromstart, fromend): if w_from.get_strategy() is self: target = self.unerase(w_str.get_storage()) # XXX inefficient for sourceindex in range(fromstart, fromend): char = ord(w_from.getitem(sourceindex)) assert char < 128 # XXX target[index] = chr(char) index += 1 else: self.make_unicode(w_str) return w_str.setslice(index, w_from, fromstart, fromend) def upper(self, w_str): # XXX inefficient return W_String.fromascii(w_str.as_str_ascii().upper()) def lower(self, w_str): # XXX inefficient return W_String.fromascii(w_str.as_str_ascii().lower())
class ObjectHashmapStrategy(HashmapStrategy): erase, unerase = rerased.new_static_erasing_pair( "object-hashmap-strategry") import_from_mixin(UnwrappedHashmapStrategyMixin) def get_bucket(self, w_dict, w_key, nonull=False): hash = tagged_hash(w_key) storage = self.get_storage(w_dict) bucket = storage.get(hash, None) if nonull and bucket is None: storage[hash] = bucket = [] return bucket def get(self, w_dict, w_key, env, cont): from pycket.interpreter import return_value bucket = self.get_bucket(w_dict, w_key) if not bucket: return return_value(w_missing, env, cont) return equal_hash_ref_loop(bucket, 0, w_key, env, cont) def set(self, w_dict, w_key, w_val, env, cont): bucket = self.get_bucket(w_dict, w_key, nonull=True) return equal_hash_set_loop(bucket, 0, w_key, w_val, env, cont) def _set(self, w_dict, w_key, w_val): raise NotImplementedError( "Unsafe set not supported for ObjectHashmapStrategy") def items(self, w_dict): items = [] storage = self.unerase(w_dict.hstorage) for bucket in storage.itervalues(): for item in bucket: items.append(item) return items if sys.maxint == 2147483647: def get_item(self, w_dict, i): storage = self.unerase(w_dict.hstorage) for bucket in storage.itervalues(): size = len(bucket) if size > i: return bucket[i] i -= size raise IndexError else: @staticmethod def _valid_bucket(v): return bool(v[1]) def get_item(self, w_dict, i): from pycket.hash.persistent_hash_map import MASK_32 storage = self.unerase(w_dict.hstorage) assert i >= 0 i = r_uint(i) index = i & MASK_32 subindex = (i >> 32) & MASK_32 bucket = get_dict_item(storage, index)[1] if bucket is None: raise IndexError return bucket[subindex] def hash_iterate_next(self, w_dict, pos): from pycket.hash.persistent_hash_map import MASK_32 storage = self.unerase(w_dict.hstorage) i = r_uint(pos.value) assert i >= 0 index = r_uint(i & MASK_32) subindex = r_uint((i >> 32) & MASK_32) bucket = get_dict_item(storage, index)[1] subindex += 1 if subindex == r_uint(len(bucket)): subindex = r_uint(0) try: next = next_valid_index(storage, intmask(index), valid=self._valid_bucket) except IndexError: return values.w_false index = r_uint(next) next = intmask((subindex << r_uint(32)) | index) return values.wrap(next) def hash_iterate_first(self, w_dict): return next_valid_index(w_dict, 0, valid=self._valid_bucket) def length(self, w_dict): storage = self.unerase(w_dict.hstorage) size = 0 for bucket in storage.itervalues(): size += len(bucket) return size def create_storage(self, keys, vals): storage = {} for i, key in enumerate(keys): val = vals[i] hash = tagged_hash(key) bucket = storage.get(hash, None) if bucket is None: storage[hash] = bucket = [] bucket.append((key, val)) return self.erase(storage)
class MutableStringStrategy(StringStrategy): erase, unerase = new_static_erasing_pair("mutable") def str_w(self, storage): return "".join(self.unerase(storage)) def liststr_w(self, storage): return self.unerase(storage) def length(self, storage): return len(self.unerase(storage)) def getitem(self, storage, idx): return self.unerase(storage)[idx] def getslice(self, space, storage, start, end): return space.newstr_fromchars(self.unerase(storage)[start:end]) def delslice(self, space, storage, start, end): del self.unerase(storage)[start:end] def hash(self, storage): storage = self.unerase(storage) length = len(storage) if length == 0: return -1 x = ord(storage[0]) << 7 i = 0 while i < length: x = intmask((1000003 * x) ^ ord(storage[i])) i += 1 x ^= length return intmask(x) def copy(self, storage): return self.erase(self.unerase(storage)[:]) def to_mutable(self, space, s): pass def extend_into(self, src_storage, dst_storage): dst_storage += self.unerase(src_storage) def clear(self, s): storage = self.unerase(s.str_storage) del storage[:] def mul(self, space, storage, times): return space.newstr_fromchars(self.unerase(storage) * times) def reverse(self, storage): storage = self.unerase(storage) storage.reverse() def swapcase(self, storage): storage = self.unerase(storage) changed = False for i, c in enumerate(storage): if ord("A") <= ord(c) <= ord("Z"): new_c = c.lower() changed = True elif ord("a") <= ord(c) <= ord("z"): new_c = c.upper() changed = True else: new_c = c storage[i] = new_c return changed def downcase(self, storage): storage = self.unerase(storage) changed = False for i, c in enumerate(storage): new_c = c.lower() changed |= (c != new_c) storage[i] = new_c return changed def upcase(self, storage): storage = self.unerase(storage) changed = False for i, c in enumerate(storage): new_c = c.upper() changed |= (c != new_c) storage[i] = new_c return changed def capitalize(self, storage): storage = self.unerase(storage) changed = False for i, c in enumerate(storage): if i == 0: new_c = c.upper() else: new_c = c.lower() changed |= (c != new_c) storage[i] = new_c return changed def chomp(self, storage, newline=None): storage = self.unerase(storage) changed = False linebreaks = ["\n", "\r"] if len(storage) == 0: return changed elif newline is not None and len(newline) == 0: ch = storage[-1] i = len(storage) - 1 if ch != "\r": while i >= 1 and ch in linebreaks: i -= 1 ch = storage[i] if i < len(storage) - 1: i += 1 changed = True if i > 0: del storage[i:] else: del storage[:] elif newline is not None and len(storage) >= len(newline): for i in xrange(len(newline) - 1, -1, -1): if newline[i] != storage[len(storage) - len(newline) + i]: return changed start = len(storage) - len(newline) assert start >= 0 del storage[start:] changed = True elif newline is None: ch = storage[-1] i = len(storage) - 1 while i >= 0 and linebreaks and ch in linebreaks: linebreaks.remove(ch) i -= 1 ch = storage[i] if i < len(storage) - 1: i += 1 changed = True if i > 0: del storage[i:] else: del storage[:] return changed def chop(self, storage): storage = self.unerase(storage) if len(storage) == 0: return False elif storage[-1] == "\n" and len(storage) >= 2 and storage[-2] == "\r": idx = len(storage) - 2 assert idx >= 0 del storage[idx:] return True else: del storage[-1] return True def succ(self, storage): storage = self.unerase(storage) if len(storage) == 0: return carry = "\0" has_alnums = False last_alnum = 0 start = len(storage) - 1 while start >= 0: ch = storage[start] if ch in string.letters or ch in string.digits: has_alnums = True if ch == "9": carry = "1" storage[start] = "0" elif ch == "z": carry = "a" storage[start] = "a" elif ch == "Z": carry = "A" storage[start] = "A" else: storage[start] = chr(ord(ch) + 1) carry = "\0" if carry == "\0": break last_alnum = start start -= 1 if not has_alnums: start = len(storage) - 1 carry = "\1" while start >= 0: ch = storage[start] if ord(ch) >= 255: storage[start] = "\0" else: storage[start] = chr(ord(ch) + 1) break start -= 1 if start < 0 and carry != "\0": last_alnum_ch = storage[last_alnum] storage[last_alnum] = carry storage.insert(last_alnum + 1, last_alnum_ch) def insert(self, storage, idx, other): storage = self.unerase(storage) for char in other: storage.insert(idx, char) idx += 1 def replaceitem(self, storage, idx, char): storage = self.unerase(storage) storage[idx] = char def strip(self, storage): storage = self.unerase(storage) if not storage: return False shift = 0 while shift < len(storage) and storage[shift].isspace(): shift += 1 if shift == len(storage): del storage[:] return True pop = len(storage) while pop > 0 and storage[pop - 1].isspace() or storage[pop - 1] == '\0': pop -= 1 if pop < len(storage) or shift > 0: end = pop new_len = end - shift assert end >= 0 assert new_len >= 0 storage[0:new_len] = storage[shift:end] del storage[new_len:] return True else: return False