diff --git a/ChangeLog b/ChangeLog index 94f2992c..726c2ddd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2017-04-17 Markus Gans * Speed up FString::setNumber() by using a decimal string lookup table + * FString allocates no new memory if the size sufficient. 2017-04-15 Markus Gans * Fix unsigned integer underflow in FString::_insert() diff --git a/src/fstring.cpp b/src/fstring.cpp index b80ccd0f..dbe3506a 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -51,7 +51,7 @@ FString::FString (int len, wchar_t c) , c_string(0) { if ( len > 0 ) - _replace ( FString(uInt(len), c).string ); + _assign ( FString(uInt(len), c).string ); else initLength(0); } @@ -87,7 +87,7 @@ FString::FString (int len, char c) c_string = 0; if ( len > 0 ) - _replace ( FString(uInt(len), c).string ); + _assign ( FString(uInt(len), c).string ); else initLength(0); } @@ -118,7 +118,7 @@ FString::FString (const FString& s) // copy constructor , c_string(0) { if ( s.string ) - _replace (s.string); + _assign (s.string); } //---------------------------------------------------------------------- @@ -129,7 +129,7 @@ FString::FString (const std::wstring& s) , c_string(0) { if ( ! s.empty() ) - _replace ( s.c_str() ); + _assign ( s.c_str() ); } //---------------------------------------------------------------------- @@ -140,7 +140,7 @@ FString::FString (const wchar_t* s) , c_string(0) { if ( s ) - _replace (s); + _assign (s); } //---------------------------------------------------------------------- @@ -158,7 +158,7 @@ FString::FString (const std::string& s) if ( wc_string ) { - _replace( wc_string ); + _assign( wc_string ); delete[] wc_string; } } @@ -175,7 +175,7 @@ FString::FString (const char* s) if ( wc_string ) { - _replace( wc_string ); + _assign (wc_string); delete[] wc_string; } } @@ -190,7 +190,7 @@ FString::FString (const wchar_t c) wchar_t s[2]; s[0] = c; s[1] = L'\0'; - _replace (s); + _assign (s); } //---------------------------------------------------------------------- @@ -203,7 +203,7 @@ FString::FString (const char c) wchar_t s[2]; s[0] = wchar_t(c & 0xff); s[1] = L'\0'; - _replace (s); + _assign (s); } //---------------------------------------------------------------------- @@ -222,7 +222,7 @@ FString::~FString() // destructor FString& FString::operator = (const FString& s) { if ( s ) - _replace (s.string); + _assign (s.string); else clear(); @@ -233,7 +233,7 @@ FString& FString::operator = (const FString& s) FString& FString::operator = (const std::wstring& s) { if ( ! s.empty() ) - _replace (s.c_str()); + _assign (s.c_str()); else clear(); @@ -244,7 +244,7 @@ FString& FString::operator = (const std::wstring& s) const FString& FString::operator = (const wchar_t* s) { if ( s ) - _replace (s); + _assign (s); else clear(); @@ -258,7 +258,7 @@ FString& FString::operator = (const std::string& s) if ( wc_string ) { - _replace( wc_string ); + _assign( wc_string ); delete[] wc_string; } else @@ -274,7 +274,7 @@ const FString& FString::operator = (const char* s) if ( wc_string ) { - _replace( wc_string ); + _assign( wc_string ); delete[] wc_string; } else @@ -289,7 +289,7 @@ const FString& FString::operator = (const wchar_t c) wchar_t s[2]; s[0] = c; s[1] = L'\0'; - _replace (s); + _assign (s); return (*this); } @@ -299,7 +299,7 @@ const FString& FString::operator = (const char c) wchar_t s[2]; s[0] = wchar_t(c & 0xff); s[1] = L'\0'; - _replace (s); + _assign (s); return (*this); } @@ -502,7 +502,7 @@ FString& FString::sprintf (const wchar_t* format, ...) std::vswprintf (buffer, buf_size, format, args); va_end (args); - _replace (buffer); + _assign (buffer); return (*this); } @@ -532,7 +532,7 @@ FString& FString::sprintf (const char* format, ...) if ( wc_string ) { - _replace(wc_string); + _assign(wc_string); delete[] wc_string; } @@ -974,7 +974,7 @@ std::vector FString::split (const FString& delimiter) //---------------------------------------------------------------------- FString& FString::setString (const wchar_t* s) { - _replace (s); + _assign (s); return (*this); } @@ -985,7 +985,7 @@ FString& FString::setString (const char* s) if ( wc_string ) { - _replace (wc_string); + _assign (wc_string); delete[] wc_string; } @@ -1023,7 +1023,7 @@ FString& FString::setNumber (long num) if ( neg ) *--s = '-'; - _replace (s); + _assign (s); return *this; } @@ -1043,7 +1043,7 @@ FString& FString::setNumber (uLong num) } while ( num ); - _replace (s); + _assign (s); return *this; } @@ -1113,7 +1113,7 @@ FString& FString::setFormatedNumber (long num, char separator) if ( neg ) *--s = '-'; - _replace (s); + _assign (s); return *this; } @@ -1142,7 +1142,7 @@ FString& FString::setFormatedNumber (uLong num, char separator) } while ( num ); - _replace (s); + _assign (s); return *this; } @@ -2212,30 +2212,33 @@ inline void FString::initLength (uInt len) } //---------------------------------------------------------------------- -inline void FString::_replace (const wchar_t* s) +inline void FString::_assign (const wchar_t* s) { - if ( string ) - delete[](string); - - length = uInt(std::wcslen(s)); - bufsize = FWDBUFFER + length + 1; - - try - { - string = new wchar_t[bufsize](); - } - catch (const std::bad_alloc& ex) - { - std::cerr << bad_alloc_str << ex.what() << std::endl; + if ( s == string ) return; - } -/* catch (std::exception& e) + + uInt new_length = uInt(std::wcslen(s)); + + if ( ! string || new_length > bufsize - 1 ) { - std::cerr << "not enough memory for a new FString object " - << e.what() << std::endl; - return; - }*/ + if ( string ) + delete[](string); + + bufsize = FWDBUFFER + new_length + 1; + + try + { + string = new wchar_t[bufsize](); + } + catch (const std::bad_alloc& ex) + { + std::cerr << bad_alloc_str << ex.what() << std::endl; + return; + } + } + std::wcsncpy (string, s, bufsize); + length = new_length; } //---------------------------------------------------------------------- @@ -2517,7 +2520,7 @@ std::istream& operator >> (std::istream& instr, FString& s) if ( wc_str ) { - s._replace (wc_str); + s._assign (wc_str); delete[] wc_str; } @@ -2538,7 +2541,7 @@ std::wistream& operator >> (std::wistream& instr, FString& s) { wchar_t buf[FString::INPBUFFER + 1]; instr.getline (buf, FString::INPBUFFER); - s._replace (buf); + s._assign (buf); return (instr); } diff --git a/src/fstring.h b/src/fstring.h index 23f6515c..b4bf42ca 100644 --- a/src/fstring.h +++ b/src/fstring.h @@ -330,7 +330,7 @@ class FString // Methods void initLength (uInt); - void _replace (const wchar_t*); + void _assign (const wchar_t*); void _insert (uInt, uInt, const wchar_t*); void _remove (uInt, uInt); char* wc_to_c_str (const wchar_t*) const; diff --git a/test/string-operations.cpp b/test/string-operations.cpp index 8c3869f8..afe8610d 100644 --- a/test/string-operations.cpp +++ b/test/string-operations.cpp @@ -28,58 +28,96 @@ int main (int, char**) std::cout << "--------------[ FString test ]-----------------" << std::endl; + // Test: input stream (operator >>) FString in; std::cout << " Input: "; std::cin >> in; std::cout << " instream >> " << in << std::endl; + // Test: output stream (operator <<) FString out = L"A test string for 0 \x20ac"; - std::cout << " outstream << " << out.c_str() << std::endl; + std::cout << " outstream << " << out << std::endl; + + // Test: c-string output printf (" c_str: \"%s\"\n", out.c_str()); + // Test: copy a c++ string FString cpp_str( std::string("c++ String") ); std::cout << " cpp_str: \"" << cpp_str << "\"" << std::endl; + + // Test: copy a character FString ch('c'); std::cout << " char: '" << ch << "'" << std::endl; + + // Test: copy a wide character FString wch(L'w'); std::cout << " wchar_t: '" << wch << "'" << std::endl; + // Test: utf-8 string FString len = "длина́"; std::cout << " length: \"" << len << "\" has " << len.getLength() << " characters" << std::endl; + // Test: convert uppercase letter to lowercase FString lower = FString(L"InPut").toLower(); std::wcout << L" toLower: " << lower << std::endl; + + // Test: convert lowercase letter to uppercase FString upper = FString("inPut").toUpper(); std::cout << " toUpper: " << upper << std::endl; + // Test: concatenate two FStrings (operator +) FString add1 = FString("FString + ") + FString("FString"); std::cout << " add: " << add1 << std::endl; + + // Test: concatenate a FString and a c++ wide string (operator +) FString add2 = FString("FString + ") + std::wstring(L"std::wstring"); std::cout << " add: " << add2 << std::endl; + + // Test: concatenate a FString and a wide string (operator +) FString add3 = FString("FString + ") + const_cast(L"wchar_t*"); std::cout << " add: " << add3 << std::endl; + + // Test: concatenate a FString and a c++ string (operator +) FString add4 = FString("FString + ") + std::string("std::string"); std::cout << " add: " << add4 << std::endl; + + // Test: concatenate a FString and a c-string (operator +) FString add5 = FString("FString + ") + const_cast("char*"); std::cout << " add: " << add5 << std::endl; + + // Test: concatenate a FString and a wide character (operator +) FString add6 = FString("FString + ") + wchar_t(L'w'); std::cout << " add: " << add6 << std::endl; + + // Test: concatenate a FString and a character (operator +) FString add7 = FString("FString + ") + char('c'); std::cout << " add: " << add7 << std::endl; + // Test: concatenate a character and a FString (operator +) FString add8 = 'c' + FString(" + FString"); std::cout << " add: " << add8 << std::endl; + + // Test: concatenate a wide character and a FString (operator +) FString add9 = L'w' + FString(" + FString"); std::cout << " add: " << add9 << std::endl; + + // Test: concatenate a c-string and a FString (operator +) FString add10 = const_cast("char*") + FString(" + FString"); std::cout << " add: " << add10 << std::endl; + + // Test: concatenate a c++ string and a FString (operator +) FString add11 = std::string("std::string") + FString(" + FString"); std::cout << " add: " << add11 << std::endl; + + // Test: concatenate a wide string and a FString (operator +) FString add12 = const_cast(L"wchar_t*") + FString(" + FString"); std::cout << " add: " << add12 << std::endl; + + // Test: concatenate a c++ wide string and a FString (operator +) FString add13 = std::wstring(L"std::wstring") + FString(" + FString"); std::cout << " add: " << add13 << std::endl; + // Test: compare operators ==, <=, <, >=, >, != FString cmp = "compare"; if ( cmp == FString("compare") ) @@ -112,6 +150,7 @@ int main (int, char**) else std::cout << " cmp: != Not Ok" << std::endl; + // Test: split a string with a delimiter and returns a vector (array) FString split_str = "a,b,c,d"; std::cout << " split: \"" << split_str << "\" into substrings ->"; @@ -124,10 +163,13 @@ int main (int, char**) std::cout << std::endl; + // Test: format a string with sprintf FString formatStr = ""; std::cout << " formatted: " << formatStr.sprintf("sqrt(%d) = %d", 16, 4) << std::endl; + + // Test: convert a string to a unsigned long interger try { uLong ulong_num = FString("123456789").toULong(); @@ -142,6 +184,7 @@ int main (int, char**) std::cerr << "Arithmetic error: " << ex.what() << std::endl; } + // Test: convert a string to a signed long interger try { long long_num = FString("-9876543210").toLong(); @@ -156,6 +199,7 @@ int main (int, char**) std::cerr << "Arithmetic error: " << ex.what() << std::endl; } + // Test: convert a string to a double value std::setlocale(LC_NUMERIC, "C"); try @@ -175,6 +219,7 @@ int main (int, char**) std::cerr << "Arithmetic error: " << ex.what() << std::endl; } + // Test: convert integer and double value to a string FString num1, num2, num3; num1.setNumber(137); num2.setNumber(-512); @@ -186,6 +231,7 @@ int main (int, char**) std::cout << " setNumber: " << num3 << " (long double)" << std::endl; + // Test: convert and format a integer number with thousand separator std::setlocale (LC_NUMERIC, ""); FString fnum1, fnum2; #if defined(__LP64__) || defined(_LP64) @@ -202,22 +248,33 @@ int main (int, char**) std::cout << "setFormatedNumber: " << fnum2 << " (signed)" << std::endl; + // Test: remove whitespace from the end of a string FString trim_str = " A string \t"; std::wcout << " rtrim: \"" << trim_str.rtrim() << "\"" << std::endl; + + // Test: remove whitespace from the beginning of a string std::cout << " ltrim: \"" << trim_str.ltrim() << "\"" << std::endl; + + // Test: remove whitespace from the beginning and end of a string std::cout << " trim: \"" << trim_str.trim() << "\"" << std::endl; + // Test: 11 characters from the left of the string FString alphabet = "a b c d e f g h i j k l m n o p q r s t u v w x y z"; std::cout << " left: \"" << alphabet.left(11) << "\"" << std::endl; + + // Test: extract a substring of 27 characters from position 12 std::cout << " mid: \"" << alphabet.mid(13,27) << "\"" << std::endl; + + // Test: 11 characters from the right of the string std::cout << " right: \"" << alphabet.right(11) << "\"" << std::endl; + // Test: insert a string at index position 7 FString insert_str = "I am a string"; try @@ -230,7 +287,8 @@ int main (int, char**) std::cerr << "Out of Range error: " << ex.what() << std::endl; } - FString index(5); // a string with five characters + // Test: get character access at a specified index position + FString index(5); // string with five characters index = "index"; try @@ -245,6 +303,7 @@ int main (int, char**) std::cerr << "Out of Range error: " << ex.what() << std::endl; } + // Test: character access with std::iterator FString stringIterator = "iterator"; FString::iterator iter; iter = stringIterator.begin(); @@ -260,14 +319,17 @@ int main (int, char**) << "', back='" << char(stringIterator.back()) << "')" << std::endl; + // Test: overwrite string at position 10 with "for t" FString overwrite_std = "Overwrite the rest"; std::cout << "overwrite: " << overwrite_std.overwrite("for t", 10) << std::endl; + // Test: remove 2 characters at position 7 FString remove_std = "A fast remove"; std::cout << " remove: " << remove_std.remove(7,2) << std::endl; + // Test: includes a substring (positive test) FString include_std = "string"; if ( include_std.includes("ring") ) @@ -279,6 +341,7 @@ int main (int, char**) << include_std << "\" includes no \"ring\" " << std::endl; + // Test: includes a substring (negativ test) if ( include_std.includes("data") ) std::cout << " includes: \"" << include_std << "\" includes \"data\" " @@ -288,19 +351,23 @@ int main (int, char**) << include_std << "\" includes no \"data\" " << std::endl; + // Test: find and replace a substring FString source_str = "computer and software"; FString replace_str = source_str.replace("computer", "hard-"); std::cout << " replace: " << replace_str << std::endl; + // Test: convert tabs to spaces FString tab_str = "1234\t5678"; std::cout << " tab: " << tab_str.expandTabs() << std::endl; + // Test: backspaces remove characters in the string FString bs_str = "t\b\bTesT\bt"; std::cout << "backspace: " << bs_str.removeBackspaces() << std::endl; + // Test: delete characters remove characters in the string FString del_str = "apple \177\177\177pietree"; std::cout << " delete: " << del_str.removeDel() << std::endl;