// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory
// License: Boost Software License   See LICENSE.txt for the full license.
// Authors: Davis E. King (davis@dlib.net)
#ifndef MIT_LL_CALL_MATLAB_H__
#define MIT_LL_CALL_MATLAB_H__

#include <string>
#include <sstream>
#include <dlib/error.h>
#include <dlib/assert.h>

namespace dlib
{

// ----------------------------------------------------------------------------------------

struct invalid_args_exception : error
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This is the exception thrown when the mex wrapper tries to convert a matlab
            object into a C++ object but for whatever reason can't (usually because the
            types don't match).
    !*/
    invalid_args_exception(const std::string& msg_): error(msg_) {}
    invalid_args_exception(const std::ostringstream& msg_): error(msg_.str()) {}
};

// ----------------------------------------------------------------------------------------

void check_for_matlab_ctrl_c();
/*!
    ensures
        - If the user of MATLAB has pressed ctrl+c then this function will throw an
          exception.
!*/

// ----------------------------------------------------------------------------------------

class matlab_object
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This object is a simple wrapper around matlab's generic mxArray, which is the
            thing that is matlab's "anything object".  So a matlab_object can be used as an
            argument to a mex_function() that can bind to any matlab object at all. It can
            also bind to "nothing" and so is inherently also an optional argument when
            present in a mex_funciton().
    !*/
public:
    matlab_object() : handle(0),should_free(false),arg_idx(0) {}
    matlab_object(const matlab_object&) = delete;

    ~matlab_object();


    // Check if a matlab object is bound to this object.
    bool is_empty() const { return handle==0; }
    operator bool() const { return handle!=0; }

    // Convert from MATLAB to C++, throw invalid_args_exception if not possible.
    template <typename T> operator T() const;
    template <typename T> void get(T& item) const; 

    // Convert from a C++ object to MATLAB
    template <typename T> matlab_object& operator= (const T& new_val);


    template <typename T> bool try_get(T& item) const
    {
        try { get(item); return true; }
        catch(invalid_args_exception&) { return false; }
    }

    const void* get_handle() const { return handle; }
    /*!
        ensures
            - returns a pointer to the mxArray object.  Might be NULL. 
    !*/


    matlab_object& operator=(const matlab_object&) = delete;

    // Users shouldn't call these functions
    const void* release_object_to_matlab() { const void* temp=handle; handle = 0; return temp; }
    void set_object_handle(int arg_idx_, const void* sh) { DLIB_CASSERT(!handle); handle = sh; arg_idx=arg_idx_; }
private:

    const void* handle;
    bool should_free;
    int arg_idx;
};

// ----------------------------------------------------------------------------------------

class matlab_struct 
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This object lets you interface with MATLAB structs from C++.  For example,
            given a MATLAB struct named mystruct, you could access it's fields like this:
                MATLAB way: mystruct.field
                C++ way:    mystruct["field"]
                MATLAB way: mystruct.field.subfield
                C++ way:    mystruct["field"]["subfield"]

            To get the values as C++ types you do something like this:
                int val = mystruct["field"];
            or 
                int val;  
                mystruct["field"].get(val);

            See also example_mex_struct.cpp for an example that uses this part of the API.
    !*/

    class sub;
public:
    matlab_struct() : struct_handle(0),should_free(false),arg_idx(0) {}
    matlab_struct(const matlab_struct&) = delete;
    ~matlab_struct();

    const sub operator[] (const std::string& name) const;
    sub operator[] (const std::string& name);
    bool has_field(const std::string& name) const;

    const void* release_struct_to_matlab() { const void* temp=struct_handle; struct_handle = 0; return temp; }
    void set_struct_handle(int arg_idx_, const void* sh) { DLIB_CASSERT(!struct_handle); struct_handle = sh; arg_idx=arg_idx_; }
