Set and get structure field with invalid name

38 visualizzazioni (ultimi 30 giorni)
I'd like to get and set a structure with potentially invalid field names. Before digging into the mex myself I was wondering if there was already a tool that existed that performed these functions. I swear I've seen this around but my search skills are failing me. Finally, I assume this is possible with mex ....
Thanks, Jim
  1 Commento
Jim Hokanson
Jim Hokanson il 28 Lug 2016
Clarification: I am trying to accomplish an ordered dictionary in Matlab that accepts and retrieves arbitrary field names. It turns out that the retrieval is relatively easy, you just need to use dynamic indexing. The setting is the difficult part, especially if it is for a structure that already exists. I am currently working on an implementation based off of: http://www.mathworks.com/matlabcentral/fileexchange/28516-renamefield
I'll post the solution when I'm done ...

Accedi per commentare.

Risposta accettata

Jim Hokanson
Jim Hokanson il 1 Ago 2016
I knew I had seen this somewhere before. Amro posted this link: http://pastebin.com/j69kQEur
Key point summaries:
  1. Retrieval is easy for invalid field names
  2. Setting can be done using mex
  3. In place modifications of a struct currently are not documented by mex, so some duplication needs to be performed.
  4. An initial version of my code can be found at: https://gist.github.com/JimHokanson/84141d0955a6a0eaed68516e3f69487a
  5. I personally have wrapped this in an object to make the call to setField transparent and only done when an in place call is not possible (i.e. when the field name is invalid)
  4 Commenti
Jim Hokanson
Jim Hokanson il 4 Ago 2016
Hi James,
Thanks for the feedback!
For point 3, what does a NULL input mean? Calling this from Matlab presumably that would not be possible? Or does a structure array have null values for unassigned elements? Where as presumably a single structure element wouldn't have extra fields?)
Since I've got something that sort of works right now I'm moving on to the next part of my project, but I plan on implementing your recommendations at a later point.
Thanks again, Jim
James Tursa
James Tursa il 4 Ago 2016
Modificato: James Tursa il 4 Ago 2016
Point 3) When you first create a struct with mxCreateStructMatrix or mxCreateStructArray, all of the field elements will contain NULL values (unless the struct is empty and there are no field elements). I.e., every result of a mxGetField or mxGetFieldByNumber call will return a NULL value since that is what is physically in the data area of the struct ... nothing has been set yet. Same thing for adding a field with mxAddField ... those new extra field elements will physically have NULL in those spots.
You can also get this from the MATLAB m-code level. Anything that creates a struct without assigning field elements will physically have NULL values in those spots. E.g., if S doesn't exist, and you did this at the m-code level:
S(3).stuff = 5;
You didn't assign anything to S(1).stuff or S(2).stuff, so those spots are physically NULL in the mxArray data area. Now, if you access those spots at the m-code level you get an empty double result, i.e. using S(1).stuff is legal and it will be an empty double, but in fact this is something that MATLAB creates on the fly in those situations ... there is no empty double mxArray in those unassigned spots. You can easily check this by passing it to a mex routine and examining those spots.
The above NULL comments apply to cell arrays also, btw.

Accedi per commentare.

Più risposte (2)

James Tursa
James Tursa il 27 Lug 2016
Modificato: James Tursa il 27 Lug 2016
I would start with this if you are trying to get stuff from a mat file:
Although I haven't looked at it in awhile to see if it still works for later versions of MATLAB.
If you are doing something else let me know and maybe we can customize it for your needs.
UPDATE:
I just did a quick check and the included savebadnames.c function does not work anymore. Apparently the matPutVariable API function now checks for invalid names. While this is probably a good thing, it also means I can't generate a bad mat file to use for checking the functionality of the main routine loadfixnames.c. I may have to write some custom C code to create the mat file from scratch without using the API functions. But that is not trivial, so it will not happen anytime soon ...
Hopefully the matGetNextVariable API function does not do this check. If it does then loadfixnames.c is toast ...
  5 Commenti
