Is there a way to add new items to enum in Objective-C? [duplicate] - iphone

I wonder whether it is possible to add/append another item to an existing enum type (part of a framework)?
Something like this: We have the enum type
typedef enum {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal,
UIModalTransitionStyleCrossDissolve,
UIModalTransitionStylePartialCurl,
} UIModalTransitionStyle;
Now I want to append or add to this set an item like UIModalTransitionStyleCoverVerticalFlipped.
Can something like this be accomplished?

You can force new element to have the same type as the enum, but you can't extend it in a subclass.
header file:
extern const UIModalTransitionStyle UIModalTransitionStyleCoverVerticalFlipped;
implementation file:
const UIModalTransitionStyle UIModalTransitionStyleCoverVerticalFlipped = 10;
Make sure to give some space in case the framework is extended, so that you don't have conflicts. This is a bit of a hack, but it will get rid of compiler errors and warnings.

To do it, you have to modify the original type definition to include the new value:
typedef enum {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal,
UIModalTransitionStyleCrossDissolve,
UIModalTransitionStylePartialCurl,
UIModalTransitionStyleCoverVerticalFlipped
} UIModalTransitionStyle;
Otherwise, you can take a chance on its not working, and define it separately:
typedef enum {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal,
UIModalTransitionStyleCrossDissolve,
UIModalTransitionStylePartialCurl,
} UIModalTransitionStyle;
typedef enum {
UIModalTransitionStyleCoverVerticalFlipped =
UIModalTransitionStylePartialCurl + 1
} ExtendedUIModalTransitionStyle;
A variable that could hold the original enumeration will usually also work perfectly fine when/if you assign the new value as well (in a typical case, it'll just be an int) -- but it's not guaranteed. At least in theory, the implementation can/could assign few enough bits to hold that enumeration that it adding more values this way wouldn't work. It could also do range checking so assigning any out of range value wouldn't be allowed. Neither of these is at all common, so from a practical viewpoint it's probably not a problem -- but from a theoretical viewpoint, nothing really guarantees that code like this will work.

Maybe this can help you:
typedef NS_ENUM(NSInteger, BaseType) {
BaseTypeCase1,
BaseTypeCase2,
BaseTypeSize
};
typedef NS_ENUM(NSInteger, SubType) {
SubTypeCase1 = BaseTypeSize,
SubTypeCase2
};
Now you can switch on SubType knowing the values are unique.
If you don't have access to BaseType, you could set SubTypeCase1 to BaseType's last item + 1.
Downside is, you can't declare a method that takes a SubType and pass to it a BaseType without getting a compiler warning. So you need to declare your methods to take NSIntegers in order silence that warning.
Also, it feels weird when you need to declare a parameter of SubType and be able to pass in a BaseType.

To do this you have to update the Enum declaration to include UIModalTransitionStyleCoverVerticalFlipped this values as well
typedef enum {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal,
UIModalTransitionStyleCrossDissolve,
UIModalTransitionStylePartialCurl,
UIModalTransitionStyleCoverVerticalFlipped
} UIModalTransitionStyle;
so UIModalTransitionStyleCoverVerticalFlipped will be equivalent to integer constant 4
whereever you use any string constant from Enum dec. corresponding constant value get replaced so it is used to constraint the variable to hold only specified set of values only(i.e. 0 to 4) in above mentioned case

Related

Doxygen enum with explicit hard value

I have a C enum with around 50 values (they are error codes). Besides the first value, the numbering is kept automatic.
typedef enum {
MY_STATUS_OK = 0,
MY_STATUS_ERROR_UNKNOWN,
MY_STATUS_ERROR_A,
MY_STATUS_ERROR_B,
/* ... */
MY_STATUS_ERROR_LAST
} my_status_t;
I do get an enum description in the HTML, but it doesn't show the explicit value, only the enum values' name.
I want to document the association between hard value and enum value name. Right now when I get an error value, I need to manually count the index in the enum to find out what it means.

Any way to pass enum values by name as commandline args?

Is there any way to pass the value of an enum by name from the commandline? Rather what's the cleanest solution?
I tried the below,
typedef enum int unsigned { white, black, red } colour_e;
class house;
rand colour_e colour;
string n_colour = "white";
constraint c_colour {
colour.name() == n_colour;
}
endclass: house
program top;
house paradise;
initial begin
paradise = new();
void'($value$plusargs("colour=%0s", paradise.n_colour));
if (!paradise.randomize())
$display("not randomized");
else
$display("paradise.colour = %s",paradise.colour);
end
endprogram: top
I would want to pass something like this +colour=black. so that the paradise.colour is assigned black.
vcs cribbed for using enum.name() in the constraints.
below is the error.
Error-[NYI-CSTR-SYS-FTC] NYI constraint: sys function calls
T-enum_1.sv, 9 $unit, "this.colour.name" System function calls are
not yet implemented in constraints. Remove the function call or if
possible replace it with an integral state variable assigned in
pre_randomize().
while Riviera cried as below
ERROR VCP7734 "Type of 'this.colour.name()' is not allowed in a
constraint block. Only integral types are allowed in a constraint
block." "design.sv" 9 1 ERROR VCP7734 "Type of 'n_colour' is not
allowed in a constraint block. Only integral types are allowed in a
constraint block." "design.sv" 9 1 WARNING VCP7114 "STRING value
expected for format specifier %s as parameter
paradise.colour." "testbench.sv" 13 54
which brings the question to me, does everything in the contraint block has to be of integral type (just like we cannot declare a string as rand variable)?
ANyone wants to play around the code please have a look at the code at EDA playground here
Use uvm_enum_wrapper class to do the conversion from string to corresponding enum value. It is a template class wrapper defined in uvm_globals.svh (part of UVM 1.2) and you can use it as follows:
typedef enum {white, black, red} colour_e;
typedef uvm_enum_wrapper#(colour_e) colour_wrapper;
string colour_str;
void'($value$plusargs("colour=%0s", colour_str));
colour_wrapper::from_name(colour_str, paradize.n_colour);
The wrapper class uvm_enum_wrapper works by traversing the enum entries and creating an assoc array for a enum[string] map for the given enum type (supplied as template parameter). For more details take a look at the documentation.
There is another solution for the same. If you are not using UVM 1.2 version then there is like you can take string as an input argument and convert that string argument into int type. After that you can directly cast int to enum type by $cast.
Because there is no way to convert string to enum type (except UVM 1.2) so you have to add one extra step for the same.
module Test;
typedef enum {black,red,blue} color_e; //enum declaration
color_e color; //type of enum
string cmd_str; //Commandline string input
int cmd_int; //Input string is first converted into int
initial
begin
$value$plusargs("enum_c=%0s",cmd_str); //Take input argument as string it may be 0,1 or 2
cmd_int=cmd_str.atoi(); //Now convert that string argument into int type
$cast(color,cmd_int); //Casting int to enum type
$display("Value of color is --> %p",color); //Display value of enum
end
endmodule

How to dynamically determine and compare the type of an objects ivars, using ivar_getTypeEncoding & #encode?

Here is the compare operation I would like to do:
// foobar is the name of an ivar on some class
// i.e. NSDate *foobar;
const char *ivarType = [self getTypeForInstanceVariableWithName:#"foobar"];
const char *objType = #encode(NSDate);
if (strcmp(ivarType, objType) == 0) {
//set value
}
NSLog(#"comparing %s with %s", ivarType, objType);
Helper method:
- (const char*)getTypeForInstanceVariableWithName:(NSString *)name {
return ivar_getTypeEncoding(class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]));
}
NSLog result:
comparing #"NSDate" with {NSDate=#}
How come #encode returns a different type syntax than ivar_getTypeEncoding()? Is there a better way to accomplish this type determination? I must be missing something here...
Thanks!
When using ivar_getTypeEncoding() you have to pay attention to the first char. Let's see an example:
If you have a primitive type the first char will be all you get, for int it will be 'i', for char 'c', for unsigned long long 'Q', etc...
For objects and classes you might get more, like on your example, but the first character is what you want, like # for objects, # for classes, : for selectors.
You can read about those types here. You can also use constants when comparing, like _C_ID, _C_CLASS, etc. Have a loot at runtime.h.
C arrays seem to be more tricky, but I'm sure you can get around that.
One problem in your code is that you're getting the type encoding for the NSDate class, not for a NSDate object. So instead of comparing to #encode(NSDate) compare to #encode(NSDate *).
To see this type of code in action have a look at Adium's code for example.

Error "Expected specifier-qualifier-list before" at struct constructor

I am trying to write some code to optimize some Open GL functions for a program I'm writing, unfortunately, I am not exactly a C or C++ veteran, but that's partially why I'm doing this project!
So I'm creating a struct to handle 3x3 matrices and I am defining the struct as follows:
#ifndef MATRIX3BY3_H
#define MATRIX3BY3_H
struct Matrix3by3
{
float ix, jx, kx;
float iy, jy, ky;
float iz, jz, kz;
Matrix3by3() {}
Matrix3by3(const Matrix3by3 &matrix)
{
ix = matrix.ix;
jx = matrix.jx;
kx = matrix.kx;
iy = matrix.iy;
jy = matrix.jy;
ky = matrix.ky;
iz = matrix.iz;
jz = matrix.jz;
kz = matrix.kz;
}
Matrix3by3 (const float _ix, const float _jx, const float _kx,
const float _iy, const float _jy, const float _ky,
const float _iz, const float _jz, const float _kz) :
ix(_ix), jx(_jx), kx(_kx),
iy(_iy), jy(_jy), ky(_ky),
iy(_iz), jx(_jz), kz(_kz) {}
};
#endif
And I get the error (twice)
Expected specifier-qualifier-list
before 'Matrix3by3'
On the line of the first constructor. I have tried to look around for answers for this, and it seems that it has to do with the compiler not knowing that this is a type. So I have tried the following, I'll remove the innards for brevity:
typedef struct Matrix3by3 { ... };
struct Matrix3by3 { struct Matrix3by3() {} ... };
struct Matrix3by3 { ... } Matrix3by3;
typdef struct Matrix3by3;
struct Matrix3by3 { ... };
Which are all solutions that were suggested on blogs and articles that I saw for this error. I also saw that it may arise because of a circular dependency, but this file has no includes that include anything else, and I've even removed them just to be certain from time to time - no change.
I could write this in a objective-c class, I'm sure, but it will probably take a tiny bit more memory and cycles, and that's exactly what I'm trying to avoid. The only thing I can think of left is some compiler/project setting that I have set by default that precludes my using this type of structure. Entirely possible, as I'm learning the language/environment.
Can any one provide some help?
Thanks!
C does not support constructors or member functions of structs. There is no way you will get this to compile as C or Objective-C. You need to compile this as C++ or Objective-C++, at which point it will almost compile: you have an error in your 3rd constructor, in that you're attempting to initialize the members iy and jx multiple times. Once you fix those typos, it compiles just fine.
typedef struct { ... } Matrix3by3;
should work. It declares the anonymous struct as a type.
And use class instead of struct :)
What language/compiler are you translating your program with? I'd guess that you are trying to compile the code as C, while the language features you are trying to use are strictly C++-specific.
The error "Expected specifier-qualifier-list before 'Matrix3by3'" is a GCC-ism and it means that the token "Matrix3by3" is unknown. This is typically the case when you have a type that the compiler doesn't recognize, either because you mistyped it or because you forgot a header. In your case, it's because the type "Matrix3by3" really doesn't exist. You have two options:
Stop using Matrix3by3 directly and start using struct Matrix3by3 instead, as that's the actual type you defined.
Give your struct a typedef. It will look something like
typedef struct {
// fields here
} Matrix3by3

