make some optimization when generating the output
Add three methods to the Generator: - void OnlyFrames(const std::vector<std::wstring> & frames); - void OnlyFrames(const std::vector<std::wstring> * frames); if provided frames then only such frames will be generated, call OnlyFrames(nullptr) to disable it (default) - void UseMainStream(bool use_main_stream); whether or not the main stream should be produced (true by default)
This commit is contained in:
303
src/generator.h
303
src/generator.h
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007-2023, Tomasz Sowa
|
||||
* Copyright (c) 2007-2024, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -127,6 +127,15 @@ public:
|
||||
|
||||
void SetExpressionParser(ExpressionParser * expression_parser);
|
||||
|
||||
// some optimization when generating the output
|
||||
// if provided frames then only such frames will be generated
|
||||
// call OnlyFrames(nullptr) to disable it (default)
|
||||
void OnlyFrames(const std::vector<std::wstring> & frames);
|
||||
void OnlyFrames(const std::vector<std::wstring> * frames);
|
||||
|
||||
// some optimization when generating the output
|
||||
// whether or not the main stream should be produced (true by default)
|
||||
void UseMainStream(bool use_main_stream);
|
||||
|
||||
// the main methods for generating
|
||||
void Generate(StreamType & out);
|
||||
@@ -255,6 +264,10 @@ private:
|
||||
bool can_find_in_cache;
|
||||
bool program_mode;
|
||||
|
||||
const std::vector<std::wstring> * only_frames;
|
||||
bool is_output_stream_allowed;
|
||||
bool use_main_stream;
|
||||
|
||||
ExpressionParser * expression_parser;
|
||||
|
||||
|
||||
@@ -373,8 +386,8 @@ private:
|
||||
void DumpSpaceIfNeeded(std::vector<Var> & parameters, StreamType & out_stream, pt::Space * space);
|
||||
void DumpModelIfNeeded(morm::Model & model, std::vector<Var> & parameters, StreamType & out_stream);
|
||||
|
||||
|
||||
void CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream);
|
||||
StreamType * FindAddOutputStream(const std::wstring & name);
|
||||
void CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream);
|
||||
|
||||
void CreateMsg(const wchar_t * type, const std::wstring & model_name, std::vector<std::wstring> & fields, size_t how_many_fields_print,
|
||||
const wchar_t * arg = nullptr, const wchar_t * arg2 = nullptr, const wchar_t * arg3 = nullptr);
|
||||
@@ -389,6 +402,11 @@ private:
|
||||
bool LimitAchieved();
|
||||
|
||||
void EvaluateProgramNode(Item & item);
|
||||
bool HasAskForSuchFrame(Item::Function & fun);
|
||||
bool HasAskForSuchFrame(const std::wstring & name);
|
||||
|
||||
StreamType * GetNewStreamForFrame();
|
||||
void DecrementFramesStackIndex();
|
||||
|
||||
void MakeTextIf_go(Item & item, bool result);
|
||||
void MakeTextIf(Item & item);
|
||||
@@ -408,6 +426,7 @@ private:
|
||||
void MakeTextEzc(Item & item);
|
||||
void MakeTextReturn(Item & item);
|
||||
void MakeText(Item & item);
|
||||
void MakeEzcFrame2(Item & item);
|
||||
void MakeEzcFrame(Item & item);
|
||||
|
||||
void Generate();
|
||||
@@ -449,6 +468,9 @@ Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::Generator() :
|
||||
can_use_vars = true;
|
||||
expression_parser = nullptr;
|
||||
program_mode = false;
|
||||
only_frames = nullptr;
|
||||
is_output_stream_allowed = true;
|
||||
use_main_stream = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -488,8 +510,11 @@ Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::operator=(cons
|
||||
stack_size = n.stack_size;
|
||||
block_stack_size = n.block_stack_size;
|
||||
ezc_frames_stack_size = n.ezc_frames_stack_size;
|
||||
expression_parser = n.expression_parser;
|
||||
expression_parser= n.expression_parser;
|
||||
program_mode = n.program_mode;
|
||||
only_frames = n.only_frames;
|
||||
is_output_stream_allowed = n.is_output_stream_allowed;
|
||||
use_main_stream = n.use_main_stream;
|
||||
|
||||
// vars doesn't have to be copied
|
||||
|
||||
@@ -598,6 +623,25 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::SetExpres
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::OnlyFrames(const std::vector<std::wstring> & frames)
|
||||
{
|
||||
this->only_frames = &frames;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::OnlyFrames(const std::vector<std::wstring> * frames)
|
||||
{
|
||||
this->only_frames = frames;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::UseMainStream(bool use_main_stream)
|
||||
{
|
||||
this->use_main_stream = use_main_stream;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
@@ -909,6 +953,7 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::Generate(
|
||||
filter_index = 0;
|
||||
stack_index = 0;
|
||||
ezc_frames_stack_index = 0;
|
||||
is_output_stream_allowed = use_main_stream;
|
||||
block_stack_index = 0;
|
||||
|
||||
if( ppattern )
|
||||
@@ -1992,7 +2037,9 @@ std::vector<Var> parameters;
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
bool Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::Call(Item::Function & item_fun)
|
||||
{
|
||||
return Call(item_fun, nullptr, stream_temp1, true, empty_stream);
|
||||
bool status = Call(item_fun, nullptr, stream_temp1, true, empty_stream);
|
||||
ClearStream(stream_temp1);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -2176,44 +2223,61 @@ return res;
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream)
|
||||
StreamType * Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::FindAddOutputStream(const std::wstring & name)
|
||||
{
|
||||
StreamType * stream = nullptr;
|
||||
|
||||
if( output_frames_streams )
|
||||
{
|
||||
CopyStream(ezc_out_tmp_stream, previous_stream);
|
||||
auto imap = output_frames_streams->streams_map.find(name);
|
||||
|
||||
for(size_t s=0 ; s < fun.parameters.size() ; ++s)
|
||||
if( imap == output_frames_streams->streams_map.end() )
|
||||
{
|
||||
std::wstring & name = fun.parameters[s]->name;
|
||||
auto imap = output_frames_streams->streams_map.find(name);
|
||||
|
||||
if( imap == output_frames_streams->streams_map.end() )
|
||||
if( output_frames_streams->streams_map.size() < output_frames_streams->streams_tab.size() )
|
||||
{
|
||||
if( output_frames_streams->streams_map.size() < output_frames_streams->streams_tab.size() )
|
||||
{
|
||||
/* a new stream from the pool (output_stream_tab) is taken */
|
||||
StreamType * stream = output_frames_streams->streams_tab[ output_frames_streams->streams_map.size() ];
|
||||
output_frames_streams->streams_map.insert(std::make_pair(name, stream));
|
||||
ClearStream(*stream);
|
||||
CopyStream(ezc_out_tmp_stream, *stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateMsg(L"limit of output streams in OutStreams<> has been reached");
|
||||
}
|
||||
/* a new stream from the pool (output_stream_tab) is taken */
|
||||
stream = output_frames_streams->streams_tab[output_frames_streams->streams_map.size()];
|
||||
output_frames_streams->streams_map.insert(std::make_pair(name, stream));
|
||||
ClearStream(*stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
StreamType * stream = imap->second;
|
||||
CopyStream(ezc_out_tmp_stream, *stream);
|
||||
CreateMsg(L"limit of output streams in OutStreams<> has been reached");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stream = imap->second;
|
||||
}
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream)
|
||||
{
|
||||
if( output_frames_streams )
|
||||
{
|
||||
for(size_t s=0 ; s < fun.parameters.size() ; ++s)
|
||||
{
|
||||
std::wstring & name = fun.parameters[s]->name;
|
||||
|
||||
if( HasAskForSuchFrame(name) )
|
||||
{
|
||||
StreamType * stream = FindAddOutputStream(name);
|
||||
|
||||
if( stream )
|
||||
{
|
||||
CopyStream(ezc_out_tmp_stream, *stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::CreateMsg(const wchar_t * type, const wchar_t * arg)
|
||||
{
|
||||
@@ -2335,20 +2399,71 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::EvaluateP
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
bool Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::HasAskForSuchFrame(Item::Function & fun)
|
||||
{
|
||||
if( only_frames )
|
||||
{
|
||||
for(size_t s=0 ; s < fun.parameters.size() ; ++s)
|
||||
{
|
||||
std::wstring & name = fun.parameters[s]->name;
|
||||
|
||||
for(size_t f=0 ; f < only_frames->size() ; ++f)
|
||||
{
|
||||
const std::wstring & frame = (*only_frames)[f];
|
||||
|
||||
if( name == frame )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
bool Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::HasAskForSuchFrame(const std::wstring & name)
|
||||
{
|
||||
if( only_frames )
|
||||
{
|
||||
for(size_t f=0 ; f < only_frames->size() ; ++f)
|
||||
{
|
||||
const std::wstring & frame = (*only_frames)[f];
|
||||
|
||||
if( name == frame )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeItemText(Item & item)
|
||||
{
|
||||
const wchar_t * start = item.text.c_str();
|
||||
const wchar_t * end = item.text.c_str() + item.text.size();
|
||||
if( is_output_stream_allowed )
|
||||
{
|
||||
const wchar_t * start = item.text.c_str();
|
||||
const wchar_t * end = item.text.c_str() + item.text.size();
|
||||
|
||||
if( trim_white )
|
||||
TrimWhite(start, end);
|
||||
if( trim_white )
|
||||
TrimWhite(start, end);
|
||||
|
||||
if( special_chars )
|
||||
PrintSpecialText(start, end);
|
||||
else
|
||||
PrintNormalText(start, end);
|
||||
if( special_chars )
|
||||
PrintSpecialText(start, end);
|
||||
else
|
||||
PrintNormalText(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2374,7 +2489,7 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeTextF
|
||||
}
|
||||
else
|
||||
{
|
||||
if( output_stream )
|
||||
if( output_stream && is_output_stream_allowed )
|
||||
{
|
||||
Call(item.function, nullptr, *output_stream, false, empty_stream);
|
||||
}
|
||||
@@ -2660,7 +2775,7 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeTextF
|
||||
|
||||
is_generating_filter = true;
|
||||
|
||||
if( old_stream )
|
||||
if( old_stream && is_output_stream_allowed )
|
||||
{
|
||||
Call(item.function, nullptr, *old_stream, false, *output_stream);
|
||||
}
|
||||
@@ -2676,57 +2791,105 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeTextF
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
although we are using a stack for [etc frame] there is no need for the stack now
|
||||
because the output is only a one-level map (not nested structure)
|
||||
but in the future we can use more complicated class like pt::Space
|
||||
and then nested [ezc frame] statements can product a better output
|
||||
*/
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeEzcFrame(Item & item)
|
||||
StreamType * Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::GetNewStreamForFrame()
|
||||
{
|
||||
std::vector<std::wstring*> output_stream_names;
|
||||
StreamType * old_stream;
|
||||
bool stream_added = true;
|
||||
|
||||
if( ezc_frames_stack_index >= ezc_frame_stack_tab.size() )
|
||||
{
|
||||
CreateMsg(L"Generator exceeded allowed number of [ezc frame] statements");
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StreamType * stream = ezc_frame_stack_tab[ezc_frames_stack_index];
|
||||
ClearStream(*stream);
|
||||
ezc_frames_stack_index += 1;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::DecrementFramesStackIndex()
|
||||
{
|
||||
if( ezc_frames_stack_index > 0 )
|
||||
{
|
||||
ezc_frames_stack_index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeEzcFrame2(Item & item)
|
||||
{
|
||||
StreamType * old_stream = output_stream;
|
||||
bool old_is_output_stream_allowed = is_output_stream_allowed;
|
||||
bool put_directly_to_one_frame = false;
|
||||
bool is_current_frame_allowed = HasAskForSuchFrame(item.function);
|
||||
|
||||
if( !is_output_stream_allowed && is_current_frame_allowed )
|
||||
{
|
||||
is_output_stream_allowed = true;
|
||||
}
|
||||
|
||||
if( !old_is_output_stream_allowed && is_current_frame_allowed && item.function.parameters.size() == 1)
|
||||
{
|
||||
/*
|
||||
* some optimization, put directly to the frame stream
|
||||
*/
|
||||
put_directly_to_one_frame = true;
|
||||
output_stream = FindAddOutputStream(item.function.parameters[0]->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
output_stream = GetNewStreamForFrame();
|
||||
}
|
||||
|
||||
if( output_stream )
|
||||
{
|
||||
if( !item.item_tab.empty() )
|
||||
MakeText( *item.item_tab[0] ); // should be only one item - item_container
|
||||
|
||||
if( !put_directly_to_one_frame )
|
||||
{
|
||||
if( old_is_output_stream_allowed )
|
||||
{
|
||||
CopyStream(*output_stream, *old_stream);
|
||||
}
|
||||
|
||||
if( is_current_frame_allowed )
|
||||
{
|
||||
CopyTmpStreamToOutputStreams(item.function, *output_stream);
|
||||
}
|
||||
|
||||
ClearStream(*output_stream);
|
||||
DecrementFramesStackIndex();
|
||||
}
|
||||
}
|
||||
|
||||
is_output_stream_allowed = old_is_output_stream_allowed;
|
||||
output_stream = old_stream;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeEzcFrame(Item & item)
|
||||
{
|
||||
/*
|
||||
if we encounter the first ezc frame statement without arguments e.g. [ezc frame] or just [frame]
|
||||
then we can simply ignore it
|
||||
*/
|
||||
if( item.function.parameters.empty() && ezc_frames_stack_index == 0 )
|
||||
stream_added = false;
|
||||
|
||||
if( stream_added )
|
||||
{
|
||||
old_stream = output_stream;
|
||||
output_stream = ezc_frame_stack_tab[ezc_frames_stack_index];
|
||||
ClearStream(*output_stream);
|
||||
ezc_frames_stack_index += 1;
|
||||
if( !item.item_tab.empty() )
|
||||
MakeText( *item.item_tab[0] ); // should be only one item - item_container
|
||||
}
|
||||
|
||||
if( !item.item_tab.empty() )
|
||||
MakeText( *item.item_tab[0] ); // should be only one item - item_container
|
||||
|
||||
if( stream_added )
|
||||
else
|
||||
{
|
||||
CopyTmpStreamToOutputStreams(item.function, *output_stream, *old_stream);
|
||||
ClearStream(*output_stream);
|
||||
output_stream = old_stream;
|
||||
ezc_frames_stack_index -= 1;
|
||||
MakeEzcFrame2(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
|
||||
void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::MakeTextEzc(Item & item)
|
||||
{
|
||||
|
Reference in New Issue
Block a user