On 20 Mar 2015, at 19:39, Scott Christley < schristley@mac.com> wrote: Hello,
This is more a generic Objective-C question versus GNUstep but maybe some experts here have a suggestion.
I have a bunch of code that looks l like this:
if ([encode isEqual: [BioSwarmModel floatEncode]]) { // interpret as float matrix float (*grid)[height][width] = matrix; for (i = 0;i < height; ++i) for (j = 0;j < width; ++j) (*grid)[i][j] = 0.0;
} else if ([encode isEqual: [BioSwarmModel doubleEncode]]) { // interpret as double matrix double (*grid)[height][width] = matrix; for (i = 0;i < height; ++i) for (j = 0;j < width; ++j) (*grid)[i][j] = 0.0; }
where I have a generic pointer void *matrix to some data, that I need to interpret as a specific data type, generally either int, float or double. The part I don’t like is that the operation is essentially identical regardless of the data type, but I have to duplicate code in order to handle it. In this example, the code is just zero’ing out the data. This can be a pain for more complicated operations as I have to make sure I do the correct changes to each code piece. What I would like is just to write the code once and have the compiler or whatever handle the data type for me:
for (i = 0;i < height; ++i) for (j = 0;j < width; ++j) (*grid)[i][j] = 0.0;
So is there some new Objective-C feature that I’m unaware of which can do this for me?
This sounds like a job for Objective-C++. You'd write something like: template<typename T> void zero(T *grid, size_t width, size_t height) { for (i = 0;i < height; ++i) for (j = 0;j < width; ++j) (*grid)[i][j] = (T)0; } And then: if ([encode isEqual: [BioSwarmModel floatEncode]]) { zero((float*)matrix, width, height); } else if ([encode isEqual: [BioSwarmModel doubleEncode]]) { zero((double*)matrix, width, height); }
Very nice, that’s pretty close to what I was thinking. I will give that a try!
Although, in this specific case, you'd actually just want to do bzero(height*width*sizeof(T)). Use Objective-C for the introspection and C++ for the generic code. Oh, and it appears that you're reimplementing part of the core Objective-C language here. You might look at @encode(). For primitive types, all of the type encodings are single chars, so you can do a simple switch, like this:
switch(encoding) { case @encode(double)[0]: zero((double*)matrix, width, height); case @encode(float)[0]: zero((float*)matrix, width, height); }
That’s a nice trick! Not sure why @encode was encapsulated like that, probably there was the thought that more advanced types would be used but never materialized.
When doing this kind of thing a lot, I generally wrap it in a macro. Take a look at type_encoding_cases in libobjc2. You'd simplify this code to:
switch(encoding) { #define APPLY_TYPE(type, name, capitalizedName, encodingChar) \ case encodingChar: zero((type*)matrix, width, height); #include "type_encoding_cases.h" }
I’ll take a look, thanks!
Scott
|