from __future__ import print_function
"Utilities for manipulating slices"
# Intersect a slice with a half-open interval [i,j).
# slice.start and slice.stop must be integers (not None).
# Returns a slice, or None if the intersection is empty.
[docs]def sliceIntersect(aSlice, interval):
p0, p1 = interval
i = aSlice.start
j = aSlice.stop
k = aSlice.step
if k is None:
k = 1
# If the slice has a negative step, generate the
# equivalent slice with positive step
irev = 0
if k < 0:
k = -k
pk = int(((j - i + k) / k) * k + i)
j = int(i + 1)
i = int(pk)
irev = 1
# Calculate the intersection for an increasing slice
px = int((int((p0 - i + k - 1) / k)) * k + i)
a = max(px, i)
b = min(j, p1)
if a < b:
if k == 1:
newSlice = slice(a, b)
else:
newSlice = slice(a, b, k)
else:
newSlice = None
# Reverse the slice if necessary
if irev == 1 and newSlice is not None:
px = int(-(int((-b + a + k) / k) * k - a))
newSlice = slice(px, a - 1, -k)
return newSlice
# Intersect a slice with a partition. The partition is a list of
# intervals, with shape (n,2). The result is a list of pairs
# [(interval,slice), (interval,slice) ...] where the intervals are
# those intervals in the partition which have non-empty intersection,
# in the same order as in the partition. If the intersection is empty,
# the result is an empty list.
[docs]def slicePartition(aSlice, partition):
result = []
for interval in partition:
intslice = sliceIntersect(aSlice, interval)
if intslice is not None:
result.append((interval, intslice))
return result
[docs]def lenSlice(aSlice):
"Return the number of values associated with a slice"
step = aSlice.step
if step is None:
step = 1
if step > 0:
start = aSlice.start
stop = aSlice.stop
else:
start = aSlice.stop
stop = aSlice.start
step = -step
return (int((stop - start - 1) / step) + 1)
[docs]def reverseSlice(s, size):
"""For 'reversed' slices (slices with negative stride),
return an equivalent slice with positive step. For positive
strides, just return the slice unchanged.
"""
if s.step > 0 or s.step is None:
return s
i = s.start
j = s.stop
k = s.step
if i is None:
i = size - 1
elif i < 0:
i = i % size
if j is None:
j = -1
elif -size - 1 < j < 0:
j = j % size
if i < -size or j < -size - 1:
raise RuntimeError("Invalid slice %s" % repr(s))
k = -k
pk = (int((j - i + k) / k)) * k + i
j = i + 1
i = pk % size
# if j==size:
# j = None
return slice(i, j, k)
[docs]def splitSlice(s, size):
"""For a 'wraparound' slice, return two equivalent slices
within the range 0..size-1."""
i, j, k = s.start, s.stop, s.step
if k > 0:
wrap1 = slice(i, size, k)
wrap2 = slice((i - size) % k, j - size, k)
else:
wrap1 = slice(i - size, None, k)
wrap2 = slice(size + (i - size) % k, j, k)
return (wrap1, wrap2)
[docs]def splitSliceExt(s, size):
"""
mf 20010330 --
For a 'wraparound' slice, return N equivalent slices
within the range 0...(N*size) N = anything"""
i, j, k = s.start, s.stop, s.step
# slice of form [i:] sets j to large int
if j > 2000000000:
j = size
_debug = 0
if(_debug):
print("SSSS0: ", i, j, k)
wrap = []
if k > 0:
iter = 0
if(_debug):
print("SSSS1: iter ", iter, j, size, k)
while(j > 0):
if(_debug):
print(" ")
if(_debug):
print("SSSS2: iter", iter, j, size, k)
jo = size
if(iter > 0):
jo = size + 1
if(_debug):
print("SSSS3: iter", iter, j, jo)
if(j < size):
jo = j
if(_debug):
print("SSSS4: iter", iter, j, jo)
wrap.append(slice(i, jo, k))
j = j - size
i = 0
iter = iter + 1
else:
wraprev = []
iter = 0
if(_debug):
print("SSSS1 neg: iter ", iter, i, j, size, k)
while(i >= 0):
if(_debug):
print(" ")
if(_debug):
print("SSSS2 neg: iter", iter, i, j, size, k)
io = size - 1
if(_debug):
print("SSSS3 neg: iter", iter, i, j, io)
if(i < size):
io = i
if(_debug):
print("SSSS4 neg: iter", iter, i, j, io)
# mf 20010405 python does not return nothing for
# slice(size-1,size-1,-1); force it
if(not (io == size - 1 and j == size - 1)):
wraprev.append(slice(io, j, k))
i = i - size
j = None
iter = iter + 1
#
# reverse
#
for k in range(0, len(wraprev)):
kk = len(wraprev) - k - 1
wrap.append(wraprev[kk])
if(_debug):
print("SSSS5 neg: ", kk, wraprev[kk])
return (wrap)