Skip to content

std.mem.copy does not work if slices overlap #382

@andrewrk

Description

@andrewrk

Zig's current implementation of std.mem.copy is this:

/// Copy all of source into dest at position 0.
/// dest.len must be >= source.len.
/// The memory areas must not overlap.
pub fn copy(comptime T: type, dest: []T, source: []const T) {
    for (source) |s, i| dest[i] = s;
}

"The memory areas must not overlap" is a pretty lame restriction, especially since the single branch it takes to make it work either way is a low cost. So this could be:

/// Copy all of source into dest at position 0.
/// dest.len must be >= source.len.
pub fn copy(comptime T: type, dest: []T, source: []const T) {
    if (usize(dest.ptr) < usize(source.ptr) or
        usize(source.ptr) + source.len <= usize(dest.ptr))
    {
        for (source) |s, i| dest[i] = s;
    } else {
        for (source) |s, i| dest[source.len - i] = source[source.len - i];
    }
}

If we want to have another function, copyAssumeNoOverlap with this branch optimized away, that's fine. We'd still need to add that assert though:

/// Copy all of source into dest at position 0.
/// dest.len must be >= source.len.
/// The memory areas must not overlap.
pub fn copyAssumeNoOverlap(comptime T: type, dest: []T, source: []const T) {
    assert(usize(dest.ptr) < usize(source.ptr) or usize(source.ptr) + source.len <= usize(dest.ptr));
    for (source) |s, i| dest[i] = s;
}

Now here's the problem:

  • usize(slice.ptr) does not work at compile time
  • std.mem.copy should work at compile time

At compile time we still have this concept of overlapping memory, but the way we want to check for overlapping memory doesn't work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementSolving this issue will likely involve adding new logic or components to the codebase.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions