While going through the code for parser, e.g. Parser.cpp inside clang/Parse directory of clang compiler
switch (Close) {
default: break;
case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
case tok::greatergreatergreater:
LHSName = "<<<"; DID = diag::err_expected_ggg; break;
}
I see that the default is at the beginning. Is there any reason for keeping it that way. Usually we keep the default at the end so I am a bit confused.
The order makes no differences, as long as you have included your breaks.
As an aside, I like to put the break immediately before every case or default. It's much easier to verify this rule has been followed than to try to look ahead to the end of each case statement.
switch (Close) {
break; default:
break; case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen;
break; case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace;
break; case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare;
break; case tok::greater: LHSName = "<"; DID = diag::err_expected_greater;
break; case tok::greatergreatergreater: LHSName = "<<<"; DID = diag::err_expected_ggg;
}
You might find this easier to understand if you interpret break to mean "Don't fall through into this case from any other case." instead of "Don't fall through from this case into any succeeding case."
In this layout, it is very easy to see if a break is missing, and therefore forcing the writer (and the reader) to ask him/herself "do I want a follow-through here?". All the breaks line up nicely, and it's very obvious if one is missing.
Clarification: There is no 'magic' in my answer. I'm just placing my whitespace in a manner that is much more readable to me. And whitespace doesn't matter, therefore I'm free to do this. A break at the very end of the switch is redundant. If missing, the compiler is not allowed to loop around to the top of the switch, as if it was some kind of while loop. Equally, a redundant break at the very start of a switch changes nothing, and must be accepted (and ignored) by the compiler.
The only time I see the position of a default matter is when doing something like this, which is a Duff's Device type construct and should probably never be attempted on modern platforms. :)
void copyAligned4Bytes(u32 *in, u32 *out, int numBytes)
{
assert((numBytes & 0x03) == 0);
while(numBytes)
{
switch(numBytes)
{
default: *out++ = *in++; numBytes -= 4;
case 12: *out++ = *in++; numBytes -= 4;
case 8: *out++ = *in++; numBytes -= 4;
case 4: *out++ = *in++; numBytes -= 4;
}
}
}
Ah, the joys of coding in C as closer to assembler as possible to get a certain type of jump table.
Related
I am writing a Python Library in C++ using the python C Api. There I have about 25 functions, that all accept two strings. Since Python might save strings in utf8/16/32 (the moment on char requires a bigger size the whole string will use the bigger size). When checking which kind the string is you get a enum value between 0 and 4. 0/4 should be handled as utf32, 1 as utf8 and 2 as utf16. So I currently have a nested switch for each combination:
The following example shows how the elements are handled in my code. random_func is different for each of my functions and is a template, that accepts a string_view of any type. This way to write the code results in about 100 lines of boilerplate for each function that accepts two strings.
Is there a way to handle all these cases without this immense code duplication and without sacrificing performance?
double result = 0;
Py_ssize_t len_s1 = PyUnicode_GET_LENGTH(py_s1);
void* s1 = PyUnicode_DATA(py_s1);
Py_ssize_t len_s2 = PyUnicode_GET_LENGTH(py_s2);
void* s2 = PyUnicode_DATA(py_s2);
int s1_kind = PyUnicode_KIND(py_s1);
int s2_kind = PyUnicode_KIND(py_s2);
switch (s1_kind) {
case PyUnicode_1BYTE_KIND:
switch (s2_kind) {
case PyUnicode_1BYTE_KIND:
result = random_func(
basic_string_view<char>(static_cast<char*>(s1), len_s1),
basic_string_view<char>(static_cast<char*>(s2), len_s2));
break;
case PyUnicode_2BYTE_KIND:
result = random_func(
basic_string_view<char>(static_cast<char*>(s1), len_s1),
basic_string_view<char16_t>(static_cast<char16_t*>(s2), len_s2));
break;
default:
result = random_func(
basic_string_view<char>(static_cast<char*>(s1), len_s1),
basic_string_view<char32_t>(static_cast<char32_t*>(s2), len_s2));
break;
}
break;
case PyUnicode_2BYTE_KIND:
switch (s2_kind) {
case PyUnicode_1BYTE_KIND:
result = random_func(
basic_string_view<char16_t>(static_cast<char16_t*>(s1), len_s1),
basic_string_view<char>(static_cast<char*>(s2), len_s2));
break;
case PyUnicode_2BYTE_KIND:
result = random_func(
basic_string_view<char16_t>(static_cast<char16_t*>(s1), len_s1),
basic_string_view<char16_t>(static_cast<char16_t*>(s2), len_s2));
break;
default:
result = random_func(
basic_string_view<char16_t>(static_cast<char16_t*>(s1), len_s1),
basic_string_view<char32_t>(static_cast<char32_t*>(s2), len_s2));
break;
}
break;
default:
switch (s2_kind) {
case PyUnicode_1BYTE_KIND:
result = random_func(
basic_string_view<char32_t>(static_cast<char32_t*>(s1), len_s1),
basic_string_view<char>(static_cast<char*>(s2), len_s2));
break;
case PyUnicode_2BYTE_KIND:
result = random_func(
basic_string_view<char32_t>(static_cast<char32_t*>(s1), len_s1),
basic_string_view<char16_t>(static_cast<char16_t*>(s2), len_s2));
break;
default:
result = random_func(
basic_string_view<char32_t>(static_cast<char32_t*>(s1), len_s1),
basic_string_view<char32_t>(static_cast<char32_t*>(s2), len_s2));
break;
}
break;
}
Put the complexity away in a function using variants
using python_string_view = std::variant<std::basic_string_view<char>,
std::basic_string_view<char16_t>,
std::basic_string_view<char32_t>;
python_string_view decode_python_string(python_string py_str)
{
Py_ssize_t len_s = PyUnicode_GET_LENGTH(py_str);
void* s = PyUnicode_DATA(py_str);
int s_kind = PyUnicode_KIND(py_str);
switch (s_kind) {
//return correct string_view here
}
}
int main()
{
python_string s1 = ..., s2 = ...;
auto v1 = decode_python_string(s1);
auto v2 = decode_python_string(s2);
std::visit([](auto&& val1, auto&& val2) {
random_func(val1, val2);
}, v1, v2);
}
I'm unsure about the performance though.
For what it is worth:
The difference it makes to have different char types is at the moment you extract the character values inside random_func (requiring nine template specializations, if I am right).
You would be close to a solution by fetching the chars in all cases using the largest type and masking out or shifting out the extra bytes where necessary. Instead of templating, you would pass a suitable mask and a stride information. Something like
for (char32_t* c= (char32_t*)s1; c &= mask, c != 0; c= (char32_t*)((char*)c + stride))
{
…
}
Unfortunately, not counting the extra masking operation, you hit a wall because you may have to fetch too many bytes at one end of the string, causing an illegal memory access.
I have this code:
#include <iostream>
using namespace std;
int main() {
int square; char state;
cout<<"Write a numbber"; cin>>square;
square *= square;
cout<<square;
switch(square) {
case 1: state = 'h';
case 3: state = 'm';
case 7: state = 'j';
case (square > 10): state = 'u'; // I try this, but not works
}
return 0;
}
I would like to know how a condition is made inside a switch, in c ++.
The expression following case must be a compile time constant. Hence, you may not use what you are trying.
Change that to default: and then use if.
default:
if (square > 10)
state = 'u';
If you have lots of items you should use a switch. If not, if else is better.
If a switch contains more than five items, it's implemented using a lookup table or a hash list. This means that all items get the same access time, compared to a list of if:s where the last item takes much more time to reach as it has to evaluate every previous condition first.
If you want to use condition or combine some:
switch(square) {
case 1: state = 'h'; break;
case 3: state = 'm';break;
case 7: state = 'j'; break;
case 8:
case 9: state = 'u';
case 10: state = 'z';break;
default: state = 'd';
}
Case 8, 9, 10 will be combined if the square is 8.
If you don't have a break at the end of a case region, control passes along to the next case label.
I am working on a rock paper scissors program, but this time the computer chooses rock half the time, scissors a third of the time, and paper only one sixth of the time. The way I did this was I enumerated six possible computer choice values:
enum choicec {rock1, rock2, rock3, scissors1, scissors2, paper};
choicec computer;
But then, after the computer makes its choice, I have to convert these enumerated values to either rock, paper, or scissors. I did this using a switch-case statement:
switch(computer) {
case rock1 || rock2 || rock3:
c = 1;
break;
case scissors1 || scissors2: //ERROR!
c = 3;
break;
case paper:
c = 2;
break;
}
one is rock, two is paper, and three is scissors. However, on the line where I have error written in as a comment, it gives me this error: [Error] duplicate case value.
I'm not sure why.
Any ideas?
I am not sure what you doing, but switch statement should look like this
switch(computer)
{
case rock1:
case rock2:
case rock3:
c = 1;
break;
case scissors1:
case scissors2:
c = 3;
break;
case paper:
c = 2;
break;
}
You can't use || in case branches. Sorry :(
When you use || it does a logical or on them, that says "is rock1 or rock2 or rock3 not a zero?". And the answer is yes, at least one of those is not zero. So rock1 || rock2 || rock3 is true, which is 1. And scissors1 || scissors is also true, which is 1. So you have two case branches for the 1 case.
You should simply use case fallthrough to select multiple conditions:
switch(computer) {
case rock1: case rock2: case rock3:
c = 1;
break;
case scissors1: case scissors2:
c = 3;
break;
case paper:
c = 2;
break;
default:
std::cerr << "INVALID COMPUTER MOVE";
}
Also, I always have a default in my case switches. Sometimes mistakes happen, and we definitely want to know if it doesn't hit any of the case branches. I'm also pretty paranoid about missing else statements, but about half the time it's ok if there's no else.
That switch statement does not do what you think.
Each case defines one value that the value of computer is matched against. Combining several values with logical disjunction to give the value associated with a single case label does not make the corresponding block be entered when the value of computer is equal to any of those values, but rather when it is equal to the result of their logical OR combination. Not very meaningful, indeed.
This is how you could rewrite your switch statement in order to make more sense:
switch(computer) {
case rock1: // Is it rock1?
case rock2: // Or perhaps rock2?
case rock3: // Or maybe rock3?
c = 1; // Well, if it's one of the above, do this...
break;
case scissors1: // OK, it wasn't. So is it scissors1?
case scissors2: // Or scissors2?
c = 3; // If it's one of the above, do this...
break;
case paper: // So is it paper?
c = 2;
break;
default: // Always better to be explicit about this
break;
}
Change it to:
switch(computer) {
case rock1:
case rock2:
case rock3:
c = 1;
break;
case scissors1:
case scissors2:
c = 3;
break;
case paper:
c = 2;
break;
}
rock1 || rock2 || rock3 and scissors1 || scissors2 are both expressions which evaluate to "true", hence the conflict.
The expression used in the switch statement must be integral type ( int, char and enum). In the Switch statement, all the matching case execute until a break statement is reached and Two case labels cannot have the same value.
But in the above case with logical or condition.
At first
case: rock1 || rock2 || rock3:
This will evaluate to 1 and second case scissors1 || scissors2: will also evaluate to 1. This is cause error as said Two case labels cannot have the same value.
This is the reason compiler complains and giving an error:
Compiler Error: duplicate case value
To solve this convert to
switch(computer) {
case rock1:
case rock2:
case rock3:
c = 1;
break;
case scissors1:
case scissors2: //Now will not give any error here...
c = 3;
break;
case paper:
c = 2;
break;
}
I came across a case-switch piece of code today and was a bit surprised to see how it worked. The code was:
switch (blah)
{
case a:
break;
case b:
break;
case c:
case d:
case e:
{
/* code here */
}
break;
default :
return;
}
To my surprise in the scenario where the variable was c, the path went inside the "code here" segment. I agree there is no break at the end of the c part of the case switch, but I would have imagined it to go through default instead. When you land at a case blah: line, doesn't it check if your current value matches the particular case and only then let you in the specific segment? Otherwise what's the point of having a case?
This is called case fall-through, and is a desirable behavior. It allows you to share code between cases.
An example of how to use case fall-through behavior:
switch(blah)
{
case a:
function1();
case b:
function2();
case c:
function3();
break;
default:
break;
}
If you enter the switch when blah == a, then you will execute function1(), function2(), and function3().
If you don't want to have this behavior, you can opt out of it by including break statements.
switch(blah)
{
case a:
function1();
break;
case b:
function2();
break;
case c:
function3();
break;
default:
break;
}
The way a switch statement works is that it will (more or less) execute a goto to jump to your case label, and keep running from that point. When the execution hits a break, it leaves the switch block.
That is the correct behavior, and it is referred to as "falling through". This lets you have multiple cases handled by the same code. In advanced situations, you may want to perform some code in one case, then fall through to another case.
Contrived example:
switch(command)
{
case CMD_SAVEAS:
{
this->PromptForFilename();
} // DO NOT BREAK, we still want to save
case CMD_SAVE:
{
this->Save();
} break;
case CMD_CLOSE:
{
this->Close();
} break;
default:
break;
}
This is called a fall-through.
It is exactly doing what you are seeing: several cases is going to execute same piece of code.
It is also convenient in doing extra processing for certain case, and some shared logic:
// psuedo code:
void stopServer() {
switch (serverStatus)
case STARTING:
{
extraCleanUpForStartingServer();
// fall-thru
}
case STARTED:
{
deallocateResources();
serverStatus = STOPPED;
break;
}
case STOPPING:
case STOPPED:
default:
// ignored
break;
}
This is a typical use of fall-through in switch-case. In case of STARTING and STARTED, we need to do deallocateResources and change the status to STOPPED, but STARTING need some extra cleanup. By the above way, you can clearly present the 'common logic' plus extra logic in STARTING.
STOPPED, STOPPING and default are similar, all of them fall thru to default logic (which is ignoring).
It is not always a good way to code like this but if it is well used it can present the logic better.
Luckily for us, C++ doesn't depend on your imagination :-)
Think of the switch labels as "goto" labels, and the switch(blah) simply "goes to" the corresponding label, and then the code just flows from there.
Actually the switch statement works the way you observed. It is designed so that you can combine several cases together until a break is encountered and it acts something like a sieve.
Here is a real-world example from one of my projects:
struct keystore_entry *new_keystore(p_rsd_t rsd, enum keystore_entry_type type, const void *value, size_t size) {
struct keystore_entry *e;
e = rsd_malloc(rsd, sizeof(struct keystore_entry));
if ( !e )
return NULL;
e->type = type;
switch (e->type) {
case KE_DOUBLE:
memcpy(&e->dblval, value, sizeof(double));
break;
case KE_INTEGER:
memcpy(&e->intval, value, sizeof(int));
break;
/* NOTICE HERE */
case KE_STRING:
if ( size == 0 ) {
/* calculate the size if it's zero */
size = strlen((const char *)value);
}
case KE_VOIDPTR:
e->ptr = rsd_malloc(rsd, size);
e->size = size;
memcpy(e->ptr, value, size);
break;
/* TO HERE */
default:
return NULL;
}
return e;
}
The code for KE_STRING and KE_VOIDPTR cases is identical except for the calculation of size in case of string.
I'm writing a game and I'm wound up in needing a console for simple text input; filenames and simple values.
Using SDL, my console looks the following at it's simplest:
class Console
{
public:
typedef std::list<String> InputList;
enum Result
{
NOTHING = 0,
ENTERED,
ESCAPED
};
static const String& GetInput() { return input; }
static Result Query(SDLKey lastKey)
{
if(lastResult == ENTERED || lastResult == ESCAPED)
{
input.clear();
}
switch (lastKey)
{
case SDLK_a:
case SDLK_b:
case SDLK_c:
case SDLK_d:
case SDLK_e:
case SDLK_f:
case SDLK_g:
case SDLK_h:
case SDLK_i:
case SDLK_j:
case SDLK_k:
case SDLK_l:
case SDLK_m:
case SDLK_n:
case SDLK_o:
case SDLK_p:
case SDLK_q:
case SDLK_r:
case SDLK_s:
case SDLK_t:
case SDLK_u:
case SDLK_v:
case SDLK_w:
case SDLK_x:
case SDLK_y:
case SDLK_z:
case SDLK_0:
case SDLK_1:
case SDLK_2:
case SDLK_3:
case SDLK_4:
case SDLK_5:
case SDLK_6:
case SDLK_7:
case SDLK_8:
case SDLK_9:
case SDLK_SLASH:
case SDLK_BACKSLASH:
case SDLK_PERIOD:
case SDLK_COMMA:
case SDLK_SPACE:
case SDLK_UNDERSCORE:
case SDLK_MINUS:
input += static_cast<char> (lastKey);
lastResult = NOTHING;
break;
case SDLK_RETURN:
lastResult = ENTERED;
break;
case SDLK_ESCAPE:
lastResult = ESCAPED;
break;
}
return lastResult;
}
protected:
static Result lastResult;
static String input;
};
This would be called from the application's main event loop, if the console is active and the last event was a keypress, then the result of the input is processed at a state where it's necessary.
Of course, it looks incredibly awkward... What's a better way to implement a simple console that can be easily rendered in my game's window? (Not going anywhere near to highly unportable solutions like having to reroute std::cout or writing code to bring up a UNIX console etc.)
One suggestion I would offer is to use if statements instead of a switch in this case:
if(lastKey == SDLK_RETURN)
lastResult = ENTERED;
else if(lastKey == SDLK_ESCAPE)
lastResult = ESCAPED;
else if(lastKey >= SDLK_SPACE && lastKey <= SDLK_z)
{
input += static_cast<char> (lastKey);
lastResult = NOTHING;
}
I took some liberties and included some characters that you didn't have in your code above, such as the ampersand, quotes, parentheses, brackets, etc. If you don't want those keys, you can add a few more if statements to break it down a bit more.
This assumes that the enum for the keys doesn't change a lot. If it does change a lot you may be better off with what you had.