added: Pattern::CacheFunctions(Functions<StreamType> & fun)

you can cache all functions (their addresses) in the pattern

changed: now we have two methods for generating content:
       Generator<>::Generate(StreamType & o, Pattern & p, Functions<StreamType> & f);
       similar like previous -- Set(...) methods were removed as well as the second ctor 

       and a second one:
       Generate(StreamType & o, Pattern & p);
       without functions, the functions should be cached beforehand in the pattern
       by calling CacheFunctions() method on the pattern
       this gives O(1) complexity when looking for a specific function
       previously was O(log n) 
       


git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@329 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
2010-11-25 22:39:58 +00:00
parent 5108495540
commit 0b09b5454f
6 changed files with 195 additions and 152 deletions
+100 -106
View File
@@ -48,8 +48,7 @@ namespace Ezc
{
/*
StreamType
we use method write where the content should not be escaped (html escaping)
we use operator<< where the content can be escaped (such as error messages)
we use only method write(const wchar_t * str, size_t len) from the stream
*/
template<class StreamType>
class Generator
@@ -57,12 +56,7 @@ class Generator
public:
Generator();
Generator(StreamType & o, Pattern & p, Functions<StreamType> & f);
void Set(StreamType & o, Pattern & p, Functions<StreamType> & f);
void Set(StreamType & o);
void Set(Pattern & p);
void Set(Functions<StreamType> & f);
void SetMax(int max_items_, int max_for_items_);
// recognizing some special characters in text patterns (item_text in Patterns)
@@ -86,8 +80,12 @@ public:
// default: false
void SkipNewLine(bool skip);
// the main method for generating
void Generate();
// the main methods for generating
void Generate(StreamType & o, Pattern & p, Functions<StreamType> & f);
// this method is used only if the pattern has cached functions
void Generate(StreamType & o, Pattern & p);
private:
@@ -111,11 +109,10 @@ private:
const std::wstring empty;
bool Find(const std::wstring & key, typename Functions<StreamType>::Function ** function);
bool Find(const Item::Function & item_fun, typename Functions<StreamType>::Function ** function);
void Call(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
bool Call(const std::wstring & name, FunInfo<StreamType> & info, typename Functions<StreamType>::Function ** pfun = 0);
bool Call(typename Item::Function & function, bool * info_res = 0, typename Functions<StreamType>::Function ** pfun = 0);
bool Call(Item::Function & function, bool * info_res = 0, typename Functions<StreamType>::Function ** pfun = 0);
void CallUserFunction(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
void CallVariable(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
@@ -128,9 +125,10 @@ private:
void SkipWhite(const wchar_t *& str);
int StrToInt(const wchar_t * str, const wchar_t ** str_end);
void CreateMsg(StreamType & o, const wchar_t * type, const wchar_t * arg = 0);
void CreateMsg(StreamType & o, const std::wstring & type, const std::wstring & arg);
void CreateMsg(StreamType & o, const std::wstring & type);
void CreateMsg(const wchar_t * type, const wchar_t * arg = 0);
void CreateMsg(const std::wstring & type, const std::wstring & arg);
void CreateMsg(const std::wstring & type);
void CreateUnknownMsg(const std::wstring & fun);
void MakeTextIf_go(Item & item, bool result);
bool MakeTextIfindexnumber(Item & item, typename Functions<StreamType>::Function * function, bool & result);
@@ -173,49 +171,6 @@ Generator<StreamType>::Generator()
}
template<class StreamType>
Generator<StreamType>::Generator(StreamType & o, Pattern & p, Functions<StreamType> & f)
{
output_stream = &o;
pattern = &p;
functions = &f;
max_items = 50000;
max_for_items = 5000;
special_chars = false;
trim_white = false;
skip_new_line = false;
}
template<class StreamType>
void Generator<StreamType>::Set(StreamType & o, Pattern & p, Functions<StreamType> & f)
{
output_stream = &o;
pattern = &p;
functions = &f;
}
template<class StreamType>
void Generator<StreamType>::Set(StreamType & o)
{
output_stream = &o;
}
template<class StreamType>
void Generator<StreamType>::Set(Pattern & p)
{
pattern = &p;
}
template<class StreamType>
void Generator<StreamType>::Set(Functions<StreamType> & f)
{
functions = &f;
}
template<class StreamType>
@@ -248,10 +203,25 @@ void Generator<StreamType>::SkipNewLine(bool skip)
template<class StreamType>
void Generator<StreamType>::Generate()
void Generator<StreamType>::Generate(StreamType & o, Pattern & p, Functions<StreamType> & f)
{
if( !output_stream || !pattern || !functions )
return;
output_stream = &o;
pattern = &p;
functions = &f;
break_generating = false;
current_item = 0;
MakeText( pattern->item_root );
}
template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p)
{
output_stream = &o;
pattern = &p;
functions = 0;
break_generating = false;
current_item = 0;
@@ -263,12 +233,27 @@ void Generator<StreamType>::Generate()
template<class StreamType>
bool Generator<StreamType>::Find(const std::wstring & key, typename Functions<StreamType>::Function ** function)
bool Generator<StreamType>::Find(const Item::Function & item_fun, typename Functions<StreamType>::Function ** function)
{
if( !functions->Find(key, function) )
if( !functions )
{
CreateMsg(*output_stream, L"can't find", key.c_str() );
if( item_fun.fun_cache )
{
*function = reinterpret_cast<typename Functions<StreamType>::Function*>(item_fun.fun_cache);
return true;
}
else
{
CreateUnknownMsg(item_fun.name);
return false;
}
}
if( !functions->Find(item_fun.name, function) )
{
CreateUnknownMsg(item_fun.name);
return false;
}
@@ -276,14 +261,13 @@ return true;
}
template<class StreamType>
void Generator<StreamType>::CallUserFunction(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
{
if( function->is_running )
{
// recurrences are not allowed
CreateMsg(*output_stream, L"the function is being executed");
CreateMsg(L"the function is being executed");
return;
}
@@ -315,53 +299,52 @@ void Generator<StreamType>::Call(typename Functions<StreamType>::Function * func
}
// return: true if a function or variable was found and called
template<class StreamType>
bool Generator<StreamType>::Call(const std::wstring & name, FunInfo<StreamType> & info, typename Functions<StreamType>::Function ** pfun)
{
typename Functions<StreamType>::Function * function;
if( Find(name, &function) )
{
Call(function, info);
if( pfun )
*pfun = function;
return true;
}
return false;
}
// return: true if a function or variable was found and called
template<class StreamType>
bool Generator<StreamType>::Call(typename Item::Function & function, bool * info_res, typename Functions<StreamType>::Function ** pfun)
bool Generator<StreamType>::Call(Item::Function & item_fun, bool * info_res, typename Functions<StreamType>::Function ** pfun)
{
bool called;
typename Functions<StreamType>::Function * fun;
bool called = false;
if( function.params.empty() )
if( item_fun.params.empty() )
{
FunInfo<StreamType> info(*output_stream, function.params, empty);
called = Call(function.name, info, pfun);
FunInfo<StreamType> info(*output_stream, item_fun.params, empty);
if( Find(item_fun, &fun) )
{
Call(fun, info);
called = true;
}
if( info_res )
*info_res = info.res;
}
else
{
FunInfo<StreamType> info(*output_stream, function.params, function.params[0]);
called = Call(function.name, info, pfun);
FunInfo<StreamType> info(*output_stream, item_fun.params, item_fun.params[0]);
if( Find(item_fun, &fun) )
{
Call(fun, info);
called = true;
}
if( info_res )
*info_res = info.res;
}
if( called && pfun )
*pfun = fun;
return called;
}
template<class StreamType>
wchar_t Generator<StreamType>::CreateSpecialChar(wchar_t c)
{
@@ -520,30 +503,35 @@ return res;
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & o, const wchar_t * type, const wchar_t * arg)
void Generator<StreamType>::CreateMsg(const wchar_t * type, const wchar_t * arg)
{
pattern->CreateMsg(temp_msg, type, arg);
o << temp_msg;
temp_msg.clear();
output_stream->write(temp_msg.c_str(), temp_msg.size());
}
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & o, const std::wstring & type, const std::wstring & arg)
void Generator<StreamType>::CreateMsg(const std::wstring & type, const std::wstring & arg)
{
CreateMsg(o, type.c_str(), arg.c_str());
CreateMsg(type.c_str(), arg.c_str());
}
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & o, const std::wstring & type)
void Generator<StreamType>::CreateMsg(const std::wstring & type)
{
CreateMsg(o, type.c_str());
CreateMsg(type.c_str());
}
template<class StreamType>
void Generator<StreamType>::CreateUnknownMsg(const std::wstring & fun)
{
CreateMsg(L"unknown function", fun.c_str());
}
@@ -770,7 +758,7 @@ bool Generator<StreamType>::MakeTextIfindexnumber(Item & item, typename Function
if( *last_char != '\0' )
{
CreateMsg(*output_stream, L"if-index: syntax error");
CreateMsg(L"if-index: syntax error");
return false;
}
@@ -792,7 +780,7 @@ void Generator<StreamType>::MakeTextIfindex(Item & item)
typename Functions<StreamType>::Function * function;
if( !Find(item.functions[0].name, &function) )
if( !Find(item.functions[0], &function) )
return;
bool result = false;
@@ -832,7 +820,7 @@ bool info_res;
{
if( function->iter >= max_for_items )
{
CreateMsg(*output_stream, item.functions[0].name.c_str(),
CreateMsg(item.functions[0].name.c_str(),
L"function exceeded a limit for a [for] statement");
break;
}
@@ -856,12 +844,12 @@ void Generator<StreamType>::MakeTextFor(Item & item)
typename Functions<StreamType>::Function * function;
if( !Find(item.functions[0].name, &function) )
if( !Find(item.functions[0], &function) )
return;
if( function->is_for )
{
CreateMsg(*output_stream, item.functions[0].name.c_str(),
CreateMsg(item.functions[0].name.c_str(),
L"this function is already used in a [for] statement");
return;
}
@@ -880,6 +868,12 @@ void Generator<StreamType>::MakeTextFor(Item & item)
template<class StreamType>
void Generator<StreamType>::MakeTextDefine(Item & item)
{
if( !functions )
{
CreateMsg(L"def statement is not available when used without functions set");
return;
}
if( item.functions.size() == 1 )
{
// inserting a new variable
@@ -891,7 +885,7 @@ void Generator<StreamType>::MakeTextDefine(Item & item)
{
typename Functions<StreamType>::Function * function;
if( Find(item.functions[1].name, &function) )
if( Find(item.functions[1], &function) )
{
if( function->type == Functions<StreamType>::function )
{
@@ -919,7 +913,7 @@ void Generator<StreamType>::MakeText(Item & item)
if( ++current_item > max_items )
{
break_generating = true;
CreateMsg(*output_stream, L"Generator exceeded allowed number of elements");
CreateMsg(L"Generator exceeded allowed number of elements");
return;
}
@@ -938,7 +932,7 @@ void Generator<StreamType>::MakeText(Item & item)
else if( item.type == Item::item_for ) MakeTextFor(item);
else if( item.type == Item::item_def ) MakeTextDefine(item);
else if( item.type == Item::item_err )
CreateMsg(*output_stream, L"a wrong directive");
CreateMsg(L"a wrong directive");
}