summaryrefslogtreecommitdiff
path: root/lib/nes/common
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nes/common')
-rw-r--r--lib/nes/common/CMakeLists.txt3
-rw-r--r--lib/nes/common/path-builder.cc19
-rw-r--r--lib/nes/common/path-builder.hh12
-rw-r--r--lib/nes/common/span.hh82
-rw-r--r--lib/nes/common/string-builder.cc9
-rw-r--r--lib/nes/common/string-builder.hh12
6 files changed, 109 insertions, 28 deletions
diff --git a/lib/nes/common/CMakeLists.txt b/lib/nes/common/CMakeLists.txt
index f0ee288..a7c1d76 100644
--- a/lib/nes/common/CMakeLists.txt
+++ b/lib/nes/common/CMakeLists.txt
@@ -12,4 +12,5 @@ target_sources(
path-view.hh
path-view.cc
path-builder.hh
- path-builder.cc) \ No newline at end of file
+ path-builder.cc
+ span.hh) \ No newline at end of file
diff --git a/lib/nes/common/path-builder.cc b/lib/nes/common/path-builder.cc
index 67190dc..794d565 100644
--- a/lib/nes/common/path-builder.cc
+++ b/lib/nes/common/path-builder.cc
@@ -2,12 +2,11 @@
namespace nes
{
- path_builder::path_builder(char* buffer, u32 const buffer_length)
+ path_builder::path_builder(span<char> const buffer)
: buffer_{ buffer }
- , buffer_length_{ buffer_length }
{
// Initialize the path to "/" if possible.
- if (buffer_length > 0) { buffer_[actual_length_++] = '/'; }
+ if (buffer_.get_length() > 0) { buffer_[length_++] = '/'; }
}
auto path_builder::push(std::string_view component) -> bool
@@ -18,30 +17,30 @@ namespace nes
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 add_leading_slash = length_ == 0 || buffer_[length_ - 1] != '/';
auto const length = component.length() + (add_leading_slash ? 1 : 0);
- if (actual_length_ + length > buffer_length_) { return false; }
+ if (length_ + length > buffer_.get_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]; }
+ if (add_leading_slash) { buffer_[length_++] = '/'; }
+ for (auto i = u32{ 0 }; i < component.length(); ++i) { buffer_[length_++] = component[i]; }
return true;
}
auto path_builder::pop() -> bool
{
- if (actual_length_ == 0 || buffer_[actual_length_ - 1] == '/') { return false; }
+ if (length_ == 0 || buffer_[length_ - 1] == '/') { return false; }
// Find the start of the last component.
- auto last_start = actual_length_ - 1;
+ auto last_start = 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;
+ 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
index 727d18c..b64fb28 100644
--- a/lib/nes/common/path-builder.hh
+++ b/lib/nes/common/path-builder.hh
@@ -1,6 +1,7 @@
#pragma once
#include "nes/common/types.hh"
+#include "nes/common/span.hh"
#include "nes/common/path-view.hh"
#include <string_view>
@@ -9,15 +10,14 @@ namespace nes
/// A mutable path with a fixed-length buffer.
class path_builder
{
- char* buffer_{ nullptr };
- u32 buffer_length_{ 0 };
- u32 actual_length_{ 0 };
+ span<char> buffer_;
+ u32 length_{ 0 };
public:
- explicit path_builder(char* buffer, u32 buffer_length);
+ explicit path_builder(span<char>);
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 get_path() const -> std::string_view { return std::string_view{ buffer_.get_data(), length_ }; }
auto push(std::string_view) -> bool;
auto pop() -> bool;
@@ -31,7 +31,7 @@ namespace nes
public:
explicit path_buffer()
- : path_builder{ buffer_, Capacity }
+ : path_builder{ buffer_ }
{
}
};
diff --git a/lib/nes/common/span.hh b/lib/nes/common/span.hh
new file mode 100644
index 0000000..16eb129
--- /dev/null
+++ b/lib/nes/common/span.hh
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "nes/common/types.hh"
+
+namespace nes
+{
+ namespace detail
+ {
+ struct span_unchecked{};
+
+ inline constexpr auto span_dynamic_length = u32{ 0xFFFF };
+
+ template<typename T>
+ struct remove_const
+ {
+ using type = T;
+ };
+
+ template<typename T>
+ struct remove_const<T const>
+ {
+ using type = T;
+ };
+ } // namespace detail
+
+ /// Implementation of a container similar to std::span in C++20.
+ template<typename T, u32 Length = detail::span_dynamic_length>
+ class span
+ {
+ template<typename U, u32 OtherLength>
+ friend class span;
+
+ T* data_{ nullptr };
+ u32 length_{ 0 };
+
+ public:
+ using iterator = T*;
+
+ explicit span()
+ {
+ static_assert(Length == 0 || Length == detail::span_dynamic_length);
+ }
+
+ explicit span(T* data, u32 const length)
+ : span{ data, length, {} }
+ {
+ static_assert(Length == detail::span_dynamic_length);
+ }
+
+ template<u32 ActualLength>
+ span(T (&data)[ActualLength])
+ : span{ data, ActualLength, {} }
+ {
+ static_assert(Length == ActualLength || Length == detail::span_dynamic_length);
+ }
+
+ span(span<typename detail::remove_const<T>::type, Length> const other)
+ : span{ other.data_, other.length_, {} }
+ {
+ }
+
+ auto get_data() const -> T* { return data_; }
+ auto get_length() const -> u32 { return length_; }
+
+ auto begin() const -> iterator { return data_; }
+ auto end() const -> iterator { return data_ + length_; }
+
+ auto subspan(u32 const first, u32 const length) const -> span<T> { return span{ data_ + first, length }; }
+ auto subspan(u32 const first) const -> span<T> { return subspan(length_ - first); }
+ template<u32 OtherLength>
+ auto subspan(u32 const first) const -> span<T, OtherLength> { return span<T, OtherLength>{ data_ + first, OtherLength, {} }; }
+
+ auto operator[](u32 const index) const -> T& { return data_[index]; }
+
+ private:
+ explicit span(T* data, u32 const length, detail::span_unchecked)
+ : data_{ data }
+ , length_{ length }
+ {
+ }
+ };
+} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/string-builder.cc b/lib/nes/common/string-builder.cc
index efc1326..087f0d4 100644
--- a/lib/nes/common/string-builder.cc
+++ b/lib/nes/common/string-builder.cc
@@ -2,22 +2,21 @@
namespace nes
{
- string_builder::string_builder(char* buffer, u32 buffer_length)
+ string_builder::string_builder(span<char> const buffer)
: buffer_{ buffer }
- , buffer_length_{ buffer_length }
{
}
auto string_builder::append_char(char const value) -> string_builder&
{
- if (actual_length_ == buffer_length_)
+ if (length_ == buffer_.get_length())
{
is_good_ = false;
return *this;
}
- buffer_[actual_length_] = value;
- actual_length_ += 1;
+ buffer_[length_] = value;
+ length_ += 1;
return *this;
}
diff --git a/lib/nes/common/string-builder.hh b/lib/nes/common/string-builder.hh
index e0bc673..256c267 100644
--- a/lib/nes/common/string-builder.hh
+++ b/lib/nes/common/string-builder.hh
@@ -1,6 +1,7 @@
#pragma once
#include "nes/common/types.hh"
+#include "nes/common/span.hh"
#include <string_view>
namespace nes
@@ -16,9 +17,8 @@ namespace nes
/// Builds a string into a fixed-length buffer.
class string_builder
{
- char* buffer_{ nullptr };
- u32 buffer_length_{ 0 };
- u32 actual_length_{ 0 };
+ span<char> buffer_;
+ u32 length_{ 0 };
bool is_good_{ true };
enum class format_arg_type
@@ -60,10 +60,10 @@ namespace nes
};
public:
- explicit string_builder(char* buffer, u32 buffer_length);
+ explicit string_builder(span<char>);
/// Get the resulting string.
- auto get_result() const -> std::string_view { return std::string_view{ buffer_, actual_length_ }; }
+ auto get_result() const -> std::string_view { return std::string_view{ buffer_.get_data(), length_ }; }
/// Returns false after an invalid format string or buffer overflow.
auto is_good() const -> bool { return is_good_; }
@@ -104,7 +104,7 @@ namespace nes
public:
explicit string_buffer()
- : string_builder{ buffer_, Capacity }
+ : string_builder{ buffer_ }
{
}
};