From 353af883aa8bf190b94260901c87f568385ad5b9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 12 Oct 2024 12:34:21 -0400 Subject: [PATCH] Add deep copy functions Does allocation, a memcpy shallow copy, and a callback to handle memory addresses if desired. Might be reusable for runahead saves. --- src/CMakeLists.txt | 1 + src/p_deepcopy.cpp | 229 +++++++++++++++++++++++++++++++++++++++++++++ src/p_deepcopy.h | 131 ++++++++++++++++++++++++++ src/p_setup.cpp | 16 +--- 4 files changed, 365 insertions(+), 12 deletions(-) create mode 100644 src/p_deepcopy.cpp create mode 100644 src/p_deepcopy.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ffac4ae2..5378021f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -167,6 +167,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 music.cpp music_manager.cpp sanitize.cpp + p_deepcopy.cpp ) if(SRB2_CONFIG_ENABLE_WEBM_MOVIES) diff --git a/src/p_deepcopy.cpp b/src/p_deepcopy.cpp new file mode 100644 index 000000000..6a6b6ec37 --- /dev/null +++ b/src/p_deepcopy.cpp @@ -0,0 +1,229 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file p_deepcopy.cpp +/// \brief Methods for deep copying + +#include "p_deepcopy.h" + +#include "typedef.h" +#include "z_zone.h" +#include "taglist.h" +#include "r_defs.h" + +/*-------------------------------------------------- + static void P_DeepCopy(Type *target, Type *source, void (*callback)(Type *, Type *)) + + Make a deep copy of a struct, by using memcpy + for an initial shallow copy, and a callback + function to handle any memory addresses. + + Input Arguments:- + Type: The type of the structs. + target: The struct to copy into. + source: The struct to copy from. + callback: A callback function, intended to replace + pointers after the initial shallow copy. + + Return:- + N/A +--------------------------------------------------*/ + +template +static void P_DeepCopy(Type *target, Type *source, void (*callback)(Type *, Type *)) +{ + memcpy(target, source, sizeof(Type)); + + if (callback != nullptr) + { + callback(target, source); + } +} + +/*-------------------------------------------------- + static void P_DeepCopyArray(Type **target_array, Type **source_array, size_t source_len, void (*callback)(Type *, Type *)) + + Make a deep copy of an array of structs, by using + memcpy for an initial shallow copy, and a callback + function to handle any memory addresses for each + individual struct. + + Input Arguments:- + Type: The type of the structs. + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + callback: A callback function, intended to replace + pointers after the initial shallow copy. + + Return:- + N/A +--------------------------------------------------*/ + +template +static void P_DeepCopyArray(Type **target_array, Type **source_array, size_t source_len, void (*callback)(Type *, Type *)) +{ + const size_t source_total = source_len * sizeof(Type); + + *target_array = static_cast(Z_Calloc(source_total, PU_LEVEL, nullptr)); + memcpy(*target_array, *source_array, source_total); + + if (callback != nullptr) + { + for (size_t i = 0; i < source_len; i++) + { + Type *target = &(*target_array)[i]; + Type *source = &(*source_array)[i]; + + callback(target, source); + } + } +} + +/*-------------------------------------------------- + static void copy_taglist_tags(taglist_t *target, taglist_t *source) + + Make a deep copy of taglist's tags fields. + Used as a helper function for other callbacks, + does not work as a full deep copy of taglist_t + on its own. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +static void copy_taglist_tags(taglist_t *target, taglist_t *source) +{ + if (source->count) + { + target->tags = static_cast( + memcpy( + Z_Malloc( + source->count * sizeof(mtag_t), + PU_LEVEL, + nullptr + ), + source->tags, + source->count * sizeof(mtag_t) + ) + ); + } +} + +/*-------------------------------------------------- + static void copy_sector_callback(sector_t *target, sector_t *source) + + Handles memory addresses after creating a shallow copy + of a sector_t, to turn it into a deep copy. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +static void copy_sector_callback(sector_t *target, sector_t *source) +{ + // (Not a true deep copy until all of the memory addresses are accounted for.) + copy_taglist_tags(&target->tags, &source->tags); +} + +/*-------------------------------------------------- + void P_DeepCopySector(sector_t *target, sector_t *source) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySector(sector_t *target, sector_t *source) +{ + P_DeepCopy(target, source, copy_sector_callback); +} + +/*-------------------------------------------------- + void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len) +{ + P_DeepCopyArray(target_array, source_array, source_len, copy_sector_callback); +} + +/*-------------------------------------------------- + static void copy_line_callback(line_t *target, line_t *source) + + Handles memory addresses after creating a shallow copy + of a line_t, to turn it into a deep copy. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +static void copy_line_callback(line_t *target, line_t *source) +{ + // (Not a true deep copy until all of the memory addresses are accounted for.) + copy_taglist_tags(&target->tags, &source->tags); +} + +/*-------------------------------------------------- + void P_DeepCopyLine(line_t *target, line_t *source) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopyLine(line_t *target, line_t *source) +{ + P_DeepCopy(target, source, copy_line_callback); +} + +/*-------------------------------------------------- + void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len) +{ + P_DeepCopyArray(target_array, source_array, source_len, copy_line_callback); +} + +/*-------------------------------------------------- + void P_DeepCopySide(line_t *target, line_t *source) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySide(side_t *target, side_t *source) +{ + P_DeepCopy(target, source, nullptr); // (Not a true deep copy until all of the memory addresses are accounted for.) +} + +/*-------------------------------------------------- + void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len) +{ + P_DeepCopyArray(target_array, source_array, source_len, nullptr); // (Not a true deep copy until all of the memory addresses are accounted for.) +} diff --git a/src/p_deepcopy.h b/src/p_deepcopy.h new file mode 100644 index 000000000..8eb766f7a --- /dev/null +++ b/src/p_deepcopy.h @@ -0,0 +1,131 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file p_deepcopy.h +/// \brief Methods for deep copying + +#ifndef __P_DEEPCOPY__ +#define __P_DEEPCOPY__ + +#include "doomdef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------- + void P_DeepCopySector(sector_t *target, sector_t *source); + + Make a deep copy of a single sector_t. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySector(sector_t *target, sector_t *source); + + +/*-------------------------------------------------- + void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len); + + Make a deep copy of an array of sector_t. + + Input Arguments:- + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len); + + +/*-------------------------------------------------- + void P_DeepCopyLine(line_t *target, line_t *source) + + Make a deep copy of a single line_t. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopyLine(line_t *target, line_t *source); + + +/*-------------------------------------------------- + void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len) + + Make a deep copy of an array of line_t. + + Input Arguments:- + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len); + + +/*-------------------------------------------------- + void P_DeepCopySide(line_t *target, line_t *source) + + Make a deep copy of a single side_t. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySide(side_t *target, side_t *source); + + +/*-------------------------------------------------- + void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len) + + Make a deep copy of an array of side_t. + + Input Arguments:- + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __P_DEEPCOPY__ diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 5ae710677..c8ed9cd95 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -119,6 +119,7 @@ #include "k_endcam.h" #include "k_credits.h" #include "k_objects.h" +#include "p_deepcopy.h" // Replay names have time #if !defined (UNDER_CE) @@ -7535,7 +7536,6 @@ static boolean P_LoadMapFromFile(void) TracyCZone(__zone, true); virtlump_t *textmap = vres_Find(curmapvirt, "TEXTMAP"); - size_t i; udmf = textmap != NULL; udmf_version = 0; @@ -7563,17 +7563,9 @@ static boolean P_LoadMapFromFile(void) P_WriteTextmap(); // Copy relevant map data for NetArchive purposes. - spawnsectors = static_cast(Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL)); - spawnlines = static_cast(Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL)); - spawnsides = static_cast(Z_Calloc(numsides * sizeof(*sides), PU_LEVEL, NULL)); - - memcpy(spawnsectors, sectors, numsectors * sizeof(*sectors)); - memcpy(spawnlines, lines, numlines * sizeof(*lines)); - memcpy(spawnsides, sides, numsides * sizeof(*sides)); - - for (i = 0; i < numsectors; i++) - if (sectors[i].tags.count) - spawnsectors[i].tags.tags = static_cast(memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t))); + P_DeepCopySectors(&spawnsectors, §ors, numsectors); + P_DeepCopyLines(&spawnlines, &lines, numlines); + P_DeepCopySides(&spawnsides, &sides, numsides); P_MakeMapMD5(curmapvirt, &mapmd5);