From 4d9f5f6c55a45d3709ed65ce5ae7e10a95660ef3 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Thu, 24 Jun 2021 20:52:48 +0200 Subject: [PATCH] Log class has the Stream class as a base class now - implemented some missing operators<<(...) - removed Manipulators: l1, l2, l3, l4, lend, lsave - PascalCase to snake_case in Log added to Stream: virtual bool is_char_stream() const = 0; virtual bool is_wchar_stream() const = 0; virtual char get_char(size_t index) const = 0; virtual wchar_t get_wchar(size_t index) const = 0; virtual Stream & operator<<(const Stream & stream) = 0; --- src/Makefile.dep | 35 +-- src/log/log.cpp | 419 +++++++++++++++++++++++++++--------- src/log/log.h | 146 +++++++------ src/textstream/stream.h | 68 ++++-- src/textstream/textstream.h | 229 +++++++++++++++----- src/utf8/utf8.cpp | 40 ++++ src/utf8/utf8.h | 10 + src/utf8/utf8_private.h | 17 -- src/utf8/utf8_templates.h | 22 +- 9 files changed, 706 insertions(+), 280 deletions(-) diff --git a/src/Makefile.dep b/src/Makefile.dep index 74cf0df..683e3cf 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -5,35 +5,40 @@ ./convert/text.o: ./convert/text.h ./convert/text_private.h ./convert/double.o: ./convert/double.h textstream/textstream.h ./convert/double.o: textstream/stream.h space/space.h textstream/types.h -./convert/double.o: convert/inttostr.h utf8/utf8.h utf8/utf8_templates.h -./convert/double.o: utf8/utf8_private.h date/date.h membuffer/membuffer.h -./convert/double.o: textstream/types.h +./convert/double.o: convert/inttostr.h utf8/utf8.h textstream/stream.h +./convert/double.o: utf8/utf8_templates.h utf8/utf8_private.h date/date.h +./convert/double.o: membuffer/membuffer.h textstream/types.h ./date/date.o: ./date/date.h convert/inttostr.h ./log/filelog.o: ./log/filelog.h textstream/textstream.h textstream/stream.h ./log/filelog.o: space/space.h textstream/types.h convert/inttostr.h -./log/filelog.o: utf8/utf8.h utf8/utf8_templates.h utf8/utf8_private.h -./log/filelog.o: date/date.h membuffer/membuffer.h textstream/types.h +./log/filelog.o: utf8/utf8.h textstream/stream.h utf8/utf8_templates.h +./log/filelog.o: utf8/utf8_private.h date/date.h membuffer/membuffer.h +./log/filelog.o: textstream/types.h ./log/log.o: ./log/log.h textstream/textstream.h textstream/stream.h ./log/log.o: space/space.h textstream/types.h convert/inttostr.h utf8/utf8.h -./log/log.o: utf8/utf8_templates.h utf8/utf8_private.h date/date.h -./log/log.o: membuffer/membuffer.h textstream/types.h ./log/filelog.h +./log/log.o: textstream/stream.h utf8/utf8_templates.h utf8/utf8_private.h +./log/log.o: date/date.h membuffer/membuffer.h textstream/types.h +./log/log.o: ./log/filelog.h ./space/space.o: ./space/space.h textstream/types.h convert/inttostr.h -./space/space.o: utf8/utf8.h utf8/utf8_templates.h utf8/utf8_private.h -./space/space.o: convert/convert.h ./convert/inttostr.h +./space/space.o: utf8/utf8.h textstream/stream.h utf8/utf8_templates.h +./space/space.o: utf8/utf8_private.h convert/convert.h ./convert/inttostr.h ./space/space.o: convert/patternreplacer.h textstream/textstream.h ./space/space.o: textstream/stream.h space/space.h date/date.h ./space/space.o: membuffer/membuffer.h textstream/types.h convert/strtoint.h ./space/space.o: ./convert/text.h ./convert/misc.h ./convert/double.h ./space/spaceparser.o: ./space/spaceparser.h ./space/space.h ./space/spaceparser.o: textstream/types.h convert/inttostr.h utf8/utf8.h -./space/spaceparser.o: utf8/utf8_templates.h utf8/utf8_private.h -./space/spaceparser.o: convert/strtoint.h ./convert/text.h ./convert/misc.h -./utf8/utf8.o: ./utf8/utf8.h utf8/utf8_templates.h utf8/utf8_private.h +./space/spaceparser.o: textstream/stream.h utf8/utf8_templates.h +./space/spaceparser.o: utf8/utf8_private.h convert/strtoint.h +./space/spaceparser.o: ./convert/text.h ./convert/misc.h +./utf8/utf8.o: ./utf8/utf8.h textstream/stream.h utf8/utf8_templates.h +./utf8/utf8.o: utf8/utf8_private.h ./utf8/utf8_private.o: utf8/utf8_private.h ./csv/csvparser.o: ./csv/csvparser.h space/space.h textstream/types.h -./csv/csvparser.o: convert/inttostr.h utf8/utf8.h utf8/utf8_templates.h -./csv/csvparser.o: utf8/utf8_private.h +./csv/csvparser.o: convert/inttostr.h utf8/utf8.h textstream/stream.h +./csv/csvparser.o: utf8/utf8_templates.h utf8/utf8_private.h ./mainoptions/mainoptionsparser.o: ./mainoptions/mainoptionsparser.h ./mainoptions/mainoptionsparser.o: space/space.h textstream/types.h ./mainoptions/mainoptionsparser.o: convert/inttostr.h utf8/utf8.h -./mainoptions/mainoptionsparser.o: utf8/utf8_templates.h utf8/utf8_private.h +./mainoptions/mainoptionsparser.o: textstream/stream.h utf8/utf8_templates.h +./mainoptions/mainoptionsparser.o: utf8/utf8_private.h diff --git a/src/log/log.cpp b/src/log/log.cpp index 9283c8f..921061b 100644 --- a/src/log/log.cpp +++ b/src/log/log.cpp @@ -54,9 +54,8 @@ Log::Log() { buffer = nullptr; file_log = nullptr; - current_level = 4; - max_buffer_length = 2 * 1024 * 1024; // 2MB + max_buffer_length = 2 * 1024 * 1024; } @@ -65,70 +64,146 @@ Log::~Log() } -void Log::SetLogBuffer(WTextStream * buffer) +bool Log::can_put_log() { - this->buffer = buffer; + return (buffer && file_log && current_level <= file_log->get_log_level()); } -WTextStream * Log::GetLogBuffer() +bool Log::is_char_stream() const { - return buffer; + return false; } -void Log::SetMaxBufferLength(size_t max_buffer_length) +bool Log::is_wchar_stream() const { - this->max_buffer_length = max_buffer_length; + return true; } -size_t Log::GetMaxBufferLength() -{ - return max_buffer_length; -} - -void Log::SetFileLog(FileLog * file_log) -{ - this->file_log = file_log; -} - - -FileLog * Log::GetFileLog() -{ - return file_log; -} - - -Log & Log::IntMinWidth(size_t min_width) +void Log::clear() { if( buffer ) { - buffer->int_min_width(min_width); + buffer->clear(); } - - return *this; } -Log & Log::operator<<(const void * s) +bool Log::empty() const { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( buffer ) { - (*buffer) << s; + return buffer->empty(); } - return *this; + return true; +} + + +size_t Log::size() const +{ + if( buffer ) + { + buffer->size(); + } + + return 0; +} + + +void Log::reserve(size_t len) +{ + if( buffer ) + { + buffer->reserve(len); + } +} + + +size_t Log::capacity() const +{ + if( buffer ) + { + buffer->capacity(); + } + + return 0; +} + + + +void Log::to_str(std::string & str, bool clear_string) const +{ + if( buffer ) + { + buffer->to_str(str, clear_string); + } +} + + +void Log::to_str(std::wstring & str, bool clear_string) const +{ + if( buffer ) + { + buffer->to_str(str, clear_string); + } +} + + + +std::string Log::to_str() const +{ + if( buffer ) + { + return buffer->to_str(); + } + + return std::string(); +} + + +std::wstring Log::to_wstr() const +{ + if( buffer ) + { + return buffer->to_wstr(); + } + + return std::wstring(); +} + + +char Log::get_char(size_t index) const +{ + if( buffer ) + { + return buffer->get_char(index); + } + + return 0; +} + + +wchar_t Log::get_wchar(size_t index) const +{ + if( buffer ) + { + return buffer->get_wchar(index); + } + + return 0; } Log & Log::operator<<(const char * s) { - if( buffer && file_log && s && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - utf8_to_wide(s, *buffer, false); + (*buffer) << s; } return *this; @@ -138,34 +213,18 @@ Log & Log::operator<<(const char * s) Log & Log::operator<<(const std::string & s) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - utf8_to_wide(s, *buffer, false); + (*buffer) << s; } return *this; } - -Log & Log::operator<<(const std::string * s) -{ - if( buffer && file_log && current_level <= file_log->get_log_level() ) - { - utf8_to_wide(*s, *buffer, false); - } - - return *this; -} - - - - - - Log & Log::operator<<(const wchar_t * s) { - if( buffer && file_log && s && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { (*buffer) << s; } @@ -174,10 +233,9 @@ Log & Log::operator<<(const wchar_t * s) } - Log & Log::operator<<(const std::wstring & s) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { (*buffer) << s; } @@ -186,89 +244,151 @@ Log & Log::operator<<(const std::wstring & s) } - -Log & Log::operator<<(const std::wstring * s) +Log & Log::operator<<(char val) { - if( buffer && file_log && s && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - (*buffer) << *s; + (*buffer) << val; } return *this; } +Log & Log::operator<<(unsigned char val) +{ + if( can_put_log() ) + { + (*buffer) << val; + } + + return *this; +} - -Log & Log::operator<<(int s) +Log & Log::operator<<(wchar_t val) { if( buffer && file_log && current_level <= file_log->get_log_level() ) { - (*buffer) << s; + (*buffer) << val; } return *this; } - -Log & Log::operator<<(long s) +Log & Log::operator<<(bool val) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - (*buffer) << s; + (*buffer) << val; } - return *this; + return *this; } -Log & Log::operator<<(long long s) +Log & Log::operator<<(short val) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - (*buffer) << s; + (*buffer) << val; } - return *this; + return *this; } -Log & Log::operator<<(char s) +Log & Log::operator<<(int val) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - (*buffer) << s; + (*buffer) << val; } return *this; } -Log & Log::operator<<(wchar_t s) + +Log & Log::operator<<(long val) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - (*buffer) << s; + (*buffer) << val; } return *this; } -Log & Log::operator<<(size_t s) +Log & Log::operator<<(long long val) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { - (*buffer) << s; + (*buffer) << val; } return *this; } +Log & Log::operator<<(unsigned short val) +{ + if( can_put_log() ) + { + (*buffer) << val; + } + + return *this; +} + + +Log & Log::operator<<(unsigned int val) +{ + if( can_put_log() ) + { + (*buffer) << val; + } + + return *this; +} + + +Log & Log::operator<<(unsigned long val) +{ + if( can_put_log() ) + { + (*buffer) << val; + } + + return *this; +} + + +Log & Log::operator<<(unsigned long long val) +{ + if( can_put_log() ) + { + (*buffer) << val; + } + + return *this; +} + + + +Log & Log::operator<<(float val) +{ + if( can_put_log() ) + { + (*buffer) << val; + } + + return *this; +} + Log & Log::operator<<(double s) { @@ -281,10 +401,20 @@ Log & Log::operator<<(double s) } - -Log & Log::operator<<(const Space & s) +Log & Log::operator<<(long double val) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) + { + (*buffer) << val; + } + + return *this; +} + + +Log & Log::operator<<(const void * s) +{ + if( can_put_log() ) { (*buffer) << s; } @@ -293,10 +423,31 @@ Log & Log::operator<<(const Space & s) } +Log & Log::operator<<(const Stream & stream) +{ + if( can_put_log() ) + { + (*buffer) << stream; + } + + return *this; +} + + +Log & Log::operator<<(const Space & s) +{ + if( can_put_log() ) + { + (*buffer) << s; + } + + return *this; +} + Log & Log::operator<<(const Date & date) { - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { (*buffer) << date; } @@ -314,13 +465,35 @@ Log & Log::operator<<(morm::Model & model) #endif + +Log & Log::write(const char * buf, size_t len) +{ + if( can_put_log() ) + { + buffer->write(buf, len); + } + + return *this; +} + + +Log & Log::write(const wchar_t * buf, size_t len) +{ + if( can_put_log() ) + { + buffer->write(buf, len); + } + + return *this; +} + + Log & Log::operator<<(Manipulators m) { switch(m) { - case lend: case logend: - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { (*buffer) << '\n'; @@ -329,27 +502,22 @@ Log & Log::operator<<(Manipulators m) } break; - case lsave: case logsave: save_log_and_clear(); break; - case l1: case log1: current_level = 1; break; - case l2: case log2: current_level = 2; break; - case l3: case log3: current_level = 3; break; - case l4: case log4: current_level = 4; break; @@ -362,20 +530,65 @@ Log & Log::operator<<(Manipulators m) } -Log & Log::LogString(const std::string & value, size_t max_size) +void Log::set_log_buffer(WTextStream * buffer) +{ + this->buffer = buffer; +} + + +WTextStream * Log::get_log_buffer() +{ + return buffer; +} + + +void Log::set_max_buffer_length(size_t max_buffer_length) +{ + this->max_buffer_length = max_buffer_length; +} + + +size_t Log::get_max_buffer_length() +{ + return max_buffer_length; +} + + +void Log::set_file_log(FileLog * file_log) +{ + this->file_log = file_log; +} + + +FileLog * Log::get_file_log() +{ + return file_log; +} + + +Log & Log::int_min_width(size_t min_width) +{ + if( buffer ) + { + buffer->int_min_width(min_width); + } + + return *this; +} + + +Log & Log::put_string(const std::string & value, size_t max_size) { return log_string_generic(value, max_size); } -Log & Log::LogString(const std::wstring & value, size_t max_size) +Log & Log::put_string(const std::wstring & value, size_t max_size) { return log_string_generic(value, max_size); } - - char Log::get_hex_digit(unsigned char c) { if( c < 10 ) @@ -385,7 +598,6 @@ return c - 10 + 'A'; } - void Log::to_hex(char * buf, unsigned char c) { buf[0] = get_hex_digit(c >> 4); @@ -394,12 +606,12 @@ void Log::to_hex(char * buf, unsigned char c) } -Log & Log::LogBinary(const char * blob, size_t blob_len) +Log & Log::put_binary_blob(const char * blob, size_t blob_len) { size_t i=0; char buf[3]; - if( buffer && file_log && blob && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { while( i < blob_len ) { @@ -446,13 +658,12 @@ char buf[3]; } -Log & Log::LogBinary(const std::string & blob) +Log & Log::put_binary_blob(const std::string & blob) { - return LogBinary(blob.c_str(), blob.size()); + return put_binary_blob(blob.c_str(), blob.size()); } - void Log::save_log_and_clear() { save_log(); @@ -475,7 +686,3 @@ void Log::save_log() } // namespace - - - - diff --git a/src/log/log.h b/src/log/log.h index 94d9125..9a19875 100644 --- a/src/log/log.h +++ b/src/log/log.h @@ -45,22 +45,16 @@ -namespace morm -{ - class Model; -} + namespace pt { - -class Log +class Log : public Stream { public: - - /* log1 - the first level log2 @@ -76,81 +70,91 @@ public: log3, log4, - l1, - l2, - l3, - l4, - logend, - lend, - logsave, - lsave, }; - Log(); - virtual ~Log(); + ~Log(); - virtual void SetLogBuffer(WTextStream * buffer); - virtual WTextStream * GetLogBuffer(); + bool is_char_stream() const; + bool is_wchar_stream() const; - void SetFileLog(FileLog * file_log); - FileLog * GetFileLog(); + void clear(); + bool empty() const; + size_t size() const; + void reserve(size_t len); + size_t capacity() const; - void SetMaxBufferLength(size_t max_buffer_length); - size_t GetMaxBufferLength(); + void to_str(std::string & str, bool clear_string = true) const; + void to_str(std::wstring & str, bool clear_string = true) const; - virtual Log & IntMinWidth(size_t min_width); + std::string to_str() const; + std::wstring to_wstr() const; - virtual Log & operator<<(const void * s); + char get_char(size_t index) const; + wchar_t get_wchar(size_t index) const; - virtual Log & operator<<(const char * s); - virtual Log & operator<<(const std::string * s); - virtual Log & operator<<(const std::string & s); + Log & operator<<(const char * s); + Log & operator<<(const std::string & s); + Log & operator<<(const wchar_t * s); + Log & operator<<(const std::wstring & s); - virtual Log & operator<<(const wchar_t * s); - virtual Log & operator<<(const std::wstring * s); - virtual Log & operator<<(const std::wstring & s); + Log & operator<<(char val); + Log & operator<<(unsigned char val); + Log & operator<<(wchar_t val); + Log & operator<<(bool val); + Log & operator<<(short val); + Log & operator<<(int s); + Log & operator<<(long s); + Log & operator<<(long long s); + Log & operator<<(unsigned short val); + Log & operator<<(unsigned int val); + Log & operator<<(unsigned long val); + Log & operator<<(unsigned long long val); + Log & operator<<(float val); + Log & operator<<(double s); + Log & operator<<(long double val); + Log & operator<<(const void * s); - virtual Log & operator<<(char s); - virtual Log & operator<<(wchar_t s); - - virtual Log & operator<<(int s); - virtual Log & operator<<(long s); - virtual Log & operator<<(long long s); - - - // add unsigned long, unsigned int - virtual Log & operator<<(size_t s); - - //virtual Log & operator<<(float s); // added - virtual Log & operator<<(double s); - - virtual Log & operator<<(const Space & space); - virtual Log & operator<<(const Date & date); + Log & operator<<(const Stream & stream); + Log & operator<<(const Space & space); + Log & operator<<(const Date & date); #ifdef PT_HAS_MORM_LIBRARY virtual Log & operator<<(morm::Model & model); #endif + template + Log & operator<<(const TextStreamBase & arg); + + Log & write(const char * buf, size_t len); + Log & write(const wchar_t * buf, size_t len); + + + /* + * methods specific to Log class + * + */ virtual Log & operator<<(Manipulators m); + virtual void set_log_buffer(WTextStream * buffer); + virtual WTextStream * get_log_buffer(); + void set_file_log(FileLog * file_log); + FileLog * get_file_log(); + void set_max_buffer_length(size_t max_buffer_length); + size_t get_max_buffer_length(); - virtual Log & LogString(const std::string & value, size_t max_size); - virtual Log & LogString(const std::wstring & value, size_t max_size); + virtual Log & int_min_width(size_t min_width); + virtual Log & put_string(const std::string & value, size_t max_size); + virtual Log & put_string(const std::wstring & value, size_t max_size); - template - Log & operator<<(const TextStreamBase & buf); - - - - virtual Log & LogBinary(const char * blob, size_t blob_len); - virtual Log & LogBinary(const std::string & blob); + virtual Log & put_binary_blob(const char * blob, size_t blob_len); + virtual Log & put_binary_blob(const std::string & blob); @@ -176,6 +180,7 @@ protected: template Log & log_string_generic(const StringType & value, size_t max_size); + virtual bool can_put_log(); virtual void save_log(); virtual void save_log_and_clear(); @@ -183,12 +188,24 @@ protected: +template +Log & Log::operator<<(const TextStreamBase & arg) +{ + if( can_put_log() ) + { + (*buffer) << arg; + } + + return *this; +} + + template Log & Log::log_string_generic(const StringType & value, size_t max_size) { std::size_t min_size = value.size() < max_size ? value.size() : max_size; - if( buffer && file_log && current_level <= file_log->get_log_level() ) + if( can_put_log() ) { for(size_t i=0 ; i < min_size ; ++i) { @@ -204,19 +221,6 @@ Log & Log::log_string_generic(const StringType & value, size_t max_size) -template -Log & Log::operator<<(const TextStreamBase & buf) -{ - if( buffer && file_log && current_level <= file_log->get_log_level() ) - { - (*buffer) << buf; - } - -return *this; -} - - - } // namespace diff --git a/src/textstream/stream.h b/src/textstream/stream.h index e0fe797..cb3e83b 100644 --- a/src/textstream/stream.h +++ b/src/textstream/stream.h @@ -41,6 +41,15 @@ #include +#ifdef PT_HAS_MORM_LIBRARY +namespace morm +{ + class Model; +} +#endif + + + namespace pt { class Space; @@ -55,6 +64,9 @@ public: virtual ~Stream() {}; + virtual bool is_char_stream() const = 0; + virtual bool is_wchar_stream() const = 0; + virtual void clear() = 0; virtual bool empty() const = 0; virtual size_t size() const = 0; @@ -67,12 +79,35 @@ public: virtual std::string to_str() const = 0; virtual std::wstring to_wstr() const = 0; + virtual char get_char(size_t index) const = 0; + virtual wchar_t get_wchar(size_t index) const = 0; + virtual Stream & operator<<(const char * str) = 0; virtual Stream & operator<<(const std::string & str) = 0; - virtual Stream & operator<<(const wchar_t * str) = 0; virtual Stream & operator<<(const std::wstring & str) = 0; + /* + * IMPROVEME + * https://en.cppreference.com/w/cpp/string + * add support for: + * char8_t + * char16_t + * char32_t + * const char8_t * + * const char16_t * + * const char32_t * + * std::u8string + * std::u16string + * std::u32string + * std::string_view + * std::wstring_view + * std::u8string_view + * std::u16string_view + * std::u32string_view + * + */ + virtual Stream & operator<<(char) = 0; virtual Stream & operator<<(unsigned char) = 0; virtual Stream & operator<<(wchar_t) = 0; @@ -89,30 +124,21 @@ public: virtual Stream & operator<<(double) = 0; virtual Stream & operator<<(long double) = 0; virtual Stream & operator<<(const void *) = 0; // printing a pointer + + virtual Stream & operator<<(const Stream & stream) = 0; virtual Stream & operator<<(const Space & space) = 0; virtual Stream & operator<<(const Date & date) = 0; - virtual char get_char(size_t index) const = 0; - virtual wchar_t get_wchar(size_t index) const = 0; +#ifdef PT_HAS_MORM_LIBRARY + /* + * this Stream base class can be used by other consumers so creating this operator + * as a pure virtual would be inconvinient for them if they do not use morm library + */ + virtual Stream & operator<<(morm::Model & model) { operator<<("serializing morm::Model objects not available"); return *this; }; +#endif - // min width for integer output - // if the output value has less digits then first zeroes are added - // (0 turn off) - //Stream & int_min_width(size_t min_width); - -// template -// Stream & operator<<(const Stream & arg); - -// template -// Stream & 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) - //virtual Stream & write(const char * format, double val) = 0; - //virtual Stream & write(const wchar_t * format, double val) = 0; - - // what is it? - //Stream & fill_up_if_needed(wchar_t fill_up_char, size_t existing_length); + virtual Stream & write(const char * buf, size_t len) = 0; + virtual Stream & write(const wchar_t * buf, size_t len) = 0; }; diff --git a/src/textstream/textstream.h b/src/textstream/textstream.h index bb1fb90..352e3e5 100644 --- a/src/textstream/textstream.h +++ b/src/textstream/textstream.h @@ -75,6 +75,9 @@ public: typedef typename buffer_type::const_iterator const_iterator; + bool is_char_stream() const; + bool is_wchar_stream() const; + void clear(); bool empty() const; size_t size() const; @@ -96,12 +99,14 @@ public: std::string to_str() const; std::wstring to_wstr() 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); @@ -121,11 +126,14 @@ public: 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); - char get_char(size_t index) const; - wchar_t get_wchar(size_t index) const; + template + TextStreamBase & operator<<(const TextStreamBase & arg); + // min width for integer output @@ -133,17 +141,9 @@ public: // (0 turn off) TextStreamBase & int_min_width(size_t min_width); - template - TextStreamBase & operator<<(const TextStreamBase & arg); - TextStreamBase & write(const char * buf, size_t len); TextStreamBase & write(const wchar_t * 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); /* @@ -152,6 +152,15 @@ public: int radix; size_t min_width_for_integers; buffer_type buffer; + + +protected: + + void put_stream(const Stream & stream); + void put_utf8_to_wide(const Stream & stream); + void put_wide_to_utf8(const Stream & stream); + + }; @@ -166,6 +175,32 @@ TextStreamBase::TextStreamBase() } +template +bool TextStreamBase::is_char_stream() const +{ + if constexpr (sizeof(char_type) == sizeof(char) ) + { + return true; + } + + return false; +} + +template +bool TextStreamBase::is_wchar_stream() const +{ + if constexpr (sizeof(char_type) == sizeof(wchar_t) ) + { + return true; + } + + return false; +} + + + + + template void TextStreamBase::clear() { @@ -302,6 +337,18 @@ std::wstring TextStreamBase::to_wstr() c } +template +char TextStreamBase::get_char(size_t index) const +{ + return static_cast(buffer[index]); +} + + +template +wchar_t TextStreamBase::get_wchar(size_t index) const +{ + return static_cast(buffer[index]); +} @@ -595,26 +642,119 @@ 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 Stream & stream) +{ + put_stream(stream); + return *this; +} + + +template +void TextStreamBase::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 + put_utf8_to_wide(stream); + } + else + if( sizeof(char_type) == sizeof(char) && stream.is_wchar_stream() ) + { + // from wide to utf8 + put_wide_to_utf8(stream); + } + 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"); + } +} + + +// test me when sizeof(wchar_t) is 2 +// or may move me to utf8 functions? +template +void TextStreamBase::put_utf8_to_wide(const Stream & stream) +{ + size_t len; + bool correct; + size_t index = 0; + int z; + + do + { + len = utf8_to_int(stream, index, z, correct); + + if( len > 0 ) + { + if( !correct ) + { + z = 0xFFFD; // U+FFFD "replacement character" + } + + int_to_wide(z, *this); + index += len; + } + } + while( len > 0 ); +} + + +// test me when sizeof(wchar_t) is 2 +// or may move me to utf8 functions? +template +void TextStreamBase::put_wide_to_utf8(const Stream & stream) +{ + char utf8_buf[10]; + size_t utf8_buf_len = sizeof(utf8_buf) / sizeof(char); + + for(size_t i=0 ; i < stream.size() ; ++i) + { + int c = static_cast(stream.get_wchar(i)); + + if( is_first_surrogate_char(c) && i + 1 < stream.size() ) + { + wchar_t c1 = static_cast(c); + wchar_t c2 = stream.get_wchar(++i); + surrogate_pair_to_int(c1, c2, c); + } + + size_t len = int_to_utf8(c, utf8_buf, utf8_buf_len); + + for(size_t u=0 ; u < len ; ++u) + { + operator<<(utf8_buf[u]); + } + } +} + + + + @@ -639,35 +779,28 @@ return *this; } -template -char TextStreamBase::get_char(size_t index) const -{ - return static_cast(buffer[index]); -} - - -template -wchar_t TextStreamBase::get_wchar(size_t index) const -{ - return static_cast(buffer[index]); -} - - - - template template TextStreamBase & TextStreamBase::operator<<( const TextStreamBase & arg) { - buffer.append(arg.buffer); + /* + * in the future we can have a faster implementation + * which uses iterators instead of get_char() and get_wchar() methods + * + */ + put_stream(arg); return *this; } + + + + template TextStreamBase & TextStreamBase::int_min_width(size_t min_width) diff --git a/src/utf8/utf8.cpp b/src/utf8/utf8.cpp index 4aaeb7d..cd488d4 100644 --- a/src/utf8/utf8.cpp +++ b/src/utf8/utf8.cpp @@ -291,6 +291,46 @@ return len; } +// new function, need to be tested a little more especially when sizeof(wchar_t) is 2 +size_t utf8_to_int(const Stream & utf8, size_t stream_index, int & res, bool & correct) +{ +size_t i, len; +unsigned char uz; + + res = 0; + correct = false; + len = 0; + + if( stream_index < utf8.size() ) + { + uz = utf8.get_char(stream_index); + + if( !private_namespace::utf8_to_int_first_octet(uz, len, res) ) + return 1; + + if( stream_index + len < utf8.size() + 1 ) + { + for(i=1 ; i +#include "textstream/stream.h" namespace pt @@ -120,6 +121,15 @@ size_t utf8_to_int(const char * utf8, size_t utf8_len, int & res, bool & correct size_t utf8_to_int(const char * utf8, int & res, bool & correct); size_t utf8_to_int(const std::string & utf8, int & res, bool & correct); size_t utf8_to_int(std::istream & utf8, int & res, bool & correct); +size_t utf8_to_int(const Stream & utf8, size_t stream_index, int & res, bool & correct); + + +/*! + converting one character from int to wide stream +*/ +template +void int_to_wide(int c, StreamType & res); + /*! diff --git a/src/utf8/utf8_private.h b/src/utf8/utf8_private.h index 8028259..c9b33d9 100644 --- a/src/utf8/utf8_private.h +++ b/src/utf8/utf8_private.h @@ -166,23 +166,6 @@ return !was_error; -template -void int_to_wide(int c, StreamType & res) -{ - if( sizeof(wchar_t)==2 && c>0xffff ) - { - // UTF16 surrogate pairs - c -= 0x10000; - res << static_cast(((c >> 10) & 0x3FF) + 0xD800); - res << static_cast((c & 0x3FF) + 0xDC00); - } - else - { - res << static_cast(c); - } -} - - // FIX ME it is not using surrogate pairs from input stream // and is not using mode parameter template diff --git a/src/utf8/utf8_templates.h b/src/utf8/utf8_templates.h index d4a5744..fc44491 100644 --- a/src/utf8/utf8_templates.h +++ b/src/utf8/utf8_templates.h @@ -47,6 +47,24 @@ namespace pt { +template +void int_to_wide(int c, StreamType & res) +{ + if( sizeof(wchar_t)==2 && c>0xffff ) + { + // UTF16 surrogate pairs + c -= 0x10000; + res << static_cast(((c >> 10) & 0x3FF) + 0xD800); + res << static_cast((c & 0x3FF) + 0xDC00); + } + else + { + res << static_cast(c); + } +} + + + /*! converting UTF-8 string to a TextStreamBase stream (need to be tested) @@ -59,7 +77,7 @@ bool utf8_to_wide(const char * utf8, size_t utf8_len, StreamType & res, bool cle res.clear(); bool status = private_namespace::utf8_to_wide_generic(utf8, utf8_len, mode, [&res](int c) { - private_namespace::int_to_wide(c, res); + int_to_wide(c, res); }); return status; @@ -110,7 +128,7 @@ bool correct, was_error = false; } else { - private_namespace::int_to_wide(z, res); + int_to_wide(z, res); } }