class W_Parameterization(W_Object): _immutable_fields_ = ["root", "map"] _attrs_ = ["root", "map"] errorname = "parameterization" def __init__(self, root, map): self.root = root self.map = map @jit.look_inside_iff(lambda self, params, vals: \ jit.loop_unrolling_heuristic(params, len(params), values.UNROLLING_CUTOFF) and jit.loop_unrolling_heuristic(vals, len(vals), values.UNROLLING_CUTOFF)) def extend(self, params, vals): assert len(params) == len(vals) map = self.map for i, param in enumerate(params): cell = values.W_ThreadCell(vals[i], True) map = map.assoc(param.get_key(), cell) return W_Parameterization(self.root, map) @jit.elidable def get(self, param): key = param.key result = self.map.val_at(key, None) if result is not None: return result result = self.root.table[key] assert result is not None return result def tostring(self): return "#<parameterization>"
def _is_ascii(s): if not jit.loop_unrolling_heuristic(s, len(s)): return _is_ascii_elidable(s) for c in s: if ord(c) >= 128: return False return True
class UnwrappedVectorStrategyMixin(object): # the concrete class needs to implement: # erase, unerase, is_correct_type, wrap, unwrap def _copy_storage(self, w_vector, immutable=False): strategy = self if not immutable else self.immutable_variant() l = self.unerase(w_vector.get_storage())[:] return W_Vector(strategy, self.erase(l), w_vector.len) def _storage(self, w_vector): l = self.unerase(w_vector.get_storage()) debug.make_sure_not_resized(l) return l def _ref(self, w_vector, i): assert i >= 0 return self.wrap(self._storage(w_vector)[i]) def _set(self, w_vector, i, w_val): assert i >= 0 self._storage(w_vector)[i] = self.unwrap(w_val) @jit.look_inside_iff(lambda strategy, w_vector: jit.isconstant( w_vector.length()) and w_vector.length() < UNROLLING_CUTOFF) def ref_all(self, w_vector): unwrapped = self._storage(w_vector) return [self.wrap(i) for i in unwrapped] def create_storage_for_element(self, element, times): e = self.unwrap(element) return self.erase([e] * times) @jit.look_inside_iff(lambda self, elements_w: jit.loop_unrolling_heuristic( elements_w, len(elements_w), UNROLLING_CUTOFF)) def create_storage_for_elements(self, elements_w): if not elements_w: return self.erase([]) l = [self.unwrap(e) for e in elements_w] return self.erase(l) def wrap(self, obj): return obj def unwrap(self, w_obj): return w_obj def unrolling_heuristic(self, w_vector): storage = self._storage(w_vector) return jit.loop_unrolling_heuristic(storage, w_vector.len, UNROLLING_CUTOFF)
def ormap_cont(f, ls, env, cont, vals): # XXX this is currently not properly jitted from pycket.interpreter import return_value, check_one_val val = check_one_val(vals) if val is values.w_true: return return_value(val, env, cont) for l in ls: if l is values.w_null: return return_value(values.w_false, env, cont) cars = [l.car() for l in ls] cdrs = [l.cdr() for l in ls] return f.call(cars, env, ormap_cont(f, cdrs, env, cont)) @expose("append", arity=Arity.geq(0)) @jit.look_inside_iff( lambda l: jit.loop_unrolling_heuristic(l, len(l), values.UNROLLING_CUTOFF)) def append(lists): if not lists: return values.w_null lists, acc = lists[:-1], lists[-1] while lists: vals = values.from_list(lists.pop()) acc = values.to_improper(vals, acc) return acc @expose("reverse", [values.W_List]) def reverse(w_l): acc = values.w_null while isinstance(w_l, values.W_Cons): val, w_l = w_l.car(), w_l.cdr() acc = values.W_Cons.make(val, acc)
def min_max(space, args, implementation_of): if not jit.we_are_jitted() or len(args.arguments_w) != 1 and \ jit.loop_unrolling_heuristic(args.arguments_w, len(args.arguments_w)): return min_max_unroll(space, args, implementation_of) else: return min_max_normal(space, args, implementation_of)
class CPyListStrategy(ListStrategy): erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) def _check_index(self, index, length): if index < 0: index = length + index if index < 0 or index >= length: raise IndexError return index def getitem(self, w_list, index): storage = self.unerase(w_list.lstorage) index = self._check_index(index, storage._length) return from_ref(w_list.space, storage._elems[index]) def setitem(self, w_list, index, w_obj): storage = self.unerase(w_list.lstorage) index = self._check_index(index, storage._length) py_old = storage._elems[index] storage._elems[index] = make_ref(w_list.space, w_obj) decref(w_list.space, py_old) def length(self, w_list): storage = self.unerase(w_list.lstorage) return storage._length def get_raw_items(self, w_list): storage = self.unerase(w_list.lstorage) return storage._elems def getslice(self, w_list, start, stop, step, length): w_list.switch_to_object_strategy() return w_list.strategy.getslice(w_list, start, stop, step, length) def getitems(self, w_list): # called when switching list strategy, so convert storage storage = self.unerase(w_list.lstorage) retval = [None] * storage._length for i in range(storage._length): retval[i] = from_ref(w_list.space, storage._elems[i]) return retval @jit.unroll_safe def getitems_unroll(self, w_list): storage = self.unerase(w_list.lstorage) retval = [None] * storage._length for i in range(storage._length): retval[i] = from_ref(w_list.space, storage._elems[i]) return retval @jit.look_inside_iff(lambda self, w_list: jit.loop_unrolling_heuristic(w_list, w_list.length(), UNROLL_CUTOFF)) def getitems_fixedsize(self, w_list): return self.getitems_unroll(w_list) def copy_into(self, w_list, w_other): w_other.strategy = self w_other.lstorage = self.getstorage_copy(w_list) def clone(self, w_list): storage = self.getstorage_copy(w_list) w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self) return w_clone def getitems_copy(self, w_list): return self.getitems(w_list) # getitems copies anyway def getstorage_copy(self, w_list): lst = self.getitems(w_list) return self.erase(CPyListStorage(w_list.space, lst)) #------------------------------------------ # all these methods fail or switch strategy and then call ListObjectStrategy's method def setslice(self, w_list, start, stop, step, length): w_list.switch_to_object_strategy() w_list.strategy.setslice(w_list, start, stop, step, length) def init_from_list_w(self, w_list, list_w): raise NotImplementedError def _resize_hint(self, w_list, hint): pass def find(self, w_list, w_item, start, stop): w_list.switch_to_object_strategy() return w_list.strategy.find(w_list, w_item, start, stop) def append(self, w_list, w_item): w_list.switch_to_object_strategy() w_list.strategy.append(w_list, w_item) def inplace_mul(self, w_list, times): w_list.switch_to_object_strategy() w_list.strategy.inplace_mul(w_list, times) def deleteslice(self, w_list, start, step, slicelength): w_list.switch_to_object_strategy() w_list.strategy.deleteslice(w_list, start, step, slicelength) def pop(self, w_list, index): w_list.switch_to_object_strategy() return w_list.strategy.pop(w_list, index) def pop_end(self, w_list): w_list.switch_to_object_strategy() return w_list.strategy.pop_end(w_list) def insert(self, w_list, index, w_item): w_list.switch_to_object_strategy() w_list.strategy.insert(w_list, index, w_item) def extend(self, w_list, w_any): w_list.switch_to_object_strategy() w_list.strategy.extend(w_list, w_any) def _extend_from_list(self, w_list, w_other): w_list.switch_to_object_strategy() w_list.strategy._extend_from_list(w_list, w_other) def _extend_from_iterable(self, w_list, w_iterable): w_list.switch_to_object_strategy() w_list.strategy._extend_from_iterable(w_list, w_iterable) def reverse(self, w_list): w_list.switch_to_object_strategy() w_list.strategy.reverse(w_list) def sort(self, w_list, reverse): w_list.switch_to_object_strategy() w_list.descr_sort(w_list.space, reverse=reverse) def is_empty_strategy(self): return False
return self.call_with_extra_info(args, env, cont, None) def call_with_extra_info(self, args, env, cont, extra_call_info): jit.promote(self) return self.code(args, env, cont, extra_call_info) def tostring(self): return "#<procedure:%s>" % self.name def to_list(l): return to_improper(l, w_null) @jit.look_inside_iff( lambda l, curr: jit.loop_unrolling_heuristic(l, len(l), UNROLLING_CUTOFF)) def to_improper(l, curr): for i in range(len(l) - 1, -1, -1): curr = W_Cons.make(l[i], curr) return curr def to_mlist(l): return to_mimproper(l, w_null) @jit.look_inside_iff( lambda l, curr: jit.loop_unrolling_heuristic(l, len(l), UNROLLING_CUTOFF)) def to_mimproper(l, curr): for i in range(len(l) - 1, -1, -1): curr = W_MCons(l[i], curr)
index = i.value if index >= self.length(w_dict) - 1: return values.w_false return values.wrap(index + 1) def hash_iterate_first(self, w_dict): return 0 def length(self, w_dict): raise NotImplementedError("abstract base class") def create_storage(self, keys, vals): raise NotImplementedError("abstract base class") @jit.look_inside_iff(lambda keys: jit.loop_unrolling_heuristic( keys, len(keys), values.UNROLLING_CUTOFF)) def _find_strategy_class(keys): if not config.strategies: return ObjectHashmapStrategy.singleton if len(keys) == 0: return EmptyHashmapStrategy.singleton # An empty vector stays empty forever. Don't implement special EmptyVectorStrategy. single_class = type(keys[0]) for elem in keys: if not isinstance(elem, single_class): return ObjectHashmapStrategy.singleton if single_class is values.W_Fixnum: return FixnumHashmapStrategy.singleton if single_class is values.W_Symbol: return SymbolHashmapStrategy.singleton if single_class is values_string.W_String:
def _unroll_condition(self): return jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF)
from rpython.rlib import debug, jit, objectmodel, rerased from rpython.rlib.longlong2float import ( can_encode_int32, decode_int32_from_longlong_nan, encode_int32_into_longlong_nan, float2longlong, is_int32_from_longlong_nan, longlong2float ) from rpython.rlib.objectmodel import import_from_mixin, specialize, we_are_translated from rpython.rlib.rarithmetic import intmask @jit.look_inside_iff(lambda elements, immutable: jit.loop_unrolling_heuristic( elements, len(elements), UNROLLING_CUTOFF)) def _find_strategy_class(elements, immutable): if not config.strategies or len(elements) == 0: # An empty vector stays empty forever. Don't implement special EmptyVectorStrategy. if immutable: return ObjectImmutableVectorStrategy.singleton return ObjectVectorStrategy.singleton single_class = type(elements[0]) for elem in elements: if not isinstance(elem, single_class): if immutable: return ObjectImmutableVectorStrategy.singleton return ObjectVectorStrategy.singleton if single_class is W_Fixnum: if immutable: return FixnumImmutableVectorStrategy.singleton
size = len(list_w) if size == 0: return W_StringObject.EMPTY if size == 1: w_s = list_w[0] # only one item, return it if it's not a subclass of str if (space.is_w(space.type(w_s), space.w_str) or space.is_w(space.type(w_s), space.w_unicode)): return w_s return _str_join_many_items(space, w_self, list_w, size) @jit.look_inside_iff(lambda space, w_self, list_w, size: jit.loop_unrolling_heuristic(list_w, size)) def _str_join_many_items(space, w_self, list_w, size): self = w_self._value reslen = len(self) * (size - 1) for i in range(size): w_s = list_w[i] if not space.isinstance_w(w_s, space.w_str): if space.isinstance_w(w_s, space.w_unicode): # we need to rebuild w_list here, because the original # w_list might be an iterable which we already consumed w_list = space.newlist(list_w) w_u = space.call_function(space.w_unicode, w_self) return space.call_method(w_u, "join", w_list) msg = "sequence item %d: expected string, %T found" raise operationerrfmt(space.w_TypeError, msg, i, w_s) reslen += len(space.str_w(w_s))
def get_result_arity(self): return self.result_arity def call_with_extra_info(self, args, env, cont, extra_call_info): jit.promote(self) return self.code(args, env, cont, extra_call_info) def tostring(self): return "#<procedure:%s>" % self.name.variable_name() def to_list(l): return to_improper(l, w_null) @jit.look_inside_iff(lambda l, curr: jit.loop_unrolling_heuristic(l, len(l), UNROLLING_CUTOFF)) def to_improper(l, curr): for i in range(len(l) - 1, -1, -1): curr = W_Cons.make(l[i], curr) return curr @jit.look_inside_iff(lambda v, curr: v.unrolling_heuristic()) def vector_to_improper(v, curr): for i in range(v.len - 1, -1, -1): curr = W_Cons.make(v.ref(i), curr) return curr def to_mlist(l): return to_mimproper(l, w_null)
class StringMethods(object): def _sliced(self, space, s, start, stop, orig_obj): assert start >= 0 assert stop >= 0 #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), # space.w_bytes): # return orig_obj return self._new(s[start:stop]) def _convert_idx_params(self, space, w_start, w_end): value = self._val(space) lenself = len(value) start, end = unwrap_start_stop(space, lenself, w_start, w_end) # the None means "no offset"; see bytearrayobject.py return (value, start, end, None) @staticmethod def descr_maketrans(space, w_type, w_from, w_to): """B.maketrans(frm, to) -> translation table Return a translation table (a bytes object of length 256) suitable for use in the bytes or bytearray translate method where each byte in frm is mapped to the byte at the same position in to. The bytes objects frm and to must be of the same length. """ from pypy.objspace.std.bytesobject import makebytesdata_w base_table = [chr(i) for i in range(256)] list_from = makebytesdata_w(space, w_from) list_to = makebytesdata_w(space, w_to) if len(list_from) != len(list_to): raise oefmt(space.w_ValueError, "maketrans arguments must have same length") for i in range(len(list_from)): pos_from = ord(list_from[i]) char_to = list_to[i] base_table[pos_from] = char_to return space.newbytes(''.join(base_table)) def _multi_chr(self, c): return c @staticmethod def _single_char(space, w_sub): try: char = space.int_w(w_sub) except OperationError as e: if e.match(space, space.w_OverflowError): char = 256 # arbitrary value which will trigger the ValueError # condition below else: raise if not 0 <= char < 256: raise oefmt(space.w_ValueError, "byte must be in range(0, 256)") return chr(char) def descr_len(self, space): return space.newint(self._len()) def descr_iter(self, space): from pypy.objspace.std.iterobject import W_StringIterObject return W_StringIterObject(self, self._iter_getitem_result) def descr_contains(self, space, w_sub): value, start, end, _ = self._convert_idx_params(space, None, None) other = self._op_val(space, w_sub, allow_char=True) if self._use_rstr_ops(space, w_sub): res = value.find(other, start, end) else: res = find(value, other, start, end) return space.newbool(res >= 0) def descr_add(self, space, w_other): if self._use_rstr_ops(space, w_other): try: other = self._op_val(space, w_other) except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise return self._new(self._val(space) + other) # Bytearray overrides this method, CPython doesn't support contacting # buffers and strs, and unicodes are always handled above return space.w_NotImplemented def descr_mul(self, space, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise if times <= 0: return self._empty() if self._len() == 1: return self._new(self._multi_chr(self._val(space)[0]) * times) return self._new(self._val(space) * times) descr_rmul = descr_mul _KIND1 = "string" _KIND2 = "string" def descr_getitem(self, space, w_index): if isinstance(w_index, W_SliceObject): selfvalue = self._val(space) length = len(selfvalue) start, stop, step, sl = w_index.indices4(space, length) if sl == 0: return self._empty() elif step == 1: assert start >= 0 and stop >= 0 return self._sliced(space, selfvalue, start, stop, self) else: ret = _descr_getslice_slowpath(selfvalue, start, step, sl) return self._new_from_list(ret) index = space.getindex_w(w_index, space.w_IndexError, self._KIND1) return self._getitem_result(space, index) def _getitem_result(self, space, index): # Returns the result of 'self[index]', where index is an unwrapped int. # Used by descr_getitem() and by descr_iter(). selfvalue = self._val(space) try: character = selfvalue[index] except IndexError: raise oefmt(space.w_IndexError, self._KIND1 + " index out of range") from pypy.objspace.std.bytesobject import W_BytesObject if isinstance(self, W_BytesObject): return space.newint(ord(character)) return self._new(character) def descr_capitalize(self, space): value = self._val(space) if len(value) == 0: return self._empty() builder = self._builder(len(value)) builder.append(self._upper(value[0])) for i in range(1, len(value)): builder.append(self._lower_in_str(value, i)) return self._new(builder.build()) @unwrap_spec(width=int, w_fillchar=WrappedDefault(' ')) def descr_center(self, space, width, w_fillchar): value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: raise oefmt(space.w_TypeError, "center() argument 2 must be a single character") d = width - len(value) if d > 0: offset = d//2 + (d & width & 1) fillchar = self._multi_chr(fillchar[0]) centered = offset * fillchar + value + (d - offset) * fillchar else: centered = value return self._new(centered) def descr_count(self, space, w_sub, w_start=None, w_end=None): value, start, end, _ = self._convert_idx_params(space, w_start, w_end) sub = self._op_val(space, w_sub, allow_char=True) if self._use_rstr_ops(space, w_sub): return space.newint(value.count(sub, start, end)) else: res = count(value, sub, start, end) assert res >= 0 return space.newint(res) def descr_decode(self, space, w_encoding=None, w_errors=None): from pypy.objspace.std.unicodeobject import ( get_encoding_and_errors, decode_object) encoding, errors = get_encoding_and_errors(space, w_encoding, w_errors) if encoding is None: encoding = 'utf8' if encoding == 'utf8' or encoding == 'utf-8': # fast path - do not call into app-level codecs.py from pypy.module._codecs.interp_codecs import CodecState state = space.fromcache(CodecState) eh = state.decode_error_handler s = space.charbuf_w(self) ret, lgt, pos = str_decode_utf8(s, errors, True, eh) return space.newtext(ret, lgt) return decode_object(space, self, encoding, errors) @unwrap_spec(tabsize=int) def descr_expandtabs(self, space, tabsize=8): value = self._val(space) if not value: return self._empty() if self._use_rstr_ops(space, self): splitted = value.split(self._chr('\t')) else: splitted = split(value, self._chr('\t')) try: if tabsize > 0: ovfcheck(len(splitted) * tabsize) except OverflowError: raise oefmt(space.w_OverflowError, "new string is too long") expanded = oldtoken = splitted.pop(0) for token in splitted: expanded += self._multi_chr(self._chr(' ')) * self._tabindent(oldtoken, tabsize) + token oldtoken = token return self._new(expanded) def _tabindent(self, token, tabsize): """calculates distance behind the token to the next tabstop""" if tabsize <= 0: return 0 distance = tabsize if token: distance = 0 offset = len(token) while 1: if token[offset-1] == "\n" or token[offset-1] == "\r": break distance += 1 offset -= 1 if offset == 0: break # the same like distance = len(token) - (offset + 1) distance = (tabsize - distance) % tabsize if distance == 0: distance = tabsize return distance def descr_find(self, space, w_sub, w_start=None, w_end=None): value, start, end, ofs = self._convert_idx_params(space, w_start, w_end) sub = self._op_val(space, w_sub, allow_char=True) if self._use_rstr_ops(space, w_sub): res = value.find(sub, start, end) else: res = find(value, sub, start, end) if ofs is not None and res >= 0: res -= ofs return space.newint(res) def descr_rfind(self, space, w_sub, w_start=None, w_end=None): value, start, end, ofs = self._convert_idx_params(space, w_start, w_end) sub = self._op_val(space, w_sub, allow_char=True) if self._use_rstr_ops(space, w_sub): res = value.rfind(sub, start, end) else: res = rfind(value, sub, start, end) if ofs is not None and res >= 0: res -= ofs return space.newint(res) def descr_index(self, space, w_sub, w_start=None, w_end=None): value, start, end, ofs = self._convert_idx_params(space, w_start, w_end) sub = self._op_val(space, w_sub, allow_char=True) if self._use_rstr_ops(space, w_sub): res = value.find(sub, start, end) else: res = find(value, sub, start, end) if res < 0: raise oefmt(space.w_ValueError, "substring not found in " + self._KIND2 + ".index") if ofs is not None: res -= ofs return space.newint(res) def descr_rindex(self, space, w_sub, w_start=None, w_end=None): value, start, end, ofs = self._convert_idx_params(space, w_start, w_end) sub = self._op_val(space, w_sub, allow_char=True) if self._use_rstr_ops(space, w_sub): res = value.rfind(sub, start, end) else: res = rfind(value, sub, start, end) if res < 0: raise oefmt(space.w_ValueError, "substring not found in " + self._KIND2 + ".rindex") if ofs is not None: res -= ofs return space.newint(res) @specialize.arg(2) def _is_generic(self, space, func_name): func = getattr(self, func_name) v = self._val(space) if len(v) == 0: return space.w_False if len(v) == 1: c = v[0] return space.newbool(func(c)) else: return self._is_generic_loop(space, v, func_name) @specialize.arg(3) def _is_generic_loop(self, space, v, func_name): func = getattr(self, func_name) for idx in range(len(v)): if not func(v[idx]): return space.w_False return space.w_True def descr_isalnum(self, space): return self._is_generic(space, '_isalnum') def descr_isalpha(self, space): return self._is_generic(space, '_isalpha') def descr_isdigit(self, space): return self._is_generic(space, '_isdigit') # this is only for bytes and bytesarray: unicodeobject overrides it def _descr_islower_slowpath(self, space, v): cased = False for idx in range(len(v)): if self._isupper(v[idx]): return False elif not cased and self._islower(v[idx]): cased = True return cased def descr_islower(self, space): v = self._val(space) if len(v) == 1: c = v[0] return space.newbool(self._islower(c)) cased = self._descr_islower_slowpath(space, v) return space.newbool(cased) def descr_isspace(self, space): return self._is_generic(space, '_isspace') def descr_istitle(self, space): input = self._val(space) cased = False previous_is_cased = False for pos in range(0, len(input)): ch = input[pos] if self._istitle(ch): if previous_is_cased: return space.w_False previous_is_cased = True cased = True elif self._islower(ch): if not previous_is_cased: return space.w_False cased = True else: previous_is_cased = False return space.newbool(cased) # this is only for bytes and bytesarray: unicodeobject overrides it def _descr_isupper_slowpath(self, space, v): cased = False for idx in range(len(v)): if self._islower(v[idx]): return False elif not cased and self._isupper(v[idx]): cased = True return cased def descr_isupper(self, space): v = self._val(space) if len(v) == 1: c = v[0] return space.newbool(self._isupper(c)) cased = self._descr_isupper_slowpath(space, v) return space.newbool(cased) def descr_join(self, space, w_list): list_w = space.listview(w_list) size = len(list_w) if size == 0: return self._empty() if size == 1: w_s = list_w[0] # only one item, return it if it's not a subclass of str if self._join_return_one(space, w_s): return w_s return self._str_join_many_items(space, list_w, size) @jit.look_inside_iff(lambda self, space, list_w, size: jit.loop_unrolling_heuristic(list_w, size)) def _str_join_many_items(self, space, list_w, size): value = self._val(space) prealloc_size = len(value) * (size - 1) unwrapped = newlist_hint(size) for i in range(size): w_s = list_w[i] try: next_string = self._op_val(space, w_s) except OperationError as e: if not e.match(space, space.w_TypeError): raise raise oefmt(space.w_TypeError, "sequence item %d: expected %s, %T found", i, self._generic_name(), w_s) # XXX Maybe the extra copy here is okay? It was basically going to # happen anyway, what with being placed into the builder unwrapped.append(next_string) prealloc_size += len(unwrapped[i]) sb = self._builder(prealloc_size) for i in range(size): if value and i != 0: sb.append(value) sb.append(unwrapped[i]) return self._new(sb.build()) @unwrap_spec(width=int, w_fillchar=WrappedDefault(' ')) def descr_ljust(self, space, width, w_fillchar): value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: raise oefmt(space.w_TypeError, "ljust() argument 2 must be a single character") d = width - len(value) if d > 0: fillchar = self._multi_chr(fillchar[0]) value = value + fillchar * d return self._new(value) @unwrap_spec(width=int, w_fillchar=WrappedDefault(' ')) def descr_rjust(self, space, width, w_fillchar): value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: raise oefmt(space.w_TypeError, "rjust() argument 2 must be a single character") d = width - len(value) if d > 0: fillchar = self._multi_chr(fillchar[0]) value = d * fillchar + value return self._new(value) def descr_lower(self, space): value = self._val(space) builder = self._builder(len(value)) for i in range(len(value)): builder.append(self._lower_in_str(value, i)) return self._new(builder.build()) def _lower_in_str(self, value, i): # overridden in unicodeobject.py return self._lower(value[i]) # This is not used for W_UnicodeObject. def descr_partition(self, space, w_sub): from pypy.objspace.std.bytearrayobject import W_BytearrayObject value = self._val(space) if self._use_rstr_ops(space, w_sub): sub = self._op_val(space, w_sub) sublen = len(sub) if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = value.find(sub) else: sub = space.readbuf_w(w_sub) sublen = sub.getlength() if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = find(value, sub, 0, len(value)) if pos != -1 and isinstance(self, W_BytearrayObject): w_sub = self._new_from_buffer(sub) if pos == -1: if isinstance(self, W_BytearrayObject): self = self._new(value) return space.newtuple([self, self._empty(), self._empty()]) else: return space.newtuple( [self._sliced(space, value, 0, pos, self), w_sub, self._sliced(space, value, pos + sublen, len(value), self)]) def descr_rpartition(self, space, w_sub): from pypy.objspace.std.bytearrayobject import W_BytearrayObject value = self._val(space) if self._use_rstr_ops(space, w_sub): sub = self._op_val(space, w_sub) sublen = len(sub) if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = value.rfind(sub) else: sub = space.readbuf_w(w_sub) sublen = sub.getlength() if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = rfind(value, sub, 0, len(value)) if pos != -1 and isinstance(self, W_BytearrayObject): w_sub = self._new_from_buffer(sub) if pos == -1: if isinstance(self, W_BytearrayObject): self = self._new(value) return space.newtuple([self._empty(), self._empty(), self]) else: return space.newtuple( [self._sliced(space, value, 0, pos, self), w_sub, self._sliced(space, value, pos + sublen, len(value), self)]) @unwrap_spec(count=int) def descr_replace(self, space, w_old, w_new, count=-1): input = self._val(space) sub = self._op_val(space, w_old) by = self._op_val(space, w_new) # the following two lines are for being bug-to-bug compatible # with CPython: see issue #2448 if count >= 0 and len(input) == 0: return self._empty() try: res = replace(input, sub, by, count) except OverflowError: raise oefmt(space.w_OverflowError, "replace string is too long") return self._new(res) @unwrap_spec(maxsplit=int) def descr_split(self, space, w_sep=None, maxsplit=-1): res = [] value = self._val(space) if space.is_none(w_sep): res = split(value, maxsplit=maxsplit) return self._newlist_unwrapped(space, res) by = self._op_val(space, w_sep) if len(by) == 0: raise oefmt(space.w_ValueError, "empty separator") res = split(value, by, maxsplit) return self._newlist_unwrapped(space, res) @unwrap_spec(maxsplit=int) def descr_rsplit(self, space, w_sep=None, maxsplit=-1): res = [] value = self._val(space) if space.is_none(w_sep): res = rsplit(value, maxsplit=maxsplit) return self._newlist_unwrapped(space, res) by = self._op_val(space, w_sep) if len(by) == 0: raise oefmt(space.w_ValueError, "empty separator") res = rsplit(value, by, maxsplit) return self._newlist_unwrapped(space, res) @unwrap_spec(keepends=int) def descr_splitlines(self, space, keepends=False): value = self._val(space) length = len(value) strs = [] pos = 0 while pos < length: sol = pos while pos < length and not self._islinebreak(value[pos]): pos += 1 eol = pos pos += 1 # read CRLF as one line break if pos < length and value[eol] == '\r' and value[pos] == '\n': pos += 1 if keepends: eol = pos strs.append(value[sol:eol]) if pos < length: # XXX is this code reachable? strs.append(value[pos:length]) return self._newlist_unwrapped(space, strs) def _generic_name(self): return "bytes" # This is overridden in unicodeobject, _startswith_tuple is not. def descr_startswith(self, space, w_prefix, w_start=None, w_end=None): value, start, end, _ = self._convert_idx_params(space, w_start, w_end) if space.isinstance_w(w_prefix, space.w_tuple): return self._startswith_tuple(space, value, w_prefix, start, end) try: res = self._startswith(space, value, w_prefix, start, end) except OperationError as e: if not e.match(space, space.w_TypeError): raise wanted = self._generic_name() raise oefmt(space.w_TypeError, "startswith first arg must be %s or a tuple of %s, " "not %T", wanted, wanted, w_prefix) return space.newbool(res) def _startswith_tuple(self, space, value, w_prefix, start, end): for w_prefix in space.fixedview(w_prefix): if self._startswith(space, value, w_prefix, start, end): return space.w_True return space.w_False # This is overridden in unicodeobject, _startswith_tuple is not. def _startswith(self, space, value, w_prefix, start, end): prefix = self._op_val(space, w_prefix) if start > len(value): return False return startswith(value, prefix, start, end) # This is overridden in unicodeobject, _endswith_tuple is not. def descr_endswith(self, space, w_suffix, w_start=None, w_end=None): value, start, end, _ = self._convert_idx_params(space, w_start, w_end) if space.isinstance_w(w_suffix, space.w_tuple): return self._endswith_tuple(space, value, w_suffix, start, end) try: res = self._endswith(space, value, w_suffix, start, end) except OperationError as e: if not e.match(space, space.w_TypeError): raise wanted = self._generic_name() raise oefmt(space.w_TypeError, "endswith first arg must be %s or a tuple of %s, not " "%T", wanted, wanted, w_suffix) return space.newbool(res) def _endswith_tuple(self, space, value, w_suffix, start, end): for w_suffix in space.fixedview(w_suffix): if self._endswith(space, value, w_suffix, start, end): return space.w_True return space.w_False # This is overridden in unicodeobject, but _endswith_tuple is not. def _endswith(self, space, value, w_prefix, start, end): prefix = self._op_val(space, w_prefix) if start > len(value): return False return endswith(value, prefix, start, end) def _strip(self, space, w_chars, left, right, name='strip'): "internal function called by str_xstrip methods" value = self._val(space) chars = self._op_val(space, w_chars) lpos = 0 rpos = len(value) if left: while lpos < rpos and value[lpos] in chars: lpos += 1 if right: while rpos > lpos and value[rpos - 1] in chars: rpos -= 1 assert rpos >= lpos # annotator hint, don't remove return self._sliced(space, value, lpos, rpos, self) def _strip_none(self, space, left, right): "internal function called by str_xstrip methods" value = self._val(space) lpos = 0 rpos = len(value) if left: while lpos < rpos and self._isspace(value[lpos]): lpos += 1 if right: while rpos > lpos and self._isspace(value[rpos - 1]): rpos -= 1 assert rpos >= lpos # annotator hint, don't remove return self._sliced(space, value, lpos, rpos, self) def descr_strip(self, space, w_chars=None): if space.is_none(w_chars): return self._strip_none(space, left=1, right=1) return self._strip(space, w_chars, left=1, right=1, name='strip') def descr_lstrip(self, space, w_chars=None): if space.is_none(w_chars): return self._strip_none(space, left=1, right=0) return self._strip(space, w_chars, left=1, right=0, name='lstrip') def descr_rstrip(self, space, w_chars=None): if space.is_none(w_chars): return self._strip_none(space, left=0, right=1) return self._strip(space, w_chars, left=0, right=1, name='rstrip') def descr_swapcase(self, space): selfvalue = self._val(space) builder = self._builder(len(selfvalue)) for i in range(len(selfvalue)): ch = selfvalue[i] if self._isupper(ch): builder.append(self._lower_in_str(selfvalue, i)) elif self._islower(ch): builder.append(self._upper(ch)) else: builder.append(ch) return self._new(builder.build()) def descr_title(self, space): selfval = self._val(space) if len(selfval) == 0: return self return self._new(self.title(selfval)) @jit.elidable def title(self, value): builder = self._builder(len(value)) previous_is_cased = False for i in range(len(value)): ch = value[i] if not previous_is_cased: builder.append(self._title(ch)) else: builder.append(self._lower_in_str(value, i)) previous_is_cased = self._iscased(ch) return builder.build() DEFAULT_NOOP_TABLE = ''.join([chr(i) for i in range(256)]) # for bytes and bytearray, overridden by unicode @unwrap_spec(w_delete=WrappedDefault('')) def descr_translate(self, space, w_table, w_delete): if space.is_w(w_table, space.w_None): table = self.DEFAULT_NOOP_TABLE else: table = self._op_val(space, w_table) if len(table) != 256: raise oefmt(space.w_ValueError, "translation table must be 256 characters long") string = self._val(space) deletechars = self._op_val(space, w_delete) if len(deletechars) == 0: buf = self._builder(len(string)) for char in string: buf.append(table[ord(char)]) else: # XXX Why not preallocate here too? buf = self._builder() deletion_table = [False] * 256 for i in range(len(deletechars)): deletion_table[ord(deletechars[i])] = True for char in string: if not deletion_table[ord(char)]: buf.append(table[ord(char)]) return self._new(buf.build()) def descr_upper(self, space): value = self._val(space) builder = self._builder(len(value)) for i in range(len(value)): builder.append(self._upper(value[i])) return self._new(builder.build()) @unwrap_spec(width=int) def descr_zfill(self, space, width): selfval = self._val(space) if len(selfval) == 0: return self._new(self._multi_chr(self._chr('0')) * width) num_zeros = width - len(selfval) if num_zeros <= 0: # cannot return self, in case it is a subclass of str return self._new(selfval) builder = self._builder(width) if len(selfval) > 0 and (selfval[0] == '+' or selfval[0] == '-'): # copy sign to first position builder.append(selfval[0]) start = 1 else: start = 0 builder.append_multiple_char(self._chr('0'), num_zeros) builder.append_slice(selfval, start, len(selfval)) return self._new(builder.build()) def descr_getnewargs(self, space): return space.newtuple([self._new(self._val(space))])
class StringMethods(object): def _sliced(self, space, s, start, stop, orig_obj): assert start >= 0 assert stop >= 0 #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), # space.w_str): # return orig_obj return self._new(s[start:stop]) @specialize.arg(4) def _convert_idx_params(self, space, w_start, w_end, upper_bound=False): value = self._val(space) lenself = len(value) start, end = unwrap_start_stop(space, lenself, w_start, w_end, upper_bound=upper_bound) return (value, start, end) def _multi_chr(self, c): return c def descr_len(self, space): return space.wrap(self._len()) #def descr_iter(self, space): # pass def descr_contains(self, space, w_sub): value = self._val(space) if self._use_rstr_ops(space, w_sub): other = self._op_val(space, w_sub) return space.newbool(value.find(other) >= 0) from pypy.objspace.std.bytesobject import W_BytesObject if isinstance(w_sub, W_BytesObject): other = self._op_val(space, w_sub) res = find(value, other, 0, len(value)) else: buffer = _get_buffer(space, w_sub) res = find(value, buffer, 0, len(value)) return space.newbool(res >= 0) def descr_add(self, space, w_other): if self._use_rstr_ops(space, w_other): try: other = self._op_val(space, w_other) except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise return self._new(self._val(space) + other) # Bytearray overrides this method, CPython doesn't support contacting # buffers and strs, and unicodes are always handled above return space.w_NotImplemented def descr_mul(self, space, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise if times <= 0: return self._empty() if self._len() == 1: return self._new(self._multi_chr(self._val(space)[0]) * times) return self._new(self._val(space) * times) descr_rmul = descr_mul def descr_getitem(self, space, w_index): if isinstance(w_index, W_SliceObject): selfvalue = self._val(space) length = len(selfvalue) start, stop, step, sl = w_index.indices4(space, length) if sl == 0: return self._empty() elif step == 1: assert start >= 0 and stop >= 0 return self._sliced(space, selfvalue, start, stop, self) else: ret = _descr_getslice_slowpath(selfvalue, start, step, sl) return self._new_from_list(ret) index = space.getindex_w(w_index, space.w_IndexError, "string index") return self._getitem_result(space, index) def _getitem_result(self, space, index): selfvalue = self._val(space) try: character = selfvalue[index] except IndexError: raise oefmt(space.w_IndexError, "string index out of range") return self._new(character) def descr_getslice(self, space, w_start, w_stop): selfvalue = self._val(space) start, stop = normalize_simple_slice(space, len(selfvalue), w_start, w_stop) if start == stop: return self._empty() else: return self._sliced(space, selfvalue, start, stop, self) def descr_capitalize(self, space): value = self._val(space) if len(value) == 0: return self._empty() builder = self._builder(len(value)) builder.append(self._upper(value[0])) for i in range(1, len(value)): builder.append(self._lower(value[i])) return self._new(builder.build()) @unwrap_spec(width=int, w_fillchar=WrappedDefault(' ')) def descr_center(self, space, width, w_fillchar): value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: raise oefmt(space.w_TypeError, "center() argument 2 must be a single character") d = width - len(value) if d > 0: offset = d//2 + (d & width & 1) fillchar = self._multi_chr(fillchar[0]) centered = offset * fillchar + value + (d - offset) * fillchar else: centered = value return self._new(centered) def descr_count(self, space, w_sub, w_start=None, w_end=None): value, start, end = self._convert_idx_params(space, w_start, w_end) if self._use_rstr_ops(space, w_sub): return space.newint(value.count(self._op_val(space, w_sub), start, end)) from pypy.objspace.std.bytearrayobject import W_BytearrayObject from pypy.objspace.std.bytesobject import W_BytesObject if isinstance(w_sub, W_BytearrayObject): res = count(value, w_sub.data, start, end) elif isinstance(w_sub, W_BytesObject): res = count(value, w_sub._value, start, end) else: buffer = _get_buffer(space, w_sub) res = count(value, buffer, start, end) return space.wrap(max(res, 0)) def descr_decode(self, space, w_encoding=None, w_errors=None): from pypy.objspace.std.unicodeobject import ( _get_encoding_and_errors, decode_object, unicode_from_string) encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) from pypy.objspace.std.bytearrayobject import W_BytearrayObject if (encoding is None and errors is None and not isinstance(self, W_BytearrayObject)): return unicode_from_string(space, self) return decode_object(space, self, encoding, errors) def descr_encode(self, space, w_encoding=None, w_errors=None): from pypy.objspace.std.unicodeobject import ( _get_encoding_and_errors, encode_object) encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) return encode_object(space, self, encoding, errors) @unwrap_spec(tabsize=int) def descr_expandtabs(self, space, tabsize=8): value = self._val(space) if not value: return self._empty() if self._use_rstr_ops(space, self): splitted = value.split(self._chr('\t')) else: splitted = split(value, self._chr('\t')) try: ovfcheck(len(splitted) * tabsize) except OverflowError: raise oefmt(space.w_OverflowError, "new string is too long") expanded = oldtoken = splitted.pop(0) for token in splitted: expanded += self._multi_chr(self._chr(' ')) * self._tabindent(oldtoken, tabsize) + token oldtoken = token return self._new(expanded) def _tabindent(self, token, tabsize): """calculates distance behind the token to the next tabstop""" distance = tabsize if token: distance = 0 offset = len(token) while 1: if token[offset-1] == "\n" or token[offset-1] == "\r": break distance += 1 offset -= 1 if offset == 0: break # the same like distance = len(token) - (offset + 1) distance = (tabsize - distance) % tabsize if distance == 0: distance = tabsize return distance def descr_find(self, space, w_sub, w_start=None, w_end=None): (value, start, end) = self._convert_idx_params(space, w_start, w_end) if self._use_rstr_ops(space, w_sub): res = value.find(self._op_val(space, w_sub), start, end) return space.wrap(res) from pypy.objspace.std.bytearrayobject import W_BytearrayObject from pypy.objspace.std.bytesobject import W_BytesObject if isinstance(w_sub, W_BytearrayObject): res = find(value, w_sub.data, start, end) elif isinstance(w_sub, W_BytesObject): res = find(value, w_sub._value, start, end) else: buffer = _get_buffer(space, w_sub) res = find(value, buffer, start, end) return space.wrap(res) def descr_rfind(self, space, w_sub, w_start=None, w_end=None): (value, start, end) = self._convert_idx_params(space, w_start, w_end) if self._use_rstr_ops(space, w_sub): res = value.rfind(self._op_val(space, w_sub), start, end) return space.wrap(res) from pypy.objspace.std.bytearrayobject import W_BytearrayObject from pypy.objspace.std.bytesobject import W_BytesObject if isinstance(w_sub, W_BytearrayObject): res = rfind(value, w_sub.data, start, end) elif isinstance(w_sub, W_BytesObject): res = rfind(value, w_sub._value, start, end) else: buffer = _get_buffer(space, w_sub) res = rfind(value, buffer, start, end) return space.wrap(res) def descr_index(self, space, w_sub, w_start=None, w_end=None): (value, start, end) = self._convert_idx_params(space, w_start, w_end) from pypy.objspace.std.bytearrayobject import W_BytearrayObject from pypy.objspace.std.bytesobject import W_BytesObject if self._use_rstr_ops(space, w_sub): res = value.find(self._op_val(space, w_sub), start, end) elif isinstance(w_sub, W_BytearrayObject): res = find(value, w_sub.data, start, end) elif isinstance(w_sub, W_BytesObject): res = find(value, w_sub._value, start, end) else: buffer = _get_buffer(space, w_sub) res = find(value, buffer, start, end) if res < 0: raise oefmt(space.w_ValueError, "substring not found in string.index") return space.wrap(res) def descr_rindex(self, space, w_sub, w_start=None, w_end=None): (value, start, end) = self._convert_idx_params(space, w_start, w_end) from pypy.objspace.std.bytearrayobject import W_BytearrayObject from pypy.objspace.std.bytesobject import W_BytesObject if self._use_rstr_ops(space, w_sub): res = value.rfind(self._op_val(space, w_sub), start, end) elif isinstance(w_sub, W_BytearrayObject): res = rfind(value, w_sub.data, start, end) elif isinstance(w_sub, W_BytesObject): res = rfind(value, w_sub._value, start, end) else: buffer = _get_buffer(space, w_sub) res = rfind(value, buffer, start, end) if res < 0: raise oefmt(space.w_ValueError, "substring not found in string.rindex") return space.wrap(res) @specialize.arg(2) def _is_generic(self, space, func_name): func = getattr(self, func_name) v = self._val(space) if len(v) == 0: return space.w_False if len(v) == 1: c = v[0] return space.newbool(func(c)) else: return self._is_generic_loop(space, v, func_name) @specialize.arg(3) def _is_generic_loop(self, space, v, func_name): func = getattr(self, func_name) for idx in range(len(v)): if not func(v[idx]): return space.w_False return space.w_True def descr_isalnum(self, space): return self._is_generic(space, '_isalnum') def descr_isalpha(self, space): return self._is_generic(space, '_isalpha') def descr_isdigit(self, space): return self._is_generic(space, '_isdigit') # this is only for bytes and bytesarray: unicodeobject overrides it def _descr_islower_slowpath(self, space, v): cased = False for idx in range(len(v)): if self._isupper(v[idx]): return False elif not cased and self._islower(v[idx]): cased = True return cased def descr_islower(self, space): v = self._val(space) if len(v) == 1: c = v[0] return space.newbool(self._islower(c)) cased = self._descr_islower_slowpath(space, v) return space.newbool(cased) def descr_isspace(self, space): return self._is_generic(space, '_isspace') def descr_istitle(self, space): input = self._val(space) cased = False previous_is_cased = False for pos in range(0, len(input)): ch = input[pos] if self._istitle(ch): if previous_is_cased: return space.w_False previous_is_cased = True cased = True elif self._islower(ch): if not previous_is_cased: return space.w_False cased = True else: previous_is_cased = False return space.newbool(cased) # this is only for bytes and bytesarray: unicodeobject overrides it def _descr_isupper_slowpath(self, space, v): cased = False for idx in range(len(v)): if self._islower(v[idx]): return False elif not cased and self._isupper(v[idx]): cased = True return cased def descr_isupper(self, space): v = self._val(space) if len(v) == 1: c = v[0] return space.newbool(self._isupper(c)) cased = self._descr_isupper_slowpath(space, v) return space.newbool(cased) def descr_join(self, space, w_list): list_w = space.listview(w_list) size = len(list_w) if size == 0: return self._empty() if size == 1: w_s = list_w[0] # only one item, return it if it's not a subclass of str if self._join_return_one(space, w_s): return w_s return self._str_join_many_items(space, list_w, size) @jit.look_inside_iff(lambda self, space, list_w, size: jit.loop_unrolling_heuristic(list_w, size)) def _str_join_many_items(self, space, list_w, size): value = self._val(space) prealloc_size = len(value) * (size - 1) unwrapped = newlist_hint(size) for i in range(size): w_s = list_w[i] check_item = self._join_check_item(space, w_s) if check_item == 1: raise oefmt(space.w_TypeError, "sequence item %d: expected string, %T found", i, w_s) elif check_item == 2: return self._join_autoconvert(space, list_w) # XXX Maybe the extra copy here is okay? It was basically going to # happen anyway, what with being placed into the builder unwrapped.append(self._op_val(space, w_s)) prealloc_size += len(unwrapped[i]) sb = self._builder(prealloc_size) for i in range(size): if value and i != 0: sb.append(value) sb.append(unwrapped[i]) return self._new(sb.build()) def _join_autoconvert(self, space, list_w): assert False, 'unreachable' @unwrap_spec(width=int, w_fillchar=WrappedDefault(' ')) def descr_ljust(self, space, width, w_fillchar): value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: raise oefmt(space.w_TypeError, "ljust() argument 2 must be a single character") d = width - len(value) if d > 0: fillchar = self._multi_chr(fillchar[0]) value = value + fillchar * d return self._new(value) @unwrap_spec(width=int, w_fillchar=WrappedDefault(' ')) def descr_rjust(self, space, width, w_fillchar): value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: raise oefmt(space.w_TypeError, "rjust() argument 2 must be a single character") d = width - len(value) if d > 0: fillchar = self._multi_chr(fillchar[0]) value = d * fillchar + value return self._new(value) def descr_lower(self, space): value = self._val(space) builder = self._builder(len(value)) for i in range(len(value)): builder.append(self._lower(value[i])) return self._new(builder.build()) def descr_partition(self, space, w_sub): from pypy.objspace.std.bytearrayobject import W_BytearrayObject value = self._val(space) if self._use_rstr_ops(space, w_sub): sub = self._op_val(space, w_sub) sublen = len(sub) if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = value.find(sub) else: sub = _get_buffer(space, w_sub) sublen = sub.getlength() if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = find(value, sub, 0, len(value)) if pos != -1 and isinstance(self, W_BytearrayObject): w_sub = self._new_from_buffer(sub) if pos == -1: if isinstance(self, W_BytearrayObject): self = self._new(value) return space.newtuple([self, self._empty(), self._empty()]) else: return space.newtuple( [self._sliced(space, value, 0, pos, self), w_sub, self._sliced(space, value, pos + sublen, len(value), self)]) def descr_rpartition(self, space, w_sub): from pypy.objspace.std.bytearrayobject import W_BytearrayObject value = self._val(space) if self._use_rstr_ops(space, w_sub): sub = self._op_val(space, w_sub) sublen = len(sub) if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = value.rfind(sub) else: sub = _get_buffer(space, w_sub) sublen = sub.getlength() if sublen == 0: raise oefmt(space.w_ValueError, "empty separator") pos = rfind(value, sub, 0, len(value)) if pos != -1 and isinstance(self, W_BytearrayObject): w_sub = self._new_from_buffer(sub) if pos == -1: if isinstance(self, W_BytearrayObject): self = self._new(value) return space.newtuple([self._empty(), self._empty(), self]) else: return space.newtuple( [self._sliced(space, value, 0, pos, self), w_sub, self._sliced(space, value, pos + sublen, len(value), self)]) @unwrap_spec(count=int) def descr_replace(self, space, w_old, w_new, count=-1): input = self._val(space) sub = self._op_val(space, w_old) by = self._op_val(space, w_new) try: res = replace(input, sub, by, count) except OverflowError: raise oefmt(space.w_OverflowError, "replace string is too long") return self._new(res) @unwrap_spec(maxsplit=int) def descr_split(self, space, w_sep=None, maxsplit=-1): res = [] value = self._val(space) if space.is_none(w_sep): res = split(value, maxsplit=maxsplit) return self._newlist_unwrapped(space, res) by = self._op_val(space, w_sep) if len(by) == 0: raise oefmt(space.w_ValueError, "empty separator") res = split(value, by, maxsplit) return self._newlist_unwrapped(space, res) @unwrap_spec(maxsplit=int) def descr_rsplit(self, space, w_sep=None, maxsplit=-1): res = [] value = self._val(space) if space.is_none(w_sep): res = rsplit(value, maxsplit=maxsplit) return self._newlist_unwrapped(space, res) by = self._op_val(space, w_sep) if len(by) == 0: raise oefmt(space.w_ValueError, "empty separator") res = rsplit(value, by, maxsplit) return self._newlist_unwrapped(space, res) @unwrap_spec(keepends=bool) def descr_splitlines(self, space, keepends=False): value = self._val(space) length = len(value) strs = [] pos = 0 while pos < length: sol = pos while pos < length and not self._islinebreak(value[pos]): pos += 1 eol = pos pos += 1 # read CRLF as one line break if pos < length and value[eol] == '\r' and value[pos] == '\n': pos += 1 if keepends: eol = pos strs.append(value[sol:eol]) if pos < length: strs.append(value[pos:length]) return self._newlist_unwrapped(space, strs) def descr_startswith(self, space, w_prefix, w_start=None, w_end=None): (value, start, end) = self._convert_idx_params(space, w_start, w_end, True) if space.isinstance_w(w_prefix, space.w_tuple): for w_prefix in space.fixedview(w_prefix): if self._startswith(space, value, w_prefix, start, end): return space.w_True return space.w_False return space.newbool(self._startswith(space, value, w_prefix, start, end)) def _startswith(self, space, value, w_prefix, start, end): return startswith(value, self._op_val(space, w_prefix), start, end) def descr_endswith(self, space, w_suffix, w_start=None, w_end=None): (value, start, end) = self._convert_idx_params(space, w_start, w_end, True) if space.isinstance_w(w_suffix, space.w_tuple): for w_suffix in space.fixedview(w_suffix): if self._endswith(space, value, w_suffix, start, end): return space.w_True return space.w_False return space.newbool(self._endswith(space, value, w_suffix, start, end)) def _endswith(self, space, value, w_prefix, start, end): return endswith(value, self._op_val(space, w_prefix), start, end) def _strip(self, space, w_chars, left, right): "internal function called by str_xstrip methods" value = self._val(space) chars = self._op_val(space, w_chars) lpos = 0 rpos = len(value) if left: while lpos < rpos and value[lpos] in chars: lpos += 1 if right: while rpos > lpos and value[rpos - 1] in chars: rpos -= 1 assert rpos >= lpos # annotator hint, don't remove return self._sliced(space, value, lpos, rpos, self) def _strip_none(self, space, left, right): "internal function called by str_xstrip methods" value = self._val(space) lpos = 0 rpos = len(value) if left: while lpos < rpos and self._isspace(value[lpos]): lpos += 1 if right: while rpos > lpos and self._isspace(value[rpos - 1]): rpos -= 1 assert rpos >= lpos # annotator hint, don't remove return self._sliced(space, value, lpos, rpos, self) def descr_strip(self, space, w_chars=None): if space.is_none(w_chars): return self._strip_none(space, left=1, right=1) return self._strip(space, w_chars, left=1, right=1) def descr_lstrip(self, space, w_chars=None): if space.is_none(w_chars): return self._strip_none(space, left=1, right=0) return self._strip(space, w_chars, left=1, right=0) def descr_rstrip(self, space, w_chars=None): if space.is_none(w_chars): return self._strip_none(space, left=0, right=1) return self._strip(space, w_chars, left=0, right=1) def descr_swapcase(self, space): selfvalue = self._val(space) builder = self._builder(len(selfvalue)) for i in range(len(selfvalue)): ch = selfvalue[i] if self._isupper(ch): builder.append(self._lower(ch)) elif self._islower(ch): builder.append(self._upper(ch)) else: builder.append(ch) return self._new(builder.build()) def descr_title(self, space): selfval = self._val(space) if len(selfval) == 0: return self return self._new(self.title(selfval)) @jit.elidable def title(self, value): builder = self._builder(len(value)) previous_is_cased = False for ch in value: if not previous_is_cased: builder.append(self._title(ch)) else: builder.append(self._lower(ch)) previous_is_cased = self._iscased(ch) return builder.build() DEFAULT_NOOP_TABLE = ''.join([chr(i) for i in range(256)]) # for bytes and bytearray, overridden by unicode @unwrap_spec(w_deletechars=WrappedDefault('')) def descr_translate(self, space, w_table, w_deletechars): if space.is_w(w_table, space.w_None): table = self.DEFAULT_NOOP_TABLE else: table = self._op_val(space, w_table) if len(table) != 256: raise oefmt(space.w_ValueError, "translation table must be 256 characters long") string = self._val(space) deletechars = self._op_val(space, w_deletechars) if len(deletechars) == 0: buf = self._builder(len(string)) for char in string: buf.append(table[ord(char)]) else: # XXX Why not preallocate here too? buf = self._builder() deletion_table = [False] * 256 for i in range(len(deletechars)): deletion_table[ord(deletechars[i])] = True for char in string: if not deletion_table[ord(char)]: buf.append(table[ord(char)]) return self._new(buf.build()) def descr_upper(self, space): value = self._val(space) builder = self._builder(len(value)) for i in range(len(value)): builder.append(self._upper(value[i])) return self._new(builder.build()) @unwrap_spec(width=int) def descr_zfill(self, space, width): selfval = self._val(space) if len(selfval) == 0: return self._new(self._multi_chr(self._chr('0')) * width) num_zeros = width - len(selfval) if num_zeros <= 0: # cannot return self, in case it is a subclass of str return self._new(selfval) builder = self._builder(width) if len(selfval) > 0 and (selfval[0] == '+' or selfval[0] == '-'): # copy sign to first position builder.append(selfval[0]) start = 1 else: start = 0 builder.append_multiple_char(self._chr('0'), num_zeros) builder.append_slice(selfval, start, len(selfval)) return self._new(builder.build()) def descr_getnewargs(self, space): return space.newtuple([self._new(self._val(space))])
def unrolling_heuristic(self, w_vector): storage = self._storage(w_vector) return jit.loop_unrolling_heuristic(storage, w_vector.len, UNROLLING_CUTOFF)
from pycket.values import W_MVector, W_VectorSuper, W_Fixnum, W_Flonum, W_Character, UNROLLING_CUTOFF, wrap from pycket.base import W_Object, SingletonMeta, UnhashableType from pycket import config from rpython.rlib import debug, jit, objectmodel, rerased from rpython.rlib.longlong2float import (can_encode_int32, decode_int32_from_longlong_nan, encode_int32_into_longlong_nan, float2longlong, is_int32_from_longlong_nan, longlong2float) from rpython.rlib.objectmodel import import_from_mixin, specialize, we_are_translated from rpython.rlib.rarithmetic import intmask @jit.look_inside_iff(lambda elements, immutable: jit.loop_unrolling_heuristic( elements, len(elements), UNROLLING_CUTOFF)) def _find_strategy_class(elements, immutable): if not config.strategies or len(elements) == 0: # An empty vector stays empty forever. Don't implement special EmptyVectorStrategy. if immutable: return ObjectImmutableVectorStrategy.singleton return ObjectVectorStrategy.singleton single_class = type(elements[0]) for elem in elements: if not isinstance(elem, single_class): if immutable: return ObjectImmutableVectorStrategy.singleton return ObjectVectorStrategy.singleton if single_class is W_Fixnum: if immutable: return FixnumImmutableVectorStrategy.singleton
from pycket.values import W_MVector, W_VectorSuper, W_Fixnum, W_Flonum, W_Character, UNROLLING_CUTOFF from pycket.base import W_Object, SingletonMeta from pycket import config from rpython.rlib import rerased from rpython.rlib.objectmodel import newlist_hint, import_from_mixin from rpython.rlib import debug, jit @jit.look_inside_iff( lambda elements, immutable: jit.loop_unrolling_heuristic(elements, len(elements), UNROLLING_CUTOFF) ) def _find_strategy_class(elements, immutable): if not config.strategies or len(elements) == 0: # An empty vector stays empty forever. Don't implement special EmptyVectorStrategy. return ObjectVectorStrategy.singleton single_class = type(elements[0]) for elem in elements: if not isinstance(elem, single_class): if immutable: return ObjectImmutableVectorStrategy.singleton return ObjectVectorStrategy.singleton if single_class is W_Fixnum: if immutable: return FixnumImmutableVectorStrategy.singleton return FixnumVectorStrategy.singleton if single_class is W_Flonum: if immutable: return FlonumImmutableVectorStrategy.singleton return FlonumVectorStrategy.singleton if single_class is W_Character:
def _unroll_condition_cmp(self, space, other): return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF))
return self.arity def call(self, args, env, cont): return self.call_with_extra_info(args, env, cont, None) def call_with_extra_info(self, args, env, cont, extra_call_info): jit.promote(self) return self.code(args, env, cont, extra_call_info) def tostring(self): return "#<procedure:%s>" % self.name.variable_name() def to_list(l): return to_improper(l, w_null) @jit.look_inside_iff( lambda l, curr: jit.loop_unrolling_heuristic(l, len(l), UNROLLING_CUTOFF)) def to_improper(l, curr): for i in range(len(l) - 1, -1, -1): curr = W_Cons.make(l[i], curr) return curr @jit.look_inside_iff( lambda v, curr: jit.loop_unrolling_heuristic(v, v.len, UNROLLING_CUTOFF)) def vector_to_improper(v, curr): for i in range(v.len - 1, -1, -1): curr = W_Cons.make(v.ref(i), curr) return curr def to_mlist(l): return to_mimproper(l, w_null) @jit.look_inside_iff(
class LLHelpers(AbstractLLHelpers): from rpython.rtyper.annlowlevel import llstr, llunicode @staticmethod @jit.elidable def ll_str_mul(s, times): if times < 0: times = 0 try: size = ovfcheck(len(s.chars) * times) except OverflowError: raise MemoryError newstr = s.malloc(size) i = 0 if i < size: s.copy_contents(s, newstr, 0, 0, len(s.chars)) i += len(s.chars) while i < size: if i <= size - i: j = i else: j = size - i s.copy_contents(newstr, newstr, 0, i, j) i += j return newstr @staticmethod @jit.elidable def ll_char_mul(ch, times): if typeOf(ch) is Char: malloc = mallocstr else: malloc = mallocunicode if times < 0: times = 0 newstr = malloc(times) j = 0 # XXX we can use memset here, not sure how useful this is while j < times: newstr.chars[j] = ch j += 1 return newstr @staticmethod def ll_strlen(s): return len(s.chars) @staticmethod @signature(types.any(), types.int(), returns=types.any()) def ll_stritem_nonneg(s, i): chars = s.chars ll_assert(i >= 0, "negative str getitem index") ll_assert(i < len(chars), "str getitem index out of bound") return chars[i] @staticmethod def ll_chr2str(ch): if typeOf(ch) is Char: malloc = mallocstr else: malloc = mallocunicode s = malloc(1) s.chars[0] = ch return s # @jit.look_inside_iff(lambda str: jit.isconstant(len(str.chars)) and len(str.chars) == 1) @staticmethod @jit.oopspec("str.str2unicode(str)") def ll_str2unicode(str): lgt = len(str.chars) s = mallocunicode(lgt) for i in range(lgt): if ord(str.chars[i]) > 127: raise UnicodeDecodeError s.chars[i] = cast_primitive(UniChar, str.chars[i]) return s @staticmethod def ll_str2bytearray(str): from rpython.rtyper.lltypesystem.rbytearray import BYTEARRAY lgt = len(str.chars) b = malloc(BYTEARRAY, lgt) for i in range(lgt): b.chars[i] = str.chars[i] return b @staticmethod def ll_strhash(s): if s: return jit.conditional_call_elidable(s.hash, LLHelpers._ll_strhash, s) else: return 0 @staticmethod @dont_inline @jit.dont_look_inside def _ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the # special non-computed-yet value. Also, jit.conditional_call_elidable # always checks for zero, for now. x = ll_hash_string(s) if x == 0: x = 29872897 s.hash = x return x @staticmethod def ll_length(s): return len(s.chars) @staticmethod def ll_strfasthash(s): ll_assert(s.hash != 0, "ll_strfasthash: hash==0") return s.hash # assumes that the hash is already computed @staticmethod @jit.elidable @jit.oopspec('stroruni.concat(s1, s2)') def ll_strconcat(s1, s2): len1 = s1.length() len2 = s2.length() # a single '+' like this is allowed to overflow: it gets # a negative result, and the gc will complain # the typechecks below are if TP == BYTEARRAY if typeOf(s1) == Ptr(STR): newstr = s2.malloc(len1 + len2) newstr.copy_contents_from_str(s1, newstr, 0, 0, len1) else: newstr = s1.malloc(len1 + len2) newstr.copy_contents(s1, newstr, 0, 0, len1) if typeOf(s2) == Ptr(STR): newstr.copy_contents_from_str(s2, newstr, 0, len1, len2) else: newstr.copy_contents(s2, newstr, 0, len1, len2) return newstr @staticmethod @jit.elidable def ll_strip(s, ch, left, right): s_len = len(s.chars) if s_len == 0: return s.empty() lpos = 0 rpos = s_len - 1 if left: while lpos < rpos and s.chars[lpos] == ch: lpos += 1 if right: while lpos < rpos + 1 and s.chars[rpos] == ch: rpos -= 1 if rpos < lpos: return s.empty() r_len = rpos - lpos + 1 result = s.malloc(r_len) s.copy_contents(s, result, lpos, 0, r_len) return result @staticmethod @jit.elidable def ll_strip_default(s, left, right): s_len = len(s.chars) if s_len == 0: return s.empty() lpos = 0 rpos = s_len - 1 if left: while lpos < rpos and s.chars[lpos].isspace(): lpos += 1 if right: while lpos < rpos + 1 and s.chars[rpos].isspace(): rpos -= 1 if rpos < lpos: return s.empty() r_len = rpos - lpos + 1 result = s.malloc(r_len) s.copy_contents(s, result, lpos, 0, r_len) return result @staticmethod @jit.elidable def ll_strip_multiple(s, s2, left, right): s_len = len(s.chars) if s_len == 0: return s.empty() lpos = 0 rpos = s_len - 1 if left: while lpos < rpos and LLHelpers.ll_contains(s2, s.chars[lpos]): lpos += 1 if right: while lpos < rpos + 1 and LLHelpers.ll_contains(s2, s.chars[rpos]): rpos -= 1 if rpos < lpos: return s.empty() r_len = rpos - lpos + 1 result = s.malloc(r_len) s.copy_contents(s, result, lpos, 0, r_len) return result @staticmethod @jit.elidable def ll_upper(s): s_chars = s.chars s_len = len(s_chars) if s_len == 0: return s.empty() i = 0 result = mallocstr(s_len) # ^^^^^^^^^ specifically to explode on unicode while i < s_len: result.chars[i] = LLHelpers.ll_upper_char(s_chars[i]) i += 1 return result @staticmethod @jit.elidable def ll_lower(s): s_chars = s.chars s_len = len(s_chars) if s_len == 0: return s.empty() i = 0 result = mallocstr(s_len) # ^^^^^^^^^ specifically to explode on unicode while i < s_len: result.chars[i] = LLHelpers.ll_lower_char(s_chars[i]) i += 1 return result @staticmethod def ll_join(s, length, items): s_chars = s.chars s_len = len(s_chars) num_items = length if num_items == 0: return s.empty() itemslen = 0 i = 0 while i < num_items: try: itemslen = ovfcheck(itemslen + len(items[i].chars)) except OverflowError: raise MemoryError i += 1 try: seplen = ovfcheck(s_len * (num_items - 1)) except OverflowError: raise MemoryError # a single '+' at the end is allowed to overflow: it gets # a negative result, and the gc will complain result = s.malloc(itemslen + seplen) res_index = len(items[0].chars) s.copy_contents(items[0], result, 0, 0, res_index) i = 1 while i < num_items: s.copy_contents(s, result, 0, res_index, s_len) res_index += s_len lgt = len(items[i].chars) s.copy_contents(items[i], result, 0, res_index, lgt) res_index += lgt i += 1 return result @staticmethod @jit.elidable @jit.oopspec('stroruni.cmp(s1, s2)') def ll_strcmp(s1, s2): if not s1 and not s2: return True if not s1 or not s2: return False chars1 = s1.chars chars2 = s2.chars len1 = len(chars1) len2 = len(chars2) if len1 < len2: cmplen = len1 else: cmplen = len2 i = 0 while i < cmplen: diff = ord(chars1[i]) - ord(chars2[i]) if diff != 0: return diff i += 1 return len1 - len2 @staticmethod @jit.elidable @jit.oopspec('stroruni.equal(s1, s2)') def ll_streq(s1, s2): if s1 == s2: # also if both are NULLs return True if not s1 or not s2: return False len1 = len(s1.chars) len2 = len(s2.chars) if len1 != len2: return False j = 0 chars1 = s1.chars chars2 = s2.chars while j < len1: if chars1[j] != chars2[j]: return False j += 1 return True @staticmethod @jit.elidable def ll_startswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) if len1 < len2: return False j = 0 chars1 = s1.chars chars2 = s2.chars while j < len2: if chars1[j] != chars2[j]: return False j += 1 return True @staticmethod def ll_startswith_char(s, ch): if not len(s.chars): return False return s.chars[0] == ch @staticmethod @jit.elidable def ll_endswith(s1, s2): len1 = len(s1.chars) len2 = len(s2.chars) if len1 < len2: return False j = 0 chars1 = s1.chars chars2 = s2.chars offset = len1 - len2 while j < len2: if chars1[offset + j] != chars2[j]: return False j += 1 return True @staticmethod def ll_endswith_char(s, ch): if not len(s.chars): return False return s.chars[len(s.chars) - 1] == ch @staticmethod @jit.elidable @signature(types.any(), types.any(), types.int(), types.int(), returns=types.int()) def ll_find_char(s, ch, start, end): i = start if end > len(s.chars): end = len(s.chars) while i < end: if s.chars[i] == ch: return i i += 1 return -1 @staticmethod @jit.elidable @signature(types.any(), types.any(), types.int(), types.int(), returns=types.int()) def ll_rfind_char(s, ch, start, end): if end > len(s.chars): end = len(s.chars) i = end while i > start: i -= 1 if s.chars[i] == ch: return i return -1 @staticmethod @jit.elidable def ll_count_char(s, ch, start, end): count = 0 i = start if end > len(s.chars): end = len(s.chars) while i < end: if s.chars[i] == ch: count += 1 i += 1 return count @staticmethod @signature(types.any(), types.any(), types.int(), types.int(), returns=types.int()) def ll_find(s1, s2, start, end): if start < 0: start = 0 if end > len(s1.chars): end = len(s1.chars) if end - start < 0: return -1 m = len(s2.chars) if m == 1: return LLHelpers.ll_find_char(s1, s2.chars[0], start, end) return LLHelpers.ll_search(s1, s2, start, end, FAST_FIND) @staticmethod @signature(types.any(), types.any(), types.int(), types.int(), returns=types.int()) def ll_rfind(s1, s2, start, end): if start < 0: start = 0 if end > len(s1.chars): end = len(s1.chars) if end - start < 0: return -1 m = len(s2.chars) if m == 1: return LLHelpers.ll_rfind_char(s1, s2.chars[0], start, end) return LLHelpers.ll_search(s1, s2, start, end, FAST_RFIND) @classmethod def ll_count(cls, s1, s2, start, end): if start < 0: start = 0 if end > len(s1.chars): end = len(s1.chars) if end - start < 0: return 0 m = len(s2.chars) if m == 1: return cls.ll_count_char(s1, s2.chars[0], start, end) res = cls.ll_search(s1, s2, start, end, FAST_COUNT) assert res >= 0 return res @staticmethod @jit.elidable def ll_search(s1, s2, start, end, mode): count = 0 n = end - start m = len(s2.chars) if m == 0: if mode == FAST_COUNT: return end - start + 1 elif mode == FAST_RFIND: return end else: return start w = n - m if w < 0: if mode == FAST_COUNT: return 0 return -1 mlast = m - 1 skip = mlast - 1 mask = 0 if mode != FAST_RFIND: for i in range(mlast): mask = bloom_add(mask, s2.chars[i]) if s2.chars[i] == s2.chars[mlast]: skip = mlast - i - 1 mask = bloom_add(mask, s2.chars[mlast]) i = start - 1 while i + 1 <= start + w: i += 1 if s1.chars[i + m - 1] == s2.chars[m - 1]: for j in range(mlast): if s1.chars[i + j] != s2.chars[j]: break else: if mode != FAST_COUNT: return i count += 1 i += mlast continue if i + m < len(s1.chars): c = s1.chars[i + m] else: c = '\0' if not bloom(mask, c): i += m else: i += skip else: if i + m < len(s1.chars): c = s1.chars[i + m] else: c = '\0' if not bloom(mask, c): i += m else: mask = bloom_add(mask, s2.chars[0]) for i in range(mlast, 0, -1): mask = bloom_add(mask, s2.chars[i]) if s2.chars[i] == s2.chars[0]: skip = i - 1 i = start + w + 1 while i - 1 >= start: i -= 1 if s1.chars[i] == s2.chars[0]: for j in xrange(mlast, 0, -1): if s1.chars[i + j] != s2.chars[j]: break else: return i if i - 1 >= 0 and not bloom(mask, s1.chars[i - 1]): i -= m else: i -= skip else: if i - 1 >= 0 and not bloom(mask, s1.chars[i - 1]): i -= m if mode != FAST_COUNT: return -1 return count @staticmethod @signature(types.int(), types.any(), returns=types.any()) @jit.look_inside_iff( lambda length, items: jit.loop_unrolling_heuristic(items, length)) def ll_join_strs(length, items): # Special case for length 1 items, helps both the JIT and other code if length == 1: return items[0] num_items = length itemslen = 0 i = 0 while i < num_items: try: itemslen = ovfcheck(itemslen + len(items[i].chars)) except OverflowError: raise MemoryError i += 1 if typeOf(items).TO.OF.TO == STR: malloc = mallocstr copy_contents = copy_string_contents else: malloc = mallocunicode copy_contents = copy_unicode_contents result = malloc(itemslen) res_index = 0 i = 0 while i < num_items: item_chars = items[i].chars item_len = len(item_chars) copy_contents(items[i], result, 0, res_index, item_len) res_index += item_len i += 1 return result @staticmethod @jit.look_inside_iff(lambda length, chars, RES: jit.isconstant(length) and jit.isvirtual(chars)) def ll_join_chars(length, chars, RES): # no need to optimize this, will be replaced by string builder # at some point soon num_chars = length if RES is StringRepr.lowleveltype: target = Char malloc = mallocstr else: target = UniChar malloc = mallocunicode result = malloc(num_chars) res_chars = result.chars i = 0 while i < num_chars: res_chars[i] = cast_primitive(target, chars[i]) i += 1 return result @staticmethod @jit.oopspec('stroruni.slice(s1, start, stop)') @signature(types.any(), types.int(), types.int(), returns=types.any()) @jit.elidable def _ll_stringslice(s1, start, stop): lgt = stop - start assert start >= 0 # If start > stop, return a empty string. This can happen if the start # is greater than the length of the string. Use < instead of <= to avoid # creating another path for the JIT when start == stop. if lgt < 0: return s1.empty() newstr = s1.malloc(lgt) s1.copy_contents(s1, newstr, start, 0, lgt) return newstr @staticmethod def ll_stringslice_startonly(s1, start): return LLHelpers._ll_stringslice(s1, start, len(s1.chars)) @staticmethod @signature(types.any(), types.int(), types.int(), returns=types.any()) def ll_stringslice_startstop(s1, start, stop): if jit.we_are_jitted(): if stop > len(s1.chars): stop = len(s1.chars) else: if stop >= len(s1.chars): if start == 0: return s1 stop = len(s1.chars) return LLHelpers._ll_stringslice(s1, start, stop) @staticmethod def ll_stringslice_minusone(s1): newlen = len(s1.chars) - 1 return LLHelpers._ll_stringslice(s1, 0, newlen) @staticmethod def ll_split_chr(LIST, s, c, max): chars = s.chars strlen = len(chars) count = 1 i = 0 if max == 0: i = strlen while i < strlen: if chars[i] == c: count += 1 if max >= 0 and count > max: break i += 1 res = LIST.ll_newlist(count) items = res.ll_items() i = 0 j = 0 resindex = 0 if max == 0: j = strlen while j < strlen: if chars[j] == c: item = items[resindex] = s.malloc(j - i) item.copy_contents(s, item, i, 0, j - i) resindex += 1 i = j + 1 if max >= 0 and resindex >= max: j = strlen break j += 1 item = items[resindex] = s.malloc(j - i) item.copy_contents(s, item, i, 0, j - i) return res @staticmethod def ll_split(LIST, s, c, max): count = 1 if max == -1: max = len(s.chars) pos = 0 last = len(s.chars) markerlen = len(c.chars) pos = s.find(c, 0, last) while pos >= 0 and count <= max: pos = s.find(c, pos + markerlen, last) count += 1 res = LIST.ll_newlist(count) items = res.ll_items() pos = 0 count = 0 pos = s.find(c, 0, last) prev_pos = 0 if pos < 0: items[0] = s return res while pos >= 0 and count < max: item = items[count] = s.malloc(pos - prev_pos) item.copy_contents(s, item, prev_pos, 0, pos - prev_pos) count += 1 prev_pos = pos + markerlen pos = s.find(c, pos + markerlen, last) item = items[count] = s.malloc(last - prev_pos) item.copy_contents(s, item, prev_pos, 0, last - prev_pos) return res @staticmethod def ll_rsplit_chr(LIST, s, c, max): chars = s.chars strlen = len(chars) count = 1 i = 0 if max == 0: i = strlen while i < strlen: if chars[i] == c: count += 1 if max >= 0 and count > max: break i += 1 res = LIST.ll_newlist(count) items = res.ll_items() i = strlen j = strlen resindex = count - 1 assert resindex >= 0 if max == 0: j = 0 while j > 0: j -= 1 if chars[j] == c: item = items[resindex] = s.malloc(i - j - 1) item.copy_contents(s, item, j + 1, 0, i - j - 1) resindex -= 1 i = j if resindex == 0: j = 0 break item = items[resindex] = s.malloc(i - j) item.copy_contents(s, item, j, 0, i - j) return res @staticmethod def ll_rsplit(LIST, s, c, max): count = 1 if max == -1: max = len(s.chars) pos = len(s.chars) markerlen = len(c.chars) pos = s.rfind(c, 0, pos) while pos >= 0 and count <= max: pos = s.rfind(c, 0, pos - markerlen) count += 1 res = LIST.ll_newlist(count) items = res.ll_items() pos = 0 pos = len(s.chars) prev_pos = pos pos = s.rfind(c, 0, pos) if pos < 0: items[0] = s return res count -= 1 while pos >= 0 and count > 0: item = items[count] = s.malloc(prev_pos - pos - markerlen) item.copy_contents(s, item, pos + markerlen, 0, prev_pos - pos - markerlen) count -= 1 prev_pos = pos pos = s.rfind(c, 0, pos) item = items[count] = s.malloc(prev_pos) item.copy_contents(s, item, 0, 0, prev_pos) return res @staticmethod @jit.elidable def ll_replace_chr_chr(s, c1, c2): length = len(s.chars) newstr = s.malloc(length) src = s.chars dst = newstr.chars j = 0 while j < length: c = src[j] if c == c1: c = c2 dst[j] = c j += 1 return newstr @staticmethod @jit.elidable def ll_contains(s, c): chars = s.chars strlen = len(chars) i = 0 while i < strlen: if chars[i] == c: return True i += 1 return False @staticmethod @jit.elidable def ll_int(s, base): if not 2 <= base <= 36: raise ValueError chars = s.chars strlen = len(chars) i = 0 #XXX: only space is allowed as white space for now while i < strlen and chars[i] == ' ': i += 1 if not i < strlen: raise ValueError #check sign sign = 1 if chars[i] == '-': sign = -1 i += 1 elif chars[i] == '+': i += 1 # skip whitespaces between sign and digits while i < strlen and chars[i] == ' ': i += 1 #now get digits val = 0 oldpos = i while i < strlen: c = ord(chars[i]) if ord('a') <= c <= ord('z'): digit = c - ord('a') + 10 elif ord('A') <= c <= ord('Z'): digit = c - ord('A') + 10 elif ord('0') <= c <= ord('9'): digit = c - ord('0') else: break if digit >= base: break val = val * base + digit i += 1 if i == oldpos: raise ValueError # catch strings like '+' and '+ ' #skip trailing whitespace while i < strlen and chars[i] == ' ': i += 1 if not i == strlen: raise ValueError return sign * val # interface to build strings: # x = ll_build_start(n) # ll_build_push(x, next_string, 0) # ll_build_push(x, next_string, 1) # ... # ll_build_push(x, next_string, n-1) # s = ll_build_finish(x) @staticmethod def ll_build_start(parts_count): return malloc(TEMP, parts_count) @staticmethod def ll_build_push(builder, next_string, index): builder[index] = next_string @staticmethod def ll_build_finish(builder): return LLHelpers.ll_join_strs(len(builder), builder) @staticmethod @specialize.memo() def ll_constant(s): return string_repr.convert_const(s) @staticmethod @specialize.memo() def ll_constant_unicode(s): return unicode_repr.convert_const(s) @classmethod def do_stringformat(cls, hop, sourcevarsrepr): s_str = hop.args_s[0] assert s_str.is_constant() is_unicode = isinstance(s_str, annmodel.SomeUnicodeString) if is_unicode: TEMPBUF = TEMP_UNICODE else: TEMPBUF = TEMP s = s_str.const things = cls.parse_fmt_string(s) size = inputconst(Signed, len(things)) # could be unsigned? cTEMP = inputconst(Void, TEMPBUF) cflags = inputconst(Void, {'flavor': 'gc'}) vtemp = hop.genop("malloc_varsize", [cTEMP, cflags, size], resulttype=Ptr(TEMPBUF)) argsiter = iter(sourcevarsrepr) from rpython.rtyper.rclass import InstanceRepr for i, thing in enumerate(things): if isinstance(thing, tuple): code = thing[0] vitem, r_arg = argsiter.next() if not hasattr(r_arg, 'll_str'): raise TyperError("ll_str unsupported for: %r" % r_arg) if code == 's': if is_unicode: # only UniCharRepr and UnicodeRepr has it so far vchunk = hop.gendirectcall(r_arg.ll_unicode, vitem) else: vchunk = hop.gendirectcall(r_arg.ll_str, vitem) elif code == 'r' and isinstance(r_arg, InstanceRepr): vchunk = hop.gendirectcall(r_arg.ll_str, vitem) elif code == 'd': assert isinstance(r_arg, IntegerRepr) #vchunk = hop.gendirectcall(r_arg.ll_str, vitem) vchunk = hop.gendirectcall(ll_str.ll_int2dec, vitem) elif code == 'f': #assert isinstance(r_arg, FloatRepr) vchunk = hop.gendirectcall(r_arg.ll_str, vitem) elif code == 'x': assert isinstance(r_arg, IntegerRepr) vchunk = hop.gendirectcall(ll_str.ll_int2hex, vitem, inputconst(Bool, False)) elif code == 'o': assert isinstance(r_arg, IntegerRepr) vchunk = hop.gendirectcall(ll_str.ll_int2oct, vitem, inputconst(Bool, False)) else: raise TyperError("%%%s is not RPython" % (code, )) else: if is_unicode: vchunk = inputconst(unicode_repr, thing) else: vchunk = inputconst(string_repr, thing) i = inputconst(Signed, i) if is_unicode and vchunk.concretetype != Ptr(UNICODE): # if we are here, one of the ll_str.* functions returned some # STR, so we convert it to unicode. It's a bit suboptimal # because we do one extra copy. vchunk = hop.gendirectcall(cls.ll_str2unicode, vchunk) hop.genop('setarrayitem', [vtemp, i, vchunk]) hop.exception_cannot_occur() # to ignore the ZeroDivisionError of '%' return hop.gendirectcall(cls.ll_join_strs, size, vtemp) @staticmethod @jit.dont_look_inside def ll_string2list(RESLIST, src): length = len(src.chars) lst = RESLIST.ll_newlist(length) dst = lst.ll_items() SRC = typeOf(src).TO # STR or UNICODE DST = typeOf(dst).TO # GcArray assert DST.OF is SRC.chars.OF # from here, no GC operations can happen asrc = llmemory.cast_ptr_to_adr(src) + (llmemory.offsetof( SRC, 'chars') + llmemory.itemoffsetof(SRC.chars, 0)) adst = llmemory.cast_ptr_to_adr(dst) + llmemory.itemoffsetof(DST, 0) llmemory.raw_memcopy(asrc, adst, llmemory.sizeof(DST.OF) * length) # end of "no GC" section keepalive_until_here(src) keepalive_until_here(dst) return lst
arrays_w = [] dtypes_w = [] for w_arg in args_w: if isinstance(w_arg, W_NDimArray): arrays_w.append(w_arg) elif is_scalar_w(space, w_arg): w_scalar = as_scalar(space, w_arg) w_arr = W_NDimArray.from_scalar(space, w_scalar) arrays_w.append(w_arr) else: dtype = as_dtype(space, w_arg) dtypes_w.append(dtype) return find_result_type(space, arrays_w, dtypes_w) @jit.look_inside_iff(lambda space, arrays_w, dtypes_w: jit.loop_unrolling_heuristic(arrays_w, len(arrays_w)) and jit.loop_unrolling_heuristic(dtypes_w, len(dtypes_w))) def find_result_type(space, arrays_w, dtypes_w): # equivalent to PyArray_ResultType if len(arrays_w) == 1 and not dtypes_w: return arrays_w[0].get_dtype() elif not arrays_w and len(dtypes_w) == 1: return dtypes_w[0] result = None if not _use_min_scalar(arrays_w, dtypes_w): for w_array in arrays_w: if result is None: result = w_array.get_dtype() else: result = promote_types(space, result, w_array.get_dtype()) for dtype in dtypes_w:
if has_key: w_compare_with = space.call_function(w_key, w_item) else: w_compare_with = w_item if (not has_item or space.is_true(compare(w_compare_with, w_max_val))): has_item = True w_max_item = w_item w_max_val = w_compare_with if w_max_item is None: raise oefmt(space.w_ValueError, "arg is an empty sequence") return w_max_item @specialize.arg(3) @jit.look_inside_iff(lambda space, args_w, w_key, implementation_of: jit.loop_unrolling_heuristic(args_w, len(args_w), 3)) def min_max_multiple_args(space, args_w, w_key, implementation_of): # case of multiple arguments (at least two). We unroll it if there # are 2 or 3 arguments. if implementation_of == "max": compare = space.gt else: compare = space.lt w_max_item = args_w[0] if w_key is not None: w_max_val = space.call_function(w_key, w_max_item) else: w_max_val = w_max_item for i in range(1, len(args_w)): w_item = args_w[i] if w_key is not None: