GeezerVison is showing github.com — Use xxHash · diffscope/diffscope-project@fd1b73f
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: scripts/vcpkg-manifest/vcpkg.json +2-1Lines changed: 2 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 34 | 34 | { | 35 | 35 | "name": "libarchive", | 36 | 36 | "default-features": false | 37 | | - } | | 37 | + }, | | 38 | + "xxhash" | 38 | 39 | ], | 39 | 40 | "vcpkg-configuration": { | 40 | 41 | "overlay-ports": [ | |
Collapse file Copy file name to clipboard Collapse file Copy file name to clipboardExpand all lines: src/plugins/audio/CMakeLists.txt +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -3,6 +3,8 @@ project(audio | 3 | 3 | DESCRIPTION ${CURRENT_PLUGIN_DESC} | 4 | 4 | ) | 5 | 5 |
| | 6 | +find_package(xxHash CONFIG REQUIRED) | | 7 | + | 6 | 8 | diffscope_add_builtin_plugin(${PROJECT_NAME} | 7 | 9 | NAME org.diffscope.audio | 8 | 10 | DISPLAY_NAME Audio | @@ -29,6 +31,7 @@ diffscope_add_builtin_plugin(${PROJECT_NAME} | 29 | 31 | talcs::Dspx | 30 | 32 | talcs::Format | 31 | 33 | talcs::Widgets | | 34 | + xxHash::xxhash | 32 | 35 | INCLUDE_PRIVATE | 33 | 36 | internal/** | 34 | 37 | ) | |
Collapse file Copy file name to clipboardExpand all lines: src/plugins/audio/internal/addon/AudioClipAddOn.cpp +3-3Lines changed: 3 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -172,7 +172,7 @@ namespace Audio::Internal { | 172 | 172 | updateAudioPathLocation(&path, filePath); | 173 | 173 | path.formatEntryClassName = entryClassName; | 174 | 174 | path.userData = userData; | 175 | | - path.sha512 = HashHelper::sha512(QFileInfo(filePath).absoluteFilePath()); | | 175 | + path.digest = HashHelper::digest(QFileInfo(filePath).absoluteFilePath()); | 176 | 176 | return path; | 177 | 177 | } | 178 | 178 |
| @@ -341,13 +341,13 @@ namespace Audio::Internal { | 341 | 341 |
| 342 | 342 | auto path = clip->path(); | 343 | 343 | const auto filePath = QDir(path.absoluteDir).filePath(path.fileName); | 344 | | - const auto sha512 = HashHelper::sha512(filePath); | | 344 | + const auto sha512 = HashHelper::digest(filePath); | 345 | 345 | if (sha512.isEmpty()) { | 346 | 346 | qCWarning(lcAudioClipAddOn) << "Failed to update audio clip digest from absolute path" << clip << filePath; | 347 | 347 | return; | 348 | 348 | } | 349 | 349 |
| 350 | | - path.sha512 = sha512; | | 350 | + path.digest = sha512; | 351 | 351 | document->transactionController()->beginScopedTransaction(tr("Updating audio clip digest"), [=] { | 352 | 352 | clip->setPath(path); | 353 | 353 | return true; | |
Collapse file Copy file name to clipboardExpand all lines: src/plugins/audio/internal/addon/ProjectAudioAddOn.cpp +5-5Lines changed: 5 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -52,7 +52,7 @@ namespace Audio::Internal { | 52 | 52 | } | 53 | 53 |
| 54 | 54 | static bool sha512Matches(const QString &filePath, const QString &expected) { | 55 | | - return !expected.isEmpty() && HashHelper::sha512(filePath).compare(expected, Qt::CaseInsensitive) == 0; | | 55 | + return !expected.isEmpty() && HashHelper::digest(filePath).compare(expected, Qt::CaseInsensitive) == 0; | 56 | 56 | } | 57 | 57 |
| 58 | 58 | ProjectAudioAddOn::ProjectAudioAddOn(QObject *parent) | @@ -507,7 +507,7 @@ namespace Audio::Internal { | 507 | 507 |
| 508 | 508 | if (QFileInfo(absoluteFilePath).isFile()) { | 509 | 509 | filePath = absoluteFilePath; | 510 | | - if (!sha512Matches(filePath, path.sha512)) { | | 510 | + if (!sha512Matches(filePath, path.digest)) { | 511 | 511 | status = AudioClipAudioContext::FileContentChanged; | 512 | 512 | } | 513 | 513 | } else { | @@ -517,11 +517,11 @@ namespace Audio::Internal { | 517 | 517 | if (!projectFilePath.isEmpty()) { | 518 | 518 | const auto projectDir = QFileInfo(projectFilePath).absoluteDir(); | 519 | 519 | const auto relativeFilePath = normalizedAbsolutePath(projectDir.filePath(QDir(path.relativeDir).filePath(path.fileName))); | 520 | | - if (QFileInfo(relativeFilePath).isFile() && sha512Matches(relativeFilePath, path.sha512)) { | | 520 | + if (QFileInfo(relativeFilePath).isFile() && sha512Matches(relativeFilePath, path.digest)) { | 521 | 521 | filePath = relativeFilePath; | 522 | 522 | } else { | 523 | 523 | const auto siblingFilePath = normalizedAbsolutePath(projectDir.filePath(path.fileName)); | 524 | | - if (QFileInfo(siblingFilePath).isFile() && sha512Matches(siblingFilePath, path.sha512)) { | | 524 | + if (QFileInfo(siblingFilePath).isFile() && sha512Matches(siblingFilePath, path.digest)) { | 525 | 525 | filePath = siblingFilePath; | 526 | 526 | } | 527 | 527 | } | @@ -584,7 +584,7 @@ namespace Audio::Internal { | 584 | 584 | windowInterface->sendNotification(SVS::SVSCraft::Warning, tr("Audio file moved"), tr("The file in audio clip \"%1\" has been moved.\nFrom: %2\nTo: %3").arg(clip->name(), path, QDir::toNativeSeparators(context->realAudioPath()))); | 585 | 585 | } else if (context->status() == AudioClipAudioContext::FileContentChanged) { | 586 | 586 | qCWarning(lcProjectAudioAddOn) << "Audio clip file content changed:" << clip->name() << clip->path().absoluteDir << clip->path().relativeDir << clip->path().fileName; | 587 | | - if (!clip->path().sha512.isEmpty()) { | | 587 | + if (!clip->path().digest.isEmpty()) { | 588 | 588 | // Empty file digest suggests that the project file might be created by another editor. We do not explicitly notify user in this case. | 589 | 589 | windowInterface->sendNotification(SVS::SVSCraft::Warning, tr("Audio file content changed"), tr("The file in audio clip \"%1\" has been changed:\n%2").arg(clip->name(), path)); | 590 | 590 | } | |
Collapse file Copy file name to clipboard +31-6Lines changed: 31 additions & 6 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | #include "HashHelper.h" | 2 | 2 |
| 3 | | -#include <QCryptographicHash> | | 3 | +#include <xxhash.h> | | 4 | + | 4 | 5 | #include <QFile> | 5 | 6 |
| 6 | 7 | namespace Audio::Internal { | 7 | 8 |
| 8 | | - QString HashHelper::sha512(const QString &filePath) { | | 9 | + namespace { | | 10 | + struct XXH3StateDeleter { | | 11 | + void operator()(XXH3_state_t* state) const noexcept { | | 12 | + XXH3_freeState(state); | | 13 | + } | | 14 | + }; | | 15 | + using XXH3StatePtr = std::unique_ptr<XXH3_state_t, XXH3StateDeleter>; | | 16 | + | | 17 | + } | | 18 | + | | 19 | + QString HashHelper::digest(const QString &filePath) { | 9 | 20 | QFile file(filePath); | 10 | 21 | if (!file.open(QIODevice::ReadOnly)) { | 11 | 22 | return {}; | 12 | 23 | } | 13 | | - | 14 | | - QCryptographicHash hash(QCryptographicHash::Sha512); | 15 | | - if (!hash.addData(&file)) { | | 24 | + XXH3StatePtr state{XXH3_createState()}; | | 25 | + if (XXH3_128bits_reset(state.get()) != XXH_OK) { | 16 | 26 | return {}; | 17 | 27 | } | 18 | | - return QString::fromLatin1(hash.result().toHex()); | | 28 | + constexpr std::size_t BufferSize = 256 * 1024; | | 29 | + std::array<char, BufferSize> buffer; | | 30 | + while (true) { | | 31 | + const qint64 size = file.read(buffer.data(),static_cast<qint64>(buffer.size())); | | 32 | + if (size < 0) { | | 33 | + return {}; | | 34 | + } | | 35 | + if (size == 0) { | | 36 | + break; | | 37 | + } | | 38 | + if (XXH3_128bits_update(state.get(), buffer.data(), static_cast<std::size_t>(size)) != XXH_OK) { | | 39 | + return {}; | | 40 | + } | | 41 | + } | | 42 | + const auto result = XXH3_128bits_digest(state.get()); | | 43 | + return QString::fromLatin1(QByteArray(reinterpret_cast<const char*>(&result), sizeof(result)).toBase64(QByteArray::Base64UrlEncoding)); | 19 | 44 | } | 20 | 45 |
| 21 | 46 | } |
Collapse file Copy file name to clipboardExpand all lines: src/plugins/audio/internal/utils/HashHelper.h +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -7,7 +7,7 @@ namespace Audio::Internal { | 7 | 7 |
| 8 | 8 | class HashHelper { | 9 | 9 | public: | 10 | | - static QString sha512(const QString &filePath); | | 10 | + static QString digest(const QString &filePath); | 11 | 11 | }; | 12 | 12 |
| 13 | 13 | } | |
Collapse file Copy file name to clipboardExpand all lines: src/plugins/audio/qml/propertyeditors/AudioPropertyEditor.qml +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -102,7 +102,7 @@ PropertyEditorGroupBox { | 102 | 102 | ThemedItem.controlType: SVS.CT_Warning | 103 | 103 | label: qsTr("Audio file content changed") | 104 | 104 | visible: groupBox.audioClipAudioContext?.status === AudioClipAudioContext.FileContentChanged | 105 | | - && Boolean(groupBox.audioClip?.path.sha512) | | 105 | + && Boolean(groupBox.audioClip?.path.digest) | 106 | 106 | display: AbstractButton.TextBesideIcon | 107 | 107 | action: Action { | 108 | 108 | text: qsTr("Confirm the Change") | @@ -116,7 +116,7 @@ PropertyEditorGroupBox { | 116 | 116 | ThemedItem.controlType: SVS.CT_Warning | 117 | 117 | label: qsTr("Audio file content consistency unknown") | 118 | 118 | visible: groupBox.audioClipAudioContext?.status === AudioClipAudioContext.FileContentChanged | 119 | | - && !groupBox.audioClip?.path.sha512 | | 119 | + && !groupBox.audioClip?.path.digest | 120 | 120 | display: AbstractButton.TextBesideIcon | 121 | 121 | action: Action { | 122 | 122 | text: qsTr("Confirm Current File") | |
Collapse file Copy file name to clipboardExpand all lines: src/plugins/synth/CMakeLists.txt +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -3,6 +3,8 @@ project(synth | 3 | 3 | DESCRIPTION ${CURRENT_PLUGIN_DESC} | 4 | 4 | ) | 5 | 5 |
| | 6 | +find_package(xxHash CONFIG REQUIRED) | | 7 | + | 6 | 8 | diffscope_add_builtin_plugin(${PROJECT_NAME} | 7 | 9 | NAME org.diffscope.synth | 8 | 10 | DISPLAY_NAME Synthesis | @@ -38,6 +40,7 @@ diffscope_add_builtin_plugin(${PROJECT_NAME} | 38 | 40 | svscraft::Quick | 39 | 41 | svscraft::QmlExtras | 40 | 42 | SVSCraft3rdParty_tinyexpr | | 43 | + xxHash::xxhash | 41 | 44 | INCLUDE_PRIVATE | 42 | 45 | internal/** | 43 | 46 | ) |
Collapse file Copy file name to clipboardExpand all lines: src/plugins/synth/internal/parameters/ParameterRuntimeRegistry.cpp +12-23Lines changed: 12 additions & 23 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 2 | 2 |
| 3 | 3 | #include <tinyexpr.h> | 4 | 4 |
| | 5 | +#include <xxhash.h> | | 6 | + | 5 | 7 | #include <algorithm> | 6 | 8 | #include <cmath> | 7 | 9 | #include <mutex> | 8 | 10 |
| 9 | 11 | #include <QCoreApplication> | 10 | | -#include <QCryptographicHash> | 11 | 12 | #include <QJsonDocument> | 12 | 13 | #include <QLocale> | 13 | 14 |
| @@ -86,8 +87,8 @@ namespace Synth::Internal { | 86 | 87 | } | 87 | 88 |
| 88 | 89 | struct ParameterRuntimeRegistry::Context { | 89 | | - explicit Context(const ParameterConfiguration &source, const QByteArray &json) | 90 | | - : configuration(source), normalizedJson(json) { | | 90 | + explicit Context(const ParameterConfiguration &source) | | 91 | + : configuration(source) { | 91 | 92 | } | 92 | 93 |
| 93 | 94 | bool compile(QString *errorMessage) { | @@ -109,7 +110,6 @@ namespace Synth::Internal { | 109 | 110 | } | 110 | 111 |
| 111 | 112 | ParameterConfiguration configuration; | 112 | | - QByteArray normalizedJson; | 113 | 113 | CompiledExpression normalization; | 114 | 114 | CompiledExpression denormalization; | 115 | 115 | CompiledExpression display; | @@ -137,28 +137,17 @@ namespace Synth::Internal { | 137 | 137 | } | 138 | 138 |
| 139 | 139 | const auto normalizedJson = QJsonDocument(configuration.toJson()).toJson(QJsonDocument::Compact); | 140 | | - auto handle = QCryptographicHash::hash(normalizedJson, QCryptographicHash::Sha512); | | 140 | + const auto hashResult = XXH3_128bits(normalizedJson.data(), normalizedJson.size()); | | 141 | + const auto handle = QByteArray(reinterpret_cast<const char *>(&hashResult), sizeof(hashResult)); | 141 | 142 | std::shared_ptr<Context> runtime; | 142 | 143 | { | 143 | 144 | std::lock_guard lock(m_mutex); | 144 | | - quint32 collisionIndex{}; | 145 | | - while (true) { | 146 | | - const auto existing = m_contexts.value(handle); | 147 | | - if (!existing) { | 148 | | - runtime = std::make_shared<Context>(configuration, normalizedJson); | 149 | | - if (!runtime->compile(errorMessage)) | 150 | | - return false; | 151 | | - m_contexts.insert(handle, runtime); | 152 | | - break; | 153 | | - } | 154 | | - if (existing->normalizedJson == normalizedJson) { | 155 | | - runtime = existing; | 156 | | - break; | 157 | | - } | 158 | | - ++collisionIndex; | 159 | | - handle = QCryptographicHash::hash( | 160 | | - normalizedJson + QByteArray::number(collisionIndex), QCryptographicHash::Sha512 | 161 | | - ); | | 145 | + runtime = m_contexts.value(handle); | | 146 | + if (!runtime) { | | 147 | + runtime = std::make_shared<Context>(configuration); | | 148 | + if (!runtime->compile(errorMessage)) | | 149 | + return false; | | 150 | + m_contexts.insert(handle, runtime); | 162 | 151 | } | 163 | 152 | } | 164 | 153 |
| |
|