Coming from an extremely spoiled family upbringing (turbo pascal, python, ruby) I'm a bit puzzled when it comes to doing all the household chores myself.
Yesterday was one of these days where I just did not find myself a solution. I had to check whether a value matches one of some other values.
x = some_function_return_value();
if x in (1,4,17,29,35):
That's how I used to write it. Now with Objective-C I obviously can't do that. And I searched the old google, but found no answer, and the old manual, and nothing there, so how do you do this in Objective-C, without doing something cranky like the following?
if (x == 1 || x == 4 || x == 17 || x == ...) {
Edited: in this case it is an (int), I know for NSArray and NSString there are methods for this
If it's about integer values, you can use switch:
switch (x) {
case 1:
case 4:
case 17:
case 29:
case 35:
do_something();
break;
}
Do not forget that in C/C++/Objective-C, the cases fall through to the next by default. You need to add break; statements to prevent that.
For non-integer values, you have to do long if statements with a lot of repetition as C doesn't provide syntactic sugar or features that many scripting languages have to abbreviate this.
Another way would be for example to prepare an array and then do:
if ([myArray containsObject:[NSNumber numberWithInteger:x]])
or even better, use an NSSet for that. This will work for most objects, for example it will also work with strings.
There is a fast enumeration syntax in objective C that uses "in" to loop over collections, however given it requires converting your int values to NSNumbers, it's probably easier to use C here
BOOL success = NO;
int size = 5
NSInteger numbers[size] = {1,4,17,29,35};
for (int i = 0; i < size; i++) {
if (yourValue == numbers[i]) {
success = YES;
break;
}
}
if (success) {
/* do your stuff */
}
admittedly not as nice as python...
Here's my silly program of the day:
bool int_exists_in_array(const int n, const int a[], const size_t elementCount) {
return (0 != elementCount) &&
(n == a[0] || int_exists_in_array(n, a + 1, elementCount - 1U));
}
so this:
if x in (1,4,17,29,35):
becomes:
const int a[] = { 1, 4, 17, 29, 35 };
if (int_exists_in_array(x, a, sizeof(a)/sizeof(a[0]))) {
...
}
You can use NSSet in addition with NSValue.
Related
I'm trying to use a variable as the case match, however I get "Expression is not an integer in Objective-C.
Is it possible to use variable in switches in this manner?
int count = [array count];
switch ([number to check]) {
case 0:
//first statement
break;
case 1 ... (count -1):
//somewhere between 1 and the next to last statement
//Basically the middle
break;
case count:
//Last statement
default:
break;
}
Objective-C (and C) switch only supports a single primitive constant value for each case statement (or a range as pointed out in the answer by TwoStraws). You would be much better off writing your code using if/else:
if ([number to check] == 0) {
} else if ([number to check] >= 1 && [number to check] < count) {
} else if ([number to check] == count) {
} else {
}
Objective-C's switch statement does support ranges of values as you've seen, but doesn't support variable matches I'm afraid.
So, the below code is valid because I've used exact integers:
int numberOfKittens = 12;
NSString *kittenDescription;
switch (numberOfKittens) {
case 0 ... 5:
kittenDescription = #"Need more kittens";
break;
case 6 ... 10:
kittenDescription = #"That's a good number of kittens.";
break;
case 11 ... 20:
kittenDescription = #"Are you sure you can handle that many kittens?";
break;
default:
kittenDescription = #"You must really love kittens!";
}
…but trying to put a variable in place of any of those will fail.
If this is something you desperately want, consider using Swift because it has a much more expressive switch matching system. Here's that same code in Swift, now with a variable being used to match a case:
let upperLimit = 20
let numberOfKittens = 19
var kittenDescription = ""
switch (numberOfKittens) {
case 0 ... 5:
kittenDescription = "Need more kittens"
case 6 ... 10:
kittenDescription = "That's a good number of kittens."
case 11 ... upperLimit:
kittenDescription = "Are you sure you can handle that many kittens?"
default:
kittenDescription = "You must really love kittens!"
}
I'd like a step by step explanation on how to parse the arguments of a variadic function
so that when calling va_arg(ap, TYPE); I pass the correct data TYPE of the argument being passed.
Currently I'm trying to code printf.
I am only looking for an explanation preferably with simple examples but not the solution to printf since I want to solve it myself.
Here are three examples which look like what I am looking for:
https://stackoverflow.com/a/1689228/3206885
https://stackoverflow.com/a/5551632/3206885
https://stackoverflow.com/a/1722238/3206885
I know the basics of what typedef, struct, enum and union do but can't figure out some practical application cases like the examples in the links.
What do they really mean? I can't wrap my brain around how they work.
How can I pass the data type from a union to va_arg like in the links examples? How does it match?
with a modifier like %d, %i ... or the data type of a parameter?
Here's what I've got so far:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "my.h"
typedef struct s_flist
{
char c;
(*f)();
} t_flist;
int my_printf(char *format, ...)
{
va_list ap;
int i;
int j;
int result;
int arg_count;
char *cur_arg = format;
char *types;
t_flist flist[] =
{
{ 's', &my_putstr },
{ 'i', &my_put_nbr },
{ 'd', &my_put_nbr }
};
i = 0;
result = 0;
types = (char*)malloc( sizeof(*format) * (my_strlen(format) / 2 + 1) );
fparser(types, format);
arg_count = my_strlen(types);
while (format[i])
{
if (format[i] == '%' && format[i + 1])
{
i++;
if (format[i] == '%')
result += my_putchar(format[i]);
else
{
j = 0;
va_start(ap, format);
while (flist[j].c)
{
if (format[i] == flist[j].c)
result += flist[i].f(va_arg(ap, flist[i].DATA_TYPE??));
j++;
}
}
}
result += my_putchar(format[i]);
i++;
}
va_end(ap);
return (result);
}
char *fparser(char *types, char *str)
{
int i;
int j;
i = 0;
j = 0;
while (str[i])
{
if (str[i] == '%' && str[i + 1] &&
str[i + 1] != '%' && str[i + 1] != ' ')
{
i++;
types[j] = str[i];
j++;
}
i++;
}
types[j] = '\0';
return (types);
}
You can't get actual type information from va_list. You can get what you're looking for from format. What it seems you're not expecting is: none of the arguments know what the actual types are, but format represents the caller's idea of what the types should be. (Perhaps a further hint: what would the actual printf do if a caller gave it format specifiers that didn't match the varargs passed in? Would it notice?)
Your code would have to parse the format string for "%" format specifiers, and use those specifiers to branch into reading the va_list with specific hardcoded types. For example, (pseudocode) if (fspec was "%s") { char* str = va_arg(ap, char*); print out str; }. Not giving more detail because you explicitly said you didn't want a complete solution.
You will never have a type as a piece of runtime data that you can pass to va_arg as a value. The second argument to va_arg must be a literal, hardcoded specification referring to a known type at compile time. (Note that va_arg is a macro that gets expanded at compile time, not a function that gets executed at runtime - you couldn't have a function taking a type as an argument.)
A couple of your links suggest keeping track of types via an enum, but this is only for the benefit of your own code being able to branch based on that information; it is still not something that can be passed to va_arg. You have to have separate pieces of code saying literally va_arg(ap, int) and va_arg(ap, char*) so there's no way to avoid a switch or a chain of ifs.
The solution you want to make, using the unions and structs, would start from something like this:
typedef union {
int i;
char *s;
} PRINTABLE_THING;
int print_integer(PRINTABLE_THING pt) {
// format and print pt.i
}
int print_string(PRINTABLE_THING pt) {
// format and print pt.s
}
The two specialized functions would work fine on their own by taking explicit int or char* params; the reason we make the union is to enable the functions to formally take the same type of parameter, so that they have the same signature, so that we can define a single type that means pointer to that kind of function:
typedef int (*print_printable_thing)(PRINTABLE_THING);
Now your code can have an array of function pointers of type print_printable_thing, or an array of structs that have print_printable_thing as one of the structs' fields:
typedef struct {
char format_char;
print_printable_thing printing_function;
} FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING;
FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING formatters[] = {
{ 'd', print_integer },
{ 's', print_string }
};
int formatter_count = sizeof(formatters) / sizeof(FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING);
(Yes, the names are all intentionally super verbose. You'd probably want shorter ones in the real program, or even anonymous types where appropriate.)
Now you can use that array to select the correct formatter at runtime:
for (int i = 0; i < formatter_count; i++)
if (current_format_char == formatters[i].format_char)
result += formatters[i].printing_function(current_printable_thing);
But the process of getting the correct thing into current_printable_thing is still going to involve branching to get to a va_arg(ap, ...) with the correct hardcoded type. Once you've written it, you may find yourself deciding that you didn't actually need the union nor the array of structs.
I have a list of variables that are named based on two digits then a word i.e. val11 or val26
I need to perform a check on whether a certain value for a variable is equal to the next variable i.e. that val32 == val33
I have the names of the first variables that I need to check in an NSArray (i.e val33)
I can then write a function to perform the check as a lot of long winded if statements
-(void)checkValues:(NSArray *)valueArray {
for (int x = 0; x < [valueArray count]; x++) {
tempStr = [offFiles objectAtIndex:x];
//split variable name
NSString *value = [tempStr substringWithRange:NSMakeRange(3,2];
int numValue= [value intValue];
//long winded if statement
if (numValue == 11) {
if(val11 == val12) {
//do something
}
}
if (numValue == 12) {
if(val12 == val13) {
//do something
}
}
.... etc
if (numValue == 87) {
if(val87 == val88) {
//do something
}
}
}
}
Is there any way I can remove the long winded if statement and replace it with a reference to the next variable so that no matter what variable name is in the array I can easily just check it against the next variable
Something like the excel command indirect
=INDIRECT(CONCATENATE("Cell!A",numValue + 1))
Unless there is some need for you to store your data in a set of discrete separate variables, this is clearly a situation were an array would work for you. This could be either a c-style array or one using NSArray - its up to you.
Using a c-style array (assuming 10 completely made up values):
int myValues[10] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }
Then your series of if statements can be reduced to one:
if (myValues[numValue] == myValues[numValue+1]) {
// so something
}
So if numValue is 3, it would compare myValues[3] and myValues[4] - essentially the same as comparing val3 and val4 in your scheme. Please note that arrays are zero based - the first value is accessed myValue[0] - so if your numbering scheme is 1-based then you need to subtract 1, e.g.:
if (myValues[numValue-1] == myValues[numValue]) {
// do something
}
Beside from the syntax bugs (like starting variable names with a number), what you are looking for is the switch() statement:
switch(a)
{
case 1: // if a is 1 do the following
printf("a is 1");
break;
case 2: // if a is 2
printf("a is 2");
break;
....
default: // if a was none of the cases before do this
printf("a sucks!!");
}
Notice that you always need a break; statement at the end of each case x:
Wondering if there is a way to shorthand these conditionals. I am working with data packets and the conditionals get a bit unwieldy at times. Here's a basic example:
I write:
if (message->messageType != kMessageTypeCutCardsArray && message->messageType != kMessageTypeQuit) {
MessageInt message;
message.message.messageType = kMessageTypeReceivedData;
NSData *packet = [NSData dataWithBytes:&message length:sizeof(message)];
[_game sendData:packet];
}
I would rather write:
if (message->messageType != (kMessageTypeCutCardsArray || kMessageTypeQuit)) {
MessageInt message;
message.message.messageType = kMessageTypeReceivedData;
NSData *packet = [NSData dataWithBytes:&message length:sizeof(message)];
[_game sendData:packet];
}
As a general matter, no. That's just the way that C (and hence Objective-C) works.
In this specific case, you could use a switch statement:
switch (message->messageType)
{
case kMessageTypeCutCardsArray:
case kMessageTypeQuit:
break;
default:
MessageInt message;
message.message.messageType = kMessageTypeReceivedData;
NSData *packet = [NSData dataWithBytes:&message length:sizeof(message)];
[_game sendData:packet];
break;
}
Whether that syntax is an improvement is up to you.
If you define your enum such that the values have mutually-exclusive bit patterns, like so:
typedef enum : NSUInteger {
kMessageTypeLoveLetter = 1 << 0,
kMessageTypeBirthdayCard = 1 << 1,
kMessageTypeVacationPostcard = 1 << 2,
kMessageTypeCreditApplication = 1 << 3,
kMessageTypeCharitySolicitation = 1 << 4
} MessageType;
You can then test for multiple values at once, using binary OR | and binary AND &:
MessageType msgType = kMessageTypeCreditApplication;
if( !(msgType & (kMessageTypeLoveLetter | kMessageTypeBirthdayCard)) ){
// Nobody loves you.
}
if( (msgType & (kMessageTypeCreditApplication | kMessageTypeCharitySolicitation) ){
// Someone wants your money.
}
This won't work, however, if you use the compiler-generated consecutive values for the enum, because the values will overlap as flags -- e.g., both 2 and 3 have the lowest bit set -- and ORing them together will often end up testing only one of the flags.
You could box the values and use a temporary array. This achieves the goal of removing the duplication in the conditional, but is unlikely to be as optimizable for the compiler.
if (message->messageType != kMessageTypeCutCardsArray &&
message->messageType != kMessageTypeQuit) {
should be equivalent to:
if(![#[#(kMessageTypeCutCardsArray),#(kMessageTypeQuit)]
contains:#(message->messageType)]) {
I am trying to increase the performance of the update(); function below. The numbers inside the mathNumber variable will come from an NSString created from a text field. Even though I'm using five numbers I would like it to be able to run any amount that the user inserts into a text field. What are some ways I could speed up the code in update(); with C and/or Objective-C? I also would like it to work on the Mac and iPhone.
typedef struct {
float *left;
float *right;
float *equals;
int operation;
} MathVariable;
#define MULTIPLY 1
#define DIVIDE 2
#define ADD 3
#define SUBTRACT 4
MathVariable *mathVariable;
float *mathPointer;
float newNumber;
void init();
void update();
float solution(float *left, float *right, int *operation);
void init()
{
float *mathNumber = (float *) malloc(sizeof(float) * 9);
mathNumber[0] =-1.0;
mathNumber[1] =-2.0;
mathNumber[2] = 3.0;
mathNumber[3] = 4.0;
mathNumber[4] = 5.0;
mathNumber[5] = 0.0;
mathNumber[6] = 0.0;
mathNumber[7] = 0.0;
mathNumber[8] = 0.0;
mathVariable = (MathVariable *) malloc(sizeof(MathVariable) * 4);
mathVariable[0].equals = &mathPointer[5];
mathVariable[0].left = &mathPointer[2];
mathVariable[0].operation = MULTIPLY;
mathVariable[0].right = &mathPointer[3];
mathVariable[1].equals = &mathPointer[6];
mathVariable[1].left = &mathPointer[1];
mathVariable[1].operation = SUBTRACT;
mathVariable[1].right = &mathPointer[5];
mathVariable[2].equals = &mathPointer[7];
mathVariable[2].left = &mathPointer[0];
mathVariable[2].operation = ADD;
mathVariable[2].right = &mathPointer[6];
mathVariable[3].equals = &mathPointer[8];
mathVariable[3].left = &mathPointer[7];
mathVariable[3].operation = MULTIPLY;
mathVariable[3].right = &mathPointer[4];
return self;
}
// This is updated with a timer
void update()
{
int i;
for (i = 0; i < 4; i++)
{
*mathVariable[i].equals = solution(mathVariable[i].left, mathVariable[i].right, &mathVariable[i].operation);
}
// Below is the equivalent of: newNumber = (-1.0 + (-2.0 - 3.0 * 4.0)) * 5.0;
// newNumber should equal -75
newNumber = mathPointer[8];
}
float solution(float *left, float *right, int *operation)
{
if ((*operation) == MULTIPLY)
{
return (*left) * (*right);
}
else if ((*operation) == DIVIDE)
{
return (*left) / (*right);
}
else if ((*operation) == ADD)
{
return (*left) + (*right);
}
else if ((*operation) == SUBTRACT)
{
return (*left) - (*right);
}
else
{
return 0.0;
}
}
EDIT:
I first must say thank you for all of your kind posts. This is the first forum I've gotten people that don't tell me I'm a complete idiot. Sorry about the return self; I didn't realize this was an objective-C forum too (thus why I hastily used C). I have my own parser which is slow but I'm not concerned with its speed. All I want is to speed up the update() function since it slows everything down and 90% of the objects use it. Also, I'm try to get it to work faster with iOS devices since I can't compile anything in the text boxes. If you have any other advice on making update() faster I thank you.
Thanks again,
Jonathan
EDIT 2:
Well I got it to run faster by changing it from:
int i;
for (i = 0; i < 4; i++)
{
*mathVariable[i].equals = solution(*mathVariable[i].left, *mathVariable[i].right, mathVariable[i].operation);
}
To:
*mathVariable[0].equals = solution(*mathVariable[0].left, *mathVariable[0].right, mathVariable[0].operation);
*mathVariable[1].equals = solution(*mathVariable[1].left, *mathVariable[1].right, mathVariable[1].operation);
*mathVariable[2].equals = solution(*mathVariable[2].left, *mathVariable[2].right, mathVariable[2].operation);
*mathVariable[3].equals = solution(*mathVariable[3].left, *mathVariable[3].right, mathVariable[3].operation);
Is there any other way to increment it as fast as the preloaded numbers in the array like above?
Your code is a mix of styles, and contains some unwarranted uses of pointers (e.g. when passing operation to solution). It is unclear why you are passing the floats by reference, but maybe you intend that these change be changed and the expression reevaluated?
Below are some changes both to tidy and incidentally speed it up - the cost of any of this is not high and you may be guilt of premature optimization. As #Dave commented there are libraries to do parsing for you, but if you're targeting simple math expressions an operator precedence stack-based parser/evaluator is easy enough to code.
Suggestion 1: use enum - cleaner:
typedef enum { MULTIPLY, DIVIDE, ADD, SUBTRACT } BinaryOp;
typedef struct
{
float *left;
float *right;
float *equals;
BinaryOp operation;
} MathVariable;
Suggestion 2: use switch - cleaner and probably faster as well:
float solution(float left, float right, int operation)
{
switch(operation)
{
case MULTIPLY:
return left * right;
case DIVIDE:
return left / right;
case ADD:
return left + right;
case SUBTRACT:
return left - right;
default:
return 0.0;
}
}
Note I also removed passing pointers, the call is now:
*mathVariable[i].equals = solution(*mathVariable[i].left,
*mathVariable[i].right,
mathVariable[i].operation);
Now an OO person will probably object (:-)) to the switch (or the if/else) and argue each node (your MathVariable) should be an instance which knows how to perform its own operation. A C person might suggest you use function pointers in the node so they can perform their own operation. All this is design and you'll have to figure that out yourself.