fast string parser C++ - c++

I have an idea to make super fast command parser.
I have more than 100 pairs of command - function, and some commands have same prefixes.
Down below there is example of my idea. I can make a program that will generate C++ code like in this example, but i think this can be realized with templates.
I'm not strong in templates. May be some one can help with it?
static const string_view s1{"hello"};
void f1() { cout << "f1" << endl; }
static const string_view s2{"helly"};
void f2() { cout << "f2" << endl; }
static const string_view s3{"hi jo"};
void f3() { cout << "f3" << endl; }
static const string_view s4{"hoyMo"};
void f4() { cout << "f4" << endl; }
void sw(string_view& hw){
switch(hw.size()){
case 5: {
switch(hw[0]){
case 'h': {
switch(hw[1]){
case 'e': {
switch(hw[2]){
case 'l': {
switch(hw[3]){
case 'l': {
switch(hw[4]){
case 'o': {
f1();
break;
}
case 'y': {
f2();
break;
}
default: cout << "command not found" << endl; break;
}
break;
}
default: cout << "command not found" << endl; break;
}
break;
}
default: cout << "command not found" << endl; break;
}
break;
}
case 'i': {
if(hw.substr(2) == s3.substr(2)){
f3();
}
break;
}
case 'o': {
if(hw.substr(2) == s4.substr(2)){
f4();
}
break;
}
default: cout << "command not found" << endl; break;
}
break;
}
default: cout << "command not found" << endl; break;
}
break;
}
case 6: {
//...
break;
}
default: cout << "command not found" << endl; break;
}
}
int main(){
string_view myCommand("hi jo");
sw(myCommand);
string_view myCommand2("hoyMo");
sw(myCommand2);
string_view myCommand3("ha ha");
sw(myCommand3);
}

You should probably be using a parser library, such as Boost.Spirit. This wil allow you to write simple code, like
string("hello")
| string("helly")
| string("hi jo")
| string("hoyMo")
and do all the heavy lifting for you to generate a parser that will probably be faster than something you would write yourself.

Related

Query about a given function's use in the code

i'm following this tutorial and they give us this code to test the function isLowerVowel:
#include <iostream>
bool isLowerVowel(char c, bool yIsVowel)
{
switch (c)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
case 'y':
return (yIsVowel ? true : false);
default:
return false;
}
}
int main()
{
std::cout << std::boolalpha;
std::cout << isLowerVowel('a',false) << "\n";
std::cout << isLowerVowel('a',true) << "\n";
std::cout << isLowerVowel('q',false) << "\n";
std::cout << isLowerVowel('q',true) << "\n";
std::cout << isLowerVowel('y',false) << "\n";
std::cout << isLowerVowel('y',true) << "\n";
return 0;
}
I dont understand what the use of yIsVowel is for, shouldnt just testing isLowerVowel be enough? Sorry i asked them but got no replies
I dont understand what the use of yIsVowel is for, shouldnt just testing isLowerVowel be enough?
If you were to use the isLowerVowel fuction to implement the isLowerVowel function you would have recursion. It is unclear how this recursion should be terminated.
yIsVowel appears to be used to set whether y is a vowel or not.

compiler give me an error by transfer an array to a function

I learn c++ by myself and read the tutorial on this link: https://www.learncpp.com
In my Exercise I have to program an array from array library and fill it with cards.
After i filled it I have to show all cards with std::cout.
But when I transfer my array to the function printCard in my main.cpp , I get an error that i can not solve.
In the following you can see my whole program.
Thank you for your help
Deck.h
#include<array>
enum CardRank {
RANK_2,
RANK_3,
RANK_4,
RANK_5,
RANK_6,
RANK_7,
RANK_8,
RANK_9,
RANK_10,
RANK_JACK,
RANK_QUEEN,
RANK_KING,
RANK_ACE,
MAX_RANK
};
enum CardSuit {
SUIT_HEART,
SUIT_CLUBS,
SUIT_SPARE,
SUIT_DIAMONDS,
MAX_SUIT
};
struct Card {
CardRank rank;
CardSuit suit;
};
void printCard(Card card);
std::array<Card, 52> createDeck();
void printDeck(std::array<Card, 52>* deck);
Deck.cpp
#include "Deck.h"
void printCard(Card& card) {
switch (card.rank) {
case CardRank::RANK_2:
std::cout << "2";
break;
case CardRank::RANK_3:
std::cout << "3";
break;
case CardRank::RANK_4:
std::cout << "4";
break;
case CardRank::RANK_5:
std::cout << "5";
break;
case CardRank::RANK_6:
std::cout << "6";
break;
case CardRank::RANK_7:
std::cout << "7";
break;
case CardRank::RANK_8:
std::cout << "8";
break;
case CardRank::RANK_9:
std::cout << "9";
break;
case CardRank::RANK_10:
std::cout << "10";
break;
case CardRank::RANK_JACK:
std::cout << "J";
break;
case CardRank::RANK_QUEEN:
std::cout << "Q";
break;
case CardRank::RANK_KING:
std::cout << "K";
break;
case CardRank::RANK_ACE:
std::cout << "A";
break;
default:
std::cout << "?";
break;
}
switch (card.suit) {
case CardSuit::SUIT_HEART:
std::cout << "H ";
break;
case CardSuit::SUIT_SPARE:
std::cout << "S ";
break;
case CardSuit::SUIT_CLUBS:
std::cout << "C ";
break;
case CardSuit::SUIT_DIAMONDS:
std::cout << "D ";
break;
default:
std::cout << "?";
break;
}
}
std::array<Card, 52>createDeck() {
std::array<Card, 52> deck;
std::size_t card{ 0 };//muss alle karten durchlaufen
//Scheleifen die die karten werte geben
for (std::size_t suit{ 0 }; suit < CardSuit::MAX_SUIT; suit++) {
for (std::size_t rank{ 0 }; rank < CardRank::MAX_RANK; rank++) {
//Wegen sizeType muss hier gecastet werden
//sonst Fehler: 2 unterschiedliche typen
deck[card].rank = static_cast<CardRank>(rank);
deck[card].suit = static_cast<CardSuit>(suit);
card++;
}
}
return deck;
}
void printDeck(const std::array<Card, 52>& deck) {
for (std::size_t card{ 0 }; card < 52; card++) {
printCard(deck[card]);
}
}
Main.cpp
#include<iostream>
#include "Deck.h"
#include <array>
int main() {
std::array<Card, 52> deck{ createDeck() };
printDeck(deck);
return 0;
}

