• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

How to copy a struct ?

Status
Not open for further replies.

DaveInDev

Member
Hi,

I have an array of structs called tab (all have the same variables), and let say that I would like to insert in position 5 a copy of the struct in position 3.

If I just make array_insert(tab,5,tab[3]), it will only copy a reference or the id of the struct in position 3.
So if I modify tab[5] content, I will also modify tab[3] content...

Thats' not what I want, I need to clone the struct in tab[3] to create a brand new object.
How can I do this ? I do not find any builtin function, nor any answer if I type "GMS2 copy struct" in google... :confused:

Am I supposed to create mu own deepcopy function that would recursively copy my struct ? (BTW, did I mention that my struct contains arrays and other structs ?... ;))
 
If you know the kind of data the struct contains, and they all have constructors, I'd recommend just writing it and all contained structs a Copy() method that spits out a clone of itself and its contained data, recursively calling Copy() on eventual struct members. This would surely run faster than anything scanning for variables and datatypes. Or you could use a pre-made library such as SNAP by JujuAdams https://github.com/JujuAdams/SNAP
 
I use this function to copy a struct:
GML:
function copyStruct(struct){
    var key, value;
    var newCopy = {};
    var keys = variable_struct_get_names(struct);
    for (var i = array_length(keys)-1; i >= 0; --i) {
            key = keys[i];
            value = struct[$ key];
            variable_struct_get(struct, key);
            variable_struct_set(newCopy, key, value)
    }
    return newCopy;
}
 

WangleLine

Member
I use this function to copy a struct:
GML:
function copyStruct(struct){
    var key, value;
    var newCopy = {};
    var keys = variable_struct_get_names(struct);
    for (var i = array_length(keys)-1; i >= 0; --i) {
            key = keys[i];
            value = struct[$ key];
            variable_struct_get(struct, key);
            variable_struct_set(newCopy, key, value)
    }
    return newCopy;
}
Sadly this doesn't quite work if you have nested structs (structs inside structs), as any included struct will only be copied by reference
 

Zhanghua

Member
When do we have "struct_map" "struct_for_each" etc.?
rwkay



I burst my DeepClone function from 350ms to 200ms per 10000 times.
Share it with guys~~
GML:
function DeepCloneArray(s){
  return array_map(s,function(e){
       if( is_array(e) ){ return DeepCloneArray(e); }
       else if( is_struct(e) ){ return DeepCloneStruct(e); }
       return e;
  });
}

function DeepCloneStruct(s){
    return array_map(
        variable_struct_get_names(s),
        method({ctx: s},function(nm){
            var e = ctx[$ nm];
            if( is_array(e) ){ return DeepCloneArray(e); }
            else if( is_struct(e) ){ return DeepCloneStruct(e); }
            return e;
        })
    );
}

function DeepClone(s){
    if( is_array(s) ){ return DeepCloneArray(s);}
    else if( is_struct(s) ){ return DeepCloneStruct(s);}
    return s;
}
 

chirpy

Member
@Zhanghua
Good code, but what is array_map? Is it a beta gml function?
Also, this doesn't seem to handle cyclic structs like builtin string(_struct) does.

GML:
var hello = { hello:"world" };
var world = { oops: hello };
hello.world = world;

//var ouch = DeepClone(hello);
var ouch = hello;
show_debug_message(string(ouch));
 

sixonekevin

Member
It feels crunchy and might have issues depending on your data types but tbh I think the easiest way is just to stringify and then parse it.
 

Zhanghua

Member
beta function.
cycle reference should be avoid by yourself considering the efficiency.
If you want to make a graph struct, you should craft anothor graph copy function.
 

ricardo1996

Member
Here's a lil function I made.
GML:
/// @function struct_update(source, target, replace)
/// @description Copy/Replace keys from source struct to target struct. Note data structures will not be deep copied.
/// @param {Struct} source Source struct to copy from.
/// @param {Struct} target Target struct to copy to.
/// @param {Bool} replace Overwrite existing target keys with source keys.
function struct_update(s, t, r = false)
{
    for(var i = 0, a = variable_struct_get_names(s), l = array_length(a); i < l; ++i)
    {
        var
        k = a[@ i],
        v = s[$ k],
        c = t[$ k];
        if(c != undefined)
        {
            if(is_array(v))
            {
                var u = array_length(c);
                for(var o = 0, p = array_length(v); o < p; ++o)
                {
                    if(!r && o < u) continue;
                    c[@ o] = v[@ o];
                }
                continue;
            }else if(is_struct(v))
            {
                struct_update(v, c, r);
                v = c;
            }else if(!r) continue;
        }
        t[$ k] = v;
    }
}
data structures aren't deep copied
 
For anyone looking for answer to this question, like I was, about a year ago Gamemaker added a new function "variable_clone()" which will copy arrays, structs etc. down over 100 layers.
 
Status
Not open for further replies.
Top