/* * This file is a part of PikoTools * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * 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 #include "space/space.h" #include "date/date.h" #include "convert/inttostr.h" #include "membuffer/membuffer.h" #include "types.h" // for snprintf #include 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 class TextStreamBase { public: TextStreamBase(); typedef CharT char_type; typedef MemBuffer 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 TextStreamBase & operator<<(const TextStreamBase & arg); template 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 TextStreamBase::TextStreamBase() { clear(); } template void TextStreamBase::clear() { radix = 10; min_width_for_integers = 0; buffer.clear(); } template bool TextStreamBase::empty() const { return buffer.empty(); } template size_t TextStreamBase::size() const { return buffer.size(); } template void TextStreamBase::reserve(size_t len) { buffer.reserve(len); } template size_t TextStreamBase::capacity() const { return buffer.capacity(); } template typename TextStreamBase::iterator TextStreamBase::begin() { return buffer.begin(); } template typename TextStreamBase::iterator TextStreamBase::end() { return buffer.end(); } template typename TextStreamBase::const_iterator TextStreamBase::begin() const { return buffer.begin(); } template typename TextStreamBase::const_iterator TextStreamBase::end() const { return buffer.end(); } template void TextStreamBase::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(*i); } template void TextStreamBase::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(*i); } template char_type & TextStreamBase::operator[](size_t index) { return buffer[index]; } template char_type TextStreamBase::operator[](size_t index) const { return buffer[index]; } template TextStreamBase & TextStreamBase::operator<<(const char * str) { for( ; *str ; ++str) buffer.append(static_cast(*str)); return *this; } template TextStreamBase & TextStreamBase::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 TextStreamBase & TextStreamBase::operator<<(const wchar_t * str) { for( ; *str ; ++str) buffer.append(static_cast(*str)); return *this; } template TextStreamBase & TextStreamBase::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 TextStreamBase & TextStreamBase::operator<<(char v) { buffer.append(static_cast(v)); return *this; } template TextStreamBase & TextStreamBase::operator<<(wchar_t v) { buffer.append(static_cast(v)); return *this; } template TextStreamBase & TextStreamBase::operator<<(int v) { return operator<<(static_cast(v)); } template TextStreamBase & TextStreamBase::operator<<(long v) { return operator<<(static_cast(v)); } template TextStreamBase & TextStreamBase::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 TextStreamBase & TextStreamBase::operator<<(unsigned int v) { return operator<<(static_cast(v)); } template TextStreamBase & TextStreamBase::operator<<(unsigned long v) { return operator<<(static_cast(v)); } template TextStreamBase & TextStreamBase::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 TextStreamBase & TextStreamBase::operator<<(double v) { char buf[100]; snprintf(buf, sizeof(buf)/sizeof(char), "%f", v); return operator<<(buf); } template TextStreamBase & TextStreamBase::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(v), buf+2, len-2, 16, &lenout) ) buffer.append(buf, lenout+2); return *this; } template template TextStreamBase & TextStreamBase::write(const in_buffer_type * buf, size_t len) { buffer.append(buf, len); return *this; } template TextStreamBase & TextStreamBase::write(const char * format, double val) { char buf[100]; snprintf(buf, sizeof(buf)/sizeof(char), format, val); return operator<<(buf); } template TextStreamBase & TextStreamBase::write(const wchar_t * format, double val) { wchar_t buf[100]; swprintf(buf, sizeof(buf)/sizeof(wchar_t), format, val); return operator<<(buf); } template TextStreamBase & TextStreamBase::operator<<(const Space & space) { space.serialize_to_space_stream(*this, true); return *this; } template TextStreamBase & TextStreamBase::operator<<(const Date & date) { date.Serialize(*this); return *this; } template template TextStreamBase & TextStreamBase::operator<<( const TextStreamBase & arg) { buffer.append(arg.buffer); return *this; } template TextStreamBase & TextStreamBase::int_min_width(size_t min_width) { min_width_for_integers = min_width; return *this; } template TextStreamBase & TextStreamBase::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