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/containers/CMakeLists.txt4
-rw-r--r--lib/nes/common/containers/box.hh8
-rw-r--r--lib/nes/common/containers/path-builder.cc12
-rw-r--r--lib/nes/common/containers/path-builder.hh11
-rw-r--r--lib/nes/common/containers/path-view.cc8
-rw-r--r--lib/nes/common/containers/path-view.hh10
-rw-r--r--lib/nes/common/containers/string-builder.cc18
-rw-r--r--lib/nes/common/containers/string-builder.hh23
-rw-r--r--lib/nes/common/containers/string-view.cc81
-rw-r--r--lib/nes/common/containers/string-view.hh40
-rw-r--r--lib/nes/common/fps-counter.cc7
-rw-r--r--lib/nes/common/fps-counter.hh3
-rw-r--r--lib/nes/common/utils.hh38
14 files changed, 215 insertions, 51 deletions
diff --git a/lib/nes/common/CMakeLists.txt b/lib/nes/common/CMakeLists.txt
index 9a7cc6b..e227ca8 100644
--- a/lib/nes/common/CMakeLists.txt
+++ b/lib/nes/common/CMakeLists.txt
@@ -7,6 +7,7 @@ target_sources(
display.hh
status.hh
fps-counter.hh
- fps-counter.cc)
+ fps-counter.cc
+ utils.hh)
add_subdirectory(containers) \ No newline at end of file
diff --git a/lib/nes/common/containers/CMakeLists.txt b/lib/nes/common/containers/CMakeLists.txt
index 351772f..69b6dd9 100644
--- a/lib/nes/common/containers/CMakeLists.txt
+++ b/lib/nes/common/containers/CMakeLists.txt
@@ -9,4 +9,6 @@ target_sources(
path-view.cc
span.hh
string-builder.hh
- string-builder.cc) \ No newline at end of file
+ string-builder.cc
+ string-view.hh
+ string-view.cc) \ No newline at end of file
diff --git a/lib/nes/common/containers/box.hh b/lib/nes/common/containers/box.hh
index 7bf2848..82f6448 100644
--- a/lib/nes/common/containers/box.hh
+++ b/lib/nes/common/containers/box.hh
@@ -2,6 +2,8 @@
#include "nes/common/types.hh"
#include "nes/common/debug.hh"
+#include "nes/common/utils.hh"
+#include <new>
namespace nes
{
@@ -56,15 +58,15 @@ namespace nes
operator bool() const { return has_value(); }
auto has_value() const -> bool { return initialized_; }
- auto get() -> T* { return has_value() ? std::launder(reinterpret_cast<T*>(buffer_)) : nullptr; }
- auto get() const -> T const* { return has_value() ? std::launder(reinterpret_cast<T const *>(buffer_)) : nullptr; }
+ auto get() -> T* { return has_value() ? launder(reinterpret_cast<T*>(buffer_)) : nullptr; }
+ auto get() const -> T const* { return has_value() ? launder(reinterpret_cast<T const *>(buffer_)) : nullptr; }
/// Construct a new value in-place, potentially replacing the old value.
template<typename... Args>
auto emplace(Args&&... args) -> void
{
clear();
- new (buffer_) T(std::forward<Args>(args)...);
+ new (buffer_) T(args...);
initialized_ = true;
}
diff --git a/lib/nes/common/containers/path-builder.cc b/lib/nes/common/containers/path-builder.cc
index 2e3ce07..f352b46 100644
--- a/lib/nes/common/containers/path-builder.cc
+++ b/lib/nes/common/containers/path-builder.cc
@@ -9,21 +9,21 @@ namespace nes
if (buffer_.get_length() > 0) { buffer_[length_++] = '/'; }
}
- auto path_builder::push(std::string_view component) -> status
+ auto path_builder::push(string_view component) -> status
{
// 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 status::error_invalid_path; }
+ while (!component.is_empty() && component.get_first() == '/') { component = component.substring(1); }
+ while (!component.is_empty() && component.get_last() == '/') { component = component.substring(0, component.get_length() - 1); }
+ if (component.is_empty() || component.contains('/')) { return status::error_invalid_path; }
// Check if there is enough remaining capacity for "/<component>"
auto const add_leading_slash = length_ == 0 || buffer_[length_ - 1] != '/';
- auto const length = component.length() + (add_leading_slash ? 1 : 0);
+ auto const length = component.get_length() + (add_leading_slash ? 1 : 0);
if (length_ + length > buffer_.get_length()) { return status::error_buffer_overflow; }
// Append "/<component>"
if (add_leading_slash) { buffer_[length_++] = '/'; }
- for (auto i = u32{ 0 }; i < component.length(); ++i) { buffer_[length_++] = component[i]; }
+ for (auto i = u32{ 0 }; i < component.get_length(); ++i) { buffer_[length_++] = component[i]; }
return status::success;
}
diff --git a/lib/nes/common/containers/path-builder.hh b/lib/nes/common/containers/path-builder.hh
index 2991a83..3bddb87 100644
--- a/lib/nes/common/containers/path-builder.hh
+++ b/lib/nes/common/containers/path-builder.hh
@@ -1,10 +1,11 @@
#pragma once
#include "nes/common/containers/span.hh"
+#include "nes/common/containers/string-view.hh"
#include "nes/common/containers/path-view.hh"
#include "nes/common/types.hh"
#include "nes/common/status.hh"
-#include <string_view>
+#include "nes/common/utils.hh"
namespace nes
{
@@ -21,9 +22,9 @@ namespace nes
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_.get_data(), length_ }; }
+ auto get_path() const -> string_view { return string_view{ buffer_.get_data(), length_ }; }
- auto push(std::string_view) -> status;
+ auto push(string_view) -> status;
auto pop() -> status;
};
@@ -42,13 +43,13 @@ namespace nes
path_buffer(path_buffer const& other)
: path_builder{ buffer_ }
{
- std::copy_n(other.buffer_, Capacity, buffer_);
+ copy(other.buffer_, buffer_, Capacity);
length_ = other.length_;
}
auto operator=(path_buffer const& other)
{
- std::copy_n(other.buffer_, Capacity, buffer_);
+ copy(other.buffer_, buffer_, Capacity);
length_ = other.length_;
}
};
diff --git a/lib/nes/common/containers/path-view.cc b/lib/nes/common/containers/path-view.cc
index c81668b..33d82a8 100644
--- a/lib/nes/common/containers/path-view.cc
+++ b/lib/nes/common/containers/path-view.cc
@@ -3,10 +3,10 @@
namespace nes
{
- auto path_view::iterator::operator*() const -> std::string_view
+ auto path_view::iterator::operator*() const -> string_view
{
NES_ASSERT(current_ != nullptr && component_length_ > 0 && "invalid iterator");
- return std::string_view{ current_, component_length_ };
+ return string_view{ current_, component_length_ };
}
auto path_view::iterator::operator++() -> iterator&
@@ -41,11 +41,11 @@ namespace nes
auto path_view::begin() const -> iterator
{
- return ++iterator{ path_.data(), 0, static_cast<u32>(path_.size()) };
+ return ++iterator{ path_.get_data(), 0, path_.get_length() };
}
auto path_view::end() const -> iterator
{
- return iterator{ path_.data() + path_.size(), 0, 0 };
+ return iterator{ path_.get_data() + path_.get_length(), 0, 0 };
}
} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/containers/path-view.hh b/lib/nes/common/containers/path-view.hh
index 7741060..1c25d26 100644
--- a/lib/nes/common/containers/path-view.hh
+++ b/lib/nes/common/containers/path-view.hh
@@ -1,14 +1,14 @@
#pragma once
+#include "nes/common/containers/string-view.hh"
#include "nes/common/types.hh"
-#include <string_view>
namespace nes
{
/// Non-owning copy of a path, useful for iterating over its components.
class path_view
{
- std::string_view path_;
+ string_view path_;
public:
/// An iterator for the path components.
@@ -24,7 +24,7 @@ namespace nes
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;
+ auto operator*() const -> string_view;
auto operator++() -> iterator&;
auto operator++(int) -> iterator;
@@ -38,12 +38,12 @@ namespace nes
};
explicit path_view() = default;
- explicit path_view(std::string_view const path)
+ explicit path_view(string_view const path)
: path_{ path }
{
}
- auto get_path() const -> std::string_view { return path_; }
+ auto get_path() const -> string_view { return path_; }
auto begin() const -> iterator;
auto end() const -> iterator;
diff --git a/lib/nes/common/containers/string-builder.cc b/lib/nes/common/containers/string-builder.cc
index 74d9548..ad2f97f 100644
--- a/lib/nes/common/containers/string-builder.cc
+++ b/lib/nes/common/containers/string-builder.cc
@@ -16,7 +16,7 @@ namespace nes
return status::success;
}
- auto string_builder::append_string(std::string_view const value) -> status
+ auto string_builder::append_string(string_view const value) -> status
{
auto copy = *this;
for (auto const c : value)
@@ -103,13 +103,13 @@ namespace nes
return append_string(value ? "true" : "false");
}
- auto string_builder::append_format(std::string_view const fmt, format_arg const* args, u32 const arg_count) -> status
+ auto string_builder::append_format(string_view const fmt, format_arg const* args, u32 const arg_count) -> status
{
auto copy = *this;
// Go through the format string, inserting the arguments for the templates as necessary.
auto current_arg = u32{ 0 };
- for (auto i = u32{ 0 }; i < fmt.length(); ++i)
+ for (auto i = u32{ 0 }; i < fmt.get_length(); ++i)
{
if (fmt[i] == '{')
{
@@ -122,10 +122,10 @@ namespace nes
else
{
// start of template
- auto const params = &fmt[i]; // remember start position
+ auto const params_start = i; // remember start position
auto params_length = u32{ 0 };
// skip to the end of the template
- while (fmt[i] && fmt[i] != '}')
+ while (i < fmt.get_length() && fmt[i] != '}')
{
params_length++;
i++;
@@ -137,7 +137,7 @@ namespace nes
}
// end of template
- auto const p = std::string_view{ params, params_length };
+ auto const p = fmt.substring(params_start, params_length);
if (current_arg < arg_count)
{
if (auto const s = copy.append_format_arg(args[current_arg], p); s != status::success) { return s; }
@@ -182,11 +182,11 @@ namespace nes
return status::success;
}
- auto string_builder::append_format_arg(format_arg const arg, std::string_view const params) -> status
+ auto string_builder::append_format_arg(format_arg const arg, string_view const params) -> status
{
auto const parse_params = [&]
{
- if (!params.empty())
+ if (!params.is_empty())
{
return status::error_invalid_format_string;
}
@@ -196,7 +196,7 @@ namespace nes
auto const parse_params_integer = [&](number_format& out_format)
{
- if (params.empty() || params == "d")
+ if (params.is_empty() || params == "d")
{
out_format = number_format::decimal;
}
diff --git a/lib/nes/common/containers/string-builder.hh b/lib/nes/common/containers/string-builder.hh
index 0f8a64c..7dcbb34 100644
--- a/lib/nes/common/containers/string-builder.hh
+++ b/lib/nes/common/containers/string-builder.hh
@@ -1,9 +1,10 @@
#pragma once
-#include "nes/common/types.hh"
#include "nes/common/containers/span.hh"
+#include "nes/common/containers/string-view.hh"
+#include "nes/common/types.hh"
#include "nes/common/status.hh"
-#include <string_view>
+#include "nes/common/utils.hh"
namespace nes
{
@@ -38,7 +39,7 @@ namespace nes
format_arg_type type;
union
{
- std::string_view string;
+ string_view string;
char character;
i64 signed_integer;
u64 unsigned_integer;
@@ -48,7 +49,7 @@ namespace nes
format_arg() = delete;
explicit format_arg(char const* v) : type{ format_arg_type::string } { string = v; }
- explicit format_arg(std::string_view const v) : type{ format_arg_type::string } { string = v; }
+ explicit format_arg(string_view const v) : type{ format_arg_type::string } { string = v; }
explicit format_arg(char const v) : type{ format_arg_type::character } { character = v; }
explicit format_arg(unsigned char const v) : format_arg{ static_cast<char>(v) } {}
explicit format_arg(long long const v) : type{ format_arg_type::signed_integer } { signed_integer = v; }
@@ -66,10 +67,10 @@ namespace nes
explicit string_builder(span<char>);
/// Get the resulting string.
- auto get_result() const -> std::string_view { return std::string_view{ buffer_.get_data(), length_ }; }
+ auto get_result() const -> string_view { return string_view{ buffer_.get_data(), length_ }; }
auto append_char(char) -> status;
- auto append_string(std::string_view) -> status;
+ auto append_string(string_view) -> status;
auto append_int(i64, number_format = number_format::decimal) -> status;
auto append_int(u64, number_format = number_format::decimal) -> status;
auto append_bool(bool) -> status;
@@ -82,7 +83,7 @@ namespace nes
///
/// Curly braces can be escaped by repeating them twice like {{this}}.
template<typename... Args>
- auto append_format(std::string_view const fmt, Args... args) -> status
+ auto append_format(string_view const fmt, Args... args) -> status
{
constexpr u32 arg_count = sizeof...(Args);
// Add another argument at the end so we don't have an empty array expression.
@@ -92,8 +93,8 @@ namespace nes
}
private:
- auto append_format(std::string_view fmt, format_arg const* args, u32 arg_count) -> status;
- auto append_format_arg(format_arg, std::string_view params) -> status;
+ auto append_format(string_view fmt, format_arg const* args, u32 arg_count) -> status;
+ auto append_format_arg(format_arg, string_view params) -> status;
};
/// A string builder with a buffer embedded into it.
@@ -111,13 +112,13 @@ namespace nes
string_buffer(string_buffer const& other)
: string_builder{ buffer_ }
{
- std::copy_n(other.buffer_, Capacity, buffer_);
+ copy(other.buffer_, buffer_, Capacity);
length_ = other.length_;
}
auto operator=(string_buffer const& other)
{
- std::copy_n(other.buffer_, Capacity, buffer_);
+ copy(other.buffer_, buffer_, Capacity);
length_ = other.length_;
}
};
diff --git a/lib/nes/common/containers/string-view.cc b/lib/nes/common/containers/string-view.cc
new file mode 100644
index 0000000..8265d09
--- /dev/null
+++ b/lib/nes/common/containers/string-view.cc
@@ -0,0 +1,81 @@
+#include "nes/common/containers/string-view.hh"
+#include "nes/common/debug.hh"
+
+namespace nes
+{
+ namespace
+ {
+ auto compute_length(char const* c_string) -> u32
+ {
+ auto res = u32{ 0 };
+ while (*c_string)
+ {
+ res += 1;
+ c_string++;
+ }
+ return res;
+ }
+ } // namespace
+
+ string_view::string_view(span<char const> const data)
+ : data_{ data }
+ {
+ }
+
+ string_view::string_view(char const* data, u32 length)
+ : data_{ data, length }
+ {
+ }
+
+ string_view::string_view(char const* c_string)
+ : string_view{ c_string, compute_length(c_string) }
+ {
+ }
+
+ auto string_view::get_first() const -> char
+ {
+ NES_ASSERT(!is_empty() && "unable to get character of empty string");
+ return data_[0];
+ }
+
+ auto string_view::get_last() const -> char
+ {
+ NES_ASSERT(!is_empty() && "unable to get character of empty string");
+ return data_[data_.get_length() - 1];
+ }
+
+ auto string_view::contains(char const needle) const -> bool
+ {
+ for (const auto c : *this)
+ {
+ if (c == needle) { return true; }
+ }
+ return false;
+ }
+
+ auto string_view::substring(u32 const first) const -> string_view
+ {
+ return string_view{ data_.subspan(first) };
+ }
+
+ auto string_view::substring(u32 const first, u32 const length) const -> string_view
+ {
+ return string_view{ data_.subspan(first, length) };
+ }
+
+ auto operator==(string_view const lhs, string_view const rhs) -> bool
+ {
+ if (lhs.get_length() != rhs.get_length()) { return false; }
+
+ for (auto i = u32{ 0 }; i < lhs.get_length(); ++i)
+ {
+ if (lhs[i] != rhs[i]) { return false; }
+ }
+
+ return true;
+ }
+ auto operator!=(string_view const lhs, string_view const rhs) -> bool
+ {
+ return !(lhs == rhs);
+ }
+} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/containers/string-view.hh b/lib/nes/common/containers/string-view.hh
new file mode 100644
index 0000000..180a688
--- /dev/null
+++ b/lib/nes/common/containers/string-view.hh
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "nes/common/containers/span.hh"
+#include "nes/common/types.hh"
+
+namespace nes
+{
+ /// Non-owning view into a (not necessarily null-terminated) string.
+ class string_view
+ {
+ span<char const> data_;
+
+ public:
+ explicit string_view() = default;
+ explicit string_view(span<char const>);
+ explicit string_view(char const* data, u32 length);
+ string_view(char const* c_string);
+
+ using iterator = span<char const>::iterator;
+
+ auto operator[](u32 const index) const -> char { return data_[index]; }
+ auto get_span() const -> span<char const> { return data_; }
+ auto get_data() const -> char const* { return data_.get_data(); }
+ auto get_length() const -> u32 { return data_.get_length(); }
+ auto is_empty() const -> bool { return get_length() == 0; }
+ auto begin() const -> iterator { return data_.begin(); }
+ auto end() const -> iterator { return data_.end(); }
+
+ // String helpers
+
+ auto get_first() const -> char;
+ auto get_last() const -> char;
+ auto contains(char) const -> bool;
+ auto substring(u32 first) const -> string_view;
+ auto substring(u32 first, u32 length) const -> string_view;
+ };
+
+ auto operator==(string_view, string_view) -> bool;
+ auto operator!=(string_view, string_view) -> bool;
+} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/fps-counter.cc b/lib/nes/common/fps-counter.cc
index ef6169b..8f19c7e 100644
--- a/lib/nes/common/fps-counter.cc
+++ b/lib/nes/common/fps-counter.cc
@@ -2,9 +2,9 @@
namespace nes
{
- auto fps_counter::frame(std::chrono::microseconds const elapsed_time) -> void
+ auto fps_counter::frame(u32 const elapsed_time_us) -> void
{
- if (elapsed_time.count() <= 0) { return; }
+ if (elapsed_time_us == 0) { return; }
if (buffer_position_ == 0)
{
@@ -22,8 +22,7 @@ namespace nes
}
// Add the frame time to the buffer, replacing any existing content in the ring buffer.
- auto const frame_time = static_cast<u32>(elapsed_time.count());
- frame_times_[buffer_position_] = frame_time;
+ frame_times_[buffer_position_] = elapsed_time_us;
buffer_position_ = (buffer_position_ + 1) % buffer_size;
}
} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/fps-counter.hh b/lib/nes/common/fps-counter.hh
index 96db98c..f921880 100644
--- a/lib/nes/common/fps-counter.hh
+++ b/lib/nes/common/fps-counter.hh
@@ -1,7 +1,6 @@
#pragma once
#include "nes/common/types.hh"
-#include <chrono>
namespace nes
{
@@ -17,7 +16,7 @@ namespace nes
public:
explicit fps_counter() = default;
- auto frame(std::chrono::microseconds elapsed_time) -> void;
+ auto frame(u32 elapsed_time_us) -> void;
auto get_fps() const -> u32 { return buffered_fps_; }
};
} // namespace nes \ No newline at end of file
diff --git a/lib/nes/common/utils.hh b/lib/nes/common/utils.hh
new file mode 100644
index 0000000..460d0d5
--- /dev/null
+++ b/lib/nes/common/utils.hh
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "nes/common/types.hh"
+
+namespace nes
+{
+ template<typename T>
+ auto launder(T* p) -> T*
+ {
+ return __builtin_launder(p);
+ }
+
+ template<typename T>
+ auto copy(T const* src, T* dst, u32 const length)
+ {
+ for (auto i = u32{ 0 }; i < length; ++i) { dst[i] = src[i]; }
+ }
+
+ template<typename T>
+ auto min(T const a, T const b)
+ {
+ return a < b ? a : b;
+ }
+
+ template<typename T>
+ auto max(T const a, T const b)
+ {
+ return a > b ? a : b;
+ }
+
+ template<typename T>
+ auto swap(T& a, T& b) -> void
+ {
+ auto const tmp = a;
+ a = b;
+ b = tmp;
+ }
+} // namespace nes \ No newline at end of file