Skip to content

Commit

Permalink
Icon cache removed - fixed #97
Browse files Browse the repository at this point in the history
  • Loading branch information
VioletGiraffe committed Sep 17, 2024
1 parent c8badd0 commit 1b10724
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 80 deletions.
80 changes: 13 additions & 67 deletions file-commander-core/src/iconprovider/ciconprovider.cpp
Original file line number Diff line number Diff line change
@@ -1,95 +1,41 @@
#include "ciconprovider.h"
#include "cfilesystemobject.h"
#include "ciconproviderimpl.h"

#include "assert/advanced_assert.h"
#include "hash/wheathash.hpp"

#include "settings/csettings.h"
#include "settings.h"

DISABLE_COMPILER_WARNINGS
#include <QIcon>
RESTORE_COMPILER_WARNINGS

// TODO: refactor this ugly singleton with unclear lifetime!
std::unique_ptr<CIconProvider> CIconProvider::_instance { new CIconProvider }; // Cannot use make_unique because CIconProvider's constructor is private

// guessIconByFileExtension is a less precise method, but much faster since it doesn't access the disk
const QIcon& CIconProvider::iconForFilesystemObject(const CFileSystemObject &object, bool guessIconByFileExtension)
QIcon CIconProvider::iconForFilesystemObject(const CFileSystemObject &object, bool guessIconByFileExtension)
{
return _instance->iconFor(object, guessIconByFileExtension);
return get()._provider->iconFor(object, guessIconByFileExtension);
}

void CIconProvider::settingsChanged()
{
if (_instance && _instance->_provider)
{
const bool showOverlayIcons = CSettings{}.value(KEY_INTERFACE_SHOW_SPECIAL_FOLDER_ICONS, false).toBool();
_instance->_provider->setShowOverlayIcons(showOverlayIcons);

_instance->_iconByKey.clear();
_instance->_iconKeyByObjectHash.clear();
}
get().onSettingsChanged();
}

CIconProvider::CIconProvider() : _provider{std::make_unique<CIconProviderImpl>()}
{
settingsChanged();
onSettingsChanged();
}

// This complicated hashing function should have addressed #97, but it doesn't actually fix it
// Temporarily disabled for optimization
//inline static qulonglong hash(const CFileSystemObject& object)
//{
// const auto properties = object.properties();
// // Use the original hash as the seed and mix it with other attributes that uniquely identify this object
// uint64_t hash = wheathash64v(properties.modificationDate, properties.hash);
// hash = wheathash64v(properties.creationDate, hash);
// hash = wheathash64v(properties.size, hash);
// hash = wheathash64v(properties.type, hash);

// return hash;
//}

// guessIconByFileExtension is a less precise method, but much faster since it doesn't access the disk
const QIcon& CIconProvider::iconFor(const CFileSystemObject& object, bool guessIconByFileExtension)
void CIconProvider::onSettingsChanged()
{
if (guessIconByFileExtension)
return iconFast(object);

const qulonglong objectHash = object.hash();
const auto iconHashIterator = _iconKeyByObjectHash.find(objectHash);
if (iconHashIterator != _iconKeyByObjectHash.end())
return _iconByKey[iconHashIterator->second];
if (!_provider)
return;

if (_iconKeyByObjectHash.size() > 500'000) [[unlikely]]
{
_iconKeyByObjectHash.clear();
}

QIcon icon = _provider->iconFor(object, false);
const auto iconHash = icon.cacheKey();
_iconKeyByObjectHash.emplace(objectHash, iconHash);

const auto iconInContainer = _iconByKey.insert_or_assign(iconHash, std::move(icon));
return iconInContainer.first->second;
const bool showOverlayIcons = CSettings{}.value(KEY_INTERFACE_SHOW_SPECIAL_FOLDER_ICONS, false).toBool();
_provider->setShowOverlayIcons(showOverlayIcons);
}

const QIcon& CIconProvider::iconFast(const CFileSystemObject& object)
CIconProvider& CIconProvider::get()
{
static const QString folderUid = "@!$%#&?~";

QString extension = object.isDir() ? folderUid : object.extension();
const auto it = _iconByExtension.find(extension);
if (it != _iconByExtension.end())
return it->second;

QIcon icon = _provider->iconFor(object, true);

if (_iconByExtension.size() > 10000) [[unlikely]]
_iconByExtension.clear();

const auto iconInContainer = _iconByExtension.emplace(std::move(extension), std::move(icon));
return iconInContainer.first->second;
static CIconProvider provider;
return provider;
}

17 changes: 4 additions & 13 deletions file-commander-core/src/iconprovider/ciconprovider.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#pragma once

#include "compiler/compiler_warnings_control.h"
#include "detail/hashmap_helpers.h"

#include "ankerl/unordered_dense.h"

DISABLE_COMPILER_WARNINGS
#include <QIcon>
Expand All @@ -18,21 +15,15 @@ class CIconProvider
{
public:
// guessIconByFileExtension is a less precise method, but much faster since it doesn't access the disk
static const QIcon& iconForFilesystemObject(const CFileSystemObject& object, bool guessIconByFileExtension);
static QIcon iconForFilesystemObject(const CFileSystemObject& object, bool guessIconByFileExtension);
static void settingsChanged();

private:
static CIconProvider& get();

CIconProvider();
const QIcon& iconFor(const CFileSystemObject& object, bool guessIconByFileExtension);
const QIcon& iconFast(const CFileSystemObject& object);
void onSettingsChanged();

private:
static std::unique_ptr<CIconProvider> _instance;

ankerl::unordered_dense::segmented_map<qint64, QIcon, NullHashExtraMixing> _iconByKey;
ankerl::unordered_dense::segmented_map<QString, QIcon, QStringHash> _iconByExtension;

ankerl::unordered_dense::map<qulonglong, qint64, NullHash> _iconKeyByObjectHash;

std::unique_ptr<CIconProviderImpl> _provider;
};

0 comments on commit 1b10724

Please sign in to comment.