Optimization of GCodeReader:

1) Use std::from_chars() instead of strtod()
2) Own implementation of buffered readline()
This commit is contained in:
Vojtech Bubnik 2021-09-03 16:19:16 +02:00
parent d154752c38
commit dc72723911
2 changed files with 41 additions and 12 deletions

View file

@ -2,6 +2,7 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/nowide/fstream.hpp>
#include <charconv>
#include <fstream>
#include <iostream>
#include <iomanip>
@ -32,7 +33,7 @@ void GCodeReader::apply_config(const DynamicPrintConfig &config)
m_extrusion_axis = get_extrusion_axis_char(m_config);
}
const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline, std::pair<const char*, const char*> &command)
const char* GCodeReader::parse_line_internal(const char *ptr, const char *end, GCodeLine &gline, std::pair<const char*, const char*> &command)
{
PROFILE_FUNC();
@ -70,9 +71,9 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
}
if (axis != NUM_AXES_WITH_UNKNOWN) {
// Try to parse the numeric value.
char *pend = nullptr;
double v = strtod(++ c, &pend);
if (pend != nullptr && is_end_of_word(*pend)) {
double v;
auto [pend, ec] = std::from_chars(++ c, end, v);
if (pend != c && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
if (axis != UNKNOWN_AXIS)
gline.m_axis[int(axis)] = float(v);
@ -128,10 +129,37 @@ void GCodeReader::update_coordinates(GCodeLine &gline, std::pair<const char*, co
void GCodeReader::parse_file(const std::string &file, callback_t callback)
{
boost::nowide::ifstream f(file);
f.sync_with_stdio(false);
std::vector<char> buffer(65536 * 10, 0);
std::string line;
m_parsing = true;
while (m_parsing && std::getline(f, line))
this->parse_line(line, callback);
GCodeLine gline;
bool eof = false;
while (m_parsing && ! eof) {
f.read(buffer.data(), buffer.size());
auto it = buffer.begin();
auto it_bufend = buffer.begin() + f.gcount();
eof = ! f.good();
while (it != it_bufend) {
bool eol = false;
auto it_end = it;
for (; it_end != it_bufend && ! (eol = *it_end == '\r' || *it_end == '\n'); ++ it_end) ;
eol |= eof && it_end == it_bufend;
if (eol) {
gline.reset();
if (line.empty())
this->parse_line(&(*it), &(*it_end), gline, callback);
else {
line.insert(line.end(), it, it_end);
this->parse_line(line.c_str(), line.c_str() + line.size(), gline, callback);
line.clear();
}
} else
line.insert(line.end(), it, it_end);
// Skip all the empty lines.
for (it = it_end; it != it_bufend && (*it == '\r' || *it == '\n'); ++ it) ;
}
}
}
bool GCodeReader::GCodeLine::has(char axis) const

View file

@ -83,11 +83,12 @@ public:
void parse_buffer(const std::string &buffer, Callback callback)
{
const char *ptr = buffer.c_str();
const char *end = ptr + buffer.size();
GCodeLine gline;
m_parsing = true;
while (m_parsing && *ptr != 0) {
gline.reset();
ptr = this->parse_line(ptr, gline, callback);
ptr = this->parse_line(ptr, end, gline, callback);
}
}
@ -95,18 +96,18 @@ public:
{ this->parse_buffer(buffer, [](GCodeReader&, const GCodeReader::GCodeLine&){}); }
template<typename Callback>
const char* parse_line(const char *ptr, GCodeLine &gline, Callback &callback)
const char* parse_line(const char *ptr, const char *end, GCodeLine &gline, Callback &callback)
{
std::pair<const char*, const char*> cmd;
const char *end = parse_line_internal(ptr, gline, cmd);
const char *line_end = parse_line_internal(ptr, end, gline, cmd);
callback(*this, gline);
update_coordinates(gline, cmd);
return end;
return line_end;
}
template<typename Callback>
void parse_line(const std::string &line, Callback callback)
{ GCodeLine gline; this->parse_line(line.c_str(), gline, callback); }
{ GCodeLine gline; this->parse_line(line.c_str(), line.c_str() + line.size(), gline, callback); }
void parse_file(const std::string &file, callback_t callback);
void quit_parsing() { m_parsing = false; }
@ -127,7 +128,7 @@ public:
// void set_extrusion_axis(char axis) { m_extrusion_axis = axis; }
private:
const char* parse_line_internal(const char *ptr, GCodeLine &gline, std::pair<const char*, const char*> &command);
const char* parse_line_internal(const char *ptr, const char *end, GCodeLine &gline, std::pair<const char*, const char*> &command);
void update_coordinates(GCodeLine &gline, std::pair<const char*, const char*> &command);
static bool is_whitespace(char c) { return c == ' ' || c == '\t'; }