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