1.1 --- a/lib/__builtins__/sequence.py Mon Dec 12 01:46:28 2016 +0100
1.2 +++ b/lib/__builtins__/sequence.py Mon Dec 12 17:05:59 2016 +0100
1.3 @@ -35,6 +35,16 @@
1.4 if index < 0 or index >= len(self):
1.5 raise IndexError(index)
1.6
1.7 + def _check_end_index(self, index):
1.8 +
1.9 + """
1.10 + Check the given absolute end 'index', raising an IndexError if out of
1.11 + bounds.
1.12 + """
1.13 +
1.14 + if index < -1 or index > len(self):
1.15 + raise IndexError(index)
1.16 +
1.17 def __getitem__(self, index):
1.18
1.19 "Return the item or slice specified by 'index'."
1.20 @@ -112,13 +122,7 @@
1.21 else:
1.22 end = _get_absolute_index(end, length)
1.23
1.24 - result = []
1.25 -
1.26 - while step > 0 and start < end or step < 0 and start > end:
1.27 - result.append(self.__get_single_item__(start))
1.28 - start += step
1.29 -
1.30 - return result
1.31 + return self.__get_multiple_items__(start, end, step)
1.32
1.33 # Methods implemented by subclasses.
1.34
1.35 @@ -140,6 +144,12 @@
1.36
1.37 pass
1.38
1.39 + def __get_multiple_items__(self, start, end, step):
1.40 +
1.41 + "Method to be overridden by subclasses."
1.42 +
1.43 + return None
1.44 +
1.45 def __len__(self):
1.46
1.47 "Method to be overridden by subclasses."
1.48 @@ -230,6 +240,21 @@
1.49
1.50 raise StopIteration()
1.51
1.52 + def __get_multiple_items__(self, start, end, step):
1.53 +
1.54 + """
1.55 + Return items from 'start' until (but excluding) 'end', at 'step'
1.56 + intervals.
1.57 + """
1.58 +
1.59 + result = []
1.60 +
1.61 + while step > 0 and start < end or step < 0 and start > end:
1.62 + result.append(self.__get_single_item__(start))
1.63 + start += step
1.64 +
1.65 + return result
1.66 +
1.67 def _get_absolute_index(index, length):
1.68
1.69 """
2.1 --- a/lib/__builtins__/str.py Mon Dec 12 01:46:28 2016 +0100
2.2 +++ b/lib/__builtins__/str.py Mon Dec 12 17:05:59 2016 +0100
2.3 @@ -22,6 +22,7 @@
2.4 from __builtins__.int import maxint, minint
2.5 from __builtins__.operator import _negate
2.6 from __builtins__.sequence import itemaccess
2.7 +from __builtins__.types import check_int
2.8 from native import str_add, str_lt, str_gt, str_eq, str_len, str_nonempty, \
2.9 str_substr
2.10
2.11 @@ -189,7 +190,26 @@
2.12 "Return the item at the normalised (positive) 'index'."
2.13
2.14 self._check_index(index)
2.15 - return str_substr(self.__data__, index, 1)
2.16 + return str_substr(self.__data__, index, index + 1, 1)
2.17 +
2.18 + def __get_multiple_items__(self, start, end, step):
2.19 +
2.20 + """
2.21 + Return items from 'start' until (but excluding) 'end', at 'step'
2.22 + intervals.
2.23 + """
2.24 +
2.25 + self._check_index(start)
2.26 + self._check_end_index(end)
2.27 + check_int(step)
2.28 +
2.29 + if step == 0:
2.30 + raise ValueError(step)
2.31 +
2.32 + if start == end:
2.33 + return ""
2.34 +
2.35 + return str_substr(self.__data__, start, end, step)
2.36
2.37 class string(basestring):
2.38 pass
3.1 --- a/lib/native/str.py Mon Dec 12 01:46:28 2016 +0100
3.2 +++ b/lib/native/str.py Mon Dec 12 17:05:59 2016 +0100
3.3 @@ -26,13 +26,13 @@
3.4
3.5 # String operations.
3.6
3.7 -def str_add(self, other): pass
3.8 -def str_eq(self, other): pass
3.9 -def str_gt(self, other): pass
3.10 -def str_lt(self, other): pass
3.11 -def str_len(self): pass
3.12 -def str_nonempty(self): pass
3.13 -def str_ord(self): pass
3.14 -def str_substr(self, start, size): pass
3.15 +def str_add(data, other_data): pass
3.16 +def str_eq(data, other_data): pass
3.17 +def str_gt(data, other_data): pass
3.18 +def str_lt(data, other_data): pass
3.19 +def str_len(data): pass
3.20 +def str_nonempty(data): pass
3.21 +def str_ord(data): pass
3.22 +def str_substr(data, start, end, step): pass
3.23
3.24 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/templates/native/str.c Mon Dec 12 01:46:28 2016 +0100
4.2 +++ b/templates/native/str.c Mon Dec 12 17:05:59 2016 +0100
4.3 @@ -113,18 +113,33 @@
4.4 {
4.5 __attr * const _data = &__args[1];
4.6 __attr * const start = &__args[2];
4.7 - __attr * const size = &__args[3];
4.8 + __attr * const end = &__args[3];
4.9 + __attr * const step = &__args[4];
4.10 /* _data interpreted as string */
4.11 char *s = _data->strvalue, *sub;
4.12 /* start.__data__ interpreted as int */
4.13 - int i = __load_via_object(start->value, __pos___data__).intvalue;
4.14 - /* size.__data__ interpreted as int */
4.15 - int l = __load_via_object(size->value, __pos___data__).intvalue;
4.16 + int istart = __load_via_object(start->value, __pos___data__).intvalue;
4.17 + /* end.__data__ interpreted as int */
4.18 + int iend = __load_via_object(end->value, __pos___data__).intvalue;
4.19 + /* step.__data__ interpreted as int */
4.20 + int istep = __load_via_object(step->value, __pos___data__).intvalue;
4.21 +
4.22 + /* Calculate the size of the substring. */
4.23 + size_t resultsize = ((iend - istart - 1) / istep) + 1;
4.24 + int to, from;
4.25
4.26 /* Reserve space for a new string. */
4.27 - sub = (char *) __ALLOCATE(l + 1, sizeof(char));
4.28 - memcpy(sub, s + i, l); /* does not null terminate but final byte should be zero */
4.29 - return __new_str(sub, l);
4.30 + sub = (char *) __ALLOCATE(resultsize + 1, sizeof(char));
4.31 +
4.32 + /* Does not null terminate but final byte should be zero. */
4.33 + if (istep > 0)
4.34 + for (from = istart, to = 0; from < iend; from += istep, to++)
4.35 + sub[to] = s[from];
4.36 + else if (istep < 0)
4.37 + for (from = istart, to = 0; from > iend; from += istep, to++)
4.38 + sub[to] = s[from];
4.39 +
4.40 + return __new_str(sub, resultsize);
4.41 }
4.42
4.43 /* Module initialisation. */
5.1 --- a/tests/string.py Mon Dec 12 01:46:28 2016 +0100
5.2 +++ b/tests/string.py Mon Dec 12 17:05:59 2016 +0100
5.3 @@ -2,6 +2,10 @@
5.4 s += " world!"
5.5 print s # Hello world!
5.6 print len(s) # 12
5.7 +print s[:5] # Hello
5.8 +print s[5:] # world!
5.9 +print s[1:10:2] # el ol
5.10 +print s[10:1:-2] # drwol
5.11
5.12 s2 = "Hello worlds!"
5.13 print s2 # Hello worlds!