summaryrefslogtreecommitdiff
path: root/numpy/f2py/capi_maps.py
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/f2py/capi_maps.py')
-rw-r--r--numpy/f2py/capi_maps.py61
1 files changed, 52 insertions, 9 deletions
diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py
index 1f43207db..e5dc2331a 100644
--- a/numpy/f2py/capi_maps.py
+++ b/numpy/f2py/capi_maps.py
@@ -56,6 +56,7 @@ c2py_map = {'double': 'float',
'complex_double': 'complex',
'complex_long_double': 'complex', # forced casting
'string': 'string',
+ 'character': 'bytes',
}
c2capi_map = {'double': 'NPY_DOUBLE',
'float': 'NPY_FLOAT',
@@ -72,7 +73,8 @@ c2capi_map = {'double': 'NPY_DOUBLE',
'complex_float': 'NPY_CFLOAT',
'complex_double': 'NPY_CDOUBLE',
'complex_long_double': 'NPY_CDOUBLE', # forced casting
- 'string': 'NPY_STRING'}
+ 'string': 'NPY_STRING',
+ 'character': 'NPY_CHAR'}
# These new maps aren't used anywhere yet, but should be by default
# unless building numeric or numarray extensions.
@@ -94,8 +96,8 @@ if using_newcore:
'complex_float': 'NPY_CFLOAT',
'complex_double': 'NPY_CDOUBLE',
'complex_long_double': 'NPY_CDOUBLE',
- 'string':'NPY_STRING'
- }
+ 'string': 'NPY_STRING',
+ 'character': 'NPY_STRING'}
c2pycode_map = {'double': 'd',
'float': 'f',
@@ -112,7 +114,8 @@ c2pycode_map = {'double': 'd',
'complex_float': 'F',
'complex_double': 'D',
'complex_long_double': 'D', # forced casting
- 'string': 'c'
+ 'string': 'c',
+ 'character': 'c'
}
if using_newcore:
@@ -133,8 +136,11 @@ if using_newcore:
'complex_float': 'F',
'complex_double': 'D',
'complex_long_double': 'G',
- 'string': 'S'}
+ 'string': 'S',
+ 'character': 'c'}
+# https://docs.python.org/3/c-api/arg.html#building-values
+# c2buildvalue_map is NumPy agnostic, so no need to bother with using_newcore
c2buildvalue_map = {'double': 'd',
'float': 'f',
'char': 'b',
@@ -146,7 +152,8 @@ c2buildvalue_map = {'double': 'd',
'complex_float': 'N',
'complex_double': 'N',
'complex_long_double': 'N',
- 'string': 'y'}
+ 'string': 'y',
+ 'character': 'c'}
f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double',
'12': 'long_double', '16': 'long_double'},
@@ -165,7 +172,6 @@ f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double',
'double complex': {'': 'complex_double'},
'double precision': {'': 'double'},
'byte': {'': 'char'},
- 'character': {'': 'string'}
}
f2cmap_default = copy.deepcopy(f2cmap_all)
@@ -230,7 +236,8 @@ cformat_map = {'double': '%g',
'complex_float': '(%g,%g)',
'complex_double': '(%g,%g)',
'complex_long_double': '(%Lg,%Lg)',
- 'string': '%s',
+ 'string': '\\"%s\\"',
+ 'character': "'%c'",
}
# Auxiliary functions
@@ -252,6 +259,10 @@ def getctype(var):
errmess('getctype: function %s has no return value?!\n' % a)
elif issubroutine(var):
return ctype
+ elif ischaracter_or_characterarray(var):
+ return 'character'
+ elif isstring_or_stringarray(var):
+ return 'string'
elif 'typespec' in var and var['typespec'].lower() in f2cmap_all:
typespec = var['typespec'].lower()
f2cmap = f2cmap_all[typespec]
@@ -283,6 +294,21 @@ def getctype(var):
return ctype
+def f2cexpr(expr):
+ """Rewrite Fortran expression as f2py supported C expression.
+
+ Due to the lack of a proper expression parser in f2py, this
+ function uses a heuristic approach that assumes that Fortran
+ arithmetic expressions are valid C arithmetic expressions when
+ mapping Fortran function calls to the corresponding C function/CPP
+ macros calls.
+
+ """
+ # TODO: support Fortran `len` function with optional kind parameter
+ expr = re.sub(r'\blen\b', 'f2py_slen', expr)
+ return expr
+
+
def getstrlength(var):
if isstringfunction(var):
if 'result' in var:
@@ -302,7 +328,7 @@ def getstrlength(var):
if '*' in a:
len = a['*']
elif 'len' in a:
- len = a['len']
+ len = f2cexpr(a['len'])
if re.match(r'\(\s*(\*|:)\s*\)', len) or re.match(r'(\*|:)', len):
if isintent_hide(var):
errmess('getstrlength:intent(hide): expected a string with defined length but got: %s\n' % (
@@ -499,6 +525,20 @@ def getinit(a, var):
return init, showinit
+def get_elsize(var):
+ if isstring(var) or isstringarray(var):
+ elsize = getstrlength(var)
+ # override with user-specified length when available:
+ elsize = var['charselector'].get('f2py_len', elsize)
+ return elsize
+ if ischaracter(var) or ischaracterarray(var):
+ return '1'
+ # for numerical types, PyArray_New* functions ignore specified
+ # elsize, so we just return 1 and let elsize be determined at
+ # runtime, see fortranobject.c
+ return '1'
+
+
def sign2map(a, var):
"""
varname,ctype,atype
@@ -553,6 +593,7 @@ def sign2map(a, var):
dim = copy.copy(var['dimension'])
if ret['ctype'] in c2capi_map:
ret['atype'] = c2capi_map[ret['ctype']]
+ ret['elsize'] = get_elsize(var)
# Debug info
if debugcapi(var):
il = [isintent_in, 'input', isintent_out, 'output',
@@ -720,6 +761,7 @@ def cb_sign2map(a, var, index=None):
ret['ctype'] = getctype(var)
if ret['ctype'] in c2capi_map:
ret['atype'] = c2capi_map[ret['ctype']]
+ ret['elsize'] = get_elsize(var)
if ret['ctype'] in cformat_map:
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
if isarray(var):
@@ -819,6 +861,7 @@ def common_sign2map(a, var): # obsolute
ret['ctype'] = 'char'
if ret['ctype'] in c2capi_map:
ret['atype'] = c2capi_map[ret['ctype']]
+ ret['elsize'] = get_elsize(var)
if ret['ctype'] in cformat_map:
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
if isarray(var):