diff -r 000000000000 -r 0d40e90630ef web/lib/django/contrib/gis/geos/mutable_list.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/django/contrib/gis/geos/mutable_list.py Wed Jan 20 00:34:04 2010 +0100 @@ -0,0 +1,309 @@ +# Copyright (c) 2008-2009 Aryeh Leib Taurog, all rights reserved. +# Released under the New BSD license. +""" +This module contains a base type which provides list-style mutations +without specific data storage methods. + +See also http://www.aryehleib.com/MutableLists.html + +Author: Aryeh Leib Taurog. +""" +class ListMixin(object): + """ + A base class which provides complete list interface. + Derived classes must call ListMixin's __init__() function + and implement the following: + + function _get_single_external(self, i): + Return single item with index i for general use. + The index i will always satisfy 0 <= i < len(self). + + function _get_single_internal(self, i): + Same as above, but for use within the class [Optional] + Note that if _get_single_internal and _get_single_internal return + different types of objects, _set_list must distinguish + between the two and handle each appropriately. + + function _set_list(self, length, items): + Recreate the entire object. + + NOTE: items may be a generator which calls _get_single_internal. + Therefore, it is necessary to cache the values in a temporary: + temp = list(items) + before clobbering the original storage. + + function _set_single(self, i, value): + Set the single item at index i to value [Optional] + If left undefined, all mutations will result in rebuilding + the object using _set_list. + + function __len__(self): + Return the length + + int _minlength: + The minimum legal length [Optional] + + int _maxlength: + The maximum legal length [Optional] + + type or tuple _allowed: + A type or tuple of allowed item types [Optional] + + class _IndexError: + The type of exception to be raise on invalid index [Optional] + """ + + _minlength = 0 + _maxlength = None + _IndexError = IndexError + + ### Python initialization and special list interface methods ### + + def __init__(self, *args, **kwargs): + if not hasattr(self, '_get_single_internal'): + self._get_single_internal = self._get_single_external + + if not hasattr(self, '_set_single'): + self._set_single = self._set_single_rebuild + self._assign_extended_slice = self._assign_extended_slice_rebuild + + super(ListMixin, self).__init__(*args, **kwargs) + + def __getitem__(self, index): + "Get the item(s) at the specified index/slice." + if isinstance(index, slice): + return [self._get_single_external(i) for i in xrange(*index.indices(len(self)))] + else: + index = self._checkindex(index) + return self._get_single_external(index) + + def __delitem__(self, index): + "Delete the item(s) at the specified index/slice." + if not isinstance(index, (int, long, slice)): + raise TypeError("%s is not a legal index" % index) + + # calculate new length and dimensions + origLen = len(self) + if isinstance(index, (int, long)): + index = self._checkindex(index) + indexRange = [index] + else: + indexRange = range(*index.indices(origLen)) + + newLen = origLen - len(indexRange) + newItems = ( self._get_single_internal(i) + for i in xrange(origLen) + if i not in indexRange ) + + self._rebuild(newLen, newItems) + + def __setitem__(self, index, val): + "Set the item(s) at the specified index/slice." + if isinstance(index, slice): + self._set_slice(index, val) + else: + index = self._checkindex(index) + self._check_allowed((val,)) + self._set_single(index, val) + + def __iter__(self): + "Iterate over the items in the list" + for i in xrange(len(self)): + yield self[i] + + ### Special methods for arithmetic operations ### + def __add__(self, other): + 'add another list-like object' + return self.__class__(list(self) + list(other)) + + def __radd__(self, other): + 'add to another list-like object' + return other.__class__(list(other) + list(self)) + + def __iadd__(self, other): + 'add another list-like object to self' + self.extend(list(other)) + return self + + def __mul__(self, n): + 'multiply' + return self.__class__(list(self) * n) + + def __rmul__(self, n): + 'multiply' + return self.__class__(list(self) * n) + + def __imul__(self, n): + 'multiply' + if n <= 0: + del self[:] + else: + cache = list(self) + for i in range(n-1): + self.extend(cache) + return self + + def __cmp__(self, other): + 'cmp' + slen = len(self) + for i in range(slen): + try: + c = cmp(self[i], other[i]) + except IndexError: + # must be other is shorter + return 1 + else: + # elements not equal + if c: return c + + return cmp(slen, len(other)) + + ### Public list interface Methods ### + ## Non-mutating ## + def count(self, val): + "Standard list count method" + count = 0 + for i in self: + if val == i: count += 1 + return count + + def index(self, val): + "Standard list index method" + for i in xrange(0, len(self)): + if self[i] == val: return i + raise ValueError('%s not found in object' % str(val)) + + ## Mutating ## + def append(self, val): + "Standard list append method" + self[len(self):] = [val] + + def extend(self, vals): + "Standard list extend method" + self[len(self):] = vals + + def insert(self, index, val): + "Standard list insert method" + if not isinstance(index, (int, long)): + raise TypeError("%s is not a legal index" % index) + self[index:index] = [val] + + def pop(self, index=-1): + "Standard list pop method" + result = self[index] + del self[index] + return result + + def remove(self, val): + "Standard list remove method" + del self[self.index(val)] + + def reverse(self): + "Standard list reverse method" + self[:] = self[-1::-1] + + def sort(self, cmp=cmp, key=None, reverse=False): + "Standard list sort method" + if key: + temp = [(key(v),v) for v in self] + temp.sort(cmp=cmp, key=lambda x: x[0], reverse=reverse) + self[:] = [v[1] for v in temp] + else: + temp = list(self) + temp.sort(cmp=cmp, reverse=reverse) + self[:] = temp + + ### Private routines ### + def _rebuild(self, newLen, newItems): + if newLen < self._minlength: + raise ValueError('Must have at least %d items' % self._minlength) + if self._maxlength is not None and newLen > self._maxlength: + raise ValueError('Cannot have more than %d items' % self._maxlength) + + self._set_list(newLen, newItems) + + def _set_single_rebuild(self, index, value): + self._set_slice(slice(index, index + 1, 1), [value]) + + def _checkindex(self, index, correct=True): + length = len(self) + if 0 <= index < length: + return index + if correct and -length <= index < 0: + return index + length + raise self._IndexError('invalid index: %s' % str(index)) + + def _check_allowed(self, items): + if hasattr(self, '_allowed'): + if False in [isinstance(val, self._allowed) for val in items]: + raise TypeError('Invalid type encountered in the arguments.') + + def _set_slice(self, index, values): + "Assign values to a slice of the object" + try: + iter(values) + except TypeError: + raise TypeError('can only assign an iterable to a slice') + + self._check_allowed(values) + + origLen = len(self) + valueList = list(values) + start, stop, step = index.indices(origLen) + + # CAREFUL: index.step and step are not the same! + # step will never be None + if index.step is None: + self._assign_simple_slice(start, stop, valueList) + else: + self._assign_extended_slice(start, stop, step, valueList) + + def _assign_extended_slice_rebuild(self, start, stop, step, valueList): + 'Assign an extended slice by rebuilding entire list' + indexList = range(start, stop, step) + # extended slice, only allow assigning slice of same size + if len(valueList) != len(indexList): + raise ValueError('attempt to assign sequence of size %d ' + 'to extended slice of size %d' + % (len(valueList), len(indexList))) + + # we're not changing the length of the sequence + newLen = len(self) + newVals = dict(zip(indexList, valueList)) + def newItems(): + for i in xrange(newLen): + if i in newVals: + yield newVals[i] + else: + yield self._get_single_internal(i) + + self._rebuild(newLen, newItems()) + + def _assign_extended_slice(self, start, stop, step, valueList): + 'Assign an extended slice by re-assigning individual items' + indexList = range(start, stop, step) + # extended slice, only allow assigning slice of same size + if len(valueList) != len(indexList): + raise ValueError('attempt to assign sequence of size %d ' + 'to extended slice of size %d' + % (len(valueList), len(indexList))) + + for i, val in zip(indexList, valueList): + self._set_single(i, val) + + def _assign_simple_slice(self, start, stop, valueList): + 'Assign a simple slice; Can assign slice of any length' + origLen = len(self) + stop = max(start, stop) + newLen = origLen - stop + start + len(valueList) + def newItems(): + for i in xrange(origLen + 1): + if i == start: + for val in valueList: + yield val + + if i < origLen: + if i < start or i >= stop: + yield self._get_single_internal(i) + + self._rebuild(newLen, newItems())