I am writing an mathematical expression parser, and therefore I need fast way to edit any string in any imaginable way.
My current solution: (compilable code)
#include <iostream>
#include <string>
#include <algorithm>
#include <list>
#include <vector>
using namespace std;
class is_whitespace {
public:
inline bool operator() (const char & c)
{
return ( ' ' == c) || ('\n' == c) ||
('\r' == c) || ('\t' == c) ||
('\b' == c) || ('\v' == c) ||
('\f' == c);
}
};
inline void erase_whitespaces(string & expr) {
expr.erase(remove_if(expr.begin(), expr.end(), is_whitespace()), expr.end());
}
class FindDelim {
private:
string & out_delim;
public:
inline FindDelim(string & out) : out_delim(out) {}
public:
inline bool operator()(char & c, string & delim) {
if (string(&c, delim.size()) == delim) {
out_delim = delim;
return true;
}
return false;
}
};
inline void split_string(
vector<string> & output_str,
vector<string> & output_del,
const string::iterator & str_beg,
const string::iterator & str_end,
const vector<string>::iterator & del_beg,
const vector<string>::iterator & del_end)
{
string delim;
size_t delim_len;
string::iterator last = str_beg;
string::iterator next = str_beg;
while ((next = find_first_of(last, str_end, del_beg, del_end, FindDelim(delim))) != str_end) {
delim_len = delim.size();
output_str.push_back(string(&(*last), distance(last, next)));
output_del.push_back(string(&(*next), delim_len));
last = next + delim_len;
}
output_str.push_back(string(&(*last)));
}
inline void split_string(
vector<string> & output_str,
vector<string> & output_del,
const string::iterator & beg,
const string::iterator & end,
vector<string> & delims)
{
return split_string(output_str, output_del, beg, end, delims.begin(), delims.end());
}
inline void split_string(
vector<string> & output_str,
vector<string> & output_del,
const string::iterator & beg,
const string::iterator & end,
vector<string> && delims)
{
return split_string(output_str, output_del, beg, end, delims.begin(), delims.end());
}
inline void split_string(
vector<string> & output_str,
vector<string> & output_del,
string & expr,
vector<string> & delims)
{
return split_string(output_str, output_del, expr.begin(), expr.end(), delims.begin(), delims.end());
}
inline void split_string(
vector<string> & output_str,
vector<string> & output_del,
string & expr,
vector<string> && delims)
{
return split_string(output_str, output_del, expr.begin(), expr.end(), delims.begin(), delims.end());
}
inline void split_string(
vector<string> & output_str,
vector<string> & output_del,
string && expr,
vector<string> & delims)
{
return split_string(output_str, output_del, expr.begin(), expr.end(), delims.begin(), delims.end());
}
inline void split_string(
vector<string> & output_str,
vector<string> & output_del,
string && expr,
vector<string> && delims)
{
return split_string(output_str, output_del, expr.begin(), expr.end(), delims.begin(), delims.end());
}
int main()
{
string expr("[X] += 2 + 100 + 32 + 231 -= 123 + 532");
// Erase white space:
erase_whitespaces(expr);
cout << expr << endl;
// Split expresion:
vector<string> splited_str;
vector<string> splited_del;
split_string(splited_str, splited_del, expr, { "+=", "-=" });
// Print result:
for (vector<string>::iterator it = splited_str.begin(); it != splited_str.end(); ++it) {
cout << *it << endl;
}
// Hold:
getchar();
}
- How can I improve this code in terms of performance?
- using
string(char *, size_t)constructor to convertstring::iterator itr(*itris achar) hurts my eyes and soul... Is there any better way of performing this conversion? - I will want to switch output containers from
vector<string>tolist<string>(REASON: callinglist<string> myList; myList.insert()will be faster.). - I know that
FindDelim()function object will perform out-of-bounds read, at the end of the string. But I think I can live with it. (prove me wrong?)
Function split_string() in the example has been called in a loop until the given time duration has passed. Measurement result is average value from every call.
measurement duration: 180 [sec]
measurement result 1: 1895.690 [ns]
measurement result 2: 1878.571 [ns]