#arraylist out of memory
1 messages · Page 1 of 1 (latest)
that isn't an OOM error, this is a type error
look closely and you'll see the compiler is telling you it's a compilation error
not the type, you need to properly unwrap errors and if you propogate them, ensure the return type is correct
what's the function that this happens in look like
it looks like you are trying to assign the result of append to a field, but append returns !void so it's probably not what you want
const std = @import("std");
const ArrayList = std.ArrayList;
const allocator = std.mem.Allocator;
const Slot = @import("slot.zig").Slot;
pub const HardFork = struct { Slot, usize };
pub const HardForks = struct {
hard_forks: ArrayList(HardFork),
const Self = @This();
pub fn default(alloc: allocator) Self {
return .{ .hard_forks = ArrayList(HardFork).init(alloc) };
}
pub fn register(self: *Self, new_slot: Slot) void {
// const index = std.mem.indexOfScalar(HardFork, self.hard_forks, .{} );
const index = for (self.hard_forks.items, 0..) |hf, i| {
if (hf[0].value == new_slot.value) break i;
} else null;
if (index != null) {
self.hard_forks = self.hard_forks.append(.{ new_slot, self.hard_forks.items[index.?][1] +| 1 });
} else {
self.hard_forks.append(.{ new_slot, 1 });
}
std.mem.sort(HardFork, self.hard_forks);
}
};
test "hard_forks" {
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};
const alloc = gpa.allocator();
defer _ = gpa.deinit();
var k = HardForks.default(alloc);
k.register(Slot.init(1));
std.debug.print("hard forks test", .{});
}
``` its the register function
right, append doesn't return a new arraylist
oh yes this makes sense
it mutates the arraylist in place
the out of memory part made it look like its a memory issue😅
so you can simply remove the assignment in this line ```rust
self.hard_forks = /* remove until here */ self.hard_forks.append(.{ new_slot, self.hard_forks.items[index.?][1] +| 1 });
for future reference: runtime error stack traces don't usually include direct references to types, rather they trace function calls
yeah zig type errors can sometimes be a bit overwhelming, especially with a lot of generics and function types
yep and also since its an ! type i added a try before both appends
but now i need to change the function return type
yep, thats how it is
where can i find the Error type for this
if i recall i need to write it as ErrorType!void
you don't need to do that
or is there a generic error type
you can just write !void
oh
that will infer the error type
(it's not generic, it's the specific set of errors that are returned from the function)
but if you want to specify the error set explicitly you could use Allocator.Error
there is a runtime-generic error type called anyerror, however you should not use this unless you specifically know that you need to
am i using the correct function for sorting
isn't there an argument missing? docs say this is the signature ```rust
fn sort(comptime T: type, items: []T, context: anytype, comptime lessThanFn: fn (@TypeOf(context), T, T) bool) void
https://github.com/rust-lang/rust/blob/a0c28cd9dc99d9acb015d06f6b27c640adad3550/library/alloc/src/slice.rs#L207 just trying to get something similar to this
yes but couldnt figure out what else its expecting so i thought im using the wrong sorting function altogether
I would probably write
std.mem.sortContext(0, self.hard_forks.items.len, struct {
items: []HardFork
pub fn lessThan(ctx: @This(), a: usize, b: usize) bool {
return ctx.items[a].slot < ctx.items[b].slot;
}
pub fn swap(ctx: @This(), a: usize, b: usize) void {
std.mem.swap(HardFork, &self.items[a], &self.items[b]);
}
}{ .items = self.hard_forks.items });
why sortContext?
could also write
std.mem.sort(HardFork, self.items, {}, struct{
pub fn lessThan(_: void, a: HardFork, b: HardFork) bool {
return a.slot < b.slot;
}
}.lessThan)
yeah thats the simpler version, and you can also just put the function outside of the call itself
I mostly use context functions because I usually end up doing something more complex with the sorting which requires I use the context variants anyway
can u explain what the other two are?
especially with MultiArrayList
oh its the actual sort function
it takes a context and a comparator function. the context is any extra value you want to use inside the less than function (in the simplest case you don't need it and use void)
btw if a.slot and b.slot are a struct with a field value:u64 does it automatically compare ?
a.slot.value < b.slot.value
eql cn be used to compare entire structs as we prev discussed
there shud be something like eql for order too
don't really see the use case. The scope is much more limited
specifically in most cases there is no natural order for structs
it would appear you are not freeing your memory
i deferred though
ensure that at some point you call .deinit() on your arraylist
can you send your code?
that doesn't free the list
that deinitialises the gpa state and tells you you leaked memory
you still need to free your allocations
ah that doesn't free, it only checks for leaks. so it tells you if you forgot to free stuff before calling deinit
if you wanted that behaviour, you'd need to use an ArenaAllocator
recommendation: add a deinit method to your HardForks type
i did it from outside
make sure you do defer k.deinit() immediately after you initialise it
otherwise you will leak memory if you encounter an error before you reach the deinit call
we can hv two defers?
you can have however many you want
the defer furthest down in the scope will be the first to run
and the first in scope will be the last to run
very much alike the behaviour RAII objects
but typically you shouldn't free the same thing twice
certainly, but in terms of how many defers are allowed in a block, you're free to write as many defers as you want
yep, just thought I'd add that in case the question comes up
so just so i get this right, i should defer the gpa first in order of the code and then the arraylist so that the array list is freed first and then the alloc is deinit?
yes
makes sense
most of the times you simply defer right after initializing/allocating something
can think of it like manual RAII
in tests its recommended to use the testing allocator right?
unless you're testing behaviour with a specific allocator, or testing your own allocator implementation, generally yes
gotcha
thanks @warped stream and @charred quartz my code works now 🥂
Hey @charred quartz i tried to set a change an index in my array list like
self.hard_forks[index] = ...
``` but it says it doesnt support indexing so is there a method for this?
or are we expected to do
self.hard_forks.items[index] = ...
yes
of course assuming that index already exists, i.e. items.len > index
@warped stream i saw a discord message where u used the older version of @mulWithOverflow where it takes 4 params, do u recall the types of that?
I believe it used to take a type parameter, the two operands, and a pointer to the result location, and it returned a bool or a vector of bools that describe whether the multiplication overflowed
Now it infers the operand types, and now returns a tuple containing the overflow bool/bool vector, and the result
yea so now its just mulwithOverflow(a: anytype, b:anytype)
is this how it used to be mulWithOverflow(type: type, a: anytype, b: anytype, result: *anytype)
More like (comptime T: type, a: T, b: T, result: *T) bool
ah ohk thanks
it returns struct { @TypeOf(a, b), u1 }
how is this a bool
is u1 a bool here
mul overflow can be as big as the input numbers
feel like the older return was simpler
t'was harder to optimize
so any idea how we get the bool result from this?
should it be @mulWithOverflow(a,b)[0] == @TypeOf(a,b)
ye
gotcha
it uses PTR
?
peer type resolution
pardon the jargon
basically when there are two or more expressions in an operation which will evaluate to another value assigned to some location (such as if (cond) a else b, a + b, switch (v) { .foo => a, .bar => b, .baz => c }, etc), peer type resolution is invoked to determine what the "resolved type" between the types of all the expressions will be
@warped stream in the older function sig what was the exact return type
bool
trying to modify this legacy code to work again
const mul_result = @mulWithOverflow(octs[octets_index], 10);
if (mul_result[1] == 1) return error.InvalidIpv4;
seems it was u1 then
no, originally it returned the result through the last out parameter
and returned the overflow state through the return value
you can always read the older docs
how?
thats what ive been trying to find
is there any way to know which version of zig this code was using
depends on the code
like rust has rustoolchain.toml
nothin like that
k
well you can see it was last commited 4 years ago
so you can probably figure out by seeing what zig version was stable 4 years ago on https://ziglang.org/download/
might be the version after the one 4 years ago if they were following master