Archived

This topic is now archived and is closed to further replies.

kodbert

Resolving a string to a function call in C++

Recommended Posts

kodbert    122
I''m having trouble coming up with an efficient way of taking a string, for example "setgravity 2" and converting it to a call for the function "setgravity" with an argument of the value 2. Ive been thinking about using the STL "map" or a hash-table, but i feel they don''t offer the speed i am after. Any ideas ? Thanks !

Share this post


Link to post
Share on other sites
billybob    134
std::map of strings to function pointers? if std::map isn''t fast enough, there probably isn''t anything fast enough to map strings to anything. how many of these functions are you after? anything less than 50 should be plenty fast. especially because it sounds like you are after a console type thing, which isn''t going to be calling functions like that much.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by billybob
std::map of strings to function pointers? if std::map isn''t fast enough, there probably isn''t anything fast enough to map strings to anything. how many of these functions are you after? anything less than 50 should be plenty fast. especially because it sounds like you are after a console type thing, which isn''t going to be calling functions like that much.


This is exactly what I do!


  
#include "CPluginBase.h"
#include <map>
#include <vector>
#include <string>

using namespace std;

class CKeywordParser
{
CKeywordParser();
public:
BOOL IsKeyword(string Keyword);
BOOL ProcessLine(string Line);
CKeywordParser* GetObject();
void AddKeyWord(string KeyWord, CPluginBase* Plugin);
BOOL ProcessKeyWord(string KeyWord, string params);

virtual ~CKeywordParser();

map<string,CPluginBase*> KeyWordTable;

};

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////


CKeywordParser::CKeywordParser()
{

}

CKeywordParser::~CKeywordParser()
{
KeyWordTable.clear();
}

BOOL CKeywordParser::ProcessKeyWord(string KeyWord, string params)
{
//Singleton Logger

CLogger* Logger = NULL;
Logger = Logger->GetObject();

map<string,CPluginBase*>::iterator itr;

itr = KeyWordTable.find(KeyWord);

if( itr == KeyWordTable.end())
{
Logger->Warning("(CKeyWordParser): KeyWord Not Found");
return FALSE;
}

Logger->Report((itr->second)->ProcessKeyWord(KeyWord, params));

return TRUE;
}

void CKeywordParser::AddKeyWord(string KeyWord, CPluginBase *Plugin)
{
char LowerCase[256];
strcpy(LowerCase,KeyWord.c_str());
strlwr(LowerCase);
KeyWordTable.insert(pair<string,CPluginBase*>(LowerCase,Plugin));
}

CKeywordParser* CKeywordParser::GetObject()
{
static CKeywordParser obj;
return &obj;
}

BOOL CKeywordParser::ProcessLine(string Line)
{
char TokenString[256] = {0};
char KeyWord[64] = {0};
char* token = NULL;
char seps[] = " ()=,;:\"[]<>/\\|\r\t\n";
string parameters;

strcpy(TokenString,Line.c_str());

token = strtok(TokenString,seps);

strcpy(KeyWord,token);
token = strtok(NULL,seps);

while(token != NULL)
{
parameters += token;
parameters += " ";
}

return ProcessKeyWord(KeyWord,parameters);
}

//Determines if we struck a keyword

BOOL CKeywordParser::IsKeyword(string Keyword)
{
//Singleton Logger

CLogger* Logger = NULL;
Logger = Logger->GetObject();

map<string,CPluginBase*>::iterator itr;

itr = KeyWordTable.find(Keyword);

if( itr == KeyWordTable.end())
{
return FALSE;
}

return TRUE;
}


However, this code uses polymorphism (the base class) to pass the keyword and the parameters to the appropiate class. If you were using a C style architecture, you would replace all of the instances of CPluginBase* with this:

  
//Define teh type needed to store in the map

#typedef string (*ParseFunction)(string)

//map would look like:

map<string,ParseFunction>KeyWordTable;

//Process

BOOL CKeywordParser::ProcessKeyWord(string KeyWord, string params)
{
map<string,ParseFunction>::iterator itr;

itr = KeyWordTable.find(KeyWord);

if( itr == KeyWordTable.end())
{
Logger->Warning("(CKeyWordParser): KeyWord Not Found");
return FALSE;
}
else{ itr->second(params);}

}

void CKeywordParser::AddKeyWord(string KeyWord, ParseFunction Plugin)
{
char LowerCase[256];
strcpy(LowerCase,KeyWord.c_str());
strlwr(LowerCase);
KeyWordTable.insert(pair<string,ParseFunction>(LowerCase,Plugin));
}

//Usage:

//Define the function globally to change gravity

void SetGravity(string parameter)
{
//whatever

}
//Singleton Parser

CKeywordparser* parser = NULL;
parser = parser->GetObject();
//add keyword

paser->AddKeyWord("setgravity", SetGravity);


That above assumes you use a C style coding and each keyword has it''s own specific GLOBAL processing function.

Share this post


Link to post
Share on other sites
billybob    134
one thing that might help AP, is to do typedef std::map[string, CPluginBase*] PluginTable. that way you don't have to do std::map[...,...] everywhere you want an iterator or something like that. just PluginTable::iterator.

edit: if you do it at class scope, it won't affect anything else either

edit again: and replace [ and ] with < and >

[edited by - billybob on March 16, 2003 9:34:52 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by billybob
one thing that might help AP, is to do typedef std::map[string, CPluginBase*] PluginTable. that way you don''t have to do std::map[...,...] everywhere you want an iterator or something like that. just PluginTable::iterator.



Thanks for the tip! Those code snippets were actually from a test application I wrote before I integrated it into the actual code base.

I have certain conventions I''m required to adhere to, but that''s a great tip. I''ll see if I can run it by the lead.

Share this post


Link to post
Share on other sites