summaryrefslogtreecommitdiff
path: root/numpy/core/_internal.py
diff options
context:
space:
mode:
authorPauli Virtanen <pav@iki.fi>2010-04-04 20:20:48 +0000
committerPauli Virtanen <pav@iki.fi>2010-04-04 20:20:48 +0000
commit8371b7563102ab5021d024a60669d926d4c577a6 (patch)
tree9c64311b88f04e4ea017eb3b0b77faf4a46ed567 /numpy/core/_internal.py
parent204efabe8d40e0ff8b7e81518476eb5253e4d09d (diff)
downloadnumpy-8371b7563102ab5021d024a60669d926d4c577a6.tar.gz
ENH: core: improve PEP 3118 parser's alignment handling
Now, padding will be more forcefully inserted for native-aligned items.
Diffstat (limited to 'numpy/core/_internal.py')
-rw-r--r--numpy/core/_internal.py58
1 files changed, 46 insertions, 12 deletions
diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py
index d7f1a1119..49216c646 100644
--- a/numpy/core/_internal.py
+++ b/numpy/core/_internal.py
@@ -403,9 +403,23 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
fields = {}
offset = 0
- findex = 0
explicit_name = False
-
+ this_explicit_name = False
+ common_alignment = 1
+ is_padding = False
+ last_offset = 0
+
+ dummy_name_index = [0]
+ def next_dummy_name():
+ dummy_name_index[0] += 1
+ def get_dummy_name():
+ while True:
+ name = 'f%d' % dummy_name_index[0]
+ if name not in fields:
+ return name
+ next_dummy_name()
+
+ # Parse spec
while spec:
value = None
@@ -448,11 +462,9 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
is_padding = False
if spec[:2] == 'T{':
- value, spec = _dtype_from_pep3118(spec[2:], byteorder=byteorder,
- is_subdtype=True)
- if itemsize != 1:
- # Not supported
- raise ValueError("Non item-size 1 structures not supported")
+ value, spec, align = _dtype_from_pep3118(spec[2:],
+ byteorder=byteorder,
+ is_subdtype=True)
elif spec[0] in type_map_chars:
if spec[0] == 'Z':
j = 2
@@ -467,6 +479,7 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
itemsize = 1
numpy_byteorder = {'@': '=', '^': '='}.get(byteorder, byteorder)
value = dtype(numpy_byteorder + dtypechar)
+ align = value.alignment
else:
raise ValueError("Unknown PEP 3118 data type specifier %r" % spec)
@@ -476,8 +489,8 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
# that the start of the array is *also* aligned.
extra_offset = 0
if byteorder == '@':
- start_padding = (-offset) % value.alignment
- intra_padding = (-value.itemsize) % value.alignment
+ start_padding = (-offset) % align
+ intra_padding = (-value.itemsize) % align
offset += start_padding
@@ -488,6 +501,10 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
else:
extra_offset += intra_padding
+ # Update common alignment
+ common_alignment = (align*common_alignment
+ / _gcd(align, common_alignment))
+
# Convert itemsize to sub-array
if itemsize != 1:
value = dtype((value, (itemsize,)))
@@ -505,20 +522,37 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False):
explicit_name = True
this_explicit_name = True
else:
- name = 'f%d' % findex
- findex += 1
+ name = get_dummy_name()
if not is_padding or this_explicit_name:
+ if name in fields:
+ raise RuntimeError("Duplicate field name '%s' in PEP3118 format"
+ % name)
fields[name] = (value, offset)
+ if not this_explicit_name:
+ next_dummy_name()
+
+ last_offset = offset
offset += value.itemsize
offset += extra_offset
+ if is_padding and not this_explicit_name:
+ # Trailing padding must be made explicit
+ name = get_dummy_name()
+ fields[name] = ('V%d' % (offset - last_offset), last_offset)
+
if len(fields.keys()) == 1 and not explicit_name and fields['f0'][1] == 0:
ret = fields['f0'][0]
else:
ret = dtype(fields)
if is_subdtype:
- return ret, spec
+ return ret, spec, common_alignment
else:
return ret
+
+def _gcd(a, b):
+ """Calculate the greatest common divisor of a and b"""
+ while b:
+ a, b = b, a%b
+ return a