web/lib/django/contrib/gis/geos/mutable_list.py
changeset 0 0d40e90630ef
--- /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())