How properly Append U8

pub fn editorOpen(fliename: [*:0]u8) !void {
    var file = try std.fs.cwd().openFile(std.mem.span(fliename), .{});
    defer file.close();

    var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){};
    const allocator = gpa.allocator();
    defer _ = gpa.deinit();

    var ab = std.ArrayListUnmanaged(u8){};
    defer ab.deinit(allocator);

    while (try file.reader().readUntilDelimiterOrEofAlloc(allocator, '\n', std.math.maxInt(usize))) |line| {

        // Trim trailing newline or carriage return characters
        var linelen = line.len;
        while (linelen > 0 and (line[linelen - 1] == '\n' or line[linelen - 1] == '\r')) {
            linelen -= 1;
        }

        const allocator_internal = std.heap.page_allocator;
        E.row.chars = try allocator_internal.alloc(u8, linelen + 1);
        @memcpy(E.row.chars[0..linelen], line[0..linelen]);
        // E.row.chars = slice;
        // defer allocator_internal.free(E.row.chars);

        E.numrows = 1;
        E.row.size += linelen;
        defer allocator.free(line);
    }
}

if i run this code only last line in file is stored in E.row.chars i want entire file in this E.row.chars what to do

If you want to append then you should use a list:

--chars: []const u8,
++chars: std.ArrayListUnmanaged(u8) = .{},
...
--        E.row.chars = try allocator_internal.alloc(u8, linelen + 1);
--        @memcpy(E.row.chars[0..linelen], line[0..linelen]);
++        try E.row.chars.append(allocator_internal, line[0..linelen]);

​

Also another note: If you want to read the entire file into a single string, you could just use std.fs.cwd().readFileAlloc(...)

1 Like

lets say if i have another
ab:std.ArrayListUnmanaged(u8) = .{}

can i append

ab.append(allocator,E.rows.chars)

when i tried to do i got error

expected u8 found ArrayListUnManaged

how to add or conactinate two ArrayListUnManaged

or if anybody can help me on how to convert ArrayListUnmanaged to u8

To merge two arrays you’ll want to use something like appendSlice.

list1.appendSlice(list2.items);

Note that pointers to items in the slice should be considred invalid after this operation as it may require memory to be moved, in order to grow the backing slice.

or if anybody can help me on how to convert ArrayListUnmanaged to u8

If you are done growing/resizing the ArrayList, you can always call toOwnedSlice which gives you a slice over the data in the ArrayList.

list1.appendSlice(list2.items);

this works fine if until i add ‘\n’ after each iteration if i add use

what should i do to append a newline to a listUnmanaged

‘\n’ is a single byte “character”, which is why you can’t append it using the appendSlice. You can just use append which is the method to append 1 item to an array list.

why a newline character causes memmory leak

I’d need to see the fully updated code.

pub fn editorOpen(fliename: [*:0]u8) !void {
    var file = try std.fs.cwd().openFile(std.mem.span(fliename), .{});
    defer file.close();

    var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){};
    const allocator = gpa.allocator();
    defer _ = gpa.deinit();

    while (try file.reader().readUntilDelimiterOrEofAlloc(allocator, '\n', std.math.maxInt(usize))) |line| {
        try E.row.chars.appendSlice(allocator, line);
        try E.row.chars.append(allocator, '\n');
        E.numrows = 1;
        defer allocator.free(line);
    }
}

pub fn editorDrawRows(allocator: std.mem.Allocator, ab: *std.ArrayListUnmanaged(u8)) !void {
    const rowsize = @as(u32, @intCast(E.screenrows));
    const colsize = @as(u32, @intCast(E.screencols));

    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator_local = gpa.allocator();

    for (0..rowsize - 1) |y| {
        if (y >= E.numrows) {
            if (y == rowsize - 2 and E.numrows == 0) {
                const welcome = try std.fmt.allocPrint(allocator_local, "Kilo editor -- version {s}", .{kiloversion});

                var padding = (colsize - welcome.len) / 2;
                if (padding > 0) {
                    try ab.appendSlice(allocator, "~");
                    padding -= 1;
                }
                while (padding > 0) {
                    try ab.appendSlice(allocator, " ");
                    padding -= 1;
                }

                if (welcome.len > colsize) {
                    try ab.appendSlice(allocator, welcome[0..colsize]);
                } else {
                    try ab.appendSlice(allocator, welcome);
                }
            } else {
                try ab.appendSlice(allocator, "~");
            }
        } else {
            try ab.appendSlice(allocator, E.row.chars.items);
            // E.row.chars.deinit(allocator);
        }
        try ab.appendSlice(allocator, "\x1b[K");
        if (y < rowsize - 1) {
            try ab.appendSlice(allocator, "\r\n");
        }
    }
}

pub fn editorRefreshScreen() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var ab = std.ArrayListUnmanaged(u8){};
    defer ab.deinit(allocator);

    try ab.appendSlice(allocator, "\x1b[?25l");
    try ab.appendSlice(allocator, "\x1b[H");

    try editorDrawRows(allocator, &ab);

    const allocator_local = std.heap.page_allocator;
    const buf = try std.fmt.allocPrint(allocator_local, "\x1b[{};{}H", .{ E.cy + 1, E.cx + 1 });
    try ab.appendSlice(allocator, buf);

    try ab.appendSlice(allocator, "\x1b[?25h");

    try std.io.getStdOut().writeAll(ab.items);
}

pub fn main() !void {
    defer disableRawMode();
    enableRawMode();
    try initEditor();
    const args = std.os.argv.len;
    if (args >= 2)
        try editorOpen(std.os.argv[1]);

    while (true) {
        editorRefreshScreen() catch {
            std.debug.print("editor refresh screen", .{});
            break;
        };
        editorProcessKeyPress() catch {
            break;
        };
    }
}

You are calling defer _ = gpa.deinit(); in your editorOpen function, but later in that function you are are making allocations with the gpa allocator that aren’t freed and seem like they should persist beyond the scope of the function. The gpa.deinit() call checks for memory leaks and frees all of the allocations.

1 Like

after removing it memmory leak error is gone

thanks

how to deint this gpa

move the:

var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

from the editorRefreshScreen function to the beginning of main, all other functions that need an allocator need to take allocator as a std.mem.Allocator parameter.


You shouldn’t create separate allocator instances all over the place, normally you create the gpa in main and then pass the allocator-interface to functions that need it, then some parts of the program may use it to create a different allocator, that is just needed temporarily.

If you create separate allocators without having a good reason for it, it defeats the debugging features of the gpa, by not being sure anymore if your allocator was even de-initialized at all. By just using one, that is de-initialized in main, you can be sure it detects the leaks once the program shuts down, it also makes it easier to change what allocator is used if you eventually want to change it.


As @IntegratedQuantum has already pointed out it would be simpler to readFileAlloc the entire file, and then find the lines within that.

Additionally you don’t need to concatenate all the lines before outputting them,
instead you can define a buffered writer and directly write the lines to it,
then flush the buffered writer to make sure everything is written.

Without a buffered writer you risk making more system calls (which your code avoids by concatenating first, but that itself creates unnecessary reallocations, when the goal is to output the result, writing the lines to a buffered writer is more efficient, because it means your program doesn’t have to allocate and re-allocate a growing buffer)
(So something more like this String formatting in a bit more complex cases - #10 by plano)

1 Like