You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

535 lines
15 KiB

/*
* This file is a part of PikoTools
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2012-2021, 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_picotools_textstream_textstream
#define headerfile_picotools_textstream_textstream
#include <string>
#include "space/space.h"
#include "date/date.h"
#include "convert/inttostr.h"
#include "membuffer/membuffer.h"
#include "types.h"
// for snprintf
#include <cstdio>
namespace pt
{
/*
a special class representing a stream buffer
similar to std::ostringstream
StringType can be either std::string or std::wstring
this class doesn't use UTF-8 in any kind
*/
template<typename CharT, size_t stack_size, size_t heap_block_size>
class TextStreamBase
{
public:
TextStreamBase();
typedef CharT char_type;
typedef MemBuffer<char_type, stack_size, heap_block_size> buffer_type;
typedef typename buffer_type::iterator iterator;
typedef typename buffer_type::const_iterator const_iterator;
void clear();
bool empty() const;
size_t size() const;
void reserve(size_t len);
size_t capacity() const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
void to_string(std::string & str, bool clear_string = true) const;
void to_string(std::wstring & str, bool clear_string = true) const;
char_type & operator[](size_t index);
char_type operator[](size_t index) const;
TextStreamBase & operator<<(const char * str);
TextStreamBase & operator<<(const std::string & str);
TextStreamBase & operator<<(const wchar_t * str);
TextStreamBase & operator<<(const std::wstring * str);
TextStreamBase & operator<<(const std::wstring & str);
TextStreamBase & operator<<(char);
TextStreamBase & operator<<(wchar_t);
TextStreamBase & operator<<(int);
TextStreamBase & operator<<(long);
TextStreamBase & operator<<(long long);
TextStreamBase & operator<<(unsigned int);
TextStreamBase & operator<<(unsigned long);
TextStreamBase & operator<<(unsigned long long);
TextStreamBase & operator<<(double);
TextStreamBase & operator<<(const void *); // printing a pointer
TextStreamBase & operator<<(const Space & space);
TextStreamBase & operator<<(const Date & date);
// min width for integer output
// if the output value has less digits then first zeroes are added
// (0 turn off)
TextStreamBase & int_min_width(size_t min_width);
template<typename arg_char_type, size_t arg_stack_size, size_t arg_heap_block_size>
TextStreamBase & operator<<(const TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size> & arg);
template<typename in_buffer_type>
TextStreamBase & write(const in_buffer_type * buf, size_t len);
// write double value in a specified format
// format is the same as in the snprintf function, e.g. write("%f", 10.0)
TextStreamBase & write(const char * format, double val);
TextStreamBase & write(const wchar_t * format, double val);
TextStreamBase & fill_up_if_needed(wchar_t fill_up_char, size_t existing_length);
/*
raw access
*/
int radix;
size_t min_width_for_integers;
buffer_type buffer;
};
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::TextStreamBase()
{
clear();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
void TextStreamBase<char_type, stack_size, heap_block_size>::clear()
{
radix = 10;
min_width_for_integers = 0;
buffer.clear();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::empty() const
{
return buffer.empty();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
size_t TextStreamBase<char_type, stack_size, heap_block_size>::size() const
{
return buffer.size();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
void TextStreamBase<char_type, stack_size, heap_block_size>::reserve(size_t len)
{
buffer.reserve(len);
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
size_t TextStreamBase<char_type, stack_size, heap_block_size>::capacity() const
{
return buffer.capacity();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
typename TextStreamBase<char_type, stack_size, heap_block_size>::iterator
TextStreamBase<char_type, stack_size, heap_block_size>::begin()
{
return buffer.begin();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
typename TextStreamBase<char_type, stack_size, heap_block_size>::iterator
TextStreamBase<char_type, stack_size, heap_block_size>::end()
{
return buffer.end();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
typename TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator
TextStreamBase<char_type, stack_size, heap_block_size>::begin() const
{
return buffer.begin();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
typename TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator
TextStreamBase<char_type, stack_size, heap_block_size>::end() const
{
return buffer.end();
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
void TextStreamBase<char_type, stack_size, heap_block_size>::to_string(std::string & str, bool clear_string) const
{
if( clear_string )
str.clear();
if( str.capacity() < str.size() + size() )
str.reserve(str.size() + size());
const_iterator i = begin();
for( ; i != end() ; ++i)
str += static_cast<char>(*i);
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
void TextStreamBase<char_type, stack_size, heap_block_size>::to_string(std::wstring & str, bool clear_string) const
{
if( clear_string )
str.clear();
if( str.capacity() < str.size() + size() )
str.reserve(str.size() + size());
const_iterator i = begin();
for( ; i != end() ; ++i)
str += static_cast<wchar_t>(*i);
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
char_type & TextStreamBase<char_type, stack_size, heap_block_size>::operator[](size_t index)
{
return buffer[index];
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
char_type TextStreamBase<char_type, stack_size, heap_block_size>::operator[](size_t index) const
{
return buffer[index];
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(const char * str)
{
for( ; *str ; ++str)
buffer.append(static_cast<char_type>(*str));
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(const std::string & str)
{
if( sizeof(char_type) == sizeof(char) )
buffer.append(str.c_str(), str.size());
else
operator<<(str.c_str());
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(const wchar_t * str)
{
for( ; *str ; ++str)
buffer.append(static_cast<char_type>(*str));
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(const std::wstring & str)
{
if( sizeof(char_type) == sizeof(wchar_t) )
buffer.append(str.c_str(), str.size());
else
operator<<(str.c_str());
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(char v)
{
buffer.append(static_cast<char_type>(v));
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(wchar_t v)
{
buffer.append(static_cast<char_type>(v));
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(int v)
{
return operator<<(static_cast<long long>(v));
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(long v)
{
return operator<<(static_cast<long long>(v));
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(long long v)
{
char_type buf[50];
size_t len = sizeof(buf) / sizeof(char_type);
size_t lenout;
if( Toa(v, buf, len, radix, &lenout) )
{
fill_up_if_needed('0', lenout);
buffer.append(buf, lenout);
}
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(unsigned int v)
{
return operator<<(static_cast<unsigned long long>(v));
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(unsigned long v)
{
return operator<<(static_cast<unsigned long long>(v));
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(unsigned long long v)
{
char_type buf[50];
size_t len = sizeof(buf) / sizeof(char_type);
size_t lenout;
if( Toa(v, buf, len, radix, &lenout) )
{
fill_up_if_needed('0', lenout);
buffer.append(buf, lenout);
}
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(double v)
{
char buf[100];
snprintf(buf, sizeof(buf)/sizeof(char), "%f", v);
return operator<<(buf);
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(const void * v)
{
char_type buf[50];
size_t len = sizeof(buf) / sizeof(char_type);
size_t lenout;
buf[0] = '0';
buf[1] = 'x';
// IMPROVE ME add some minimal width?
if( Toa(reinterpret_cast<unsigned long long>(v), buf+2, len-2, 16, &lenout) )
buffer.append(buf, lenout+2);
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
template<typename in_buffer_type>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::write(const in_buffer_type * buf, size_t len)
{
buffer.append(buf, len);
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::write(const char * format, double val)
{
char buf[100];
snprintf(buf, sizeof(buf)/sizeof(char), format, val);
return operator<<(buf);
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::write(const wchar_t * format, double val)
{
wchar_t buf[100];
swprintf(buf, sizeof(buf)/sizeof(wchar_t), format, val);
return operator<<(buf);
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(const Space & space)
{
space.serialize_to_space_stream(*this, true);
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(const Date & date)
{
date.Serialize(*this);
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
template<typename arg_char_type, size_t arg_stack_size, size_t arg_heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::operator<<(
const TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size> & arg)
{
buffer.append(arg.buffer);
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::int_min_width(size_t min_width)
{
min_width_for_integers = min_width;
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::fill_up_if_needed(wchar_t fill_up_char, size_t existing_length)
{
if( min_width_for_integers > 0 && min_width_for_integers > existing_length )
{
for(size_t i = existing_length ; i < min_width_for_integers ; ++i)
{
buffer.append(fill_up_char);
}
}
return *this;
}
} // namespace
#endif