File indexing completed on 2024-12-29 04:11:44
0001 /*************************************************************************** 0002 * * 0003 * Copyright : (C) 2012 Peter Kümmel * 0004 * email : syntheticpp@gmx.net * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 ***************************************************************************/ 0012 0013 #include "asciifiledata.h" 0014 0015 #ifndef QT5 0016 // needed to track memeory usage 0017 #include "qplatformdefs.h" 0018 #include <stdlib.h> 0019 void* fileBufferMalloc(size_t bytes); 0020 void fileBufferFree(void* ptr); 0021 #define malloc fileBufferMalloc 0022 #define qMalloc fileBufferMalloc 0023 #define free fileBufferFree 0024 #define qFree fileBufferFree 0025 #include <QVarLengthArray> 0026 #undef malloc 0027 #undef qMalloc 0028 #undef free 0029 #undef qFree 0030 #endif 0031 0032 #include "debug.h" 0033 0034 #include <QFile> 0035 #include <QDebug> 0036 #include <QByteArray> 0037 0038 int MB = 1024*1024; 0039 0040 // Simulate out of memory scenario 0041 //#define KST_TEST_OOM 0042 0043 #ifdef KST_TEST_OOM 0044 size_t maxAllocate = 1 * MB; 0045 #else 0046 size_t maxAllocate = (size_t) -1; 0047 #endif 0048 0049 #define KST_MEMORY_DEBUG if(0) 0050 0051 //------------------------------------------------------------------------------------------- 0052 static QMap<void*, size_t> allocatedMBs; 0053 0054 //------------------------------------------------------------------------------------------- 0055 static void logMemoryUsed() 0056 { 0057 size_t sum = 0; 0058 QMapIterator<void*, size_t> it(allocatedMBs); 0059 while (it.hasNext()) { 0060 it.next(); 0061 sum += it.value(); 0062 } 0063 if(sum / MB != 0) Kst::Debug::self()->log(QString("AsciiFileData: %1 MB used").arg(sum / MB), Kst::Debug::Warning); 0064 KST_MEMORY_DEBUG if(sum / MB != 0) qDebug() << "AsciiFileData: " << sum / MB<< "MB used"; 0065 } 0066 0067 //------------------------------------------------------------------------------------------- 0068 void* fileBufferMalloc(size_t bytes) 0069 { 0070 void* ptr = 0; 0071 #ifdef KST_TEST_OOM 0072 if (bytes <= maxAllocate) 0073 #endif 0074 ptr = malloc(bytes); 0075 if (ptr) { 0076 allocatedMBs[ptr] = bytes; 0077 KST_MEMORY_DEBUG if(bytes / MB != 0) qDebug() << "AsciiFileBuffer: " << bytes / MB << "MB allocated"; 0078 KST_MEMORY_DEBUG if(bytes / MB != 0) logMemoryUsed(); 0079 } else { 0080 Kst::Debug::self()->log(QString("AsciiFileData: failed to allocate %1 MBs").arg(bytes / MB), Kst::Debug::Warning); 0081 logMemoryUsed(); 0082 KST_MEMORY_DEBUG qDebug() << "AsciiFileData: error when allocating " << bytes / MB << "MB"; 0083 } 0084 return ptr; 0085 } 0086 0087 //------------------------------------------------------------------------------------------- 0088 void fileBufferFree(void* ptr) 0089 { 0090 if (allocatedMBs.contains(ptr)) { 0091 KST_MEMORY_DEBUG if(allocatedMBs[ptr] / MB != 0) qDebug() << "AsciiFileData: " << allocatedMBs[ptr] / MB << "MB freed"; 0092 allocatedMBs.remove(ptr); 0093 } 0094 KST_MEMORY_DEBUG logMemoryUsed(); 0095 free(ptr); 0096 } 0097 0098 0099 0100 //------------------------------------------------------------------------------------------- 0101 AsciiFileData::AsciiFileData() : 0102 _array(new Array), _file(0), _fileRead(false), _reread(false), 0103 _begin(-1), _bytesRead(0), _rowBegin(-1), _rowsRead(0) 0104 { 0105 } 0106 0107 //------------------------------------------------------------------------------------------- 0108 AsciiFileData::~AsciiFileData() 0109 { 0110 } 0111 0112 //------------------------------------------------------------------------------------------- 0113 char* AsciiFileData::data() 0114 { 0115 return _array->data(); 0116 } 0117 0118 //------------------------------------------------------------------------------------------- 0119 const char* const AsciiFileData::constPointer() const 0120 { 0121 return _array->data(); 0122 } 0123 0124 const AsciiFileData::Array& AsciiFileData::constArray() const 0125 { 0126 return *_array; 0127 } 0128 0129 //------------------------------------------------------------------------------------------- 0130 bool AsciiFileData::resize(qint64 bytes) 0131 { 0132 try { 0133 _array->resize(bytes); 0134 } catch (const std::bad_alloc&) { 0135 // work around Qt bug: Qt4 does not release the heap allocated memory 0136 clear(true); 0137 return false; 0138 } 0139 return true; 0140 } 0141 0142 //------------------------------------------------------------------------------------------- 0143 void AsciiFileData::clear(bool forceDeletingArray) 0144 { 0145 // force deletion of heap allocated memory if any 0146 if (forceDeletingArray || _array->capacity() > Prealloc) { 0147 _array = QSharedPointer<Array>(new Array); 0148 } 0149 _begin = -1; 0150 _bytesRead = 0; 0151 _fileRead = false; 0152 } 0153 0154 //------------------------------------------------------------------------------------------- 0155 qint64 AsciiFileData::read(QFile& file, qint64 start, qint64 bytesToRead, qint64 maximalBytes) 0156 { 0157 _begin = -1; 0158 _bytesRead = 0; 0159 0160 if (bytesToRead <= 0 || start < 0) 0161 return 0; 0162 0163 if (maximalBytes == -1) { 0164 if (!resize(bytesToRead + 1)) 0165 return 0; 0166 } else { 0167 bytesToRead = qMin(bytesToRead, maximalBytes); 0168 if (!resize(bytesToRead + 1)) 0169 return 0; 0170 } 0171 if (!file.seek(start)) // expensive? 0172 return 0; 0173 qint64 bytesRead = file.read(_array->data(), bytesToRead); 0174 if (!resize(bytesRead + 1)) 0175 return 0; 0176 0177 _array->data()[bytesRead] = '\0'; 0178 _begin = start; 0179 _bytesRead = bytesRead; 0180 0181 return bytesRead; 0182 } 0183 0184 //------------------------------------------------------------------------------------------- 0185 bool AsciiFileData::read() 0186 { 0187 if (_fileRead && !_reread) { 0188 return true; 0189 } 0190 0191 if (!_file || _file->openMode() != QIODevice::ReadOnly) { 0192 return false; 0193 } 0194 0195 qint64 start = _begin; 0196 qint64 bytesToRead = _bytesRead; 0197 read(*_file, start, bytesToRead); 0198 if (begin() != start || bytesRead() != bytesToRead) { 0199 clear(true); 0200 return false; 0201 } 0202 0203 _fileRead = true; 0204 return true; 0205 } 0206 0207 //------------------------------------------------------------------------------------------- 0208 void AsciiFileData::logData() const 0209 { 0210 QString this_str; 0211 QString data_str; 0212 0213 this_str.sprintf("%p", this); 0214 data_str.sprintf("%p", _array.data()); 0215 qDebug() << QString("AsciiFileData %1, array %2, byte %3 ... %4 (%8), row %5 ... %6 (%9), lazy: %7") 0216 .arg(this_str) 0217 .arg(data_str) 0218 .arg(begin(), 8).arg(begin() + bytesRead(), 8) 0219 .arg(rowBegin(), 8).arg(rowBegin() + rowsRead(), 8) 0220 .arg(_reread).arg(bytesRead(), 8).arg(rowsRead(), 8); 0221 } 0222 0223 //------------------------------------------------------------------------------------------- 0224 void AsciiFileData::logData(const QVector<AsciiFileData>& chunks) 0225 { 0226 foreach (const AsciiFileData& chunk, chunks) { 0227 chunk.logData(); 0228 } 0229 } 0230 0231 //------------------------------------------------------------------------------------------- 0232 void AsciiFileData::setSharedArray(AsciiFileData& arrayData) 0233 { 0234 _array = arrayData._array; 0235 } 0236