changed: [ezc streams "..."] to [ezc out "..."] or just [out "..."]

the syntax has been changed, now [ezc ...] is used with [end] statement
added: OutStreams<StreamType> 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
This commit is contained in:
Tomasz Sowa 2015-11-12 09:53:20 +00:00
parent 76490d4c19
commit 7b6f7ad328
4 changed files with 378 additions and 170 deletions

View File

@ -43,6 +43,7 @@
#include "pattern.h"
#include "functions.h"
#include "objects.h"
#include "outstreams.h"
#include <sstream>
#include <fstream>
#include <vector>
@ -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<StreamType> & o);
void Generate(std::vector<StreamType*> & o);
void Generate(StreamType & out);
void Generate(StreamType & out, OutStreams<StreamType> & out_streams);
void Generate(OutStreams<StreamType> & 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<StreamType> * pfunctions;
Objects<StreamType> * 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<StreamType*> 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<size_t> 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<StreamType> * 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<StreamType*> filter_tab;
std::vector<StreamType*> 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<StreamType*> & stream_tab, size_t stream_tab_max_size);
void ResizeFilterTab();
void ResizeStack();
void ResizeBlockStack();
void ResizeEzcOutStack();
void ClearStreamStack(std::vector<StreamType*> & 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<class StreamType>
Generator<StreamType>::Generator() : empty_stream()
{
output_stream = 0;
ppattern = 0;
pblocks = 0;
pfunctions = 0;
@ -363,7 +346,7 @@ Generator<StreamType>::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<StreamType>::Generator(const Generator<StreamType> & n)
template<class StreamType>
Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamType> & 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<StreamType> & Generator<StreamType>::operator=(const Generator<StreamT
special_chars = n.special_chars;
trim_white = n.trim_white;
skip_new_line = n.skip_new_line;
has_skip_stream_index = n.has_skip_stream_index;
can_find_in_cache = n.can_find_in_cache;
can_use_vars = n.can_use_vars;
@ -404,11 +380,14 @@ Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamT
filter_size = n.filter_size;
stack_size = n.stack_size;
block_stack_size = n.block_stack_size;
ezc_out_stack_size = n.ezc_out_stack_size;
// vars doesn't have to be copied
// don't copy filter tab
// don't copy stack
// don't copy ezc_out_stack_tab
// don't copy output_stream and output_stream_map
// !! CHECK ME
// may copying should be denied when generator is working?
@ -426,6 +405,7 @@ Generator<StreamType>::~Generator()
ClearFilterTab();
ClearForStack();
ClearBlockStack();
ClearEzcOutTab();
}
@ -509,26 +489,6 @@ void Generator<StreamType>::CanUseVars(bool can_use_variables)
template<class StreamType>
void Generator<StreamType>::ResizeFilterTab()
{
if( filter_tab.size() != filter_size )
{
if( filter_tab.size() < filter_size )
{
for(size_t i=filter_tab.size() ; i<filter_size ; ++i)
filter_tab.push_back( new StreamType() );
}
else
{
for(size_t i=filter_size ; i<filter_tab.size() ; ++i)
delete filter_tab[i];
filter_tab.resize(filter_size);
}
}
}
template<class StreamType>
void Generator<StreamType>::ResizeStack()
@ -546,6 +506,45 @@ void Generator<StreamType>::ResizeStack()
}
template<class StreamType>
void Generator<StreamType>::ResizeStreamStack(std::vector<StreamType*> & 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<stream_tab.size() ; ++i)
stream_tab[i] = new StreamType();
}
else
{
for(size_t i=stream_tab_max_size ; i<stream_tab.size() ; ++i)
delete stream_tab[i];
stream_tab.resize(stream_tab_max_size);
}
}
}
template<class StreamType>
void Generator<StreamType>::ResizeFilterTab()
{
ResizeStreamStack(filter_tab, filter_size);
}
template<class StreamType>
void Generator<StreamType>::ResizeEzcOutStack()
{
ResizeStreamStack(ezc_out_stack_tab, ezc_out_stack_size);
}
template<class StreamType>
void Generator<StreamType>::ResizeBlockStack()
{
@ -570,13 +569,30 @@ void Generator<StreamType>::ResizeBlockStack()
}
template<class StreamType>
void Generator<StreamType>::ClearStreamStack(std::vector<StreamType*> & stream_tab)
{
for(size_t i=0 ; i<stream_tab.size() ; ++i)
delete stream_tab[i];
stream_tab.clear();
}
template<class StreamType>
void Generator<StreamType>::ClearFilterTab()
{
for(size_t i=0 ; i<filter_tab.size() ; ++i)
delete filter_tab[i];
filter_tab.clear();
ClearStreamStack(filter_tab);
}
template<class StreamType>
void Generator<StreamType>::ClearEzcOutTab()
{
ClearStreamStack(ezc_out_stack_tab);
}
@ -620,22 +636,6 @@ void Generator<StreamType>::RemoveStackFunData(Stack & s)
}
template<class StreamType>
void Generator<StreamType>::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<class StreamType>
template<class CharType>
CharType Generator<StreamType>::ToLower(CharType c)
@ -712,19 +712,6 @@ void Generator<StreamType>::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<StreamType>::Generate()
ResizeFilterTab();
ResizeStack();
ResizeBlockStack();
ResizeEzcOutStack();
filter_index = 0;
stack_index = 0;
block_stack_index = 0;
@ -747,10 +735,8 @@ void Generator<StreamType>::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<StreamType>::Generate()
template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o)
void Generator<StreamType>::Generate(StreamType & out)
{
output_stream_tab.resize(1);
output_stream_tab[0] = &o;
output_stream = &out;
output_stream_map = 0;
Generate();
}
template<class StreamType>
void Generator<StreamType>::Generate(std::vector<StreamType> & o)
void Generator<StreamType>::Generate(StreamType & out, OutStreams<StreamType> & out_streams)
{
output_stream_tab.resize(o.size());
for(size_t i=0 ; i<o.size() ; ++i)
output_stream_tab[i] = &o[i];
output_stream = &out;
output_stream_map = &out_streams;
Generate();
}
template<class StreamType>
void Generator<StreamType>::Generate(std::vector<StreamType*> & o)
void Generator<StreamType>::Generate(OutStreams<StreamType> & out_streams)
{
output_stream_tab.resize(o.size());
for(size_t i=0 ; i<o.size() ; ++i)
output_stream_tab[i] = o[i];
output_stream = 0;
output_stream_map = &out_streams;
Generate();
}
@ -1332,26 +1311,48 @@ return res;
template<class StreamType>
void Generator<StreamType>::WriteTmpStreamToStreams()
void Generator<StreamType>::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<OutStreams<StreamType>::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<StreamType>::CreateMsg(std::wstring & out, const wchar_t * type,
}
template<class StreamType>
void Generator<StreamType>::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<class StreamType>
void Generator<StreamType>::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<StreamType>::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<class StreamType>
void Generator<StreamType>::MakeEzcStream(Item::Function & fun)
void Generator<StreamType>::MakeEzcOut(Item & item)
{
if( output_stream_index.size() > 1 )
WriteTmpStreamToStreams();
std::vector<std::wstring*> output_stream_names;
StreamType * old_stream;
bool stream_added = true;
output_stream_index.clear();
for(size_t i=0 ; i<fun.parameters.size() ; ++i)
if( ezc_out_stack_index >= 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<class StreamType>
void Generator<StreamType>::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
}

171
src/outstreams.h Normal file
View File

@ -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 <t.sowa@ttmath.org>
*/
/*
* 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 <string>
#include <vector>
#include <map>
namespace Ezc
{
template<class StreamType>
class OutStreams
{
public:
typedef std::map<std::wstring, StreamType*> StreamsMap; // can have null pointers
typedef std::vector<StreamType*> StreamsTab;
StreamsMap streams_map;
StreamsTab streams_tab;
void ResizeTab(size_t len);
void ClearMap();
void ClearTab();
~OutStreams();
OutStreams();
OutStreams(const OutStreams<StreamType> & o);
OutStreams<StreamType> & operator=(const OutStreams<StreamType> & o);
};
template<class StreamType>
OutStreams<StreamType>::~OutStreams()
{
ClearTab();
}
template<class StreamType>
OutStreams<StreamType>::OutStreams()
{
}
template<class StreamType>
OutStreams<StreamType>::OutStreams(const OutStreams<StreamType> & o)
{
// we do not copy streams but creating new ones
ResizeTab(o.streams_tab.size());
}
template<class StreamType>
OutStreams<StreamType> & OutStreams<StreamType>::operator=(const OutStreams<StreamType> & o)
{
// we do not copy streams but creating new ones
streams_map.clear();
ResizeTab(o.streams_tab.size());
return *this;
}
template<class StreamType>
void OutStreams<StreamType>::ClearTab()
{
for(size_t i=0 ; i<streams_tab.size() ; ++i)
delete streams_tab[i];
streams_tab.clear();
streams_map.clear();
}
template<class StreamType>
void OutStreams<StreamType>::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<streams_tab.size() ; ++i)
streams_tab[i] = new StreamType();
}
else
{
streams_map.clear();
for(size_t i=len ; i<streams_tab.size() ; ++i)
delete streams_tab[i];
streams_tab.resize(len);
}
}
}
template<class StreamType>
void OutStreams<StreamType>::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

View File

@ -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 )

View File

@ -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);