Allocator Deep Dupe

Is there a function in the standard library that can recursively dupe a data structure containing pointers?

Something like this:

test {
    const strs: []const []const u8 = &.{ "hello", "world" };
    const strs2: [][]u8 = std.testing.allocator.dupeDeep(strs);
    strs2[0][0] = 'd';
    try std.testing.expectEqualSlices(u8, "dello", strs2[0]);
}

My use case is that I want to write some tests where I only change one small part of a large data structure that I have initially written as a const.

I guess you would also need some kind of freeDeep…

That is a fairly complicated problem to solve to ever be a “general purpose” function, you will most assuredly need to roll your own that knows about your specific data.

Obviously recursively iterating through fields is pretty straightforward, but knowing which pointers should be followed, which are heap-allocated, which are pointing to temporary values on the stack, which are pointing to each other, which are pointing to themselves, etc, etc. offers no shortage of scenarios that will explode your program.

Can you not just @constCast it or not initialize it as constant? If this is just for tests, I personally wouldn’t think twice about using @constCast shenanigans to simplify things.

An arena would be a simple solution for this, assuming it is appropriate for your use-case.

This is in a nutshell why I prefer nested arrays over nested slices. Allows to copy everything with a single dumb assignment and without having to worry about ownerhship and lifetime (at the cost of unused array slots, but very often a good max bound can be defined).

3 Likes

Consider interning the strings instead, so you can copy your lineral intern structure, and complicated nested datastructures simply point to the interned structure.

5 Likes

This is only possible if all possible string values are comptime-known, is it not?

Nope, interning is basically a small wrapper around a hash map and a memory pool, in the case of strings that can just be an array list.

Your handle could just be a slice, or if you null terminate the strings in the array list it can just be the index of the start, which you can shrink further with a smaller integer type.

3 Likes

Ooh.

Check if the string constant exists, create it if it doesn’t, all future instances that want this particular string points to the instance in the map. Now all instances are trivially copyable because they all contain a pointer to the same memory.

Like that?

1 Like

an index / offset, otherwise yes.

Here is one within the Zig source zig/src/link/StringTable.zig at master · ziglang/zig · GitHub

2 Likes

@sze, @vulpesx, thank you both for the enlightening replies. :slight_smile:

1 Like