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:
2024-07-07 21:55:49 +02:00
parent d6ca791fbc
commit 6def06c647
2 changed files with 234 additions and 71 deletions

View File

@@ -19,6 +19,7 @@
./patternparser.o: ../../pikotools/src/textstream/stream.h
./patternparser.o: ../../pikotools/src/space/space.h
./patternparser.o: ../../pikotools/src/convert/inttostr.h
./patternparser.o: ../../pikotools/src/convert/misc.h
./patternparser.o: ../../pikotools/src/date/date.h
./patternparser.o: ../../pikotools/src/membuffer/membuffer.h
./patternparser.o: ../../pikotools/src/textstream/types.h
@@ -30,6 +31,5 @@
./patternparser.o: ../../pikotools/src/convert/strtoint.h
./patternparser.o: ../../pikotools/src/convert/text.h
./patternparser.o: ../../pikotools/src/convert/misc.h
./patternparser.o: ../../pikotools/src/textstream/types.h
./patternparser.o: ../../pikotools/src/convert/double.h
./models.o: models.h

View File

@@ -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;
}
@@ -490,6 +512,9 @@ Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::operator=(cons
ezc_frames_stack_size = n.ezc_frames_stack_size;
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,15 +2223,12 @@ 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);
for(size_t s=0 ; s < fun.parameters.size() ; ++s)
{
std::wstring & name = fun.parameters[s]->name;
auto imap = output_frames_streams->streams_map.find(name);
if( imap == output_frames_streams->streams_map.end() )
@@ -2192,10 +2236,9 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::CopyTmpSt
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() ];
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
{
@@ -2204,14 +2247,35 @@ void Generator<StreamType, is_pikotools_stream, is_autoescape_stream>::CopyTmpSt
}
else
{
StreamType * stream = imap->second;
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>
@@ -2335,9 +2399,59 @@ 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)
{
if( is_output_stream_allowed )
{
const wchar_t * start = item.text.c_str();
const wchar_t * end = item.text.c_str() + item.text.size();
@@ -2350,6 +2464,7 @@ const wchar_t * end = item.text.c_str() + item.text.size();
else
PrintNormalText(start, end);
}
}
template<class StreamType, bool is_pikotools_stream, bool is_autoescape_stream>
@@ -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( 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)
{