From 5e42763478ee898f3978edac49173d1d586c1ccc Mon Sep 17 00:00:00 2001 From: Ian McInerney Date: Tue, 21 Nov 2023 16:26:26 +0000 Subject: [PATCH] Refactor how structs are passed to allow cleaner passing of OSQPInfo --- c_sources/CMakeLists.txt | 3 +- c_sources/osqp_mex.cpp | 59 +-------- c_sources/osqp_struct.h | 205 +++++++++++++++++++++++++++++ c_sources/osqp_struct_info.cpp | 43 ++++++ c_sources/osqp_struct_settings.cpp | 61 +++++++++ c_sources/settings_matlab.cpp | 103 --------------- c_sources/settings_matlab.h | 125 ------------------ 7 files changed, 317 insertions(+), 282 deletions(-) create mode 100644 c_sources/osqp_struct.h create mode 100644 c_sources/osqp_struct_info.cpp create mode 100644 c_sources/osqp_struct_settings.cpp delete mode 100644 c_sources/settings_matlab.cpp delete mode 100644 c_sources/settings_matlab.h diff --git a/c_sources/CMakeLists.txt b/c_sources/CMakeLists.txt index 86a1ec3..5c42782 100644 --- a/c_sources/CMakeLists.txt +++ b/c_sources/CMakeLists.txt @@ -67,7 +67,8 @@ matlab_add_mex( NAME osqp_mex SRC ${CMAKE_CURRENT_SOURCE_DIR}/osqp_mex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/interrupt_matlab.c ${CMAKE_CURRENT_SOURCE_DIR}/memory_matlab.c - ${CMAKE_CURRENT_SOURCE_DIR}/settings_matlab.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/osqp_struct_info.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/osqp_struct_settings.cpp LINK_TO osqpstatic ${UT_LIBRARY} # Force compilation in the traditional C API (equivalent to the -R2017b flag) diff --git a/c_sources/osqp_mex.cpp b/c_sources/osqp_mex.cpp index d97b5d4..52ec218 100755 --- a/c_sources/osqp_mex.cpp +++ b/c_sources/osqp_mex.cpp @@ -6,8 +6,8 @@ // Mex-specific functionality #include "osqp_mex.hpp" +#include "osqp_struct.h" #include "memory_matlab.h" -#include "settings_matlab.h" //c_int is replaced with OSQPInt //c_float is replaced with OSQPFloat @@ -16,23 +16,6 @@ // enum linsys_solver_type { QDLDL_SOLVER, MKL_PARDISO_SOLVER }; #define QDLDL_SOLVER 0 //Based on the previous API -// all of the OSQP_INFO fieldnames as strings -const char* OSQP_INFO_FIELDS[] = {"status", //char* - "status_val", //OSQPInt - "status_polish", //OSQPInt - "obj_val", //OSQPFloat - "prim_res", //OSQPFloat - "dual_res", //OSQPFloat - "iter", //OSQPInt - "rho_updates", //OSQPInt - "rho_estimate", //OSQPFloat - "setup_time", //OSQPFloat - "solve_time", //OSQPFloat - "update_time", //OSQPFloat - "polish_time", //OSQPFloat - "run_time", //OSQPFloat - }; - #define NEW_SETTINGS_TOL (1e-10) // wrapper class for all osqp data and settings @@ -52,7 +35,6 @@ void freeCscMatrix(OSQPCscMatrix* M); OSQPInt* copyToOSQPIntVector(mwIndex * vecData, OSQPInt numel); OSQPInt* copyDoubleToOSQPIntVector(double* vecData, OSQPInt numel); OSQPFloat* copyToOSQPFloatVector(double * vecData, OSQPInt numel); -mxArray* copyInfoToMxStruct(OSQPInfo* info); void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) @@ -131,7 +113,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } OSQPSettingsWrapper settings(prhs[2]); - osqp_update_settings(osqpData->solver, settings.GetOSQPSettings()); + osqp_update_settings(osqpData->solver, settings.GetOSQPStruct()); return; } @@ -214,7 +196,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) // Setup workspace //exitflag = osqp_setup(&(osqpData->work), data, settings); - exitflag = osqp_setup(&(osqpData->solver), dataP, dataQ, dataA, dataL, dataU, dataM, dataN, settings.GetOSQPSettings()); + exitflag = osqp_setup(&(osqpData->solver), dataP, dataQ, dataA, dataL, dataU, dataM, dataN, settings.GetOSQPStruct()); //cleanup temporary structures // Data if (Px) c_free(Px); @@ -466,7 +448,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) osqpData->solver->info->obj_val = mxGetNaN(); } - plhs[4] = copyInfoToMxStruct(osqpData->solver->info); // Info structure + // Populate the info structure + OSQPInfoWrapper info(osqpData->solver->info); + plhs[4] = info.GetMxStruct(); return; } @@ -614,34 +598,3 @@ void setToNaN(double* arr_out, OSQPInt len){ arr_out[i] = mxGetNaN(); } } - -mxArray* copyInfoToMxStruct(OSQPInfo* info){ - - //create mxArray with the right number of fields - int nfields = sizeof(OSQP_INFO_FIELDS) / sizeof(OSQP_INFO_FIELDS[0]); - mxArray* mxPtr = mxCreateStructMatrix(1,1,nfields,OSQP_INFO_FIELDS); - - //map the OSQP_INFO fields one at a time into mxArrays - //matlab all numeric values as doubles - mxSetField(mxPtr, 0, "iter", mxCreateDoubleScalar(info->iter)); - mxSetField(mxPtr, 0, "status", mxCreateString(info->status)); - mxSetField(mxPtr, 0, "status_val", mxCreateDoubleScalar(info->status_val)); - mxSetField(mxPtr, 0, "status_polish", mxCreateDoubleScalar(info->status_polish)); - mxSetField(mxPtr, 0, "obj_val", mxCreateDoubleScalar(info->obj_val)); - mxSetField(mxPtr, 0, "prim_res", mxCreateDoubleScalar(info->prim_res)); - mxSetField(mxPtr, 0, "dual_res", mxCreateDoubleScalar(info->dual_res)); - - mxSetField(mxPtr, 0, "setup_time", mxCreateDoubleScalar(info->setup_time)); - mxSetField(mxPtr, 0, "solve_time", mxCreateDoubleScalar(info->solve_time)); - mxSetField(mxPtr, 0, "update_time", mxCreateDoubleScalar(info->update_time)); - mxSetField(mxPtr, 0, "polish_time", mxCreateDoubleScalar(info->polish_time)); - mxSetField(mxPtr, 0, "run_time", mxCreateDoubleScalar(info->run_time)); - - - mxSetField(mxPtr, 0, "rho_updates", mxCreateDoubleScalar(info->rho_updates)); - mxSetField(mxPtr, 0, "rho_estimate", mxCreateDoubleScalar(info->rho_estimate)); - - - return mxPtr; - -} diff --git a/c_sources/osqp_struct.h b/c_sources/osqp_struct.h new file mode 100644 index 0000000..94a432f --- /dev/null +++ b/c_sources/osqp_struct.h @@ -0,0 +1,205 @@ +#ifndef OSQP_STRUCT_H_ +#define OSQP_STRUCT_H_ + +#include +#include +#include +#include + +#include +#include + +#include "memory_matlab.h" +#include + +/** + * Base class used to store the field types for a struct. + */ +class OSQPStructFieldBase { +public: + OSQPStructFieldBase() {} + + /** + * Set the field in the given Matlab struct to the value of this field + */ + virtual void ToMxStruct(mxArray* aStruct) = 0; + + /** + * Set the field in the internal struct with the data from aStruct + */ + virtual void ToOSQPStruct(const mxArray* aStruct) = 0; +}; + +/** + * Class to hold a numeric struct field (e.g. float/double/int/enum, etc.). + */ +template +class OSQPStructField : public OSQPStructFieldBase { +public: + OSQPStructField(T* aStructPtr, std::string aName) : + m_structPtr(aStructPtr), + m_name(aName) { + } + + void ToMxStruct(mxArray* aStruct) override { + mxAddField(aStruct, m_name.data()); + mxSetField(aStruct, 0, m_name.data(), mxCreateDoubleScalar(*m_structPtr)); + } + + void ToOSQPStruct(const mxArray* aStruct) override { + *(m_structPtr) = static_cast(mxGetScalar(mxGetField(aStruct, 0, m_name.data()))); + } + +private: + T* m_structPtr; + std::string m_name; +}; + +/** + * Class to hold a character array (actual array, not char* array) field in a struct. + */ +class OSQPStructFieldCharArray : public OSQPStructFieldBase { +public: + OSQPStructFieldCharArray(char* aStructPtr, size_t aLength, std::string aName) : + m_structPtr(aStructPtr), + m_name(aName), + m_length(aLength) { + } + + void ToMxStruct(mxArray* aStruct) override { + mxAddField(aStruct, m_name.data()); + mxSetField(aStruct, 0, m_name.data(), mxCreateString(m_structPtr)); + } + + void ToOSQPStruct(const mxArray* aStruct) override { + mxArray* tmp = mxGetField(aStruct, 0, m_name.data()); + mxGetString(tmp, m_structPtr, m_length); + } + +private: + char* m_structPtr; + std::string m_name; + size_t m_length; +}; + +/** + * Wrap a struct from OSQP to automatically transfer the data between OSQP and Matlab. + */ +template +class OSQPStructWrapper { +public: + /** + * Initialize the wrapper using the default values. + */ + OSQPStructWrapper() { + // Allocate the default struct and register field handlers + registerFields(); + } + + /** + * Initialize the wrapper using the values from the OSQP struct. + */ + OSQPStructWrapper(const T* aStruct) { + // Allocate the default struct and register field handlers + registerFields(); + ParseOSQPStruct(aStruct); + } + + /** + * Initialize the wrapper using the values from the Matlab struct + */ + OSQPStructWrapper(const mxArray* aStruct) { + // Allocate the default struct and register field handlers + registerFields(); + ParseMxStruct(aStruct); + } + + ~OSQPStructWrapper() { + for(auto& s : m_structFields) { + delete s; + } + + c_free(m_struct); + } + + /** + * Return a Matlab struct populated with the values of the current struct + * contained in this wrapper. + * + * @return a Matlab struct with a copy of the struct (caller owns this copy and must free it) + */ + mxArray* GetMxStruct() { + // No fields are added right now, they are added in the for loop when they are set + mxArray* matStruct = mxCreateStructMatrix(1, 1, 0, NULL); + + // Copy the current struct into the struct to return + for(const auto& s : m_structFields) { + s->ToMxStruct(matStruct); + } + + return matStruct; + } + + /** + * Read a Matlab struct and populate the wrapper with its values. + */ + void ParseMxStruct(const mxArray* aStruct) { + for(const auto& s : m_structFields) { + s->ToOSQPStruct(aStruct); + } + } + + /** + * Get a copy of the struct contained inside this wrapper. + * + * @return a copy of the struct (caller owns this copy and must free it) + */ + T* GetOSQPStructCopy() { + // Allocate the default struct + T* ret = static_cast(c_calloc(1, sizeof(T))); + + // Copy the current values for their return + std::memcpy(ret, m_struct, sizeof(T)); + return ret; + } + + /** + * Get the pointer to the internal struct object. + */ + T* GetOSQPStruct() { + return m_struct; + } + + /* + * Read an existing OSQP struct object into this wrapper. + * The struct elements are copied, so no ownership of the aStruct pointer is transferred. + */ + void ParseOSQPStruct(const T* aStruct) { + std::memcpy(m_struct, aStruct, sizeof(T)); + } + +private: + /** + * Register all the fields for the wrapper. + * This function should be specialized for each struct type to map the fields appropriately. + */ + void registerFields(); + + // All struct fields + std::vector m_structFields; + + // Base OSQP struct object. Owned by this wrapper. + T* m_struct; +}; + +/** + * Wrapper around the OSQPSettings struct + */ +typedef OSQPStructWrapper OSQPSettingsWrapper; + +/** + * Wrapper around the OSQPInfo struct + */ +typedef OSQPStructWrapper OSQPInfoWrapper; + +#endif \ No newline at end of file diff --git a/c_sources/osqp_struct_info.cpp b/c_sources/osqp_struct_info.cpp new file mode 100644 index 0000000..b454a1c --- /dev/null +++ b/c_sources/osqp_struct_info.cpp @@ -0,0 +1,43 @@ +#include +#include "osqp_struct.h" + + +/* + * Specialization of the struct wrapper for the OSQPInfo struct. + */ +template<> +void OSQPStructWrapper::registerFields() { + m_struct = static_cast(c_calloc(1, sizeof(OSQPInfo))); + + if(!m_struct) + mexErrMsgTxt("Failed to allocate a OSQPInfo object."); + + /* + * Register the mapping between struct field name and the info struct memory location + */ + // Solver status + m_structFields.push_back(new OSQPStructFieldCharArray(m_struct->status, 32, "status")); + m_structFields.push_back(new OSQPStructField(&m_struct->status_val, "status_val")); + m_structFields.push_back(new OSQPStructField(&m_struct->status_polish, "status_polish")); + + // Solution quality + m_structFields.push_back(new OSQPStructField(&m_struct->obj_val, "obj_val")); + m_structFields.push_back(new OSQPStructField(&m_struct->prim_res, "prim_res")); + m_structFields.push_back(new OSQPStructField(&m_struct->dual_res, "dual_res")); + + // Algorithm information + m_structFields.push_back(new OSQPStructField(&m_struct->iter, "iter")); + m_structFields.push_back(new OSQPStructField(&m_struct->rho_updates, "rho_updates")); + m_structFields.push_back(new OSQPStructField(&m_struct->rho_estimate, "rho_estimate")); + + // Timing information + m_structFields.push_back(new OSQPStructField(&m_struct->setup_time, "setup_time")); + m_structFields.push_back(new OSQPStructField(&m_struct->solve_time, "solve_time")); + m_structFields.push_back(new OSQPStructField(&m_struct->update_time, "update_time")); + m_structFields.push_back(new OSQPStructField(&m_struct->polish_time, "polish_time")); + m_structFields.push_back(new OSQPStructField(&m_struct->run_time, "run_time")); +} + + +// Instantiate the OSQPInfo wrapper class +template class OSQPStructWrapper; \ No newline at end of file diff --git a/c_sources/osqp_struct_settings.cpp b/c_sources/osqp_struct_settings.cpp new file mode 100644 index 0000000..97fc357 --- /dev/null +++ b/c_sources/osqp_struct_settings.cpp @@ -0,0 +1,61 @@ +#include +#include "osqp_struct.h" + +/* + * Specialization for the settings struct + */ +template<> +void OSQPStructWrapper::registerFields() { + m_struct = static_cast(c_calloc(1, sizeof(OSQPSettings))); + + if(!m_struct) + mexErrMsgTxt("Failed to allocate a OSQPSettings object."); + + osqp_set_default_settings(m_struct); + + /* + * Register the mapping between struct field name and the settings memory location + */ + m_structFields.push_back(new OSQPStructField(&m_struct->device, "device")); + m_structFields.push_back(new OSQPStructField(&m_struct->linsys_solver, "linsys_solver")); + m_structFields.push_back(new OSQPStructField(&m_struct->verbose, "verbose")); + m_structFields.push_back(new OSQPStructField(&m_struct->warm_starting, "warm_starting")); + m_structFields.push_back(new OSQPStructField(&m_struct->scaling, "scaling")); + m_structFields.push_back(new OSQPStructField(&m_struct->polishing, "polishing")); + + // ADMM parameters + m_structFields.push_back(new OSQPStructField(&m_struct->rho, "rho")); + m_structFields.push_back(new OSQPStructField(&m_struct->rho_is_vec, "rho_is_vec")); + m_structFields.push_back(new OSQPStructField(&m_struct->sigma, "sigma")); + m_structFields.push_back(new OSQPStructField(&m_struct->alpha, "alpha")); + + // CG settings + m_structFields.push_back(new OSQPStructField(&m_struct->cg_max_iter, "cg_max_iter")); + m_structFields.push_back(new OSQPStructField(&m_struct->cg_tol_reduction, "cg_tol_reduction")); + m_structFields.push_back(new OSQPStructField(&m_struct->cg_tol_fraction, "cg_tol_fraction")); + m_structFields.push_back(new OSQPStructField(&m_struct->cg_precond, "cg_precond")); + + // adaptive rho logic + m_structFields.push_back(new OSQPStructField(&m_struct->adaptive_rho, "adaptive_rho")); + m_structFields.push_back(new OSQPStructField(&m_struct->adaptive_rho_interval, "adaptive_rho_interval")); + m_structFields.push_back(new OSQPStructField(&m_struct->adaptive_rho_fraction, "adaptive_rho_fraction")); + m_structFields.push_back(new OSQPStructField(&m_struct->adaptive_rho_tolerance, "adaptive_rho_tolerance")); + + // termination parameters + m_structFields.push_back(new OSQPStructField(&m_struct->max_iter, "max_iter")); + m_structFields.push_back(new OSQPStructField(&m_struct->eps_abs, "eps_abs")); + m_structFields.push_back(new OSQPStructField(&m_struct->eps_rel, "eps_rel")); + m_structFields.push_back(new OSQPStructField(&m_struct->eps_prim_inf, "eps_prim_inf")); + m_structFields.push_back(new OSQPStructField(&m_struct->eps_dual_inf, "eps_dual_inf")); + m_structFields.push_back(new OSQPStructField(&m_struct->scaled_termination, "scaled_termination")); + m_structFields.push_back(new OSQPStructField(&m_struct->check_termination, "check_termination")); + m_structFields.push_back(new OSQPStructField(&m_struct->time_limit, "time_limit")); + + // polishing parameters + m_structFields.push_back(new OSQPStructField(&m_struct->delta, "delta")); + m_structFields.push_back(new OSQPStructField(&m_struct->polish_refine_iter, "polish_refine_iter")); +} + + +// Instantiate the OSQPSettings wrapper class +template class OSQPStructWrapper; \ No newline at end of file diff --git a/c_sources/settings_matlab.cpp b/c_sources/settings_matlab.cpp deleted file mode 100644 index 6607331..0000000 --- a/c_sources/settings_matlab.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include - -#include "memory_matlab.h" -#include "settings_matlab.h" - -#include - - -void OSQPSettingsWrapper::registerFields() { - m_settings = static_cast(c_calloc(1, sizeof(OSQPSettings))); - - if(!m_settings) - mexErrMsgTxt("Failed to allocate a OSQPSettings object."); - - osqp_set_default_settings(m_settings); - - /* - * Register the mapping between struct field name and the settings memory location - */ - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->device, "device")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->linsys_solver, "linsys_solver")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->verbose, "verbose")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->warm_starting, "warm_starting")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->scaling, "scaling")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->polishing, "polishing")); - - // ADMM parameters - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->rho, "rho")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->rho_is_vec, "rho_is_vec")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->sigma, "sigma")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->alpha, "alpha")); - - // CG settings - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->cg_max_iter, "cg_max_iter")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->cg_tol_reduction, "cg_tol_reduction")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->cg_tol_fraction, "cg_tol_fraction")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->cg_precond, "cg_precond")); - - // adaptive rho logic - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->adaptive_rho, "adaptive_rho")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->adaptive_rho_interval, "adaptive_rho_interval")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->adaptive_rho_fraction, "adaptive_rho_fraction")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->adaptive_rho_tolerance, "adaptive_rho_tolerance")); - - // termination parameters - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->max_iter, "max_iter")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->eps_abs, "eps_abs")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->eps_rel, "eps_rel")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->eps_prim_inf, "eps_prim_inf")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->eps_dual_inf, "eps_dual_inf")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->scaled_termination, "scaled_termination")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->check_termination, "check_termination")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->time_limit, "time_limit")); - - // polishing parameters - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->delta, "delta")); - m_settingsFields.push_back(new OSQPSettingsField(&m_settings->polish_refine_iter, "polish_refine_iter")); -} - - -OSQPSettingsWrapper::~OSQPSettingsWrapper() { - for(auto& s : m_settingsFields) { - delete s; - } - - c_free(m_settings); -} - - -mxArray* OSQPSettingsWrapper::GetMxStruct() { - // No fields are added right now, they are added in the for loop when they are set - mxArray* mxSettings = mxCreateStructMatrix(1, 1, 0, NULL); - - // Copy the current settings into the struct to return - for(const auto& s : m_settingsFields) { - s->ToMxStruct(mxSettings); - } - - return mxSettings; -} - - -void OSQPSettingsWrapper::ParseMxStruct(const mxArray* aStruct) { - for(const auto& s : m_settingsFields) { - s->ToOSQPSettings(aStruct); - } -} - - -OSQPSettings* OSQPSettingsWrapper::GetOSQPSettingsCopy() { - // Allocate the default settings - OSQPSettings* ret = static_cast(c_calloc(1, sizeof(OSQPSettings))); - - // Copy the current settings for their return - std::memcpy(ret, m_settings, sizeof(OSQPSettings)); - - return ret; -} - - -void OSQPSettingsWrapper::ParseOSQPSettings(const OSQPSettings* aSettings) { - std::memcpy(m_settings, aSettings, sizeof(OSQPSettings)); -} diff --git a/c_sources/settings_matlab.h b/c_sources/settings_matlab.h deleted file mode 100644 index 28ee832..0000000 --- a/c_sources/settings_matlab.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef SETTINGS_MATLAB_H_ -#define SETTINGS_MATLAB_H_ - -#include -#include -#include - -#include -#include -#include - -/* - * Base class used to store the templated settings field types. - */ -class OSQPSettingsFieldBase { -public: - OSQPSettingsFieldBase() {} - - virtual void ToMxStruct(mxArray* aStruct) = 0; - virtual void ToOSQPSettings(const mxArray* aStruct) = 0; -}; - -template -class OSQPSettingsField : public OSQPSettingsFieldBase { -public: - OSQPSettingsField(T* aSettingPtr, std::string aName) : - m_settingsPtr(aSettingPtr), - m_name(aName) { - } - - /* - * Set the field in the given Matlab struct to the value of this settings field - */ - void ToMxStruct(mxArray* aStruct) override { - mxAddField(aStruct, m_name.data()); - mxSetField(aStruct, 0, m_name.data(), mxCreateDoubleScalar(*m_settingsPtr)); - } - - /* - * Set the field in the internal OSQPSettings struct with the data from aStruct - */ - void ToOSQPSettings(const mxArray* aStruct) override { - *(m_settingsPtr) = static_cast(mxGetScalar(mxGetField(aStruct, 0, m_name.data()))); - } - -private: - T* m_settingsPtr; - std::string m_name; -}; - -class OSQPSettingsWrapper { -public: - /* - * Initialize the settings wrapper using the default settings. - */ - OSQPSettingsWrapper() { - // Allocate the default settings and register field handlers - registerFields(); - } - - /* - * Initialize the settings wrapper using the values from aSettings. - */ - OSQPSettingsWrapper(const OSQPSettings* aSettings) { - // Allocate the default settings and register field handlers - registerFields(); - ParseOSQPSettings(aSettings); - } - - /* - * Initialize the settings wrapper using the values from aStruct - */ - OSQPSettingsWrapper(const mxArray* aStruct) { - // Allocate the default settings and register field handlers - registerFields(); - ParseMxStruct(aStruct); - } - - ~OSQPSettingsWrapper(); - - /* - * Return a Matlab structu populated with the values of the current settings - * contained in this wrapper. - * - * @return a Matlab struct with a copy of the settings (caller owns this copy and must free it) - */ - mxArray* GetMxStruct(); - - /* - * Read a Matlab struct and populate the wrapper with its values. - */ - void ParseMxStruct(const mxArray* aStruct); - - /* - * Get a copy of the settings contained inside this wrapper. - * - * @return a copy of the settings (caller owns this copy and must free it) - */ - OSQPSettings* GetOSQPSettingsCopy(); - - /* - * Get the pointer to the internal settings object. - */ - OSQPSettings* GetOSQPSettings() { - return m_settings; - } - - /* - * Read an existing OSQPSettings object into this wrapper. - * The settings are copied, so no ownership of the aSettings pointer is transferred. - */ - void ParseOSQPSettings(const OSQPSettings* aSettings); - -private: - // Register all the fields - void registerFields(); - - // All settings fields - std::vector m_settingsFields; - - // Base OSQP settings object. Owned by this wrapper. - OSQPSettings* m_settings; -}; - -#endif \ No newline at end of file