summaryrefslogtreecommitdiff
path: root/src/database
diff options
context:
space:
mode:
Diffstat (limited to 'src/database')
-rw-r--r--src/database/CMakeLists.txt2
-rw-r--r--src/database/database.cpp74
-rw-r--r--src/database/file_gatherer.cpp22
-rw-r--r--src/database/include/database.hpp22
-rw-r--r--src/database/include/file_gatherer.hpp8
-rw-r--r--src/database/include/index.hpp10
-rw-r--r--src/database/include/records.hpp8
-rw-r--r--src/database/include/tag_parser.hpp18
-rw-r--r--src/database/include/track.hpp29
-rw-r--r--src/database/index.cpp10
-rw-r--r--src/database/records.cpp36
-rw-r--r--src/database/tag_parser.cpp38
-rw-r--r--src/database/test/test_database.cpp12
-rw-r--r--src/database/test/test_records.cpp4
-rw-r--r--src/database/track.cpp20
15 files changed, 169 insertions, 144 deletions
diff --git a/src/database/CMakeLists.txt b/src/database/CMakeLists.txt
index 008757f8..dffc3a26 100644
--- a/src/database/CMakeLists.txt
+++ b/src/database/CMakeLists.txt
@@ -7,7 +7,7 @@ idf_component_register(
"file_gatherer.cpp" "tag_parser.cpp" "index.cpp"
INCLUDE_DIRS "include"
REQUIRES "result" "span" "esp_psram" "fatfs" "libtags" "komihash" "cbor"
- "tasks" "shared_string" "util" "tinyfsm" "events" "opusfile")
+ "tasks" "memory" "util" "tinyfsm" "events" "opusfile")
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/database/database.cpp b/src/database/database.cpp
index d73ce771..fd0e50c1 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -31,6 +31,7 @@
#include "env_esp.hpp"
#include "event_queue.hpp"
#include "file_gatherer.hpp"
+#include "memory_resource.hpp"
#include "records.hpp"
#include "result.hpp"
#include "tag_parser.hpp"
@@ -195,7 +196,7 @@ auto Database::Update() -> std::future<void> {
events::Ui().Dispatch(event::UpdateProgress{
.stage = event::UpdateProgress::Stage::kScanningForNewTracks,
});
- file_gatherer_.FindFiles("", [&](const std::string& path) {
+ file_gatherer_.FindFiles("", [&](const std::pmr::string& path) {
TrackTags tags;
if (!tag_parser_.ReadAndParseTags(path, &tags) ||
tags.encoding() == Container::kUnsupported) {
@@ -252,9 +253,9 @@ auto Database::Update() -> std::future<void> {
}
auto Database::GetTrackPath(TrackId id)
- -> std::future<std::optional<std::string>> {
- return worker_task_->Dispatch<std::optional<std::string>>(
- [=, this]() -> std::optional<std::string> {
+ -> std::future<std::optional<std::pmr::string>> {
+ return worker_task_->Dispatch<std::optional<std::pmr::string>>(
+ [=, this]() -> std::optional<std::pmr::string> {
auto track_data = dbGetTrackData(id);
if (track_data) {
return track_data->filepath();
@@ -362,14 +363,14 @@ auto Database::GetTracks(std::size_t page_size) -> std::future<Result<Track>*> {
}
auto Database::GetDump(std::size_t page_size)
- -> std::future<Result<std::string>*> {
- return worker_task_->Dispatch<Result<std::string>*>(
- [=, this]() -> Result<std::string>* {
- Continuation<std::string> c{.prefix = "",
- .start_key = "",
- .forward = true,
- .was_prev_forward = true,
- .page_size = page_size};
+ -> std::future<Result<std::pmr::string>*> {
+ return worker_task_->Dispatch<Result<std::pmr::string>*>(
+ [=, this]() -> Result<std::pmr::string>* {
+ Continuation<std::pmr::string> c{.prefix = "",
+ .start_key = "",
+ .forward = true,
+ .was_prev_forward = true,
+ .page_size = page_size};
return dbGetPage(c);
});
}
@@ -385,8 +386,9 @@ template auto Database::GetPage<Track>(Continuation<Track>* c)
-> std::future<Result<Track>*>;
template auto Database::GetPage<IndexRecord>(Continuation<IndexRecord>* c)
-> std::future<Result<IndexRecord>*>;
-template auto Database::GetPage<std::string>(Continuation<std::string>* c)
- -> std::future<Result<std::string>*>;
+template auto Database::GetPage<std::pmr::string>(
+ Continuation<std::pmr::string>* c)
+ -> std::future<Result<std::pmr::string>*>;
auto Database::dbMintNewTrackId() -> TrackId {
TrackId next_id = 1;
@@ -466,7 +468,7 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
// Work out our starting point. Sometimes this will already done.
std::unique_ptr<leveldb::Iterator> it{
db_->NewIterator(leveldb::ReadOptions{})};
- it->Seek(c.start_key);
+ it->Seek({c.start_key.data(), c.start_key.size()});
// Fix off-by-one if we just changed direction.
if (c.forward != c.was_prev_forward) {
@@ -478,10 +480,10 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
}
// Grab results.
- std::optional<std::string> first_key;
+ std::optional<std::pmr::string> first_key;
std::vector<T> records;
while (records.size() < c.page_size && it->Valid()) {
- if (!it->key().starts_with(c.prefix)) {
+ if (!it->key().starts_with({c.prefix.data(), c.prefix.size()})) {
break;
}
if (!first_key) {
@@ -498,7 +500,8 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
}
}
- if (!it->Valid() || !it->key().starts_with(c.prefix)) {
+ if (!it->Valid() ||
+ !it->key().starts_with({c.prefix.data(), c.prefix.size()})) {
it.reset();
}
@@ -512,7 +515,8 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
if (c.forward) {
if (it != nullptr) {
// We were going forward, and now we want the next page.
- std::string key = it->key().ToString();
+ std::pmr::string key{it->key().data(), it->key().size(),
+ &memory::kSpiRamResource};
next_page = Continuation<T>{
.prefix = c.prefix,
.start_key = key,
@@ -549,7 +553,8 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
} else {
if (it != nullptr) {
// We were going backwards, and we still want to go backwards.
- std::string key = it->key().ToString();
+ std::pmr::string key{it->key().data(), it->key().size(),
+ &memory::kSpiRamResource};
prev_page = Continuation<T>{
.prefix = c.prefix,
.start_key = key,
@@ -566,8 +571,8 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
template auto Database::dbGetPage<Track>(const Continuation<Track>& c)
-> Result<Track>*;
-template auto Database::dbGetPage<std::string>(
- const Continuation<std::string>& c) -> Result<std::string>*;
+template auto Database::dbGetPage<std::pmr::string>(
+ const Continuation<std::pmr::string>& c) -> Result<std::pmr::string>*;
template <>
auto Database::ParseRecord<IndexRecord>(const leveldb::Slice& key,
@@ -578,7 +583,7 @@ auto Database::ParseRecord<IndexRecord>(const leveldb::Slice& key,
return {};
}
- std::optional<std::string> title;
+ std::optional<std::pmr::string> title;
if (!val.empty()) {
title = val.ToString();
}
@@ -602,43 +607,42 @@ auto Database::ParseRecord<Track>(const leveldb::Slice& key,
}
template <>
-auto Database::ParseRecord<std::string>(const leveldb::Slice& key,
- const leveldb::Slice& val)
- -> std::optional<std::string> {
+auto Database::ParseRecord<std::pmr::string>(const leveldb::Slice& key,
+ const leveldb::Slice& val)
+ -> std::optional<std::pmr::string> {
std::ostringstream stream;
stream << "key: ";
if (key.size() < 3 || key.data()[1] != '\0') {
stream << key.ToString().c_str();
} else {
- std::string str = key.ToString();
- for (size_t i = 0; i < str.size(); i++) {
+ for (size_t i = 0; i < key.size(); i++) {
if (i == 0) {
- stream << str[i];
+ stream << key.data()[i];
} else if (i == 1) {
stream << " / 0x";
} else {
stream << std::hex << std::setfill('0') << std::setw(2)
- << static_cast<int>(str[i]);
+ << static_cast<int>(key.data()[i]);
}
}
}
if (!val.empty()) {
stream << "\tval: 0x";
- std::string str = val.ToString();
for (int i = 0; i < val.size(); i++) {
stream << std::hex << std::setfill('0') << std::setw(2)
- << static_cast<int>(str[i]);
+ << static_cast<int>(val.data()[i]);
}
}
- return stream.str();
+ std::pmr::string res{stream.str(), &memory::kSpiRamResource};
+ return res;
}
IndexRecord::IndexRecord(const IndexKey& key,
- std::optional<shared_string> title,
+ std::optional<std::pmr::string> title,
std::optional<TrackId> track)
: key_(key), override_text_(title), track_(track) {}
-auto IndexRecord::text() const -> std::optional<shared_string> {
+auto IndexRecord::text() const -> std::optional<std::pmr::string> {
if (override_text_) {
return override_text_;
}
diff --git a/src/database/file_gatherer.cpp b/src/database/file_gatherer.cpp
index 2d17a925..d8c80b0d 100644
--- a/src/database/file_gatherer.cpp
+++ b/src/database/file_gatherer.cpp
@@ -13,18 +13,20 @@
#include "ff.h"
+#include "memory_resource.hpp"
+
namespace database {
static_assert(sizeof(TCHAR) == sizeof(char), "TCHAR must be CHAR");
-auto FileGathererImpl::FindFiles(const std::string& root,
- std::function<void(const std::string&)> cb)
- -> void {
- std::deque<std::string> to_explore;
+auto FileGathererImpl::FindFiles(
+ const std::pmr::string& root,
+ std::function<void(const std::pmr::string&)> cb) -> void {
+ std::pmr::deque<std::pmr::string> to_explore(&memory::kSpiRamResource);
to_explore.push_back(root);
while (!to_explore.empty()) {
- std::string next_path_str = to_explore.front();
+ std::pmr::string next_path_str = to_explore.front();
const TCHAR* next_path = static_cast<const TCHAR*>(next_path_str.c_str());
FF_DIR dir;
@@ -44,16 +46,18 @@ auto FileGathererImpl::FindFiles(const std::string& root,
// System or hidden file. Ignore it and move on.
continue;
} else {
- std::stringstream full_path;
- full_path << next_path_str << "/" << info.fname;
+ std::pmr::string full_path{&memory::kSpiRamResource};
+ full_path += next_path_str;
+ full_path += "/";
+ full_path += info.fname;
if (info.fattrib & AM_DIR) {
// This is a directory. Add it to the explore queue.
- to_explore.push_back(full_path.str());
+ to_explore.push_back(full_path);
} else {
// This is a file! Let the callback know about it.
// std::invoke(cb, full_path.str(), info);
- std::invoke(cb, full_path.str());
+ std::invoke(cb, full_path);
}
}
}
diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp
index 00704a5f..98540f41 100644
--- a/src/database/include/database.hpp
+++ b/src/database/include/database.hpp
@@ -22,9 +22,9 @@
#include "leveldb/iterator.h"
#include "leveldb/options.h"
#include "leveldb/slice.h"
+#include "memory_resource.hpp"
#include "records.hpp"
#include "result.hpp"
-#include "shared_string.h"
#include "tag_parser.hpp"
#include "tasks.hpp"
#include "track.hpp"
@@ -33,8 +33,8 @@ namespace database {
template <typename T>
struct Continuation {
- std::string prefix;
- std::string start_key;
+ std::pmr::string prefix;
+ std::pmr::string start_key;
bool forward;
bool was_prev_forward;
size_t page_size;
@@ -70,17 +70,17 @@ class Result {
class IndexRecord {
public:
explicit IndexRecord(const IndexKey&,
- std::optional<shared_string>,
+ std::optional<std::pmr::string>,
std::optional<TrackId>);
- auto text() const -> std::optional<shared_string>;
+ auto text() const -> std::optional<std::pmr::string>;
auto track() const -> std::optional<TrackId>;
auto Expand(std::size_t) const -> std::optional<Continuation<IndexRecord>>;
private:
IndexKey key_;
- std::optional<shared_string> override_text_;
+ std::optional<std::pmr::string> override_text_;
std::optional<TrackId> track_;
};
@@ -100,7 +100,7 @@ class Database {
auto Update() -> std::future<void>;
- auto GetTrackPath(TrackId id) -> std::future<std::optional<std::string>>;
+ auto GetTrackPath(TrackId id) -> std::future<std::optional<std::pmr::string>>;
auto GetTrack(TrackId id) -> std::future<std::optional<Track>>;
@@ -115,7 +115,7 @@ class Database {
auto GetTracksByIndex(const IndexInfo& index, std::size_t page_size)
-> std::future<Result<IndexRecord>*>;
auto GetTracks(std::size_t page_size) -> std::future<Result<Track>*>;
- auto GetDump(std::size_t page_size) -> std::future<Result<std::string>*>;
+ auto GetDump(std::size_t page_size) -> std::future<Result<std::pmr::string>*>;
template <typename T>
auto GetPage(Continuation<T>* c) -> std::future<Result<T>*>;
@@ -167,8 +167,8 @@ auto Database::ParseRecord<Track>(const leveldb::Slice& key,
const leveldb::Slice& val)
-> std::optional<Track>;
template <>
-auto Database::ParseRecord<std::string>(const leveldb::Slice& key,
- const leveldb::Slice& val)
- -> std::optional<std::string>;
+auto Database::ParseRecord<std::pmr::string>(const leveldb::Slice& key,
+ const leveldb::Slice& val)
+ -> std::optional<std::pmr::string>;
} // namespace database
diff --git a/src/database/include/file_gatherer.hpp b/src/database/include/file_gatherer.hpp
index ff0a6ac2..133cf81a 100644
--- a/src/database/include/file_gatherer.hpp
+++ b/src/database/include/file_gatherer.hpp
@@ -19,15 +19,15 @@ class IFileGatherer {
public:
virtual ~IFileGatherer(){};
- virtual auto FindFiles(const std::string& root,
- std::function<void(const std::string&)> cb)
+ virtual auto FindFiles(const std::pmr::string& root,
+ std::function<void(const std::pmr::string&)> cb)
-> void = 0;
};
class FileGathererImpl : public IFileGatherer {
public:
- virtual auto FindFiles(const std::string& root,
- std::function<void(const std::string&)> cb)
+ virtual auto FindFiles(const std::pmr::string& root,
+ std::function<void(const std::pmr::string&)> cb)
-> void override;
};
diff --git a/src/database/include/index.hpp b/src/database/include/index.hpp
index 17b40f5b..838eff31 100644
--- a/src/database/include/index.hpp
+++ b/src/database/include/index.hpp
@@ -17,7 +17,7 @@
#include "leveldb/slice.h"
#include "leveldb/write_batch.h"
-#include "shared_string.h"
+#include "memory_resource.hpp"
#include "track.hpp"
namespace database {
@@ -29,7 +29,7 @@ struct IndexInfo {
IndexId id;
// Localised, user-friendly description of this index. e.g. "Albums by Artist"
// or "All Tracks".
- std::string name;
+ std::pmr::string name;
// Specifier for how this index breaks down the database.
std::vector<Tag> components;
};
@@ -51,7 +51,7 @@ struct IndexKey {
// The filterable / selectable item that this key represents. "Jacqueline" for
// kArtist, "My Cool Album" for kAlbum, etc.
- std::optional<std::string> item;
+ std::optional<std::pmr::string> item;
// If this is a leaf component, the track id for this record.
// This could reasonably be the value for a record, but we keep it as a part
// of the key to help with disambiguation.
@@ -59,8 +59,8 @@ struct IndexKey {
};
auto Index(const IndexInfo&, const Track&, leveldb::WriteBatch*) -> bool;
-auto ExpandHeader(const IndexKey::Header&, const std::optional<std::string>&)
- -> IndexKey::Header;
+auto ExpandHeader(const IndexKey::Header&,
+ const std::optional<std::pmr::string>&) -> IndexKey::Header;
// Predefined indexes
// TODO(jacqueline): Make these defined at runtime! :)
diff --git a/src/database/include/records.hpp b/src/database/include/records.hpp
index 58f29b20..b144dece 100644
--- a/src/database/include/records.hpp
+++ b/src/database/include/records.hpp
@@ -16,7 +16,7 @@
#include "leveldb/slice.h"
#include "index.hpp"
-#include "shared_string.h"
+#include "memory_resource.hpp"
#include "track.hpp"
namespace database {
@@ -28,10 +28,10 @@ namespace database {
*/
class OwningSlice {
public:
- std::string data;
+ std::pmr::string data;
leveldb::Slice slice;
- explicit OwningSlice(std::string d);
+ explicit OwningSlice(std::pmr::string d);
};
/*
@@ -88,6 +88,6 @@ auto TrackIdToBytes(TrackId id) -> OwningSlice;
* Converts a track id encoded via TrackIdToBytes back into a TrackId. May
* return nullopt if parsing fails.
*/
-auto BytesToTrackId(const std::string& bytes) -> std::optional<TrackId>;
+auto BytesToTrackId(cpp::span<const char> bytes) -> std::optional<TrackId>;
} // namespace database
diff --git a/src/database/include/tag_parser.hpp b/src/database/include/tag_parser.hpp
index 85721357..d77967d8 100644
--- a/src/database/include/tag_parser.hpp
+++ b/src/database/include/tag_parser.hpp
@@ -16,24 +16,24 @@ namespace database {
class ITagParser {
public:
virtual ~ITagParser() {}
- virtual auto ReadAndParseTags(const std::string& path, TrackTags* out)
+ virtual auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
-> bool = 0;
};
class GenericTagParser : public ITagParser {
public:
- auto ReadAndParseTags(const std::string& path, TrackTags* out)
+ auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
-> bool override;
};
class TagParserImpl : public ITagParser {
public:
TagParserImpl();
- auto ReadAndParseTags(const std::string& path, TrackTags* out)
+ auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
-> bool override;
private:
- std::map<std::string, std::unique_ptr<ITagParser>> extension_to_parser_;
+ std::map<std::pmr::string, std::unique_ptr<ITagParser>> extension_to_parser_;
GenericTagParser generic_parser_;
/*
@@ -41,16 +41,16 @@ class TagParserImpl : public ITagParser {
* cache should be slightly larger than any page sizes in the UI.
*/
std::mutex cache_mutex_;
- util::LruCache<16, std::string, TrackTags> cache_;
+ util::LruCache<16, std::pmr::string, TrackTags> cache_;
- // We could also consider keeping caches of artist name -> shared_string and
- // similar. This hasn't been done yet, as this isn't a common workload in any
- // of our UI.
+ // We could also consider keeping caches of artist name -> std::pmr::string
+ // and similar. This hasn't been done yet, as this isn't a common workload in
+ // any of our UI.
};
class OpusTagParser : public ITagParser {
public:
- auto ReadAndParseTags(const std::string& path, TrackTags* out)
+ auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
-> bool override;
};
diff --git a/src/database/include/track.hpp b/src/database/include/track.hpp
index 41f552d2..1c11ddea 100644
--- a/src/database/include/track.hpp
+++ b/src/database/include/track.hpp
@@ -16,7 +16,7 @@
#include <utility>
#include "leveldb/db.h"
-#include "shared_string.h"
+#include "memory_resource.hpp"
#include "span.hpp"
namespace database {
@@ -64,7 +64,8 @@ class TrackTags {
auto encoding() const -> Container { return encoding_; };
auto encoding(Container e) -> void { encoding_ = e; };
- TrackTags() : encoding_(Container::kUnsupported) {}
+ TrackTags()
+ : encoding_(Container::kUnsupported), tags_(&memory::kSpiRamResource) {}
std::optional<int> channels;
std::optional<int> sample_rate;
@@ -72,9 +73,9 @@ class TrackTags {
std::optional<int> duration;
- auto set(const Tag& key, const std::string& val) -> void;
- auto at(const Tag& key) const -> std::optional<shared_string>;
- auto operator[](const Tag& key) const -> std::optional<shared_string>;
+ auto set(const Tag& key, const std::pmr::string& val) -> void;
+ auto at(const Tag& key) const -> std::optional<std::pmr::string>;
+ auto operator[](const Tag& key) const -> std::optional<std::pmr::string>;
/*
* Returns a hash of the 'identifying' tags of this track. That is, a hash
@@ -90,7 +91,7 @@ class TrackTags {
private:
Container encoding_;
- std::unordered_map<Tag, shared_string> tags_;
+ std::pmr::unordered_map<Tag, std::pmr::string> tags_;
};
/*
@@ -113,33 +114,33 @@ class TrackTags {
class TrackData {
private:
const TrackId id_;
- const std::string filepath_;
+ const std::pmr::string filepath_;
const uint64_t tags_hash_;
const uint32_t play_count_;
const bool is_tombstoned_;
public:
/* Constructor used when adding new tracks to the database. */
- TrackData(TrackId id, const std::string& path, uint64_t hash)
+ TrackData(TrackId id, const std::pmr::string& path, uint64_t hash)
: id_(id),
- filepath_(path),
+ filepath_(path, &memory::kSpiRamResource),
tags_hash_(hash),
play_count_(0),
is_tombstoned_(false) {}
TrackData(TrackId id,
- const std::string& path,
+ const std::pmr::string& path,
uint64_t hash,
uint32_t play_count,
bool is_tombstoned)
: id_(id),
- filepath_(path),
+ filepath_(path, &memory::kSpiRamResource),
tags_hash_(hash),
play_count_(play_count),
is_tombstoned_(is_tombstoned) {}
auto id() const -> TrackId { return id_; }
- auto filepath() const -> std::string { return filepath_; }
+ auto filepath() const -> std::pmr::string { return filepath_; }
auto play_count() const -> uint32_t { return play_count_; }
auto tags_hash() const -> uint64_t { return tags_hash_; }
auto is_tombstoned() const -> bool { return is_tombstoned_; }
@@ -156,7 +157,7 @@ class TrackData {
* Clears the tombstone bit of this track, and updates the path to reflect its
* new location.
*/
- auto Exhume(const std::string& new_path) const -> TrackData;
+ auto Exhume(const std::pmr::string& new_path) const -> TrackData;
bool operator==(const TrackData&) const = default;
};
@@ -178,7 +179,7 @@ class Track {
auto data() const -> const TrackData& { return data_; }
auto tags() const -> const TrackTags& { return tags_; }
- auto TitleOrFilename() const -> shared_string;
+ auto TitleOrFilename() const -> std::pmr::string;
bool operator==(const Track&) const = default;
Track operator=(const Track& other) const { return Track(other); }
diff --git a/src/database/index.cpp b/src/database/index.cpp
index 9d77e530..79939aaa 100644
--- a/src/database/index.cpp
+++ b/src/database/index.cpp
@@ -41,7 +41,7 @@ const IndexInfo kAllAlbums{
};
static auto missing_component_text(const Track& track, Tag tag)
- -> std::optional<std::string> {
+ -> std::optional<std::pmr::string> {
switch (tag) {
case Tag::kArtist:
return "Unknown Artist";
@@ -76,9 +76,9 @@ auto Index(const IndexInfo& info, const Track& t, leveldb::WriteBatch* batch)
for (std::uint8_t i = 0; i < info.components.size(); i++) {
// Fill in the text for this depth.
auto text = t.tags().at(info.components.at(i));
- std::string value;
+ std::pmr::string value;
if (text) {
- std::string orig = *text;
+ std::pmr::string orig = *text;
key.item = col.transform(&orig[0], &orig[0] + orig.size());
value = *text;
} else {
@@ -94,7 +94,7 @@ auto Index(const IndexInfo& info, const Track& t, leveldb::WriteBatch* batch)
}
auto encoded = EncodeIndexKey(key);
- batch->Put(encoded.slice, value);
+ batch->Put(encoded.slice, {value.data(), value.size()});
// If there are more components after this, then we need to finish by
// narrowing the header with the current title.
@@ -106,7 +106,7 @@ auto Index(const IndexInfo& info, const Track& t, leveldb::WriteBatch* batch)
}
auto ExpandHeader(const IndexKey::Header& header,
- const std::optional<std::string>& component)
+ const std::optional<std::pmr::string>& component)
-> IndexKey::Header {
IndexKey::Header ret{header};
ret.depth++;
diff --git a/src/database/records.cpp b/src/database/records.cpp
index 0d28ca28..f493500c 100644
--- a/src/database/records.cpp
+++ b/src/database/records.cpp
@@ -8,7 +8,9 @@
#include <stdint.h>
+#include <functional>
#include <iomanip>
+#include <memory_resource>
#include <sstream>
#include <string>
#include <vector>
@@ -18,7 +20,7 @@
#include "index.hpp"
#include "komihash.h"
-#include "shared_string.h"
+#include "memory_resource.hpp"
#include "track.hpp"
// As LevelDB is a key-value store, each record in the database consists of a
@@ -47,6 +49,11 @@ static const char kHashPrefix = 'H';
static const char kIndexPrefix = 'I';
static const char kFieldSeparator = '\0';
+using ostringstream =
+ std::basic_ostringstream<char,
+ std::char_traits<char>,
+ std::pmr::polymorphic_allocator<char>>;
+
/*
* Helper function for allocating an appropriately-sized byte buffer, then
* encoding data into it.
@@ -78,7 +85,8 @@ auto cbor_encode(uint8_t** out_buf, T fn) -> std::size_t {
return buf_size;
}
-OwningSlice::OwningSlice(std::string d) : data(d), slice(data) {}
+OwningSlice::OwningSlice(std::pmr::string d)
+ : data(d), slice(data.data(), data.size()) {}
/* 'D/' */
auto EncodeDataPrefix() -> OwningSlice {
@@ -88,7 +96,7 @@ auto EncodeDataPrefix() -> OwningSlice {
/* 'D/ 0xACAB' */
auto EncodeDataKey(const TrackId& id) -> OwningSlice {
- std::ostringstream output;
+ ostringstream output;
output.put(kDataPrefix).put(kFieldSeparator);
output << TrackIdToBytes(id).data;
return OwningSlice(output.str());
@@ -136,7 +144,7 @@ auto EncodeDataValue(const TrackData& track) -> OwningSlice {
return;
}
});
- std::string as_str(reinterpret_cast<char*>(buf), buf_len);
+ std::pmr::string as_str(reinterpret_cast<char*>(buf), buf_len);
delete buf;
return OwningSlice(as_str);
}
@@ -174,7 +182,7 @@ auto ParseDataValue(const leveldb::Slice& slice) -> std::optional<TrackData> {
if (err != CborNoError || !cbor_value_is_unsigned_integer(&val)) {
return {};
}
- std::string path(raw_path, len);
+ std::pmr::string path(raw_path, len);
delete raw_path;
err = cbor_value_get_uint64(&val, &raw_int);
@@ -208,7 +216,7 @@ auto ParseDataValue(const leveldb::Slice& slice) -> std::optional<TrackData> {
/* 'H/ 0xBEEF' */
auto EncodeHashKey(const uint64_t& hash) -> OwningSlice {
- std::ostringstream output;
+ ostringstream output;
output.put(kHashPrefix).put(kFieldSeparator);
uint8_t buf[16];
@@ -222,7 +230,7 @@ auto EncodeHashKey(const uint64_t& hash) -> OwningSlice {
}
auto ParseHashValue(const leveldb::Slice& slice) -> std::optional<TrackId> {
- return BytesToTrackId(slice.ToString());
+ return BytesToTrackId({slice.data(), slice.size()});
}
auto EncodeHashValue(TrackId id) -> OwningSlice {
@@ -235,7 +243,7 @@ auto EncodeAllIndexesPrefix() -> OwningSlice {
return OwningSlice({data, 2});
}
-auto AppendIndexHeader(const IndexKey::Header& header, std::ostringstream* out)
+auto AppendIndexHeader(const IndexKey::Header& header, ostringstream* out)
-> void {
*out << kIndexPrefix << kFieldSeparator;
@@ -270,13 +278,13 @@ auto AppendIndexHeader(const IndexKey::Header& header, std::ostringstream* out)
return;
}
});
- std::string encoded{reinterpret_cast<char*>(buf), buf_len};
+ std::pmr::string encoded{reinterpret_cast<char*>(buf), buf_len};
delete buf;
*out << encoded << kFieldSeparator;
}
auto EncodeIndexPrefix(const IndexKey::Header& header) -> OwningSlice {
- std::ostringstream out;
+ ostringstream out;
AppendIndexHeader(header, &out);
return OwningSlice(out.str());
}
@@ -296,7 +304,7 @@ auto EncodeIndexPrefix(const IndexKey::Header& header) -> OwningSlice {
* id for now, but could reasonably be something like 'release year' as well.
*/
auto EncodeIndexKey(const IndexKey& key) -> OwningSlice {
- std::ostringstream out;
+ ostringstream out;
// Construct the header.
AppendIndexHeader(key.header, &out);
@@ -319,7 +327,7 @@ auto ParseIndexKey(const leveldb::Slice& slice) -> std::optional<IndexKey> {
IndexKey result{};
auto prefix = EncodeAllIndexesPrefix();
- if (!slice.starts_with(prefix.data)) {
+ if (!slice.starts_with(prefix.slice)) {
return {};
}
@@ -409,11 +417,11 @@ auto TrackIdToBytes(TrackId id) -> OwningSlice {
cbor_encoder_init(&enc, buf, sizeof(buf), 0);
cbor_encode_uint(&enc, id);
std::size_t len = cbor_encoder_get_buffer_size(&enc, buf);
- std::string as_str(reinterpret_cast<char*>(buf), len);
+ std::pmr::string as_str(reinterpret_cast<char*>(buf), len);
return OwningSlice(as_str);
}
-auto BytesToTrackId(const std::string& bytes) -> std::optional<TrackId> {
+auto BytesToTrackId(cpp::span<const char> bytes) -> std::optional<TrackId> {
CborParser parser;
CborValue val;
cbor_parser_init(reinterpret_cast<const uint8_t*>(bytes.data()), bytes.size(),
diff --git a/src/database/tag_parser.cpp b/src/database/tag_parser.cpp
index a4aaf0f5..8912690b 100644
--- a/src/database/tag_parser.cpp
+++ b/src/database/tag_parser.cpp
@@ -6,14 +6,17 @@
#include "tag_parser.hpp"
-#include <esp_log.h>
-#include <ff.h>
#include <stdint.h>
-#include <tags.h>
#include <cstdlib>
#include <iomanip>
#include <mutex>
+
+#include "esp_log.h"
+#include "ff.h"
#include "opusfile.h"
+#include "tags.h"
+
+#include "memory_resource.hpp"
namespace database {
@@ -25,13 +28,14 @@ const static std::array<std::pair<const char*, Tag>, 5> kVorbisIdToTag = {{
{"GENRE", Tag::kGenre},
}};
-static auto convert_track_number(int number) -> std::string {
+static auto convert_track_number(int number) -> std::pmr::string {
std::ostringstream oss;
oss << std::setw(4) << std::setfill('0') << number;
- return oss.str();
+ return std::pmr::string(oss.str());
}
-static auto convert_track_number(const std::string& raw) -> std::string {
+static auto convert_track_number(const std::pmr::string& raw)
+ -> std::pmr::string {
uint32_t as_int = std::atoi(raw.c_str());
return convert_track_number(as_int);
}
@@ -106,7 +110,7 @@ static void tag(Tagctx* ctx,
if (!tag) {
return;
}
- std::string value{v};
+ std::pmr::string value{v, &memory::kSpiRamResource};
if (value.empty()) {
return;
}
@@ -126,8 +130,8 @@ TagParserImpl::TagParserImpl() {
extension_to_parser_["opus"] = std::make_unique<OpusTagParser>();
}
-auto TagParserImpl::ReadAndParseTags(const std::string& path, TrackTags* out)
- -> bool {
+auto TagParserImpl::ReadAndParseTags(const std::pmr::string& path,
+ TrackTags* out) -> bool {
{
std::lock_guard<std::mutex> lock{cache_mutex_};
std::optional<TrackTags> cached = cache_.Get(path);
@@ -139,8 +143,8 @@ auto TagParserImpl::ReadAndParseTags(const std::string& path, TrackTags* out)
ITagParser* parser = &generic_parser_;
auto dot_pos = path.find_last_of(".");
- if (dot_pos != std::string::npos && path.size() - dot_pos > 1) {
- std::string extension = path.substr(dot_pos + 1);
+ if (dot_pos != std::pmr::string::npos && path.size() - dot_pos > 1) {
+ std::pmr::string extension = path.substr(dot_pos + 1);
std::transform(extension.begin(), extension.end(), extension.begin(),
[](unsigned char c) { return std::tolower(c); });
if (extension_to_parser_.contains(extension)) {
@@ -157,7 +161,7 @@ auto TagParserImpl::ReadAndParseTags(const std::string& path, TrackTags* out)
// start.
if (!out->at(Tag::kAlbumTrack)) {
auto slash_pos = path.find_last_of("/");
- if (slash_pos != std::string::npos && path.size() - slash_pos > 1) {
+ if (slash_pos != std::pmr::string::npos && path.size() - slash_pos > 1) {
out->set(Tag::kAlbumTrack, path.substr(slash_pos + 1));
}
}
@@ -175,8 +179,8 @@ auto TagParserImpl::ReadAndParseTags(const std::string& path, TrackTags* out)
return true;
}
-auto GenericTagParser::ReadAndParseTags(const std::string& path, TrackTags* out)
- -> bool {
+auto GenericTagParser::ReadAndParseTags(const std::pmr::string& path,
+ TrackTags* out) -> bool {
libtags::Aux aux;
aux.tags = out;
if (f_stat(path.c_str(), &aux.info) != FR_OK ||
@@ -239,9 +243,9 @@ auto GenericTagParser::ReadAndParseTags(const std::string& path, TrackTags* out)
return true;
}
-auto OpusTagParser::ReadAndParseTags(const std::string& path, TrackTags* out)
- -> bool {
- std::string vfs_path = "/sdcard" + path;
+auto OpusTagParser::ReadAndParseTags(const std::pmr::string& path,
+ TrackTags* out) -> bool {
+ std::pmr::string vfs_path = "/sdcard" + path;
int err;
OggOpusFile* f = op_test_file(vfs_path.c_str(), &err);
if (f == NULL) {
diff --git a/src/database/test/test_database.cpp b/src/database/test/test_database.cpp
index 1ce364d9..6aec9bfb 100644
--- a/src/database/test/test_database.cpp
+++ b/src/database/test/test_database.cpp
@@ -26,23 +26,25 @@ namespace database {
class TestBackends : public IFileGatherer, public ITagParser {
public:
- std::map<std::string, TrackTags> tracks;
+ std::map<std::pmr::string, TrackTags> tracks;
- auto MakeTrack(const std::string& path, const std::string& title) -> void {
+ auto MakeTrack(const std::pmr::string& path, const std::pmr::string& title)
+ -> void {
TrackTags tags;
tags.encoding = Encoding::kMp3;
tags.title = title;
tracks[path] = tags;
}
- auto FindFiles(const std::string& root,
- std::function<void(const std::string&)> cb) -> void override {
+ auto FindFiles(const std::pmr::string& root,
+ std::function<void(const std::pmr::string&)> cb)
+ -> void override {
for (auto keyval : tracks) {
std::invoke(cb, keyval.first);
}
}
- auto ReadAndParseTags(const std::string& path, TrackTags* out)
+ auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
-> bool override {
if (tracks.contains(path)) {
*out = tracks.at(path);
diff --git a/src/database/test/test_records.cpp b/src/database/test/test_records.cpp
index 5729003e..2f59489c 100644
--- a/src/database/test/test_records.cpp
+++ b/src/database/test/test_records.cpp
@@ -12,10 +12,10 @@
#include "catch2/catch.hpp"
-std::string ToHex(const std::string& s) {
+std::pmr::string ToHex(const std::pmr::string& s) {
std::ostringstream ret;
- for (std::string::size_type i = 0; i < s.length(); ++i)
+ for (std::pmr::string::size_type i = 0; i < s.length(); ++i)
ret << std::hex << std::setfill('0') << std::setw(2) << std::uppercase
<< (int)s[i];
diff --git a/src/database/track.cpp b/src/database/track.cpp
index fa65261e..a3c7dc99 100644
--- a/src/database/track.cpp
+++ b/src/database/track.cpp
@@ -7,15 +7,16 @@
#include "track.hpp"
#include <komihash.h>
-#include "shared_string.h"
+
+#include "memory_resource.hpp"
namespace database {
-auto TrackTags::set(const Tag& key, const std::string& val) -> void {
+auto TrackTags::set(const Tag& key, const std::pmr::string& val) -> void {
tags_[key] = val;
}
-auto TrackTags::at(const Tag& key) const -> std::optional<shared_string> {
+auto TrackTags::at(const Tag& key) const -> std::optional<std::pmr::string> {
if (tags_.contains(key)) {
return tags_.at(key);
}
@@ -23,12 +24,13 @@ auto TrackTags::at(const Tag& key) const -> std::optional<shared_string> {
}
auto TrackTags::operator[](const Tag& key) const
- -> std::optional<shared_string> {
+ -> std::optional<std::pmr::string> {
return at(key);
}
-/* Helper function to update a komihash stream with a std::string. */
-auto HashString(komihash_stream_t* stream, const std::string& str) -> void {
+/* Helper function to update a komihash stream with a std::pmr::string. */
+auto HashString(komihash_stream_t* stream, const std::pmr::string& str)
+ -> void {
komihash_stream_update(stream, str.c_str(), str.length());
}
@@ -58,7 +60,7 @@ auto TrackData::Entomb() const -> TrackData {
return TrackData(id_, filepath_, tags_hash_, play_count_, true);
}
-auto TrackData::Exhume(const std::string& new_path) const -> TrackData {
+auto TrackData::Exhume(const std::pmr::string& new_path) const -> TrackData {
return TrackData(id_, new_path, tags_hash_, play_count_, false);
}
@@ -68,13 +70,13 @@ void swap(Track& first, Track& second) {
second = temp;
}
-auto Track::TitleOrFilename() const -> shared_string {
+auto Track::TitleOrFilename() const -> std::pmr::string {
auto title = tags().at(Tag::kTitle);
if (title) {
return *title;
}
auto start = data().filepath().find_last_of('/');
- if (start == std::string::npos) {
+ if (start == std::pmr::string::npos) {
return data().filepath();
}
return data().filepath().substr(start);