From 7b6f7ad32807ddde676389a75596c6f3ade9666c Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Thu, 12 Nov 2015 09:53:20 +0000 Subject: [PATCH] changed: [ezc streams "..."] to [ezc out "..."] or just [out "..."] the syntax has been changed, now [ezc ...] is used with [end] statement added: OutStreams class with a pool with output streams, the Generator::Generate() method can take it as its argument (Generator API has been changed) git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@1014 e52654a7-88a9-db11-a3e9-0013d4bc506e --- src/generator.h | 352 ++++++++++++++++++++++-------------------- src/outstreams.h | 171 ++++++++++++++++++++ src/patternparser.cpp | 24 ++- src/patternparser.h | 1 + 4 files changed, 378 insertions(+), 170 deletions(-) create mode 100644 src/outstreams.h diff --git a/src/generator.h b/src/generator.h index 5d36942..6944924 100644 --- a/src/generator.h +++ b/src/generator.h @@ -43,6 +43,7 @@ #include "pattern.h" #include "functions.h" #include "objects.h" +#include "outstreams.h" #include #include #include @@ -102,12 +103,6 @@ public: // default stack size: 300 void SetStackSize(size_t new_stack_size); - // do not print anything to stream stream_index - // useful when using Generate() method with StreamType tables - // this is a small optimization if we know that a stream with stream_index will not be used later - // set stream_index to -1 to turn off (default) - void SkipStream(int stream_index); - // set whether or not we can use cache for functions or blocks // true by default void CanUseCache(bool can_use_cache); @@ -117,9 +112,10 @@ public: void CanUseVars(bool can_use_variables); // the main methods for generating - void Generate(StreamType & o); - void Generate(std::vector & o); - void Generate(std::vector & o); + void Generate(StreamType & out); + void Generate(StreamType & out, OutStreams & out_streams); + void Generate(OutStreams & out_streams); + void SetCommentary(const char * com_start, const char * com_stop); void SetCommentary(const std::string & com_start, const std::string & com_stop); @@ -145,14 +141,8 @@ private: size_t block_stack_index; size_t block_stack_size; - // current output stream - // if we are printing only to one stream e.g. [ezc output "3"] - // then output_stream is pointing directly to that stream - // but if we are printing to more than one stream e.g. [ezc output "0" "2" "5"] - // then output_stream is pointing to output_tmp_stream and at the end - // output_tmp_stream is copied to the correct streams - // output_stream can be null e.g. [ezc output] without arguments - // in such a case we do not print anything (but any functions are evaluated) + // current output stream (can be null) + // at the beginning it is pointing to the main stream (to the StreamType argument passsed to Generate method) StreamType * output_stream; Pattern * ppattern; @@ -160,23 +150,9 @@ private: Functions * pfunctions; Objects * pobjects; - // output_tmp_stream is used when outputting to more than one stream - // (first we output to output_tmp_stream and then the content is copied - // to the correct streams) - StreamType output_tmp_stream; - - // pointers to the output streams - std::vector output_stream_tab; - - // indices to output_stream_tab - // they are set by [put stream ...] keyword - // at the beginning there is only one index created automatically - "0" - std::vector output_stream_index; - - // if has_skip_stream_index is true then when reading stream indices from [put stream ...] - // a stream with skip_stream_index index will be ignored - bool has_skip_stream_index; - size_t skip_stream_index; + // pointer to the output streams map (can be null) + // output stream will be created when [ezc out "stream_name"] statement is found + OutStreams * output_stream_map; // temporary error messages std::wstring temp_msg; @@ -189,6 +165,9 @@ private: bool trim_white; bool skip_new_line; + size_t ezc_out_stack_index; + size_t ezc_out_stack_size; + size_t stack_index; size_t stack_size; @@ -197,6 +176,7 @@ private: // we have to use a pointers table because standard streams such // as std::wostringstream are not copyable std::vector filter_tab; + std::vector ezc_out_stack_tab; const StreamType empty_stream; // used in [0] [1] [2] when there is no such argument defined @@ -230,13 +210,17 @@ private: bool can_use_vars; bool can_find_in_cache; + void ResizeStreamStack(std::vector & stream_tab, size_t stream_tab_max_size); void ResizeFilterTab(); void ResizeStack(); void ResizeBlockStack(); + void ResizeEzcOutStack(); + void ClearStreamStack(std::vector & stream_tab); void ClearFilterTab(); void ClearForStack(); void ClearBlockStack(); + void ClearEzcOutTab(); void ClearStream(StreamType & str); void RemoveStackFunData(Stack & sitem); @@ -312,8 +296,9 @@ private: size_t StrToSize(const wchar_t * str, const wchar_t ** str_end = 0); - void WriteTmpStreamToStreams(); + void CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream); void CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg = 0); + void CreateMsg(StreamType & stream, const wchar_t * type, const wchar_t * arg = 0); 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); @@ -331,8 +316,7 @@ private: void MakeTextEzc(Item & item); void MakeTextReturn(Item & item); void MakeText(Item & item); - - void MakeEzcStream(Item::Function & fun); + void MakeEzcOut(Item & item); void Generate(); @@ -348,7 +332,6 @@ private: template Generator::Generator() : empty_stream() { - output_stream = 0; ppattern = 0; pblocks = 0; pfunctions = 0; @@ -363,7 +346,7 @@ Generator::Generator() : empty_stream() is_generator_working = false; stack_size = 300; block_stack_size = 64; - has_skip_stream_index = false; + ezc_out_stack_size = 16; can_find_in_cache = true; can_use_vars = true; } @@ -380,12 +363,6 @@ Generator::Generator(const Generator & n) template Generator & Generator::operator=(const Generator & n) { - // !! CHECK ME may output_streams should not be copied? - output_stream_tab = n.output_stream_tab; - output_stream_index = n.output_stream_index; - output_tmp_stream = n.output_tmp_stream; - output_stream = n.output_stream; - ppattern = n.ppattern; pblocks = n.pblocks; pfunctions = n.pfunctions; @@ -396,7 +373,6 @@ Generator & Generator::operator=(const Generator & Generator::operator=(const Generator::~Generator() ClearFilterTab(); ClearForStack(); ClearBlockStack(); + ClearEzcOutTab(); } @@ -509,26 +489,6 @@ void Generator::CanUseVars(bool can_use_variables) -template -void Generator::ResizeFilterTab() -{ - if( filter_tab.size() != filter_size ) - { - if( filter_tab.size() < filter_size ) - { - for(size_t i=filter_tab.size() ; i void Generator::ResizeStack() @@ -546,6 +506,45 @@ void Generator::ResizeStack() } + +template +void Generator::ResizeStreamStack(std::vector & stream_tab, size_t stream_tab_max_size) +{ + if( stream_tab.size() != stream_tab_max_size ) + { + if( stream_tab.size() < stream_tab_max_size ) + { + size_t i = stream_tab.size(); + stream_tab.resize(stream_tab_max_size); + + for( ; i +void Generator::ResizeFilterTab() +{ + ResizeStreamStack(filter_tab, filter_size); +} + + +template +void Generator::ResizeEzcOutStack() +{ + ResizeStreamStack(ezc_out_stack_tab, ezc_out_stack_size); +} + + template void Generator::ResizeBlockStack() { @@ -570,13 +569,30 @@ void Generator::ResizeBlockStack() } + + + +template +void Generator::ClearStreamStack(std::vector & stream_tab) +{ + for(size_t i=0 ; i void Generator::ClearFilterTab() { - for(size_t i=0 ; i +void Generator::ClearEzcOutTab() +{ + ClearStreamStack(ezc_out_stack_tab); } @@ -620,22 +636,6 @@ void Generator::RemoveStackFunData(Stack & s) } -template -void Generator::SkipStream(int stream_index) -{ - if( stream_index < 0 ) - { - has_skip_stream_index = false; - } - else - { - has_skip_stream_index = true; - skip_stream_index = stream_index; - } -} - - - template template CharType Generator::ToLower(CharType c) @@ -712,19 +712,6 @@ void Generator::Generate() return; } - output_stream = 0; - output_stream_index.clear(); - ClearStream(output_tmp_stream); - - if( !output_stream_tab.empty() ) - { - if( !has_skip_stream_index || skip_stream_index != 0 ) - { - output_stream_index.push_back(0); - output_stream = output_stream_tab[0]; - } - } - break_generating = false; current_item = 0; @@ -736,6 +723,7 @@ void Generator::Generate() ResizeFilterTab(); ResizeStack(); ResizeBlockStack(); + ResizeEzcOutStack(); filter_index = 0; stack_index = 0; block_stack_index = 0; @@ -747,10 +735,8 @@ void Generator::Generate() { is_generator_working = true; MakeText( ppattern->item_root ); - - if( output_stream_index.size() > 1 ) - WriteTmpStreamToStreams(); - + // !! IMPROVE ME we can print an error message if the stacks are not empty + // (some [end] statements has been omited) vars.clear(); is_generator_working = false; } @@ -764,36 +750,29 @@ void Generator::Generate() template -void Generator::Generate(StreamType & o) +void Generator::Generate(StreamType & out) { - output_stream_tab.resize(1); - output_stream_tab[0] = &o; - + output_stream = &out; + output_stream_map = 0; Generate(); } template -void Generator::Generate(std::vector & o) +void Generator::Generate(StreamType & out, OutStreams & out_streams) { - output_stream_tab.resize(o.size()); - - for(size_t i=0 ; i -void Generator::Generate(std::vector & o) +void Generator::Generate(OutStreams & out_streams) { - output_stream_tab.resize(o.size()); - - for(size_t i=0 ; i -void Generator::WriteTmpStreamToStreams() +void Generator::CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream) { - #ifdef EZC_HAS_SPECIAL_STREAM - const std::wstring & str = output_tmp_stream.Str(); - #else - const std::wstring & str = output_tmp_stream.str(); - #endif - - - if( !str.empty() ) + if( output_stream_map ) { - for(size_t s = 0 ; s < output_stream_index.size() ; ++s) + #ifdef EZC_HAS_SPECIAL_STREAM + const std::wstring & str = ezc_out_tmp_stream.Str(); + #else + const std::wstring & str = ezc_out_tmp_stream.str(); + #endif + + if( !str.empty() ) { - size_t i = output_stream_index[s]; + previous_stream.write(str.c_str(), str.size()); - if( i < output_stream_tab.size() ) - output_stream_tab[i]->write(str.c_str(), str.size()); + for(size_t s=0 ; s < fun.parameters.size() ; ++s) + { + std::wstring & name = fun.parameters[s]->name; + std::pair::StreamsMap::iterator, bool> iterator_inserted = output_stream_map->streams_map.insert(std::make_pair(name, (StreamType*)0)); + + StreamType * & stream = iterator_inserted.first->second; + bool inserted = iterator_inserted.second; + + if( inserted ) + { + if( output_stream_map->streams_map.size() <= output_stream_map->streams_tab.size() ) + { + /* a new stream from the pool (output_stream_tab) has been taken */ + stream = output_stream_map->streams_tab[ output_stream_map->streams_map.size() - 1 ]; + ClearStream(*stream); + stream->write(str.c_str(), str.size()); + } + else + { + CreateMsg(previous_stream, L"limit of output streams has been reached"); + } + } + else + { + stream->write(str.c_str(), str.size()); + } + } } - - ClearStream(output_tmp_stream); } } @@ -1374,15 +1375,20 @@ void Generator::CreateMsg(std::wstring & out, const wchar_t * type, } +template +void Generator::CreateMsg(StreamType & stream, const wchar_t * type, const wchar_t * arg) +{ + CreateMsg(temp_msg, type, arg); + stream.write(temp_msg.c_str(), temp_msg.size()); + temp_msg.clear(); +} + template void Generator::CreateMsg(const wchar_t * type, const wchar_t * arg) { if( output_stream ) - { - CreateMsg(temp_msg, type, arg); - output_stream->write(temp_msg.c_str(), temp_msg.size()); - } + CreateMsg(*output_stream, type, arg); } @@ -1598,53 +1604,61 @@ void Generator::MakeTextFilter(Item & item) + + +/* + although we are using a stack for [etc out] 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 out] statements can product a better output +*/ template -void Generator::MakeEzcStream(Item::Function & fun) +void Generator::MakeEzcOut(Item & item) { - if( output_stream_index.size() > 1 ) - WriteTmpStreamToStreams(); +std::vector output_stream_names; +StreamType * old_stream; +bool stream_added = true; - output_stream_index.clear(); - - for(size_t i=0 ; i= ezc_out_stack_tab.size() ) { - size_t index = StrToSize(fun.parameters[i]->name.c_str()); - - if( index < output_stream_tab.size() ) - { - if( !has_skip_stream_index || skip_stream_index != index ) - output_stream_index.push_back(index); - } - - // we do not print any information if the index is out of range - // because we do not know to which stream is should be printed + CreateMsg(L"Generator exceeded allowed number of [ezc out] statements"); + return; } - if( output_stream_index.size() > 1 ) + /* + if we encounter the first ezc_out statement without arguments e.g. [ezc out] or just [out] + then we can simply ignore it + */ + if( item.function.parameters.empty() && ezc_out_stack_index == 0 ) + stream_added = false; + + if( stream_added ) { - ClearStream(output_tmp_stream); - output_stream = &output_tmp_stream; + old_stream = output_stream; + output_stream = ezc_out_stack_tab[ezc_out_stack_index]; + ClearStream(*output_stream); + ezc_out_stack_index += 1; } - else - if( output_stream_index.size() == 1 ) + + if( !item.item_tab.empty() ) + MakeText( *item.item_tab[0] ); // should be only one item - item_container + + if( stream_added ) { - size_t index = output_stream_index[0]; - output_stream = output_stream_tab[index]; - } - else - { - output_stream = 0; + CopyTmpStreamToOutputStreams(item.function, *output_stream, *old_stream); + ClearStream(*output_stream); + output_stream = old_stream; + ezc_out_stack_index -= 1; } } + template void Generator::MakeTextEzc(Item & item) { - if( item.function.name == L"stream" ) - MakeEzcStream(item.function); - else - CreateMsg(L"incorrect argument to [ezc] statement"); + if( item.function.name == L"out" ) + MakeEzcOut(item); // in the future we can use more builtin functions } diff --git a/src/outstreams.h b/src/outstreams.h new file mode 100644 index 0000000..8b1aa63 --- /dev/null +++ b/src/outstreams.h @@ -0,0 +1,171 @@ +/* + * This file is a part of EZC -- Easy templating in C++ library + * and is distributed under the BSD 3-Clause licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2015, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef headerfile_ezc_outstreams +#define headerfile_ezc_outstreams + +#include +#include +#include + + +namespace Ezc +{ + + +template +class OutStreams +{ +public: + + typedef std::map StreamsMap; // can have null pointers + typedef std::vector StreamsTab; + + StreamsMap streams_map; + StreamsTab streams_tab; + + void ResizeTab(size_t len); + + void ClearMap(); + void ClearTab(); + + ~OutStreams(); + OutStreams(); + OutStreams(const OutStreams & o); + OutStreams & operator=(const OutStreams & o); + + +}; + + +template +OutStreams::~OutStreams() +{ + ClearTab(); +} + +template +OutStreams::OutStreams() +{ +} + + + +template +OutStreams::OutStreams(const OutStreams & o) +{ + // we do not copy streams but creating new ones + ResizeTab(o.streams_tab.size()); +} + + +template +OutStreams & OutStreams::operator=(const OutStreams & o) +{ + // we do not copy streams but creating new ones + streams_map.clear(); + ResizeTab(o.streams_tab.size()); + +return *this; +} + + +template +void OutStreams::ClearTab() +{ + for(size_t i=0 ; i +void OutStreams::ResizeTab(size_t len) +{ + if( streams_tab.size() != len ) + { + if( streams_tab.size() < len ) + { + size_t i = streams_tab.size(); + streams_tab.resize(len); + + for( ; i +void OutStreams::ClearMap() +{ + StreamsMap::iterator i; + + for(i=streams_map.begin() ; i != streams_map.end() ; ++i) + { + StreamType & str = *(i->second); + + #ifdef EZC_HAS_SPECIAL_STREAM + str.Clear(); + #else + str.str(L""); + #endif + + } + + streams_map.clear(); +} + + + + + + +} // namespace + +#endif diff --git a/src/patternparser.cpp b/src/patternparser.cpp index c77c998..3dfd788 100644 --- a/src/patternparser.cpp +++ b/src/patternparser.cpp @@ -791,6 +791,26 @@ void PatternParser::ReadDirectiveEzc(Item & item) } +/* + [out] is a shorthand for [ezc out] +*/ +void PatternParser::ReadDirectiveOut(Item & item) +{ + item.type = Item::item_ezc; + item.has_function = true; + + item.function.Clear(); + item.function.name = L"out"; + item.function.is_function = true; + + if( !ReadParams(item.function) ) + { + item.type = Item::item_err; + item.function.Clear(); + } +} + + void PatternParser::ReadDirectiveBlock(Item & item) { item.type = Item::item_block; @@ -827,6 +847,7 @@ std::wstring name; else if( name == L"def" ) ReadDirectiveDef(item); else if( name == L"filter" ) ReadDirectiveFilter(item); else if( name == L"ezc" ) ReadDirectiveEzc(item); + else if( name == L"out" ) ReadDirectiveOut(item); else if( name == L"block" ) ReadDirectiveBlock(item); else if( name == L"return" ) ReadDirectiveReturn(item); else if( name == L"#" ) ReadDirectiveComment(item); @@ -990,7 +1011,8 @@ void PatternParser::CreateTree(Item & item) CreateTreeReadIf(*pitem); if( pitem->type == Item::item_for || - pitem->type == Item::item_filter ) + pitem->type == Item::item_filter || + pitem->type == Item::item_ezc ) CreateTreeReadFor(*pitem); if( pitem->type == Item::item_include ) diff --git a/src/patternparser.h b/src/patternparser.h index 901831c..d6a08eb 100644 --- a/src/patternparser.h +++ b/src/patternparser.h @@ -172,6 +172,7 @@ private: void ReadDirectiveDef(Item & item); void ReadDirectiveFilter(Item & item); void ReadDirectiveEzc(Item & item); + void ReadDirectiveOut(Item & item); void ReadDirectiveBlock(Item & item); void ReadDirectiveReturn(Item & item); void ReadDirectiveNormal(const std::wstring & name, Item & item);