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:
Tomasz Sowa 2010-11-25 22:39:58 +00:00
parent 5108495540
commit 0b09b5454f
6 changed files with 195 additions and 152 deletions

View File

@ -1,7 +1,7 @@
# DO NOT DELETE
edanticitem.o: item.h
edanticpattern.o: pattern.h item.h stringconv.h utf8.h
edanticitem.o: item.h funinfo.h
edanticpattern.o: pattern.h item.h funinfo.h functions.h stringconv.h utf8.h
edanticpattern.o: /home/tomek/roboczy/winix/core/log.h
edanticpattern.o: /home/tomek/roboczy/winix/core/textstream.h
edanticpattern.o: /home/tomek/roboczy/winix/core/misc.h

View File

@ -40,7 +40,7 @@
#include <map>
#include "funinfo.h"
#include "stringconv.h"
namespace Ezc
@ -87,8 +87,7 @@ public:
bool Find(const std::string & key, Function ** fun);
bool Find(const std::wstring & key, Function ** fun);
void Clear();
size_t Size();
size_t Size() const;
private:
typedef std::map<std::wstring, Function> FunctionsTable;
@ -99,9 +98,6 @@ private:
template<class StreamType>
Functions<StreamType>::Function::Function()
{
@ -246,13 +242,15 @@ void Functions<StreamType>::Clear()
}
template<class StreamType>
size_t Functions<StreamType>::Size()
size_t Functions<StreamType>::Size() const
{
return functions_tab.size();
}
} // namespace Ezc

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");
}

View File

@ -41,6 +41,7 @@
#include <vector>
#include <string>
#include "funinfo.h"
namespace Ezc
@ -61,6 +62,12 @@ struct Item
{
std::wstring name; // function name
std::vector<std::wstring> params; // function parameters
void * fun_cache;
Function()
{
fun_cache = 0;
}
};
Type type;

View File

@ -38,9 +38,6 @@
#include "pattern.h"
#ifdef EZC_USE_WINIX_LOGGER
#include "core/log.h"
#endif
namespace Ezc
@ -70,6 +67,22 @@ void Pattern::Clear()
}
void Pattern::ClearCache()
{
ClearCache(item_root);
}
void Pattern::ClearCache(Item & item)
{
for(size_t f = 0; f < item.functions.size() ; ++f)
item.functions[f].fun_cache = 0;
for(size_t i = 0; i < item.item_tab.size() ; ++i)
ClearCache(*item.item_tab[i]);
}
void Pattern::Directory(const char * dir, const char * dir2)
{
@ -77,17 +90,17 @@ void Pattern::Directory(const char * dir, const char * dir2)
directory2.clear();
if( dir )
AssignString(dir, directory);
UTF8ToWide(dir, directory);
if( dir2 )
AssignString(dir2, directory2);
UTF8ToWide(dir2, directory2);
}
void Pattern::Directory(const std::string & dir)
{
AssignString(dir, directory);
UTF8ToWide(dir, directory);
directory2.clear();
}
@ -95,8 +108,8 @@ void Pattern::Directory(const std::string & dir)
void Pattern::Directory(const std::string & dir, const std::string & dir2)
{
AssignString(dir, directory);
AssignString(dir2, directory2);
UTF8ToWide(dir, directory);
UTF8ToWide(dir2, directory2);
}
@ -141,7 +154,7 @@ void Pattern::ParseFile(const std::string & file_name)
void Pattern::ParseFile(const char * file_name)
{
AssignString(file_name, item_root.file_name);
UTF8ToWide(file_name, item_root.file_name);
include_level = 0;
CreateTreeReadIncludeSkipAllowFlag(item_root);
}
@ -169,7 +182,11 @@ void Pattern::ParseFile(const wchar_t * file_name)
void Pattern::ParseString(const char * str)
{
AssignString(str, string_content);
if( input_as_utf8 )
UTF8ToWide(str, string_content);
else
AssignString(str, string_content);
ParseString(string_content.c_str());
string_content.clear();
}
@ -243,16 +260,16 @@ void Pattern::UTF8(bool utf8)
void Pattern::SetCommentary(const char * com_start, const char * com_stop)
{
AssignString(com_start, commentary_start);
AssignString(com_stop, commentary_stop);
UTF8ToWide(com_start, commentary_start);
UTF8ToWide(com_stop, commentary_stop);
}
void Pattern::SetCommentary(const std::string & com_start, const std::string & com_stop)
{
AssignString(com_start, commentary_start);
AssignString(com_stop, commentary_stop);
UTF8ToWide(com_start, commentary_start);
UTF8ToWide(com_stop, commentary_stop);
}
@ -275,23 +292,6 @@ void Pattern::SetCommentary(const std::wstring & com_start, const std::wstring &
void Pattern::CreateMsg(std::wstring & out, const char * type, const char * arg)
{
out = commentary_start;
out += L"Ezc: ";
AssignString(type, out, false);
if( arg )
{
out += ' ';
AssignString(arg, out, false);
}
out += commentary_stop;
}
void Pattern::CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg)
{
out = commentary_start;
@ -409,12 +409,15 @@ bool Pattern::ReadFileFromDir(const std::wstring & dir, const wchar_t * name, st
return false;
}
ReadFile(file, result);
#ifdef EZC_USE_WINIX_LOGGER
log << log3 << "Ezc: read pattern: " << afile_name << logend;
if( include_level <= 1 )
log << log3 << "Ezc: reading pattern: " << afile_name << logend;
else
log << log3 << " including pattern: " << afile_name << logend;
#endif
ReadFile(file, result);
file_name.clear();
afile_name.clear();

View File

@ -41,9 +41,13 @@
#include <string>
#include "item.h"
#include "functions.h"
#include "stringconv.h"
#include "utf8.h"
#ifdef EZC_USE_WINIX_LOGGER
#include "core/log.h"
#endif
namespace Ezc
@ -98,14 +102,18 @@ public:
void SetCommentary(const wchar_t * com_start, const wchar_t * com_stop);
void SetCommentary(const std::wstring & com_start, const std::wstring & com_stop);
void CreateMsg(std::wstring & out, const char * type, const char * arg = 0);
void CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg = 0);
static bool IsWhite(wchar_t c);
Item item_root;
template<class StreamType>
void CacheFunctions(Functions<StreamType> & fun)
{
CacheFunctions(item_root, fun);
}
void ClearCache();
private:
@ -203,6 +211,39 @@ private:
void CreateTreeReadInclude(Item & item);
void CreateTreeReadIncludeSkipAllowFlag(Item & item);
template<class StreamType>
void CacheFunctions(Item & item, Functions<StreamType> & fun)
{
typename Functions<StreamType>::Function * ezc_fun;
for(size_t f = 0; f < item.functions.size() ; ++f)
{
if( fun.Find(item.functions[f].name, &ezc_fun) )
{
item.functions[f].fun_cache = ezc_fun;
}
else
{
item.functions[f].fun_cache = 0;
#ifdef EZC_USE_WINIX_LOGGER
log << log1 << "Ezc: unknown function: " << item.functions[f].name << logend;
#endif
}
// one exception (if_index is putting its argument on the functions stack)
if( item.type == Item::item_ifindex )
break;
}
for(size_t i = 0; i < item.item_tab.size() ; ++i)
CacheFunctions(*item.item_tab[i], fun);
}
void ClearCache(Item & item);
}; // class Pattern