What's the difference between typedef const struct *CGPath and typedef struct *CGPath?

I've found this in the CGPath.h header file. I'm curious what this const thing does?
typedef struct CGPath *CGMutablePathRef;
typedef const struct CGPath *CGPathRef;
My guess: If I typedef something as const, it's constant so immutable and can't be changed in any way. Does that make sense?
Yes the const means you cannot change the path externally.
For CoreFoundation-based libraries though, the const is more a hack to allow mutable objects to use immutable methods without casting, and not vice-versa. That means
CGMutablePathRef mpath;
...
CGPathContainsPoint(mpath, ...);
compiles fine because a Foo* can be implicitly converted to a const Foo*, but
CGPathRef path;
...
CGPathAddRect(path, ...);
will throw an error because a const Foo* cannot be safely converted to a Foo*.
const T* means that the type is a pointer and that the pointee cannot be changed via that pointer. (That doesn't necessarily mean that the pointee can never change; it might be modified by a different, non-const reference to it, for example.)
"In any way" might be an overstatement, but you're correct. You'll notice that one is called CGPathRef and the other is CGMutablePathRef.
const is from standard C. It means that the dereferenced pointer cannot be assigned to. So I cannot do:
GCPathRef p = &my_path;
*p = new_path; // generates compiler error
But note that p itself can be changed:
p = &another_path; // this is OK.
It is not a hack at all as another poster has suggested. It has been part of C for generations.