summaryrefslogtreecommitdiff
path: root/zen/zstring.h
blob: 8f7486b03d30ba4f2a138c359b6138e382f06912 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html       *
// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved    *
// **************************************************************************

#ifndef ZSTRING_H_INCLUDED
#define ZSTRING_H_INCLUDED

#include "string_base.h"
#include <cstring> //strcmp()

#ifndef NDEBUG
#include "thread.h" //includes <boost/thread.hpp>
#include <map>
#endif


#ifndef NDEBUG
class LeakChecker //small test for memory leaks
{
public:
    void insert(const void* ptr, size_t size)
    {
        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));

        activeStrings[ptr] = size;
    }

    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();

private:
    LeakChecker() {}
    LeakChecker(const LeakChecker&);
    LeakChecker& operator=(const LeakChecker&);
    ~LeakChecker();

    static std::string rawMemToString(const void* ptr, size_t size);
    void reportProblem(const std::string& message); //throw std::logic_error

    boost::mutex lockActStrings;
    zen::hash_map<const void*, size_t> activeStrings;
};
#endif //NDEBUG


class AllocatorFreeStoreChecked
{
public:
    static void* allocate(size_t size) //throw std::bad_alloc
    {
#ifndef NDEBUG
        void* newMem = ::operator new(size);
        LeakChecker::instance().insert(newMem, size); //test Zbase for memory leaks
        return newMem;
#else
        return ::operator new(size);
#endif
    }

    static void deallocate(void* ptr)
    {
#ifndef NDEBUG
        LeakChecker::instance().remove(ptr); //check for memory leaks
#endif
        ::operator delete(ptr);
    }

    static size_t calcCapacity(size_t length) { return std::max<size_t>(16, length + length / 2); } //exponential growth + min size
};


//############################## helper functions #############################################
#if defined(FFS_WIN) || defined(FFS_LINUX)
//Compare filenames: Windows does NOT distinguish between upper/lower-case, while Linux DOES
template <class T, template <class, class> class SP, class AP> int cmpFileName(const zen::Zbase<T, SP, AP>& lhs, const zen::Zbase<T, SP, AP>& rhs);

struct LessFilename //case-insensitive on Windows, case-sensitive on Linux
{
    template <class T, template <class, class> class SP, class AP>
    bool operator()(const zen::Zbase<T, SP, AP>& lhs, const zen::Zbase<T, SP, AP>& rhs) const;
};

struct EqualFilename //case-insensitive on Windows, case-sensitive on Linux
{
    template <class T, template <class, class> class SP, class AP>
    bool operator()(const zen::Zbase<T, SP, AP>& lhs, const zen::Zbase<T, SP, AP>& rhs) const;
};
#endif

#ifdef FFS_WIN
template <template <class, class> class SP, class AP>
void makeUpper(zen::Zbase<wchar_t, SP, AP>& str);
#endif

#ifdef FFS_WIN //Windows stores filenames in wide character format
typedef wchar_t Zchar;
#define Zstr(x) L ## x
const Zchar FILE_NAME_SEPARATOR = L'\\';

#elif defined FFS_LINUX //Linux uses UTF-8
typedef char Zchar;
#define Zstr(x) x
const Zchar FILE_NAME_SEPARATOR = '/';

#else
#error define your platform: FFS_WIN or FFS_LINUX
#endif

//"The reason for all the fuss above" - Loki/SmartPtr
//a high-performance string for use as file name in multithreaded contexts
typedef zen::Zbase<Zchar, zen::StorageRefCountThreadSafe, AllocatorFreeStoreChecked> Zstring;


inline
Zstring appendSeparator(Zstring path) //support rvalue references!
{
    return endsWith(path, FILE_NAME_SEPARATOR) ? path : (path += FILE_NAME_SEPARATOR);
}




















//################################# inline implementation ########################################
#if defined(FFS_WIN) || defined(FFS_LINUX)
namespace z_impl
{
int compareFilenamesWin(const wchar_t* lhs, const wchar_t* rhs, size_t sizeLhs, size_t sizeRhs);
void makeUpperCaseWin(wchar_t* str, size_t size);
}


template <class T, template <class, class> class SP, class AP>
inline
int cmpFileName(const zen::Zbase<T, SP, AP>& lhs, const zen::Zbase<T, SP, AP>& rhs)
{
#ifdef FFS_WIN
    return z_impl::compareFilenamesWin(lhs.data(), rhs.data(), lhs.length(), rhs.length());
#elif defined FFS_LINUX
    return ::strcmp(lhs.c_str(), rhs.c_str()); //POSIX filenames don't have embedded 0
#endif
}


template <class T, template <class, class> class SP, class AP>
inline
bool LessFilename::operator()(const zen::Zbase<T, SP, AP>& lhs, const zen::Zbase<T, SP, AP>& rhs) const
{
#ifdef FFS_WIN
    return z_impl::compareFilenamesWin(lhs.data(), rhs.data(), lhs.length(), rhs.length()) < 0;
#elif defined FFS_LINUX
    return ::strcmp(lhs.c_str(), rhs.c_str()) < 0; //POSIX filenames don't have embedded 0
#endif
}


template <class T, template <class, class> class SP, class AP>
inline
bool EqualFilename::operator()(const zen::Zbase<T, SP, AP>& lhs, const zen::Zbase<T, SP, AP>& rhs) const
{
#ifdef FFS_WIN
    return z_impl::compareFilenamesWin(lhs.data(), rhs.data(), lhs.length(), rhs.length()) == 0;
#elif defined FFS_LINUX
    return ::strcmp(lhs.c_str(), rhs.c_str()) == 0; //POSIX filenames don't have embedded 0
#endif
}
#endif //defined(FFS_WIN) || defined(FFS_LINUX)


#ifdef FFS_WIN
template <template <class, class> class SP, class AP>
inline
void makeUpper(zen::Zbase<wchar_t, SP, AP>& str)
{
    z_impl::makeUpperCaseWin(str.begin(), str.length());
}
#endif


namespace std
{
template<> inline
void swap(Zstring& rhs, Zstring& lhs)
{
    rhs.swap(lhs);
}
}

#endif //ZSTRING_H_INCLUDED
bgstack15