pikotools/src/textstream/textstream.h

1320 lines
35 KiB
C++

/*
* This file is a part of PikoTools
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2012-2023, 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:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 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 HOLDER 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_pikotools_src_textstream_textstream
#define headerfile_pikotools_src_textstream_textstream
#include <string>
#include "stream.h"
#include "space/space.h"
#include "date/date.h"
#include "convert/inttostr.h"
#include "membuffer/membuffer.h"
#include "types.h"
#include "utf8/utf8.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
*/
template<typename CharT, size_t stack_size, size_t heap_block_size>
class TextStreamBase : public Stream
{
public:
TextStreamBase();
typedef CharT char_type;
typedef MemBuffer<char_type, stack_size, heap_block_size> buffer_type;
class iterator
{
public:
typename buffer_type::iterator membuffer_iterator;
iterator();
iterator(const iterator & i);
iterator & operator=(const iterator & i);
iterator(const typename buffer_type::iterator & i);
iterator & operator=(const typename buffer_type::iterator & i);
bool operator==(const iterator & i) const;
bool operator!=(const iterator & i) const;
iterator & operator++(); // prefix ++
iterator operator++(int); // postfix ++
iterator & operator--(); // prefix --
iterator operator--(int); // postfix --
CharT & operator*();
wchar_t get_unicode_and_advance(const iterator & end);
};
class const_iterator
{
public:
typename buffer_type::const_iterator membuffer_const_iterator;
const_iterator();
const_iterator(const const_iterator & i);
const_iterator(const iterator & i);
const_iterator & operator=(const const_iterator & i);
const_iterator & operator=(const iterator & i);
const_iterator(const typename buffer_type::const_iterator & i);
const_iterator(const typename buffer_type::iterator & i);
const_iterator & operator=(const typename buffer_type::const_iterator & i);
const_iterator & operator=(const typename buffer_type::iterator & i);
bool operator==(const const_iterator & i) const;
bool operator!=(const const_iterator & i) const;
const_iterator & operator++(); // prefix ++
const_iterator operator++(int); // postfix ++
const_iterator & operator--(); // prefix --
const_iterator operator--(int); // postfix --
CharT operator*();
wchar_t get_unicode_and_advance(const const_iterator & end);
};
bool is_char_stream() const;
bool is_wchar_stream() const;
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;
// IMPROVE ME
// add cbegin(), cend(), rbegin(), rend(), crbegin(), crend()
void to_str(std::string & str, bool clear_string = true) const;
void to_str(std::wstring & str, bool clear_string = true) const;
std::string to_str() const;
std::wstring to_wstr() const;
/*
* returns true if the buffer was sufficient large and there were no convertion errors
*/
bool to_str(char * str, size_t max_buf_len) const;
bool to_str(wchar_t * str, size_t max_buf_len) const;
char get_char(size_t index) const;
wchar_t get_wchar(size_t index) 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<<(char);
TextStreamBase & operator<<(unsigned char);
TextStreamBase & operator<<(wchar_t); // no surrogate pairs are used
TextStreamBase & operator<<(bool);
TextStreamBase & operator<<(short);
TextStreamBase & operator<<(int);
TextStreamBase & operator<<(long);
TextStreamBase & operator<<(long long);
TextStreamBase & operator<<(unsigned short);
TextStreamBase & operator<<(unsigned int);
TextStreamBase & operator<<(unsigned long);
TextStreamBase & operator<<(unsigned long long);
TextStreamBase & operator<<(float);
TextStreamBase & operator<<(double);
TextStreamBase & operator<<(long double);
TextStreamBase & operator<<(const void *); // printing a pointer
TextStreamBase & operator<<(const Stream & stream);
TextStreamBase & operator<<(const Space & space);
TextStreamBase & operator<<(const Date & date);
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 arg_char_type, size_t arg_stack_size, size_t arg_heap_block_size>
bool operator==(const TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size> & stream) const;
template<typename arg_char_type, size_t arg_stack_size, size_t arg_heap_block_size>
bool operator!=(const TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size> & stream) const;
// 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);
TextStreamBase & write(const char * buf, size_t len);
TextStreamBase & write(const wchar_t * buf, size_t len);
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;
protected:
template<typename char_type_to, size_t stack_size_to, size_t heap_block_size_to>
void put_stream(const TextStreamBase<char_type_to, stack_size_to, heap_block_size_to> & stream);
void put_stream(const Stream & stream);
};
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>
TextStreamBase<char_type, stack_size, heap_block_size>::iterator::iterator()
{
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::iterator::iterator(const iterator & i) : membuffer_iterator(i)
{
}
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>::iterator::operator=(const iterator & i)
{
membuffer_iterator = i;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::iterator::iterator(const typename buffer_type::iterator & i) : membuffer_iterator(i)
{
}
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>::iterator::operator=(const typename buffer_type::iterator & i)
{
membuffer_iterator = i;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::iterator::operator==(const iterator & i) const
{
return membuffer_iterator == i.membuffer_iterator;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::iterator::operator!=(const iterator & i) const
{
return membuffer_iterator != i.membuffer_iterator;
}
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>::iterator::operator++()
{
++membuffer_iterator;
return *this;
}
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>::iterator::operator++(int)
{
const_iterator old(*this);
membuffer_iterator++;
return old;
}
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>::iterator::operator--()
{
--membuffer_iterator;
return *this;
}
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>::iterator::operator--(int)
{
const_iterator old(*this);
membuffer_iterator--;
return old;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
char_type & TextStreamBase<char_type, stack_size, heap_block_size>::iterator::operator*()
{
return *membuffer_iterator;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
wchar_t TextStreamBase<char_type, stack_size, heap_block_size>::iterator::get_unicode_and_advance(const iterator & end)
{
if( *this != end )
{
if constexpr (sizeof(char_type) == sizeof(char) )
{
int res;
bool correct;
utf8_to_int(*this, end, res, correct);
if( correct )
return static_cast<wchar_t>(res);
else
return static_cast<wchar_t>(0xFFFD); // U+FFFD "replacement character"
}
else
{
wchar_t c = operator*();
++membuffer_iterator;
return c;
}
}
return 0;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::const_iterator()
{
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::const_iterator(const const_iterator & i) : membuffer_const_iterator(i.membuffer_const_iterator)
{
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::const_iterator(const iterator & i) : membuffer_const_iterator(i.membuffer_iterator)
{
}
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>::const_iterator::operator=(const const_iterator & i)
{
membuffer_const_iterator = i.membuffer_const_iterator;
return *this;
}
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>::const_iterator::operator=(const iterator & i)
{
membuffer_const_iterator = i.membuffer_iterator;
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::const_iterator(const typename buffer_type::const_iterator & i) : membuffer_const_iterator(i)
{
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::const_iterator(const typename buffer_type::iterator & i) : membuffer_const_iterator(i)
{
}
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>::const_iterator::operator=(const typename buffer_type::const_iterator & i)
{
membuffer_const_iterator = i;
return *this;
}
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>::const_iterator::operator=(const typename buffer_type::iterator & i)
{
membuffer_const_iterator = i;
return *this;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::operator==(const const_iterator & i) const
{
return membuffer_const_iterator == i.membuffer_const_iterator;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::operator!=(const const_iterator & i) const
{
return membuffer_const_iterator != i.membuffer_const_iterator;
}
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>::const_iterator::operator++()
{
++membuffer_const_iterator;
return *this;
}
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>::const_iterator::operator++(int)
{
const_iterator old(*this);
membuffer_const_iterator++;
return old;
}
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>::const_iterator::operator--()
{
--membuffer_const_iterator;
return *this;
}
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>::const_iterator::operator--(int)
{
const_iterator old(*this);
membuffer_const_iterator--;
return old;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
char_type TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::operator*()
{
return *membuffer_const_iterator;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
wchar_t TextStreamBase<char_type, stack_size, heap_block_size>::const_iterator::get_unicode_and_advance(const const_iterator & end)
{
if( *this != end )
{
if constexpr (sizeof(char_type) == sizeof(char) )
{
int res;
bool correct;
pt::utf8_to_int(*this, end, res, correct);
if( correct )
return static_cast<wchar_t>(res);
else
return static_cast<wchar_t>(0xFFFD); // U+FFFD "replacement character"
}
else
{
wchar_t c = operator*();
++membuffer_const_iterator;
return c;
}
}
return 0;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::is_char_stream() const
{
if constexpr (sizeof(char_type) == sizeof(char) )
{
return true;
}
return false;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::is_wchar_stream() const
{
if constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
return true;
}
return false;
}
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_str(std::string & str, bool clear_string) const
{
if( clear_string )
str.clear();
if( str.capacity() < str.size() + size() )
str.reserve(str.size() + size());
if constexpr (sizeof(char_type) == sizeof(char) )
{
const_iterator i = begin();
const_iterator i_end = end();
for( ; i != i_end ; ++i)
str += *i;
}
else
{
wide_stream_to_utf8(*this, str);
}
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
void TextStreamBase<char_type, stack_size, heap_block_size>::to_str(std::wstring & str, bool clear_string) const
{
if( clear_string )
str.clear();
if( str.capacity() < str.size() + size() )
str.reserve(str.size() + size());
if constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
const_iterator i = begin();
for( ; i != end() ; ++i)
str += *i;
}
else
{
utf8_to_wide(*this, str, false);
}
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
std::string TextStreamBase<char_type, stack_size, heap_block_size>::to_str() const
{
std::string str;
to_str(str, false);
return str;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
std::wstring TextStreamBase<char_type, stack_size, heap_block_size>::to_wstr() const
{
std::wstring str;
to_str(str, false);
return str;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::to_str(char * str, size_t max_buf_len) const
{
bool converted_correctly = false;
if( max_buf_len > 0 )
{
if constexpr (sizeof(char_type) == sizeof(char) )
{
converted_correctly = true;
const_iterator i = begin();
const_iterator i_end = end();
size_t len = 0;
max_buf_len -= 1; // for terminating null character
for( ; i != i_end ; ++i, ++len)
{
if( len < max_buf_len )
{
str[len] = *i;
}
else
{
converted_correctly = false;
break;
}
}
str[len] = 0;
}
else
{
converted_correctly = wide_stream_to_utf8(*this, str, max_buf_len);
}
}
return converted_correctly;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
bool TextStreamBase<char_type, stack_size, heap_block_size>::to_str(wchar_t * str, size_t max_buf_len) const
{
bool converted_correctly = false;
if( max_buf_len > 0 )
{
if constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
converted_correctly = true;
const_iterator i = begin();
const_iterator i_end = end();
size_t len = 0;
max_buf_len -= 1; // for terminating null character
for( ; i != i_end ; ++i, ++len)
{
if( len < max_buf_len )
{
str[len] = *i;
}
else
{
converted_correctly = false;
break;
}
}
str[len] = 0;
}
else
{
converted_correctly = utf8_to_wide(*this, str, max_buf_len);
}
}
return converted_correctly;
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
char TextStreamBase<char_type, stack_size, heap_block_size>::get_char(size_t index) const
{
return static_cast<char>(buffer[index]);
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
wchar_t TextStreamBase<char_type, stack_size, heap_block_size>::get_wchar(size_t index) const
{
return static_cast<wchar_t>(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)
{
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)
{
if constexpr ( sizeof(char_type) == sizeof(char) )
{
for( ; *str ; ++str)
buffer.append(*str);
}
else
{
utf8_to_wide(str, *this, false);
}
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 constexpr ( sizeof(char_type) == sizeof(char) )
{
buffer.append(str.c_str(), str.size());
}
else
{
utf8_to_wide(str, *this, false);
}
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)
{
if constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
for( ; *str ; ++str)
buffer.append(*str);
}
else
{
wide_to_utf8(str, *this, false);
}
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 constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
buffer.append(str.c_str(), str.size());
}
else
{
wide_to_utf8(str, *this, false);
}
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)
{
if constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
buffer.append(static_cast<char_type>(static_cast<unsigned char>(v)));
}
else
{
buffer.append(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<<(unsigned 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)
{
if constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
buffer.append(v);
}
else
{
pt::int_to_utf8(static_cast<int>(v), *this);
}
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<<(bool v)
{
char c = v ? '1' : '0';
buffer.append(static_cast<char_type>(c));
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<<(short 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<<(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 short 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 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<<(float v)
{
return operator<<(static_cast<double>(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<<(double v)
{
char buf[100];
snprintf(buf, sizeof(buf)/sizeof(char), "%g", 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<<(long double v)
{
char buf[100];
snprintf(buf, sizeof(buf)/sizeof(char), "%Lg", 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>
TextStreamBase<char_type, stack_size, heap_block_size> &
TextStreamBase<char_type, stack_size, heap_block_size>::write(const char * str, size_t len)
{
if constexpr ( sizeof(char_type) == sizeof(char) )
{
for(size_t i=0 ; i < len ; ++i)
buffer.append(str[i]);
}
else
{
utf8_to_wide(str, *this, false);
}
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 wchar_t * str, size_t len)
{
if constexpr (sizeof(char_type) == sizeof(wchar_t) )
{
for(size_t i=0 ; i < len ; ++i)
buffer.append(str[i]);
}
else
{
wide_to_utf8(str, *this);
}
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 Stream & stream)
{
put_stream(stream);
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>
void TextStreamBase<char_type, stack_size, heap_block_size>::put_stream(
const TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size> & stream
)
{
if( (sizeof(char_type) == sizeof(char) && stream.is_char_stream()) ||
(sizeof(char_type) == sizeof(wchar_t) && stream.is_wchar_stream()) )
{
// from utf8 to utf8 or from wide to wide
typename TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size>::const_iterator i = stream.begin();
for( ; i != stream.end() ; ++i)
{
operator<<(*i);
}
}
else
if( sizeof(char_type) == sizeof(wchar_t) && stream.is_char_stream() )
{
// from utf8 to wide
utf8_to_wide(stream, *this, false);
}
else
if( sizeof(char_type) == sizeof(char) && stream.is_wchar_stream() )
{
// from wide to utf8
wide_stream_to_utf8(stream, *this, false);
}
else
{
operator<<("such conversion is not implemented");
}
}
template<typename char_type, size_t stack_size, size_t heap_block_size>
void TextStreamBase<char_type, stack_size, heap_block_size>::put_stream(const Stream & stream)
{
if( sizeof(char_type) == sizeof(char) && stream.is_char_stream() )
{
// from utf8 to utf8
for(size_t i=0 ; i < stream.size() ; ++i)
{
char c = stream.get_char(i);
operator<<(c);
}
}
else
if( sizeof(char_type) == sizeof(wchar_t) && stream.is_char_stream() )
{
// from utf8 to wide
utf8_to_wide(stream, *this, false);
}
else
if( sizeof(char_type) == sizeof(char) && stream.is_wchar_stream() )
{
// from wide to utf8
wide_stream_to_utf8(stream, *this, false);
}
else
if( sizeof(char_type) == sizeof(wchar_t) && stream.is_wchar_stream() )
{
// from wide to wide
for(size_t i=0 ; i < stream.size() ; ++i)
{
wchar_t c = stream.get_wchar(i);
operator<<(c);
}
}
else
{
operator<<("such conversion is not implemented");
}
}
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_json_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)
{
put_stream(arg);
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>
bool TextStreamBase<char_type, stack_size, heap_block_size>::operator==(const TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size> & stream) const
{
bool are_the_same = false;
/*
* at the moment we do not make any conversions for == and != operators
* this may change in the future
*/
if( sizeof(char_type) == sizeof(arg_char_type) && size() == stream.size() )
{
are_the_same = true;
const_iterator i1 = begin();
const_iterator i2 = stream.begin();
const_iterator i1_end = end();
while( i1 != i1_end )
{
if( *i1 != *i2 )
{
are_the_same = false;
break;
}
++i1;
++i2;
}
}
return are_the_same;
}
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>
bool TextStreamBase<char_type, stack_size, heap_block_size>::operator!=(const TextStreamBase<arg_char_type, arg_stack_size, arg_heap_block_size> & stream) const
{
return !operator==(stream);
}
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;
}
/*!
this function converts an UTF-8 stream into wide stream or wide string
(is declared in utf8/utf8.h)
input:
iterator_in - an TextStream iterator for reading from
iterator_end - an end iterator (can be returned by end() method from TextStream)
output:
out_stream - an output wide stream or wide string
this function returns false if there were some errors when converting
*/
template<size_t stack_size, size_t heap_block_size, typename StreamOrStringType>
bool utf8_to_wide(
const TextStreamBase<char, stack_size, heap_block_size> & utf8,
StreamOrStringType & out_stream,
bool clear_stream,
int mode
)
{
typename TextStreamBase<char, stack_size, heap_block_size>::const_iterator i_begin = utf8.begin();
return utf8_to_wide(i_begin, utf8.end(), out_stream, clear_stream, mode);
}
} // namespace
#endif