Fixed performance problem.

This commit is contained in:
yhirose 2015-03-02 17:35:55 -05:00
parent d93a007ef0
commit d5e28fff94
3 changed files with 62 additions and 75 deletions

View File

@ -61,7 +61,9 @@ int main(int argc, const char** argv)
return -1;
}
auto ret = peg.lint(source.data(), source.size(), true, [&](size_t ln, size_t col, const string& msg) {
peglib::any dt;
auto ret = peg.lint(source.data(), source.size(), true, false, dt,
[&](size_t ln, size_t col, const string& msg) {
cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl;
});

131
peglib.h
View File

@ -15,30 +15,12 @@
#include <mutex>
#include <vector>
#include <unordered_map>
#include <map>
#include <cassert>
#include <cstring>
#include <initializer_list>
#include <iostream>
// From http://stackoverflow.com/questions/7222143/unordered-map-hash-function-c#answer-7222201
template <class T>
inline void hash_combine(std::size_t & seed, const T & v) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std {
template<typename S, typename T>
struct hash<pair<S, T>> {
inline size_t operator()(const pair<S, T> & v) const {
size_t seed = 0;
::hash_combine(seed, v.first);
::hash_combine(seed, v.second);
return seed;
}
};
}
namespace peglib {
void* enabler;
@ -437,7 +419,7 @@ struct Context
std::vector<bool> cache_register;
std::vector<bool> cache_success;
std::unordered_map<std::pair<size_t, size_t>, std::pair<int, any>> cache_result;
std::map<std::pair<size_t, size_t>, std::pair<int, any>> cache_result;
std::vector<std::shared_ptr<SemanticValues>> stack;
size_t stack_size;
@ -445,7 +427,7 @@ struct Context
mutable size_t hit;
mutable size_t miss;
Context(const char* _s, size_t _l, size_t _def_count, bool packrat = true)
Context(const char* _s, size_t _l, size_t _def_count, bool packrat)
: s(_s)
, l(_l)
, def_count(_def_count)
@ -461,7 +443,8 @@ struct Context
//std::cout << "hit:" << hit << " miss:" << miss << std::endl;
}
void packrat(const char* s, size_t def_id, int& len, any& val, std::function<void (int&, any&)> fn) {
template <typename T>
void packrat(const char* s, size_t def_id, int& len, any& val, T fn) {
if (cache_register.empty()) {
fn(len, val);
return;
@ -493,13 +476,15 @@ struct Context
}
}
SemanticValues& push() {
inline SemanticValues& push() {
assert(stack_size <= stack.size());
if (stack_size == stack.size()) {
stack.push_back(std::make_shared<SemanticValues>());
}
auto& sv = *stack[stack_size++];
sv.clear();
if (!sv.empty()) {
sv.clear();
}
sv.s = nullptr;
sv.l = 0;
return sv;
@ -984,13 +969,13 @@ struct Ope::Visitor
struct DefinitionIDs : public Ope::Visitor
{
void visit(Sequence& ope) override {
for (auto ope: ope.opes_) {
ope->accept(*this);
for (auto op: ope.opes_) {
op->accept(*this);
}
}
void visit(PrioritizedChoice& ope) override {
for (auto ope: ope.opes_) {
ope->accept(*this);
for (auto op: ope.opes_) {
op->accept(*this);
}
}
void visit(ZeroOrMore& ope) override {
@ -1088,35 +1073,36 @@ public:
return *this;
}
Result parse_core(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse_core(const char* s, size_t l, SemanticValues& sv, any& dt, bool packrat) const {
DefinitionIDs defIds;
holder_->accept(defIds);
Context c(s, l, defIds.ids.size());
Context c(s, l, defIds.ids.size(), packrat);
auto len = holder_->parse(s, l, sv, c, dt);
return Result { success(len), len, c.error_ptr, c.msg };
}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
return parse_core(s, l, sv, dt);
Result parse(const char* s, size_t l, any& dt, bool packrat = false) const {
SemanticValues sv;
return parse_core(s, l, sv, dt, packrat);
}
Result parse(const char* s, size_t l) const {
Result parse(const char* s, size_t l, bool packrat = false) const {
SemanticValues sv;
any dt;
return parse_core(s, l, sv, dt);
return parse_core(s, l, sv, dt, packrat);
}
Result parse(const char* s) const {
Result parse(const char* s, bool packrat = false) const {
auto l = strlen(s);
return parse(s, l);
return parse(s, l, packrat);
}
template <typename T>
Result parse_with_value(const char* s, size_t l, T& val) const {
Result parse_with_value(const char* s, size_t l, T& val, bool packrat = false) const {
SemanticValues sv;
any dt;
auto r = parse_core(s, l, sv, dt);
auto r = parse_core(s, l, sv, dt, packrat);
if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) {
val = sv[0].val.get<T>();
}
@ -1124,9 +1110,9 @@ public:
}
template <typename T>
Result parse_with_value(const char* s, T& val) const {
Result parse_with_value(const char* s, T& val, bool packrat = false) const {
auto l = strlen(s);
return parse_with_value(s, l, val);
return parse_with_value(s, l, val, packrat);
}
Definition& operator=(Action ac) {
@ -1615,9 +1601,8 @@ private:
Data data;
data.match_action = ma;
SemanticValues sv;
any dt = &data;
auto r = g["Grammar"].parse(s, l, sv, dt);
auto r = g["Grammar"].parse(s, l, dt, false);
if (!r.ret) {
if (log) {
@ -1787,42 +1772,61 @@ public:
}
template <typename T>
bool parse(const char* s, size_t l, T& out, bool exact = true) const {
bool parse(const char* s, size_t l, T& out, bool exact = true, bool packrat = false) const {
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse_with_value(s, l, out);
auto r = rule.parse_with_value(s, l, out, packrat);
return r.ret && (!exact || r.len == l);
}
return false;
}
template <typename T>
bool parse(const char* s, T& out, bool exact = true) const {
bool parse(const char* s, T& out, bool exact = true, bool packrat = false) const {
auto l = strlen(s);
return parse(s, l, out, exact);
return parse(s, l, out, exact, packrat);
}
bool parse(const char* s, size_t l, bool exact = true) const {
bool parse(const char* s, size_t l, bool exact = true, bool packrat = false) const {
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l);
auto r = rule.parse(s, l, packrat);
return r.ret && (!exact || r.len == l);
}
return false;
}
bool parse(const char* s, bool exact = true) const {
bool parse(const char* s, bool exact = true, bool packrat = false) const {
auto l = strlen(s);
return parse(s, l, exact);
return parse(s, l, exact, packrat);
}
bool search(const char* s, size_t l, size_t& mpos, size_t& mlen) const {
bool lint(const char* s, size_t l, bool exact, bool packrat, any& dt, Log log) {
assert(grammar_);
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l, dt, packrat);
if (!r.ret) {
if (log) {
auto line = line_info(s, r.error_ptr);
log(line.first, line.second, r.msg ? "syntax error" : r.msg);
}
} else if (exact && r.len != l) {
auto line = line_info(s, s + r.len);
log(line.first, line.second, "syntax error");
}
return r.ret && (!exact || r.len == l);
}
return false;
}
bool search(const char* s, size_t l, size_t& mpos, size_t& mlen, bool packrat = false) const {
const auto& rule = (*grammar_)[start_];
if (grammar_ != nullptr) {
size_t pos = 0;
while (pos < l) {
size_t len = l - pos;
auto r = rule.parse(s + pos, len);
auto r = rule.parse(s + pos, len, packrat);
if (r.ret) {
mpos = pos;
mlen = len;
@ -1836,28 +1840,9 @@ public:
return false;
}
bool search(const char* s, size_t& mpos, size_t& mlen) const {
bool search(const char* s, size_t& mpos, size_t& mlen, bool packrat) const {
auto l = strlen(s);
return search(s, l, mpos, mlen);
}
bool lint(const char* s, size_t l, bool exact, Log log = nullptr) {
assert(grammar_);
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l);
if (!r.ret) {
if (log) {
auto line = line_info(s, r.error_ptr);
log(line.first, line.second, r.msg ? "syntax error" : r.msg);
}
} else if (exact && r.len != l) {
auto line = line_info(s, s + r.len);
log(line.first, line.second, "syntax error");
}
return r.ret && (!exact || r.len == l);
}
return false;
return search(s, l, mpos, mlen, packrat);
}
Definition& operator[](const char* s) {

View File

@ -204,7 +204,7 @@ TEST_CASE("Backtracking test", "[general]")
count++;
};
bool ret = parser.parse("Hello Two");
bool ret = parser.parse("Hello Two", true, true);
REQUIRE(ret == true);
REQUIRE(count == 1); // Skip second time
}