diff --git a/similar/main/state.cpp b/similar/main/state.cpp index 54472e313..19a08f3be 100644 --- a/similar/main/state.cpp +++ b/similar/main/state.cpp @@ -162,7 +162,6 @@ struct savegame_newmenu_items }; static constexpr unsigned decorative_item_count = 1; using imenu_description_buffers_array = std::array, NUM_SAVES>; - imenu_description_buffers_array *const user_entered_savegame_descriptions; d_game_unique_state::savegame_description *const caller_savegame_description; d_game_unique_state::savegame_file_path &savegame_file_path; enumerated_array savegame_file_paths; @@ -182,7 +181,7 @@ struct savegame_newmenu_items * savegame slot in use, return true. This does not test whether * there currently exists a savegame in the specified slot. */ - static unsigned valid_savegame_index(void *const user_entered_savegame_descriptions, const d_game_unique_state::save_slot selection) + static unsigned valid_savegame_index(const d_game_unique_state::savegame_description *const user_entered_savegame_descriptions, const d_game_unique_state::save_slot selection) { return user_entered_savegame_descriptions ? GameUniqueState.valid_save_slot(selection) @@ -190,7 +189,7 @@ struct savegame_newmenu_items } unsigned valid_savegame_index(const d_game_unique_state::save_slot selection) const { - return valid_savegame_index(user_entered_savegame_descriptions, selection); + return valid_savegame_index(caller_savegame_description, selection); } std::size_t get_count_valid_menuitem_entries(d_game_unique_state::savegame_description *const savegame_description) const { @@ -198,14 +197,30 @@ struct savegame_newmenu_items } }; -struct savegame_chooser_newmenu : savegame_newmenu_items, newmenu +struct savegame_chooser_newmenu final : savegame_newmenu_items, newmenu { + enum class trailing_storage_size : std::size_t + { + }; + static void *operator new(std::size_t bytes) = delete; + static void *operator new(std::size_t bytes, const trailing_storage_size extra_bytes) + { + return ::operator new(bytes + static_cast(extra_bytes)); + } + static void operator delete(void *p) + { + ::operator delete(p); + } + static void operator delete(void *p, trailing_storage_size) + { + ::operator delete(p); + } virtual window_event_result event_handler(const d_event &) override; static std::unique_ptr create(menu_subtitle caption, grs_canvas &src, d_game_unique_state::savegame_description *const savegame_description, d_game_unique_state::savegame_file_path &savegame_file_path); private: void draw_handler(grs_canvas &canvas, const grs_bitmap &bmp); void draw_handler(); - savegame_chooser_newmenu(menu_subtitle caption, grs_canvas &src, d_game_unique_state::savegame_description *, d_game_unique_state::savegame_file_path &, imenu_description_buffers_array *); + savegame_chooser_newmenu(menu_subtitle caption, grs_canvas &src, d_game_unique_state::savegame_description *, d_game_unique_state::savegame_file_path &); d_game_unique_state::save_slot build_save_slot_from_citem() const { if (citem < decorative_item_count) @@ -216,18 +231,18 @@ private: std::unique_ptr savegame_chooser_newmenu::create(menu_subtitle caption, grs_canvas &src, d_game_unique_state::savegame_description *const savegame_description, d_game_unique_state::savegame_file_path &savegame_file_path) { - std::unique_ptr p(savegame_description - /* request to create a "Save game" menu */ - ? reinterpret_cast(new typename std::aligned_union::type) - /* request to create a "Load game" menu */ - : reinterpret_cast(new typename std::aligned_union<0 /* no extra storage needed, and aligned_union will ensure the value is sufficient for the aligned type */, savegame_chooser_newmenu>::type) - ); - new (p.get()) savegame_chooser_newmenu(caption, src, savegame_description, savegame_file_path, savegame_description ? reinterpret_cast(p.get() + sizeof(savegame_chooser_newmenu)) : nullptr); - return std::unique_ptr(reinterpret_cast(p.release())); + /* If savegame_description is not nullptr, then this is a request to + * create a "Save game" menu. Otherwise, it is a request to create a + * "Load game" menu. + */ + const savegame_chooser_newmenu::trailing_storage_size extra_bytes{ + savegame_description ? sizeof(savegame_chooser_newmenu::imenu_description_buffers_array) : 0 + }; + return std::unique_ptr(new (extra_bytes) savegame_chooser_newmenu(caption, src, savegame_description, savegame_file_path)); } -savegame_chooser_newmenu::savegame_chooser_newmenu(menu_subtitle subtitle, grs_canvas &src, d_game_unique_state::savegame_description *const savegame_description, d_game_unique_state::savegame_file_path &savegame_file_path, imenu_description_buffers_array *const user_entered_savegame_descriptions) : - savegame_newmenu_items(savegame_description, savegame_file_path, user_entered_savegame_descriptions), +savegame_chooser_newmenu::savegame_chooser_newmenu(menu_subtitle subtitle, grs_canvas &src, d_game_unique_state::savegame_description *const savegame_description, d_game_unique_state::savegame_file_path &savegame_file_path) : + savegame_newmenu_items(savegame_description, savegame_file_path, savegame_description ? reinterpret_cast(this + 1) : nullptr), newmenu(menu_title{nullptr}, subtitle, menu_filename{nullptr}, tiny_mode_flag::normal, tab_processing_flag::ignore, adjusted_citem::create(unchecked_partial_range(m, get_count_valid_menuitem_entries(savegame_description)), decorative_item_count), src) { } @@ -975,7 +990,6 @@ uint8_t read_savegame_properties(const std::size_t savegame_index, d_game_unique } savegame_newmenu_items::savegame_newmenu_items(d_game_unique_state::savegame_description *const savegame_description, d_game_unique_state::savegame_file_path &savegame_file_path, imenu_description_buffers_array *const user_entered_savegame_descriptions) : - user_entered_savegame_descriptions(user_entered_savegame_descriptions), caller_savegame_description(savegame_description), savegame_file_path(savegame_file_path) {