James Tursa
James Tursa il 28 Lug 2016
Modificato: James Tursa il 28 Lug 2016
Some comments:
It sounds like you want to do the equivalent of the following with a mex routine:
Create a struct with arbitrary field names
Add arbitrary field names to an existing struct
Set an arbitrary field element to something, e.g.,
mystruct.('Bad Field Name$') = something
1) Creating a struct with arbitrary field names is easy in a mex routine, since the mxCreateStructArray API function apparently does not check for invalid field names, at least on the R2011b version I just spot checked. Not sure about later versions. If later versions do check for invalid field names, this becomes much more difficult and would probably require hacking into the mxArray. That in itself is very tricky because the method of storing field names in a mxArray is different depending on which version of MATLAB you are running.
2) Modifying an existing struct in a mex routine, either by adding a new field or by setting a field, has the problem of efficiency. The only way to take an input struct and modify it with official API functions is to first create a deep copy of it with mxDuplicateArray, and then do the modifications. If your field elements are large, then you get memory bloat and speed problems. The only way to avoid this is to use unofficial API functions to do what MATLAB does at the m-file level ... modify only the field element you want and make everything else a reference copy. This is memory efficient and fast, but you have no way to do this with official API functions. For a first cut at this, I would advise using the mxDuplicateArray approach just to get things working. Don't worry about the unofficial efficient approach unless you really really need it.
3) I haven't looked at Jan's code so I don't know what it does or how it does it. So I have no advice on using it. But writing the basic functionality described above in a mex routine would only take some 20-30 lines of code (plus argument checking). Let me know if you want me to post it or if you need more help.
Jim Hokanson
Jim Hokanson il 30 Lug 2016
Modificato: Jim Hokanson il 30 Lug 2016
Usage code is at the top of the linked file.
There's one change I'm planning on making in terms of making two for loops and avoiding created a shared copy of the value I am about to override (when the field exists). I should also probably check the length of the input name against the max length.
My intention is to wrap all this in a class with some subsref work and a try/catch for when the name is valid vs invalid (i.e. try to do the assignment, on failing trying the mex).
I'd be curious as to your feedback.

Accedi per commentare.


Steven Lord
Steven Lord il 28 Lug 2016
Trying to fiddle around with invalid data is probably not going to be robust (or possible, if we've done our jobs well.)
If you're on Windows, why not try using a .NET OrderedDictionary from within MATLAB?
Q = System.Collections.Specialized.OrderedDictionary();
Q.Add('123 for all!', '2734')
Q.Item('does not exist') % returns []
Q.Item('123 for all!') % returns System.String('2734')
char(Q.Item('123 for all!')) % returns the char array '2734'
I imagine there's probably something similar you could do in Java if you need your code to run on a non-Windows platform.
  1 Commento
Jim Hokanson
Jim Hokanson il 30 Lug 2016
Thanks for the suggestions. The problem with Java (and .NET) is all the extra work that goes on to convert the memory format from these languages into Matlab native entities. Also, I'm using a lot of code that is expecting a structure, not a .NET or Java class. That means I would constantly need to add in additional checks into other peoples code, or just convert to a structure.
I think it has been well accepted for a while now that writing invalid fields to Matlab structures is possible using mex. I've seen a fair bit of code that relies on this functionality, rather than checking the field names. After all, as I reminded myself while writing code related to this question, Matlab supports retrieval of fields with invalid names, just not writing them. Thus someone that writes invalid names in mex doesn't need to worry about retrieving the data in Matlab.
Given the use of dynamic field referencing in Matlab for over a decade, I'd think it would make more sense to support any string as a field name. Instead what I've seen way too often is ugly name mangling code to create a valid name for a field. I think the code and usage of code associated with name changes is way more harmful and confusing then just telling people they need to use parentheses with invalid field names.
Perhaps I'm missing something?

Accedi per commentare.

Categorie

Scopri di più su Write C Functions Callable from MATLAB (MEX Files) in Help Center e File Exchange

Tag

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by