1 #!/usr/bin/env python 2 3 """ 4 Sequence operations. 5 6 Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from native import _isinstance 23 24 class sequence: 25 26 "A common base class for sequence types." 27 28 def _check_index(self, index): 29 30 """ 31 Check the given absolute 'index', raising an IndexError if out of 32 bounds. 33 """ 34 35 if index < 0 or index >= len(self): 36 raise IndexError(index) 37 38 def _str(self, opening, closing): 39 40 "Serialise this object with the given 'opening' and 'closing' strings." 41 42 b = buffer() 43 i = 0 44 l = self.__len__() 45 first = True 46 47 b.append(opening) 48 while i < l: 49 if first: 50 first = False 51 else: 52 b.append(", ") 53 b.append(repr(self.__get_single_item__(i))) 54 i += 1 55 b.append(closing) 56 57 return str(b) 58 59 def __contains__(self, value): 60 61 "Return whether the list contains 'value'." 62 63 # Perform a linear search of the sequence contents. 64 65 for v in self: 66 67 # Return True if the current value is equal to the specified one. 68 # Note that this is not an identity test, but an equality test. 69 70 if v == value: 71 return True 72 73 return False 74 75 def index(self, value): 76 77 "Return the index of 'value' or raise ValueError." 78 79 i = 0 80 l = len(self) 81 while i < l: 82 if self[i] == value: 83 return i 84 i += 1 85 86 raise ValueError(value) 87 88 def __getitem__(self, index): 89 90 "Return the item or slice specified by 'index'." 91 92 # Normalise any integer indexes, converting negative indexes to positive 93 # ones. 94 95 if _isinstance(index, int): 96 index = _get_absolute_index(index, self.__len__()) 97 return self.__get_single_item__(index) 98 99 # Handle slices separately. 100 101 elif _isinstance(index, slice): 102 return self.__getslice__(index.start, index.end) 103 104 # No other kinds of objects are supported as indexes. 105 106 else: 107 raise TypeError() 108 109 def __setitem__(self, index, value): 110 111 "Set at 'index' the given 'value'." 112 113 # Normalise any integer indexes, converting negative indexes to positive 114 # ones. 115 116 if _isinstance(index, int): 117 index = _get_absolute_index(index, self.__len__()) 118 return self.__set_single_item__(index, value) 119 120 # Handle slices separately. 121 122 elif _isinstance(index, slice): 123 return self.__setslice__(index.start, index.end, value) 124 125 # No other kinds of objects are supported as indexes. 126 127 else: 128 raise TypeError() 129 130 def __getslice__(self, start, end=None): 131 132 "Return a slice starting from 'start', with the optional 'end'." 133 134 length = self.__len__() 135 136 # Handle a null start as the first position, otherwise normalising any 137 # start index. 138 139 if start is None: 140 start = 0 141 else: 142 start = _get_absolute_index(start, length) 143 144 # Handle a null end as the first position after the end of the sequence, 145 # otherwise normalising any end index. 146 147 if end is None: 148 end = length 149 else: 150 end = _get_absolute_index(end, length) 151 152 result = [] 153 154 while start < end: 155 result.append(self.__get_single_item__(start)) 156 start += 1 157 158 return result 159 160 def __eq__(self, other): 161 162 "Return whether this sequence is equal to 'other'." 163 164 # Sequences must have equal lengths to be equal. 165 166 n = self.__len__() 167 if len(other) != n: 168 return False 169 170 i = 0 171 while i < n: 172 if self.__getitem__(i) != other.__getitem__(i): 173 return False 174 i += 1 175 176 return True 177 178 def __ne__(self, other): 179 180 "Return whether this sequence is not equal to 'other'." 181 182 return not self.__eq__(other) 183 184 def _get_absolute_index(index, length): 185 186 """ 187 Return the absolute index for 'index' given a collection having the 188 specified 'length'. 189 """ 190 191 if index < 0: 192 return length + index 193 else: 194 return index 195 196 def _max(x, y): 197 198 "Return the maximum of 'x' and 'y'." 199 200 if x >= y: 201 return x 202 else: 203 return y 204 205 def _min(x, y): 206 207 "Return the minimum of 'x' and 'y'." 208 209 if x <= y: 210 return x 211 else: 212 return y 213 214 def _tuple(l): pass 215 216 # vim: tabstop=4 expandtab shiftwidth=4