From 6def06c6477920fa03e8467439b1513cad3b06f6 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Sun, 7 Jul 2024 21:55:49 +0200 Subject: [PATCH] make some optimization when generating the output Add three methods to the Generator: - void OnlyFrames(const std::vector & frames); - void OnlyFrames(const std::vector * 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) --- src/Makefile.dep | 2 +- src/generator.h | 303 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 234 insertions(+), 71 deletions(-) diff --git a/src/Makefile.dep b/src/Makefile.dep index 4f8545b..18a8dcc 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -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 diff --git a/src/generator.h b/src/generator.h index 7f43c42..250f739 100644 --- a/src/generator.h +++ b/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 & frames); + void OnlyFrames(const std::vector * 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 * only_frames; + bool is_output_stream_allowed; + bool use_main_stream; + ExpressionParser * expression_parser; @@ -373,8 +386,8 @@ private: void DumpSpaceIfNeeded(std::vector & parameters, StreamType & out_stream, pt::Space * space); void DumpModelIfNeeded(morm::Model & model, std::vector & 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 & 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::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::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::SetExpres } +template +void Generator::OnlyFrames(const std::vector & frames) +{ + this->only_frames = &frames; +} + + +template +void Generator::OnlyFrames(const std::vector * frames) +{ + this->only_frames = frames; +} + + +template +void Generator::UseMainStream(bool use_main_stream) +{ + this->use_main_stream = use_main_stream; +} template @@ -909,6 +953,7 @@ void Generator::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 parameters; template bool Generator::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 -void Generator::CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream) +StreamType * Generator::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 +void Generator::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 void Generator::CreateMsg(const wchar_t * type, const wchar_t * arg) { @@ -2335,20 +2399,71 @@ void Generator::EvaluateP } +template +bool Generator::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 +bool Generator::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 void Generator::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::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::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::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 -void Generator::MakeEzcFrame(Item & item) +StreamType * Generator::GetNewStreamForFrame() { -std::vector 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 +void Generator::DecrementFramesStackIndex() +{ + if( ezc_frames_stack_index > 0 ) + { + ezc_frames_stack_index -= 1; + } +} + + +template +void Generator::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 +void Generator::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 void Generator::MakeTextEzc(Item & item) {