Implement the file trie
This commit is contained in:
parent
336847ee7c
commit
99b7780ff3
5 changed files with 168 additions and 11 deletions
|
|
@ -21,7 +21,8 @@ set(VSTPLUGIN_SOURCES
|
||||||
SfizzForeignPaths.cpp
|
SfizzForeignPaths.cpp
|
||||||
VstPluginFactory.cpp
|
VstPluginFactory.cpp
|
||||||
X11RunLoop.cpp
|
X11RunLoop.cpp
|
||||||
NativeHelpers.cpp)
|
NativeHelpers.cpp
|
||||||
|
FileTrie.cpp)
|
||||||
|
|
||||||
set(VSTPLUGIN_HEADERS
|
set(VSTPLUGIN_HEADERS
|
||||||
SfizzVstProcessor.h
|
SfizzVstProcessor.h
|
||||||
|
|
@ -31,7 +32,8 @@ set(VSTPLUGIN_HEADERS
|
||||||
SfizzFileScan.h
|
SfizzFileScan.h
|
||||||
SfizzForeignPaths.h
|
SfizzForeignPaths.h
|
||||||
X11RunLoop.h
|
X11RunLoop.h
|
||||||
NativeHelpers.h)
|
NativeHelpers.h
|
||||||
|
FileTrie.h)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(VSTPLUGIN_MAC_SOURCES
|
set(VSTPLUGIN_MAC_SOURCES
|
||||||
|
|
|
||||||
98
vst/FileTrie.cpp
Normal file
98
vst/FileTrie.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include "FileTrie.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
constexpr size_t FileTrie::npos;
|
||||||
|
|
||||||
|
fs::path FileTrie::at(size_t index) const
|
||||||
|
{
|
||||||
|
if (index >= entries_.size())
|
||||||
|
throw std::out_of_range("FileTrie::at");
|
||||||
|
return pathFromEntry(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path FileTrie::operator[](size_t index) const
|
||||||
|
{
|
||||||
|
assert(index < entries_.size());
|
||||||
|
return pathFromEntry(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path FileTrie::pathFromEntry(size_t index) const
|
||||||
|
{
|
||||||
|
const Entry* currentEntry = &entries_[index];
|
||||||
|
fs::path path { currentEntry->name };
|
||||||
|
|
||||||
|
size_t currentIndex;
|
||||||
|
while ((currentIndex = currentEntry->parent) != npos) {
|
||||||
|
currentEntry = &entries_[currentIndex];
|
||||||
|
path = fs::path { currentEntry->name } / path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
FileTrieBuilder::FileTrieBuilder(size_t initialCapacity)
|
||||||
|
{
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
trie.entries_.reserve(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileTrie&& FileTrieBuilder::build()
|
||||||
|
{
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
trie.entries_.shrink_to_fit();
|
||||||
|
return std::move(trie);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileTrieBuilder::addFile(const fs::path& path)
|
||||||
|
{
|
||||||
|
if (path.empty())
|
||||||
|
return FileTrie::npos;
|
||||||
|
|
||||||
|
size_t dirIndex = ensureDirectory(path.parent_path());
|
||||||
|
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
FileTrie::Entry ent;
|
||||||
|
ent.parent = dirIndex;
|
||||||
|
ent.name = (--path.end())->u8string();
|
||||||
|
|
||||||
|
size_t fileIndex = trie.entries_.size();
|
||||||
|
trie.entries_.push_back(std::move(ent));
|
||||||
|
|
||||||
|
return fileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileTrieBuilder::ensureDirectory(const fs::path& dirPath)
|
||||||
|
{
|
||||||
|
if (dirPath.empty())
|
||||||
|
return FileTrie::npos;
|
||||||
|
|
||||||
|
const fs::path::string_type& dirNat = dirPath.native();
|
||||||
|
auto it = directories_.find(dirNat);
|
||||||
|
if (it != directories_.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
FileTrie& trie = trie_;
|
||||||
|
FileTrie::Entry ent;
|
||||||
|
ent.parent = FileTrie::npos;
|
||||||
|
ent.name = (--dirPath.end())->u8string();
|
||||||
|
if (dirPath.has_parent_path()) {
|
||||||
|
fs::path parentPath = dirPath.parent_path();
|
||||||
|
if (parentPath != dirPath)
|
||||||
|
ent.parent = ensureDirectory(parentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dirIndex = trie.entries_.size();
|
||||||
|
trie.entries_.push_back(std::move(ent));
|
||||||
|
|
||||||
|
directories_[dirNat] = dirIndex;
|
||||||
|
|
||||||
|
return dirIndex;
|
||||||
|
}
|
||||||
49
vst/FileTrie.h
Normal file
49
vst/FileTrie.h
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <ghc/fs_std.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
class FileTrie {
|
||||||
|
public:
|
||||||
|
static constexpr size_t npos = ~size_t(0);
|
||||||
|
|
||||||
|
size_t size() const noexcept { return entries_.size(); }
|
||||||
|
fs::path at(size_t index) const;
|
||||||
|
fs::path operator[](size_t index) const;
|
||||||
|
void clear() noexcept { entries_.clear(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
fs::path pathFromEntry(size_t index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Entry {
|
||||||
|
size_t parent = npos;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
std::vector<Entry> entries_;
|
||||||
|
|
||||||
|
friend class FileTrieBuilder;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
class FileTrieBuilder {
|
||||||
|
public:
|
||||||
|
explicit FileTrieBuilder(size_t initialCapacity = 8192);
|
||||||
|
FileTrie&& build();
|
||||||
|
size_t addFile(const fs::path& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t ensureDirectory(const fs::path& dirPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileTrie trie_;
|
||||||
|
std::unordered_map<fs::path::string_type, size_t> directories_;
|
||||||
|
};
|
||||||
|
|
@ -34,13 +34,13 @@ bool SfzFileScan::locateRealFile(const fs::path& pathOrig, fs::path& pathFound)
|
||||||
if (it == file_index_.end())
|
if (it == file_index_.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::list<std::string> candidateStrings = it->second;
|
const std::list<size_t>& candidateIndices = it->second;
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
std::vector<fs::path> candidates;
|
std::vector<fs::path> candidates;
|
||||||
candidates.reserve(candidateStrings.size());
|
candidates.reserve(candidateIndices.size());
|
||||||
for (const std::string& str : candidateStrings)
|
for (const size_t index : candidateIndices)
|
||||||
candidates.push_back(fs::u8path(str));
|
candidates.push_back(file_trie_[index]);
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
pathFound = electBestMatch(pathOrig, candidates);
|
pathFound = electBestMatch(pathOrig, candidates);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -57,8 +57,11 @@ void SfzFileScan::refreshScan(bool force)
|
||||||
if (!force && !isExpired())
|
if (!force && !isExpired())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
file_trie_.clear();
|
||||||
file_index_.clear();
|
file_index_.clear();
|
||||||
|
|
||||||
|
FileTrieBuilder builder;
|
||||||
|
|
||||||
for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) {
|
for (const fs::path& dirPath : SfizzPaths::sfzDefaultPaths()) {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
const fs::directory_options dirOpts =
|
const fs::directory_options dirOpts =
|
||||||
|
|
@ -71,11 +74,14 @@ void SfzFileScan::refreshScan(bool force)
|
||||||
const fs::directory_entry& ent = *it;
|
const fs::directory_entry& ent = *it;
|
||||||
const fs::path& filePath = ent.path();
|
const fs::path& filePath = ent.path();
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
if (ent.is_regular_file(ec) /*&& pathIsSfz(filePath)*/)
|
if (ent.is_regular_file(ec) /*&& pathIsSfz(filePath)*/) {
|
||||||
file_index_[keyOf(filePath.filename())].push_back(filePath.u8string());
|
size_t fileIndex = builder.addFile(filePath);
|
||||||
|
file_index_[keyOf(filePath.filename())].push_back(fileIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_trie_ = builder.build();
|
||||||
completion_time_ = clock::now();
|
completion_time_ = clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "FileTrie.h"
|
||||||
#include <absl/types/span.h>
|
#include <absl/types/span.h>
|
||||||
#include <absl/types/optional.h>
|
#include <absl/types/optional.h>
|
||||||
#include <ghc/fs_std.hpp>
|
#include <ghc/fs_std.hpp>
|
||||||
|
|
@ -23,7 +24,8 @@ private:
|
||||||
typedef std::chrono::steady_clock clock;
|
typedef std::chrono::steady_clock clock;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
absl::optional<clock::time_point> completion_time_;
|
absl::optional<clock::time_point> completion_time_;
|
||||||
std::unordered_map<std::string, std::list<std::string>> file_index_;
|
FileTrie file_trie_;
|
||||||
|
std::unordered_map<std::string, std::list<size_t>> file_index_;
|
||||||
|
|
||||||
bool isExpired() const;
|
bool isExpired() const;
|
||||||
void refreshScan(bool force = false);
|
void refreshScan(bool force = false);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue