diff --git a/modules/gmt/modgmt_strcomp.cpp b/modules/gmt/modgmt_strcomp.cpp new file mode 100644 index 0000000..db5803b --- /dev/null +++ b/modules/gmt/modgmt_strcomp.cpp @@ -0,0 +1,139 @@ +#include "modgmt_strcomp.h" + +TemplateComparator::Block::pBlock TemplateComparator::Parse() +{ + size_t e=0; + struct Block* blk; + struct Block* root; + auto c=s[e]; + bool init,next; + + // First symbol + if('['==c || '('==c) blk=new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS); + else blk=new Block(e,e+1); + root=blk; + init=root->type!=Block::TEXT; + next=!init; + + e++; + while(enext:blk->child).reset(new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS,(next?blk->parent:blk))); + blk=(next?blk->next:blk->child).get(); + init=true; + next=false; + break; + } + case ']': + case ')': + { + blk=const_cast(blk->parent); + init=true; + next=true; + break; + } + case '|': {blk->next.reset(new Block(Block::DELIM,blk->parent)); blk=blk->next.get(); init=next=true; break;} + default: + { + if(init) + { + (next?blk->next:blk->child).reset(new Block(e,e+1,(next?blk->parent:blk))); + blk=(next?blk->next:blk->child).get(); + } + else blk->e=e+1; + init=false; + next=true; + } + } + e++; + } + return Block::pBlock(root); +} + +void TemplateComparator::InitCursors(const struct TemplateComparator::Block* blk) +{ + switch(blk->type) + { + case Block::TEXT: {cursors.insert({blk,0}); break;} + case Block::OPTIONAL: + { + auto b=blk; + InitCursors(b->child.get()); + while(true) + { + if(!b->next) break; + b=b->next.get(); + InitCursors(b); + if(b->type!=Block::OPTIONAL) break; + } + break; + } + case Block::VARIANTS: + { + auto b=blk->child.get(); + while(true) + { + InitCursors(b); + while(b->type!=Block::DELIM) + { + if(!b->next) break; + b=b->next.get(); + } + if(!b->next) break; + b=b->next.get(); + } + } + default: {} + } +} + +bool TemplateComparator::CmpSmb(const char c) +{ + pCursor p=cursors.cbegin(); + bool res=false; + + // Compare symbol with all cursors + while(p!=cursors.end()) + { + if(p->compare(s,c)) {res=true; p++;} + else p=cursors.erase(p); + } + + Cursors old(std::move(cursors)); + for(const auto& p:old) + { + auto blk=p.block; + // Increment cursors + if(blk->b+p.offset+1e) cursors.insert({blk,p.offset+1}); // Advance in current block + else // Move to next block + { + if(!blk->next || blk->next->type==Block::DELIM) // End of chain, must go up + { + while(blk->parent!=nullptr) + { + blk=blk->parent; + if(!blk->next || blk->next->type==Block::DELIM) continue; + InitCursors(blk->next.get()); + } + } + else InitCursors(blk->next.get()); // Next block in chain + } + + // Try to leave optional blocks + blk=p.block; + while(blk->parent!=nullptr) + { + blk=blk->parent; + if(blk->type!=Block::OPTIONAL || !blk->next || blk->next->type==Block::DELIM) continue; + InitCursors(blk->next.get()); + } + } + return res; +} diff --git a/modules/gmt/modgmt_strcomp.h b/modules/gmt/modgmt_strcomp.h new file mode 100644 index 0000000..143822c --- /dev/null +++ b/modules/gmt/modgmt_strcomp.h @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +class TemplateComparator +{ + TemplateComparator() = delete; + TemplateComparator(const TemplateComparator&) = delete; + TemplateComparator(TemplateComparator&&) = delete; + + struct Block + { + using pBlock=std::unique_ptr; + enum Type {NOTDEF,TEXT,OPTIONAL,VARIANTS,DELIM}; + size_t b,e; + Type type; + const struct Block* parent; + pBlock next,child; + + Block() = delete; + Block(const struct Block&) = delete; + Block(struct Block&&) = delete; + + Block(Type t, const struct Block* p=nullptr):b(0),e(0),type(t),parent(p),next(nullptr),child(nullptr) {} + Block(size_t bb, size_t ee, const struct Block* p=nullptr):b(bb),e(ee),type(TEXT),parent(p),next(nullptr),child(nullptr) {} + }; + + struct Cursor + { + const struct Block* block; + size_t offset; + bool operator <(const struct Cursor& c) const {return blockb+offset];} + Cursor(const struct Block* b, size_t o):block(b),offset(o) {} + }; + + using Cursors=std::set; + using pCursor=std::set::const_iterator; + + Block::pBlock Parse(); + void InitCursors(const struct Block* blk); + bool CmpSmb(const char c); + + Block::pBlock root; + Cursors cursors; + const std::string s; + + public: + TemplateComparator(const char* str):s(str) {root=Parse();} + TemplateComparator(const std::string& str):s(str) {root=Parse();} + TemplateComparator(std::string&& str):s(std::move(str)) {root=Parse();} + + bool Compare(const std::string& str) + { + Reset(); + for(size_t pos=0; pos