diff --git a/src/Makefile.dep b/src/Makefile.dep index a2410fd..683e3cf 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -3,41 +3,42 @@ ./convert/inttostr.o: ./convert/inttostr.h ./convert/misc.o: ./convert/misc.h ./convert/text.h ./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 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 space/space.h -./log/filelog.o: textstream/types.h convert/inttostr.h date/date.h -./log/filelog.o: membuffer/membuffer.h textstream/types.h utf8/utf8.h -./log/filelog.o: utf8/utf8_templates.h utf8/utf8_private.h -./log/log.o: ./log/log.h textstream/textstream.h space/space.h -./log/log.o: textstream/types.h convert/inttostr.h date/date.h -./log/log.o: membuffer/membuffer.h textstream/types.h ./log/filelog.h -./log/log.o: utf8/utf8.h utf8/utf8_templates.h utf8/utf8_private.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 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: 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 textstream/textstream.h space/space.h -./space/space.o: date/date.h membuffer/membuffer.h textstream/types.h -./space/space.o: utf8/utf8_templates.h utf8/utf8_private.h convert/convert.h -./space/space.o: ./convert/inttostr.h convert/patternreplacer.h -./space/space.o: convert/strtoint.h ./convert/text.h ./convert/misc.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: textstream/textstream.h space/space.h date/date.h -./space/spaceparser.o: membuffer/membuffer.h textstream/types.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 textstream/textstream.h space/space.h -./utf8/utf8.o: textstream/types.h convert/inttostr.h date/date.h -./utf8/utf8.o: membuffer/membuffer.h textstream/types.h utf8/utf8_templates.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 textstream/textstream.h -./utf8/utf8_private.o: space/space.h textstream/types.h convert/inttostr.h -./utf8/utf8_private.o: date/date.h membuffer/membuffer.h textstream/types.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 textstream/textstream.h -./csv/csvparser.o: date/date.h membuffer/membuffer.h textstream/types.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: textstream/textstream.h date/date.h -./mainoptions/mainoptionsparser.o: membuffer/membuffer.h textstream/types.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/convert/convert.h b/src/convert/convert.h index 2feb28c..9463e76 100644 --- a/src/convert/convert.h +++ b/src/convert/convert.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2012-2018, Tomasz Sowa + * Copyright (c) 2012-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,5 +43,6 @@ #include "patternreplacer.h" #include "strtoint.h" #include "text.h" +#include "double.h" #endif diff --git a/src/convert/double.cpp b/src/convert/double.cpp new file mode 100644 index 0000000..dc2893f --- /dev/null +++ b/src/convert/double.cpp @@ -0,0 +1,225 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 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. + */ + +#include +#include +#include "double.h" +#include "textstream/textstream.h" + + + +namespace pt +{ + + +float to_float(const char * str, const char ** after) +{ + char * after_local; + float res = std::strtof(str, &after_local); + + if( after ) + { + *after = after_local; + } + + return res; +} + + +float to_float(const wchar_t * str, const wchar_t ** after) +{ + wchar_t * after_local; + float res = std::wcstof(str, &after_local); + + if( after ) + { + *after = after_local; + } + + return res; +} + + +double to_double(const char * str, const char ** after) +{ + char * after_local; + double res = std::strtod(str, &after_local); + + if( after ) + { + *after = after_local; + } + + return res; +} + + +double to_double(const wchar_t * str, const wchar_t ** after) +{ + wchar_t * after_local; + double res = std::wcstod(str, &after_local); + + if( after ) + { + *after = after_local; + } + + return res; +} + + +long double to_long_double(const char * str, const char ** after) +{ + char * after_local; + long double res = std::strtold(str, &after_local); + + if( after ) + { + *after = after_local; + } + + return res; +} + + +long double to_long_double(const wchar_t * str, const wchar_t ** after) +{ + wchar_t * after_local; + long double res = std::wcstold(str, &after_local); + + if( after ) + { + *after = after_local; + } + + return res; +} + + +float to_float(const std::string & str, const char ** after) +{ + return to_float(str.c_str(), after); +} + + +float to_float(const std::wstring & str, const wchar_t ** after) +{ + return to_float(str.c_str(), after); +} + + +double to_double(const std::string & str, const char ** after) +{ + return to_double(str.c_str(), after); +} + +double to_double(const std::wstring & str, const wchar_t ** after) +{ + return to_double(str.c_str(), after); +} + + +long double to_long_double(const std::string & str, const char ** after) +{ + return to_long_double(str.c_str(), after); +} + + +long double to_long_double(const std::wstring & str, const wchar_t ** after) +{ + return to_long_double(str.c_str(), after); +} + + + + + + +std::string to_str(float val) +{ + TextStream str; + str << val; + return str.to_str();; +} + + +std::wstring to_wstr(float val) +{ + TextStream str; + str << val; + return str.to_wstr();; +} + + +std::string to_str(double val) +{ + TextStream str; + str << val; + return str.to_str();; +} + + +std::wstring to_wstr(double val) +{ + TextStream str; + str << val; + return str.to_wstr();; +} + + +std::string to_str(long double val) +{ + TextStream str; + str << val; + return str.to_str();; +} + + +std::wstring to_wstr(long double val) +{ + TextStream str; + str << val; + return str.to_wstr();; +} + + + + + + +} + diff --git a/src/convert/double.h b/src/convert/double.h new file mode 100644 index 0000000..d179767 --- /dev/null +++ b/src/convert/double.h @@ -0,0 +1,80 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 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_membuffer_convert_double +#define headerfile_picotools_membuffer_convert_double + +#include + + +namespace pt +{ + +float to_float(const char * str, const char ** after = nullptr); +float to_float(const wchar_t * str, const wchar_t ** after = nullptr); + +double to_double(const char * str, const char ** after = nullptr); +double to_double(const wchar_t * str, const wchar_t ** after = nullptr); + +long double to_long_double(const char * str, const char ** after = nullptr); +long double to_long_double(const wchar_t * str, const wchar_t ** after = nullptr); + +float to_float(const std::string & str, const char ** after = nullptr); +float to_float(const std::wstring & str, const wchar_t ** after = nullptr); + +double to_double(const std::string & str, const char ** after = nullptr); +double to_double(const std::wstring & str, const wchar_t ** after = nullptr); + +long double to_long_double(const std::string & str, const char ** after = nullptr); +long double to_long_double(const std::wstring & str, const wchar_t ** after = nullptr); + + + +std::string to_str(float val); +std::wstring to_wstr(float val); + +std::string to_str(double val); +std::wstring to_wstr(double val); + +std::string to_str(long double val); +std::wstring to_wstr(long double val); + + + +} + +#endif diff --git a/src/convert/patternreplacer.h b/src/convert/patternreplacer.h index 65569f0..02d73b4 100644 --- a/src/convert/patternreplacer.h +++ b/src/convert/patternreplacer.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -86,7 +86,7 @@ private: params.clear(); AddParams(types...); ReplacePattern(pattern); - buffer.to_string(output_string); + buffer.to_str(output_string); params.clear(); buffer.clear(); @@ -104,7 +104,7 @@ private: { buffer.clear(); buffer << type; - buffer.to_string(temp_str); + buffer.to_str(temp_str); params.push_back(temp_str); temp_str.clear(); diff --git a/src/convert/text.cpp b/src/convert/text.cpp index 8551ba0..7f0227a 100644 --- a/src/convert/text.cpp +++ b/src/convert/text.cpp @@ -463,8 +463,76 @@ bool is_substr_nc(const std::wstring & short_str, const std::wstring & long_str) } +void trim_first_white(std::string & str, bool check_additional_chars, bool treat_new_line_as_white) +{ + pt_private::trim_first_white_generic(str, check_additional_chars, treat_new_line_as_white); +} +void trim_first_white(std::wstring & str, bool check_additional_chars, bool treat_new_line_as_white) +{ + pt_private::trim_first_white_generic(str, check_additional_chars, treat_new_line_as_white); +} + + +void trim_last_white(std::string & str, bool check_additional_chars, bool treat_new_line_as_white) +{ + pt_private::trim_last_white_generic(str, check_additional_chars, treat_new_line_as_white); +} + + +void trim_last_white(std::wstring & str, bool check_additional_chars, bool treat_new_line_as_white) +{ + pt_private::trim_last_white_generic(str, check_additional_chars, treat_new_line_as_white); +} + + +void trim_white(std::string & str, bool check_additional_chars, bool treat_new_line_as_white) +{ + pt_private::trim_white_generic(str, check_additional_chars, treat_new_line_as_white); +} + + +void trim_white(std::wstring & str, bool check_additional_chars, bool treat_new_line_as_white) +{ + pt_private::trim_white_generic(str, check_additional_chars, treat_new_line_as_white); +} + + +void trim_first(std::string & str, wchar_t c) +{ + pt_private::trim_first_generic(str, c); +} + + +void trim_first(std::wstring & str, wchar_t c) +{ + pt_private::trim_first_generic(str, c); +} + + +void trim_last(std::string & str, wchar_t c) +{ + pt_private::trim_last_generic(str, c); +} + + +void trim_last(std::wstring & str, wchar_t c) +{ + pt_private::trim_last_generic(str, c); +} + + +void trim(std::string & str, wchar_t c) +{ + pt_private::trim_generic(str, c); +} + + +void trim(std::wstring & str, wchar_t c) +{ + pt_private::trim_generic(str, c); +} diff --git a/src/convert/text.h b/src/convert/text.h index d5dcdf2..14df30e 100644 --- a/src/convert/text.h +++ b/src/convert/text.h @@ -143,6 +143,26 @@ bool is_substr_nc(const std::string & short_str, const std::string & long_str); bool is_substr_nc(const std::wstring & short_str, const std::wstring & long_str); +void trim_first_white(std::string & str, bool check_additional_chars = true, bool treat_new_line_as_white = true); +void trim_first_white(std::wstring & str, bool check_additional_chars = true, bool treat_new_line_as_white = true); + +void trim_last_white(std::string & str, bool check_additional_chars = true, bool treat_new_line_as_white = true); +void trim_last_white(std::wstring & str, bool check_additional_chars = true, bool treat_new_line_as_white = true); + +void trim_white(std::string & str, bool check_additional_chars = true, bool treat_new_line_as_white = true); +void trim_white(std::wstring & str, bool check_additional_chars = true, bool treat_new_line_as_white = true); + +void trim_first(std::string & str, wchar_t c); +void trim_first(std::wstring & str, wchar_t c); + +void trim_last(std::string & str, wchar_t c); +void trim_last(std::wstring & str, wchar_t c); + +void trim(std::string & str, wchar_t c); +void trim(std::wstring & str, wchar_t c); + + + } diff --git a/src/convert/text_private.h b/src/convert/text_private.h index 2b93ac4..8718b80 100644 --- a/src/convert/text_private.h +++ b/src/convert/text_private.h @@ -299,6 +299,112 @@ bool is_substr_nc_generic(const StringType1 * short_str, const StringType2 * lon +template +void trim_first_white_generic(StringType & s, bool check_additional_chars, bool treat_new_line_as_white) +{ +size_t i; + + if( s.empty() ) + return; + + // looking for white characters at the beginning + for(i=0 ; i +void trim_last_white_generic(StringType & s, bool check_additional_chars, bool treat_new_line_as_white) +{ +size_t i; + + if( s.empty() ) + return; + + // looking for white characters at the end + for(i=s.size()-1 ; i>0 && is_white(s[i], check_additional_chars, treat_new_line_as_white) ; --i); + + if( i==0 && is_white(s[i], check_additional_chars, treat_new_line_as_white) ) + { + // the whole string has white characters + s.clear(); + return; + } + + // deleting white characters at the end + if( i != s.size() - 1 ) + s.erase(i+1, StringType::npos); +} + + +template +void trim_white_generic(StringType & s, bool check_additional_chars, bool treat_new_line_as_white) +{ + if( s.empty() ) + return; + + trim_last_white_generic(s, check_additional_chars, treat_new_line_as_white); + trim_first_white_generic(s, check_additional_chars, treat_new_line_as_white); +} + + + +template +void trim_first_generic(StringType & s, wchar_t c) +{ +size_t i; + + if( s.empty() ) + return; + + // looking for the 'c' characters at the beginning + for(i=0 ; i +void trim_last_generic(StringType & s, wchar_t c) +{ +size_t i; + + if( s.empty() ) + return; + + // looking for the 'c' characters at the end + for(i=s.size()-1 ; i>0 && s[i]==c ; --i); + + if( i==0 && s[i]==c ) + { + // the whole string has the 'c' characters + s.clear(); + return; + } + + // deleting 'c' characters at the end + if( i != s.size() - 1 ) + s.erase(i+1, StringType::npos); +} + + +template +void trim_generic(StringType & s, wchar_t c) +{ + if( s.empty() ) + return; + + trim_last_generic(s, c); + trim_first_generic(s, c); +} + + + } // namespace pt_private diff --git a/src/date/date.h b/src/date/date.h index 59938c3..c9ba433 100644 --- a/src/date/date.h +++ b/src/date/date.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2012-2018, Tomasz Sowa + * Copyright (c) 2012-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -251,12 +251,21 @@ public: int WeekDay() const; + /* + this method outputs to the given stream the number of a month in Roman numerals + e.g: if month is equal to 3 then III will be put to 'out' + month should be in the range [1,12] + */ + template + static void SerializeMonthAsRoman(Stream & out, int month); + + /* this method outputs to the given stream: YYYY-MM-DD, eg. 1990-02-12 ISO 8601 format */ template - void SerializeYearMonthDay(Stream & out) const; + void SerializeYearMonthDay(Stream & out, bool roman_month = false) const; /* @@ -271,7 +280,7 @@ public: this method outputs to the given stream: MM-DD, eg. 02-12 (02 month, 12 day) */ template - void SerializeMonthDay(Stream & out) const; + void SerializeMonthDay(Stream & out, bool roman_month = false) const; /* @@ -286,7 +295,7 @@ public: ISO 8601 format */ template - void Serialize(Stream & out) const; + void Serialize(Stream & out, bool roman_month = false, bool with_seconds = true) const; /* @@ -547,13 +556,32 @@ void Date::SerializeInt(Stream & out, int val) const } +template +void Date::SerializeMonthAsRoman(Stream & out, int month) +{ + const char * month_roman[] = { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII" }; + + if( month >= 1 && month <= 12 ) + { + const char * month_str = month_roman[month - 1]; + + for( ; *month_str ; ++month_str) + out << *month_str; + } +} + template -void Date::SerializeYearMonthDay(Stream & out) const +void Date::SerializeYearMonthDay(Stream & out, bool roman_month) const { SerializeInt(out, year, 4); out << '-'; - SerializeInt(out, month); + + if( roman_month ) + SerializeMonthAsRoman(out, month); + else + SerializeInt(out, month); + out << '-'; SerializeInt(out, day); } @@ -571,9 +599,13 @@ void Date::SerializeHourMinSec(Stream & out) const template -void Date::SerializeMonthDay(Stream & out) const +void Date::SerializeMonthDay(Stream & out, bool roman_month) const { - SerializeInt(out, month); + if( roman_month ) + SerializeMonthAsRoman(out, month); + else + SerializeInt(out, month); + out << '-'; SerializeInt(out, day); } @@ -589,17 +621,22 @@ void Date::SerializeHourMin(Stream & out) const template -void Date::Serialize(Stream & out) const +void Date::Serialize(Stream & out, bool roman_month, bool with_seconds) const { - SerializeYearMonthDay(out); + SerializeYearMonthDay(out, roman_month); out << ' '; - SerializeHourMinSec(out); + + if( with_seconds ) + SerializeHourMinSec(out); + else + SerializeHourMin(out); } + template void Date::SerializeISO(Stream & out) const { - SerializeYearMonthDay(out); + SerializeYearMonthDay(out, false); out << 'T'; SerializeHourMinSec(out); out << 'Z'; diff --git a/src/log/log.cpp b/src/log/log.cpp index fb7ec91..921061b 100644 --- a/src/log/log.cpp +++ b/src/log/log.cpp @@ -41,7 +41,7 @@ #include "date/date.h" #include "utf8/utf8.h" -#ifdef PT_HAS_MORM +#ifdef PT_HAS_MORM_LIBRARY #include "morm.h" #endif @@ -54,89 +54,156 @@ Log::Log() { buffer = nullptr; file_log = nullptr; - current_level = 4; - max_buffer_length = 2 * 1024 * 1024; // 2MB + max_buffer_length = 2 * 1024 * 1024; } Log::~Log() { - // IMPROVE ME - // I am not sure if this is a correct behaviour - // the log buffer and file logger may not exist now - // (life time of objects) - // may would be better to have a flag 'clear_at_the_end' - // and if true then call this method? - - save_log_and_clear(); } -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; @@ -146,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; } @@ -182,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; } @@ -194,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) { @@ -289,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; } @@ -301,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; } @@ -313,7 +456,7 @@ Log & Log::operator<<(const Date & date) } -#ifdef PT_HAS_MORM +#ifdef PT_HAS_MORM_LIBRARY Log & Log::operator<<(morm::Model & model) { operator<<(model.to_string()); @@ -322,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'; @@ -337,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; @@ -370,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 ) @@ -393,7 +598,6 @@ return c - 10 + 'A'; } - void Log::to_hex(char * buf, unsigned char c) { buf[0] = get_hex_digit(c >> 4); @@ -402,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 ) { @@ -454,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(); @@ -483,7 +686,3 @@ void Log::save_log() } // namespace - - - - diff --git a/src/log/log.h b/src/log/log.h index d5073ae..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); + Log & operator<<(const Stream & stream); + Log & operator<<(const Space & space); + Log & operator<<(const Date & date); - 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); - -#ifdef PT_HAS_MORM +#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/mainoptions/mainoptionsparser.cpp b/src/mainoptions/mainoptionsparser.cpp index ae839b5..6d208ff 100644 --- a/src/mainoptions/mainoptionsparser.cpp +++ b/src/mainoptions/mainoptionsparser.cpp @@ -346,7 +346,7 @@ void MainOptionsParser::parse_non_option_arguments(size_t argc, const char ** ar void MainOptionsParser::add_option_to_space(const std::wstring & option, const std::vector & arguments) { - Space * option_table = space->get_object_field(option); + Space * option_table = space->get_space(option); if( !option_table ) { diff --git a/src/space/space.cpp b/src/space/space.cpp index 6d36ef6..ca816f3 100644 --- a/src/space/space.cpp +++ b/src/space/space.cpp @@ -152,6 +152,11 @@ Space::Space(double val) set(val); } +Space::Space(long double val) +{ + initialize(); + set(val); +} Space::Space(const char * str) { @@ -273,7 +278,7 @@ void Space::set_empty_table() { if( type == type_table ) { - value.value_table.clear(); + remove_value_table(true); } else { @@ -285,7 +290,7 @@ void Space::set_empty_object() { if( type == type_object ) { - value.value_object.clear(); + remove_value_object(true); } else { @@ -355,6 +360,12 @@ void Space::set(double val) value.value_double = val; } +void Space::set(long double val) +{ + initialize_value_long_double_if_needed(); + value.value_long_double = val; +} + void Space::set(const char * str) { @@ -473,6 +484,11 @@ Space & Space::add(double val) return add_generic(val); } +Space & Space::add(long double val) +{ + return add_generic(val); +} + Space & Space::add(const char * val) { return add_generic(val); @@ -575,6 +591,11 @@ Space & Space::add(const wchar_t * field, double val) return add_generic(field, val); } +Space & Space::add(const wchar_t * field, long double val) +{ + return add_generic(field, val); +} + Space & Space::add(const wchar_t * field, const char * val) { return add_generic(field, val); @@ -608,9 +629,16 @@ Space & Space::add(const wchar_t * field, const Space * space) Space & Space::add(const wchar_t * field, Space && space) { initialize_value_object_if_needed(); - auto insert_res = value.value_object.insert(std::make_pair(field, nullptr)); - insert_res.first->second = new Space(std::move(space)); + + if( insert_res.second ) + { + insert_res.first->second = new Space(std::move(space)); + } + else + { + insert_res.first->second->set(std::move(space)); + } return *(insert_res.first->second); } @@ -678,6 +706,11 @@ Space & Space::add(const std::wstring & field, double val) return add_generic(field, val); } +Space & Space::add(const std::wstring & field, long double val) +{ + return add_generic(field, val); +} + Space & Space::add(const std::wstring & field, const char * val) { return add_generic(field, val); @@ -753,9 +786,14 @@ bool Space::is_double() const return type == type_double; } +bool Space::is_long_double() const +{ + return type == type_long_double; +} + bool Space::is_numeric() const { - return is_long_long() || is_float() || is_double(); + return is_long_long() || is_float() || is_double() || is_long_double(); } bool Space::is_str() const @@ -835,6 +873,9 @@ long long Space::to_long_long() const case type_double: return static_cast(value.value_double); + case type_long_double: + return static_cast(value.value_long_double); + case type_string: return convert_string_to_long_long(); @@ -931,6 +972,9 @@ unsigned long long Space::to_ulong_long() const case type_double: return static_cast(value.value_double); + case type_long_double: + return static_cast(value.value_long_double); + case type_string: return convert_string_to_ulong_long(); @@ -943,6 +987,112 @@ unsigned long long Space::to_ulong_long() const +float Space::to_float() const +{ + switch(type) + { + case type_null: + case type_object: + case type_table: + return 0; + + case type_bool: + return value.value_bool ? 1.0f : 0.0f; + + case type_long: + return static_cast(value.value_long); + + case type_float: + return value.value_float; + + case type_double: + return static_cast(value.value_double); + + case type_long_double: + return static_cast(value.value_long_double); + + case type_string: + return pt::to_float(value.value_string); + + case type_wstring: + return pt::to_float(value.value_wstring); + } + + return 0; +} + +double Space::to_double() const +{ + switch(type) + { + case type_null: + case type_object: + case type_table: + return 0; + + case type_bool: + return value.value_bool ? 1.0 : 0.0; + + case type_long: + return static_cast(value.value_long); + + case type_float: + return static_cast(value.value_float); + + case type_double: + return value.value_double; + + case type_long_double: + return static_cast(value.value_long_double); + + case type_string: + return pt::to_double(value.value_string); + + case type_wstring: + return pt::to_double(value.value_wstring); + } + + return 0; +} + + +long double Space::to_long_double() const +{ + switch(type) + { + case type_null: + case type_object: + case type_table: + return 0; + + case type_bool: + return value.value_bool ? 1.0 : 0.0; + + case type_long: + return static_cast(value.value_long); + + case type_float: + return static_cast(value.value_float); + + case type_double: + return static_cast(value.value_double); + + case type_long_double: + return value.value_long_double; + + case type_string: + return pt::to_long_double(value.value_string); + + case type_wstring: + return pt::to_long_double(value.value_wstring); + } + + return 0; +} + + + + std::string Space::to_str() const { if( type == type_string ) @@ -954,7 +1104,7 @@ std::string Space::to_str() const { TextStream stream; serialize_string_buffer(value.value_wstring.c_str(), value.value_wstring.size(), stream, Escape::no_escape); - stream.to_string(str); + stream.to_str(str); return str; } @@ -1012,73 +1162,73 @@ void Space::to_list(std::vector & output_list, bool clear_list) co bool Space::to_bool(const wchar_t * field, bool default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_bool() : default_value; } short Space::to_short(const wchar_t * field, short default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_short() : default_value; } int Space::to_int(const wchar_t * field, int default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_int() : default_value; } long Space::to_long(const wchar_t * field, long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_long() : default_value; } long long Space::to_llong(const wchar_t * field, long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_llong() : default_value; } long long Space::to_long_long(const wchar_t * field, long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_long_long() : default_value; } unsigned short Space::to_ushort(const wchar_t * field, unsigned short default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ushort() : default_value; } unsigned int Space::to_uint(const wchar_t * field, unsigned int default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_uint() : default_value; } unsigned long Space::to_ulong(const wchar_t * field, unsigned long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ulong() : default_value; } unsigned long long Space::to_ullong(const wchar_t * field, unsigned long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ullong() : default_value; } unsigned long long Space::to_ulong_long(const wchar_t * field, unsigned long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ulong_long() : default_value; } std::string Space::to_str(const wchar_t * field, const char * default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1096,14 +1246,14 @@ std::string Space::to_str(const wchar_t * field, const char * default_value) con std::string Space::to_str(const wchar_t * field, const std::string & default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_str() : default_value; } std::wstring Space::to_wstr(const wchar_t * field, const wchar_t * default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1121,7 +1271,7 @@ std::wstring Space::to_wstr(const wchar_t * field, const wchar_t * default_value std::wstring Space::to_wstr(const wchar_t * field, const std::wstring & default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_wstr() : default_value; } @@ -1173,73 +1323,73 @@ bool Space::to_list(const std::wstring & field, std::vector & outp bool Space::to_bool(const std::wstring & field, bool default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_bool() : default_value; } short Space::to_short(const std::wstring & field, short default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_short() : default_value; } int Space::to_int(const std::wstring & field, int default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_int() : default_value; } long Space::to_long(const std::wstring & field, long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_long() : default_value; } long long Space::to_llong(const std::wstring & field, long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_llong() : default_value; } long long Space::to_long_long(const std::wstring & field, long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_long_long() : default_value; } unsigned short Space::to_ushort(const std::wstring & field, unsigned short default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ushort() : default_value; } unsigned int Space::to_uint(const std::wstring & field, unsigned int default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_uint() : default_value; } unsigned long Space::to_ulong(const std::wstring & field, unsigned long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ulong() : default_value; } unsigned long long Space::to_ullong(const std::wstring & field, unsigned long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ullong() : default_value; } unsigned long long Space::to_ulong_long(const std::wstring & field, unsigned long long default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_ulong_long() : default_value; } std::string Space::to_str(const std::wstring & field, const char * default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1256,14 +1406,14 @@ std::string Space::to_str(const std::wstring & field, const char * default_value std::string Space::to_str(const std::wstring & field, const std::string & default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_str() : default_value; } std::wstring Space::to_wstr(const std::wstring & field, const wchar_t * default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1280,7 +1430,7 @@ std::wstring Space::to_wstr(const std::wstring & field, const wchar_t * default_ std::wstring Space::to_wstr(const std::wstring & field, const std::wstring & default_value) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->to_wstr() : default_value; } @@ -1310,7 +1460,7 @@ void Space::serialize_to_space_to(std::string & str, bool pretty_print) const TextStream stream; serialize_to_space_stream(stream, pretty_print); - stream.to_string(str); + stream.to_str(str); } @@ -1319,7 +1469,7 @@ void Space::serialize_to_space_to(std::wstring & str, bool pretty_print) const WTextStream stream; serialize_to_space_stream(stream, pretty_print); - stream.to_string(str); + stream.to_str(str); } @@ -1345,7 +1495,7 @@ void Space::serialize_to_json_to(std::string & str) const TextStream stream; serialize_to_json_stream(stream); - stream.to_string(str); + stream.to_str(str); } @@ -1354,7 +1504,7 @@ void Space::serialize_to_json_to(std::wstring & str) const WTextStream stream; serialize_to_json_stream(stream); - stream.to_string(str); + stream.to_str(str); } @@ -1384,6 +1534,11 @@ double * Space::get_double() return type == type_double ? &value.value_double : nullptr; } +long double * Space::get_long_double() +{ + return type == type_long_double ? &value.value_long_double : nullptr; +} + std::string * Space::get_str() { return type == type_string ? &value.value_string : nullptr; @@ -1513,8 +1668,7 @@ bool Space::has_value(const std::wstring & val) const - -Space * Space::get_object_field(const wchar_t * field) +Space * Space::get_space(const wchar_t * field) { if( is_object() ) { @@ -1529,57 +1683,90 @@ Space * Space::get_object_field(const wchar_t * field) return nullptr; } +Space * Space::get_space(const std::wstring & field) +{ + return get_space(field.c_str()); +} + + +Space & Space::get_add_space(const wchar_t * field) +{ + pt::Space * space = get_space(field); + + if( !space ) + { + return add_empty_space(field); + } + + return *space; +} + + +Space & Space::get_add_space(const std::wstring & field) +{ + return get_add_space(field.c_str()); +} + + + + bool * Space::get_bool(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_bool() : nullptr; } long long * Space::get_llong(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_llong() : nullptr; } long long * Space::get_long_long(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_long_long() : nullptr; } float * Space::get_float(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_float() : nullptr; } double * Space::get_double(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_double() : nullptr; } +long double * Space::get_long_double(const wchar_t * field) +{ + Space * space = get_space(field); + return space ? space->get_long_double() : nullptr; +} + std::string * Space::get_str(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_str() : nullptr; } std::wstring * Space::get_wstr(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_wstr() : nullptr; } Space::ObjectType * Space::get_object(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_object() : nullptr; } Space::TableType * Space::get_table(const wchar_t * field) { - Space * space = get_object_field(field); + Space * space = get_space(field); return space ? space->get_table() : nullptr; } @@ -1611,6 +1798,11 @@ const double * Space::get_double() const return type == type_double ? &value.value_double : nullptr; } +const long double * Space::get_long_double() const +{ + return type == type_long_double ? &value.value_long_double : nullptr; +} + const std::string * Space::get_str() const { return type == type_string ? &value.value_string : nullptr; @@ -1635,18 +1827,18 @@ const Space::TableType * Space::get_table() const bool Space::has_key(const wchar_t * field) const { - return get_object_field(field) != nullptr; + return get_space(field) != nullptr; } bool Space::has_key(const std::wstring & field) const { - return get_object_field(field) != nullptr; + return get_space(field) != nullptr; } -const Space * Space::get_object_field(const wchar_t * field) const +const Space * Space::get_space(const wchar_t * field) const { if( is_object() ) { @@ -1662,68 +1854,70 @@ const Space * Space::get_object_field(const wchar_t * field) const } -Space * Space::get_object_field(const std::wstring & field) +const Space * Space::get_space(const std::wstring & field) const { - return get_object_field(field.c_str()); + return get_space(field.c_str()); } -const Space * Space::get_object_field(const std::wstring & field) const -{ - return get_object_field(field.c_str()); -} const bool * Space::get_bool(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_bool() : nullptr; } const long long * Space::get_llong(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_llong() : nullptr; } const long long * Space::get_long_long(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_long_long() : nullptr; } const float * Space::get_float(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_float() : nullptr; } const double * Space::get_double(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_double() : nullptr; } +const long double * Space::get_long_double(const wchar_t * field) const +{ + const Space * space = get_space(field); + return space ? space->get_long_double() : nullptr; +} + const std::string * Space::get_str(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_str() : nullptr; } const std::wstring * Space::get_wstr(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_wstr() : nullptr; } const Space::ObjectType * Space::get_object(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_object() : nullptr; } const Space::TableType * Space::get_table(const wchar_t * field) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); return space ? space->get_table() : nullptr; } @@ -1731,7 +1925,7 @@ const Space::TableType * Space::get_table(const wchar_t * field) const -Space * Space::get_object_field_nc(const wchar_t * field) +Space * Space::get_space_nc(const wchar_t * field) { if( is_object() ) { @@ -1750,13 +1944,13 @@ Space * Space::get_object_field_nc(const wchar_t * field) } -Space * Space::get_object_field_nc(const std::wstring & field) +Space * Space::get_space_nc(const std::wstring & field) { - return get_object_field_nc(field.c_str()); + return get_space_nc(field.c_str()); } -const Space * Space::get_object_field_nc(const wchar_t * field) const +const Space * Space::get_space_nc(const wchar_t * field) const { if( is_object() ) { @@ -1775,9 +1969,9 @@ const Space * Space::get_object_field_nc(const wchar_t * field) const } -const Space * Space::get_object_field_nc(const std::wstring & field) const +const Space * Space::get_space_nc(const std::wstring & field) const { - return get_object_field_nc(field.c_str()); + return get_space_nc(field.c_str()); } @@ -1807,9 +2001,20 @@ void Space::remove(const std::wstring & field) } +void Space::remove(size_t table_index) +{ + if( type == type_table && table_index < value.value_table.size() ) + { + delete value.value_table[table_index]; + value.value_table[table_index] = nullptr; + value.value_table.erase(value.value_table.begin() + table_index); + } +} + + bool Space::is_equal(const wchar_t * field, const char * val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1821,7 +2026,7 @@ bool Space::is_equal(const wchar_t * field, const char * val) const bool Space::is_equal(const wchar_t * field, const std::string & val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1834,7 +2039,7 @@ bool Space::is_equal(const wchar_t * field, const std::string & val) const bool Space::is_equal(const wchar_t * field, const wchar_t * val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1847,7 +2052,7 @@ bool Space::is_equal(const wchar_t * field, const wchar_t * val) const bool Space::is_equal(const wchar_t * field, const std::wstring & val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1863,7 +2068,7 @@ bool Space::is_equal(const wchar_t * field, const std::wstring & val) const bool Space::has_value(const wchar_t * field, const char * val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1875,7 +2080,7 @@ bool Space::has_value(const wchar_t * field, const char * val) const bool Space::has_value(const wchar_t * field, const std::string & val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1888,7 +2093,7 @@ bool Space::has_value(const wchar_t * field, const std::string & val) const bool Space::has_value(const wchar_t * field, const wchar_t * val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1901,7 +2106,7 @@ bool Space::has_value(const wchar_t * field, const wchar_t * val) const bool Space::has_value(const wchar_t * field, const std::wstring & val) const { - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -1914,251 +2119,9 @@ bool Space::has_value(const wchar_t * field, const std::wstring & val) const -const Space * Space::find_child_space_const(const wchar_t * name) const -{ - const TableType * child_table = find_child_space_table(); - if( child_table ) - { - for(const Space & space : *child_table) - { - if( space.is_equal(child_spaces_name, name) ) - { - return &space; - } - } - } - return nullptr; -} - - - -const Space * Space::find_child_space_const(size_t table_index) const -{ - const TableType * child_table = find_child_space_table(); - - if( child_table && table_index < child_table->size() ) - { - return (*child_table)[table_index]; - } - - return nullptr; -} - - - -Space::TableType * Space::find_child_space_table() -{ - return get_table(child_spaces_field_table_name); -} - - -const Space::TableType * Space::find_child_space_table() const -{ - return get_table(child_spaces_field_table_name); -} - - -bool Space::child_spaces_empty() const -{ - const TableType * child_table = find_child_space_table(); - - if( child_table ) - { - return child_table->empty(); - } - - return true; -} - -size_t Space::child_spaces_size() const -{ - const TableType * child_table = find_child_space_table(); - - if( child_table ) - { - return child_table->size(); - } - - return 0; -} - - -Space * Space::find_child_space(const wchar_t * name) -{ - return const_cast(find_child_space_const(name)); -} - - -Space * Space::find_child_space(const std::wstring & name) -{ - return find_child_space(name.c_str()); -} - - -const Space * Space::find_child_space(const wchar_t * name) const -{ - return find_child_space_const(name); -} - - -const Space * Space::find_child_space(const std::wstring & name) const -{ - return find_child_space(name.c_str()); -} - - - -Space * Space::find_child_space(size_t table_index) -{ - return const_cast(find_child_space_const(table_index)); -} - -const Space * Space::find_child_space(size_t table_index) const -{ - return find_child_space_const(table_index); -} - - -Space & Space::add_child_space() -{ - initialize_child_spaces_if_needed(); - - TableType * child_table = find_child_space_table(); - child_table->push_back(new Space()); - - return *child_table->back(); -} - - -Space & Space::add_child_space(const wchar_t * space_name) -{ - initialize_child_spaces_if_needed(); - - TableType * child_table = find_child_space_table(); - child_table->push_back(new Space()); - Space * last_space = child_table->back(); - last_space->add(child_spaces_name, space_name); - - return *last_space; -} - - -Space & Space::add_child_space(const std::wstring & space_name) -{ - return add_child_space(space_name.c_str()); -} - - -Space & Space::find_add_child_space(const wchar_t * name) -{ - Space * space = find_child_space(name); - - if( !space ) - { - return add_child_space(name); - } - - return *space; -} - - -Space & Space::find_add_child_space(const std::wstring & name) -{ - return find_add_child_space(name.c_str()); -} - - -std::wstring * Space::find_child_space_name() -{ - return get_wstr(child_spaces_name); -} - - -const std::wstring * Space::find_child_space_name() const -{ - return get_wstr(child_spaces_name); -} - - -std::wstring Space::get_child_space_name() const -{ - const std::wstring * name = find_child_space_name(); - - if( name ) - { - return *name; - } - else - { - return std::wstring(); - } -} - - - -bool Space::is_child_space_name(const wchar_t * name) const -{ - return is_equal(child_spaces_name, name); -} - - -bool Space::is_child_space_name(const std::wstring & name) const -{ - return is_equal(child_spaces_name, name.c_str()); -} - - - - -void Space::remove_child_space(const wchar_t * name) -{ - TableType * child_table = find_child_space_table(); - - if( child_table ) - { - for(size_t i=0 ; isize() ; ) - { - Space * child = (*child_table)[i]; - - if( child->is_equal(child_spaces_name, name) ) - { - delete child; - child_table->erase(child_table->begin() + i); - } - else - { - ++i; - } - } - } -} - -void Space::remove_child_space(const std::wstring & name) -{ - return remove_child_space(name.c_str()); -} - - -void Space::remove_child_space(size_t index) -{ - TableType * child_table = find_child_space_table(); - - if( child_table && index < child_table->size() ) - { - Space * child = (*child_table)[index]; - delete child; - child_table->erase(child_table->begin() + index); - } -} - - - - - - -void Space::copy_value_from(const Space & space) +void Space::copy_from(const Space & space) { switch(space.type) { @@ -2186,6 +2149,11 @@ void Space::copy_value_from(const Space & space) value.value_double = space.value.value_double; break; + case type_long_double: + initialize_value_long_double_if_needed(); + value.value_long_double = space.value.value_long_double; + break; + case type_string: initialize_value_string_if_needed(); value.value_string = space.value.value_string; @@ -2208,19 +2176,18 @@ void Space::copy_value_from(const Space & space) -void Space::copy_from(const Space & space) -{ - copy_value_from(space); -} - - - void Space::copy_value_object(const Value & value_from) { - initialize_value_object_if_needed(); - value.value_object.clear(); + if( type == type_object ) + { + remove_value_object(true); + } + else + { + initialize_value_object_if_needed(); + } for(auto map_item : value_from.value_object) { @@ -2232,9 +2199,14 @@ void Space::copy_value_object(const Value & value_from) void Space::copy_value_table(const Value & value_from) { - initialize_value_table_if_needed(); - - value.value_table.clear(); + if( type == type_table ) + { + remove_value_table(true); + } + else + { + initialize_value_table_if_needed(); + } for(Space * space : value_from.value_table) { @@ -2265,7 +2237,7 @@ void Space::move_value_from(Space && space) break; default: - copy_value_from(space); + copy_from(space); break; } } @@ -2339,6 +2311,17 @@ void Space::initialize_value_double_if_needed() } +void Space::initialize_value_long_double_if_needed() +{ + if( type != type_long_double ) + { + remove_value(); + new (&value) long double; + type = type_long_double; + } +} + + void Space::initialize_value_string_if_needed() { if( type != type_string ) @@ -2411,6 +2394,7 @@ void Space::initialize_value_object_if_needed(ObjectType && obj) } else { + remove_value_object(true); value.value_object = std::move(obj); } } @@ -2437,27 +2421,12 @@ void Space::initialize_value_table_if_needed(TableType && tab) } else { + remove_value_table(true); value.value_table = std::move(tab); } } -void Space::initialize_child_spaces_if_needed() -{ - Space * child_spaces = get_object_field(child_spaces_field_table_name); - - if( child_spaces ) - { - if( !child_spaces->is_table() ) - child_spaces->set_empty_table(); - } - else - { - Space & new_child_spaces = add_empty_space(child_spaces_field_table_name); - new_child_spaces.set_empty_table(); - } -} - void Space::remove_value() @@ -2471,6 +2440,7 @@ void Space::remove_value() case type_long: case type_float: case type_double: + case type_long_double: type = type_null; break; @@ -2513,7 +2483,7 @@ void Space::remove_value_wstring() } -void Space::remove_value_object() +void Space::remove_value_object(bool only_clear) { for(auto map_item : value.value_object) { @@ -2521,12 +2491,19 @@ void Space::remove_value_object() map_item.second = nullptr; } - value.value_object.~ObjectType(); - type = type_null; + if( only_clear ) + { + value.value_object.clear(); + } + else + { + value.value_object.~ObjectType(); + type = type_null; + } } -void Space::remove_value_table() +void Space::remove_value_table(bool only_clear) { for(size_t i = 0 ; i < value.value_table.size() ; ++i) { @@ -2534,8 +2511,15 @@ void Space::remove_value_table() value.value_table[i] = nullptr; } - value.value_table.~TableType(); - type = type_null; + if( only_clear ) + { + value.value_table.clear(); + } + else + { + value.value_table.~TableType(); + type = type_null; + } } diff --git a/src/space/space.h b/src/space/space.h index 1a79748..02241d4 100644 --- a/src/space/space.h +++ b/src/space/space.h @@ -44,9 +44,10 @@ #include #include #include +#include #include "textstream/types.h" #include "convert/inttostr.h" -#include +#include "utf8/utf8.h" @@ -135,9 +136,6 @@ public: typedef std::map ObjectType; typedef std::vector TableType; - constexpr static const wchar_t * child_spaces_field_table_name = L"child_spaces"; - constexpr static const wchar_t * child_spaces_name = L"name"; - enum Escape { no_escape, @@ -152,6 +150,7 @@ public: type_long, type_float, type_double, + type_long_double, type_string, type_wstring, type_object, @@ -164,6 +163,7 @@ public: long long value_long; float value_float; double value_double; + long double value_long_double; std::string value_string; std::wstring value_wstring; ObjectType value_object; @@ -201,6 +201,7 @@ public: Space(unsigned long long val); Space(float val); Space(double val); + Space(long double val); Space(const char * str); Space(const wchar_t * str); Space(const std::string & str); @@ -234,6 +235,7 @@ public: void set(unsigned long long val); void set(float val); void set(double val); + void set(long double val); void set(const char * str); void set(const wchar_t * str); void set(const std::string & str); @@ -255,6 +257,7 @@ public: Space & add(unsigned long long val); Space & add(float val); Space & add(double val); + Space & add(long double val); Space & add(const char * val); Space & add(const wchar_t * val); Space & add(const std::string & val); @@ -278,6 +281,7 @@ public: Space & add(const wchar_t * field, unsigned long long val); Space & add(const wchar_t * field, float val); Space & add(const wchar_t * field, double val); + Space & add(const wchar_t * field, long double val); Space & add(const wchar_t * field, const char * val); Space & add(const wchar_t * field, const wchar_t * val); Space & add(const wchar_t * field, const std::string & val); @@ -298,6 +302,7 @@ public: Space & add(const std::wstring & field, unsigned long long val); Space & add(const std::wstring & field, float val); Space & add(const std::wstring & field, double val); + Space & add(const std::wstring & field, long double val); Space & add(const std::wstring & field, const char * val); Space & add(const std::wstring & field, const wchar_t * val); Space & add(const std::wstring & field, const std::string & val); @@ -313,7 +318,7 @@ public: Space & add_stream(const wchar_t * field, StreamType & str) { std::wstring temp; - str.to_string(temp); + str.to_str(temp); return add(field, temp); } @@ -322,7 +327,7 @@ public: Space & add_stream(const std::wstring & field, StreamType & str) { std::wstring temp; - str.to_string(temp); + str.to_str(temp); return add(field, temp); } @@ -335,6 +340,7 @@ public: bool is_long_long() const; bool is_float() const; bool is_double() const; + bool is_long_double() const; bool is_numeric() const; bool is_str() const; bool is_wstr() const; @@ -355,6 +361,9 @@ public: unsigned long to_ulong() const; unsigned long long to_ullong() const; unsigned long long to_ulong_long() const; + float to_float() const; + double to_double() const; + long double to_long_double() const; std::string to_str() const; std::wstring to_wstr() const; @@ -418,6 +427,7 @@ public: long long * get_long_long(); float * get_float(); double * get_double(); + long double * get_long_double(); std::string * get_str(); std::wstring * get_wstr(); ObjectType * get_object(); @@ -443,17 +453,21 @@ public: // size_t argument will be only for tables, wchar_t* or std::wstring for objects? // getters from object - Space * get_object_field(const wchar_t * field); // may a better name? - const Space * get_object_field(const wchar_t * field) const; // may a better name? - Space * get_object_field(const std::wstring & field); - const Space * get_object_field(const std::wstring & field) const; // may a better name? + Space * get_space(const wchar_t * field); + const Space * get_space(const wchar_t * field) const; + Space * get_space(const std::wstring & field); + const Space * get_space(const std::wstring & field) const; + // find for such a space in an object, if not found then create one + Space & get_add_space(const wchar_t * field); + Space & get_add_space(const std::wstring & field); bool * get_bool(const wchar_t * field); long long * get_llong(const wchar_t * field); long long * get_long_long(const wchar_t * field); float * get_float(const wchar_t * field); double * get_double(const wchar_t * field); + long double * get_long_double(const wchar_t * field); std::string * get_str(const wchar_t * field); std::wstring * get_wstr(const wchar_t * field); ObjectType * get_object(const wchar_t * field); @@ -466,6 +480,7 @@ public: const long long * get_long_long() const; const float * get_float() const; const double * get_double() const; + const long double * get_long_double() const; const std::string * get_str() const; const std::wstring * get_wstr() const; const ObjectType * get_object() const; @@ -480,6 +495,7 @@ public: const long long * get_long_long(const wchar_t * field) const; const float * get_float(const wchar_t * field) const; const double * get_double(const wchar_t * field) const; + const long double * get_long_double(const wchar_t * field) const; const std::string * get_str(const wchar_t * field) const; const std::wstring * get_wstr(const wchar_t * field) const; const ObjectType * get_object(const wchar_t * field) const; @@ -488,10 +504,10 @@ public: // no case, has O(n) complexity - Space * get_object_field_nc(const wchar_t * field); - Space * get_object_field_nc(const std::wstring & field); - const Space * get_object_field_nc(const wchar_t * field) const; - const Space * get_object_field_nc(const std::wstring & field) const; + Space * get_space_nc(const wchar_t * field); + Space * get_space_nc(const std::wstring & field); + const Space * get_space_nc(const wchar_t * field) const; + const Space * get_space_nc(const std::wstring & field) const; @@ -499,6 +515,29 @@ public: void remove(const wchar_t * field); void remove(const std::wstring & field); + // remove a table item + void remove(size_t table_index); + + template + void serialize_to_string(StreamType & stream) const + { + if( type == type_wstring ) + { + stream << value.value_wstring; + } + else + if( type == type_string ) + { + stream << value.value_string; + } + else + { + serialize_to_json_stream(stream); + } + } + + + std::string serialize_to_space_str(bool pretty_print = false) const; std::wstring serialize_to_space_wstr(bool pretty_print = false) const; @@ -510,7 +549,7 @@ public: { if( is_object() ) { - serialize_to_space_stream(str, pretty_print, 0, true); + serialize_to_space_stream(str, pretty_print, -1, true); } } @@ -524,6 +563,13 @@ public: template void serialize_to_json_stream(StreamType & str, bool pretty_print = false) const + { + serialize_to_json_stream(str, pretty_print, 0); + } + + // make me private + template + void serialize_to_json_stream(StreamType & str, bool pretty_print, int level) const { switch(type) { @@ -547,6 +593,10 @@ public: serialize_json_double(str); break; + case type_long_double: + serialize_json_long_double(str); + break; + case type_string: serialize_json_string(str); break; @@ -556,11 +606,11 @@ public: break; case type_object: - serialize_json_object(str); + serialize_json_object(str, pretty_print, level + 1); break; case type_table: - serialize_json_table(str); + serialize_json_table(str, pretty_print, level + 1); break; } } @@ -580,39 +630,7 @@ public: bool has_value(const wchar_t * field, const std::wstring & val) const; - // for child spaces (used only in Space format) - TableType * find_child_space_table(); - const TableType * find_child_space_table() const; - bool child_spaces_empty() const; - size_t child_spaces_size() const; - - Space * find_child_space(const wchar_t * name); - Space * find_child_space(const std::wstring & name); - const Space * find_child_space(const wchar_t * name) const; - const Space * find_child_space(const std::wstring & name) const; - - Space * find_child_space(size_t table_index); - const Space * find_child_space(size_t table_index) const; - - Space & add_child_space(); - Space & add_child_space(const wchar_t * space_name); - Space & add_child_space(const std::wstring & space_name); - - Space & find_add_child_space(const wchar_t * name); - Space & find_add_child_space(const std::wstring & name); - - std::wstring * find_child_space_name(); - const std::wstring * find_child_space_name() const; - - std::wstring get_child_space_name() const; - - bool is_child_space_name(const wchar_t * name) const; - bool is_child_space_name(const std::wstring & name) const; - - void remove_child_space(const wchar_t * name); - void remove_child_space(const std::wstring & name); - void remove_child_space(size_t index); protected: @@ -634,9 +652,16 @@ protected: Space & add_generic(const wchar_t * field, const ArgType & val) { initialize_value_object_if_needed(); - auto insert_res = value.value_object.insert(std::make_pair(field, nullptr)); - insert_res.first->second = new Space(val); + + if( insert_res.second ) + { + insert_res.first->second = new Space(val); + } + else + { + insert_res.first->second->set(val); + } return *(insert_res.first->second); } @@ -733,7 +758,7 @@ protected: if( clear_list ) output_list.clear(); - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -751,7 +776,7 @@ protected: if( clear_list ) output_list.clear(); - const Space * space = get_object_field(field); + const Space * space = get_space(field); if( space ) { @@ -948,7 +973,7 @@ protected: wchar_t buffer[100]; size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); - int chars_written = std::swprintf(buffer, buffer_len, L"%e", static_cast(value.value_float)); + int chars_written = std::swprintf(buffer, buffer_len, L"%g", static_cast(value.value_float)); if( errno == EOVERFLOW || chars_written < 0 ) buffer[0] = 0; @@ -962,7 +987,21 @@ protected: wchar_t buffer[100]; size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); - int chars_written = std::swprintf(buffer, buffer_len, L"%e", value.value_double); + int chars_written = std::swprintf(buffer, buffer_len, L"%g", value.value_double); + + if( errno == EOVERFLOW || chars_written < 0 ) + buffer[0] = 0; + + serialize_string_buffer(buffer, str, Escape::escape_space); + } + + template + void serialize_space_long_double(StreamType & str) const + { + wchar_t buffer[100]; + size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); + + int chars_written = std::swprintf(buffer, buffer_len, L"%Lg", value.value_long_double); if( errno == EOVERFLOW || chars_written < 0 ) buffer[0] = 0; @@ -992,19 +1031,26 @@ protected: if( !is_main_object ) { str << '{'; - print_if(pretty_print && (!value.value_object.empty() || !child_spaces_empty()), str, '\n'); } bool is_first = true; for(auto & map_item : value.value_object) { - if( !is_first ) - print_if(pretty_print, str, '\n', ','); + if( is_first ) + { + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); + } + else + { + str << ','; + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); + } bool quote_field = should_field_be_quoted(map_item.first); - print_level(pretty_print, level, str); print_if(quote_field, str, '"'); serialize_string_buffer(map_item.first.c_str(), str, Escape::escape_space); print_if(quote_field, str, '"'); @@ -1013,87 +1059,52 @@ protected: str << '='; print_if(pretty_print, str, ' '); - map_item.second->serialize_to_space_stream(str, pretty_print, level + 1, false); + map_item.second->serialize_to_space_stream(str, pretty_print, level, false); is_first = false; } - print_if(!is_first && pretty_print, str, '\n'); - serialize_child_spaces(str, pretty_print, level); - if( !is_main_object ) { - print_level(pretty_print, level - 1, str); + print_if(pretty_print && !is_first, str, '\n'); + print_level(pretty_print && !is_first, level - 1, str); str << '}'; - print_if(pretty_print, str, '\n'); } } - template - void serialize_child_spaces(StreamType & str, bool pretty_print, int level) const - { - const TableType * child_table = find_child_space_table(); - - if( child_table && !child_table->empty() ) - { - print_if(pretty_print, str, '\n'); - - for(Space * child_space : *child_table) - { - print_if(!pretty_print, str, ' '); - - const std::wstring * name = child_space->get_wstr(child_spaces_name); - - if( name && !name->empty() ) - { - bool quote_field = should_field_be_quoted(*name); - - print_level(pretty_print, level, str); - print_if(quote_field, str, '"'); - serialize_string_buffer(name->c_str(), str, Escape::escape_space); - print_if(quote_field, str, '"'); - - str << ' '; - } - - child_space->serialize_to_space_stream(str, pretty_print, level + 1, false); - print_if(pretty_print, str, '\n'); - } - } - } - template void serialize_space_table(StreamType & str, bool pretty_print, int level) const { - bool multivalue_table = false; bool is_first = true; - - if( value.value_table.size() > 1 ) - { - multivalue_table = true; - } - str << '('; - print_if(pretty_print && multivalue_table, str, '\n'); for(Space * space : value.value_table) { - if( !is_first ) - print_if(pretty_print, str, '\n', ','); + if( is_first ) + { + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); + } + else + { + str << ','; + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); + } - print_level(pretty_print && multivalue_table, level, str); - space->serialize_to_space_stream(str, pretty_print, level + 1, false); + space->serialize_to_space_stream(str, pretty_print, level, false); is_first = false; } - print_if(pretty_print && multivalue_table, str, '\n'); - print_level(pretty_print && multivalue_table, level - 1, str); + print_if(pretty_print && !is_first, str, '\n'); + print_level(pretty_print && !is_first, level - 1, str); str << ')'; } +protected: template @@ -1132,7 +1143,7 @@ protected: wchar_t buffer[100]; size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); - int chars_written = std::swprintf(buffer, buffer_len, L"%e", static_cast(value.value_float)); + int chars_written = std::swprintf(buffer, buffer_len, L"%g", static_cast(value.value_float)); if( errno == EOVERFLOW || chars_written < 0 ) buffer[0] = 0; @@ -1146,7 +1157,21 @@ protected: wchar_t buffer[100]; size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); - int chars_written = std::swprintf(buffer, buffer_len, L"%e", value.value_double); + int chars_written = std::swprintf(buffer, buffer_len, L"%g", value.value_double); + + if( errno == EOVERFLOW || chars_written < 0 ) + buffer[0] = 0; + + serialize_string_buffer(buffer, str, Escape::escape_json); + } + + template + void serialize_json_long_double(StreamType & str) const + { + wchar_t buffer[100]; + size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); + + int chars_written = std::swprintf(buffer, buffer_len, L"%Lg", value.value_long_double); if( errno == EOVERFLOW || chars_written < 0 ) buffer[0] = 0; @@ -1171,53 +1196,70 @@ protected: } template - void serialize_json_object(StreamType & str) const + void serialize_json_object(StreamType & str, bool pretty_print, int level) const { str << '{'; - bool is_first = true; for(auto & map_item : value.value_object) { - if( !is_first ) + if( is_first ) + { + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); + } + else { str << ','; + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); } str << '"'; serialize_string_buffer(map_item.first.c_str(), str, Escape::escape_json); str << '"'; str << ':'; - map_item.second->serialize_to_json_stream(str); + print_if(pretty_print, str, ' '); + map_item.second->serialize_to_json_stream(str, pretty_print, level); is_first = false; } + print_if(pretty_print && !is_first, str, '\n'); + print_level(pretty_print && !is_first, level - 1, str); str << '}'; } template - void serialize_json_table(StreamType & str) const + void serialize_json_table(StreamType & str, bool pretty_print, int level) const { str << '['; - bool is_first = true; for(Space * space : value.value_table) { - if( !is_first ) + if( is_first ) + { + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); + } + else { str << ','; + print_if(pretty_print, str, '\n'); + print_level(pretty_print, level, str); } - space->serialize_to_json_stream(str); + space->serialize_to_json_stream(str, pretty_print, level); is_first = false; } + print_if(pretty_print && !is_first, str, '\n'); + print_level(pretty_print && !is_first, level - 1, str); str << ']'; } -protected: + template void serialize_to_space_stream(StreamType & str, bool pretty_print, int level, bool is_main_object) const @@ -1244,6 +1286,10 @@ protected: serialize_space_double(str); break; + case type_long_double: + serialize_space_long_double(str); + break; + case type_string: serialize_space_string(str); break; @@ -1253,11 +1299,11 @@ protected: break; case type_object: - serialize_space_object(str, pretty_print, level, is_main_object); + serialize_space_object(str, pretty_print, level + 1, is_main_object); break; case type_table: - serialize_space_table(str, pretty_print, level); + serialize_space_table(str, pretty_print, level + 1); break; } } @@ -1303,17 +1349,7 @@ protected: str << c; } - template - void print_if(bool condition, StreamType & str, wchar_t c1, wchar_t c2) const - { - if( condition ) - str << c1; - else - str << c2; - } - - void copy_value_from(const Space & space); void copy_from(const Space & space); void copy_value_object(const Value & value_from); @@ -1328,6 +1364,7 @@ protected: void initialize_value_long_if_needed(); void initialize_value_float_if_needed(); void initialize_value_double_if_needed(); + void initialize_value_long_double_if_needed(); void initialize_value_string_if_needed(); void initialize_value_string_if_needed(std::string && str); void initialize_value_wstring_if_needed(); @@ -1336,16 +1373,12 @@ protected: void initialize_value_object_if_needed(ObjectType && obj); void initialize_value_table_if_needed(); void initialize_value_table_if_needed(TableType && tab); - void initialize_child_spaces_if_needed(); void remove_value(); void remove_value_string(); void remove_value_wstring(); - void remove_value_object(); - void remove_value_table(); - - const Space * find_child_space_const(const wchar_t * name) const; - const Space * find_child_space_const(size_t table_index) const; + void remove_value_object(bool only_clear = false); + void remove_value_table(bool only_clear = false); }; diff --git a/src/space/spaceparser.cpp b/src/space/spaceparser.cpp index 0fb5570..ccd905e 100644 --- a/src/space/spaceparser.cpp +++ b/src/space/spaceparser.cpp @@ -499,7 +499,7 @@ void SpaceParser::parse_key_value_pairs(Space * space) if( parsing_space ) { - // in space format a space_end character is allowed to be after the last table item + // in space format a space_end character is allowed to be after the option_delimiter skip_white(); if( lastc == space_end ) @@ -530,12 +530,6 @@ void SpaceParser::parse_key_value_pairs(Space * space) parse(&new_space, true, false); } else - if( parsing_space && lastc == space_start ) - { - Space & new_space = space->add_child_space(token.c_str()); - parse_space(&new_space); - } - else { status = syntax_error; } diff --git a/src/textstream/stream.h b/src/textstream/stream.h new file mode 100644 index 0000000..cb3e83b --- /dev/null +++ b/src/textstream/stream.h @@ -0,0 +1,149 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 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_stream +#define headerfile_picotools_textstream_stream + +#include + + +#ifdef PT_HAS_MORM_LIBRARY +namespace morm +{ + class Model; +} +#endif + + + +namespace pt +{ +class Space; +class Date; + + + + +class Stream +{ +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; + virtual void reserve(size_t len) = 0; + virtual size_t capacity() const = 0; + + virtual void to_str(std::string & str, bool clear_string = true) const = 0; + virtual void to_str(std::wstring & str, bool clear_string = true) const = 0; + + 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; + virtual Stream & operator<<(bool) = 0; + virtual Stream & operator<<(short) = 0; + virtual Stream & operator<<(int) = 0; + virtual Stream & operator<<(long) = 0; + virtual Stream & operator<<(long long) = 0; + virtual Stream & operator<<(unsigned short) = 0; + virtual Stream & operator<<(unsigned int) = 0; + virtual Stream & operator<<(unsigned long) = 0; + virtual Stream & operator<<(unsigned long long) = 0; + virtual Stream & operator<<(float) = 0; + 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; + +#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 + + virtual Stream & write(const char * buf, size_t len) = 0; + virtual Stream & write(const wchar_t * buf, size_t len) = 0; + +}; + + +} + + +#endif diff --git a/src/textstream/textstream.h b/src/textstream/textstream.h index 1ad96cc..772a073 100644 --- a/src/textstream/textstream.h +++ b/src/textstream/textstream.h @@ -39,16 +39,18 @@ #define headerfile_picotools_textstream_textstream #include +#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 + namespace pt { @@ -58,10 +60,9 @@ namespace pt 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 +class TextStreamBase : public Stream { public: @@ -74,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; @@ -86,47 +90,59 @@ public: 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; + // 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; + + 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<<(const std::wstring & str); TextStreamBase & operator<<(char); + TextStreamBase & operator<<(unsigned char); TextStreamBase & operator<<(wchar_t); + 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 + TextStreamBase & operator<<(const TextStreamBase & arg); + + + // 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 & 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); @@ -136,6 +152,13 @@ public: int radix; size_t min_width_for_integers; buffer_type buffer; + + +protected: + + void put_stream(const Stream & stream); + + }; @@ -150,6 +173,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() { @@ -215,7 +264,7 @@ TextStreamBase::end() const template -void TextStreamBase::to_string(std::string & str, bool clear_string) const +void TextStreamBase::to_str(std::string & str, bool clear_string) const { if( clear_string ) str.clear(); @@ -223,16 +272,24 @@ void TextStreamBase::to_string(std::stri if( str.capacity() < str.size() + size() ) str.reserve(str.size() + size()); - const_iterator i = begin(); - for( ; i != end() ; ++i) - str += static_cast(*i); + if constexpr (sizeof(char_type) == sizeof(char) ) + { + const_iterator i = begin(); + + for( ; i != end() ; ++i) + str += *i; + } + else + { + wide_stream_to_utf8(*this, str); + } } template -void TextStreamBase::to_string(std::wstring & str, bool clear_string) const +void TextStreamBase::to_str(std::wstring & str, bool clear_string) const { if( clear_string ) str.clear(); @@ -240,14 +297,64 @@ void TextStreamBase::to_string(std::wstr if( str.capacity() < str.size() + size() ) str.reserve(str.size() + size()); - const_iterator i = begin(); + if constexpr (sizeof(char_type) == sizeof(wchar_t) ) + { + const_iterator i = begin(); - for( ; i != end() ; ++i) - str += static_cast(*i); + for( ; i != end() ; ++i) + str += *i; + } + else + { + // IMPROVE ME don't use a temporary object + std::string utf8; + to_str(utf8); + utf8_to_wide(utf8, str, false); + } } +template +std::string TextStreamBase::to_str() const +{ + std::string str; + to_str(str, false); + + return str; +} + + +template +std::wstring TextStreamBase::to_wstr() const +{ + std::wstring str; + to_str(str, false); + + return str; +} + + +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 char_type & TextStreamBase::operator[](size_t index) @@ -267,8 +374,15 @@ template TextStreamBase & TextStreamBase::operator<<(const char * str) { - for( ; *str ; ++str) - buffer.append(static_cast(*str)); + if constexpr ( sizeof(char_type) == sizeof(char) ) + { + for( ; *str ; ++str) + buffer.append(*str); + } + else + { + utf8_to_wide(str, *this, false); + } return *this; } @@ -278,10 +392,7 @@ 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()); + operator<<(str.c_str()); return *this; } @@ -292,8 +403,15 @@ template TextStreamBase & TextStreamBase::operator<<(const wchar_t * str) { - for( ; *str ; ++str) - buffer.append(static_cast(*str)); + if constexpr (sizeof(char_type) == sizeof(wchar_t) ) + { + for( ; *str ; ++str) + buffer.append(*str); + } + else + { + wide_to_utf8(str, *this); + } return *this; } @@ -304,10 +422,7 @@ 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()); + operator<<(str.c_str()); return *this; } @@ -318,6 +433,22 @@ template TextStreamBase & TextStreamBase::operator<<(char v) { + // IMPROVEME + // if char_type == 1 then if v <= 127 then put that char but if (unsigned)v > 127 put replacement character + // if char_type > 1 then simply put that character + buffer.append(static_cast(v)); + +return *this; +} + + +template +TextStreamBase & +TextStreamBase::operator<<(unsigned char v) +{ + // IMPROVEME + // if char_type == 1 then if v <= 127 then put that char but if v > 127 put replacement character + // if char_type > 1 then simply put that character buffer.append(static_cast(v)); return *this; @@ -328,12 +459,32 @@ template TextStreamBase & TextStreamBase::operator<<(wchar_t v) { + // IMPROVEME add utf8/wide conversion, if v is from surrogate pair we can skip it buffer.append(static_cast(v)); return *this; } +template +TextStreamBase & +TextStreamBase::operator<<(bool v) +{ + char c = v ? '1' : '0'; + buffer.append(static_cast(c)); + +return *this; +} + + +template +TextStreamBase & +TextStreamBase::operator<<(short v) +{ + return operator<<(static_cast(v)); +} + + template TextStreamBase & TextStreamBase::operator<<(int v) @@ -368,6 +519,14 @@ return *this; } +template +TextStreamBase & +TextStreamBase::operator<<(unsigned short v) +{ + return operator<<(static_cast(v)); +} + + template TextStreamBase & TextStreamBase::operator<<(unsigned int v) @@ -402,13 +561,31 @@ return *this; } +template +TextStreamBase & +TextStreamBase::operator<<(float v) +{ + return operator<<(static_cast(v)); +} + template TextStreamBase & TextStreamBase::operator<<(double v) { char buf[100]; - snprintf(buf, sizeof(buf)/sizeof(char), "%f", v); + snprintf(buf, sizeof(buf)/sizeof(char), "%g", v); + return operator<<(buf); +} + + +template +TextStreamBase & +TextStreamBase::operator<<(long double v) +{ +char buf[100]; + + snprintf(buf, sizeof(buf)/sizeof(char), "%Lg", v); return operator<<(buf); } @@ -433,12 +610,20 @@ return *this; + template -template TextStreamBase & -TextStreamBase::write(const in_buffer_type * buf, size_t len) +TextStreamBase::write(const char * str, size_t len) { - buffer.append(buf, 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; } @@ -446,23 +631,73 @@ return *this; template TextStreamBase & -TextStreamBase::write(const char * format, double val) +TextStreamBase::write(const wchar_t * str, size_t len) { -char buf[100]; + 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); + } - snprintf(buf, sizeof(buf)/sizeof(char), format, val); - return operator<<(buf); +return *this; } + template TextStreamBase & -TextStreamBase::write(const wchar_t * format, double val) +TextStreamBase::operator<<(const Stream & stream) { -wchar_t buf[100]; + put_stream(stream); + return *this; +} - swprintf(buf, sizeof(buf)/sizeof(wchar_t), format, val); - return operator<<(buf); + + +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 + 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"); + } } @@ -488,20 +723,28 @@ return *this; } - 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 d891dd6..cd488d4 100644 --- a/src/utf8/utf8.cpp +++ b/src/utf8/utf8.cpp @@ -35,6 +35,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include "utf8.h" #include "utf8_private.h" @@ -290,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/textstream.h" +#include "textstream/stream.h" namespace pt @@ -60,6 +60,8 @@ namespace pt /*! returns true if 'c' is a correct unicode character + + RENAMEME to is_correct_unicode_char */ bool utf8_check_range(int c); @@ -121,6 +123,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); + /*! @@ -143,6 +154,8 @@ bool utf8_to_wide(const std::string & utf8, StreamType & res, bool clear = true, template bool utf8_to_wide(std::istream & utf8, StreamType & res, bool clear = true, int mode = 1); // need to be tested +template +bool utf8_to_wide(const Stream & stream, StreamType & res, bool clear = true, int mode = 1); /* @@ -196,8 +209,11 @@ bool wide_to_utf8(const std::wstring & wide_string, char * utf8, s template void wide_stream_to_utf8(StreamType & buffer, std::string & utf8, bool clear = true, int mode = 1); // not tested +template +bool wide_stream_to_utf8(const Stream & stream, StreamType & utf8, bool clear = true, int mode = 1); + template -void wide_stream_to_utf8(StreamTypeIn & buffer, StreamTypeOut & utf8, int mode = 1); // not tested +void wide_stream_to_utf8(StreamTypeIn & buffer, StreamTypeOut & utf8, int mode = 1); // not tested, IMPROVE ME add clear parameter, mode parameter is not used diff --git a/src/utf8/utf8_private.h b/src/utf8/utf8_private.h index 1fb3726..c9b33d9 100644 --- a/src/utf8/utf8_private.h +++ b/src/utf8/utf8_private.h @@ -38,7 +38,7 @@ #ifndef headerfile_picotools_utf8_utf8_private #define headerfile_picotools_utf8_utf8_private -#include "textstream/textstream.h" +#include namespace pt @@ -166,35 +166,17 @@ 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); - } -} - - -// not tested // FIX ME it is not using surrogate pairs from input stream -// and mode parameter -template -void wide_to_utf8_generic(TextStreamBase & buffer, int mode, function_type write_function) +// and is not using mode parameter +template +void wide_to_utf8_generic(StreamType & buffer, int mode, function_type write_function) { char utf8_buffer[256]; std::size_t buffer_len = sizeof(utf8_buffer) / sizeof(char); std::size_t utf8_sequence_max_length = 10; std::size_t index = 0; - typename TextStreamBase::const_iterator i = buffer.begin(); + typename StreamType::const_iterator i = buffer.begin(); while( i != buffer.end() ) { diff --git a/src/utf8/utf8_templates.h b/src/utf8/utf8_templates.h index d4a5744..a0f7613 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); } } @@ -118,6 +136,59 @@ return !was_error; } +/* +this function converts a UTF-8 stream into wide stream + +input: + stream - a UTF-8 stream for converting + mode - what to do with errors when converting + 0: skip an invalid character + 1: put U+FFFD "replacement character" istead of the invalid character (default) + +output: + res - a wide stream for the output sequence + + this function returns false if there were some errors when converting +*/ +template +bool utf8_to_wide(const Stream & stream, StreamType & res, bool clear, int mode) +{ + size_t len; + bool correct; + int z; + size_t index = 0; + bool was_error = false; + + if( clear ) + res.clear(); + + // CHECKME test me when sizeof(wchar_t) is 2 + + do + { + len = utf8_to_int(stream, index, z, correct); + + if( len > 0 ) + { + if( !correct ) + { + if( mode == 1 ) + res << 0xFFFD; // U+FFFD "replacement character" + + was_error = true; + } + else + { + int_to_wide(z, res); + } + + index += len; + } + } + while( len > 0 ); + + return !was_error; +} @@ -250,6 +321,59 @@ void wide_stream_to_utf8(StreamType & buffer, std::string & utf8, bool clear, in } + +template +bool wide_stream_to_utf8(const Stream & stream, StreamType & utf8, bool clear, int mode) +{ + bool was_error = false; + + if( clear ) + utf8.clear(); + + for(size_t i=0 ; i < stream.size() ; ++i) + { + int c = static_cast(stream.get_wchar(i)); + bool is_correct = false; + + if( utf8_check_range(c) ) + { + // CHECKME test me when sizeof(wchar_t) == 2 + if( is_first_surrogate_char(c) ) + { + if( i + 1 < stream.size() ) + { + wchar_t c1 = static_cast(c); + wchar_t c2 = stream.get_wchar(++i); + + if( surrogate_pair_to_int(c1, c2, c) ) + { + is_correct = true; + } + } + } + else + { + is_correct = true; + } + } + + if( is_correct ) + { + int_to_utf8(c, utf8); + } + else + { + was_error = true; + + if( mode == 1 ) + int_to_utf8(0xFFFD, utf8); // U+FFFD "replacement character" + } + } + + return !was_error; +} + + // not tested template void wide_stream_to_utf8(StreamTypeIn & buffer, StreamTypeOut & utf8, int mode) diff --git a/tests/Makefile.dep b/tests/Makefile.dep index 7af1bb8..85bda87 100644 --- a/tests/Makefile.dep +++ b/tests/Makefile.dep @@ -3,23 +3,30 @@ ./main.o: convert.h mainoptionsparser.h csvparser.h ./convert.o: convert.h test.h ../src/convert/convert.h ./convert.o: ../src/convert/inttostr.h ../src/convert/patternreplacer.h -./convert.o: ../src/textstream/textstream.h ../src/space/space.h -./convert.o: ../src/textstream/types.h ../src/convert/inttostr.h -./convert.o: ../src/date/date.h ../src/membuffer/membuffer.h -./convert.o: ../src/textstream/types.h ../src/convert/strtoint.h -./convert.o: ../src/convert/text.h ../src/convert/misc.h +./convert.o: ../src/textstream/textstream.h ../src/textstream/stream.h +./convert.o: ../src/space/space.h ../src/textstream/types.h +./convert.o: ../src/convert/inttostr.h ../src/utf8/utf8.h +./convert.o: ../src/textstream/stream.h ../src/utf8/utf8_templates.h +./convert.o: ../src/utf8/utf8_private.h ../src/date/date.h +./convert.o: ../src/membuffer/membuffer.h ../src/textstream/types.h +./convert.o: ../src/convert/strtoint.h ../src/convert/text.h +./convert.o: ../src/convert/misc.h ../src/convert/double.h ./test.o: test.h ./mainoptionsparser.o: mainoptionsparser.h test.h ./mainoptionsparser.o: ../src/mainoptions/mainoptionsparser.h ./mainoptionsparser.o: ../src/space/space.h ../src/textstream/types.h ./mainoptionsparser.o: ../src/convert/inttostr.h ../src/utf8/utf8.h -./mainoptionsparser.o: ../src/textstream/textstream.h ../src/date/date.h -./mainoptionsparser.o: ../src/membuffer/membuffer.h ../src/textstream/types.h +./mainoptionsparser.o: ../src/textstream/stream.h ./mainoptionsparser.o: ../src/utf8/utf8_templates.h ./mainoptionsparser.o: ../src/utf8/utf8_private.h ../src/convert/convert.h ./mainoptionsparser.o: ../src/convert/inttostr.h ./mainoptionsparser.o: ../src/convert/patternreplacer.h +./mainoptionsparser.o: ../src/textstream/textstream.h +./mainoptionsparser.o: ../src/textstream/stream.h ../src/date/date.h +./mainoptionsparser.o: ../src/membuffer/membuffer.h ../src/textstream/types.h ./mainoptionsparser.o: ../src/convert/strtoint.h ../src/convert/text.h -./mainoptionsparser.o: ../src/convert/misc.h +./mainoptionsparser.o: ../src/convert/misc.h ../src/convert/double.h ./csvparser.o: csvparser.h ../src/csv/csvparser.h ../src/space/space.h -./csvparser.o: ../src/textstream/types.h ../src/convert/inttostr.h test.h +./csvparser.o: ../src/textstream/types.h ../src/convert/inttostr.h +./csvparser.o: ../src/utf8/utf8.h ../src/textstream/stream.h +./csvparser.o: ../src/utf8/utf8_templates.h ../src/utf8/utf8_private.h test.h