private:

    class sub 
    {
    public:
        sub() : struct_handle(0), field_idx(-1) {}

        template <typename T> operator T() const;
        template <typename T> void get(T& item) const; 
        template <typename T> sub& operator= (const T& new_val);
        const sub operator[] (const std::string& name) const;
        sub operator[] (const std::string& name);
        bool has_field(const std::string& name) const;
    private:
        friend class matlab_struct;
        const void* struct_handle;
        int field_idx;
        sub& operator=(const sub&);
    };
    const void* struct_handle;
    bool should_free;
    int arg_idx;
    matlab_struct& operator=(const matlab_struct&); 
};

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

template <typename T> 
struct output_decorator
{
    output_decorator(T& item_):item(item_){}
    T& item;
};

template <typename T>
output_decorator<T> returns(T& item) { return output_decorator<T>(item); }
/*!
    ensures
        - decorates item as an output type.  This stuff is used by the call_matlab()
          functions to tell if an argument is an input to the function or is supposed
          to be bound to one of the return arguments.
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

struct function_handle
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This type is used to represent function handles passed from MATLAB into a
            mex function.  You can call the function referenced by the handle by
            saying:
                call_matlab(my_handle);
    !*/

    // These two lines are just implementation details, ignore them.
    function_handle():h(0){}
    void* const h;
};

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void call_matlab (
    const std::string& function_name
);
/*!
    ensures
        - Calls MATLAB's function of the given name
!*/

// ----------------------------------------------------------------------------------------

void call_matlab (
    const function_handle& funct 
);
/*!
    ensures
        - Calls MATLAB's function represented by the handle funct
!*/

// ----------------------------------------------------------------------------------------

template <
    typename T1
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1
);
/*!
    ensures
        - calls MATLAB's function of the given name.  
        - if (A1 is not decorated as an output by returns()) then
            - A1 is passed as an argument into the MATLAB function
        - else
            - A1 is treated as the first return value from the MATLAB function.
!*/

template <
    typename T1
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1
) { call_matlab("feval", funct, A1); }
/*!
    ensures
        - Calls MATLAB's function represented by the handle funct
        - if (A1 is not decorated as an output by returns()) then
            - A1 is passed as an argument into the MATLAB function
        - else
            - A1 is treated as the first return value from the MATLAB function.
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
/*
    The rest of this file is just overloads of call_matlab() for up to 10 arguments (or
    just 9 arguments if function_handle is used).  They all do the same thing as the above 
    version of call_matlab().  Generally, any argument not decorated by returns() is an 
    input to the MATLAB function.  On the other hand, all arguments decorated by returns() 
    are treated as outputs.  
*/
// ----------------------------------------------------------------------------------------

template <
    typename T1, 
    typename T2
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, 
    typename T2,
    typename T3
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, 
    typename T2,
    typename T3,
    typename T4
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, 
    typename T2,
    typename T3,
    typename T4,
    typename T5
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, 
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, 
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, 
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& A12
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16, typename T17
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16, typename T17, typename T18
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,
    const T18& A18
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16, typename T17, typename T18, typename T19
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,
    const T18& A18, const T19& A19
);

// ----------------------------------------------------------------------------------------

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16, typename T17, typename T18, typename T19,
    typename T20
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,
    const T18& A18, const T19& A19, const T20& A20
);

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2
)
{
    call_matlab("feval", funct, A1, A2);
}

template <
    typename T1,
    typename T2,
    typename T3
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3
)
{
    call_matlab("feval", funct, A1, A2, A3);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4
)
{
    call_matlab("feval", funct, A1, A2, A3, A4);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16, typename T17
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16, typename T17, typename T18
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,
    const T18& A18
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
}

template <
    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename
    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,
    typename T14, typename T15, typename T16, typename T17, typename T18, typename T19
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,
    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&
    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,
    const T18& A18, const T19& A19
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
}

// ----------------------------------------------------------------------------------------

// We define this function here so that, if you write some code that has check_for_matlab_ctrl_c()
// sprinkled throughout it you can still compile that code outside the mex wrapper
// environment and these calls will simply be no-ops.
#ifndef MATLAB_MEX_FILE
inline void check_for_matlab_ctrl_c() {}
#endif

}

#endif // MIT_LL_CALL_MATLAB_H__