C++, efficient way to call many possible functions from user - c++

I'm relatively new to c++, mostly worked with python.
I have a scenario where a user(me) uses a GUI to send commands to a microcontroller via serial, and then the microcontroller processes them.
Right now i have 10 commands, but as the project develops (some form of modular robot) I can envision having 50-100 possible commands.
Is there a better way for my c++ handleCommands function to select which one of the possible 100 functions to run without doing massive case switches or if else statements?
Extract of the code:
char cmd = 1; // example place holder
int value = 10; //example place holder
switch (cmd){
case '1':
toggleBlink(value);
break;
case '2':
getID(value); // in this case value gets ignored by the function as its not required
break;
This works fine for 3-4 functions but doesn't seem to me like the best way to do it for more functions.
I've heard of lookup tables but as each function is different and may require arguments or not I'm consumed on how to implement them.
Some background on the set-up:
The commands are mainly diagnostic ,< ID > ect and a couple of functional ones that require parameters like, <blink,10> <runto,90> <set-mode,locked>
The validation is done in python against a csv file and the actual serial message sent to the microcontroller is sent as <(index of comand in csvfile),parameter> with < > and , being delimiters.
So the user would type blink,10 and the python app will send <1,10> over serial as blink is found at index 1 of the csv file.
The microcontroller reads these in and i am left over with 2 char arrays, the command array containing a number, and the value array containing the value sent.(also a number)
As I'm running this on a microcontroller i don't really want to have to store a long file of possible commands in flash, hence the validation done on the python gui side.
Note that in the case of a possible multi argument function, say <move,90,30> i.e move 90 degrees in 30 seconds eat, the actual function would only receive one argument "30,90" and then split that up as needed.

If you have the commands comming over the serial line in the format
<command-mapped-to-a-number,...comma-separated-parameters...>
we can simulate that like so:
#include <iostream>
#include <sstream> // needed for simple parsing
#include <string>
#include <unordered_map> // needed for mapping of commands to functors
int main() {
std::cout << std::boolalpha;
// example commands lines read from serial:
for (auto& cmdline : {"<1,10>", "<2,10,90>", "<3,locked>", "<4>"}) {
std::cout << exec(cmdline) << '\n';
}
}
exec above is the interpreter that will return true if the command line was parsed and executed ok. In the examples above, command 1 takes one parameter, 2 takes two, 3 takes one (string) and 4 doesn't have a parameter.
The mapping from command-mapped-to-a-number could be an enum:
// uint8_t has room for 256 commands, make it uint16_t to get room for 65536 commands
enum class command_t : uint8_t {
blink = 1,
take_two = 2,
set_mode = 3,
no_param = 4,
};
and exec would make the most basic validation of the command line (checking < and >) and put it in a std::istringstream for easy extraction of the information on this command line:
bool exec(const std::string& cmdline) {
if(cmdline.size() < 2 || cmdline.front() != '<' || cmdline.back() != '>' )
return false;
// put all but `<` and `>` in an istringstream:
std::istringstream is(cmdline.substr(1,cmdline.size()-2));
// extract the command number
if (int cmd; is >> cmd) {
// look-up the command number in an `unordered_map` that is mapped to a functor
// that takes a reference to an `istringstream` as an argument:
if (auto cit = commands.find(command_t(cmd)); cit != commands.end()) {
// call the correct functor with the rest of the command line
// so that it can extract, validate and use the arguments:
return cit->second(is);
}
return false; // command look-up failed
}
return false; // command number extraction failed
}
The only tricky part left is the unordered_map of commands and functors.
Here's a start:
// a helper to eat commas from the command line
struct comma_eater {} comma;
std::istream& operator>>(std::istream& is, const comma_eater&) {
// next character must be a comma or else the istream's failbit is set
if(is.peek() == ',') is.ignore();
else is.setstate(std::ios::failbit);
return is;
}
std::unordered_map<command_t, bool (*)(std::istringstream&)> commands{
{command_t::blink,
[](std::istringstream& is) {
if (int i; is >> comma >> i && is.eof()) {
std::cout << "<blink," << i << "> ";
return true;
}
return false;
}},
{command_t::take_two,
[](std::istringstream& is) {
if (int a, b; is >> comma >> a >> comma >> b && is.eof()) {
std::cout << "<take-two," << a << ',' << b << "> ";
return true;
}
return false;
}},
{command_t::set_mode,
[](std::istringstream& is) {
if (std::string mode; is >> comma && std::getline(is, mode,',') && is.eof()) {
std::cout << "<set-mode," << mode << "> ";
return true;
}
return false;
}},
{command_t::no_param,
[](std::istringstream& is) {
if (is.eof()) {
std::cout << "<no-param> ";
return true;
}
return false;
}},
};
If you put that together you'll get the below output from the successful parsing (and execution) of all command lines received:
<blink,10> true
<take-two,10,90> true
<set-mode,locked> true
<no-param> true
Here's a live demo.

Given an integer index for each "command" a simple function pointer look-up table can be used. For example:
#include <cstdio>
namespace
{
// Command functions (dummy examples)
int examleCmdFunctionNoArgs() ;
int examleCmdFunction1Arg( int arg1 ) ;
int examleCmdFunction2Args( int arg1, int arg2 ) ;
int examleCmdFunction3Args( int arg1, int arg2, arg3 ) ;
int examleCmdFunction4Args( int arg1, int arg2, int arg3, int arg4 ) ;
const int MAX_ARGS = 4 ;
const int MAX_CMD_LEN = 32 ;
typedef int (*tCmdFn)( int, int, int, int ) ;
// Symbol table
#define CMD( f ) reinterpret_cast<tCmdFn>(f)
static const tCmdFn cmd_lookup[] =
{
0, // Invalid command
CMD( examleCmdFunctionNoArgs ),
CMD( examleCmdFunction1Arg ),
CMD( examleCmdFunction2Args ),
CMD( examleCmdFunction3Args ),
CMD( examleCmdFunction4Args )
} ;
}
namespace cmd
{
// For commands of the form: "<cmd_index[,arg1[,arg2[,arg3[,arg4]]]]>"
// i.e an angle bracketed comma-delimited sequence commprising a command
// index followed by zero or morearguments.
// e.g.: "<1,123,456,0>"
int execute( const char* command )
{
int ret = 0 ;
int argv[MAX_ARGS] = {0} ;
int cmd_index = 0 ;
int tokens = std::sscanf( "<%d,%d,%d,%d,%d>", command, &cmd_index, &argv[0], &argv[1], &argv[2], &argv[3] ) ;
if( tokens > 0 && cmd_index < sizeof(cmd_lookup) / sizeof(*cmd_lookup) )
{
if( cmd_index > 0 )
{
ret = cmd_lookup[cmd_index]( argv[0], argv[1], argv[2], argv[3] ) ;
}
}
return ret ;
}
}
The command execution passes four arguments (you can expand that as necessary) but for command functions taking fewer arguments they will simply be "dummy" arguments that will be ignored.
Your proposed translation to an index is somewhat error prone and maintenance heavy since it requires you to maintain both the PC application symbol table and the embedded look up table in sync. It may not be prohibitive to have the symbol table on the embedded target; for example:
#include <cstdio>
#include <cstring>
namespace
{
// Command functions (dummy examples)
int examleCmdFunctionNoArgs() ;
int examleCmdFunction1Arg( int arg1 ) ;
int examleCmdFunction2Args( int arg1, int arg2 ) ;
int examleCmdFunction3Args( int arg1, int arg2, arg3 ) ;
int examleCmdFunction4Args( int arg1, int arg2, int arg3, int arg4 ) ;
const int MAX_ARGS = 4 ;
const int MAX_CMD_LEN = 32 ;
typedef int (*tCmdFn)( int, int, int, int ) ;
// Symbol table
#define SYM( c, f ) {#c, reinterpret_cast<tCmdFn>(f)}
static const struct
{
const char* symbol ;
const tCmdFn command ;
} symbol_table[] =
{
SYM( cmd0, examleCmdFunctionNoArgs ),
SYM( cmd1, examleCmdFunction1Arg ),
SYM( cmd2, examleCmdFunction2Args ),
SYM( cmd3, examleCmdFunction3Args ),
SYM( cmd4, examleCmdFunction4Args )
} ;
}
namespace cmd
{
// For commands of the form: "cmd[ arg1[, arg2[, arg3[, arg4]]]]"
// i.e a command string followed by zero or more comma-delimited arguments
// e.g.: "cmd3 123, 456, 0"
int execute( const char* command_line )
{
int ret = 0 ;
int argv[MAX_ARGS] = {0} ;
char cmd[MAX_CMD_LEN + 1] ;
int tokens = std::sscanf( "%s %d,%d,%d,%d", command_line, cmd, &argv[0], &argv[1], &argv[2], &argv[3] ) ;
if( tokens > 0 )
{
bool cmd_found = false ;
for( int i = 0;
!cmd_found && i < sizeof(symbol_table) / sizeof(*symbol_table);
i++ )
{
cmd_found = std::strcmp( cmd, symbol_table[i].symbol ) == 0 ;
if( cmd_found )
{
ret = symbol_table[i].command( argv[0], argv[1], argv[2], argv[3] ) ;
}
}
}
return ret ;
}
}
For very large symbol tables you might want a more sophisticated look-up, but depending on the required performance and determinism, the simple exhaustive search will be sufficient - far faster than the time taken to send the serial data.
Whilst the resource requirement for the symbol table is somewhat higher that the indexed look-up, it is nonetheless ROM-able and will can be be located in Flash memory which on most MCUs is a less scarce resource than SRAM. Being static const the linker/compiler will most likely place the tables in ROM without any specific directive - though you should check the link map or the toolchain documentation n this.
In both cases I have defined the command functions and executer as returning an int. That is optional of course, but you might use that for returning responses to the PC issuing the serial command.

What you are talking about are remote procedure calls. So you need to have some mechanism to serialize and un-serialize the calls.
As mentioned in the comments you can make a map from cmd to the function implementing the command. Or simply an array. But the problem remains that different functions will want different arguments.
So my suggestion would be to add a wrapper function using vardiac templates.
Prefix every command with the length of data for the command so the receiver can read a block of data for the command and knows when to dispatch it to a function. The wrapper then takes the block of data, splits it into the right size for each argument and converts it and then calls the read function.
Now you can make a map or array of those wrapper function, each one bound to one command and the compiler will generate the un-serialize code for you from the types. (You still have to do it once for each type, the compiler only combines those for the full function call).

Related

Transferring string arrays from VBA7 to C++

I'm currently working on a project where I want to be able to manipulate and graph data with relative ease in Excel. However, a lot of the data involved exceeds Excels row limits considerably and it needs a degree of preprocessing before I can work with it.
To solve this I decided to write a backend in C++ to handle the preprocessing so that it's acceptable for Excel. The aim is to be able to pick several files within excel which are then sent to the .dll to be parsed, preprocessed, and have some averaging applied to make it more easily handled in excel. The data is then passed back to Excel to be graphed, etc.
I've already worked out how to send arrays of data from the .dll to Excel reliably. However, sending data from Excel to the .dll, usually an array of BSTR which hold file paths, has proven more difficult.
After reading through a few questions:
How to create an array of strings in VBA/Excel and send it to a C++ DLL so that it can be iterated through in the DLL
VBA/Excel, and C++ DLL, specifically problems with strings
Calling C++ function from Excel and VBA using DLL created in C++
I thought the following code should work:
// lib.cpp
/*
* clear_log() & write_log(...) both write to a specified log file
*/
inline std::string WINAPI
bstr_string_convert( const BSTR bstr ) {
const auto bstrlen = SysStringLen(bstr);
const auto buffer = new char[bstrlen + 1];
size_t n_char_converted{ 0 };
if ( bstrlen > 0 ) {
const auto err =
wcstombs_s( &n_char_converted,
buffer, bstrlen + 1,
bstr, bstrlen );
}
else {
buffer[0] = '\0';
}
return std::string{ buffer };
}
const std::string log_location{
"C:\\\\path\\to\\log\\location\\"
};
void WINAPI
clear_log( const std::string_view filename ) {
std::fstream log_file( log_location + filename,
std::ios_base::out | std::ios_base::trunc );
log_file.close();
}
void WINAPI
write_log( const std::string_view filename, const std::string_view str ) {
std::fstream log_file( log_location + filename,
std::ios_base::out | std::ios_base::app );
log_file << str << "\n";
log_file.close();
}
// This works
__declspec(dllexport) LPSAFEARRAY WINAPI
get_double_array( _In_ const LPSAFEARRAY* ppsa ) {
CComSafeArray<double> csa(*ppsa);
clear_log("double_log.txt");
write_log( "double_log.txt",
std::format("size: {}", csa.GetCount()) );
for ( LONG i{ csa.GetLowerBound() }; i < csa.GetUpperBound(); ++i ) {
write_log( "double_log.txt",
std::format("{}: {}", i, csa.GetAt(i)) );
}
return csa.Detach();
}
// This doesn't
__declspec(dllexport) LPSAFEARRAY WINAPI
get_str_array( _In_ const LPSAFEARRAY* ppsa ) {
CComSafeArray<BSTR> csa(*ppsa);
clear_log("string_log.txt");
write_log( "string_log.txt",
std::format("size: {}", csa.GetCount()));
for (LONG i{ csa.GetLowerBound() }; i < csa.GetUpperBound(); ++i ) {
write_log( "string_log.txt",
std::format( "{}: {}",
i,
bstr_string_convert(csa.GetAt(i))
) );
}
return csa.Detach();
}
Declare PtrSafe Function send_string_array _
Lib "path\to\dll" _
Alias "_get_str_array#4" _
(ByRef first_element() As String) As String()
Declare PtrSafe Function send_double_array _
Lib "path\to\dll" _
Alias "_get_double_array#4" _
(ByRef ptr() As Double) As Double()
(Not sure what's making the syntax highlighting weird here)
Sub test()
Dim doubles(3) As Double
doubles(0) = 3.141592
doubles(1) = 1235.12617
doubles(2) = -1266.2346
Dim d_result() As Double
d_result = send_double_array(doubles)
Dim n As Long
For n = 0 To 2
Debug.Print d_result(n)
Next n
Dim strings(3) As String
strings(0) = "This"
strings(1) = "is a "
strings(2) = "test."
Dim result() As String
result = send_string_array(strings)
For n = 0 To 2
Debug.Print result(n)
Next n
End Sub
Immediate Window:
3.141592
1235.12617
-1266.2346
??
??
??
double_log.txt:
size: 4
0: 3.141592
1: 1235.12617
2: -1266.2346
string_log.txt:
size: 4
0:
1:
2:
So my question is what am I missing that causes get_double_array(...) to work, but get_str_array(...) doesn't?
As an aside, why does CComSafeArray::GetCount() return 4 for an array declared with 3 elements? Seems like something weird is going on there.

Elegantly attempt to execute various functions a specific way

I'm attempting to execute various functions sequentially n number of times, only moving forward if previous function did not return false (error) otherwise I reset and start all over again.
An example of a sequence would be :
Turn module ON : module.power(true), 3 attempts
Wait for a signal : module.signal(), 10 attempts
Send a message : module.sendSMS('test'), 3 attempts
Turn module OFF : module.power(false), 1 attempt
Each of those actions are done the same way, only changing the DEBUG text and the function to launch :
DEBUG_PRINT("Powering ON"); // This line changes
uint8_t attempts = 0;
uint8_t max_attempts = 3; // max_attempts changes
while(!module.power(true) && attempts < max_attempts){ // This line changes
attempts++;
DEBUG_PRINT(".");
if(attempts == max_attempts) {
DEBUG_PRINTLN(" - Failed.");
soft_reset(); // Start all over again
}
delay(100);
}
DEBUG_PRINTLN(" - Success");
wdt_reset(); // Reset watchdog timer, ready for next action
Is there an elegant way I can put this process in a function I could call to execute the required functions this particular way, for example something like :
void try_this_action(description, function, n_attempts)
Which would make actions 1-4 above like :
try_this_action("Powering ON", module.power(true), 3);
try_this_action("Waiting for signal", module.signal(), 10);
try_this_action("Sending SMS", module.sendSMS('test'), 3);
try_this_action("Powering OFF", module.power(false), 1);
A difficulty I have is that the functions called have different syntax (some take parameters, some other don't...). Is there a more elegant modulable way of doing this besides copy/paste the chunck of code everywhere I need it ?
A difficulty I have is that the functions called have different syntax
(some take parameters, some other don't...).
That is indeed an issue. Along with it you have the possibility of variation in actual function arguments for the same function.
Is there a more elegant
modulable way of doing this besides copy/paste the chunck of code
everywhere I need it ?
I think you could make a variadic function that uses specific knowledge of the functions to dispatch in order to deal with the differing function signatures and actual arguments. I'm doubtful that I would consider the result more elegant, though.
I would be inclined to approach this job via a macro, instead:
// desc: a descriptive string, evaluated once
// action: an expression to (re)try until it evaluates to true in boolean context
// attempts: the maximum number of times the action will be evaluated, itself evaluated once
#define try_this_action(desc, action, attempts) do { \
int _attempts = (attempts); \
DEBUG_PRINT(desc); \
while(_attempts && !(action)) { \
_attempts -= 1; \
DEBUG_PRINT("."); \
delay(100); \
} \
if (_attempts) { \
DEBUG_PRINTLN(" - Success"); \
} else { \
DEBUG_PRINTLN(" - Failed."); \
soft_reset(); \
} \
wdt_reset(); \
} while (0)
Usage would be just as you described:
try_this_action("Powering ON", module.power(true), 3);
etc.. Although the effect is as if you did insert the code for each action in each spot, using a macro such as this would yield code that is much easier to read, and that is not lexically repetitive. Thus, for example, if you ever need to change the the steps for trying actions, you can do it once for all by modifying the macro.
You need to make the function pointers all have the same signature. I would use something like this;
typedef int(*try_func)(void *arg);
And have a try_this_action(...) signature similar to the following;
void try_this_action(char * msg, int max_trys, try_func func, void *arg)
You would then implement your actions similar to this;
int power(void *pv)
{
int *p = pv;
int on_off = *p;
static int try = 0;
if (on_off && try++)
return 1;
return 0;
}
int signal(void *pv)
{
static int try = 0;
if (try++ > 6)
return 1;
return 0;
}
And call them like this;
int main(int c, char *v[])
{
int on_off = 1;
try_this_action("Powering ON", 3, power, &on_off);
try_this_action("Signaling", 10, signal, 0);
}
Functions of different arity may be abstracted with a generic signature (think about main). Instead of each giving each their own unique arguments, you simply supply them all with:
An argument count.
A vector of pointers to the arguments.
This is how your operating system treats all programs it runs anyways. I've given a very basic example below which you can inspect.
#include <stdio.h>
#include <stdlib.h>
/* Define total function count */
#define MAX_FUNC 2
/* Generic function signature */
typedef void (*func)(int, void **, const char *);
/* Function pointer array (NULL - initialized) */
func functions[MAX_FUNC];
/* Example function #1 */
void printName (int argc, void **argv, const char *desc) {
fprintf(stdout, "Running: %s\n", desc);
if (argc != 1 || argv == NULL) {
fprintf(stderr, "Err in %s!\n", desc);
return;
}
const char *name = (const char *)(argv[0]);
fprintf(stdout, "Name: %s\n", name);
}
/* Example function #2 */
void printMax (int argc, void **argv, const char *desc) {
fprintf(stdout, "Running: %s\n", desc);
if (argc != 2 || argv == NULL) {
fprintf(stderr, "Err in %s!\n", desc);
return;
}
int *a = (int *)(argv[0]), *b = (int *)(argv[1]);
fprintf(stdout, "Max: %d\n", (*a > *b) ? *a : *b);
}
int main (void) {
functions[0] = printName; // Set function #0
functions[1] = printMax; // Set function #1
int f_arg_count[2] = {1, 2}; // Function 0 takes 1 argument, function 1 takes 2.
const char *descs[2] = {"printName", "printMax"};
const char *name = "Natasi"; // Args of function 0
int a = 2, b = 3; // Args of function 1
int *args[2] = {&a, &b}; // Args of function 1 in an array.
void **f_args[2] = {(void **)(&name),
(void **)(&args)}; // All function args.
// Invoke all functions.
for (int i = 0; i < MAX_FUNC; i++) {
func f = functions[i];
const char *desc = descs[i];
int n = f_arg_count[i];
void **args = f_args[i];
f(n, args, desc);
}
return EXIT_SUCCESS;
}
You can use a variadic function, declaring in the parameter list first those parameters that are always present, then the variable part.
In following code we define a type for action functions, void returning having as parameter an argument list:
typedef void (*action)(va_list);
Then define the generic action routine that prepare for the action execution:
void try_this_action(char *szActionName, int trials, action fn_action, ...)
{
va_list args;
va_start(args, fn_action); //Init the argument list
DEBUG_PRINT(szActionName); // This line changes
uint8_t attempts = 0;
uint8_t max_attempts = trials; // max_attempts changes
//Here we call our function through the pointer passed as argument
while (!fn_action(args) && attempts < max_attempts)
{ // This line changes
attempts++;
DEBUG_PRINT(".");
if (attempts == max_attempts)
{
DEBUG_PRINTLN(" - Failed.");
soft_reset(); // Start all over again
}
delay(100);
}
DEBUG_PRINTLN(" - Success");
wdt_reset(); // Reset watchdog timer, ready for next action
va_end(args);
}
Each function must be coded to use an argument list:
int power(va_list args)
{
//First recover all our arguments using the va_arg macro
bool cond = va_arg(args, bool);
if (cond == true)
{
... //do something
return true;
}
return false;
}
The usage will be:
try_this_action("Powering ON", 3, module.power, true);
try_this_action("Waiting for signal", 10, module.signal);
try_this_action("Sending SMS", 3, module.sendSMS, "test");
try_this_action("Powering OFF", 1, module.power, false);
If you need more info on variadic functions and usage of stdarg.h macros google the net. Start from here https://en.cppreference.com/w/c/variadic.
It could be coded also as a macro implementation, as the excellent proposal in the John Bollinger answer, but in that case you must consider that each macro usage will instantiate the whole code, that could be eventually even better for speed (avoiding a function call), but could be not suitable on systems with limited memory (embedded), or where you need reference to the function try_this_action (inexistent).

How to test a string that contains a random value?

My mock class looks like this:
struct StringEater {
MOCK_CONST_METHOD1( ExecuteCommand, void( const char* ) );
};
and the string consist of part that doesn't change, and small part that I can not set in test. Something like this :
Command 825 finished
but it can be
Command 123 finished
or "Command " + any number + " finished".
The method from the mock class is always called.
So, how do I set the test? This obviously can not be used:
StringEater mock;
EXPECT_CALL( mock, ExecuteCommand( StrEq( expectedJsonCmd ) ) ).Times( 1 );
What do I need to put for the matcher?
This works (thanks to J):
TEST( abc, some )
{
struct StringEater {
MOCK_CONST_METHOD1( ExecuteCommand, void( const char* ) );
};
StringEater eater;
EXPECT_CALL( eater, ExecuteCommand( MatchesRegex( "Command\\s([0-9]*)\\sfinished" ) ) ).Times( 1 );
eater.ExecuteCommand( "Command 643 finished" );
}
So it will always be the string "Command" followed by an integral number followed by the string "finished"?
Then it could be tested by attempting to extract these three parts from the string, comparing the first and third parts to the expected strings.
Something like
std::istringstream iss(the_input_string);
std::string s1, s3;
int i2;
if (iss >> s1 >> i2 >> s3)
{
if (s1 == "Command" && s3 == "finished")
{
// Test succeeded
}
else
{
// Test failed
}
}
else
{
// Failed, not correct format
}
You could try using regexp where you check whether the string begins with "Command" and ends with "finished" and extract the number as a group.
Similar problem was described in another post:
Regex C++: extract substring

C++ How to use less conditional statements?

For my assignment, I'm storing user login infos. I'm taking in a string which is the command. The command can be create, login, remove, etc. There are 10 total options, i.e 10 different strings possible. Can anyone explain a more efficient way to write this instead of 10 if and else if statements? Basically how should I format/structure things besides using a bunch of if (string == "one"), else if (string == "two"). Thank you
I expect that your lecturer would like you to extract function to another re-usable function:
string action;
command = CreateAction(action);
command.Do(...);
Ofcourse, inside you CreateAction class you still need to have the conditionals that determine which commands need to be created.
AbstractCommand CreateAction(action)
{
if (action == "login")
return LoginCommand();
else if (action == "remove")
return RemoveCommand();
..... etc etc
}
And if you really want to get rid of all the conditionals than you can create some self-registering commands but that involves a lot more code and classes......
You should look up things like Command Pattern and Factory Pattern
You can use function pointers and a lookup table.
typedef void (*Function_Pointer)(void);
void Create(void);
void Login(void);
void Remove(void);
struct Function_Option_Entry
{
const char * option_text;
Function_Pointer p_function;
};
Function_Option_Entry option_table[] =
{
{"one", Create},
{"two", Login},
{"three", Remove},
};
const unsigned int option_table_size =
sizeof(option_table) / sizeof(option_table[0]);
//...
std::string option_text;
//...
for (i = 0; i < option_table_size; ++i)
{
if (option_text == option_table[i].option_text)
{
option_table[i].p_function();
break;
}
}
Use a switch, and a simple hash-function.
You need to use a hash-function, because C and C++ only allow switching on integral values.
template<size_t N> constexpr char myhash(const char &x[N]) { return x[0] ^ (x[1]+63); }
char myhash(const string& x) { return x.size() ? x[0] ^ (x[1]+63) : 0; }
switch(myhash(s)) {
case myhash("one"):
if(s != "one") goto nomatch;
// do things
break;
case myhash("two"):
if(s != "two") goto nomatch;
// do things
break;
default:
nomatch:
// No match
}
Slight adjustments are needed if you are not using std::string.
I would recommend you to create a function for every specific string. For example, if you receive a string "create" you will call function doCreate(), if you receive a string "login" then you call function doLogin()
The only restriction on these function is that all of them must have the same signature. In an example above it was smh like this:
typedef void (*func_t) ();
The idea is to create a std::map from strings to these functions. So you wouldn't have to write 10 if's or so because you will be able to simple choose the right function from the map by the name of a specific string name. Let me explain it by the means of a small example:
typedef void (*func_t) ();
void doCreate()
{
std::cout << "Create function called!\n";
}
void doLogin()
{
std::cout << "Login function called!\n";
}
std::map<std::string, func_t> functionMap;
void initMap()
{
functionMap["create"] = doCreate;
functionMap["login"] = doLogin;
}
int main()
{
initMap();
std::string str = "login";
functionMap[str](); // will call doLogin()
str = "create";
functionMap[str](); // will call doCreate()
std::string userStr;
// let's now assume that we also can receive a string not from our set of functions
std::cin >> userStr;
if (functionMap.count(userStr))
{
functionMap[str](); // now we call doCreate() or doLogin()
}
else
{
std::cout << "Unknown command\n";
}
return 0;
}
I hope it will help you in someway=)
You can use a map which does the comparison for you.
Something like this:
Initialise map:
std::map<std::string, std::function<void(std::string&)>> map;
map["login"] = std::bind(&Class::DoLogin, this, std::placeholders::_1);
map["create"] = std::bind(&Class::DoCreate, this, std::placeholders::_1);
Receive message:
map.at(rx.msg_type)(rx.msg_data);
Handler:
void Class::DoLogin(const std::string& data)
{
// do login
}
Maybe you can create a std::map<std::string, int> and use map lookups to get the code of the command that was passed - you can later switch on that number. Or create an enum Command and have a std::map<std::string, Command> and use the switch.
Example:
enum Command
{
CREATE,
LOGIN,
...
};
std::map<std::string, Command> commandNameToCode;
// fill the map with appropriate values
commandNameToCode["create"] = Command::CREATE;
// somehow get command name from user and store in the below variable (not shown)
std::string input;
// check if the command is in the map and if so, act accordingly
if(commandNameToCode.find(input) != commandNameToCode.end())
{
switch(commandNameToCode[input])
{
case CREATE:
// handle create
break;
...
}
}

How to know written var type with Clang using C API instead of actual?

I'm trying to use Clang via C API, indexing to be detailed. The problem is that some types are returned not as they are written, but as they are for compiler. For example "Stream &" becomes "int &" and "byte" becomes "int.
Some test lib:
// TODO make it a subclass of a generic Serial/Stream base class
class FirmataClass
{
public:
FirmataClass(Stream &s);
void setFirmwareNameAndVersion(const char *name, byte major, byte minor);
I'm using the code to get method information:
void showMethodInfo(const CXIdxDeclInfo *info) {
int numArgs = clang_Cursor_getNumArguments(info->cursor);
fprintf(stderr, " %i args:\n", numArgs);
for (int i=0; i<numArgs; i++) {
CXCursor argCursor = clang_Cursor_getArgument(info->cursor, i);
CXString name = clang_getCursorDisplayName(argCursor);
CXString spelling = clang_getCursorSpelling(argCursor);
CXType type = clang_getCursorType(argCursor);
CXString typeSpelling = clang_getTypeSpelling(type);
CXCursorKind kind = clang_getCursorKind(argCursor);
fprintf(stderr, " kind=[%s (%i)], type=[%s], spelling=[%s]\n",
cursor_kinds[kind], kind, clang_getCString(typeSpelling),
clang_getCString(spelling));
clang_disposeString(name);
clang_disposeString(spelling);
clang_disposeString(typeSpelling);
}
// return type
CXType returnType = clang_getCursorResultType(info->cursor);
CXString returnTypeSpelling = clang_getTypeSpelling(returnType);
fprintf(stderr, " returns %s\n", clang_getCString(returnTypeSpelling));
clang_disposeString(returnTypeSpelling);
}
Output:
[105:10 4689] access=[CX_CXXPublic]
kind=[CXIdxEntity_CXXInstanceMethod] (21)
name=[setFirmwareNameAndVersion] is_container=[0] 3 args:
kind=[CXCursor_ParmDecl (10)], type=[const char *], spelling=[name]
kind=[CXCursor_ParmDecl (10)], type=[int], spelling=[major]
kind=[CXCursor_ParmDecl (10)], type=[int], spelling=[minor]
returns void
So you can see that byte function arguments are described as int.
How can i get actual spelling?
Is byte declared via a typedef, or a #define?
When I declare these types:
typedef int MyType_t;
#define MyType2_t int
class Foo
{
public:
bool bar( MyType_t a, MyType2_t b );
};
And then print the type names I get from clang_GetTypeSpelling this is what I get:
bool Foo_bar( MyType_t a, int b )
Libclang presumably can't print the #defined name because the preprocessor has already replaced it with int by the time the parse tree is built.
I've solved this a few days ago.
"Stream &" becomes "int &" and "byte" becomes "int.
libclang doesn't know what Stream or byte are until you insert the standard headers manualy using the flag -isystem <pathToStdHeaderDirectory>
I wrote a C# function that retrieves all the visual studio VC headers include directory:
private static string[] GetStdIncludes()
{
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\VisualStudio"))
{
if (key != null)
{
var lastVcVersions = key.GetSubKeyNames()
.Select(s =>
{
float result = 0;
if (float.TryParse(s, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result))
return result;
else return 0F;
}).Where(w => w > 0F)
.OrderByDescending(or => or)
.Select(s => s.ToString("n1", System.Globalization.CultureInfo.InvariantCulture))
.ToArray();
foreach (var v in lastVcVersions)
{
using (var vk = key.OpenSubKey(v))
{
var val = (string)vk.GetValue("Source Directories");
if (!string.IsNullOrEmpty(val))
return val.Split(";");
}
}
}
}
throw new Exception("Couldn't find VC runtime include directories");
}
hope that helps
I was having the same issue with my own classes.
You need to pass on the same flags you would use for compiling with clang to either clang_parseTranslationUnit or clang_createTranslationUnit, in particular the -I flags which are used to look up the header files where your class or type definitions are.
it seems that if libclang can't find a type declaration, it just defaults to all of then to int.
calling clang_createIndex ( 1, 1 ) should provide you with hints on what you are missing via stderr.
Here is some sample code that works for me now:
int main ( int argc, char* argv[] )
{
char *clang_args[] =
{
"-I.",
"-I./include",
"-I../include",
"-x",
"c++",
"-Xclang",
"-ast-dump",
"-fsyntax-only",
"-std=c++1y"
};
CXIndex Idx = clang_createIndex ( 1, 1 );
CXTranslationUnit TU = clang_parseTranslationUnit ( Idx, argv[1], clang_args, 9, NULL, 0, CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies );
clang_visitChildren ( clang_getTranslationUnitCursor ( TU ),
TranslationUnitVisitor, NULL );
clang_disposeTranslationUnit ( TU );
return 0;
}
I am trying to get the AST for a header file, hence the CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies flags and -ast-dump -fsyntax-only command line options, you may want to omit them if you dont need them and of course add and change the -I parameters according to your needs.