diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:23:19 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:23:19 +0200 |
commit | 0887aee8c54d0ed51bb2031431e2bcdafebb4c6e (patch) | |
tree | 69537ceb9787bb25ac363cc4e6cdaf0804d78363 /zen/zstring.cpp | |
parent | 5.12 (diff) | |
download | FreeFileSync-0887aee8c54d0ed51bb2031431e2bcdafebb4c6e.tar.gz FreeFileSync-0887aee8c54d0ed51bb2031431e2bcdafebb4c6e.tar.bz2 FreeFileSync-0887aee8c54d0ed51bb2031431e2bcdafebb4c6e.zip |
5.13
Diffstat (limited to 'zen/zstring.cpp')
-rw-r--r-- | zen/zstring.cpp | 196 |
1 files changed, 101 insertions, 95 deletions
diff --git a/zen/zstring.cpp b/zen/zstring.cpp index 7f4e79db..b371e598 100644 --- a/zen/zstring.cpp +++ b/zen/zstring.cpp @@ -6,93 +6,141 @@ #include "zstring.h" #include <stdexcept> -#include <zen/stl_tools.h> #ifdef FFS_WIN #include "dll.h" #include "win_ver.h" + +#elif defined FFS_MAC +#include <ctype.h> //toupper() #endif #ifndef NDEBUG +#include "thread.h" //includes <boost/thread.hpp> #include <iostream> -#include <cstdlib> #endif using namespace zen; #ifndef NDEBUG -LeakChecker::~LeakChecker() +namespace { - if (!activeStrings.empty()) +class LeakChecker //small test for memory leaks +{ +public: + void insert(const void* ptr, size_t size) { - std::string leakingStrings; + boost::lock_guard<boost::mutex> dummy(lockActStrings); + if (activeStrings.find(ptr) != activeStrings.end()) + reportProblem("Fatal Error: New memory points into occupied space: " + rawMemToString(ptr, size)); - int items = 0; - for (auto it = activeStrings.begin(); it != activeStrings.end() && items < 20; ++it, ++items) - leakingStrings += "\"" + rawMemToString(it->first, it->second) + "\"\n"; + activeStrings[ptr] = size; + } - const std::string message = std::string("Memory leak detected!") + "\n\n" - + "Candidates:\n" + leakingStrings; -#ifdef FFS_WIN - MessageBoxA(nullptr, message.c_str(), "Error", 0); -#else - std::cerr << message; - std::abort(); -#endif + void remove(const void* ptr) + { + boost::lock_guard<boost::mutex> dummy(lockActStrings); + if (activeStrings.find(ptr) == activeStrings.end()) + reportProblem("Fatal Error: No memory available for deallocation at this location!"); + + activeStrings.erase(ptr); } -} + static LeakChecker& instance() { static LeakChecker inst; return inst; } -LeakChecker& LeakChecker::instance() -{ - static LeakChecker inst; - return inst; -} +private: + LeakChecker() {} + ~LeakChecker() + { + if (!activeStrings.empty()) + { + std::string leakingStrings; -//caveat: function scope static initialization is not thread-safe in VS 2010! => make sure to call at app start! -namespace -{ -const LeakChecker& dummy = LeakChecker::instance(); -} + int items = 0; + for (auto it = activeStrings.begin(); it != activeStrings.end() && items < 20; ++it, ++items) + leakingStrings += "\"" + rawMemToString(it->first, it->second) + "\"\n"; + const std::string message = std::string("Memory leak detected!") + "\n\n" + + "Candidates:\n" + leakingStrings; +#ifdef FFS_WIN + MessageBoxA(nullptr, message.c_str(), "Error", 0); +#else + std::cerr << message; + std::abort(); +#endif + } + } -std::string LeakChecker::rawMemToString(const void* ptr, size_t size) -{ - std::string output = std::string(reinterpret_cast<const char*>(ptr), size); - vector_remove_if(output, [](char& c) { return c == 0; }); //remove intermediate 0-termination - if (output.size() > 100) - output.resize(100); - return output; -} + LeakChecker(const LeakChecker&); + LeakChecker& operator=(const LeakChecker&); + static std::string rawMemToString(const void* ptr, size_t size) + { + std::string output(reinterpret_cast<const char*>(ptr), size); + vector_remove_if(output, [](char& c) { return c == 0; }); //remove intermediate 0-termination + if (output.size() > 100) + output.resize(100); + return output; + } -void LeakChecker::reportProblem(const std::string& message) //throw std::logic_error -{ + void reportProblem(const std::string& message) //throw std::logic_error + { #ifdef FFS_WIN - ::MessageBoxA(nullptr, message.c_str(), "Error", 0); + ::MessageBoxA(nullptr, message.c_str(), "Error", 0); #else - std::cerr << message; + std::cerr << message; #endif - throw std::logic_error("Memory leak! " + message); + throw std::logic_error("Memory leak! " + message); + } + + boost::mutex lockActStrings; + zen::hash_map<const void*, size_t> activeStrings; +}; + +//caveat: function scope static initialization is not thread-safe in VS 2010! => make sure to call at app start! +const LeakChecker& dummy = LeakChecker::instance(); } + +void z_impl::leakCheckerInsert(const void* ptr, size_t size) { LeakChecker::instance().insert(ptr, size); } +void z_impl::leakCheckerRemove(const void* ptr ) { LeakChecker::instance().remove(ptr); } #endif //NDEBUG +/* +Perf test: compare strings 10 mio times; 64 bit build +----------------------------------------------------- + string a = "Fjk84$%kgfj$%T\\\\Gffg\\gsdgf\\fgsx----------d-" + string b = "fjK84$%kgfj$%T\\\\gfFg\\gsdgf\\fgSy----------dfdf" + +Windows (UTF16 wchar_t) + 4 ns | wcscmp + 67 ns | CompareStringOrdinalFunc+ + bIgnoreCase +314 ns | LCMapString + wmemcmp + +OS X (UTF8 char) + 6 ns | strcmp + 98 ns | strcasecmp + 120 ns | strncasecmp + std::min(sizeLhs, sizeRhs); + 856 ns | CFStringCreateWithCString + CFStringCompare(kCFCompareCaseInsensitive) +1110 ns | CFStringCreateWithCStringNoCopy + CFStringCompare(kCFCompareCaseInsensitive) +________________________ +time per call | function +*/ + + #ifdef FFS_WIN namespace { -#ifndef LOCALE_INVARIANT //invariant locale has been introduced with XP -#define LOCALE_INVARIANT 0x007f +#ifndef LOCALE_INVARIANT //not known to MinGW +#define LOCALE_INVARIANT 0x007f #endif - //warning: LOCALE_INVARIANT is NOT available with Windows 2000, so we have to make yet another distinction... const LCID ZSTRING_INVARIANT_LOCALE = zen::winXpOrLater() ? LOCALE_INVARIANT : MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); //see: http://msdn.microsoft.com/en-us/goglobal/bb688122.aspx - //try to call "CompareStringOrdinal" for low-level string comparison: unfortunately available not before Windows Vista! //by a factor ~3 faster than old string comparison using "LCMapString" typedef int (WINAPI* CompareStringOrdinalFunc)(LPCWSTR lpString1, @@ -104,7 +152,7 @@ const SysDllFun<CompareStringOrdinalFunc> compareStringOrdinal = SysDllFun<Compa } -int z_impl::compareFilenamesWin(const wchar_t* lhs, const wchar_t* rhs, size_t sizeLhs, size_t sizeRhs) +int z_impl::compareFilenamesNoCase(const wchar_t* lhs, const wchar_t* rhs, size_t sizeLhs, size_t sizeRhs) { //caveat: function scope static initialization is not thread-safe in VS 2010! if (compareStringOrdinal) //this additional test has no noticeable performance impact @@ -165,26 +213,12 @@ int z_impl::compareFilenamesWin(const wchar_t* lhs, const wchar_t* rhs, size_t s return rv; } } - return static_cast<int>(sizeLhs) - static_cast<int>(sizeRhs); } - - // const int rv = CompareString( - // invariantLocale, //locale independent - // NORM_IGNORECASE | SORT_STRINGSORT, //comparison-style options - // a, //pointer to first string - // aCount, //size, in bytes or characters, of first string - // b, //pointer to second string - // bCount); //size, in bytes or characters, of second string - // - // if (rv == 0) - // throw std::runtime_error("Error comparing strings!"); - // else - // return rv - 2; //convert to C-style string compare result } -void z_impl::makeUpperCaseWin(wchar_t* str, size_t size) +void z_impl::makeFilenameUpperCase(wchar_t* str, size_t size) { if (size == 0) //LCMapString does not allow input sizes of 0! return; @@ -194,38 +228,10 @@ void z_impl::makeUpperCaseWin(wchar_t* str, size_t size) throw std::runtime_error("Error converting to upper case! (LCMapString)"); } - -/* -#include <fstream> - extern std::wofstream statShared; -extern std::wofstream statLowCapacity; -extern std::wofstream statOverwrite; - -std::wstring p(ptr); -p.erase(std::remove(p.begin(), p.end(), L'\n'), p.end()); -p.erase(std::remove(p.begin(), p.end(), L','), p.end()); - - if (descr(ptr)->refCount > 1) - statShared << - minCapacity << L"," << - descr(ptr)->refCount << L"," << - descr(ptr)->length << L"," << - descr(ptr)->capacity << L"," << - p << L"\n"; -else if (minCapacity > descr(ptr)->capacity) - statLowCapacity << - minCapacity << L"," << - descr(ptr)->refCount << L"," << - descr(ptr)->length << L"," << - descr(ptr)->capacity << L"," << - p << L"\n"; -else - statOverwrite << - minCapacity << L"," << - descr(ptr)->refCount << L"," << - descr(ptr)->length << L"," << - descr(ptr)->capacity << L"," << - p << L"\n"; -*/ - -#endif //FFS_WIN +#elif defined FFS_MAC +void z_impl::makeFilenameUpperCase(char* str, size_t size) +{ + std::for_each(str, str + size, [](char& c) { c = static_cast<char>(::toupper(static_cast<unsigned char>(c))); }); //locale-dependent! + //result of toupper() is an unsigned char mapped to int range, so the char representation is in the last 8 bits and we need not care about signedness! +} +#endif |