summaryrefslogtreecommitdiff
path: root/lib/nes/common
diff options
context:
space:
mode:
authorHannes Schulze <haschu0103@outlook.de>2025-02-04 19:25:03 +0100
committerHannes Schulze <haschu0103@outlook.de>2025-02-04 19:25:03 +0100
commite791ac9a46095e0241181da89c35a7c702982c21 (patch)
treed959c79c24ae03282f1b00ec9bcb2ccf86d9c96c /lib/nes/common
parent0f22ed2ef160eef2da6080782943b22c9539650d (diff)
clean up path logic a bit
Diffstat (limited to 'lib/nes/common')
-rw-r--r--lib/nes/common/CMakeLists.txt6
-rw-r--r--lib/nes/common/path-builder.cc47
-rw-r--r--lib/nes/common/path-builder.hh38
-rw-r--r--lib/nes/common/path-view.cc49
-rw-r--r--lib/nes/common/path-view.hh52
-rw-r--r--lib/nes/common/string-builder.hh13
6 files changed, 168 insertions, 37 deletions
diff --git a/lib/nes/common/CMakeLists.txt b/lib/nes/common/CMakeLists.txt
index 11143d7..f0ee288 100644
--- a/lib/nes/common/CMakeLists.txt
+++ b/lib/nes/common/CMakeLists.txt
@@ -8,4 +8,8 @@ target_sources(
box.hh
display.hh
string-builder.hh
- string-builder.cc) \ No newline at end of file
+ string-builder.cc
+ path-view.hh
+ path-view.cc
+ path-builder.hh
+ path-builder.cc) \ No newline at end of file
diff --git a/lib/nes/common/path-builder.cc b/lib/nes/common/path-builder.cc
new file mode 100644
index 0000000..67190dc
--- /dev/null
+++ b/lib/nes/common/path-builder.cc
@@ -0,0 +1,47 @@
+#include "nes/common/path-builder.hh"
+
+namespace nes
+{
+ path_builder::path_builder(char* buffer, u32 const buffer_length)
+ : buffer_{ buffer }
+ , buffer_length_{ buffer_length }
+ {
+ // Initialize the path to "/" if possible.
+ if (buffer_length > 0) { buffer_[actual_length_++] = '/'; }
+ }
+
+ auto path_builder::push(std::string_view component) -> bool
+ {
+ // Trim leading and trailing slashes
+ while (!component.empty() && component[0] == '/') { component = component.substr(1); }
+ while (!component.empty() && component[component.length() - 1] == '/') { component = component.substr(0, component.length() - 1); }
+ if (component.empty() || std::find(component.begin(), component.end(), '/') != component.end()) { return false; }
+
+ // Check if there is enough remaining capacity for "/<component>"
+ auto const add_leading_slash = actual_length_ == 0 || buffer_[actual_length_ - 1] != '/';
+ auto const length = component.length() + (add_leading_slash ? 1 : 0);
+ if (actual_length_ + length > buffer_length_) { return false; }
+
+ // Append "/<component>"
+ if (add_leading_slash) { buffer_[actual_length_++] = '/'; }
+ for (auto i = u32{ 0 }; i < component.length(); ++i) { buffer_[actual_length_++] = component[i]; }
+
+ return true;
+ }
+
+ auto path_builder::pop() -> bool
+ {
+ if (actual_length_ == 0 || buffer_[actual_length_ - 1] == '/') { return false; }
+
+ // Find the start of the last component.
+ auto last_start = actual_length_ - 1;
+ while (last_start > 0 && buffer_[last_start] != '/') { last_start -= 1; }
+
+ // Drop the slash if we are not at the root.
+ if (last_start == 0) { last_start += 1; }
+
+ // Drop everything including the trailing slash.
+ actual_length_ = last_start;
+ return true;
+ }
+} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/path-builder.hh b/lib/nes/common/path-builder.hh
new file mode 100644
index 0000000..727d18c
--- /dev/null
+++ b/lib/nes/common/path-builder.hh
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "nes/common/types.hh"
+#include "nes/common/path-view.hh"
+#include <string_view>
+
+namespace nes
+{
+ /// A mutable path with a fixed-length buffer.
+ class path_builder
+ {
+ char* buffer_{ nullptr };
+ u32 buffer_length_{ 0 };
+ u32 actual_length_{ 0 };
+
+ public:
+ explicit path_builder(char* buffer, u32 buffer_length);
+
+ auto get_components() const -> path_view { return path_view{ get_path() }; }
+ auto get_path() const -> std::string_view { return std::string_view{ buffer_, actual_length_ }; }
+
+ auto push(std::string_view) -> bool;
+ auto pop() -> bool;
+ };
+
+ /// A path builder with a buffer embedded into it.
+ template<u32 Capacity>
+ class path_buffer : public path_builder
+ {
+ char buffer_[Capacity];
+
+ public:
+ explicit path_buffer()
+ : path_builder{ buffer_, Capacity }
+ {
+ }
+ };
+} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/path-view.cc b/lib/nes/common/path-view.cc
new file mode 100644
index 0000000..47f198b
--- /dev/null
+++ b/lib/nes/common/path-view.cc
@@ -0,0 +1,49 @@
+#include "nes/common/path-view.hh"
+
+namespace nes
+{
+ auto path_view::iterator::operator*() const -> std::string_view
+ {
+ return current_ ? std::string_view{ current_, component_length_ } : "";
+ }
+
+ auto path_view::iterator::operator++() -> iterator&
+ {
+ // Move forward to next component
+ current_ += component_length_;
+ remaining_ -= component_length_;
+
+ // Skip over '/'.
+ while (remaining_ > 0 && *current_ == '/')
+ {
+ current_ += 1;
+ remaining_ -= 1;
+ }
+
+ // Scan until end of component to find its length.
+ component_length_ = 0;
+ while (component_length_ < remaining_ && current_[component_length_] != '/')
+ {
+ component_length_ += 1;
+ }
+
+ return *this;
+ }
+
+ auto path_view::iterator::operator++(int) -> iterator
+ {
+ auto const res = *this;
+ ++*this;
+ return res;
+ }
+
+ auto path_view::begin() const -> iterator
+ {
+ return ++iterator{ path_.data(), 0, static_cast<u32>(path_.size()) };
+ }
+
+ auto path_view::end() const -> iterator
+ {
+ return iterator{ path_.data() + path_.size(), 0, 0 };
+ }
+} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/path-view.hh b/lib/nes/common/path-view.hh
index 3d670bf..7741060 100644
--- a/lib/nes/common/path-view.hh
+++ b/lib/nes/common/path-view.hh
@@ -5,13 +5,10 @@
namespace nes
{
- /// Non-owning copy of a path, consisting of multiple path components stored as string views.
- ///
- /// This is similar in spirit to a string_view, but for collections of string_views instead of characters.
+ /// Non-owning copy of a path, useful for iterating over its components.
class path_view
{
- std::string_view const* components_{ nullptr };
- u32 component_count_{ 0 };
+ std::string_view path_;
public:
/// An iterator for the path components.
@@ -19,54 +16,37 @@ namespace nes
{
friend path_view;
- std::string_view const* current_{ nullptr };
- u32 remaining_{ 0 };
+ char const* current_{ nullptr }; // Start of the current component
+ u32 component_length_{ 0 }; // Length of the current component
+ u32 remaining_{ 0 }; // Number of characters remaining in the buffer, including the current component.
public:
auto operator==(iterator const& other) -> bool { return current_ == other.current_; }
auto operator!=(iterator const& other) -> bool { return current_ != other.current_; }
- auto operator*() const -> std::string_view { return current_ ? *current_ : ""; }
-
- auto operator++() -> iterator&
- {
- if (remaining_ > 0)
- {
- current_ += 1;
- remaining_ -= 1;
- }
- return *this;
- }
-
- auto operator++(int) -> iterator
- {
- auto res = *this;
- ++*this;
- return res;
- }
+ auto operator*() const -> std::string_view;
+ auto operator++() -> iterator&;
+ auto operator++(int) -> iterator;
private:
- explicit iterator() = default;
- explicit iterator(std::string_view const* current, u32 const remaining)
+ explicit iterator(char const* current, u32 const component_length, u32 const remaining)
: current_{ current }
+ , component_length_{ component_length }
, remaining_{ remaining }
{
}
};
explicit path_view() = default;
-
- explicit path_view(std::string_view const* components, u32 const component_count)
- : components_{ components }
- , component_count_{ component_count }
+ explicit path_view(std::string_view const path)
+ : path_{ path }
{
}
- auto get_components() const -> std::string_view const* { return components_; }
- auto get_component_count() const -> u32 { return component_count_; }
- auto get_component(u32 const index) const -> std::string_view { return components_[index]; }
+ auto get_path() const -> std::string_view { return path_; }
- auto begin() const -> iterator { return iterator{ components_, component_count_ }; }
- auto end() const -> iterator { return iterator{ components_ + component_count_, 0 }; }
+ auto begin() const -> iterator;
+ auto end() const -> iterator;
+ auto is_empty() const -> bool { return begin() == end(); }
};
} // namespace nes::app \ No newline at end of file
diff --git a/lib/nes/common/string-builder.hh b/lib/nes/common/string-builder.hh
index fda85a4..e0bc673 100644
--- a/lib/nes/common/string-builder.hh
+++ b/lib/nes/common/string-builder.hh
@@ -95,4 +95,17 @@ namespace nes
auto append_format(std::string_view fmt, format_arg const* args, u32 arg_count) -> string_builder&;
auto append_format_arg(format_arg, std::string_view params) -> string_builder&;
};
+
+ /// A string builder with a buffer embedded into it.
+ template<u32 Capacity>
+ class string_buffer : public string_builder
+ {
+ char buffer_[Capacity];
+
+ public:
+ explicit string_buffer()
+ : string_builder{ buffer_, Capacity }
+ {
+ }
+ };
} // namespace nes \ No newline at end of file