(func)
return fdef
Build a function from a templated function.  The function must look like
    template<class I, class T, ...>
    void func(const p[], p_size, ...)

    rules:
        - a pointer or array p is followed by int p_size
        - all arrays are templated
        - non arrays are basic types: int, double, complex, etc
        - all functions are straight up c++
Build a function from a templated function.  The function must look like
    template<class I, class T, ...>
    void func(const p[], p_size, ...)
Build a function from a templated function . The function must look like template<class I class T ... > void func ( const p [] p_size ... )
def build_function(func):
    """
    Build a function from a templated function.  The function must look like
    template<class I, class T, ...>
    void func(const p[], p_size, ...)

    rules:
        - a pointer or array p is followed by int p_size
        - all arrays are templated
        - non arrays are basic types: int, double, complex, etc
        - all functions are straight up c++
    """

    indent = '    '

    # temlpate and function name

    if func['template']:
        fdef = func['template'] + '\n'
    else:
        fdef = ''

    newcall = func['returns'] + ' _' + func['name'] + '('
    fdef += newcall + '\n'

    # function parameters

    # for each parameter
    # if it's an array
    #   - replace with py::array_t
    #   - skip the next _size argument
    #   - save in a list of arrays
    # else replicate

    i = 0
    arraylist = []
    needsize = False
    while i < len(func['parameters']):
        p = func['parameters'][i]
        i += 1

        # check if pointer/array
        if p['pointer'] or p['array']:
            paramtype = p['raw_type']
            const = ''
            if p['constant']:
                const = 'const '

            param = f'py::array_t<{paramtype}> &' + ' ' + p['name']
            arraylist.append((const, paramtype, p['name']))
            needsize = True
        elif '_size' not in p['name'] and needsize:
            # not a size, but needed one
            raise ValueError(
                'Expecting a _size parameter for {}'.format(
                    p['name']))
        elif '_size' in p['name']:
            # just size, skip it
            needsize = False
            continue
        else:
            # if not a pointer, just copy it
            param = p['type'] + ' ' + p['name']

        fdef += f'{param:>25}'    # set width to 25
        fdef += ',\n'
    fdef = fdef[:-2]  # remove trailing comma and newline
    fdef += '\n' + ' ' * len(newcall) + ')'
    fdef += '\n{\n'

    # make a list of python objects
    for a in arraylist:
        if 'const' in a[0]:
            unchecked = '.unchecked();\n'
        else:
            unchecked = '.mutable_unchecked();\n'

        fdef += indent
        fdef += "auto py_" + a[2] + ' = ' + a[2] + unchecked

    # make a list of pointers to the arrays
    for a in arraylist:
        if 'const' in a[0]:
            data = '.data();\n'
        else:
            data = '.mutable_data();\n'
        fdef += indent
        fdef += a[0] + a[1] + ' *_' + a[2] + ' = py_' + a[2] + data

    # get the template signature
    if len(arraylist) > 0:
        fdef += '\n'
    if func['template']:
        template = func['template']
        template = template.replace('template', '').replace(
            'class ', '')   # template <class T> ----> <T>
    else:
        template = ''
    newcall = '    return ' + func['name'] + template + '('
    fdef += newcall + '\n'

    # function parameters
    for i, p in enumerate(func['parameters']):
        if '_size' in p['name']:
            fdef = fdef.strip()
            name, s = p['name'].split('_size')
            if s == '':
                s = '0'
            fdef += f" {name}.shape({s})"
        else:
            if p['pointer'] or p['array']:
                name = '_' + p['name']
            else:
                name = p['name']
            fdef += f'{name:>25}'
        if i < len(func['parameters'])-1:
            fdef += ',\n'
    fdef += '\n' + ' ' * len(newcall) + ');\n}'
    return fdef
def build_function ( func ) : indent = '    ' # temlpate and function name if func [ 'template' ] : fdef = func [ 'template' ] + '\n' else : fdef = '' newcall = func [ 'returns' ] + ' _' + func [ 'name' ] + '(' fdef += newcall + '\n' # function parameters # for each parameter # if it's an array #   - replace with py::array_t #   - skip the next _size argument #   - save in a list of arrays # else replicate i = 0 arraylist = [ ] needsize = False while i < len ( func [ 'parameters' ] ) : p = func [ 'parameters' ] [ i ] i += 1 # check if pointer/array if p [ 'pointer' ] or p [ 'array' ] : paramtype = p [ 'raw_type' ] const = '' if p [ 'constant' ] : const = 'const ' param = f'py::array_t<{paramtype}> &' + ' ' + p [ 'name' ] arraylist . append ( ( const , paramtype , p [ 'name' ] ) ) needsize = True elif '_size' not in p [ 'name' ] and needsize : # not a size, but needed one raise ValueError ( 'Expecting a _size parameter for {}' . format ( p [ 'name' ] ) ) elif '_size' in p [ 'name' ] : # just size, skip it needsize = False continue else : # if not a pointer, just copy it param = p [ 'type' ] + ' ' + p [ 'name' ] fdef += f'{param:>25}' # set width to 25 fdef += ',\n' fdef = fdef [ : - 2 ] # remove trailing comma and newline fdef += '\n' + ' ' * len ( newcall ) + ')' fdef += '\n{\n' # make a list of python objects for a in arraylist : if 'const' in a [ 0 ] : unchecked = '.unchecked();\n' else : unchecked = '.mutable_unchecked();\n' fdef += indent fdef += "auto py_" + a [ 2 ] + ' = ' + a [ 2 ] + unchecked # make a list of pointers to the arrays for a in arraylist : if 'const' in a [ 0 ] : data = '.data();\n' else : data = '.mutable_data();\n' fdef += indent fdef += a [ 0 ] + a [ 1 ] + ' *_' + a [ 2 ] + ' = py_' + a [ 2 ] + data # get the template signature if len ( arraylist ) > 0 : fdef += '\n' if func [ 'template' ] : template = func [ 'template' ] template = template . replace ( 'template' , '' ) . replace ( 'class ' , '' ) # template <class T> ----> <T> else : template = '' newcall = '    return ' + func [ 'name' ] + template + '(' fdef += newcall + '\n' # function parameters for i , p in enumerate ( func [ 'parameters' ] ) : if '_size' in p [ 'name' ] : fdef = fdef . strip ( ) name , s = p [ 'name' ] . split ( '_size' ) if s == '' : s = '0' fdef += f" {name}.shape({s})" else : if p [ 'pointer' ] or p [ 'array' ] : name = '_' + p [ 'name' ] else : name = p [ 'name' ] fdef += f'{name:>25}' if i < len ( func [ 'parameters' ] ) - 1 : fdef += ',\n' fdef += '\n' + ' ' * len ( newcall ) + ');\n}' return fdef