GetOpt not working on Mac, none of the arguments show up

int c = 0;
while (c = getopt(argc, argv, "p:t:e:") != -1) {
std::cout<<"c: "<<c<<std::endl;
switch (c) {
case 'p':
if (optarg) {
std::cout << "lol" << std::endl;
person = atoi(optarg);
}
break;
case 't':
if (optarg) {
time = stod(optarg);
std::cout << "ll" << std::endl;
}
break;
case 'e':
if (optarg) {
ecg = atoi(optarg);
std::cout << "2dasf" << std::endl;
}
break;
}
}
Been trying to make getopt work on my Mac. C is printed as 1, but None of the print statements within the switch are printed. This works perfectly in Linux. What is wrong with my Mac?

Switch case for Rapidjson::Type

JSON that I'm trying to parse looks something like this is:
{
"testBool": true,
"testString": "eu"
}
And my current parser looks really ugly and it really feels like there is a more elegant way to solve this problem. I tried looking into rapidjson::Type for a switch case using document.GetObject().GetType() but it doesn't provide the same type precision that you can achieve by using Get%TypeName%() functions. hashmap is nothing but a wrapper around std::unordered_map<std::string, std::any>.
rapidjson::Document document;
document.Parse(tmp_string.c_str());
for (auto& member : document.GetObject())
{
if (member.value.IsBool())
{
hashmap->addEntry<bool>(member.name.GetString(), member.value.GetBool());
}
else if (member.value.IsString())
{
hashmap->addEntry<std::string>(member.name.GetString(), member.value.GetString());
}
else if (member.value.IsInt())
{
hashmap->addEntry<int>(member.name.GetString(), member.value.GetInt());
}
.....
//And so on
.....
}
my current parser looks really ugly
Beauty is in the eye of the be(er)holder...here's my code:
static void
printField(const Value& e, const string& fld, bool print_newline = true) {
const Value &v = fld.empty() ? e : e[fld];
if (print_newline)
cout << endl << "\t";
if (not fld.empty())
cout << fld << ": ";
if ( /* custom stuff required? */ ) {
// Do custom stuff
else {
switch (v.GetType()) {
case kNullType:
cout << "Null";
break;
case kFalseType:
case kTrueType:
cout << v.GetBool();
break;
case kObjectType: {
bool first = true;
cout << "{ ";
for (const auto &subfield: v.GetObject()) {
if (first)
first = false;
else
cout << ", ";
printField(v, subfield.name.GetString(), false);
}
cout << " }";
break;
}
case kArrayType: {
bool first = true;
cout << "[ ";
for (const auto &arrEntry: v.GetArray()) {
if (first)
first = false;
else
cout << ", ";
printField(arrEntry, "", false);
}
cout << " ]";
break;
}
case kStringType:
cout << v.GetString();
break;
case kNumberType:
if (v.IsInt64())
cout << v.GetInt64();
else if (v.IsUint64())
cout << v.GetUint64();
else
cout << v.GetDouble();
break;
default:
stringstream msg;
msg << "Unexpected RapidJSON Value type: " << v.GetType();
throw logic_error(msg.str());
}
}
}
This uses the stringize stuff to solve some problems, but, if you don't like that, you can get the same effect manually. It subdivides the IsNumber case using a cascading if; if you need more resolution, you can add the other cases to that.

atof coredump with getopt

I'm writing a C++ application which converts fahrenheit to celsius and kelvin, and kelvin to celsius and fahrenheit, etc. Since it's stupid to write an interative application here, I decided to familiarize myself with the getopt function in unistd.h.
Format:
F2C -k 273.15
Output:
FAHR CELSIUS KELVIN
32 0 273.15
Here is my code:
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#define VERSION 0.1
#define HELP help(argv[0])
#define OPTS "vk:f:c:h"
float ver = (float)VERSION;
void help(char *s);
namespace Fahrenheit
{
float FK(float F) {
return ((5.0/9.0) * (F - 32.0) + 273.15);
}
float FC(float F) {
return ((5.0/9.0) * (F - 32.0));
}
void printfahr(float F) {
std::cout << "FAHR\t\tCELSIUS\t\tKELVIN" << std::endl;
std::cout << F << "\t\t" << FC(F) << "\t\t" << FK(F) << std::endl;
}
}
namespace Celsius
{
float CF(float C) {
return ((C*(9/5)) + 32);
}
float CK(float C) {
return (C+273.15);
}
void printc(float C) {
std::cout << "FAHR\t\tCELSIUS\t\tKELVIN" << std::endl;
std::cout << CF(C) << "\t\t" << C << "\t\t" << CK(C) << std::endl;
}
}
namespace Kelvin
{
float KF(float K) {
return (((9.0/5.0) * (K-273.15)) + 32);
}
float KC(float K) {
return (K-273.15);
}
void printk(float K) {
std::cout << "FAHR\t\tCELSIUS\t\tKELVIN" << std::endl;
std::cout << KF(K) << "\t\t" << KC(K) << "\t\t" << K << std::endl;
}
}
int main(int argc, char *argv[])
{
char arg = '\0';
if(argc < 2 && argc == 1 && argc > 0) {
help(argv[0]);
exit(1);
}
/*** Use function getopt() defined in unistd.h to accept 5 arguments: -v, -h, -k, -f, and -c ***/
while((arg=getopt(argc, argv, OPTS))!=-1)
{
float floatarg = atof(optarg);
switch(arg)
{
case 'v':
std::cout << "The current version is:" << ver << std::endl;
break;
case 'h':
HELP;
break;
case 'k':
Kelvin::printk(floatarg);
break;
case 'f':
Fahrenheit::printfahr(floatarg);
break;
case 'c':
Celsius::printc(floatarg);
break;
default:
HELP;
break;
}
}
return 0;
}
void help(char *s) {
std::cout << "Usage:\t"<< s << " [-option] [argument]" << std::endl;
std::cout << "option:\t" << "-c [temperature]: convert a Celsius temperature to Fahrenheit and Kelvin" << std::endl;
std::cout << "\t" << "-f [temperature]: convert a Fahrenheit temperature to Celsius and Kelvin" << std::endl;
std::cout << "\t" << "-h: show help information" << std::endl;
std::cout << "\t" << "-k [temperature]: convert a Kelvin temperature to Fahrenheit and Celsius" << std::endl;
std::cout << "\t" << "-v: show version information" << std::endl;
}
My problem is that whenever I use an option that accepts no arguments (like -v) I get a core dump.
dbx has shown me that the SIGSEV occurs at line 70 (float floatarg = atof(optarg);).
When I run the program like this:
./F2C -k 273.15
The math is done correctly and I get a clear printout. It's only when I use -v or -h that my program SIGSEV's.
Extra information:
This program was compiled with the Sun studio compiler suite, version 5.12.
I'm completely baffled as to why my program SIGSEV's. It is inconsistent and makes no sense.
I would appreciate any help available.
Should have done some optarg checking. After all, you can't convert null to a float.
new main():
#define FLOATARG atof(optarg)
int main(int argc, char *argv[])
{
char arg = '\0';
if(argc < 2 && argc == 1 && argc > 0) {
help(argv[0]);
exit(1);
}
/*** Use function getopt() defined in unistd.h to accept 5 arguments: -v, -h, -k, -f, and -c ***/
while((arg=getopt(argc, argv, OPTS))!=-1)
{
switch(arg)
{
case 'v':
std::cout << "The current version is: << ver << std::endl;
break;
case 'h':
HELP;
break;
case 'k':
Kelvin::printk(FLOATARG);
break;
case 'f':
Fahrenheit::printfahr(FLOATARG);
break;
case 'c':
Celsius::printc(FLOATARG);
break;
default:
HELP;
break;
}
}
return 0;
}
The shortest fix is:
float floatarg = optarg ? atof(optarg) : 0.0;
You can also rewrite your code like
float floatarg = 0.0;
switch(arg)
{
case 'v':
std::cout << "The current version is:" << ver << std::endl;
break;
case 'h':
HELP;
break;
case 'k':
floatarg = atof(optarg);
Kelvin::printk(floatarg);
break;
case 'f':
floatarg = atof(optarg);
Fahrenheit::printfahr(floatarg);
break;
...
or
float floatarg = 0.0;
if(optarg) {
floatarg = atof(optarg);
}
switch(arg)
{
case 'v':
std::cout << "The current version is:" << ver << std::endl;
break;
case 'h':
HELP;
break;
case 'k':
Kelvin::printk(floatarg);
break;
case 'f':
Fahrenheit::printfahr(floatarg);
break;
...