MocoExtendProblem: Interface Between OpenSim and MATLAB for Rapidly Developing Direct Collocation Goals in Moco 1.1.0
add custom Moco goals to existing matlab scripts
arguments.h
Go to the documentation of this file.
1
30#ifndef INCLUDE_MEXPLUS_ARGUMENTS_H_
31#define INCLUDE_MEXPLUS_ARGUMENTS_H_
32
33#include <cstdarg>
34#include <map>
35#include <sstream>
36#include <string>
37#include <vector>
38#include "mexplus/mxarray.h"
39
40namespace mexplus {
41
70 public:
75 bool operator() (const char& c1, const char& c2) const {
76 return tolower(c1) < tolower(c2);
77 }
78 };
79 bool operator() (const std::string & s1, const std::string & s2) const {
80 return std::lexicographical_compare(s1.begin(),
81 s1.end(),
82 s2.begin(),
83 s2.end(),
85 }
86 };
87
88 typedef std::map<std::string, const mxArray*, CaseInsensitiveComparator>
92 typedef struct Definition_tag {
93 std::vector<const mxArray*> mandatories;
94 OptionMap optionals;
95 } Definition;
96
103 const mxArray* prhs[],
104 int mandatory_size = 1,
105 int option_size = 0,
106 ...) {
107 Definition* definition = &definitions_["default"];
108 definition->mandatories.resize(mandatory_size, NULL);
109 va_list variable_list;
110 va_start(variable_list, option_size);
111 fillOptionalDefinition(option_size, &definition->optionals, variable_list);
112 va_end(variable_list);
113 parse(nrhs, prhs);
114 }
115 virtual ~InputArguments() {}
118 void define(const std::string name,
119 int mandatory_size,
120 int option_size = 0,
121 ...) {
122 Definition* definition = &definitions_[name];
123 definition->mandatories.resize(mandatory_size);
124 va_list variable_list;
125 va_start(variable_list, option_size);
126 fillOptionalDefinition(option_size, &definition->optionals, variable_list);
127 va_end(variable_list);
128 }
131 void parse(int nrhs,
132 const mxArray* prhs[],
133 bool ignore_multi_signatures = false) {
134 if (definitions_.empty())
135 mexErrMsgIdAndTxt("mexplus:arguments:error", "No format defined.");
136 std::map<std::string, Definition>::iterator entry;
137 std::vector<std::map<std::string, Definition>::iterator> delete_positions;
138 for (entry = definitions_.begin(); entry != definitions_.end(); ++entry)
139 if (!parseDefinition(nrhs, prhs, &entry->second))
140 delete_positions.push_back(entry);
141 for (size_t i = 0; i < delete_positions.size(); ++i)
142 definitions_.erase(delete_positions[i]);
143 if (definitions_.empty())
144 mexErrMsgIdAndTxt("mexplus:arguments:error",
145 (error_message_.empty()) ?
146 "Invalid arguments." : error_message_.c_str());
147 if (definitions_.size() > 1 && !ignore_multi_signatures)
148 mexWarnMsgIdAndTxt("mexplus:arguments:warning",
149 "Input arguments match more than one signature.");
150 }
153 bool is(const std::string& name) const {
154 std::map<std::string, Definition>::const_iterator entry =
155 definitions_.find(name);
156 return (entry != definitions_.end());
157 }
160 const mxArray* get(size_t index) const {
161 if (definitions_.empty())
162 mexErrMsgIdAndTxt("mexplus:arguments:error", "No format defined.");
163 const Definition& definition = definitions_.begin()->second;
164 if (index >= definition.mandatories.size())
165 mexErrMsgIdAndTxt("mexplus:arguments:error", "Index out of range.");
166 return definition.mandatories[index];
167 }
170 template <typename T>
171 T get(size_t index) const;
172 template <typename T>
173 void get(size_t index, T* value) const;
176 const mxArray* get(const std::string& option_name) const {
177 if (definitions_.empty())
178 mexErrMsgIdAndTxt("mexplus:arguments:error", "No format defined.");
179 const Definition& definition = definitions_.begin()->second;
180 OptionMap::const_iterator entry =
181 definition.optionals.find(option_name);
182 if (entry == definition.optionals.end())
183 mexErrMsgIdAndTxt("mexplus:arguments:error",
184 "Unknown option %s.",
185 option_name.c_str());
186 return entry->second;
187 }
190 template <typename T>
191 T get(const std::string& option_name, const T& default_value) const;
192 template <typename T>
193 void get(const std::string& option_name,
194 const T& default_value,
195 T* value) const;
198 const mxArray* operator[] (size_t index) const { return get(index); }
201 const mxArray* operator[] (const std::string& option_name) const {
202 return get(option_name);
203 }
204
205 private:
208 void fillOptionalDefinition(int option_size,
209 OptionMap* optionals,
210 va_list variable_list) {
211 for (int i = 0; i < option_size; ++i) {
212 const char* option_name = va_arg(variable_list, const char*);
213 (*optionals)[std::string(option_name)] = NULL;
214 }
215 }
218 bool parseDefinition(size_t nrhs,
219 const mxArray* prhs[],
220 Definition* definition) {
221 const size_t kMaxOptionNameSize = 64;
222 std::stringstream message;
223 std::string option_name;
224 if (nrhs < definition->mandatories.size()) {
225 message << "Too few arguments: " << nrhs << " for at least "
226 << definition->mandatories.size() << ".";
227 error_message_.assign(message.str());
228 return false;
229 }
230 size_t index = 0;
231 for (; index < definition->mandatories.size(); ++index)
232 definition->mandatories[index] = prhs[index];
233
234 /* If the first argument behind all mandatories is the least one and
235 * represents a structure array with only one element, it is assumed to be
236 * a config structure with fields for all optionals.
237 */
238 if (nrhs - index == 1 &&
239 mxIsStruct(prhs[index]) &&
240 mxGetNumberOfElements(prhs[index]) == 1) {
241 MxArray config(prhs[index]);
242 for (int field_index = 0;
243 field_index < config.fieldSize();
244 ++field_index) {
245 // Check the config structure for fields.
246 option_name = config.fieldName(field_index);
247 if (option_name.size() > kMaxOptionNameSize) {
248 message << "Option name too long: " << option_name.size()
249 << " characters for " << kMaxOptionNameSize - 1;
250 error_message_.assign(message.str());
251 return false;
252 }
253 OptionMap::iterator entry =
254 definition->optionals.find(option_name);
255 if (entry == definition->optionals.end()) {
256 message << "Invalid option name: '" << option_name << "'.";
257 error_message_.assign(message.str());
258 return false;
259 }
260 // Get optional value from "config structure".
261 entry->second = config.at(config.fieldName(field_index));
262 }
263 }
264 else { // Conventional option list.
265 while (true) {
266 if (index >= nrhs) break;
267 // Check if the option name is valid.
268 MxArray option_name_array(prhs[index++]);
269 if (!option_name_array.isChar()) {
270 message << "Option name must be char but is given "
271 << option_name_array.className() << ".";
272 error_message_.assign(message.str());
273 return false;
274 }
275 option_name = option_name_array.to<std::string>();
276 if (option_name.size() > kMaxOptionNameSize) {
277 message << "Option name too long: " << option_name.size()
278 << " characters for " << kMaxOptionNameSize - 1;
279 error_message_.assign(message.str());
280 return false;
281 }
282 OptionMap::iterator entry =
283 definition->optionals.find(option_name);
284 if (entry == definition->optionals.end()) {
285 message << "Invalid option name: '" << option_name << "'.";
286 error_message_.assign(message.str());
287 return false;
288 }
289 // Check if options are even.
290 if (index >= nrhs) {
291 message << "Missing option value for option '" << option_name
292 << "'.";
293 error_message_.assign(message.str());
294 return false;
295 }
296 // Check if the option is already filled.
297 if (entry->second)
298 mexWarnMsgIdAndTxt("mexplus:arguments:warning",
299 "Option '%s' appeared more than once.",
300 option_name.c_str());
301 // Assign optional value.
302 entry->second = prhs[index++];
303 }
304 }
305 return true;
306 }
309 std::map<std::string, Definition> definitions_;
312 std::string error_message_;
313};
314
315template <typename T>
316T InputArguments::get(size_t index) const {
317 T value;
318 get<T>(index, &value);
319 return value;
320}
321
322template <typename T>
323void InputArguments::get(size_t index, T* value) const {
324 MxArray::to<T>(get(index), value);
325}
326
327template <typename T>
328T InputArguments::get(const std::string& option_name,
329 const T& default_value) const {
330 T value;
331 get<T>(option_name, default_value, &value);
332 return value;
333}
334
335template <typename T>
336void InputArguments::get(const std::string& option_name,
337 const T& default_value,
338 T* value) const {
339 MxArray option(get(option_name));
340 if (option)
341 option.to<T>(value);
342 else
343 *value = default_value;
344}
345
360 public:
364 mxArray** plhs,
365 int maximum_size = 1,
366 int mandatory_size = 0) : nlhs_(nlhs), plhs_(plhs) {
367 if (mandatory_size > nlhs)
368 mexErrMsgIdAndTxt("mexplus:arguments:error",
369 "Too few output: %d for %d.",
370 nlhs,
371 mandatory_size);
372 if (maximum_size < nlhs)
373 mexErrMsgIdAndTxt("mexplus:arguments:error",
374 "Too many output: %d for %d.",
375 nlhs,
376 maximum_size);
377 }
380 void set(size_t index, mxArray* value) {
381 if (index < nlhs_)
382 plhs_[index] = value;
383 }
386 template <typename T>
387 void set(size_t index, const T& value) {
388 set(index, MxArray::from(value));
389 }
392 size_t size() const { return nlhs_; }
395 mxArray* const& operator[] (size_t index) const {
396 if (index >= nlhs_)
397 mexErrMsgIdAndTxt("mexplus:arguments:error",
398 "Output index out of range: %d.",
399 index);
400 return plhs_[index];
401 }
404 mxArray*& operator[] (size_t index) {
405 if (index >= nlhs_)
406 mexErrMsgIdAndTxt("mexplus:arguments:error",
407 "Output index out of range: %d.",
408 index);
409 return plhs_[index];
410 }
411
412 private:
415 size_t nlhs_;
418 mxArray** plhs_;
419};
420
421} // namespace mexplus
422
423#endif // INCLUDE_MEXPLUS_ARGUMENTS_H_
Utility to parse input arguments.
Definition arguments.h:69
void parse(int nrhs, const mxArray *prhs[], bool ignore_multi_signatures=false)
Parse arguments from mexFunction input.
Definition arguments.h:131
void fillOptionalDefinition(int option_size, OptionMap *optionals, va_list variable_list)
Fill in optional arguments definition.
Definition arguments.h:208
const mxArray * get(const std::string &option_name) const
Get a parsed optional argument.
Definition arguments.h:176
InputArguments(int nrhs, const mxArray *prhs[], int mandatory_size=1, int option_size=0,...)
Shorthand constructor for a single argument definition.
Definition arguments.h:102
std::map< std::string, Definition > definitions_
Format definitions.
Definition arguments.h:309
bool is(const std::string &name) const
Return which format is chosen.
Definition arguments.h:153
std::string error_message_
Last error message.
Definition arguments.h:312
void define(const std::string name, int mandatory_size, int option_size=0,...)
Define a new argument format.
Definition arguments.h:118
const mxArray * get(size_t index) const
Get a parsed mandatory argument.
Definition arguments.h:160
InputArguments()
Empty constructor.
Definition arguments.h:99
bool parseDefinition(size_t nrhs, const mxArray *prhs[], Definition *definition)
Try to parse one definition or return false on failure.
Definition arguments.h:218
std::map< std::string, const mxArray *, CaseInsensitiveComparator > OptionMap
Definition arguments.h:89
virtual ~InputArguments()
Definition arguments.h:115
const mxArray * operator[](size_t index) const
Access raw mxArray* pointer.
Definition arguments.h:198
mxArray object wrapper for data conversion and manipulation.
Definition mxarray.h:101
static void to(const mxArray *array, T *value)
mxArray* exporter methods.
Definition mxarray.h:315
static T at(const mxArray *array, mwIndex index)
mxArray* element reader methods.
Definition mxarray.h:327
static mxArray * from(const T &value)
mxArray* importer methods.
Definition mxarray.h:300
T to() const
Convert MxArray to a specified type.
Definition mxarray.h:402
std::string fieldName(int index) const
Get field name of a struct array.
Definition mxarray.h:591
int fieldSize() const
Number of fields in a struct array.
Definition mxarray.h:586
const std::string className() const
Class name of mxArray.
Definition mxarray.h:559
bool isChar() const
Determine whether input is string array.
Definition mxarray.h:634
Output arguments wrapper.
Definition arguments.h:359
size_t size() const
Size of the output.
Definition arguments.h:392
void set(size_t index, const T &value)
Safely assign T to the output.
Definition arguments.h:387
mxArray *const & operator[](size_t index) const
Const square bracket operator.
Definition arguments.h:395
void set(size_t index, mxArray *value)
Safely assign mxArray to the output.
Definition arguments.h:380
mxArray ** plhs_
Output argument array.
Definition arguments.h:418
size_t nlhs_
Number of output arguments.
Definition arguments.h:415
OutputArguments(int nlhs, mxArray **plhs, int maximum_size=1, int mandatory_size=0)
Construct output argument wrapper.
Definition arguments.h:363
MEX function arguments helper library.
Definition arguments.h:40
Definition of arguments.
Definition arguments.h:92
std::vector< const mxArray * > mandatories
Definition arguments.h:93
OptionMap optionals
Definition arguments.h:94
bool operator()(const char &c1, const char &c2) const
Definition arguments.h:75
Case-insensitive comparator for std::string.
Definition arguments.h:73
bool operator()(const std::string &s1, const std::string &s2) const
Definition arguments.h:79