{"id":28463835,"url":"https://github.com/kalamay/small-array-list","last_synced_at":"2025-06-14T08:38:09.796Z","repository":{"id":295684292,"uuid":"990803863","full_name":"kalamay/small-array-list","owner":"kalamay","description":"Memory efficient array list for zig that allows a small number of items to be stored allocation-free.","archived":false,"fork":false,"pushed_at":"2025-05-28T01:38:37.000Z","size":22,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-07T05:02:04.332Z","etag":null,"topics":["array","array-list","memory-efficient","zig","zig-package","ziglang"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kalamay.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-26T16:57:34.000Z","updated_at":"2025-05-27T14:44:32.000Z","dependencies_parsed_at":"2025-05-26T21:34:56.642Z","dependency_job_id":"460ba5bd-44b8-4f01-b823-6a84c5884743","html_url":"https://github.com/kalamay/small-array-list","commit_stats":null,"previous_names":["kalamay/small-array-list"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/kalamay/small-array-list","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kalamay%2Fsmall-array-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kalamay%2Fsmall-array-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kalamay%2Fsmall-array-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kalamay%2Fsmall-array-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kalamay","download_url":"https://codeload.github.com/kalamay/small-array-list/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kalamay%2Fsmall-array-list/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259789069,"owners_count":22911499,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["array","array-list","memory-efficient","zig","zig-package","ziglang"],"created_at":"2025-06-07T05:01:18.060Z","updated_at":"2025-06-14T08:38:09.790Z","avatar_url":"https://github.com/kalamay.png","language":"Zig","readme":"# small-array-list\n\nThis library provides a `SmallArrayList` type (and some variants), which is\noptimized for memory efficient storage of arrays that generally contain few\nitems. This works by sharing the memory internal storage space between either\na fixed size array, or an externally allocated slice, and switching between\nthe two as needed. See the [Small Capacity Limit](#small-capacity-limit) for\ndetails on this storage mechanism.\n\n```zig\n// We'll just use SmallArrayList for this example, but there are variants\n// that allow further parameterization.\nconst SmallArrayList = @import(\"small_array_list\").SmallArrayList;\n\n// Setup whichever allocator you'd like to use.\nvar arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);\ndefer arena.deinit();\nconst allocator = arena.allocator();\n\nvar list: SmallArrayList(i32) = .empty;\ndefer list.deinit(allocator);\n\n// Append works just like the std.array_list.ArrayListUnmanaged append.\ntry list.append(allocator, 1);\n\n// Nearly all of the standard library methods are available.\nvar many = try list.addManyAsArray(allocator, 2);\nmany[0] = 2;\nmany[1] = 3;\n\n// Unlike ArrayList, items cannot be accessed directly as a slice.\nfor (list.items()) |item| {\n    std.debug.print(\"item={}\\n\", .{item});\n}\n\n// You can see if the SmallArrayList is using an allocation or not.\nif (!list.hasAllocation()) {\n    std.debug.print(\"no allocations!\\n\", .{});\n}\n\n// Unlike ArrayList, len is a top-level field.\n// On 64-bit systems, this will be: len=3 capacity=4\nstd.debug.print(\"len={} capacity={}\\n\", .{ list.len, list.capacity });\n```\n\n\u003e [!IMPORTANT]\n\u003e Instances keep much of the interface in common with `std.array_list.ArrayListUnmanaged`\n\u003e with a few important differences:\n\u003e\n\u003e 1. To get the number of items in the list, use `list.len` instead of `list.items.len`.\n\u003e 1. To get the items of in the list, use `list.items()` instead of `list.items`.\n\n## Installing\n\nFirst, add the dependency to your `build.zig.zon`:\n\n```sh\nzig fetch --save git+https://github.com/kalamay/small-array-list#v0.2.0\n```\n\nNext add the dependecy to your `build.zig`:\n\n```zig\nconst small_array_list_mod = b.dependency(\"small_array_list\", .{\n    .target = target,\n    .optimize = optimize,\n}).module(\"small_array_list\");\n\nexe_mod.addImport(\"small_array_list\", small_array_list_mod);\n// or lib_mod, or any other module\n```\n\nNow you can import the library:\n\n```zig\nconst small_array_list = @import(\"small_array_list\");\n```\n\n### Using a Different Name\n\nIf you'd like to use a different name within your project, you can choose a\ndifferent import name for the module:\n\n```zig\nconst small_array_list_mod = b.dependency(\"small_array_list\", .{\n    .target = target,\n    .optimize = optimize,\n}).module(\"small_array_list\");\n\nexe_mod.addImport(\"array\", small_array_list_mod);\n```\n\nAnd then you'd be able to import it as `\"array\"`:\n\n```zig\nconst array = @import(\"array\");\n```\n\n## Why This Library\n\nThe standard library already includes `std.ArrayList`. In many cases, this is\nthe ideal choice. This is especially so if you know you are going to be storing\nmany items in the array. Alternatively, if you know you will only be storing\na limited number of items, using zig's array types (i.e. `[8]i32`) is sensible.\n\nHowever, there are cases where you are most likely going to be storing few\nitems, but need the flexibility to grow past the fixed limit that arrays\nprovide. That is, you will generally need the compactness of a zig array,\nbut you need the option to grow like a `std.ArrayList`.\n\nThis is where `SmallArrayList` comes in. In the low item count case, you can\nstay allocation-free, like a zig array. If item capacity needs to increase,\nhowever, you can still expand to support whatever size is needed. This can\nkeep overall memory usage down for low-item array lists. Additionally, when\nthe items are non-allocated, you gain a memory locality benefit as there is\nno pointer indirection.\n\n## Small Capacity Limit\n\nThe available small capacity limit is determined by the type stored and the\nnative machine word size. Because a zig slice requires two machine words for\nstoring it's `ptr` and `len`, this space can be used for direct item storage\ninstead until the small capacity is exceeded. For any given type `T`, the\nsmall array list can store up to `2*@sizeOf(usize) / @sizeOf(T)` items before\nrequiring any internal allocation.\n\nFor example on a 64-bit processor will print out `smallCapacity=4 sizeOf=24`:\n\n```zig\nconst List = SmallArrayList(i32);\nstd.debug.print(\"smallCapacity={} sizeOf={}\\n\", .{List.smallCapacity, @sizeOf(List)});\n```\n\nThe over size of a `SmallArrayList` is generally three machine words. This is\nachieved using a few trade-offs:\n\n1. The overlapped memory of the internal array and external slice is achieved\nusing a union. By ensuring this union is indiscriminate, the array list can\nmaximize storage efficiency. This union is then discriminated using the\n`capacity` field of the array list. Using `SmallArrayListSized`, you can set\na small capacity limit that exceeds the default size. This will cause the\noverall small array list size to grow.\n\n2. The `len` and `capacity` are each half of a `usize`. This does mean it will result\nin an `error.OutOfMemory` when trying to allocate a capacity greater than\nhalf the maximum of a `std.array_list.ArrayList`. However, this library is\noptimized for small array lists. If lists of such size are needed, the standard\nlibrary should be used.\n\n3. All `SmallArrayList` types are unmanaged, meaning they do not store the\n`std.mem.Allocator` internally, and each function that could possibly allocate\nor deallocate takes the allocator as a parameter. Note that the same allocator\ninstance must be used for each call into any single small array list.\n\n\u003e [!IMPORTANT]\n\u003e One important thing to keep in mind when using larger types is that there is\n\u003e a minimum small capacity of 1, so if the size of `T` exceeds two machine words,\n\u003e the overall size of the `SmallArrayList` will expand. This can still be\n\u003e beneficial, but it is something you'll want to consider.\n\n## Variants\n\nThe `SmallArrayList` uses the default alignment of `T` and a small capacity\ndetermined by how many items of `T` can be stored in two machine words. However,\nboth of these values may be overridden.\n\nIf you want to change the alignment, you can use either `SmallArrayListAligned`\nor `SmallArrayListAlignedSized`, passing in the desired alignment.\n\nChanging the small capacity can be done using either `SmallArrayListSized` or\n`SmallArrayListAlignedSized`. Using a small capacity larger than the default\nwill increase the overall size of the `SmallArrayList`, but it allows for\nstoring more items before allocating.\n\nFor example, on a 64-bit system:\n\n```zig\nconst std = @import(\"std\");\nconst expect = std.testing.expect;\n\ntest \"sizes\" {\n    const a = testing.allocator;\n\n    const List1 = SmallArrayList(i32);\n    const List2 = SmallArrayListSized(i32, 6);\n\n    // This holds true on a 64-bit system\n    try testing.expect(@sizeOf(List1) == 24);\n    try testing.expect(@sizeOf(List2) == 32);\n\n    var list1: List1 = .empty;\n    var list2: List2 = .empty;\n\n    defer list1.deinit(a);\n    defer list2.deinit(a); // don't strictly need to deinit list2\n\n    for (0..List2.smallCapacity) |i| {\n        try list1.append(a, @intCast(i));\n        try list2.append(a, @intCast(i));\n    }\n\n    try testing.expect(list1.hasAllocation());\n    try testing.expect(!list2.hasAllocation());\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkalamay%2Fsmall-array-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkalamay%2Fsmall-array-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkalamay%2Fsmall-array-list/lists"}