From 64ebfde8bcd6408e3b6925624e8680c314db6efc Mon Sep 17 00:00:00 2001 From: Hannes Schulze Date: Thu, 6 Feb 2025 19:54:38 +0100 Subject: get rid of nasty stdlib --- lib/nes/app/action.hh | 16 +++--- lib/nes/app/application.cc | 8 +-- lib/nes/app/application.hh | 5 +- lib/nes/app/file-browser.hh | 13 ++--- lib/nes/app/graphics/renderer.cc | 37 ++++++------- lib/nes/app/graphics/renderer.hh | 8 +-- lib/nes/app/input/input-device-keyboard.hh | 2 +- lib/nes/app/input/input-device.hh | 4 +- lib/nes/app/input/input-manager.cc | 2 +- lib/nes/app/ui/screen-browser.cc | 3 +- lib/nes/app/ui/screen-error.hh | 7 +-- lib/nes/app/ui/screen-settings.cc | 2 +- lib/nes/common/CMakeLists.txt | 3 +- lib/nes/common/containers/CMakeLists.txt | 4 +- lib/nes/common/containers/box.hh | 8 +-- lib/nes/common/containers/path-builder.cc | 12 ++--- lib/nes/common/containers/path-builder.hh | 11 ++-- lib/nes/common/containers/path-view.cc | 8 +-- lib/nes/common/containers/path-view.hh | 10 ++-- lib/nes/common/containers/string-builder.cc | 18 +++---- lib/nes/common/containers/string-builder.hh | 23 ++++---- lib/nes/common/containers/string-view.cc | 81 +++++++++++++++++++++++++++++ lib/nes/common/containers/string-view.hh | 40 ++++++++++++++ lib/nes/common/fps-counter.cc | 7 ++- lib/nes/common/fps-counter.hh | 3 +- lib/nes/common/utils.hh | 38 ++++++++++++++ lib/nes/sys/cartridge.cc | 8 +-- lib/nes/sys/cpu.cc | 4 +- lib/nes/sys/cpu.hh | 4 +- lib/nes/sys/nes.cc | 8 +-- lib/nes/sys/nes.hh | 6 +-- lib/nes/sys/ppu.cc | 7 ++- lib/nes/sys/ppu.hh | 4 +- lib/nes/sys/types/cycle-count.hh | 9 ++-- lib/nes/sys/types/snapshot.hh | 6 ++- 35 files changed, 302 insertions(+), 127 deletions(-) create mode 100644 lib/nes/common/containers/string-view.cc create mode 100644 lib/nes/common/containers/string-view.hh create mode 100644 lib/nes/common/utils.hh (limited to 'lib/nes') diff --git a/lib/nes/app/action.hh b/lib/nes/app/action.hh index cca7a35..ed879f3 100644 --- a/lib/nes/app/action.hh +++ b/lib/nes/app/action.hh @@ -1,7 +1,7 @@ #pragma once -#include "../common/status.hh" -#include +#include "nes/common/containers/string-view.hh" +#include "nes/common/status.hh" namespace nes::app { @@ -25,8 +25,8 @@ namespace nes::app private: type type_{ type::none }; - std::string_view file_name_; - std::string_view message_; + string_view file_name_; + string_view message_; status error_{ status::success }; public: @@ -40,14 +40,14 @@ namespace nes::app static auto cancel_quit() -> action { return action{ type::cancel_quit }; } static auto confirm_quit() -> action { return action{ type::confirm_quit }; } - static auto launch_game(std::string_view const file_name) -> action + static auto launch_game(string_view const file_name) -> action { auto res = action{ type::launch_game }; res.file_name_ = file_name; return res; } - static auto show_error(std::string_view const message, status const error) -> action + static auto show_error(string_view const message, status const error) -> action { auto res = action{ type::show_error }; res.message_ = message; @@ -56,8 +56,8 @@ namespace nes::app } auto get_type() const -> type { return type_; } - auto get_file_name() const -> std::string_view { return file_name_; } - auto get_message() const -> std::string_view { return message_; } + auto get_file_name() const -> string_view { return file_name_; } + auto get_message() const -> string_view { return message_; } auto get_error() const -> status { return error_; } private: diff --git a/lib/nes/app/application.cc b/lib/nes/app/application.cc index 015e641..ac9f731 100644 --- a/lib/nes/app/application.cc +++ b/lib/nes/app/application.cc @@ -46,9 +46,9 @@ namespace nes::app display_.screen = &screen_title_; } - auto application::frame(std::chrono::microseconds const elapsed_time) -> void + auto application::frame(u32 const elapsed_time_us) -> void { - display_.fps_counter.frame(elapsed_time); + display_.fps_counter.frame(elapsed_time_us); if (display_.popup) { @@ -89,7 +89,7 @@ namespace nes::app // The scene is rendered by the console after the PPU requests a new frame (thus calling // display_proxy::switch_buffers). - console_->step(elapsed_time); + console_->step(sys::cycle_count::from_microseconds(elapsed_time_us)); if (console_->get_status() != status::success) { @@ -171,7 +171,7 @@ namespace nes::app } } - auto application::show_error(std::string_view const message, status const error, action const& action) -> void + auto application::show_error(string_view const message, status const error, action const& action) -> void { screen_error_.set_message(message); screen_error_.set_error(error); diff --git a/lib/nes/app/application.hh b/lib/nes/app/application.hh index c23f654..f0117b1 100644 --- a/lib/nes/app/application.hh +++ b/lib/nes/app/application.hh @@ -13,7 +13,6 @@ #include "nes/common/display.hh" #include "nes/common/fps-counter.hh" #include "nes/common/types.hh" -#include namespace nes::app { @@ -71,14 +70,14 @@ namespace nes::app auto operator=(application&&) -> application& = delete; /// Request a new frame for the application. - auto frame(std::chrono::microseconds elapsed_time) -> void; + auto frame(u32 elapsed_time_us) -> void; auto add_controller(input_device_controller& c) -> void { input_manager_.add_controller(c); } auto remove_controller(input_device_controller& c) -> void { input_manager_.remove_controller(c); } private: auto handle_action(action const&) -> void; - auto show_error(std::string_view message, status error, action const& action = action::close_popup()) -> void; + auto show_error(string_view message, status error, action const& action = action::close_popup()) -> void; auto go_to_screen(screen*) -> void; }; } // namespace nes::app \ No newline at end of file diff --git a/lib/nes/app/file-browser.hh b/lib/nes/app/file-browser.hh index 3465000..1da4cd6 100644 --- a/lib/nes/app/file-browser.hh +++ b/lib/nes/app/file-browser.hh @@ -1,9 +1,10 @@ #pragma once #include "nes/common/containers/span.hh" +#include "nes/common/containers/string-view.hh" #include "nes/common/types.hh" #include "nes/common/status.hh" -#include +#include "nes/common/utils.hh" namespace nes { @@ -33,14 +34,14 @@ namespace nes::app public: explicit entry() = default; - explicit entry(entry_type const type, std::string_view const name) + explicit entry(entry_type const type, string_view const name) : type_{ type } { - std::copy_n(name.begin(), std::min(static_cast(name.length()), max_name_length), name_); + copy(name.get_data(), name_, min(name.get_length(), max_name_length)); } auto get_type() const -> entry_type { return type_; } - auto get_name() const -> std::string_view { return name_; } + auto get_name() const -> string_view { return name_; } }; virtual ~file_browser() = default; @@ -63,10 +64,10 @@ namespace nes::app virtual auto navigate_up() -> status = 0; /// Change the current working directory to an item. - virtual auto navigate(std::string_view) -> status = 0; + virtual auto navigate(string_view) -> status = 0; /// Load a file in the current working directory into memory. - virtual auto load(std::string_view, span, u32* out_length) -> status = 0; + virtual auto load(string_view, span, u32* out_length) -> status = 0; protected: explicit file_browser() = default; diff --git a/lib/nes/app/graphics/renderer.cc b/lib/nes/app/graphics/renderer.cc index 4f0d562..1745dd7 100644 --- a/lib/nes/app/graphics/renderer.cc +++ b/lib/nes/app/graphics/renderer.cc @@ -7,6 +7,7 @@ #include "nes/app/graphics/tiles/characters.hh" #include "nes/app/graphics/tiles/borders.hh" #include "nes/common/display.hh" +#include "nes/common/utils.hh" namespace nes::app { @@ -64,32 +65,32 @@ namespace nes::app } auto renderer::render_text( - i32 x, i32 const y, std::string_view const str, color const c, text_attributes const attributes) -> u32 + i32 x, i32 const y, string_view const str, color const c, text_attributes const attributes) -> u32 { // Enforce max length char buffer[width]; - auto const length = std::min(static_cast(str.length()), std::min(width, attributes.get_max_width())); - auto const ellipsize_dots = std::min(length, u32{ 3 }); + auto const length = min(str.get_length(), min(width, attributes.get_max_width())); + auto const ellipsize_dots = min(length, u32{ 3 }); // Enforce ellipsize mode - if (str.length() > length) + if (str.get_length() > length) { switch (attributes.get_ellipsize_mode()) { case ellipsize_mode::clip: { - std::copy_n(str.begin(), length, buffer); + copy(str.get_data(), buffer, length); break; } case ellipsize_mode::end: { - std::copy_n(str.begin(), length, buffer); + copy(str.get_data(), buffer, length); for (auto i = u32{ 0 }; i < ellipsize_dots; ++i) { buffer[length - 1 - i] = '.'; } break; } case ellipsize_mode::start: { - std::copy_n(str.begin() + str.length() - length, length, buffer); + copy(str.get_data() + str.get_length() - length, buffer, length); for (auto i = u32{ 0 }; i < ellipsize_dots; ++i) { buffer[i] = '.'; } break; } @@ -98,16 +99,16 @@ namespace nes::app auto const visible = length - ellipsize_dots; auto const start = visible / 2; auto const end = visible - start; - std::copy_n(str.begin(), start, buffer); + copy(str.get_data(), buffer, start); for (auto i = u32{ 0 }; i < ellipsize_dots; ++i) { buffer[start + i] = '.'; } - std::copy_n(str.begin() + str.length() - end, end, buffer + start + ellipsize_dots); + copy(str.get_data() + str.get_length() - end, buffer + start + ellipsize_dots, end); break; } } } else { - std::copy_n(str.begin(), length, buffer); + copy(str.get_data(), buffer, length); } // Enforce alignment @@ -132,10 +133,10 @@ namespace nes::app if (c == color::transparent) { return; } auto const resolved = resolve_color(c); - auto const x_stop = std::min(x + static_cast(width), static_cast(renderer::width)); - auto const y_stop = std::min(y + static_cast(height), static_cast(renderer::height)); - auto const x_start = std::max(x, 0); - auto const y_start = std::max(y, 0); + auto const x_stop = min(x + static_cast(width), static_cast(renderer::width)); + auto const y_stop = min(y + static_cast(height), static_cast(renderer::height)); + auto const x_start = max(x, 0); + auto const y_start = max(y, 0); for (auto y_px = i32{ y_start * 8 }; y_px < y_stop * 8; ++y_px) { for (auto x_px = i32{ x_start * 8 }; x_px < x_stop * 8; ++x_px) @@ -149,10 +150,10 @@ namespace nes::app { if (width <= 1 || height <= 1) { return; } - auto const x_last = std::min(x + static_cast(width), static_cast(renderer::width)) - 1; - auto const y_last = std::min(y + static_cast(height), static_cast(renderer::height)) - 1; - auto const x_start = std::max(x, 0); - auto const y_start = std::max(y, 0); + auto const x_last = min(x + static_cast(width), static_cast(renderer::width)) - 1; + auto const y_last = min(y + static_cast(height), static_cast(renderer::height)) - 1; + auto const x_start = max(x, 0); + auto const y_start = max(y, 0); for (auto border_y = i32{ y_start }; border_y <= y_last; ++border_y) { for (auto border_x = i32{ x_start }; border_x <= x_last; ++border_x) diff --git a/lib/nes/app/graphics/renderer.hh b/lib/nes/app/graphics/renderer.hh index 2e24ad3..50ca092 100644 --- a/lib/nes/app/graphics/renderer.hh +++ b/lib/nes/app/graphics/renderer.hh @@ -3,8 +3,8 @@ #include "nes/app/graphics/color.hh" #include "nes/app/graphics/text-attributes.hh" #include "nes/common/containers/string-builder.hh" +#include "nes/common/containers/string-view.hh" #include "nes/common/types.hh" -#include namespace nes { @@ -46,11 +46,11 @@ namespace nes::app /// Render an image at the given tile coordinates. auto render_image(i32 x, i32 y, image_view) -> void; /// Render a string of text at the given tile coordinates (one tile per character). - auto render_text(i32 x, i32 y, std::string_view, color, text_attributes = text_attributes{}) -> u32; + auto render_text(i32 x, i32 y, string_view, color, text_attributes = text_attributes{}) -> u32; template auto render_text_format( - i32 const x, i32 const y, color const c, text_attributes const attrs, std::string_view const fmt, + i32 const x, i32 const y, color const c, text_attributes const attrs, string_view const fmt, Args... args) -> u32 { string_buffer buffer{}; @@ -60,7 +60,7 @@ namespace nes::app template auto render_text_format( - i32 const x, i32 const y, color const c, std::string_view const fmt, Args... args) -> u32 + i32 const x, i32 const y, color const c, string_view const fmt, Args... args) -> u32 { return render_text_format(x, y, c, text_attributes{}, fmt, args...); } diff --git a/lib/nes/app/input/input-device-keyboard.hh b/lib/nes/app/input/input-device-keyboard.hh index ef89c59..1365a1b 100644 --- a/lib/nes/app/input/input-device-keyboard.hh +++ b/lib/nes/app/input/input-device-keyboard.hh @@ -43,7 +43,7 @@ namespace nes::app return res; } - auto get_name() const -> std::string_view final { return "Keyboard"; } + auto get_name() const -> string_view final { return "Keyboard"; } protected: explicit input_device_keyboard() = default; diff --git a/lib/nes/app/input/input-device.hh b/lib/nes/app/input/input-device.hh index 008825d..bd2f7c2 100644 --- a/lib/nes/app/input/input-device.hh +++ b/lib/nes/app/input/input-device.hh @@ -1,7 +1,7 @@ #pragma once #include "nes/sys/types/button-mask.hh" -#include +#include "nes/common/containers/string-view.hh" namespace nes::app { @@ -20,7 +20,7 @@ namespace nes::app virtual auto read_buttons() -> sys::button_mask = 0; /// Human-readable name for the device. - virtual auto get_name() const -> std::string_view = 0; + virtual auto get_name() const -> string_view = 0; protected: explicit input_device() = default; diff --git a/lib/nes/app/input/input-manager.cc b/lib/nes/app/input/input-manager.cc index e88ac84..27b29e4 100644 --- a/lib/nes/app/input/input-manager.cc +++ b/lib/nes/app/input/input-manager.cc @@ -15,7 +15,7 @@ namespace nes::app return res; } - auto get_name() const -> std::string_view override { return "(None)"; } + auto get_name() const -> string_view override { return "(None)"; } auto read_buttons() -> sys::button_mask override { return sys::button_mask{}; } }; } // namespace diff --git a/lib/nes/app/ui/screen-browser.cc b/lib/nes/app/ui/screen-browser.cc index 1b515bd..50b0060 100644 --- a/lib/nes/app/ui/screen-browser.cc +++ b/lib/nes/app/ui/screen-browser.cc @@ -4,6 +4,7 @@ #include "nes/app/graphics/tiles/icons.hh" #include "nes/app/input/input-device-keyboard.hh" #include "nes/common/containers/path-view.hh" +#include "nes/common/utils.hh" namespace nes::app { @@ -152,6 +153,6 @@ namespace nes::app // Round up to get page count. auto const page_count = (count + (page_size - 1)) / page_size; // Always show at least one page. - selection_.set_page_count(std::max(u32{ 1 }, page_count)); + selection_.set_page_count(max(u32{ 1 }, page_count)); } } // namespace nes::app \ No newline at end of file diff --git a/lib/nes/app/ui/screen-error.hh b/lib/nes/app/ui/screen-error.hh index 4559942..53b6407 100644 --- a/lib/nes/app/ui/screen-error.hh +++ b/lib/nes/app/ui/screen-error.hh @@ -1,6 +1,7 @@ #pragma once #include "nes/app/ui/screen.hh" +#include "nes/common/containers/string-view.hh" namespace nes::app { @@ -10,17 +11,17 @@ namespace nes::app class screen_error final : public screen { input_device_keyboard& keyboard_; - std::string_view message_; + string_view message_; status error_{ status::success }; action action_{}; public: explicit screen_error(input_device_keyboard&); - auto get_message() const -> std::string_view { return message_; } + auto get_message() const -> string_view { return message_; } auto get_error() const -> status { return error_; } auto get_action() const -> action { return action_; } - auto set_message(std::string_view const v) -> void { message_ = v; } + auto set_message(string_view const v) -> void { message_ = v; } auto set_error(status const v) -> void { error_ = v; } auto set_action(action const& v) -> void { action_ = v; } diff --git a/lib/nes/app/ui/screen-settings.cc b/lib/nes/app/ui/screen-settings.cc index 98070d7..9ba4b50 100644 --- a/lib/nes/app/ui/screen-settings.cc +++ b/lib/nes/app/ui/screen-settings.cc @@ -7,7 +7,7 @@ namespace nes::app auto screen_settings::selection_impl::render_item( renderer& renderer, item const& item, i32 const x, i32 const y, u32 const width, color const c) const -> void { - auto const render = [&](std::string_view const label, std::string_view const value) + auto const render = [&](string_view const label, string_view const value) { auto const label_length = renderer.render_text(x, y, label, c); auto const value_attrs = text_attributes{} 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 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(buffer_)) : nullptr; } - auto get() const -> T const* { return has_value() ? std::launder(reinterpret_cast(buffer_)) : nullptr; } + auto get() -> T* { return has_value() ? launder(reinterpret_cast(buffer_)) : nullptr; } + auto get() const -> T const* { return has_value() ? launder(reinterpret_cast(buffer_)) : nullptr; } /// Construct a new value in-place, potentially replacing the old value. template auto emplace(Args&&... args) -> void { clear(); - new (buffer_) T(std::forward(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 "/" 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 "/" 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 +#include "nes/common/utils.hh" namespace nes { @@ -21,9 +22,9 @@ namespace nes explicit path_builder(span); 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(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 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 +#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(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); /// 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 - 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 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 data_; + + public: + explicit string_view() = default; + explicit string_view(span); + explicit string_view(char const* data, u32 length); + string_view(char const* c_string); + + using iterator = span::iterator; + + auto operator[](u32 const index) const -> char { return data_[index]; } + auto get_span() const -> span { 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(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 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 + auto launder(T* p) -> T* + { + return __builtin_launder(p); + } + + template + auto copy(T const* src, T* dst, u32 const length) + { + for (auto i = u32{ 0 }; i < length; ++i) { dst[i] = src[i]; } + } + + template + auto min(T const a, T const b) + { + return a < b ? a : b; + } + + template + auto max(T const a, T const b) + { + return a > b ? a : b; + } + + template + auto swap(T& a, T& b) -> void + { + auto const tmp = a; + a = b; + b = tmp; + } +} // namespace nes \ No newline at end of file diff --git a/lib/nes/sys/cartridge.cc b/lib/nes/sys/cartridge.cc index 0729107..b6670a3 100644 --- a/lib/nes/sys/cartridge.cc +++ b/lib/nes/sys/cartridge.cc @@ -1,6 +1,6 @@ #include "nes/sys/cartridge.hh" #include "nes/common/status.hh" -#include +#include "nes/common/utils.hh" namespace nes::sys { @@ -27,16 +27,16 @@ namespace nes::sys prg_rom_size_ = h.get_prg_rom_banks() * prg_rom_bank_size; if (data.get_length() < offset + prg_rom_size_) { return; } if (prg_rom_size_ > max_prg_rom_size) { return; } - std::copy_n(&data[offset], prg_rom_size_, prg_rom_); + copy(&data[offset], prg_rom_, prg_rom_size_); offset += prg_rom_size_; chr_rom_size_ = h.get_chr_rom_banks() * chr_rom_bank_size; if (data.get_length() < offset + chr_rom_size_) { return; } if (chr_rom_size_ > max_chr_rom_size) { return; } - std::copy_n(&data[offset], chr_rom_size_, chr_rom_); + copy(&data[offset], chr_rom_, chr_rom_size_); - ram_size_ = std::max(h.get_ram_banks(), 1u) * ram_bank_size; + ram_size_ = max(h.get_ram_banks(), u32{ 1 }) * ram_bank_size; if (ram_size_ > max_ram_size) { return; } status_ = get_mapper().validate(*this); diff --git a/lib/nes/sys/cpu.cc b/lib/nes/sys/cpu.cc index 09e2094..55bbb21 100644 --- a/lib/nes/sys/cpu.cc +++ b/lib/nes/sys/cpu.cc @@ -15,6 +15,7 @@ namespace nes::sys registers_.pc = read16(address{ 0xFFFC }); } +#ifdef NES_ENABLE_SNAPSHOTS auto cpu::build_snapshot(snapshot& snapshot) -> void { snapshot.cpu_cycle = current_cycles_; @@ -33,6 +34,7 @@ namespace nes::sys snapshot.registers.v = registers_.p.get_v(); snapshot.registers.n = registers_.p.get_n(); } +#endif auto cpu::stall_cycles(cycle_count const count) -> void { @@ -1236,7 +1238,7 @@ namespace nes::sys } case addressing_mode::relative: { - auto const offset = static_cast(advance_pc8()); + auto const offset = static_cast(advance_pc8()); auto const base = address{ registers_.pc }; addr = address{ static_cast(registers_.pc + offset) }; auto const page_crossing = diff --git a/lib/nes/sys/cpu.hh b/lib/nes/sys/cpu.hh index 99753a7..795039c 100644 --- a/lib/nes/sys/cpu.hh +++ b/lib/nes/sys/cpu.hh @@ -2,6 +2,7 @@ #include "nes/sys/types/cycle-count.hh" #include "nes/sys/types/address.hh" +#include "nes/sys/types/snapshot.hh" #include "nes/common/status.hh" #include "nes/common/types.hh" @@ -10,7 +11,6 @@ namespace nes::sys class ppu; class controller; class cartridge; - struct snapshot; class cpu { @@ -138,7 +138,9 @@ namespace nes::sys auto operator=(cpu&&) -> cpu& = delete; auto get_cycles() const -> cycle_count { return current_cycles_; } +#ifdef NES_ENABLE_SNAPSHOTS auto build_snapshot(snapshot&) -> void; +#endif auto stall_cycles(cycle_count) -> void; auto trigger_nmi() -> void; auto step() -> status; diff --git a/lib/nes/sys/nes.cc b/lib/nes/sys/nes.cc index 5cc47a4..ca12190 100644 --- a/lib/nes/sys/nes.cc +++ b/lib/nes/sys/nes.cc @@ -1,5 +1,4 @@ #include "nes/sys/nes.hh" -#include "nes/sys/types/snapshot.hh" namespace nes::sys { @@ -12,11 +11,6 @@ namespace nes::sys { } - auto nes::step(std::chrono::microseconds const delta) -> void - { - step(cycle_count::from_duration(delta)); - } - auto nes::step() -> void { if (get_status() != status::success) { return; } @@ -49,6 +43,7 @@ namespace nes::sys } } +#ifdef NES_ENABLE_SNAPSHOTS auto nes::get_snapshot() -> snapshot { auto res = snapshot{}; @@ -57,4 +52,5 @@ namespace nes::sys ppu_.build_snapshot(res); return res; } +#endif } // namespace nes::sys \ No newline at end of file diff --git a/lib/nes/sys/nes.hh b/lib/nes/sys/nes.hh index 2533cbb..8d03dd7 100644 --- a/lib/nes/sys/nes.hh +++ b/lib/nes/sys/nes.hh @@ -1,6 +1,7 @@ #pragma once #include "nes/sys/types/cycle-count.hh" +#include "nes/sys/types/snapshot.hh" #include "nes/sys/cartridge.hh" #include "nes/sys/controller.hh" #include "nes/sys/cpu.hh" @@ -14,8 +15,6 @@ namespace nes namespace nes::sys { - struct snapshot; - /// The main console abstraction. class nes { @@ -43,10 +42,11 @@ namespace nes::sys auto ref_controller_2() -> controller& { return controller_2_; } auto step() -> void; - auto step(std::chrono::microseconds delta) -> void; auto step(cycle_count delta) -> void; auto step_to_nmi() -> void; +#ifdef NES_ENABLE_SNAPSHOTS auto get_snapshot() -> snapshot; +#endif }; } // namespace nes::sys \ No newline at end of file diff --git a/lib/nes/sys/ppu.cc b/lib/nes/sys/ppu.cc index 2419030..ce145d5 100644 --- a/lib/nes/sys/ppu.cc +++ b/lib/nes/sys/ppu.cc @@ -6,6 +6,7 @@ #include "nes/common/display.hh" #include "nes/common/rgb.hh" #include "nes/common/debug.hh" +#include "nes/common/utils.hh" namespace nes::sys { @@ -16,11 +17,13 @@ namespace nes::sys { } +#ifdef NES_ENABLE_SNAPSHOTS auto ppu::build_snapshot(snapshot& snapshot) -> void { snapshot.vram = std::vector(std::begin(vram_), std::end(vram_)); snapshot.oam = std::vector(std::begin(oam_), std::end(oam_)); } +#endif auto ppu::step() -> void { @@ -291,7 +294,7 @@ namespace nes::sys { for (auto i = u32{ 0 }; i < tile_size / 2; ++i) { - std::swap(res.colors[i], res.colors[tile_size - 1 - i]); + swap(res.colors[i], res.colors[tile_size - 1 - i]); } } @@ -382,7 +385,7 @@ namespace nes::sys if (addr % 0x4000 <= address{ 0x3EFF }) { - std::swap(res, ppudata_read_buffer_); + swap(res, ppudata_read_buffer_); } else { diff --git a/lib/nes/sys/ppu.hh b/lib/nes/sys/ppu.hh index 5697081..898ddd3 100644 --- a/lib/nes/sys/ppu.hh +++ b/lib/nes/sys/ppu.hh @@ -1,6 +1,7 @@ #pragma once #include "nes/sys/types/cycle-count.hh" +#include "nes/sys/types/snapshot.hh" #include "nes/common/containers/span.hh" #include "nes/common/types.hh" @@ -15,7 +16,6 @@ namespace nes::sys class address; class cpu; class cartridge; - struct snapshot; class ppu { @@ -239,7 +239,9 @@ namespace nes::sys auto operator=(ppu&&) -> ppu& = delete; auto get_cycles() const -> cycle_count { return current_cycles_; } +#ifdef NES_ENABLE_SNAPSHOTS auto build_snapshot(snapshot&) -> void; +#endif auto step() -> void; // Memory access diff --git a/lib/nes/sys/types/cycle-count.hh b/lib/nes/sys/types/cycle-count.hh index c977d1d..2368008 100644 --- a/lib/nes/sys/types/cycle-count.hh +++ b/lib/nes/sys/types/cycle-count.hh @@ -1,7 +1,6 @@ #pragma once #include "nes/common/types.hh" -#include namespace nes::sys { @@ -34,9 +33,9 @@ namespace nes::sys return cycle_count{ units }; } - static constexpr auto from_duration(std::chrono::microseconds const duration) -> cycle_count + static constexpr auto from_microseconds(u64 const microseconds) -> cycle_count { - return from_units(static_cast(duration.count()) * second().get_units() / (1000 * 1000)); + return from_units(microseconds * second().get_units() / (1000 * 1000)); } static constexpr auto from_cpu(u64 const cpu_cycles) -> cycle_count @@ -52,9 +51,9 @@ namespace nes::sys /// Value in implementation-defined units. constexpr auto get_units() const -> u64 { return units_; } - constexpr auto to_duration() const -> std::chrono::microseconds + constexpr auto to_microseconds() const -> u64 { - return std::chrono::microseconds{ get_units() * 1000 * 1000 / second().get_units() }; + return get_units() * 1000 * 1000 / second().get_units(); } constexpr auto to_cpu() const -> u64 diff --git a/lib/nes/sys/types/snapshot.hh b/lib/nes/sys/types/snapshot.hh index c057aeb..ff3f6a6 100644 --- a/lib/nes/sys/types/snapshot.hh +++ b/lib/nes/sys/types/snapshot.hh @@ -1,5 +1,7 @@ #pragma once +#ifdef NES_ENABLE_SNAPSHOTS + #include "nes/sys/types/cycle-count.hh" #include "nes/common/types.hh" #include @@ -60,4 +62,6 @@ namespace nes::sys } inline auto operator!=(snapshot const& a, snapshot const& b) -> bool { return !(a == b); } -} // namespace nes::sys \ No newline at end of file +} // namespace nes::sys + +#endif \ No newline at end of file -- cgit v1.3.1