Minimize encoding conversions when generating unique file name

With minor adjustments, createFileFromTemplate is made to work directly
on (UTF-16) QString data, which is already in the native encoding for
Windows and Symbian. This is possible because the function only fills
out the placeholder sub-string, without touching adjacent characters.

This eliminates unnecessary conversions on those platforms.

Reviewed-by: Gareth Stockwell
Reviewed-by: Shane Kearns
(cherry picked from commit 9a76587363a2f37312326286e08cce502f7fe27e)

Change-Id: I8732b88ece5e2befb2da2e717758954c9aa7e5b0
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
bb10
João Abecasis 2011-08-05 10:58:08 +02:00 committed by Qt by Nokia
parent b3ca1d4a84
commit a4a09488ee
1 changed files with 54 additions and 15 deletions

View File

@ -61,6 +61,33 @@
QT_BEGIN_NAMESPACE
#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
typedef ushort Char;
static inline Char Latin1Char(char ch)
{
return ushort(uchar(ch));
}
template <>
struct QConcatenable<Char>
{
typedef Char type;
typedef QString ConvertTo;
enum { ExactSize = true };
static int size(const Char &) { return 1; }
static inline void appendTo(const Char &u16, QChar *&out)
{
*out++ = QChar(u16);
}
};
#else // POSIX
typedef char Char;
typedef char Latin1Char;
#endif
struct Placeholder
{
Placeholder(int size)
@ -134,23 +161,24 @@ struct QConcatenable<Placeholder>
handle otherwise. In both cases, the string in \a path will be changed and
contain the generated path name.
*/
static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length)
static int createFileFromTemplate(QFileSystemEntry::NativePath &path,
size_t pos, size_t length)
{
Q_ASSERT(length != 0);
Q_ASSERT(pos < size_t(path.length()));
Q_ASSERT(length < size_t(path.length()) - pos);
char *const placeholderStart = path.data() + pos;
char *const placeholderEnd = placeholderStart + length;
Char *const placeholderStart = (Char *)path.data() + pos;
Char *const placeholderEnd = placeholderStart + length;
// Initialize placeholder with random chars + PID.
{
char *rIter = placeholderEnd;
Char *rIter = placeholderEnd;
#if defined(QT_BUILD_CORE_LIB)
quint64 pid = quint64(QCoreApplication::applicationPid());
do {
*--rIter = (pid % 10) + '0';
*--rIter = Latin1Char((pid % 10) + '0');
pid /= 10;
} while (rIter != placeholderStart && pid != 0);
#endif
@ -158,9 +186,9 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length)
while (rIter != placeholderStart) {
char ch = char((qrand() & 0xffff) % (26 + 26));
if (ch < 26)
*--rIter = ch + 'A';
*--rIter = Latin1Char(ch + 'A');
else
*--rIter = ch - 26 + 'a';
*--rIter = Latin1Char(ch - 26 + 'a');
}
}
@ -177,18 +205,18 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length)
return -1;
}
#else
if (!QFileInfo(QString::fromLocal8Bit(path.constData(), path.length())).exists())
if (!QFileInfo(path).exists())
return 1;
#endif
/* tricky little algorwwithm for backward compatibility */
for (char *iter = placeholderStart;;) {
for (Char *iter = placeholderStart;;) {
// Character progression: [0-9] => 'a' ... 'z' => 'A' .. 'Z'
// String progression: "ZZaiC" => "aabiC"
switch (*iter) {
switch (char(*iter)) {
case 'Z':
// Rollover, advance next character
*iter = 'a';
*iter = Latin1Char('a');
if (++iter == placeholderEnd)
return -1;
@ -196,12 +224,12 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length)
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
*iter = 'a';
*iter = Latin1Char('a');
break;
case 'z':
// increment 'z' to 'A'
*iter = 'A';
*iter = Latin1Char('A');
break;
default:
@ -314,8 +342,9 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
phLength = 0;
}
QByteArray filename;
QFileSystemEntry::NativePath filename;
#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN)
if (phLength < 6) {
filename = qfilename.toLocal8Bit();
@ -330,6 +359,16 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
phPos = prefix.length();
filename = prefix % Placeholder(phLength) % suffix;
}
#else
if (phLength < 6) {
phPos = qfilename.length() + 1; // Account for added dot in prefix
phLength = 6;
filename = qfilename % Latin1Char('.') % Placeholder(phLength);
} else
filename = qfilename;
// No native separators, not a "native path"
#endif
int fd = createFileFromTemplate(filename, phPos, phLength);
@ -356,7 +395,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
if (fd == -1)
return false;
d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length()));
d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromInternalPath());
if (QFSFileEngine::open(openMode)) {
filePathIsTemplate = false;
return true;