Michael Uleysky
8 years ago
2 changed files with 206 additions and 0 deletions
@ -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(e<s.length()) |
||||
{ |
||||
c=s[e]; |
||||
|
||||
switch(c) |
||||
{ |
||||
case '[': |
||||
case '(': |
||||
{ |
||||
(next?blk->next: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<struct Block*>(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+1<blk->e) 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; |
||||
} |
@ -0,0 +1,67 @@
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <set> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
class TemplateComparator |
||||
{ |
||||
TemplateComparator() = delete; |
||||
TemplateComparator(const TemplateComparator&) = delete; |
||||
TemplateComparator(TemplateComparator&&) = delete; |
||||
|
||||
struct Block |
||||
{ |
||||
using pBlock=std::unique_ptr<struct Block>; |
||||
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 block<c.block;} |
||||
bool compare(const std::string& str, const char c) const {return c==str[block->b+offset];} |
||||
Cursor(const struct Block* b, size_t o):block(b),offset(o) {} |
||||
}; |
||||
|
||||
using Cursors=std::set<struct Cursor>; |
||||
using pCursor=std::set<struct Cursor>::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<str.length(); ++pos) if(!CmpSmb(str[pos])) return false; |
||||
return true; |
||||
} |
||||
|
||||
void Reset() |
||||
{ |
||||
cursors.clear(); |
||||
InitCursors(root.get()); |
||||
} |
||||
}; |
Loading…
Reference in new issue