@@ -3,19 +3,20 @@ const builtin = @import("builtin");
33const os = std .os ;
44const posix = std .posix ;
55const mem = std .mem ;
6+ const heap = std .heap ;
67const assert = std .debug .assert ;
78
89const AllocError = std .mem .Allocator .Error ;
910
1011const darwin = struct {
11- extern "c" fn madvise (ptr : [* ]align (mem.page_size ) u8 , length : usize , advice : c_int ) c_int ;
12+ extern "c" fn madvise (ptr : [* ]align (heap.page_size_min ) u8 , length : usize , advice : c_int ) c_int ;
1213};
1314
1415pub fn StableArray (comptime T : type ) type {
1516 return StableArrayAligned (T , @alignOf (T ));
1617}
1718
18- pub fn StableArrayAligned (comptime T : type , comptime alignment : u29 ) type {
19+ pub fn StableArrayAligned (comptime T : type , comptime _alignment : u29 ) type {
1920 if (@sizeOf (T ) == 0 ) {
2021 @compileError ("StableArray does not support types of size 0. Use ArrayList instead." );
2122 }
@@ -27,13 +28,25 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type {
2728 pub const VariableSlice = [* ]align (alignment ) T ;
2829
2930 pub const k_sizeof : usize = if (alignment > @sizeOf (T )) alignment else @sizeOf (T );
31+ pub const page_size : usize = heap .pageSize ();
32+ pub const alignment = _alignment ;
3033
3134 items : Slice ,
3235 capacity : usize ,
3336 max_virtual_alloc_bytes : usize ,
3437
38+ pub fn getPageSize (self : * Self ) usize {
39+ _ = self ;
40+ return Self .page_size ;
41+ }
42+
43+ pub fn getAlignment (self : * Self ) usize {
44+ _ = self ;
45+ return Self .alignment ;
46+ }
47+
3548 pub fn init (max_virtual_alloc_bytes : usize ) Self {
36- assert (@mod (max_virtual_alloc_bytes , mem . page_size ) == 0 ); // max_virtual_alloc_bytes must be a multiple of mem. page_size
49+ assert (@mod (max_virtual_alloc_bytes , page_size ) == 0 ); // max_virtual_alloc_bytes must be a multiple of page_size
3750 return Self {
3851 .items = &[_ ]T {},
3952 .capacity = 0 ,
@@ -208,8 +221,8 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type {
208221 } else {
209222 const base_addr : usize = @intFromPtr (self .items .ptr );
210223 const offset_addr : usize = base_addr + new_capacity_bytes ;
211- const addr : [* ]align (mem . page_size ) u8 = @ptrFromInt (offset_addr );
212- if (comptime builtin .target .isDarwin ()) {
224+ const addr : [* ]align (heap . page_size_min ) u8 = @ptrFromInt (offset_addr );
225+ if (comptime builtin .os . tag .isDarwin ()) {
213226 const MADV_DONTNEED = 4 ;
214227 const err : c_int = darwin .madvise (addr , bytes_to_free , MADV_DONTNEED );
215228 switch (@as (posix .E , @enumFromInt (err ))) {
@@ -243,7 +256,7 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type {
243256 const w = os .windows ;
244257 w .VirtualFree (@as (* anyopaque , @ptrCast (self .items .ptr )), 0 , w .MEM_RELEASE );
245258 } else {
246- var slice : []align (mem . page_size ) const u8 = undefined ;
259+ var slice : []align (heap . page_size_min ) const u8 = undefined ;
247260 slice .ptr = @alignCast (@as ([* ]u8 , @ptrCast (self .items .ptr )));
248261 slice .len = self .max_virtual_alloc_bytes ;
249262 posix .munmap (slice );
@@ -340,7 +353,7 @@ pub fn StableArrayAligned(comptime T: type, comptime alignment: u29) type {
340353 }
341354
342355 fn calcBytesUsedForCapacity (capacity : usize ) usize {
343- return mem .alignForward (usize , k_sizeof * capacity , mem . page_size );
356+ return mem .alignForward (usize , k_sizeof * capacity , page_size );
344357 }
345358 };
346359}
@@ -355,56 +368,61 @@ test "init" {
355368 a .deinit ();
356369
357370 var b = StableArrayAligned (u8 , 16 ).init (TEST_VIRTUAL_ALLOC_SIZE );
371+ assert (b .getAlignment () == 16 );
358372 assert (b .items .len == 0 );
359373 assert (b .capacity == 0 );
360374 assert (b .max_virtual_alloc_bytes == TEST_VIRTUAL_ALLOC_SIZE );
361375 b .deinit ();
376+
377+ assert (a .getPageSize () == b .getPageSize ());
362378}
363379
364380test "append" {
365381 var a = StableArray (u8 ).init (TEST_VIRTUAL_ALLOC_SIZE );
366382 try a .appendSlice (&[_ ]u8 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 });
367- assert (a .calcTotalUsedBytes () == mem . page_size );
383+ assert (a .calcTotalUsedBytes () == a . getPageSize () );
368384 for (a .items , 0.. ) | v , i | {
369385 assert (v == i );
370386 }
371387 a .deinit ();
372388
373- var b = StableArrayAligned (u8 , mem . page_size ).init (TEST_VIRTUAL_ALLOC_SIZE );
389+ var b = StableArrayAligned (u8 , heap . pageSize () ).init (TEST_VIRTUAL_ALLOC_SIZE );
374390 try b .appendSlice (&[_ ]u8 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 });
375- assert (b .calcTotalUsedBytes () == mem . page_size * 10 );
391+ assert (b .calcTotalUsedBytes () == a . getPageSize () * 10 );
376392 for (b .items , 0.. ) | v , i | {
377393 assert (v == i );
378394 }
379395 b .deinit ();
380396}
381397
382398test "shrinkAndFree" {
399+ const page_size = heap .pageSize ();
400+
383401 var a = StableArray (u8 ).init (TEST_VIRTUAL_ALLOC_SIZE );
384402 try a .appendSlice (&[_ ]u8 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 });
385403 a .shrinkAndFree (5 );
386-
387- assert (a .calcTotalUsedBytes () == mem .page_size );
404+ assert (a .calcTotalUsedBytes () == page_size ); // still using only a page
388405 assert (a .items .len == 5 );
389406 for (a .items , 0.. ) | v , i | {
390407 assert (v == i );
391408 }
392409 a .deinit ();
393410
394- var b = StableArrayAligned (u8 , mem . page_size ).init (TEST_VIRTUAL_ALLOC_SIZE );
411+ var b = StableArrayAligned (u8 , heap . pageSize () ).init (TEST_VIRTUAL_ALLOC_SIZE );
395412 try b .appendSlice (&[_ ]u8 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 });
396413 b .shrinkAndFree (5 );
397- assert (b .calcTotalUsedBytes () == mem . page_size * 5 );
414+ assert (b .calcTotalUsedBytes () == page_size * 5 ); // alignment of each item is 1 page
398415 assert (b .items .len == 5 );
399416 for (b .items , 0.. ) | v , i | {
400417 assert (v == i );
401418 }
402419 b .deinit ();
403420
404- var c = StableArrayAligned (u8 , 2048 ).init (TEST_VIRTUAL_ALLOC_SIZE );
421+ var c = StableArrayAligned (u8 , page_size / 2 ).init (TEST_VIRTUAL_ALLOC_SIZE );
422+ assert (c .getAlignment () == page_size / 2 );
405423 try c .appendSlice (&[_ ]u8 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 });
406424 c .shrinkAndFree (5 );
407- assert (c .calcTotalUsedBytes () == mem . page_size * 3 );
425+ assert (c .calcTotalUsedBytes () == page_size * 3 );
408426 assert (c .capacity == 6 );
409427 assert (c .items .len == 5 );
410428 for (c .items , 0.. ) | v , i | {
@@ -426,10 +444,10 @@ test "resize" {
426444}
427445
428446test "out of memory" {
429- var a = StableArrayAligned (u8 , mem . page_size ).init (TEST_VIRTUAL_ALLOC_SIZE );
447+ var a = StableArrayAligned (u8 , heap . pageSize () ).init (TEST_VIRTUAL_ALLOC_SIZE );
430448 defer a .deinit ();
431449
432- const max_capacity : usize = TEST_VIRTUAL_ALLOC_SIZE / mem . page_size ;
450+ const max_capacity : usize = TEST_VIRTUAL_ALLOC_SIZE / a . getPageSize () ;
433451 try a .appendNTimes (0xFF , max_capacity );
434452 for (a .items ) | v | {
435453 assert (v == 0xFF );
@@ -464,8 +482,8 @@ test "growing retains values" {
464482 var a = StableArray (u8 ).init (TEST_VIRTUAL_ALLOC_SIZE );
465483 defer a .deinit ();
466484
467- try a .resize (mem . page_size );
485+ try a .resize (a . getPageSize () );
468486 a .items [0 ] = 0xFF ;
469- try a .resize (mem . page_size * 2 );
487+ try a .resize (a . getPageSize () * 2 );
470488 assert (a .items [0 ] == 0xFF );
471489}
0 commit comments