2
0

mutable_list.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. # Copyright (c) 2008-2009 Aryeh Leib Taurog, all rights reserved.
  2. # Released under the New BSD license.
  3. """
  4. This module contains a base type which provides list-style mutations
  5. without specific data storage methods.
  6. See also http://www.aryehleib.com/MutableLists.html
  7. Author: Aryeh Leib Taurog.
  8. """
  9. from django.utils.functional import total_ordering
  10. from django.utils import six
  11. from django.utils.six.moves import xrange
  12. @total_ordering
  13. class ListMixin(object):
  14. """
  15. A base class which provides complete list interface.
  16. Derived classes must call ListMixin's __init__() function
  17. and implement the following:
  18. function _get_single_external(self, i):
  19. Return single item with index i for general use.
  20. The index i will always satisfy 0 <= i < len(self).
  21. function _get_single_internal(self, i):
  22. Same as above, but for use within the class [Optional]
  23. Note that if _get_single_internal and _get_single_internal return
  24. different types of objects, _set_list must distinguish
  25. between the two and handle each appropriately.
  26. function _set_list(self, length, items):
  27. Recreate the entire object.
  28. NOTE: items may be a generator which calls _get_single_internal.
  29. Therefore, it is necessary to cache the values in a temporary:
  30. temp = list(items)
  31. before clobbering the original storage.
  32. function _set_single(self, i, value):
  33. Set the single item at index i to value [Optional]
  34. If left undefined, all mutations will result in rebuilding
  35. the object using _set_list.
  36. function __len__(self):
  37. Return the length
  38. int _minlength:
  39. The minimum legal length [Optional]
  40. int _maxlength:
  41. The maximum legal length [Optional]
  42. type or tuple _allowed:
  43. A type or tuple of allowed item types [Optional]
  44. class _IndexError:
  45. The type of exception to be raise on invalid index [Optional]
  46. """
  47. _minlength = 0
  48. _maxlength = None
  49. _IndexError = IndexError
  50. ### Python initialization and special list interface methods ###
  51. def __init__(self, *args, **kwargs):
  52. if not hasattr(self, '_get_single_internal'):
  53. self._get_single_internal = self._get_single_external
  54. if not hasattr(self, '_set_single'):
  55. self._set_single = self._set_single_rebuild
  56. self._assign_extended_slice = self._assign_extended_slice_rebuild
  57. super(ListMixin, self).__init__(*args, **kwargs)
  58. def __getitem__(self, index):
  59. "Get the item(s) at the specified index/slice."
  60. if isinstance(index, slice):
  61. return [self._get_single_external(i) for i in xrange(*index.indices(len(self)))]
  62. else:
  63. index = self._checkindex(index)
  64. return self._get_single_external(index)
  65. def __delitem__(self, index):
  66. "Delete the item(s) at the specified index/slice."
  67. if not isinstance(index, six.integer_types + (slice,)):
  68. raise TypeError("%s is not a legal index" % index)
  69. # calculate new length and dimensions
  70. origLen = len(self)
  71. if isinstance(index, six.integer_types):
  72. index = self._checkindex(index)
  73. indexRange = [index]
  74. else:
  75. indexRange = range(*index.indices(origLen))
  76. newLen = origLen - len(indexRange)
  77. newItems = ( self._get_single_internal(i)
  78. for i in xrange(origLen)
  79. if i not in indexRange )
  80. self._rebuild(newLen, newItems)
  81. def __setitem__(self, index, val):
  82. "Set the item(s) at the specified index/slice."
  83. if isinstance(index, slice):
  84. self._set_slice(index, val)
  85. else:
  86. index = self._checkindex(index)
  87. self._check_allowed((val,))
  88. self._set_single(index, val)
  89. def __iter__(self):
  90. "Iterate over the items in the list"
  91. for i in xrange(len(self)):
  92. yield self[i]
  93. ### Special methods for arithmetic operations ###
  94. def __add__(self, other):
  95. 'add another list-like object'
  96. return self.__class__(list(self) + list(other))
  97. def __radd__(self, other):
  98. 'add to another list-like object'
  99. return other.__class__(list(other) + list(self))
  100. def __iadd__(self, other):
  101. 'add another list-like object to self'
  102. self.extend(list(other))
  103. return self
  104. def __mul__(self, n):
  105. 'multiply'
  106. return self.__class__(list(self) * n)
  107. def __rmul__(self, n):
  108. 'multiply'
  109. return self.__class__(list(self) * n)
  110. def __imul__(self, n):
  111. 'multiply'
  112. if n <= 0:
  113. del self[:]
  114. else:
  115. cache = list(self)
  116. for i in range(n-1):
  117. self.extend(cache)
  118. return self
  119. def __eq__(self, other):
  120. for i in range(len(self)):
  121. try:
  122. c = self[i] == other[i]
  123. except IndexError:
  124. # must be other is shorter
  125. return False
  126. if not c:
  127. return False
  128. return True
  129. def __lt__(self, other):
  130. slen = len(self)
  131. for i in range(slen):
  132. try:
  133. c = self[i] < other[i]
  134. except IndexError:
  135. # must be other is shorter
  136. return False
  137. if c:
  138. return c
  139. return slen < len(other)
  140. ### Public list interface Methods ###
  141. ## Non-mutating ##
  142. def count(self, val):
  143. "Standard list count method"
  144. count = 0
  145. for i in self:
  146. if val == i: count += 1
  147. return count
  148. def index(self, val):
  149. "Standard list index method"
  150. for i in xrange(0, len(self)):
  151. if self[i] == val: return i
  152. raise ValueError('%s not found in object' % str(val))
  153. ## Mutating ##
  154. def append(self, val):
  155. "Standard list append method"
  156. self[len(self):] = [val]
  157. def extend(self, vals):
  158. "Standard list extend method"
  159. self[len(self):] = vals
  160. def insert(self, index, val):
  161. "Standard list insert method"
  162. if not isinstance(index, six.integer_types):
  163. raise TypeError("%s is not a legal index" % index)
  164. self[index:index] = [val]
  165. def pop(self, index=-1):
  166. "Standard list pop method"
  167. result = self[index]
  168. del self[index]
  169. return result
  170. def remove(self, val):
  171. "Standard list remove method"
  172. del self[self.index(val)]
  173. def reverse(self):
  174. "Standard list reverse method"
  175. self[:] = self[-1::-1]
  176. def sort(self, cmp=cmp, key=None, reverse=False):
  177. "Standard list sort method"
  178. if key:
  179. temp = [(key(v),v) for v in self]
  180. temp.sort(cmp=cmp, key=lambda x: x[0], reverse=reverse)
  181. self[:] = [v[1] for v in temp]
  182. else:
  183. temp = list(self)
  184. temp.sort(cmp=cmp, reverse=reverse)
  185. self[:] = temp
  186. ### Private routines ###
  187. def _rebuild(self, newLen, newItems):
  188. if newLen < self._minlength:
  189. raise ValueError('Must have at least %d items' % self._minlength)
  190. if self._maxlength is not None and newLen > self._maxlength:
  191. raise ValueError('Cannot have more than %d items' % self._maxlength)
  192. self._set_list(newLen, newItems)
  193. def _set_single_rebuild(self, index, value):
  194. self._set_slice(slice(index, index + 1, 1), [value])
  195. def _checkindex(self, index, correct=True):
  196. length = len(self)
  197. if 0 <= index < length:
  198. return index
  199. if correct and -length <= index < 0:
  200. return index + length
  201. raise self._IndexError('invalid index: %s' % str(index))
  202. def _check_allowed(self, items):
  203. if hasattr(self, '_allowed'):
  204. if False in [isinstance(val, self._allowed) for val in items]:
  205. raise TypeError('Invalid type encountered in the arguments.')
  206. def _set_slice(self, index, values):
  207. "Assign values to a slice of the object"
  208. try:
  209. iter(values)
  210. except TypeError:
  211. raise TypeError('can only assign an iterable to a slice')
  212. self._check_allowed(values)
  213. origLen = len(self)
  214. valueList = list(values)
  215. start, stop, step = index.indices(origLen)
  216. # CAREFUL: index.step and step are not the same!
  217. # step will never be None
  218. if index.step is None:
  219. self._assign_simple_slice(start, stop, valueList)
  220. else:
  221. self._assign_extended_slice(start, stop, step, valueList)
  222. def _assign_extended_slice_rebuild(self, start, stop, step, valueList):
  223. 'Assign an extended slice by rebuilding entire list'
  224. indexList = range(start, stop, step)
  225. # extended slice, only allow assigning slice of same size
  226. if len(valueList) != len(indexList):
  227. raise ValueError('attempt to assign sequence of size %d '
  228. 'to extended slice of size %d'
  229. % (len(valueList), len(indexList)))
  230. # we're not changing the length of the sequence
  231. newLen = len(self)
  232. newVals = dict(zip(indexList, valueList))
  233. def newItems():
  234. for i in xrange(newLen):
  235. if i in newVals:
  236. yield newVals[i]
  237. else:
  238. yield self._get_single_internal(i)
  239. self._rebuild(newLen, newItems())
  240. def _assign_extended_slice(self, start, stop, step, valueList):
  241. 'Assign an extended slice by re-assigning individual items'
  242. indexList = range(start, stop, step)
  243. # extended slice, only allow assigning slice of same size
  244. if len(valueList) != len(indexList):
  245. raise ValueError('attempt to assign sequence of size %d '
  246. 'to extended slice of size %d'
  247. % (len(valueList), len(indexList)))
  248. for i, val in zip(indexList, valueList):
  249. self._set_single(i, val)
  250. def _assign_simple_slice(self, start, stop, valueList):
  251. 'Assign a simple slice; Can assign slice of any length'
  252. origLen = len(self)
  253. stop = max(start, stop)
  254. newLen = origLen - stop + start + len(valueList)
  255. def newItems():
  256. for i in xrange(origLen + 1):
  257. if i == start:
  258. for val in valueList:
  259. yield val
  260. if i < origLen:
  261. if i < start or i >= stop:
  262. yield self._get_single_internal(i)
  263. self._rebuild(newLen, newItems())