Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*******************************************************************************\
- * *
- * This code is free software : you can redistribute it and / or modify *
- * it under the terms of the GNU Lesser General Public License as published by *
- * the Free Software Foundation, either version 3 of the License, or *
- * (at your option) any later version. *
- * *
- * This code is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the *
- * GNU Lesser General Public License for more details. *
- * *
- * A copy of the GNU Lesser General Public License is *
- * available at < http://www.gnu.org/licenses/ >. *
- * *
- \*******************************************************************************/
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- // MemoryMappedDevice.h
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- #ifndef MemoryMappedDevice_h__
- #define MemoryMappedDevice_h__
- #include <tuple>
- #include <QByteArray>
- #include <QDataStream>
- class QIODevice;
- class MemoryMappedDevicePrivate;
- /*!
- \brief A memory mapped device storing items as key-value pairs
- \details This class handles reading and writing of items into a memory mapped file using the key-value pair paradigm.
- Items are added to the map with setValue() and retrieved with value().
- The type of items saved does not need to be unique but this class will not check for type safety when retrieving values, it has to be done by the user.
- To save items of type MyClass in the map tou have to reimplement the operators
- \code
- QDataStream& operator<<(QDataStream&, const MyClass&);
- QDataStream& operator>>(QDataStream& , MyClass&);
- \endcode
- If the supplied device is not seekable a failed assertion will trigger
- */
- class MemoryMappedDevice
- {
- Q_DECLARE_PRIVATE(MemoryMappedDevice)
- MemoryMappedDevice(MemoryMappedDevicePrivate *d);
- public:
- //! Creates an null object
- MemoryMappedDevice();
- virtual ~MemoryMappedDevice()=default;
- //! Creates memory map on the source device
- MemoryMappedDevice(QIODevice* source);
- //! Clears the map and reset it to the source device
- void setDevice(QIODevice* source = nullptr);
- //! Adds the value val to the map associating the given key. Returns true if succesful
- template <class T> bool setValue(qint32 key, const T& val){
- QByteArray block;
- {
- QDataStream writerStream(&block, QIODevice::WriteOnly);
- writerStream << val;
- }
- return writeBlock(key, block);
- }
- //! Retrieves the item associated with the given key. The first element of the tuple determines if the process was succesful
- template <class T> std::tuple<bool,T> value(qint32 key) const {
- static_assert(std::is_default_constructible<T>::value, "T must provide a default constructor");
- T result;
- QByteArray block = readBlock(key);
- if (block.isEmpty())
- return std::make_tuple(false, result);
- QDataStream readerStream(block);
- readerStream >> result;
- return std::make_tuple(true,result);
- }
- //! Clears the map
- void clear();
- //! Removes the item associated with the given key from the map
- bool removeValue(qint32 key);
- //! Returns all the keys of the map
- QList<qint32> keys() const;
- //! Returns true if the map contains an item associated with the given key
- bool contains(qint32 key) const;
- //! Returns the number of items in the map
- qint32 size() const;
- //! Returns the total size of memory occupied by the items in the map
- qint64 deviceSize() const;
- //! Returns true if there are no items in the map
- bool isEmpty() const;
- //! Retunrs the device associated with the map
- QIODevice* device();
- //! Reads the entire contents of the mapped device
- QByteArray readAll() const;
- protected:
- MemoryMappedDevice(const MemoryMappedDevice&) = delete;
- MemoryMappedDevice& operator=(const MemoryMappedDevice&) = delete;
- MemoryMappedDevicePrivate* d_ptr;
- bool writeBlock(qint32 key, const QByteArray& block);
- QByteArray readBlock(qint32 key) const;
- qint64 writeInMap(const QByteArray& block);
- };
- #endif // MemoryMappedDevice_h__
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- // MemoryMappedDevice_p.h
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- #ifndef MemoryMappedDevice_p_h__
- #define MemoryMappedDevice_p_h__
- #include <QPointer>
- #include <QHash>
- #include <QMap>
- #include "MemoryMappedDevice.h"
- class QIODevice;
- class MemoryMappedDevicePrivate
- {
- Q_DECLARE_PUBLIC(MemoryMappedDevice)
- public:
- MemoryMappedDevicePrivate(MemoryMappedDevice *q);
- virtual ~MemoryMappedDevicePrivate();
- private:
- MemoryMappedDevicePrivate(const MemoryMappedDevicePrivate &other) =delete;
- MemoryMappedDevicePrivate& operator=(const MemoryMappedDevicePrivate &other) = delete;
- protected:
- QPointer<QIODevice> m_device;
- QHash<qint32, qint64> m_itemsMap;
- QMap<qint64, bool> m_memoryMap;
- MemoryMappedDevice* q_ptr;
- };
- #endif // MemoryMappedDevice_p_h__
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- // MemoryMappedDevice.cpp
- ///////////////////////////////////////////////////////////////////////////////////////////////////////
- #include "MemoryMappedDevice.h"
- #include "MemoryMappedDevice_p.h"
- #include <QIODevice>
- MemoryMappedDevicePrivate::MemoryMappedDevicePrivate(MemoryMappedDevice *q)
- :q_ptr(q)
- ,m_device(nullptr)
- {}
- MemoryMappedDevice::MemoryMappedDevice()
- : MemoryMappedDevice(static_cast<QIODevice*>(nullptr))
- {}
- MemoryMappedDevice::MemoryMappedDevice(MemoryMappedDevicePrivate *d)
- :d_ptr(d)
- {
- }
- MemoryMappedDevicePrivate::~MemoryMappedDevicePrivate()
- {
- if (m_device) {
- if (m_device->isOpen()) {
- m_device->close();
- }
- }
- }
- MemoryMappedDevice::MemoryMappedDevice(QIODevice* source)
- :MemoryMappedDevice(new MemoryMappedDevicePrivate(this))
- {
- setDevice(source);
- }
- void MemoryMappedDevice::setDevice(QIODevice* source)
- {
- Q_D(MemoryMappedDevice);
- if (d->m_device) {
- if (d->m_device->isOpen()) {
- d->m_device->close();
- }
- }
- d->m_itemsMap.clear();
- d->m_memoryMap.clear();
- d->m_memoryMap.insert(0, true);
- d->m_device = source;
- if (d->m_device) {
- if (d->m_device->isSequential()) {
- Q_ASSERT_X(false, "MemoryMappedDevice()", "Device must be seekable");
- d->m_device = nullptr;
- }
- if (!d->m_device->isOpen()) {
- d->m_device->open(QIODevice::ReadWrite);
- }
- }
- }
- void MemoryMappedDevice::clear()
- {
- Q_D(MemoryMappedDevice);
- if (d->m_device) {
- if (d->m_device->isOpen()) {
- d->m_device->close();
- }
- d->m_device->open(QIODevice::Truncate);
- d->m_device->close();
- d->m_device->open(QIODevice::ReadWrite);
- }
- d->m_itemsMap.clear();
- d->m_memoryMap.clear();
- d->m_memoryMap.insert(0, true);
- }
- bool MemoryMappedDevice::removeValue(qint32 key)
- {
- Q_D(MemoryMappedDevice);
- auto itemIter = d->m_itemsMap.find(key);
- if (itemIter == d->m_itemsMap.end())
- return false;
- auto fileIter = d->m_memoryMap.find(itemIter.value());
- Q_ASSERT(fileIter != d->m_memoryMap.end());
- if (fileIter.value())
- return false;
- d->m_itemsMap.erase(itemIter);
- if (fileIter != d->m_memoryMap.begin()) {
- if ((fileIter - 1).value()) {
- fileIter = d->m_memoryMap.erase(fileIter);
- if (fileIter.value())
- d->m_memoryMap.erase(fileIter);
- return true;
- }
- }
- if ((fileIter + 1) != d->m_memoryMap.end()) {
- if ((fileIter + 1).value())
- d->m_memoryMap.erase(fileIter + 1);
- }
- fileIter.value() = true;
- return true;
- }
- QList<qint32> MemoryMappedDevice::keys() const
- {
- Q_D(const MemoryMappedDevice);
- return d->m_itemsMap.keys();
- }
- bool MemoryMappedDevice::contains(qint32 key) const
- {
- Q_D(const MemoryMappedDevice);
- return d->m_itemsMap.contains(key);
- }
- qint32 MemoryMappedDevice::size() const
- {
- Q_D(const MemoryMappedDevice);
- return d->m_itemsMap.size();
- }
- qint64 MemoryMappedDevice::deviceSize() const
- {
- Q_D(const MemoryMappedDevice);
- if (!d->m_device)
- return 0;
- return d->m_device->size();
- }
- bool MemoryMappedDevice::isEmpty() const
- {
- Q_D(const MemoryMappedDevice);
- return d->m_itemsMap.isEmpty();
- }
- QIODevice* MemoryMappedDevice::device()
- {
- Q_D(MemoryMappedDevice);
- return d->m_device;
- }
- QByteArray MemoryMappedDevice::readAll() const
- {
- Q_D(MemoryMappedDevice);
- if (!d->m_device)
- return QByteArray();
- d->m_device->seek(0);
- return d->m_device->readAll();
- }
- bool MemoryMappedDevice::writeBlock(qint32 key, const QByteArray& block)
- {
- Q_D(MemoryMappedDevice);
- if (!d->m_device)
- return false;
- if (!d->m_device->isOpen()) {
- if (!d->m_device->open(QIODevice::ReadWrite))
- return false;
- }
- if (!d->m_device->isWritable())
- return false;
- d->m_device->setTextModeEnabled(false);
- auto itemIter = d->m_itemsMap.find(key);
- if (itemIter != d->m_itemsMap.end()) {
- removeValue(key);
- }
- d->m_itemsMap.insert(key, writeInMap(block));
- return true;
- }
- QByteArray MemoryMappedDevice::readBlock(qint32 key) const
- {
- Q_D(const MemoryMappedDevice);
- if (!d->m_device)
- return QByteArray();
- if (!d->m_device->isOpen()) {
- if (!d->m_device->open(QIODevice::ReadWrite))
- return QByteArray();
- }
- if (!d->m_device->isReadable())
- return QByteArray();
- d->m_device->setTextModeEnabled(false);
- auto itemIter = d->m_itemsMap.constFind(key);
- if (itemIter == d->m_itemsMap.constEnd())
- return QByteArray();
- auto fileIter = d->m_memoryMap.constFind(itemIter.value());
- Q_ASSERT(fileIter != d->m_memoryMap.constEnd());
- if(fileIter.value())
- return QByteArray();
- auto nextIter = fileIter + 1;
- d->m_device->seek(fileIter.key());
- if (nextIter == d->m_memoryMap.constEnd())
- return d->m_device->readAll();
- return d->m_device->read(nextIter.key() - fileIter.key());
- }
- qint64 MemoryMappedDevice::writeInMap(const QByteArray& block)
- {
- Q_D(MemoryMappedDevice);
- for (auto i = d->m_memoryMap.begin(); i != d->m_memoryMap.end(); ++i) {
- if (i.value()) {
- // Space is available
- auto j = i + 1;
- if (j != d->m_memoryMap.end()) {
- if (i.key() + static_cast<qint64>(block.size()) > j.key())
- // Not enough space to save here
- continue;
- if (i.key() + static_cast<qint64>(block.size()) < j.key()) {
- // Item smaller than available space
- d->m_memoryMap.insert(i.key() + static_cast<qint64>(block.size()), true);
- }
- }
- else {
- d->m_memoryMap.insert(i.key() + block.size(), true);
- }
- i.value() = false;
- d->m_device->seek(i.key());
- d->m_device->write(block);
- return i.key();
- }
- }
- Q_UNREACHABLE();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement