/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qbs. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QBS_PERSISTENCE #define QBS_PERSISTENCE #include "persistentobject.h" #include #include #include #include #include #include #include #include namespace qbs { namespace Internal { class PersistentPool { public: PersistentPool(Logger &logger); ~PersistentPool(); class HeadData { public: QVariantMap projectConfig; }; // We need a helper class template, because we require partial specialization for some of // the aggregate types, which is not possible with function templates. // The generic implementation assumes that T is of class type and has load() and store() // member functions. template struct Helper { static void store(const T &object, PersistentPool *pool) { object.store(*pool); } static void load(T &object, PersistentPool *pool) { object.load(*pool); } }; template void store(const T &value) { Helper().store(value, this); } template void load(T &value) { Helper().load(value, this); } template T load() { T tmp; Helper().load(tmp, this); return tmp; } void load(const QString &filePath); void setupWriteStream(const QString &filePath); void finalizeWriteStream(); void closeStream(); void clear(); const HeadData &headData() const { return m_headData; } void setHeadData(const HeadData &hd) { m_headData = hd; } private: typedef int PersistentObjectId; template T *idLoad(); template QSharedPointer idLoadS(); template T *loadRaw(PersistentObjectId id); template QSharedPointer load(PersistentObjectId id); void storePersistentObject(const PersistentObject *object); void storeVariant(const QVariant &variant); QVariant loadVariant(); void storeString(const QString &t); QString loadString(int id); QString idLoadString(); QDataStream m_stream; HeadData m_headData; QVector m_loadedRaw; QVector > m_loaded; QHash m_storageIndices; PersistentObjectId m_lastStoredObjectId; QVector m_stringStorage; QHash m_inverseStringStorage; PersistentObjectId m_lastStoredStringId; Logger &m_logger; }; template inline T *PersistentPool::idLoad() { PersistentObjectId id; m_stream >> id; return loadRaw(id); } template inline QSharedPointer PersistentPool::idLoadS() { PersistentObjectId id; m_stream >> id; return load(id); } template inline T *PersistentPool::loadRaw(PersistentObjectId id) { if (id < 0) return 0; if (id < m_loadedRaw.count()) { PersistentObject *obj = m_loadedRaw.value(id); return dynamic_cast(obj); } int i = m_loadedRaw.count(); m_loadedRaw.resize(id + 1); for (; i < m_loadedRaw.count(); ++i) m_loadedRaw[i] = 0; T * const t = new T; PersistentObject * const po = t; m_loadedRaw[id] = po; po->load(*this); return t; } template inline QSharedPointer PersistentPool::load(PersistentObjectId id) { if (id < 0) return QSharedPointer(); if (id < m_loaded.count()) { QSharedPointer obj = m_loaded.value(id); return obj.dynamicCast(); } m_loaded.resize(id + 1); const QSharedPointer t = T::create(); m_loaded[id] = t; PersistentObject * const po = t.data(); po->load(*this); return t; } /***** Specializations of Helper class *****/ template struct PersistentPool::Helper::value>::type> { static void store(const T &value, PersistentPool *pool) { pool->m_stream << value; } static void load(T &value, PersistentPool *pool) { pool->m_stream >> value; } }; // TODO: Use constexpr function once we require MSVC 2015. template struct IsPersistentObject { static const bool value = std::is_base_of::value; }; template struct PersistentPool::Helper, typename std::enable_if::value>::type> { static void store(const QSharedPointer &value, PersistentPool *pool) { pool->store(value.data()); } static void load(QSharedPointer &value, PersistentPool *pool) { value = pool->idLoadS::type>(); } }; template struct PersistentPool::Helper::value>::type> { static void store(const T *value, PersistentPool *pool) { pool->storePersistentObject(value); } void load(T* &value, PersistentPool *pool) { value = pool->idLoad(); } }; template<> struct PersistentPool::Helper { static void store(const QString &s, PersistentPool *pool) { pool->storeString(s); } static void load(QString &s, PersistentPool *pool) { s = pool->idLoadString(); } }; template<> struct PersistentPool::Helper { static void store(const QVariant &v, PersistentPool *pool) { pool->storeVariant(v); } static void load(QVariant &v, PersistentPool *pool) { v = pool->loadVariant(); } }; template<> struct PersistentPool::Helper { static void store(const QProcessEnvironment &env, PersistentPool *pool) { const QStringList &keys = env.keys(); pool->store(keys.count()); for (const QString &key : keys) { pool->store(key); pool->store(env.value(key)); } } static void load(QProcessEnvironment &env, PersistentPool *pool) { const int count = pool->load(); for (int i = 0; i < count; ++i) { const auto &key = pool->load(); const auto &value = pool->load(); env.insert(key, value); } } }; template struct PersistentPool::Helper> { static void store(const QPair &pair, PersistentPool *pool) { pool->store(pair.first); pool->store(pair.second); } static void load(QPair &pair, PersistentPool *pool) { pool->load(pair.first); pool->load(pair.second); } }; class ArtifactSet; class FileTags; template struct IsSimpleContainer { static const bool value = false; }; template<> struct IsSimpleContainer { static const bool value = true; }; template<> struct IsSimpleContainer { static const bool value = true; }; template<> struct IsSimpleContainer { static const bool value = true; }; template struct IsSimpleContainer> { static const bool value = true; }; template struct IsSimpleContainer> { static const bool value = true; }; template struct IsSimpleContainer> { static const bool value = true; }; template struct PersistentPool::Helper::value>::type> { static void store(const T &container, PersistentPool *pool) { pool->store(container.count()); for (auto it = container.cbegin(); it != container.cend(); ++it) pool->store(*it); } static void load(T &container, PersistentPool *pool) { const int count = pool->load(); container.clear(); container.reserve(count); for (int i = count; --i >= 0;) container += pool->load(); } }; template struct IsKeyValueContainer { static const bool value = false; }; template struct IsKeyValueContainer> { static const bool value = true; }; template struct IsKeyValueContainer> { static const bool value = true; }; template struct PersistentPool::Helper::value>::type> { static void store(const T &container, PersistentPool *pool) { pool->store(container.count()); for (auto it = container.cbegin(); it != container.cend(); ++it) { pool->store(it.key()); pool->store(it.value()); } } static void load(T &container, PersistentPool *pool) { container.clear(); const int count = pool->load(); for (int i = 0; i < count; ++i) { const auto &key = pool->load(); const auto &value = pool->load(); container.insert(key, value); } } }; } // namespace Internal } // namespace qbs #endif