From efd772fe2843eaaa2cda54fe0fd966ac958d0470 Mon Sep 17 00:00:00 2001 From: pedropark99 Date: Sat, 24 Aug 2024 14:44:15 -0300 Subject: [PATCH 1/4] Add section --- Chapters/09-data-structures.qmd | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Chapters/09-data-structures.qmd b/Chapters/09-data-structures.qmd index 2e93e22..1b812b1 100644 --- a/Chapters/09-data-structures.qmd +++ b/Chapters/09-data-structures.qmd @@ -23,7 +23,7 @@ to talk about one of the key features of Zig in this chapter, which is `comptime how we can use it to create generics in Zig. -## Dynamic Arrays +## Dynamic Arrays {#sec-dynamic-array} In high level languages, arrays are usually dynamic. They easily grow in size when they have to, and you don't need to worry about it. @@ -834,6 +834,21 @@ a singly linked list or a doubly linked list, that might be very useful for you, +## Multi array structure + +Zig introduces a new data structure called `MultiArrayList()`. It is a different version of the dynamic array +that we have introduced at @sec-dynamic-array. + +```{zig} +const Person = struct { + name: []const u8, + age: u8, + height: f32, +}; +``` + + + From 21ce5ff4bcfb35ae606bc8a4daebad890518e2d4 Mon Sep 17 00:00:00 2001 From: pedropark99 Date: Sat, 24 Aug 2024 15:08:25 -0300 Subject: [PATCH 2/4] Add multi array example --- Chapters/09-data-structures.qmd | 19 +++++++++++++++ .../data-structures/multi-array-list.zig | 23 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 ZigExamples/data-structures/multi-array-list.zig diff --git a/Chapters/09-data-structures.qmd b/Chapters/09-data-structures.qmd index 1b812b1..5a58cef 100644 --- a/Chapters/09-data-structures.qmd +++ b/Chapters/09-data-structures.qmd @@ -840,11 +840,30 @@ Zig introduces a new data structure called `MultiArrayList()`. It is a different that we have introduced at @sec-dynamic-array. ```{zig} +const std = @import("std"); const Person = struct { name: []const u8, age: u8, height: f32, }; +const PersonArray = std.MultiArrayList(Person); + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = gpa.allocator(); + var people = PersonArray{}; + defer people.deinit(allocator); + + try people.append(allocator, .{ + .name = "Auguste", .age = 15, .height = 1.54 + }); + try people.append(allocator, .{ + .name = "Elena", .age = 26, .height = 1.65 + }); + try people.append(allocator, .{ + .name = "Michael", .age = 64, .height = 1.87 + }); +} ``` diff --git a/ZigExamples/data-structures/multi-array-list.zig b/ZigExamples/data-structures/multi-array-list.zig new file mode 100644 index 0000000..49d8b1e --- /dev/null +++ b/ZigExamples/data-structures/multi-array-list.zig @@ -0,0 +1,23 @@ +const std = @import("std"); +const Person = struct { + name: []const u8, + age: u8, + height: f32, +}; +const PersonArray = std.MultiArrayList(Person); + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = gpa.allocator(); + var people = PersonArray{}; + defer people.deinit(allocator); + + try people.append(allocator, .{ .name = "Auguste", .age = 15, .height = 1.54 }); + try people.append(allocator, .{ .name = "Elena", .age = 26, .height = 1.65 }); + try people.append(allocator, .{ .name = "Michael", .age = 64, .height = 1.87 }); + + var slice = people.slice(); + for (slice.items(.age)) |*age| { + age.* += 10; + } +} From cb67577a763dd32194fb34c896a8f2b18b497b79 Mon Sep 17 00:00:00 2001 From: pedropark99 Date: Sat, 24 Aug 2024 15:44:10 -0300 Subject: [PATCH 3/4] Add content --- Chapters/09-data-structures.qmd | 74 +++++++++++++++- Figures/Powerpoint/multi-array.odp | Bin 0 -> 36581 bytes Figures/multi-array.png | Bin 0 -> 24122 bytes .../data-structures/multi-array-list.zig | 8 ++ .../execute-results/html.json | 4 +- docs/Chapters/09-data-structures.html | 82 ++++++++++++++++-- docs/Figures/multi-array.png | Bin 0 -> 24122 bytes docs/search.json | 24 ++++- 8 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 Figures/Powerpoint/multi-array.odp create mode 100644 Figures/multi-array.png create mode 100644 docs/Figures/multi-array.png diff --git a/Chapters/09-data-structures.qmd b/Chapters/09-data-structures.qmd index 5a58cef..b5f2ea1 100644 --- a/Chapters/09-data-structures.qmd +++ b/Chapters/09-data-structures.qmd @@ -837,9 +837,18 @@ a singly linked list or a doubly linked list, that might be very useful for you, ## Multi array structure Zig introduces a new data structure called `MultiArrayList()`. It is a different version of the dynamic array -that we have introduced at @sec-dynamic-array. +that we have introduced at @sec-dynamic-array. The difference between this structure and the `ArrayList()` +that we know from @sec-dynamic-array, is that `MultiArrayList()` creates a separate dynamic array +for each field of the struct that you provide as input. + +Consider the following code example. We create a new custom struct called `Person`. This +struct contains three different data members, or, three different fields. As consequence, +when we provide this `Person` data type as input to `MultiArrayList()`, this +creates three different arrays. One array for each field in the struct. + ```{zig} +#| auto_main: false const std = @import("std"); const Person = struct { name: []const u8, @@ -866,9 +875,72 @@ pub fn main() !void { } ``` +In other words, instead of creating an array of "persons", the `MultiArrayList()` function +creates a "struct of arrays". Each data member of this struct is a different array that stores +the values of a specific field from the `Person` struct values that are added (or, appended) to the "struct of arrays". + +The @fig-multi-array exposed below presents a diagram that describes the `PersonArray` struct +that we have created in the previous code example. Notice that the values of the data members +present in each of the three `Person` values that we have appended into the `PersonArray` object +that we have instantiated, are scattered across three different internal arrays of the `PersonArray` object. +![A diagram of the `PersonArray` struct.](./../Figures/multi-array.png){#fig-multi-array} + +You can easily access each of these arrays separately, and iterate over the values of each array. +For that, you will need to call the `items()` method from the `PersonArray` object, and provide as input +to this method, the name of the field that you want to iterate over. +If you want to iterate through the `.age` array for example, then, you need to call `items(.age)` from +the `PersonArray` object, like in the example below: + +```{zig} +#| eval: false +for (people.items(.age)) |*age| { + try stdout.print("Age: {d}\n", .{age.*}); +} +``` + +``` +Age: 15 +Age: 26 +Age: 64 +``` +In the above example, we are iterating over the values of the `.age` array, or, +the internal array of the `PersonArray` object that contains the values of the `age` +data member from the `Person` values that were added to the multi array struct. + +In this example we are calling the `items()` method directly from the `PersonArray` +object. However, it is recommended on most situations to call this `items()` method +from a "slice object", which you can create from the `slice()` method. +The reason for this is that calling `items()` multiple times have better performance +if you use a slice object. + +In other words, if you are planning to access only one of the +internal arrays from your "multi array struct", it is fine to call `items()` directly +from the multi array object. But if you need to access many of the internal arrays +from your "multi array struct", then, you will likely need to call `items()` more +than once, and, in such circustance, is better to call `items()` through a slice object. +The example below demonstrates the use of such object: + +```{zig} +#| eval: false +var slice = people.slice(); +for (slice.items(.age)) |*age| { + age.* += 10; +} +for (slice.items(.name), slice.items(.age)) |*n,*a| { + try stdout.print( + "Name: {s}, Age: {d}\n", .{n.*, a.*} + ); +} +``` + +``` +Name: Auguste, Age: 25 +Name: Elena, Age: 36 +Name: Michael, Age: 74 +``` ## Conclusion diff --git a/Figures/Powerpoint/multi-array.odp b/Figures/Powerpoint/multi-array.odp new file mode 100644 index 0000000000000000000000000000000000000000..50a0772de1f568de68e5fa9d72ee00073ae212b6 GIT binary patch literal 36581 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 IfBgJ^05uL6IsgCw literal 0 HcmV?d00001 diff --git a/ZigExamples/data-structures/multi-array-list.zig b/ZigExamples/data-structures/multi-array-list.zig index 49d8b1e..cbb0677 100644 --- a/ZigExamples/data-structures/multi-array-list.zig +++ b/ZigExamples/data-structures/multi-array-list.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const stdout = std.io.getStdOut().writer(); const Person = struct { name: []const u8, age: u8, @@ -16,8 +17,15 @@ pub fn main() !void { try people.append(allocator, .{ .name = "Elena", .age = 26, .height = 1.65 }); try people.append(allocator, .{ .name = "Michael", .age = 64, .height = 1.87 }); + for (people.items(.age)) |*age| { + try stdout.print("Age: {d}\n", .{age.*}); + } + var slice = people.slice(); for (slice.items(.age)) |*age| { age.* += 10; } + for (slice.items(.name), slice.items(.age)) |*n, *a| { + try stdout.print("Name: {s}, Age: {d}\n", .{ n.*, a.* }); + } } diff --git a/_freeze/Chapters/09-data-structures/execute-results/html.json b/_freeze/Chapters/09-data-structures/execute-results/html.json index 561fced..187d6f0 100644 --- a/_freeze/Chapters/09-data-structures/execute-results/html.json +++ b/_freeze/Chapters/09-data-structures/execute-results/html.json @@ -1,8 +1,8 @@ { - "hash": "d055290c588660ee832d92d3eee7e8a4", + "hash": "a71a1416c129be13271ccb2b18c4bafb", "result": { "engine": "knitr", - "markdown": "---\nengine: knitr\nknitr: true\nsyntax-definition: \"../Assets/zig.xml\"\n---\n\n\n\n\n\n\n# Data Structures\n\nIn this chapter, we are going to discuss some Data Structures that are available from\nthe Zig Standard Library, specially `ArrayList` and also `HashMap`. I'm also want\nto talk about one of the key features of Zig in this chapter, which is `comptime`, and\nhow we can use it to create generics in Zig.\n\n\n## Dynamic Arrays\n\nIn high level languages, arrays are usually dynamic. They easily grow\nin size when they have to, and you don't need to worry about it.\nIn contrast, arrays in low level languages are usually static by default.\nThis is the reality of C, C++, Rust and also Zig. Static arrays were presented at\n@sec-arrays, but in this section, we are going to talk about dynamic arrays.\n\nDynamic arrays are simply arrays that can grow in size during the runtime\nof your program. Most low level languages offer some implementation of\na dynamic array in their standard library. C++ have `std::vector`, Rust have `Vec`,\nand Zig have `std.ArrayList`.\n\nThe `std.ArrayList` struct provides a contiguous and growable array for you.\nIt works like any other dinamic array, it allocates a contiguous block of memory, and when this block have no space left,\n`ArrayList` allocates another contiguous and bigger block of memory, copies the\nelements to this new location, and erases (or frees) the previous block of memory.\n\n\n### Capacity vs Length\n\nWhen we talk about dynamic arrays, we have two similar concepts that\nare very essential to how a dynamic array works behind the hood.\nThese concepts are *capacity* and *length*. In some contexts, specially\nin C++, *length* is also called of *size*.\n\nAlthough they look similar, these concepts represent different things\nin the context of dynamic arrays. *Capacity* is the number of items (or elements)\nthat your dynamic array can currently hold without the need to allocate more memory.\n\nIn contrast, the *length* refers to how many elements in the array\nare currently being used, or, in other words, how many elements in this array\nthat you assigned a value to. Every dynamic array works around\na block of allocated memory that represents an array with total capacity of $n$ elements,\nbut only a portion of these $n$ elements are being used most of the time. This portion\nof $n$ is the *length* of the array. So every time you append a new value\nto the array, you are incrementing it's *length* by one.\n\nThis means that a dynamic array usually works with an extra margin, or, an extra space\nwhich is currently empty, but it is waiting and ready to be used. This \"extra space\"\nis essentially the difference between *capacity* and *length*. *Capacity* represents\nthe total number of elements that the array can hold without the need to re-allocate\nor re-expand the array, while the *length* represents how much of this capacity\nis currently being used to hold/store values.\n\n@fig-capacity-length presents this idea visually. Notice that, at first,\nthe capacity of the array is greater than the length of the array.\nSo, the dynamic array have extra space that is currently empty, but it\nis ready to receive a value to be stored.\n\n![Difference between capacity and length in a dynamic array](./../Figures/dynamic-array.png){#fig-capacity-length}\n\nWe can also see at @fig-capacity-length that, when *length* and *capacity* are equal, it means that the array have no space left.\nWe reached the roof of our capacity, and because of that, if we want to store more values\nin this array, we need to expand it. We need to get a bigger space that can hold more values\nthat we currently have.\n\nA dynamic array works by expanding the underlying array, whenever the *length* becomes equal\nto the *capacity* of the array. It basically allocates a new contiguos block of memory that is bigger\nthan the previous one, then, it copies all values that are currently being stored to this new\nlocation (i.e. this new block of memory), then, it frees the previous block of\nmemory. At the end of this process, the new underlying array have a bigger *capacity*, and, therefore,\nthe *length* becomes once again smaller than the *capacity* of the array.\n\nThis is the cycle of an dynamic array. Notice that, throughout this cycle, the *capacity* is always\neither equal to or higher than the *length* of the array. If youh have an `ArrayList` object, let's suppose\nyou named it of `buffer`, you can check the current capacity of your array by accessing the `capacity`\nattribute of your `ArrayList` object, while the current *length* of it is available through the `items.len`\nattribute of your `ArrayList` object.\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\n// Check capacity\nbuffer.capacity;\n// Check length\nbuffer.items.len;\n```\n:::\n\n\n### Creating an `ArrayList` object\n\nIn order to use `ArrayList`, you must provide an allocator object to it.\nRemember, Zig does not have a default memory allocator. And as I described at @sec-allocators, all memory\nallocations must be done by allocator objects that you define, that\nyou have control over. In our example here, I'm going to use\na general purpose allocator, but you can use any other allocator\nof your preference.\n\nWhen you initialize an `ArrayList` object, you must provide the data type of the elements of\nthe array. In other words, this defines the type of data that this array (or container) will\nstore. Therefore, if I provide the `u8` type to it, then, I will create a dynamic\narray of `u8` values. However, if I provide a struct that I defined instead, like the struct `User`\nfrom @sec-structs-and-oop, then, a dynamic array of `User` values\nwill be created. In the example below, with the expression `ArrayList(u8)` we\nare creating a dynamic array of `u8` values.\n\nAfter you provide the data type of the elements of the array, you can initialize\nan `ArrayList` object by either using the `init()` or the `initCapacity()` method.\nThe former method receives only the allocator object\nas input, while the latter method receives both the allocator object and a capacity number as inputs.\nWith the latter method, you not only initialize the struct, but you\nalso set the starting capacity of the allocated array.\n\nUsing the `initCapacity()` method is the preferred way to initialize your dynamic array.\nBecause reallocations, or, in other words, the process of expanding the capacity of the array,\nis always a high cost operation. You should take any possible opportunity to avoid reallocations in\nyour array. If you know how much space your array needs to occupy at the beginning,\nyou should always use `initCapacity()` to create your dynamic array.\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n```\n:::\n\n\n\nIn the example above, the `buffer` object starts as an array of 100 elements. If this\n`buffer` object needs to create more space to accomodate more elements during the runtime of your program, the `ArrayList`\ninternals will perform the necessary actions for you automatically.\nAlso notice the `deinit()` method being used to destroy the `buffer` object at the\nend of the current scope, by freeing all the memory that was allocated for the dynamic\narray stored in this `buffer` object.\n\n\n### Adding new elements to the array\n\nNow that we created our dynamic array, we can start to use it. You can append (a.k.a \"add\")\nnew values to this array by using the `append()` method. This method works the same way\nas the `append()` method from a Python list, or, the `emplace_back()` method from `std::vector` of C++.\nYou provide a single value to this method, and the method appends this value to the array.\n\nYou can also use the `appendSlice()` method to append multiple values at once. You provide\na slice (slices were described at @sec-arrays) to this method, and the method adds all values present\nin this slice to your dynamic array.\n\n\n::: {.cell}\n\n```{.zig .cell-code}\ntry buffer.append('H');\ntry buffer.append('e');\ntry buffer.append('l');\ntry buffer.append('l');\ntry buffer.append('o');\ntry buffer.appendSlice(\" World!\");\n```\n:::\n\n\n### Removing elements from the array {#sec-dynamic-array-remove}\n\nYou can use the `pop()` method to \"pop\" or remove\nthe last element in the array. Is worth noting that this method\ndo not change the capacity of the array. It just deletes or erases\nthe last value stored in the array.\n\nAlso, this method returns as result the value that got deleted. That is, you can\nuse this method to both get the last value in the array, and also, remove\nit from the array. It is a \"get and remove value\" type of method.\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst exclamation_mark = buffer.pop();\n```\n:::\n\n\nNow, if you want to remove specific elements from specific positions\nof your array, you can use the `orderedRemove()` method from your\n`ArrayList` object. With this method, you can provide an index as input,\nthen, the method will delete the value that is at this index in the array.\nThis effectively reduces the *length* of the array everytime you execute\nan `orderedRemove()` operation.\n\nIn the example below, we first create an `ArrayList` object, and we fill it\nwith numbers. Then, we use `orderedRemove()` to remove the value at\nindex 3 in the array, two consecutive times.\n\nAlso, notice that we are assigning the result of `orderedRemove()` to the\nunderscore character. So we are discarding the result value of this method.\nAs the result value, the `orderedRemove()` method returns the value that\ngot deleted, in a similar style to the `pop()` method.\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n\nfor (0..10) |i| {\n const index: u8 = @intCast(i);\n try buffer.append(index);\n}\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\n_ = buffer.orderedRemove(3);\n_ = buffer.orderedRemove(3);\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\nstd.debug.print(\n \"{any}\\n\", .{buffer.items.len}\n);\n```\n:::\n\n\n```\n{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }\n{ 0, 1, 2, 5, 6, 7, 8, 9 }\n8\n```\n\nOne key characteristic about `orderedRemove()` is that it preserves the order\nof the values in the array. So, it deletes the value that you asked it to\nremove, but it also makes sure that the order of the values that remain in the array\nstay the same as before.\n\nNow, if you don't care about the order of the values, for example, maybe you want to treat\nyour dynamic array as a set of values, like the `std::unordered_set`\nstructure from C++, you can use the `swapRemove()` method instead. This method\nworks similarly to the `orderedRemove()` method. You give an index to this\nmethod, then, it deletes the value that is at this index in the array.\nBut this method does not preserve the original order of the values that remain\nin the array. As a result, `swapRemove()` is, in general, faster than `orderedRemove()`.\n\n\n### Inserting elements at specific indexes\n\nWhen you need to insert values in the middle of your array,\ninstead of just appending them to the end of the array, you need to use\nthe `insert()` and `insertSlice()` methods, instead of\nthe `append()` and `appendSlice()` methods.\n\nThese two methods work very similarly to `insert()` and `insert_range()`\nfrom the C++ vector class. You provide an index to these methods,\nand they insert the values that you provide at that index in the array.\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 10);\ndefer buffer.deinit();\n\ntry buffer.appendSlice(\"My Pedro\");\ntry buffer.insert(4, '3');\ntry buffer.insertSlice(2, \" name\");\nfor (buffer.items) |char| {\n try stdout.print(\"{c}\", .{char});\n}\n```\n:::\n\n\n```\nMy name P3edro\n```\n\n\n### Conclusion\n\nIf you feel the lack of some other method, I recommend\nyou to read the [official documentation for the `ArrayListAligned`](https://ziglang.org/documentation/master/std/#std.array_list.ArrayListAligned)[^zig-array2]\nstruct, which describes most of the methods available\nthrough the `ArrayList` object.\n\nYou will notice that there is a lot other methods in this page that\nI did not described here, and I recommend you to explore these methods,\nand understand how they work.\n\n[^zig-array2]: \n\n\n\n## Maps or HashTables\n\nSome professionals know this type of data structure by different terms, like \"map\", \"hashmap\" or \"associative arrays\". But most professionals\nknow this structure by the name *hashtable*.\nEvery programming language normally have some implementation of a hashtable in their\nstardard libraries. Python have `dict()`, C++ have `std::map` and `std::unordered_map`, Rust\nhave `HashMap`, Javascript have `Object()` and `Map()`,\nC# have `Hashtable()`, etc.\n\n\n\n### What is a hashtable?\n\nA hashtable is a data structure based on key-value pairs.\nYou provide a key and a value to this structure, then, the hashtable will store\nthe input value at a location that can be identified by the input\nkey that you provided.\nIt does that by using an underlying array and a hash function.\nThese two components are essential to how a hashtable works.\n\nUnder the hood, the hashtable contains an array. This array is where the values\nare stored, and the elements of this array are usually called of *buckets*.\nSo the values that you provide to the hashtable are stored inside buckets,\nand you access each bucket by using an index.\n\nWhen you provide a key to a hashtable, it passes this key to the\nhash function. This hash function uses some sort of hashing algorithm to transform\nthis key into an index. This index is actually an array index. It is a position\nin the underlying array of the hashtable.\nThis is how a key identifies a specific position (or location) inside the hashtable\nstructure.\n\nSo you provide a key to the hashtable, and this key identifies an specific location\ninside the hastable, then, the hashtable takes the input value that you provided,\nand stores this value in the location identified by the input key that you provided.\nYou could say that the key maps to the value stored in the hashtable. You find\nthe value, by using the key that identifies the location where the value is stored.\nThe @fig-hashtable presents this process visually.\n\n\n![A diagram of a Hashtable. Source: Wikipedia, the free encyclopedia.](./../Figures/hashtable.svg){#fig-hashtable}\n\n\nThe operation described in the previous paragraph is normally called an *insertion* operation.\nBecause you are inserting new values into the hashtable.\nBut there are other types of operations in hashtables such as *delete* and *lookup*.\nDelete is self describing, it is when you delete (or remove) a value from the hashtable.\nWhile lookup corresponds to when you retrieve (or look at) a value that is stored in\nthe hashtable, by using the key that identifies the location where this value is stored.\n\nSometimes, instead of storing the values directly, the underlying array of the hashtable might be an array of pointers,\ni.e. the buckets of the array stores pointers that points to the value,\nor also, may be an array of linked lists.\nThese cases are commom on hashtables that allows duplicate keys, or, in other words,\non hashtables that effectively handle \"collisions\" that may arise from the hash function.\n\nDuplicate keys, or this \"collision\" thing that I'm talking about, is when you have two different keys that points to the same location (i.e. to the same index)\nin the underlying array of the hashtable. This might happen depending on the characteristics of the hash function\nthat is being used in the hashtable. Some implementations of the hashtable will actively deal with collisions,\nmeaning that, they will handle this case in some way. For example, the hashtable\nmight transform all buckets into linked lists. Because with a liked list you can store\nmultiple values into a single bucket.\n\nThere are different techniques to handle collisions in hashtables, which I will not describe\nin this book, because it is not our main scope here. But you can find a good description of\nsome of the most commom techniques at the Wikipedia page of hashtables [@wikipedia_hashtables].\n\n\n### Hashtables in Zig {#sec-hashmap}\n\nThe Zig Standard Library provides different implementations of a hashtable,\nlike the struct `HashMap`. Each implementation have it's own cons and pros, which we will\ndiscuss later on, and all of them are available through the `std.hash_map` module.\n\nThe `HashMap` struct is a general-purpose hashtable,\nwhich have very fast operations (lookup, insertion, delete), and also,\nquite high load factors for low memory usage. You can create and provide a context object\nto the `HashMap` constructor. This context object allows you to tailor\nthe behaviour of the hashtable itself, because you can\nprovide a hash function implementation to be used by the hashtable\nthrough this context object.\n\nBut let's not worry about this context object now, because it is meant to be used\nby \"experts in the field of hashtables\". Since we are most likely not\nexperts in this field, we are going to take the easy way to create\na hashtable. Which is by using the `AutoHashMap()` function.\n\n\nThis `AutoHashMap()` function is essentially a \"create a hashtable object that uses the default settings\"\ntype of function. It chooses a context object, and, therefore, a hash function implementation,\nautomatically for you. This function receives two data types as input, the first data type is the data type of the keys\nthat will be used in this hashtable, while the second data type is the data type of that data that will be\nstored inside the hashtable, that is, the data type of the values to be stored.\n\nIn the example below, we are providing the data type `u32` in the first argument, and `u16` in the second argument of this\nfunction. It means that we are going to use `u32` values as keys in this hashtable, while `u16` values are the actual values\nthat are going to be stored into this hashtable.\nAt the end of this process, the `hash_table` object contains a `HashMap` object as output\nthat uses the default context, and the default load factor.\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n std.debug.print(\n \"Value at key 50050: {d}\\n\",\n .{hash_table.get(50050).?}\n );\n\n if (hash_table.remove(57709)) {\n std.debug.print(\n \"Value at key 57709 succesfully removed!\\n\",\n .{}\n );\n }\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n}\n```\n:::\n\n\n```\nN of values stored: 3\nValue at key 50050: 55\nValue at key 57709 succesfully removed!\nN of values stored: 2\n```\n\nYou can add/put new values into the hashtable by using the `put()` method. The first argument\nis the key to be used, and the second argument is the actual value that you want to store inside\nthe hashtable. In the example below, we first add the value 89 using the key 54321, next, we add\nthe value 55 using the key 50050, etc.\n\nNotice that we used the method `count()` to see how many values are currently stored in the\nhashtable. After that, we also used the `get()` method to access (or look) at the value stored in\nthe position identified by the key 500050. The output of this `get()` method is an optional value,\nand that is why we use the `?` method at the end to get access to the actual value.\n\nAlso notice that we can remove (or delete) values from a hashtables by using the `remove()` method.\nYou provide the key that identifies the value that you want to delete, then, the method will\ndelete this value and return a `true` value as output. This `true` value essentially tells us\nthat the method succesfully deleted the value.\n\nBut this delete operation might not be always successful. For example, you might provide the wrong\nkey to this method. I mean, maybe you provide\n(either intentionally or unintentionally) a key that points to an empty bucket,\ni.e. a bucket that still doesn't have a value in it.\nIn this case, the `remove()` method would return a `false` value.\n\n\n\n### Iterating through the hashtable\n\nIterating through the keys and values that are currently being stored in\nthe hashtable is a very commom need.\nYou can do that in Zig by using an iterator object that can iterate\nthrough the elements of you hashtable object.\n\nThis iterator object works like any other iterator object that you would\nfind in languages such as C++ and Rust. It is basically a pointer object\nthat points to some value in the container, and has a `next()` method\nthat you can use to navigate (or iterate) through the next values in the\ncontainer.\n\nYou can create such iterator object by using the `iterator()` method of the hashtable object.\nThis method returns an iterator object, from which you can use the `next()` method in conjunction\nwith a while loop to iterate through the elements of your hashtable. The `next()` method returns an optional\n`Entry` value, and therefore, you must unwrap this optional value to get the actual `Entry` value\nfrom which you can access the key and also the value identified by this key.\n\nWith this `Entry` value at hand, you can access the key of this current entry by using the `key_ptr`\nattribute and dereferencing the pointer that lives inside of it, while the value identified by this\nkey is accessed through the `value_ptr` attribute instead, which is also a pointer to be dereferenced.\nThe code example below demonstrates the use of these elements:\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n\n var it = hash_table.iterator();\n while (it.next()) |kv| {\n // Access the current key\n std.debug.print(\"Key: {d} | \", .{kv.key_ptr.*});\n // Access the current value\n std.debug.print(\"Value: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n```\nKey: 54321 | Value: 89\nKey: 50050 | Value: 55\nKey: 57709 | Value: 41\n```\n\n\nIf you want to iterate through only the values or the keys of your hashtable,\nyou can create a key iterator or a value iterator object. These are also iterator\nobjects, which have the same `next()` method that you can use to iterate through the\nsequence of values.\n\nKey iterators are created from the `keyIterator()` method of your\nhashtable object, while value iterators are created from the `valueIterator()` method.\nAll you have to do is to unwrap the value from the `next()` method and deference it\ndirectly to access the key or value that you iterating over.\nThe code example below demonstrates what would this be for a key iterator,\nbut you can replicate the same logic to a value iterator.\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar kit = hash_table.keyIterator();\nwhile (kit.next()) |key| {\n std.debug.print(\"Key: {d}\\n\", .{key.*});\n}\n```\n:::\n\n\n```\nKey: 54321\nKey: 50050\nKey: 57709\n```\n\n\n### The `ArrayHashMap` hashtable {#sec-array-map}\n\nIf you need to iterate through the elements of your hashtable constantly,\nyou might want to use the `ArrayHashMap` struct for your specific case,\ninstead of going with the usual and general-purpose `HashMap` struct.\n\nThe `ArrayHashMap` struct creates a hashtable that is faster to iterate over.\nThat is why this specific type of hashtable might be valuable to you.\nSome other properties of a `ArrayHashMap` hashtable are:\n\n- the order of insertion is preserved. So the order of the values you find while iterating through this hashtable\nare actually the order in which these values were inserted in the hashtable.\n\n- the key-value pairs are stored sequentially, one after another.\n\n\nYou can create an `ArrayHashMap` object by using, once again, a helper function that\nchooses automatically for you a hash function implementation. This is the\n`AutoArrayHashMap()` function, which works very similarly to the `AutoHashMap()`\nfunction that we presented at @sec-hashmap.\n\nYou provide two data types to this function. The data type of the keys that will be\nused in this hashtable, and the data type of the values that will be stored in\nthis hashtable.\n\nAn `ArrayHashMap` object have essentially the exact same methods from the `HashMap` struct.\nSo you can insert new values into the hashtable by using the `put()` method, you can look (or get)\na value from the hashtable by using the `get()` method. But the `remove()` method is not available\nin this specific type of hashtable.\n\nIn order to delete values from the hashtable, you would use the same methods that you find in\nan `ArrayList` object, i.e. a dynamic array. I presented these methods at @sec-dynamic-array-remove,\nwhich are the `swapRemove()` and `orderedRemove()` methods. These methods have here the same meaning, or,\nthe same effect that they have in an `ArrayList` object.\n\nThis means that, with `swapRemove()` you remove the value from the hashtable, but you do not preserve\nthe order in which the values were inserted into the structure. While `orderedRemove()` is capable\nof retaining the insertion order of these values.\n\nBut instead of providing an index as input to `swapRemove()` or `orderedRemove()`, like I described\nat @sec-dynamic-array-remove, these methods here in an `ArrayHashMap` take a key as input, like\nthe `remove()` method from a `HashMap` object. If you want to provide an index as input, instead\nof a key, you should use the `swapRemoveAt()` and `orderedRemoveAt()` methods.\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar hash_table = AutoArrayHashMap(u32, u16)\n .init(allocator);\ndefer hash_table.deinit();\n```\n:::\n\n\n\n\n### The `StringHashMap` hashtable {#sec-string-hash-map}\n\nOne thing that you will notice in the other two types of hashtables that I\npresented in the last sections, is that neither of them accepts a slice data type\nin their keys.\nWhat this means is that you cannot use a slice value to represent a key in\nthese types of hashtable.\n\nThe most obvious consequence of this, is that you cannot use strings as keys\nin these hashtables. But is extremely commom to use string values as keys\nin hashtables.\n\nTake this very simple Javascript code snippet as an example. We are creating\na simple hashtable object named `people`. Then, we add a new entry to this\nhashtable, which is identified by the string `'Pedro'`. This string is the\nkey in this case, while the object containing different personal information such as\nage, height and city, is the value to be stored in the hashtable.\n\n```js\nvar people = new Object();\npeople['Pedro'] = {\n 'age': 25,\n 'height': 1.67,\n 'city': 'Belo Horizonte'\n};\n```\n\nThis pattern of using strings as keys is very commom in\nall sorts of situations. That is why the Zig Standard Library offers a\nspecific type of hashtable for this purpose, which is created through the `StringHashMap()` function.\nThis function creates a hashtable that uses strings as keys. The only input of this\nfunction is the data type of the values that will be stored into this hashtable.\n\nIn the example below, I'm creating a hashtable to store the ages of different people.\nThe keys to be used in this hashtable are the names of each person, while the value stored in the\nhashtable is the age of the person identified by the key.\n\nThat is why I provide the `u8` data type (which is the data type used by the age values) as input to this `StringHashMap()` function.\nAs the result, it creates a hashtable that uses string values as keys, and, that stores\n`u8` values in it. Notice that an allocator object is provided at the `init()` method of the\nresulting object from the `StringHashMap()` function.\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var ages = std.StringHashMap(u8).init(allocator);\n defer ages.deinit();\n\n try ages.put(\"Pedro\", 25);\n try ages.put(\"Matheus\", 21);\n try ages.put(\"Abgail\", 42);\n\n var it = ages.iterator();\n while (it.next()) |kv| {\n std.debug.print(\"Key: {s} | \", .{kv.key_ptr.*});\n std.debug.print(\"Age: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n```\nKey: Pedro | Age: 25\nKey: Abgail | Age: 42\nKey: Matheus | Age: 21\n```\n\n\n### The `StringArrayHashMap` hashtable\n\nThe Zig Standard Library also provides a type of hashtable that mix the cons and pros of the\ntypes of hashtables that were presented on the previous two sections. That is, a hashtable\nthat uses strings as keys, but also have the advantages from the `ArrayHashMap` struct.\nIn other words, you can have a hashtable that is fast to iterate over,\nthat preserves insertion order, and also, that uses strings as keys.\n\nYou can create such type of hashtable by using the `StringArrayHashMap()` function.\nThis function accepts a data type as input, which is the data type of the values that are\ngoing to be stored inside this hashtable, in the same style as the function presented\nat @sec-string-hash-map.\n\nYou can insert new values into this hashtable by using the same `put()` method that\nI presented at @sec-string-hash-map. And you can also get values from the hashtable\nby using the same `get()` method that I exposed on previous sections.\nLike it's `ArrayHashMap` brother, to delete values from this specific type of hashtable,\nwe also use the `orderedRemove()` and `swapRemove()` methods, with the same effects that\nI described at @sec-array-map.\n\nIf we take the code example that was exposed at @sec-string-hash-map, we can\nachieve the exact same result with `StringArrayHashMap()`. All we have to do\nis to change the use of `StringHashMap()` to `StringArrayHashMap()` at the\nfifth line in this code example. It would change to this:\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar ages = std.StringArrayHashMap(u8).init(allocator);\n```\n:::\n\n\n\n\n## Linked lists\n\nThe Zig Standard Library provides implementation for both single and doubly linked lists.\nA linked list is a linear data structure that looks like a chain, or, a rope.\nThe main advantage of this data structure is that you normally have fast\ninsertion and deletion operations. But, as a disadvantage, iterating through\nthis data structure is usually not so fast as iterating through an array.\n\nThe idea behind a linked list is basically build a structure that concists of a series of nodes\nconnected to each other by pointers. This means that linked lists are usually not contiguos\nin memory, because each node might be south in memory, but the next node might be north\nin memory, then the next node might be left in memory, anyway, you get it, they can be anywhere.\n\nAt @fig-linked-list we can see a diagram of a singly linked list. Notice that we begin with\na first node. This first node is usually called \"the head of the linked list\". Then, from this\nfirst node we uncover the remaining nodes in the structure, by following the locations pointed\nby the pointers.\n\nEvery node have two things in it. It have the value that is stored in the current node\n, and also have a pointer. This pointer points to the next node in the list. If this pointer\nis null, then, it means that we reached the end of our linked list.\n\n![A diagram of a singly linked list.](./../Figures/linked-list.png){#fig-linked-list}\n\n\nAt @fig-linked-list2 we can see a diagram of a doubly linked list. The only thing that really\nchanges is that every node in the linked list have both a pointer to the previous node,\nand, a pointer to the next node. So every node have now two pointers in it. These are\nusually called the `prev` (for \"previous\") and `next` (for \"next\") pointers of the node.\n\nIn the singly linked list example, we had only one single pointer in each node, and this singular\npointer was always pointing to the next node in the sequence. In other words, singly linked lists\nnormally have only the `next` pointer in them.\n\n![A diagram of a doubly linked list.](./../Figures/doubly-linked-list.png){#fig-linked-list2}\n\n\n\nLinked lists are available in Zig through the functions `SinglyLinkedList()` and\n`DoublyLinkedList()`, for \"singly linked lists\" and \"doubly linked lists\", respectively. These functions are\nactually generic functions, which we are going to talk more about at @sec-generic-fun.\n\nFor now, just understand that, in order to create a linked list object,\nwe begin by providing a data type to these functions. This data type defines\nthe type of data that this linked list will store. In the example below,\nwe are creating a singly linked list capable of storing `u32` values.\nSo each node in this linked list will store a `u32` value.\n\nBoth the `SinglyLinkedList()` and `DoublyLinkedList()` functions returns a type, i.e. a struct definition, as result. This means that\nthe object `Lu32` is actually a type definition, or a struct definition. It defines\nthe type \"singly linked list of `u32` values\".\n\nSo now that we have the definition of the struct, we have to instantiate a `Lu32` object.\nWe normally instantiate struct objects in Zig by using an `init()` method.\nBut in this case, we are instantiating the struct directly, by using an empty\n`struct` literal, in the expression `Lu32{}`.\n\nIn this example, we first create multiple node objects, and after we create them,\nwe start to insert and connect these nodes to build the linked list, using the\n`prepend()` and `insertAfter()` methods. Notice that the `prepend()` method\nis a method from the linked list object, while the `insertAfter()` is a method\npresent in the node objects.\n\nIn essence, the `prepend()` method inserts a node at the beginning of the linked\nlist. In other words, the node that you provide to this method, becomes the new\n\"head node\" of the linked list. It becomes the first node in the list (see @fig-linked-list).\n\nOn the other side, the `insertAfter()` method is used to basically connect two nodes together.\nWhen you provide a node to this method, it creates a pointer to this input node,\nand stores this pointer in the current node, from which the method was called from.\nIn other words, this method creates the pointer that connects these two nodes together\nand stores it in the `next` attribute of the current node.\n\nSince doubly linked list have both a `next` and a `prev` pointers in each node,\nreferring to the next and previous nodes in the sequence, respectively,\nas I described at @fig-linked-list2, a node object created from\na `DoublyLinkedList()` object would have both a\n`insertBefore()` (for `prev`) and a `insertAfter()` (for `next`) methods\navailable.\n\nThis means that, if we used a doubly linked list, we could use the `insertBefore()` method\nto store the pointer to the input node in the `prev` attribute. This would put the input\nnode as the \"previous node\", or, the node before the current node. The `insertAfter()` method\nhave \"after\" in it's name to indicate that this method puts the pointer created to the input\nnode in the `next` attribute of the current node, and as the result, the input node becomes\nthe \"next node\" of the current node.\n\nSince we are using a singly linked list in this example, we have only the `insertAfter()` method\navailable in the node objects that we create from our `Lu32` type.\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst SinglyLinkedList = std.SinglyLinkedList;\nconst Lu32 = SinglyLinkedList(u32);\n\npub fn main() !void {\n var list = Lu32{};\n var one = Lu32.Node{ .data = 1 };\n var two = Lu32.Node{ .data = 2 };\n var three = Lu32.Node{ .data = 3 };\n var four = Lu32.Node{ .data = 4 };\n var five = Lu32.Node{ .data = 5 };\n\n list.prepend(&two); // {2}\n two.insertAfter(&five); // {2, 5}\n list.prepend(&one); // {1, 2, 5}\n two.insertAfter(&three); // {1, 2, 3, 5}\n three.insertAfter(&four); // {1, 2, 3, 4, 5}\n}\n```\n:::\n\n\n\nThere are other methods available from the linked list object, depending if this object is\na singly linked list or a doubly linked list, that might be very useful for you, like:\n\n- `remove()` to remove a specific node from the linked list.\n- `popFirst()` to remove the first node from the linked list.\n- if singly linked list, `len()` to count how many nodes there is in the linked list.\n- if doubly linked list, checkout the `len` attribute to see how many nodes there is in the linked list.\n- if singly linked list, `popFirst()` to remove the first node from the linked list.\n- if doubly linked list, `pop()` and `popFirst()` to remove the last and first nodes from the linked list, respectively.\n- if doubly linked list, `append()` to add a new node to end of the linked list (i.e. inverse of `prepend()`).\n\n\n\n\n\n\n## Conclusion\n\nThere are many other data structures that I did not presented here.\nBut you can check them out at the offical Zig Standard Library documentation page.\nActually, when you get into the [homepage of the documentation](https://ziglang.org/documentation/master/std/#)[^home], the first thing\nthat appears to you in this page, is a list of types and data structures.\n\n\nIn this section you can see a list of the many different data structures available in\nthe Zig Standard Library. There are some very specific structures in this list, like a\n[`BoundedArray` struct](https://ziglang.org/documentation/master/std/#std.bounded_array.BoundedArray)[^bounded]\n, but there is also some more general structures, such as a\n[`PriorityQueue` struct](https://ziglang.org/documentation/master/std/#std.priority_queue.PriorityQueue)[^priority].\n\n\n[^home]: \n[^priority]: .\n[^bounded]: \n\n\n\n\n\n\n", + "markdown": "---\nengine: knitr\nknitr: true\nsyntax-definition: \"../Assets/zig.xml\"\n---\n\n\n\n\n\n\n\n\n\n# Data Structures\n\nIn this chapter, we are going to discuss some Data Structures that are available from\nthe Zig Standard Library, specially `ArrayList` and also `HashMap`. I'm also want\nto talk about one of the key features of Zig in this chapter, which is `comptime`, and\nhow we can use it to create generics in Zig.\n\n\n## Dynamic Arrays {#sec-dynamic-array}\n\nIn high level languages, arrays are usually dynamic. They easily grow\nin size when they have to, and you don't need to worry about it.\nIn contrast, arrays in low level languages are usually static by default.\nThis is the reality of C, C++, Rust and also Zig. Static arrays were presented at\n@sec-arrays, but in this section, we are going to talk about dynamic arrays.\n\nDynamic arrays are simply arrays that can grow in size during the runtime\nof your program. Most low level languages offer some implementation of\na dynamic array in their standard library. C++ have `std::vector`, Rust have `Vec`,\nand Zig have `std.ArrayList`.\n\nThe `std.ArrayList` struct provides a contiguous and growable array for you.\nIt works like any other dinamic array, it allocates a contiguous block of memory, and when this block have no space left,\n`ArrayList` allocates another contiguous and bigger block of memory, copies the\nelements to this new location, and erases (or frees) the previous block of memory.\n\n\n### Capacity vs Length\n\nWhen we talk about dynamic arrays, we have two similar concepts that\nare very essential to how a dynamic array works behind the hood.\nThese concepts are *capacity* and *length*. In some contexts, specially\nin C++, *length* is also called of *size*.\n\nAlthough they look similar, these concepts represent different things\nin the context of dynamic arrays. *Capacity* is the number of items (or elements)\nthat your dynamic array can currently hold without the need to allocate more memory.\n\nIn contrast, the *length* refers to how many elements in the array\nare currently being used, or, in other words, how many elements in this array\nthat you assigned a value to. Every dynamic array works around\na block of allocated memory that represents an array with total capacity of $n$ elements,\nbut only a portion of these $n$ elements are being used most of the time. This portion\nof $n$ is the *length* of the array. So every time you append a new value\nto the array, you are incrementing it's *length* by one.\n\nThis means that a dynamic array usually works with an extra margin, or, an extra space\nwhich is currently empty, but it is waiting and ready to be used. This \"extra space\"\nis essentially the difference between *capacity* and *length*. *Capacity* represents\nthe total number of elements that the array can hold without the need to re-allocate\nor re-expand the array, while the *length* represents how much of this capacity\nis currently being used to hold/store values.\n\n@fig-capacity-length presents this idea visually. Notice that, at first,\nthe capacity of the array is greater than the length of the array.\nSo, the dynamic array have extra space that is currently empty, but it\nis ready to receive a value to be stored.\n\n![Difference between capacity and length in a dynamic array](./../Figures/dynamic-array.png){#fig-capacity-length}\n\nWe can also see at @fig-capacity-length that, when *length* and *capacity* are equal, it means that the array have no space left.\nWe reached the roof of our capacity, and because of that, if we want to store more values\nin this array, we need to expand it. We need to get a bigger space that can hold more values\nthat we currently have.\n\nA dynamic array works by expanding the underlying array, whenever the *length* becomes equal\nto the *capacity* of the array. It basically allocates a new contiguos block of memory that is bigger\nthan the previous one, then, it copies all values that are currently being stored to this new\nlocation (i.e. this new block of memory), then, it frees the previous block of\nmemory. At the end of this process, the new underlying array have a bigger *capacity*, and, therefore,\nthe *length* becomes once again smaller than the *capacity* of the array.\n\nThis is the cycle of an dynamic array. Notice that, throughout this cycle, the *capacity* is always\neither equal to or higher than the *length* of the array. If youh have an `ArrayList` object, let's suppose\nyou named it of `buffer`, you can check the current capacity of your array by accessing the `capacity`\nattribute of your `ArrayList` object, while the current *length* of it is available through the `items.len`\nattribute of your `ArrayList` object.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\n// Check capacity\nbuffer.capacity;\n// Check length\nbuffer.items.len;\n```\n:::\n\n\n\n\n\n### Creating an `ArrayList` object\n\nIn order to use `ArrayList`, you must provide an allocator object to it.\nRemember, Zig does not have a default memory allocator. And as I described at @sec-allocators, all memory\nallocations must be done by allocator objects that you define, that\nyou have control over. In our example here, I'm going to use\na general purpose allocator, but you can use any other allocator\nof your preference.\n\nWhen you initialize an `ArrayList` object, you must provide the data type of the elements of\nthe array. In other words, this defines the type of data that this array (or container) will\nstore. Therefore, if I provide the `u8` type to it, then, I will create a dynamic\narray of `u8` values. However, if I provide a struct that I defined instead, like the struct `User`\nfrom @sec-structs-and-oop, then, a dynamic array of `User` values\nwill be created. In the example below, with the expression `ArrayList(u8)` we\nare creating a dynamic array of `u8` values.\n\nAfter you provide the data type of the elements of the array, you can initialize\nan `ArrayList` object by either using the `init()` or the `initCapacity()` method.\nThe former method receives only the allocator object\nas input, while the latter method receives both the allocator object and a capacity number as inputs.\nWith the latter method, you not only initialize the struct, but you\nalso set the starting capacity of the allocated array.\n\nUsing the `initCapacity()` method is the preferred way to initialize your dynamic array.\nBecause reallocations, or, in other words, the process of expanding the capacity of the array,\nis always a high cost operation. You should take any possible opportunity to avoid reallocations in\nyour array. If you know how much space your array needs to occupy at the beginning,\nyou should always use `initCapacity()` to create your dynamic array.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n```\n:::\n\n\n\n\n\n\nIn the example above, the `buffer` object starts as an array of 100 elements. If this\n`buffer` object needs to create more space to accomodate more elements during the runtime of your program, the `ArrayList`\ninternals will perform the necessary actions for you automatically.\nAlso notice the `deinit()` method being used to destroy the `buffer` object at the\nend of the current scope, by freeing all the memory that was allocated for the dynamic\narray stored in this `buffer` object.\n\n\n### Adding new elements to the array\n\nNow that we created our dynamic array, we can start to use it. You can append (a.k.a \"add\")\nnew values to this array by using the `append()` method. This method works the same way\nas the `append()` method from a Python list, or, the `emplace_back()` method from `std::vector` of C++.\nYou provide a single value to this method, and the method appends this value to the array.\n\nYou can also use the `appendSlice()` method to append multiple values at once. You provide\na slice (slices were described at @sec-arrays) to this method, and the method adds all values present\nin this slice to your dynamic array.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\ntry buffer.append('H');\ntry buffer.append('e');\ntry buffer.append('l');\ntry buffer.append('l');\ntry buffer.append('o');\ntry buffer.appendSlice(\" World!\");\n```\n:::\n\n\n\n\n\n### Removing elements from the array {#sec-dynamic-array-remove}\n\nYou can use the `pop()` method to \"pop\" or remove\nthe last element in the array. Is worth noting that this method\ndo not change the capacity of the array. It just deletes or erases\nthe last value stored in the array.\n\nAlso, this method returns as result the value that got deleted. That is, you can\nuse this method to both get the last value in the array, and also, remove\nit from the array. It is a \"get and remove value\" type of method.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst exclamation_mark = buffer.pop();\n```\n:::\n\n\n\n\n\nNow, if you want to remove specific elements from specific positions\nof your array, you can use the `orderedRemove()` method from your\n`ArrayList` object. With this method, you can provide an index as input,\nthen, the method will delete the value that is at this index in the array.\nThis effectively reduces the *length* of the array everytime you execute\nan `orderedRemove()` operation.\n\nIn the example below, we first create an `ArrayList` object, and we fill it\nwith numbers. Then, we use `orderedRemove()` to remove the value at\nindex 3 in the array, two consecutive times.\n\nAlso, notice that we are assigning the result of `orderedRemove()` to the\nunderscore character. So we are discarding the result value of this method.\nAs the result value, the `orderedRemove()` method returns the value that\ngot deleted, in a similar style to the `pop()` method.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n\nfor (0..10) |i| {\n const index: u8 = @intCast(i);\n try buffer.append(index);\n}\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\n_ = buffer.orderedRemove(3);\n_ = buffer.orderedRemove(3);\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\nstd.debug.print(\n \"{any}\\n\", .{buffer.items.len}\n);\n```\n:::\n\n\n\n\n\n```\n{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }\n{ 0, 1, 2, 5, 6, 7, 8, 9 }\n8\n```\n\nOne key characteristic about `orderedRemove()` is that it preserves the order\nof the values in the array. So, it deletes the value that you asked it to\nremove, but it also makes sure that the order of the values that remain in the array\nstay the same as before.\n\nNow, if you don't care about the order of the values, for example, maybe you want to treat\nyour dynamic array as a set of values, like the `std::unordered_set`\nstructure from C++, you can use the `swapRemove()` method instead. This method\nworks similarly to the `orderedRemove()` method. You give an index to this\nmethod, then, it deletes the value that is at this index in the array.\nBut this method does not preserve the original order of the values that remain\nin the array. As a result, `swapRemove()` is, in general, faster than `orderedRemove()`.\n\n\n### Inserting elements at specific indexes\n\nWhen you need to insert values in the middle of your array,\ninstead of just appending them to the end of the array, you need to use\nthe `insert()` and `insertSlice()` methods, instead of\nthe `append()` and `appendSlice()` methods.\n\nThese two methods work very similarly to `insert()` and `insert_range()`\nfrom the C++ vector class. You provide an index to these methods,\nand they insert the values that you provide at that index in the array.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 10);\ndefer buffer.deinit();\n\ntry buffer.appendSlice(\"My Pedro\");\ntry buffer.insert(4, '3');\ntry buffer.insertSlice(2, \" name\");\nfor (buffer.items) |char| {\n try stdout.print(\"{c}\", .{char});\n}\n```\n:::\n\n\n\n\n\n```\nMy name P3edro\n```\n\n\n### Conclusion\n\nIf you feel the lack of some other method, I recommend\nyou to read the [official documentation for the `ArrayListAligned`](https://ziglang.org/documentation/master/std/#std.array_list.ArrayListAligned)[^zig-array2]\nstruct, which describes most of the methods available\nthrough the `ArrayList` object.\n\nYou will notice that there is a lot other methods in this page that\nI did not described here, and I recommend you to explore these methods,\nand understand how they work.\n\n[^zig-array2]: \n\n\n\n## Maps or HashTables\n\nSome professionals know this type of data structure by different terms, like \"map\", \"hashmap\" or \"associative arrays\". But most professionals\nknow this structure by the name *hashtable*.\nEvery programming language normally have some implementation of a hashtable in their\nstardard libraries. Python have `dict()`, C++ have `std::map` and `std::unordered_map`, Rust\nhave `HashMap`, Javascript have `Object()` and `Map()`,\nC# have `Hashtable()`, etc.\n\n\n\n### What is a hashtable?\n\nA hashtable is a data structure based on key-value pairs.\nYou provide a key and a value to this structure, then, the hashtable will store\nthe input value at a location that can be identified by the input\nkey that you provided.\nIt does that by using an underlying array and a hash function.\nThese two components are essential to how a hashtable works.\n\nUnder the hood, the hashtable contains an array. This array is where the values\nare stored, and the elements of this array are usually called of *buckets*.\nSo the values that you provide to the hashtable are stored inside buckets,\nand you access each bucket by using an index.\n\nWhen you provide a key to a hashtable, it passes this key to the\nhash function. This hash function uses some sort of hashing algorithm to transform\nthis key into an index. This index is actually an array index. It is a position\nin the underlying array of the hashtable.\nThis is how a key identifies a specific position (or location) inside the hashtable\nstructure.\n\nSo you provide a key to the hashtable, and this key identifies an specific location\ninside the hastable, then, the hashtable takes the input value that you provided,\nand stores this value in the location identified by the input key that you provided.\nYou could say that the key maps to the value stored in the hashtable. You find\nthe value, by using the key that identifies the location where the value is stored.\nThe @fig-hashtable presents this process visually.\n\n\n![A diagram of a Hashtable. Source: Wikipedia, the free encyclopedia.](./../Figures/hashtable.svg){#fig-hashtable}\n\n\nThe operation described in the previous paragraph is normally called an *insertion* operation.\nBecause you are inserting new values into the hashtable.\nBut there are other types of operations in hashtables such as *delete* and *lookup*.\nDelete is self describing, it is when you delete (or remove) a value from the hashtable.\nWhile lookup corresponds to when you retrieve (or look at) a value that is stored in\nthe hashtable, by using the key that identifies the location where this value is stored.\n\nSometimes, instead of storing the values directly, the underlying array of the hashtable might be an array of pointers,\ni.e. the buckets of the array stores pointers that points to the value,\nor also, may be an array of linked lists.\nThese cases are commom on hashtables that allows duplicate keys, or, in other words,\non hashtables that effectively handle \"collisions\" that may arise from the hash function.\n\nDuplicate keys, or this \"collision\" thing that I'm talking about, is when you have two different keys that points to the same location (i.e. to the same index)\nin the underlying array of the hashtable. This might happen depending on the characteristics of the hash function\nthat is being used in the hashtable. Some implementations of the hashtable will actively deal with collisions,\nmeaning that, they will handle this case in some way. For example, the hashtable\nmight transform all buckets into linked lists. Because with a liked list you can store\nmultiple values into a single bucket.\n\nThere are different techniques to handle collisions in hashtables, which I will not describe\nin this book, because it is not our main scope here. But you can find a good description of\nsome of the most commom techniques at the Wikipedia page of hashtables [@wikipedia_hashtables].\n\n\n### Hashtables in Zig {#sec-hashmap}\n\nThe Zig Standard Library provides different implementations of a hashtable,\nlike the struct `HashMap`. Each implementation have it's own cons and pros, which we will\ndiscuss later on, and all of them are available through the `std.hash_map` module.\n\nThe `HashMap` struct is a general-purpose hashtable,\nwhich have very fast operations (lookup, insertion, delete), and also,\nquite high load factors for low memory usage. You can create and provide a context object\nto the `HashMap` constructor. This context object allows you to tailor\nthe behaviour of the hashtable itself, because you can\nprovide a hash function implementation to be used by the hashtable\nthrough this context object.\n\nBut let's not worry about this context object now, because it is meant to be used\nby \"experts in the field of hashtables\". Since we are most likely not\nexperts in this field, we are going to take the easy way to create\na hashtable. Which is by using the `AutoHashMap()` function.\n\n\nThis `AutoHashMap()` function is essentially a \"create a hashtable object that uses the default settings\"\ntype of function. It chooses a context object, and, therefore, a hash function implementation,\nautomatically for you. This function receives two data types as input, the first data type is the data type of the keys\nthat will be used in this hashtable, while the second data type is the data type of that data that will be\nstored inside the hashtable, that is, the data type of the values to be stored.\n\nIn the example below, we are providing the data type `u32` in the first argument, and `u16` in the second argument of this\nfunction. It means that we are going to use `u32` values as keys in this hashtable, while `u16` values are the actual values\nthat are going to be stored into this hashtable.\nAt the end of this process, the `hash_table` object contains a `HashMap` object as output\nthat uses the default context, and the default load factor.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n std.debug.print(\n \"Value at key 50050: {d}\\n\",\n .{hash_table.get(50050).?}\n );\n\n if (hash_table.remove(57709)) {\n std.debug.print(\n \"Value at key 57709 succesfully removed!\\n\",\n .{}\n );\n }\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n}\n```\n:::\n\n\n\n\n\n```\nN of values stored: 3\nValue at key 50050: 55\nValue at key 57709 succesfully removed!\nN of values stored: 2\n```\n\nYou can add/put new values into the hashtable by using the `put()` method. The first argument\nis the key to be used, and the second argument is the actual value that you want to store inside\nthe hashtable. In the example below, we first add the value 89 using the key 54321, next, we add\nthe value 55 using the key 50050, etc.\n\nNotice that we used the method `count()` to see how many values are currently stored in the\nhashtable. After that, we also used the `get()` method to access (or look) at the value stored in\nthe position identified by the key 500050. The output of this `get()` method is an optional value,\nand that is why we use the `?` method at the end to get access to the actual value.\n\nAlso notice that we can remove (or delete) values from a hashtables by using the `remove()` method.\nYou provide the key that identifies the value that you want to delete, then, the method will\ndelete this value and return a `true` value as output. This `true` value essentially tells us\nthat the method succesfully deleted the value.\n\nBut this delete operation might not be always successful. For example, you might provide the wrong\nkey to this method. I mean, maybe you provide\n(either intentionally or unintentionally) a key that points to an empty bucket,\ni.e. a bucket that still doesn't have a value in it.\nIn this case, the `remove()` method would return a `false` value.\n\n\n\n### Iterating through the hashtable\n\nIterating through the keys and values that are currently being stored in\nthe hashtable is a very commom need.\nYou can do that in Zig by using an iterator object that can iterate\nthrough the elements of you hashtable object.\n\nThis iterator object works like any other iterator object that you would\nfind in languages such as C++ and Rust. It is basically a pointer object\nthat points to some value in the container, and has a `next()` method\nthat you can use to navigate (or iterate) through the next values in the\ncontainer.\n\nYou can create such iterator object by using the `iterator()` method of the hashtable object.\nThis method returns an iterator object, from which you can use the `next()` method in conjunction\nwith a while loop to iterate through the elements of your hashtable. The `next()` method returns an optional\n`Entry` value, and therefore, you must unwrap this optional value to get the actual `Entry` value\nfrom which you can access the key and also the value identified by this key.\n\nWith this `Entry` value at hand, you can access the key of this current entry by using the `key_ptr`\nattribute and dereferencing the pointer that lives inside of it, while the value identified by this\nkey is accessed through the `value_ptr` attribute instead, which is also a pointer to be dereferenced.\nThe code example below demonstrates the use of these elements:\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n\n var it = hash_table.iterator();\n while (it.next()) |kv| {\n // Access the current key\n std.debug.print(\"Key: {d} | \", .{kv.key_ptr.*});\n // Access the current value\n std.debug.print(\"Value: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n\n\n\n```\nKey: 54321 | Value: 89\nKey: 50050 | Value: 55\nKey: 57709 | Value: 41\n```\n\n\nIf you want to iterate through only the values or the keys of your hashtable,\nyou can create a key iterator or a value iterator object. These are also iterator\nobjects, which have the same `next()` method that you can use to iterate through the\nsequence of values.\n\nKey iterators are created from the `keyIterator()` method of your\nhashtable object, while value iterators are created from the `valueIterator()` method.\nAll you have to do is to unwrap the value from the `next()` method and deference it\ndirectly to access the key or value that you iterating over.\nThe code example below demonstrates what would this be for a key iterator,\nbut you can replicate the same logic to a value iterator.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar kit = hash_table.keyIterator();\nwhile (kit.next()) |key| {\n std.debug.print(\"Key: {d}\\n\", .{key.*});\n}\n```\n:::\n\n\n\n\n\n```\nKey: 54321\nKey: 50050\nKey: 57709\n```\n\n\n### The `ArrayHashMap` hashtable {#sec-array-map}\n\nIf you need to iterate through the elements of your hashtable constantly,\nyou might want to use the `ArrayHashMap` struct for your specific case,\ninstead of going with the usual and general-purpose `HashMap` struct.\n\nThe `ArrayHashMap` struct creates a hashtable that is faster to iterate over.\nThat is why this specific type of hashtable might be valuable to you.\nSome other properties of a `ArrayHashMap` hashtable are:\n\n- the order of insertion is preserved. So the order of the values you find while iterating through this hashtable\nare actually the order in which these values were inserted in the hashtable.\n\n- the key-value pairs are stored sequentially, one after another.\n\n\nYou can create an `ArrayHashMap` object by using, once again, a helper function that\nchooses automatically for you a hash function implementation. This is the\n`AutoArrayHashMap()` function, which works very similarly to the `AutoHashMap()`\nfunction that we presented at @sec-hashmap.\n\nYou provide two data types to this function. The data type of the keys that will be\nused in this hashtable, and the data type of the values that will be stored in\nthis hashtable.\n\nAn `ArrayHashMap` object have essentially the exact same methods from the `HashMap` struct.\nSo you can insert new values into the hashtable by using the `put()` method, you can look (or get)\na value from the hashtable by using the `get()` method. But the `remove()` method is not available\nin this specific type of hashtable.\n\nIn order to delete values from the hashtable, you would use the same methods that you find in\nan `ArrayList` object, i.e. a dynamic array. I presented these methods at @sec-dynamic-array-remove,\nwhich are the `swapRemove()` and `orderedRemove()` methods. These methods have here the same meaning, or,\nthe same effect that they have in an `ArrayList` object.\n\nThis means that, with `swapRemove()` you remove the value from the hashtable, but you do not preserve\nthe order in which the values were inserted into the structure. While `orderedRemove()` is capable\nof retaining the insertion order of these values.\n\nBut instead of providing an index as input to `swapRemove()` or `orderedRemove()`, like I described\nat @sec-dynamic-array-remove, these methods here in an `ArrayHashMap` take a key as input, like\nthe `remove()` method from a `HashMap` object. If you want to provide an index as input, instead\nof a key, you should use the `swapRemoveAt()` and `orderedRemoveAt()` methods.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar hash_table = AutoArrayHashMap(u32, u16)\n .init(allocator);\ndefer hash_table.deinit();\n```\n:::\n\n\n\n\n\n\n\n### The `StringHashMap` hashtable {#sec-string-hash-map}\n\nOne thing that you will notice in the other two types of hashtables that I\npresented in the last sections, is that neither of them accepts a slice data type\nin their keys.\nWhat this means is that you cannot use a slice value to represent a key in\nthese types of hashtable.\n\nThe most obvious consequence of this, is that you cannot use strings as keys\nin these hashtables. But is extremely commom to use string values as keys\nin hashtables.\n\nTake this very simple Javascript code snippet as an example. We are creating\na simple hashtable object named `people`. Then, we add a new entry to this\nhashtable, which is identified by the string `'Pedro'`. This string is the\nkey in this case, while the object containing different personal information such as\nage, height and city, is the value to be stored in the hashtable.\n\n```js\nvar people = new Object();\npeople['Pedro'] = {\n 'age': 25,\n 'height': 1.67,\n 'city': 'Belo Horizonte'\n};\n```\n\nThis pattern of using strings as keys is very commom in\nall sorts of situations. That is why the Zig Standard Library offers a\nspecific type of hashtable for this purpose, which is created through the `StringHashMap()` function.\nThis function creates a hashtable that uses strings as keys. The only input of this\nfunction is the data type of the values that will be stored into this hashtable.\n\nIn the example below, I'm creating a hashtable to store the ages of different people.\nThe keys to be used in this hashtable are the names of each person, while the value stored in the\nhashtable is the age of the person identified by the key.\n\nThat is why I provide the `u8` data type (which is the data type used by the age values) as input to this `StringHashMap()` function.\nAs the result, it creates a hashtable that uses string values as keys, and, that stores\n`u8` values in it. Notice that an allocator object is provided at the `init()` method of the\nresulting object from the `StringHashMap()` function.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var ages = std.StringHashMap(u8).init(allocator);\n defer ages.deinit();\n\n try ages.put(\"Pedro\", 25);\n try ages.put(\"Matheus\", 21);\n try ages.put(\"Abgail\", 42);\n\n var it = ages.iterator();\n while (it.next()) |kv| {\n std.debug.print(\"Key: {s} | \", .{kv.key_ptr.*});\n std.debug.print(\"Age: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n\n\n\n```\nKey: Pedro | Age: 25\nKey: Abgail | Age: 42\nKey: Matheus | Age: 21\n```\n\n\n### The `StringArrayHashMap` hashtable\n\nThe Zig Standard Library also provides a type of hashtable that mix the cons and pros of the\ntypes of hashtables that were presented on the previous two sections. That is, a hashtable\nthat uses strings as keys, but also have the advantages from the `ArrayHashMap` struct.\nIn other words, you can have a hashtable that is fast to iterate over,\nthat preserves insertion order, and also, that uses strings as keys.\n\nYou can create such type of hashtable by using the `StringArrayHashMap()` function.\nThis function accepts a data type as input, which is the data type of the values that are\ngoing to be stored inside this hashtable, in the same style as the function presented\nat @sec-string-hash-map.\n\nYou can insert new values into this hashtable by using the same `put()` method that\nI presented at @sec-string-hash-map. And you can also get values from the hashtable\nby using the same `get()` method that I exposed on previous sections.\nLike it's `ArrayHashMap` brother, to delete values from this specific type of hashtable,\nwe also use the `orderedRemove()` and `swapRemove()` methods, with the same effects that\nI described at @sec-array-map.\n\nIf we take the code example that was exposed at @sec-string-hash-map, we can\nachieve the exact same result with `StringArrayHashMap()`. All we have to do\nis to change the use of `StringHashMap()` to `StringArrayHashMap()` at the\nfifth line in this code example. It would change to this:\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar ages = std.StringArrayHashMap(u8).init(allocator);\n```\n:::\n\n\n\n\n\n\n\n## Linked lists\n\nThe Zig Standard Library provides implementation for both single and doubly linked lists.\nA linked list is a linear data structure that looks like a chain, or, a rope.\nThe main advantage of this data structure is that you normally have fast\ninsertion and deletion operations. But, as a disadvantage, iterating through\nthis data structure is usually not so fast as iterating through an array.\n\nThe idea behind a linked list is basically build a structure that concists of a series of nodes\nconnected to each other by pointers. This means that linked lists are usually not contiguos\nin memory, because each node might be south in memory, but the next node might be north\nin memory, then the next node might be left in memory, anyway, you get it, they can be anywhere.\n\nAt @fig-linked-list we can see a diagram of a singly linked list. Notice that we begin with\na first node. This first node is usually called \"the head of the linked list\". Then, from this\nfirst node we uncover the remaining nodes in the structure, by following the locations pointed\nby the pointers.\n\nEvery node have two things in it. It have the value that is stored in the current node\n, and also have a pointer. This pointer points to the next node in the list. If this pointer\nis null, then, it means that we reached the end of our linked list.\n\n![A diagram of a singly linked list.](./../Figures/linked-list.png){#fig-linked-list}\n\n\nAt @fig-linked-list2 we can see a diagram of a doubly linked list. The only thing that really\nchanges is that every node in the linked list have both a pointer to the previous node,\nand, a pointer to the next node. So every node have now two pointers in it. These are\nusually called the `prev` (for \"previous\") and `next` (for \"next\") pointers of the node.\n\nIn the singly linked list example, we had only one single pointer in each node, and this singular\npointer was always pointing to the next node in the sequence. In other words, singly linked lists\nnormally have only the `next` pointer in them.\n\n![A diagram of a doubly linked list.](./../Figures/doubly-linked-list.png){#fig-linked-list2}\n\n\n\nLinked lists are available in Zig through the functions `SinglyLinkedList()` and\n`DoublyLinkedList()`, for \"singly linked lists\" and \"doubly linked lists\", respectively. These functions are\nactually generic functions, which we are going to talk more about at @sec-generic-fun.\n\nFor now, just understand that, in order to create a linked list object,\nwe begin by providing a data type to these functions. This data type defines\nthe type of data that this linked list will store. In the example below,\nwe are creating a singly linked list capable of storing `u32` values.\nSo each node in this linked list will store a `u32` value.\n\nBoth the `SinglyLinkedList()` and `DoublyLinkedList()` functions returns a type, i.e. a struct definition, as result. This means that\nthe object `Lu32` is actually a type definition, or a struct definition. It defines\nthe type \"singly linked list of `u32` values\".\n\nSo now that we have the definition of the struct, we have to instantiate a `Lu32` object.\nWe normally instantiate struct objects in Zig by using an `init()` method.\nBut in this case, we are instantiating the struct directly, by using an empty\n`struct` literal, in the expression `Lu32{}`.\n\nIn this example, we first create multiple node objects, and after we create them,\nwe start to insert and connect these nodes to build the linked list, using the\n`prepend()` and `insertAfter()` methods. Notice that the `prepend()` method\nis a method from the linked list object, while the `insertAfter()` is a method\npresent in the node objects.\n\nIn essence, the `prepend()` method inserts a node at the beginning of the linked\nlist. In other words, the node that you provide to this method, becomes the new\n\"head node\" of the linked list. It becomes the first node in the list (see @fig-linked-list).\n\nOn the other side, the `insertAfter()` method is used to basically connect two nodes together.\nWhen you provide a node to this method, it creates a pointer to this input node,\nand stores this pointer in the current node, from which the method was called from.\nIn other words, this method creates the pointer that connects these two nodes together\nand stores it in the `next` attribute of the current node.\n\nSince doubly linked list have both a `next` and a `prev` pointers in each node,\nreferring to the next and previous nodes in the sequence, respectively,\nas I described at @fig-linked-list2, a node object created from\na `DoublyLinkedList()` object would have both a\n`insertBefore()` (for `prev`) and a `insertAfter()` (for `next`) methods\navailable.\n\nThis means that, if we used a doubly linked list, we could use the `insertBefore()` method\nto store the pointer to the input node in the `prev` attribute. This would put the input\nnode as the \"previous node\", or, the node before the current node. The `insertAfter()` method\nhave \"after\" in it's name to indicate that this method puts the pointer created to the input\nnode in the `next` attribute of the current node, and as the result, the input node becomes\nthe \"next node\" of the current node.\n\nSince we are using a singly linked list in this example, we have only the `insertAfter()` method\navailable in the node objects that we create from our `Lu32` type.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst SinglyLinkedList = std.SinglyLinkedList;\nconst Lu32 = SinglyLinkedList(u32);\n\npub fn main() !void {\n var list = Lu32{};\n var one = Lu32.Node{ .data = 1 };\n var two = Lu32.Node{ .data = 2 };\n var three = Lu32.Node{ .data = 3 };\n var four = Lu32.Node{ .data = 4 };\n var five = Lu32.Node{ .data = 5 };\n\n list.prepend(&two); // {2}\n two.insertAfter(&five); // {2, 5}\n list.prepend(&one); // {1, 2, 5}\n two.insertAfter(&three); // {1, 2, 3, 5}\n three.insertAfter(&four); // {1, 2, 3, 4, 5}\n}\n```\n:::\n\n\n\n\n\n\nThere are other methods available from the linked list object, depending if this object is\na singly linked list or a doubly linked list, that might be very useful for you, like:\n\n- `remove()` to remove a specific node from the linked list.\n- `popFirst()` to remove the first node from the linked list.\n- if singly linked list, `len()` to count how many nodes there is in the linked list.\n- if doubly linked list, checkout the `len` attribute to see how many nodes there is in the linked list.\n- if singly linked list, `popFirst()` to remove the first node from the linked list.\n- if doubly linked list, `pop()` and `popFirst()` to remove the last and first nodes from the linked list, respectively.\n- if doubly linked list, `append()` to add a new node to end of the linked list (i.e. inverse of `prepend()`).\n\n\n\n## Multi array structure\n\nZig introduces a new data structure called `MultiArrayList()`. It is a different version of the dynamic array\nthat we have introduced at @sec-dynamic-array. The difference between this structure and the `ArrayList()`\nthat we know from @sec-dynamic-array, is that `MultiArrayList()` creates a separate dynamic array\nfor each field of the struct that you provide as input.\n\nConsider the following code example. We create a new custom struct called `Person`. This\nstruct contains three different data members, or, three different fields. As consequence,\nwhen we provide this `Person` data type as input to `MultiArrayList()`, this\ncreates three different arrays. One array for each field in the struct.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst Person = struct {\n name: []const u8,\n age: u8,\n height: f32,\n};\nconst PersonArray = std.MultiArrayList(Person);\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var people = PersonArray{};\n defer people.deinit(allocator);\n\n try people.append(allocator, .{\n .name = \"Auguste\", .age = 15, .height = 1.54\n });\n try people.append(allocator, .{\n .name = \"Elena\", .age = 26, .height = 1.65\n });\n try people.append(allocator, .{\n .name = \"Michael\", .age = 64, .height = 1.87\n });\n}\n```\n:::\n\n\n\n\n\nIn other words, instead of creating an array of \"persons\", the `MultiArrayList()` function\ncreates a \"struct of arrays\". Each data member of this struct is a different array that stores\nthe values of a specific field from the `Person` struct values that are added (or, appended) to the \"struct of arrays\".\n\nThe @fig-multi-array exposed below presents a diagram that describes the `PersonArray` struct\nthat we have created in the previous code example. Notice that the values of the data members\npresent in each of the three `Person` values that we have appended into the `PersonArray` object\nthat we have instantiated, are scattered across three different internal arrays of the `PersonArray` object.\n\n![A diagram of the `PersonArray` struct.](./../Figures/multi-array.png){#fig-multi-array}\n\nYou can easily access each of these arrays separately, and iterate over the values of each array.\nFor that, you will need to call the `items()` method from the `PersonArray` object, and provide as input\nto this method, the name of the field that you want to iterate over.\nIf you want to iterate through the `.age` array for example, then, you need to call `items(.age)` from\nthe `PersonArray` object, like in the example below:\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nfor (people.items(.age)) |*age| {\n try stdout.print(\"Age: {d}\\n\", .{age.*});\n}\n```\n:::\n\n\n\n\n\n```\nAge: 15\nAge: 26\nAge: 64\n```\n\n\nIn the above example, we are iterating over the values of the `.age` array, or,\nthe internal array of the `PersonArray` object that contains the values of the `age`\ndata member from the `Person` values that were added to the multi array struct.\n\nIn this example we are calling the `items()` method directly from the `PersonArray`\nobject. However, it is recommended on most situations to call this `items()` method\nfrom a \"slice object\", which you can create from the `slice()` method.\nThe reason for this is that calling `items()` multiple times have better performance\nif you use a slice object.\n\nIn other words, if you are planning to access only one of the\ninternal arrays from your \"multi array struct\", it is fine to call `items()` directly\nfrom the multi array object. But if you need to access many of the internal arrays\nfrom your \"multi array struct\", then, you will likely need to call `items()` more\nthan once, and, in such circustance, is better to call `items()` through a slice object.\nThe example below demonstrates the use of such object:\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar slice = people.slice();\nfor (slice.items(.age)) |*age| {\n age.* += 10;\n}\nfor (slice.items(.name), slice.items(.age)) |*n,*a| {\n try stdout.print(\n \"Name: {s}, Age: {d}\\n\", .{n.*, a.*}\n );\n}\n```\n:::\n\n\n\n\n\n```\nName: Auguste, Age: 25\nName: Elena, Age: 36\nName: Michael, Age: 74\n```\n\n\n## Conclusion\n\nThere are many other data structures that I did not presented here.\nBut you can check them out at the offical Zig Standard Library documentation page.\nActually, when you get into the [homepage of the documentation](https://ziglang.org/documentation/master/std/#)[^home], the first thing\nthat appears to you in this page, is a list of types and data structures.\n\n\nIn this section you can see a list of the many different data structures available in\nthe Zig Standard Library. There are some very specific structures in this list, like a\n[`BoundedArray` struct](https://ziglang.org/documentation/master/std/#std.bounded_array.BoundedArray)[^bounded]\n, but there is also some more general structures, such as a\n[`PriorityQueue` struct](https://ziglang.org/documentation/master/std/#std.priority_queue.PriorityQueue)[^priority].\n\n\n[^home]: \n[^priority]: .\n[^bounded]: \n\n\n\n\n\n\n", "supporting": [], "filters": [ "rmarkdown/pagebreak.lua" diff --git a/docs/Chapters/09-data-structures.html b/docs/Chapters/09-data-structures.html index 240a48b..44077d6 100644 --- a/docs/Chapters/09-data-structures.html +++ b/docs/Chapters/09-data-structures.html @@ -294,7 +294,7 @@

Table of contents

@@ -340,8 +341,8 @@

11  -

11.1 Dynamic Arrays

+
+

11.1 Dynamic Arrays

In high level languages, arrays are usually dynamic. They easily grow in size when they have to, and you don’t need to worry about it. In contrast, arrays in low level languages are usually static by default. This is the reality of C, C++, Rust and also Zig. Static arrays were presented at Section 1.6, but in this section, we are going to talk about dynamic arrays.

Dynamic arrays are simply arrays that can grow in size during the runtime of your program. Most low level languages offer some implementation of a dynamic array in their standard library. C++ have std::vector, Rust have Vec, and Zig have std.ArrayList.

The std.ArrayList struct provides a contiguous and growable array for you. It works like any other dinamic array, it allocates a contiguous block of memory, and when this block have no space left, ArrayList allocates another contiguous and bigger block of memory, copies the elements to this new location, and erases (or frees) the previous block of memory.

@@ -722,8 +723,77 @@

if doubly linked list, append() to add a new node to end of the linked list (i.e. inverse of prepend()).

-
-

11.4 Conclusion

+
+

11.4 Multi array structure

+

Zig introduces a new data structure called MultiArrayList(). It is a different version of the dynamic array that we have introduced at Section 11.1. The difference between this structure and the ArrayList() that we know from Section 11.1, is that MultiArrayList() creates a separate dynamic array for each field of the struct that you provide as input.

+

Consider the following code example. We create a new custom struct called Person. This struct contains three different data members, or, three different fields. As consequence, when we provide this Person data type as input to MultiArrayList(), this creates three different arrays. One array for each field in the struct.

+
+
const std = @import("std");
+const Person = struct {
+    name: []const u8,
+    age: u8,
+    height: f32,
+};
+const PersonArray = std.MultiArrayList(Person);
+
+pub fn main() !void {
+    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+    const allocator = gpa.allocator();
+    var people = PersonArray{};
+    defer people.deinit(allocator);
+
+    try people.append(allocator, .{
+        .name = "Auguste", .age = 15, .height = 1.54
+    });
+    try people.append(allocator, .{
+        .name = "Elena", .age = 26, .height = 1.65
+    });
+    try people.append(allocator, .{
+        .name = "Michael", .age = 64, .height = 1.87
+    });
+}
+
+

In other words, instead of creating an array of “persons”, the MultiArrayList() function creates a “struct of arrays”. Each data member of this struct is a different array that stores the values of a specific field from the Person struct values that are added (or, appended) to the “struct of arrays”.

+

The Figure 11.5 exposed below presents a diagram that describes the PersonArray struct that we have created in the previous code example. Notice that the values of the data members present in each of the three Person values that we have appended into the PersonArray object that we have instantiated, are scattered across three different internal arrays of the PersonArray object.

+
+
+
+ +
+
+Figure 11.5: A diagram of the PersonArray struct. +
+
+
+

You can easily access each of these arrays separately, and iterate over the values of each array. For that, you will need to call the items() method from the PersonArray object, and provide as input to this method, the name of the field that you want to iterate over. If you want to iterate through the .age array for example, then, you need to call items(.age) from the PersonArray object, like in the example below:

+
+
for (people.items(.age)) |*age| {
+    try stdout.print("Age: {d}\n", .{age.*});
+}
+
+
Age: 15
+Age: 26
+Age: 64
+

In the above example, we are iterating over the values of the .age array, or, the internal array of the PersonArray object that contains the values of the age data member from the Person values that were added to the multi array struct.

+

In this example we are calling the items() method directly from the PersonArray object. However, it is recommended on most situations to call this items() method from a “slice object”, which you can create from the slice() method. The reason for this is that calling items() multiple times have better performance if you use a slice object.

+

In other words, if you are planning to access only one of the internal arrays from your “multi array struct”, it is fine to call items() directly from the multi array object. But if you need to access many of the internal arrays from your “multi array struct”, then, you will likely need to call items() more than once, and, in such circustance, is better to call items() through a slice object. The example below demonstrates the use of such object:

+
+
var slice = people.slice();
+for (slice.items(.age)) |*age| {
+    age.* += 10;
+}
+for (slice.items(.name), slice.items(.age)) |*n,*a| {
+    try stdout.print(
+        "Name: {s}, Age: {d}\n", .{n.*, a.*}
+    );
+}
+
+
Name: Auguste, Age: 25
+Name: Elena, Age: 36
+Name: Michael, Age: 74
+
+
+

11.5 Conclusion

There are many other data structures that I did not presented here. But you can check them out at the offical Zig Standard Library documentation page. Actually, when you get into the homepage of the documentation2, the first thing that appears to you in this page, is a list of types and data structures.

In this section you can see a list of the many different data structures available in the Zig Standard Library. There are some very specific structures in this list, like a BoundedArray struct3 , but there is also some more general structures, such as a PriorityQueue struct4.

diff --git a/docs/Figures/multi-array.png b/docs/Figures/multi-array.png new file mode 100644 index 0000000000000000000000000000000000000000..95748ab770f328fe9344046e3e602716f0cf5951 GIT binary patch literal 24122 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 IfBgJ^05uL6IsgCw literal 0 HcmV?d00001 diff --git a/docs/search.json b/docs/search.json index cdf226e..29559a3 100644 --- a/docs/search.json +++ b/docs/search.json @@ -873,8 +873,8 @@ "objectID": "Chapters/09-data-structures.html#conclusion-1", "href": "Chapters/09-data-structures.html#conclusion-1", "title": "11  Data Structures", - "section": "11.4 Conclusion", - "text": "11.4 Conclusion\nThere are many other data structures that I did not presented here. But you can check them out at the offical Zig Standard Library documentation page. Actually, when you get into the homepage of the documentation2, the first thing that appears to you in this page, is a list of types and data structures.\nIn this section you can see a list of the many different data structures available in the Zig Standard Library. There are some very specific structures in this list, like a BoundedArray struct3 , but there is also some more general structures, such as a PriorityQueue struct4.\n\n\n\n\nWikipedia. 2024. “Hash Tables.” Wikipedia. https://en.wikipedia.org/wiki/Hash_table.", + "section": "11.5 Conclusion", + "text": "11.5 Conclusion\nThere are many other data structures that I did not presented here. But you can check them out at the offical Zig Standard Library documentation page. Actually, when you get into the homepage of the documentation2, the first thing that appears to you in this page, is a list of types and data structures.\nIn this section you can see a list of the many different data structures available in the Zig Standard Library. There are some very specific structures in this list, like a BoundedArray struct3 , but there is also some more general structures, such as a PriorityQueue struct4.\n\n\n\n\nWikipedia. 2024. “Hash Tables.” Wikipedia. https://en.wikipedia.org/wiki/Hash_table.", "crumbs": [ "11  Data Structures" ] @@ -1128,5 +1128,25 @@ "crumbs": [ "13  Filesystem and Input/Output (IO)" ] + }, + { + "objectID": "Chapters/09-data-structures.html#sec-dynamic-array", + "href": "Chapters/09-data-structures.html#sec-dynamic-array", + "title": "11  Data Structures", + "section": "", + "text": "11.1.1 Capacity vs Length\nWhen we talk about dynamic arrays, we have two similar concepts that are very essential to how a dynamic array works behind the hood. These concepts are capacity and length. In some contexts, specially in C++, length is also called of size.\nAlthough they look similar, these concepts represent different things in the context of dynamic arrays. Capacity is the number of items (or elements) that your dynamic array can currently hold without the need to allocate more memory.\nIn contrast, the length refers to how many elements in the array are currently being used, or, in other words, how many elements in this array that you assigned a value to. Every dynamic array works around a block of allocated memory that represents an array with total capacity of \\(n\\) elements, but only a portion of these \\(n\\) elements are being used most of the time. This portion of \\(n\\) is the length of the array. So every time you append a new value to the array, you are incrementing it’s length by one.\nThis means that a dynamic array usually works with an extra margin, or, an extra space which is currently empty, but it is waiting and ready to be used. This “extra space” is essentially the difference between capacity and length. Capacity represents the total number of elements that the array can hold without the need to re-allocate or re-expand the array, while the length represents how much of this capacity is currently being used to hold/store values.\nFigure 11.1 presents this idea visually. Notice that, at first, the capacity of the array is greater than the length of the array. So, the dynamic array have extra space that is currently empty, but it is ready to receive a value to be stored.\n\n\n\n\n\n\nFigure 11.1: Difference between capacity and length in a dynamic array\n\n\n\nWe can also see at Figure 11.1 that, when length and capacity are equal, it means that the array have no space left. We reached the roof of our capacity, and because of that, if we want to store more values in this array, we need to expand it. We need to get a bigger space that can hold more values that we currently have.\nA dynamic array works by expanding the underlying array, whenever the length becomes equal to the capacity of the array. It basically allocates a new contiguos block of memory that is bigger than the previous one, then, it copies all values that are currently being stored to this new location (i.e. this new block of memory), then, it frees the previous block of memory. At the end of this process, the new underlying array have a bigger capacity, and, therefore, the length becomes once again smaller than the capacity of the array.\nThis is the cycle of an dynamic array. Notice that, throughout this cycle, the capacity is always either equal to or higher than the length of the array. If youh have an ArrayList object, let’s suppose you named it of buffer, you can check the current capacity of your array by accessing the capacity attribute of your ArrayList object, while the current length of it is available through the items.len attribute of your ArrayList object.\n\n// Check capacity\nbuffer.capacity;\n// Check length\nbuffer.items.len;\n\n\n\n11.1.2 Creating an ArrayList object\nIn order to use ArrayList, you must provide an allocator object to it. Remember, Zig does not have a default memory allocator. And as I described at Section 3.2, all memory allocations must be done by allocator objects that you define, that you have control over. In our example here, I’m going to use a general purpose allocator, but you can use any other allocator of your preference.\nWhen you initialize an ArrayList object, you must provide the data type of the elements of the array. In other words, this defines the type of data that this array (or container) will store. Therefore, if I provide the u8 type to it, then, I will create a dynamic array of u8 values. However, if I provide a struct that I defined instead, like the struct User from Section 2.3, then, a dynamic array of User values will be created. In the example below, with the expression ArrayList(u8) we are creating a dynamic array of u8 values.\nAfter you provide the data type of the elements of the array, you can initialize an ArrayList object by either using the init() or the initCapacity() method. The former method receives only the allocator object as input, while the latter method receives both the allocator object and a capacity number as inputs. With the latter method, you not only initialize the struct, but you also set the starting capacity of the allocated array.\nUsing the initCapacity() method is the preferred way to initialize your dynamic array. Because reallocations, or, in other words, the process of expanding the capacity of the array, is always a high cost operation. You should take any possible opportunity to avoid reallocations in your array. If you know how much space your array needs to occupy at the beginning, you should always use initCapacity() to create your dynamic array.\n\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n\nIn the example above, the buffer object starts as an array of 100 elements. If this buffer object needs to create more space to accomodate more elements during the runtime of your program, the ArrayList internals will perform the necessary actions for you automatically. Also notice the deinit() method being used to destroy the buffer object at the end of the current scope, by freeing all the memory that was allocated for the dynamic array stored in this buffer object.\n\n\n11.1.3 Adding new elements to the array\nNow that we created our dynamic array, we can start to use it. You can append (a.k.a “add”) new values to this array by using the append() method. This method works the same way as the append() method from a Python list, or, the emplace_back() method from std::vector of C++. You provide a single value to this method, and the method appends this value to the array.\nYou can also use the appendSlice() method to append multiple values at once. You provide a slice (slices were described at Section 1.6) to this method, and the method adds all values present in this slice to your dynamic array.\n\ntry buffer.append('H');\ntry buffer.append('e');\ntry buffer.append('l');\ntry buffer.append('l');\ntry buffer.append('o');\ntry buffer.appendSlice(\" World!\");\n\n\n\n11.1.4 Removing elements from the array\nYou can use the pop() method to “pop” or remove the last element in the array. Is worth noting that this method do not change the capacity of the array. It just deletes or erases the last value stored in the array.\nAlso, this method returns as result the value that got deleted. That is, you can use this method to both get the last value in the array, and also, remove it from the array. It is a “get and remove value” type of method.\n\nconst exclamation_mark = buffer.pop();\n\nNow, if you want to remove specific elements from specific positions of your array, you can use the orderedRemove() method from your ArrayList object. With this method, you can provide an index as input, then, the method will delete the value that is at this index in the array. This effectively reduces the length of the array everytime you execute an orderedRemove() operation.\nIn the example below, we first create an ArrayList object, and we fill it with numbers. Then, we use orderedRemove() to remove the value at index 3 in the array, two consecutive times.\nAlso, notice that we are assigning the result of orderedRemove() to the underscore character. So we are discarding the result value of this method. As the result value, the orderedRemove() method returns the value that got deleted, in a similar style to the pop() method.\n\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n\nfor (0..10) |i| {\n const index: u8 = @intCast(i);\n try buffer.append(index);\n}\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\n_ = buffer.orderedRemove(3);\n_ = buffer.orderedRemove(3);\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\nstd.debug.print(\n \"{any}\\n\", .{buffer.items.len}\n);\n\n{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }\n{ 0, 1, 2, 5, 6, 7, 8, 9 }\n8\nOne key characteristic about orderedRemove() is that it preserves the order of the values in the array. So, it deletes the value that you asked it to remove, but it also makes sure that the order of the values that remain in the array stay the same as before.\nNow, if you don’t care about the order of the values, for example, maybe you want to treat your dynamic array as a set of values, like the std::unordered_set structure from C++, you can use the swapRemove() method instead. This method works similarly to the orderedRemove() method. You give an index to this method, then, it deletes the value that is at this index in the array. But this method does not preserve the original order of the values that remain in the array. As a result, swapRemove() is, in general, faster than orderedRemove().\n\n\n11.1.5 Inserting elements at specific indexes\nWhen you need to insert values in the middle of your array, instead of just appending them to the end of the array, you need to use the insert() and insertSlice() methods, instead of the append() and appendSlice() methods.\nThese two methods work very similarly to insert() and insert_range() from the C++ vector class. You provide an index to these methods, and they insert the values that you provide at that index in the array.\n\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 10);\ndefer buffer.deinit();\n\ntry buffer.appendSlice(\"My Pedro\");\ntry buffer.insert(4, '3');\ntry buffer.insertSlice(2, \" name\");\nfor (buffer.items) |char| {\n try stdout.print(\"{c}\", .{char});\n}\n\nMy name P3edro\n\n\n11.1.6 Conclusion\nIf you feel the lack of some other method, I recommend you to read the official documentation for the ArrayListAligned1 struct, which describes most of the methods available through the ArrayList object.\nYou will notice that there is a lot other methods in this page that I did not described here, and I recommend you to explore these methods, and understand how they work.", + "crumbs": [ + "11  Data Structures" + ] + }, + { + "objectID": "Chapters/09-data-structures.html#multi-array-structure", + "href": "Chapters/09-data-structures.html#multi-array-structure", + "title": "11  Data Structures", + "section": "11.4 Multi array structure", + "text": "11.4 Multi array structure\nZig introduces a new data structure called MultiArrayList(). It is a different version of the dynamic array that we have introduced at Section 11.1. The difference between this structure and the ArrayList() that we know from Section 11.1, is that MultiArrayList() creates a separate dynamic array for each field of the struct that you provide as input.\nConsider the following code example. We create a new custom struct called Person. This struct contains three different data members, or, three different fields. As consequence, when we provide this Person data type as input to MultiArrayList(), this creates three different arrays. One array for each field in the struct.\n\nconst std = @import(\"std\");\nconst Person = struct {\n name: []const u8,\n age: u8,\n height: f32,\n};\nconst PersonArray = std.MultiArrayList(Person);\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var people = PersonArray{};\n defer people.deinit(allocator);\n\n try people.append(allocator, .{\n .name = \"Auguste\", .age = 15, .height = 1.54\n });\n try people.append(allocator, .{\n .name = \"Elena\", .age = 26, .height = 1.65\n });\n try people.append(allocator, .{\n .name = \"Michael\", .age = 64, .height = 1.87\n });\n}\n\nIn other words, instead of creating an array of “persons”, the MultiArrayList() function creates a “struct of arrays”. Each data member of this struct is a different array that stores the values of a specific field from the Person struct values that are added (or, appended) to the “struct of arrays”.\nThe Figure 11.5 exposed below presents a diagram that describes the PersonArray struct that we have created in the previous code example. Notice that the values of the data members present in each of the three Person values that we have appended into the PersonArray object that we have instantiated, are scattered across three different internal arrays of the PersonArray object.\n\n\n\n\n\n\nFigure 11.5: A diagram of the PersonArray struct.\n\n\n\nYou can easily access each of these arrays separately, and iterate over the values of each array. For that, you will need to call the items() method from the PersonArray object, and provide as input to this method, the name of the field that you want to iterate over. If you want to iterate through the .age array for example, then, you need to call items(.age) from the PersonArray object, like in the example below:\n\nfor (people.items(.age)) |*age| {\n try stdout.print(\"Age: {d}\\n\", .{age.*});\n}\n\nAge: 15\nAge: 26\nAge: 64\nIn the above example, we are iterating over the values of the .age array, or, the internal array of the PersonArray object that contains the values of the age data member from the Person values that were added to the multi array struct.\nIn this example we are calling the items() method directly from the PersonArray object. However, it is recommended on most situations to call this items() method from a “slice object”, which you can create from the slice() method. The reason for this is that calling items() multiple times have better performance if you use a slice object.\nIn other words, if you are planning to access only one of the internal arrays from your “multi array struct”, it is fine to call items() directly from the multi array object. But if you need to access many of the internal arrays from your “multi array struct”, then, you will likely need to call items() more than once, and, in such circustance, is better to call items() through a slice object. The example below demonstrates the use of such object:\n\nvar slice = people.slice();\nfor (slice.items(.age)) |*age| {\n age.* += 10;\n}\nfor (slice.items(.name), slice.items(.age)) |*n,*a| {\n try stdout.print(\n \"Name: {s}, Age: {d}\\n\", .{n.*, a.*}\n );\n}\n\nName: Auguste, Age: 25\nName: Elena, Age: 36\nName: Michael, Age: 74", + "crumbs": [ + "11  Data Structures" + ] } ] \ No newline at end of file From f42758dc1aae568304280cc105fd1b062a456d1d Mon Sep 17 00:00:00 2001 From: pedropark99 Date: Sat, 24 Aug 2024 15:52:39 -0300 Subject: [PATCH 4/4] Recompile book --- Chapters/09-data-structures.qmd | 7 +- .../execute-results/html.json | 8 +- docs/Chapters/09-data-structures.html | 4 +- docs/Figures/buffered-io2.png | Bin 38262 -> 0 bytes docs/index.html | 4 +- docs/search.json | 134 +++++------------- 6 files changed, 52 insertions(+), 105 deletions(-) delete mode 100644 docs/Figures/buffered-io2.png diff --git a/Chapters/09-data-structures.qmd b/Chapters/09-data-structures.qmd index b5f2ea1..041cef3 100644 --- a/Chapters/09-data-structures.qmd +++ b/Chapters/09-data-structures.qmd @@ -844,7 +844,9 @@ for each field of the struct that you provide as input. Consider the following code example. We create a new custom struct called `Person`. This struct contains three different data members, or, three different fields. As consequence, when we provide this `Person` data type as input to `MultiArrayList()`, this -creates three different arrays. One array for each field in the struct. +creates a "struct of three different arrays" called `PersonArray`. In other words, +this `PersonArray` is a struct that contains three internal dynamic arrays in it. +One array for each field found in the `Person` struct definition. ```{zig} @@ -878,6 +880,9 @@ pub fn main() !void { In other words, instead of creating an array of "persons", the `MultiArrayList()` function creates a "struct of arrays". Each data member of this struct is a different array that stores the values of a specific field from the `Person` struct values that are added (or, appended) to the "struct of arrays". +One important detail is that each of these separate internal arrays stored inside `PersonArray` +are dynamic arrays. This means that these arrays can grow automatically as needed, to accomodate +more values. The @fig-multi-array exposed below presents a diagram that describes the `PersonArray` struct that we have created in the previous code example. Notice that the values of the data members diff --git a/_freeze/Chapters/09-data-structures/execute-results/html.json b/_freeze/Chapters/09-data-structures/execute-results/html.json index 187d6f0..531453a 100644 --- a/_freeze/Chapters/09-data-structures/execute-results/html.json +++ b/_freeze/Chapters/09-data-structures/execute-results/html.json @@ -1,9 +1,11 @@ { - "hash": "a71a1416c129be13271ccb2b18c4bafb", + "hash": "772530f1a031cba70f93391a2d146e58", "result": { "engine": "knitr", - "markdown": "---\nengine: knitr\nknitr: true\nsyntax-definition: \"../Assets/zig.xml\"\n---\n\n\n\n\n\n\n\n\n\n# Data Structures\n\nIn this chapter, we are going to discuss some Data Structures that are available from\nthe Zig Standard Library, specially `ArrayList` and also `HashMap`. I'm also want\nto talk about one of the key features of Zig in this chapter, which is `comptime`, and\nhow we can use it to create generics in Zig.\n\n\n## Dynamic Arrays {#sec-dynamic-array}\n\nIn high level languages, arrays are usually dynamic. They easily grow\nin size when they have to, and you don't need to worry about it.\nIn contrast, arrays in low level languages are usually static by default.\nThis is the reality of C, C++, Rust and also Zig. Static arrays were presented at\n@sec-arrays, but in this section, we are going to talk about dynamic arrays.\n\nDynamic arrays are simply arrays that can grow in size during the runtime\nof your program. Most low level languages offer some implementation of\na dynamic array in their standard library. C++ have `std::vector`, Rust have `Vec`,\nand Zig have `std.ArrayList`.\n\nThe `std.ArrayList` struct provides a contiguous and growable array for you.\nIt works like any other dinamic array, it allocates a contiguous block of memory, and when this block have no space left,\n`ArrayList` allocates another contiguous and bigger block of memory, copies the\nelements to this new location, and erases (or frees) the previous block of memory.\n\n\n### Capacity vs Length\n\nWhen we talk about dynamic arrays, we have two similar concepts that\nare very essential to how a dynamic array works behind the hood.\nThese concepts are *capacity* and *length*. In some contexts, specially\nin C++, *length* is also called of *size*.\n\nAlthough they look similar, these concepts represent different things\nin the context of dynamic arrays. *Capacity* is the number of items (or elements)\nthat your dynamic array can currently hold without the need to allocate more memory.\n\nIn contrast, the *length* refers to how many elements in the array\nare currently being used, or, in other words, how many elements in this array\nthat you assigned a value to. Every dynamic array works around\na block of allocated memory that represents an array with total capacity of $n$ elements,\nbut only a portion of these $n$ elements are being used most of the time. This portion\nof $n$ is the *length* of the array. So every time you append a new value\nto the array, you are incrementing it's *length* by one.\n\nThis means that a dynamic array usually works with an extra margin, or, an extra space\nwhich is currently empty, but it is waiting and ready to be used. This \"extra space\"\nis essentially the difference between *capacity* and *length*. *Capacity* represents\nthe total number of elements that the array can hold without the need to re-allocate\nor re-expand the array, while the *length* represents how much of this capacity\nis currently being used to hold/store values.\n\n@fig-capacity-length presents this idea visually. Notice that, at first,\nthe capacity of the array is greater than the length of the array.\nSo, the dynamic array have extra space that is currently empty, but it\nis ready to receive a value to be stored.\n\n![Difference between capacity and length in a dynamic array](./../Figures/dynamic-array.png){#fig-capacity-length}\n\nWe can also see at @fig-capacity-length that, when *length* and *capacity* are equal, it means that the array have no space left.\nWe reached the roof of our capacity, and because of that, if we want to store more values\nin this array, we need to expand it. We need to get a bigger space that can hold more values\nthat we currently have.\n\nA dynamic array works by expanding the underlying array, whenever the *length* becomes equal\nto the *capacity* of the array. It basically allocates a new contiguos block of memory that is bigger\nthan the previous one, then, it copies all values that are currently being stored to this new\nlocation (i.e. this new block of memory), then, it frees the previous block of\nmemory. At the end of this process, the new underlying array have a bigger *capacity*, and, therefore,\nthe *length* becomes once again smaller than the *capacity* of the array.\n\nThis is the cycle of an dynamic array. Notice that, throughout this cycle, the *capacity* is always\neither equal to or higher than the *length* of the array. If youh have an `ArrayList` object, let's suppose\nyou named it of `buffer`, you can check the current capacity of your array by accessing the `capacity`\nattribute of your `ArrayList` object, while the current *length* of it is available through the `items.len`\nattribute of your `ArrayList` object.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\n// Check capacity\nbuffer.capacity;\n// Check length\nbuffer.items.len;\n```\n:::\n\n\n\n\n\n### Creating an `ArrayList` object\n\nIn order to use `ArrayList`, you must provide an allocator object to it.\nRemember, Zig does not have a default memory allocator. And as I described at @sec-allocators, all memory\nallocations must be done by allocator objects that you define, that\nyou have control over. In our example here, I'm going to use\na general purpose allocator, but you can use any other allocator\nof your preference.\n\nWhen you initialize an `ArrayList` object, you must provide the data type of the elements of\nthe array. In other words, this defines the type of data that this array (or container) will\nstore. Therefore, if I provide the `u8` type to it, then, I will create a dynamic\narray of `u8` values. However, if I provide a struct that I defined instead, like the struct `User`\nfrom @sec-structs-and-oop, then, a dynamic array of `User` values\nwill be created. In the example below, with the expression `ArrayList(u8)` we\nare creating a dynamic array of `u8` values.\n\nAfter you provide the data type of the elements of the array, you can initialize\nan `ArrayList` object by either using the `init()` or the `initCapacity()` method.\nThe former method receives only the allocator object\nas input, while the latter method receives both the allocator object and a capacity number as inputs.\nWith the latter method, you not only initialize the struct, but you\nalso set the starting capacity of the allocated array.\n\nUsing the `initCapacity()` method is the preferred way to initialize your dynamic array.\nBecause reallocations, or, in other words, the process of expanding the capacity of the array,\nis always a high cost operation. You should take any possible opportunity to avoid reallocations in\nyour array. If you know how much space your array needs to occupy at the beginning,\nyou should always use `initCapacity()` to create your dynamic array.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n```\n:::\n\n\n\n\n\n\nIn the example above, the `buffer` object starts as an array of 100 elements. If this\n`buffer` object needs to create more space to accomodate more elements during the runtime of your program, the `ArrayList`\ninternals will perform the necessary actions for you automatically.\nAlso notice the `deinit()` method being used to destroy the `buffer` object at the\nend of the current scope, by freeing all the memory that was allocated for the dynamic\narray stored in this `buffer` object.\n\n\n### Adding new elements to the array\n\nNow that we created our dynamic array, we can start to use it. You can append (a.k.a \"add\")\nnew values to this array by using the `append()` method. This method works the same way\nas the `append()` method from a Python list, or, the `emplace_back()` method from `std::vector` of C++.\nYou provide a single value to this method, and the method appends this value to the array.\n\nYou can also use the `appendSlice()` method to append multiple values at once. You provide\na slice (slices were described at @sec-arrays) to this method, and the method adds all values present\nin this slice to your dynamic array.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\ntry buffer.append('H');\ntry buffer.append('e');\ntry buffer.append('l');\ntry buffer.append('l');\ntry buffer.append('o');\ntry buffer.appendSlice(\" World!\");\n```\n:::\n\n\n\n\n\n### Removing elements from the array {#sec-dynamic-array-remove}\n\nYou can use the `pop()` method to \"pop\" or remove\nthe last element in the array. Is worth noting that this method\ndo not change the capacity of the array. It just deletes or erases\nthe last value stored in the array.\n\nAlso, this method returns as result the value that got deleted. That is, you can\nuse this method to both get the last value in the array, and also, remove\nit from the array. It is a \"get and remove value\" type of method.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst exclamation_mark = buffer.pop();\n```\n:::\n\n\n\n\n\nNow, if you want to remove specific elements from specific positions\nof your array, you can use the `orderedRemove()` method from your\n`ArrayList` object. With this method, you can provide an index as input,\nthen, the method will delete the value that is at this index in the array.\nThis effectively reduces the *length* of the array everytime you execute\nan `orderedRemove()` operation.\n\nIn the example below, we first create an `ArrayList` object, and we fill it\nwith numbers. Then, we use `orderedRemove()` to remove the value at\nindex 3 in the array, two consecutive times.\n\nAlso, notice that we are assigning the result of `orderedRemove()` to the\nunderscore character. So we are discarding the result value of this method.\nAs the result value, the `orderedRemove()` method returns the value that\ngot deleted, in a similar style to the `pop()` method.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n\nfor (0..10) |i| {\n const index: u8 = @intCast(i);\n try buffer.append(index);\n}\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\n_ = buffer.orderedRemove(3);\n_ = buffer.orderedRemove(3);\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\nstd.debug.print(\n \"{any}\\n\", .{buffer.items.len}\n);\n```\n:::\n\n\n\n\n\n```\n{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }\n{ 0, 1, 2, 5, 6, 7, 8, 9 }\n8\n```\n\nOne key characteristic about `orderedRemove()` is that it preserves the order\nof the values in the array. So, it deletes the value that you asked it to\nremove, but it also makes sure that the order of the values that remain in the array\nstay the same as before.\n\nNow, if you don't care about the order of the values, for example, maybe you want to treat\nyour dynamic array as a set of values, like the `std::unordered_set`\nstructure from C++, you can use the `swapRemove()` method instead. This method\nworks similarly to the `orderedRemove()` method. You give an index to this\nmethod, then, it deletes the value that is at this index in the array.\nBut this method does not preserve the original order of the values that remain\nin the array. As a result, `swapRemove()` is, in general, faster than `orderedRemove()`.\n\n\n### Inserting elements at specific indexes\n\nWhen you need to insert values in the middle of your array,\ninstead of just appending them to the end of the array, you need to use\nthe `insert()` and `insertSlice()` methods, instead of\nthe `append()` and `appendSlice()` methods.\n\nThese two methods work very similarly to `insert()` and `insert_range()`\nfrom the C++ vector class. You provide an index to these methods,\nand they insert the values that you provide at that index in the array.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 10);\ndefer buffer.deinit();\n\ntry buffer.appendSlice(\"My Pedro\");\ntry buffer.insert(4, '3');\ntry buffer.insertSlice(2, \" name\");\nfor (buffer.items) |char| {\n try stdout.print(\"{c}\", .{char});\n}\n```\n:::\n\n\n\n\n\n```\nMy name P3edro\n```\n\n\n### Conclusion\n\nIf you feel the lack of some other method, I recommend\nyou to read the [official documentation for the `ArrayListAligned`](https://ziglang.org/documentation/master/std/#std.array_list.ArrayListAligned)[^zig-array2]\nstruct, which describes most of the methods available\nthrough the `ArrayList` object.\n\nYou will notice that there is a lot other methods in this page that\nI did not described here, and I recommend you to explore these methods,\nand understand how they work.\n\n[^zig-array2]: \n\n\n\n## Maps or HashTables\n\nSome professionals know this type of data structure by different terms, like \"map\", \"hashmap\" or \"associative arrays\". But most professionals\nknow this structure by the name *hashtable*.\nEvery programming language normally have some implementation of a hashtable in their\nstardard libraries. Python have `dict()`, C++ have `std::map` and `std::unordered_map`, Rust\nhave `HashMap`, Javascript have `Object()` and `Map()`,\nC# have `Hashtable()`, etc.\n\n\n\n### What is a hashtable?\n\nA hashtable is a data structure based on key-value pairs.\nYou provide a key and a value to this structure, then, the hashtable will store\nthe input value at a location that can be identified by the input\nkey that you provided.\nIt does that by using an underlying array and a hash function.\nThese two components are essential to how a hashtable works.\n\nUnder the hood, the hashtable contains an array. This array is where the values\nare stored, and the elements of this array are usually called of *buckets*.\nSo the values that you provide to the hashtable are stored inside buckets,\nand you access each bucket by using an index.\n\nWhen you provide a key to a hashtable, it passes this key to the\nhash function. This hash function uses some sort of hashing algorithm to transform\nthis key into an index. This index is actually an array index. It is a position\nin the underlying array of the hashtable.\nThis is how a key identifies a specific position (or location) inside the hashtable\nstructure.\n\nSo you provide a key to the hashtable, and this key identifies an specific location\ninside the hastable, then, the hashtable takes the input value that you provided,\nand stores this value in the location identified by the input key that you provided.\nYou could say that the key maps to the value stored in the hashtable. You find\nthe value, by using the key that identifies the location where the value is stored.\nThe @fig-hashtable presents this process visually.\n\n\n![A diagram of a Hashtable. Source: Wikipedia, the free encyclopedia.](./../Figures/hashtable.svg){#fig-hashtable}\n\n\nThe operation described in the previous paragraph is normally called an *insertion* operation.\nBecause you are inserting new values into the hashtable.\nBut there are other types of operations in hashtables such as *delete* and *lookup*.\nDelete is self describing, it is when you delete (or remove) a value from the hashtable.\nWhile lookup corresponds to when you retrieve (or look at) a value that is stored in\nthe hashtable, by using the key that identifies the location where this value is stored.\n\nSometimes, instead of storing the values directly, the underlying array of the hashtable might be an array of pointers,\ni.e. the buckets of the array stores pointers that points to the value,\nor also, may be an array of linked lists.\nThese cases are commom on hashtables that allows duplicate keys, or, in other words,\non hashtables that effectively handle \"collisions\" that may arise from the hash function.\n\nDuplicate keys, or this \"collision\" thing that I'm talking about, is when you have two different keys that points to the same location (i.e. to the same index)\nin the underlying array of the hashtable. This might happen depending on the characteristics of the hash function\nthat is being used in the hashtable. Some implementations of the hashtable will actively deal with collisions,\nmeaning that, they will handle this case in some way. For example, the hashtable\nmight transform all buckets into linked lists. Because with a liked list you can store\nmultiple values into a single bucket.\n\nThere are different techniques to handle collisions in hashtables, which I will not describe\nin this book, because it is not our main scope here. But you can find a good description of\nsome of the most commom techniques at the Wikipedia page of hashtables [@wikipedia_hashtables].\n\n\n### Hashtables in Zig {#sec-hashmap}\n\nThe Zig Standard Library provides different implementations of a hashtable,\nlike the struct `HashMap`. Each implementation have it's own cons and pros, which we will\ndiscuss later on, and all of them are available through the `std.hash_map` module.\n\nThe `HashMap` struct is a general-purpose hashtable,\nwhich have very fast operations (lookup, insertion, delete), and also,\nquite high load factors for low memory usage. You can create and provide a context object\nto the `HashMap` constructor. This context object allows you to tailor\nthe behaviour of the hashtable itself, because you can\nprovide a hash function implementation to be used by the hashtable\nthrough this context object.\n\nBut let's not worry about this context object now, because it is meant to be used\nby \"experts in the field of hashtables\". Since we are most likely not\nexperts in this field, we are going to take the easy way to create\na hashtable. Which is by using the `AutoHashMap()` function.\n\n\nThis `AutoHashMap()` function is essentially a \"create a hashtable object that uses the default settings\"\ntype of function. It chooses a context object, and, therefore, a hash function implementation,\nautomatically for you. This function receives two data types as input, the first data type is the data type of the keys\nthat will be used in this hashtable, while the second data type is the data type of that data that will be\nstored inside the hashtable, that is, the data type of the values to be stored.\n\nIn the example below, we are providing the data type `u32` in the first argument, and `u16` in the second argument of this\nfunction. It means that we are going to use `u32` values as keys in this hashtable, while `u16` values are the actual values\nthat are going to be stored into this hashtable.\nAt the end of this process, the `hash_table` object contains a `HashMap` object as output\nthat uses the default context, and the default load factor.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n std.debug.print(\n \"Value at key 50050: {d}\\n\",\n .{hash_table.get(50050).?}\n );\n\n if (hash_table.remove(57709)) {\n std.debug.print(\n \"Value at key 57709 succesfully removed!\\n\",\n .{}\n );\n }\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n}\n```\n:::\n\n\n\n\n\n```\nN of values stored: 3\nValue at key 50050: 55\nValue at key 57709 succesfully removed!\nN of values stored: 2\n```\n\nYou can add/put new values into the hashtable by using the `put()` method. The first argument\nis the key to be used, and the second argument is the actual value that you want to store inside\nthe hashtable. In the example below, we first add the value 89 using the key 54321, next, we add\nthe value 55 using the key 50050, etc.\n\nNotice that we used the method `count()` to see how many values are currently stored in the\nhashtable. After that, we also used the `get()` method to access (or look) at the value stored in\nthe position identified by the key 500050. The output of this `get()` method is an optional value,\nand that is why we use the `?` method at the end to get access to the actual value.\n\nAlso notice that we can remove (or delete) values from a hashtables by using the `remove()` method.\nYou provide the key that identifies the value that you want to delete, then, the method will\ndelete this value and return a `true` value as output. This `true` value essentially tells us\nthat the method succesfully deleted the value.\n\nBut this delete operation might not be always successful. For example, you might provide the wrong\nkey to this method. I mean, maybe you provide\n(either intentionally or unintentionally) a key that points to an empty bucket,\ni.e. a bucket that still doesn't have a value in it.\nIn this case, the `remove()` method would return a `false` value.\n\n\n\n### Iterating through the hashtable\n\nIterating through the keys and values that are currently being stored in\nthe hashtable is a very commom need.\nYou can do that in Zig by using an iterator object that can iterate\nthrough the elements of you hashtable object.\n\nThis iterator object works like any other iterator object that you would\nfind in languages such as C++ and Rust. It is basically a pointer object\nthat points to some value in the container, and has a `next()` method\nthat you can use to navigate (or iterate) through the next values in the\ncontainer.\n\nYou can create such iterator object by using the `iterator()` method of the hashtable object.\nThis method returns an iterator object, from which you can use the `next()` method in conjunction\nwith a while loop to iterate through the elements of your hashtable. The `next()` method returns an optional\n`Entry` value, and therefore, you must unwrap this optional value to get the actual `Entry` value\nfrom which you can access the key and also the value identified by this key.\n\nWith this `Entry` value at hand, you can access the key of this current entry by using the `key_ptr`\nattribute and dereferencing the pointer that lives inside of it, while the value identified by this\nkey is accessed through the `value_ptr` attribute instead, which is also a pointer to be dereferenced.\nThe code example below demonstrates the use of these elements:\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n\n var it = hash_table.iterator();\n while (it.next()) |kv| {\n // Access the current key\n std.debug.print(\"Key: {d} | \", .{kv.key_ptr.*});\n // Access the current value\n std.debug.print(\"Value: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n\n\n\n```\nKey: 54321 | Value: 89\nKey: 50050 | Value: 55\nKey: 57709 | Value: 41\n```\n\n\nIf you want to iterate through only the values or the keys of your hashtable,\nyou can create a key iterator or a value iterator object. These are also iterator\nobjects, which have the same `next()` method that you can use to iterate through the\nsequence of values.\n\nKey iterators are created from the `keyIterator()` method of your\nhashtable object, while value iterators are created from the `valueIterator()` method.\nAll you have to do is to unwrap the value from the `next()` method and deference it\ndirectly to access the key or value that you iterating over.\nThe code example below demonstrates what would this be for a key iterator,\nbut you can replicate the same logic to a value iterator.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar kit = hash_table.keyIterator();\nwhile (kit.next()) |key| {\n std.debug.print(\"Key: {d}\\n\", .{key.*});\n}\n```\n:::\n\n\n\n\n\n```\nKey: 54321\nKey: 50050\nKey: 57709\n```\n\n\n### The `ArrayHashMap` hashtable {#sec-array-map}\n\nIf you need to iterate through the elements of your hashtable constantly,\nyou might want to use the `ArrayHashMap` struct for your specific case,\ninstead of going with the usual and general-purpose `HashMap` struct.\n\nThe `ArrayHashMap` struct creates a hashtable that is faster to iterate over.\nThat is why this specific type of hashtable might be valuable to you.\nSome other properties of a `ArrayHashMap` hashtable are:\n\n- the order of insertion is preserved. So the order of the values you find while iterating through this hashtable\nare actually the order in which these values were inserted in the hashtable.\n\n- the key-value pairs are stored sequentially, one after another.\n\n\nYou can create an `ArrayHashMap` object by using, once again, a helper function that\nchooses automatically for you a hash function implementation. This is the\n`AutoArrayHashMap()` function, which works very similarly to the `AutoHashMap()`\nfunction that we presented at @sec-hashmap.\n\nYou provide two data types to this function. The data type of the keys that will be\nused in this hashtable, and the data type of the values that will be stored in\nthis hashtable.\n\nAn `ArrayHashMap` object have essentially the exact same methods from the `HashMap` struct.\nSo you can insert new values into the hashtable by using the `put()` method, you can look (or get)\na value from the hashtable by using the `get()` method. But the `remove()` method is not available\nin this specific type of hashtable.\n\nIn order to delete values from the hashtable, you would use the same methods that you find in\nan `ArrayList` object, i.e. a dynamic array. I presented these methods at @sec-dynamic-array-remove,\nwhich are the `swapRemove()` and `orderedRemove()` methods. These methods have here the same meaning, or,\nthe same effect that they have in an `ArrayList` object.\n\nThis means that, with `swapRemove()` you remove the value from the hashtable, but you do not preserve\nthe order in which the values were inserted into the structure. While `orderedRemove()` is capable\nof retaining the insertion order of these values.\n\nBut instead of providing an index as input to `swapRemove()` or `orderedRemove()`, like I described\nat @sec-dynamic-array-remove, these methods here in an `ArrayHashMap` take a key as input, like\nthe `remove()` method from a `HashMap` object. If you want to provide an index as input, instead\nof a key, you should use the `swapRemoveAt()` and `orderedRemoveAt()` methods.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar hash_table = AutoArrayHashMap(u32, u16)\n .init(allocator);\ndefer hash_table.deinit();\n```\n:::\n\n\n\n\n\n\n\n### The `StringHashMap` hashtable {#sec-string-hash-map}\n\nOne thing that you will notice in the other two types of hashtables that I\npresented in the last sections, is that neither of them accepts a slice data type\nin their keys.\nWhat this means is that you cannot use a slice value to represent a key in\nthese types of hashtable.\n\nThe most obvious consequence of this, is that you cannot use strings as keys\nin these hashtables. But is extremely commom to use string values as keys\nin hashtables.\n\nTake this very simple Javascript code snippet as an example. We are creating\na simple hashtable object named `people`. Then, we add a new entry to this\nhashtable, which is identified by the string `'Pedro'`. This string is the\nkey in this case, while the object containing different personal information such as\nage, height and city, is the value to be stored in the hashtable.\n\n```js\nvar people = new Object();\npeople['Pedro'] = {\n 'age': 25,\n 'height': 1.67,\n 'city': 'Belo Horizonte'\n};\n```\n\nThis pattern of using strings as keys is very commom in\nall sorts of situations. That is why the Zig Standard Library offers a\nspecific type of hashtable for this purpose, which is created through the `StringHashMap()` function.\nThis function creates a hashtable that uses strings as keys. The only input of this\nfunction is the data type of the values that will be stored into this hashtable.\n\nIn the example below, I'm creating a hashtable to store the ages of different people.\nThe keys to be used in this hashtable are the names of each person, while the value stored in the\nhashtable is the age of the person identified by the key.\n\nThat is why I provide the `u8` data type (which is the data type used by the age values) as input to this `StringHashMap()` function.\nAs the result, it creates a hashtable that uses string values as keys, and, that stores\n`u8` values in it. Notice that an allocator object is provided at the `init()` method of the\nresulting object from the `StringHashMap()` function.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var ages = std.StringHashMap(u8).init(allocator);\n defer ages.deinit();\n\n try ages.put(\"Pedro\", 25);\n try ages.put(\"Matheus\", 21);\n try ages.put(\"Abgail\", 42);\n\n var it = ages.iterator();\n while (it.next()) |kv| {\n std.debug.print(\"Key: {s} | \", .{kv.key_ptr.*});\n std.debug.print(\"Age: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n\n\n\n```\nKey: Pedro | Age: 25\nKey: Abgail | Age: 42\nKey: Matheus | Age: 21\n```\n\n\n### The `StringArrayHashMap` hashtable\n\nThe Zig Standard Library also provides a type of hashtable that mix the cons and pros of the\ntypes of hashtables that were presented on the previous two sections. That is, a hashtable\nthat uses strings as keys, but also have the advantages from the `ArrayHashMap` struct.\nIn other words, you can have a hashtable that is fast to iterate over,\nthat preserves insertion order, and also, that uses strings as keys.\n\nYou can create such type of hashtable by using the `StringArrayHashMap()` function.\nThis function accepts a data type as input, which is the data type of the values that are\ngoing to be stored inside this hashtable, in the same style as the function presented\nat @sec-string-hash-map.\n\nYou can insert new values into this hashtable by using the same `put()` method that\nI presented at @sec-string-hash-map. And you can also get values from the hashtable\nby using the same `get()` method that I exposed on previous sections.\nLike it's `ArrayHashMap` brother, to delete values from this specific type of hashtable,\nwe also use the `orderedRemove()` and `swapRemove()` methods, with the same effects that\nI described at @sec-array-map.\n\nIf we take the code example that was exposed at @sec-string-hash-map, we can\nachieve the exact same result with `StringArrayHashMap()`. All we have to do\nis to change the use of `StringHashMap()` to `StringArrayHashMap()` at the\nfifth line in this code example. It would change to this:\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar ages = std.StringArrayHashMap(u8).init(allocator);\n```\n:::\n\n\n\n\n\n\n\n## Linked lists\n\nThe Zig Standard Library provides implementation for both single and doubly linked lists.\nA linked list is a linear data structure that looks like a chain, or, a rope.\nThe main advantage of this data structure is that you normally have fast\ninsertion and deletion operations. But, as a disadvantage, iterating through\nthis data structure is usually not so fast as iterating through an array.\n\nThe idea behind a linked list is basically build a structure that concists of a series of nodes\nconnected to each other by pointers. This means that linked lists are usually not contiguos\nin memory, because each node might be south in memory, but the next node might be north\nin memory, then the next node might be left in memory, anyway, you get it, they can be anywhere.\n\nAt @fig-linked-list we can see a diagram of a singly linked list. Notice that we begin with\na first node. This first node is usually called \"the head of the linked list\". Then, from this\nfirst node we uncover the remaining nodes in the structure, by following the locations pointed\nby the pointers.\n\nEvery node have two things in it. It have the value that is stored in the current node\n, and also have a pointer. This pointer points to the next node in the list. If this pointer\nis null, then, it means that we reached the end of our linked list.\n\n![A diagram of a singly linked list.](./../Figures/linked-list.png){#fig-linked-list}\n\n\nAt @fig-linked-list2 we can see a diagram of a doubly linked list. The only thing that really\nchanges is that every node in the linked list have both a pointer to the previous node,\nand, a pointer to the next node. So every node have now two pointers in it. These are\nusually called the `prev` (for \"previous\") and `next` (for \"next\") pointers of the node.\n\nIn the singly linked list example, we had only one single pointer in each node, and this singular\npointer was always pointing to the next node in the sequence. In other words, singly linked lists\nnormally have only the `next` pointer in them.\n\n![A diagram of a doubly linked list.](./../Figures/doubly-linked-list.png){#fig-linked-list2}\n\n\n\nLinked lists are available in Zig through the functions `SinglyLinkedList()` and\n`DoublyLinkedList()`, for \"singly linked lists\" and \"doubly linked lists\", respectively. These functions are\nactually generic functions, which we are going to talk more about at @sec-generic-fun.\n\nFor now, just understand that, in order to create a linked list object,\nwe begin by providing a data type to these functions. This data type defines\nthe type of data that this linked list will store. In the example below,\nwe are creating a singly linked list capable of storing `u32` values.\nSo each node in this linked list will store a `u32` value.\n\nBoth the `SinglyLinkedList()` and `DoublyLinkedList()` functions returns a type, i.e. a struct definition, as result. This means that\nthe object `Lu32` is actually a type definition, or a struct definition. It defines\nthe type \"singly linked list of `u32` values\".\n\nSo now that we have the definition of the struct, we have to instantiate a `Lu32` object.\nWe normally instantiate struct objects in Zig by using an `init()` method.\nBut in this case, we are instantiating the struct directly, by using an empty\n`struct` literal, in the expression `Lu32{}`.\n\nIn this example, we first create multiple node objects, and after we create them,\nwe start to insert and connect these nodes to build the linked list, using the\n`prepend()` and `insertAfter()` methods. Notice that the `prepend()` method\nis a method from the linked list object, while the `insertAfter()` is a method\npresent in the node objects.\n\nIn essence, the `prepend()` method inserts a node at the beginning of the linked\nlist. In other words, the node that you provide to this method, becomes the new\n\"head node\" of the linked list. It becomes the first node in the list (see @fig-linked-list).\n\nOn the other side, the `insertAfter()` method is used to basically connect two nodes together.\nWhen you provide a node to this method, it creates a pointer to this input node,\nand stores this pointer in the current node, from which the method was called from.\nIn other words, this method creates the pointer that connects these two nodes together\nand stores it in the `next` attribute of the current node.\n\nSince doubly linked list have both a `next` and a `prev` pointers in each node,\nreferring to the next and previous nodes in the sequence, respectively,\nas I described at @fig-linked-list2, a node object created from\na `DoublyLinkedList()` object would have both a\n`insertBefore()` (for `prev`) and a `insertAfter()` (for `next`) methods\navailable.\n\nThis means that, if we used a doubly linked list, we could use the `insertBefore()` method\nto store the pointer to the input node in the `prev` attribute. This would put the input\nnode as the \"previous node\", or, the node before the current node. The `insertAfter()` method\nhave \"after\" in it's name to indicate that this method puts the pointer created to the input\nnode in the `next` attribute of the current node, and as the result, the input node becomes\nthe \"next node\" of the current node.\n\nSince we are using a singly linked list in this example, we have only the `insertAfter()` method\navailable in the node objects that we create from our `Lu32` type.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst SinglyLinkedList = std.SinglyLinkedList;\nconst Lu32 = SinglyLinkedList(u32);\n\npub fn main() !void {\n var list = Lu32{};\n var one = Lu32.Node{ .data = 1 };\n var two = Lu32.Node{ .data = 2 };\n var three = Lu32.Node{ .data = 3 };\n var four = Lu32.Node{ .data = 4 };\n var five = Lu32.Node{ .data = 5 };\n\n list.prepend(&two); // {2}\n two.insertAfter(&five); // {2, 5}\n list.prepend(&one); // {1, 2, 5}\n two.insertAfter(&three); // {1, 2, 3, 5}\n three.insertAfter(&four); // {1, 2, 3, 4, 5}\n}\n```\n:::\n\n\n\n\n\n\nThere are other methods available from the linked list object, depending if this object is\na singly linked list or a doubly linked list, that might be very useful for you, like:\n\n- `remove()` to remove a specific node from the linked list.\n- `popFirst()` to remove the first node from the linked list.\n- if singly linked list, `len()` to count how many nodes there is in the linked list.\n- if doubly linked list, checkout the `len` attribute to see how many nodes there is in the linked list.\n- if singly linked list, `popFirst()` to remove the first node from the linked list.\n- if doubly linked list, `pop()` and `popFirst()` to remove the last and first nodes from the linked list, respectively.\n- if doubly linked list, `append()` to add a new node to end of the linked list (i.e. inverse of `prepend()`).\n\n\n\n## Multi array structure\n\nZig introduces a new data structure called `MultiArrayList()`. It is a different version of the dynamic array\nthat we have introduced at @sec-dynamic-array. The difference between this structure and the `ArrayList()`\nthat we know from @sec-dynamic-array, is that `MultiArrayList()` creates a separate dynamic array\nfor each field of the struct that you provide as input.\n\nConsider the following code example. We create a new custom struct called `Person`. This\nstruct contains three different data members, or, three different fields. As consequence,\nwhen we provide this `Person` data type as input to `MultiArrayList()`, this\ncreates three different arrays. One array for each field in the struct.\n\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst Person = struct {\n name: []const u8,\n age: u8,\n height: f32,\n};\nconst PersonArray = std.MultiArrayList(Person);\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var people = PersonArray{};\n defer people.deinit(allocator);\n\n try people.append(allocator, .{\n .name = \"Auguste\", .age = 15, .height = 1.54\n });\n try people.append(allocator, .{\n .name = \"Elena\", .age = 26, .height = 1.65\n });\n try people.append(allocator, .{\n .name = \"Michael\", .age = 64, .height = 1.87\n });\n}\n```\n:::\n\n\n\n\n\nIn other words, instead of creating an array of \"persons\", the `MultiArrayList()` function\ncreates a \"struct of arrays\". Each data member of this struct is a different array that stores\nthe values of a specific field from the `Person` struct values that are added (or, appended) to the \"struct of arrays\".\n\nThe @fig-multi-array exposed below presents a diagram that describes the `PersonArray` struct\nthat we have created in the previous code example. Notice that the values of the data members\npresent in each of the three `Person` values that we have appended into the `PersonArray` object\nthat we have instantiated, are scattered across three different internal arrays of the `PersonArray` object.\n\n![A diagram of the `PersonArray` struct.](./../Figures/multi-array.png){#fig-multi-array}\n\nYou can easily access each of these arrays separately, and iterate over the values of each array.\nFor that, you will need to call the `items()` method from the `PersonArray` object, and provide as input\nto this method, the name of the field that you want to iterate over.\nIf you want to iterate through the `.age` array for example, then, you need to call `items(.age)` from\nthe `PersonArray` object, like in the example below:\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nfor (people.items(.age)) |*age| {\n try stdout.print(\"Age: {d}\\n\", .{age.*});\n}\n```\n:::\n\n\n\n\n\n```\nAge: 15\nAge: 26\nAge: 64\n```\n\n\nIn the above example, we are iterating over the values of the `.age` array, or,\nthe internal array of the `PersonArray` object that contains the values of the `age`\ndata member from the `Person` values that were added to the multi array struct.\n\nIn this example we are calling the `items()` method directly from the `PersonArray`\nobject. However, it is recommended on most situations to call this `items()` method\nfrom a \"slice object\", which you can create from the `slice()` method.\nThe reason for this is that calling `items()` multiple times have better performance\nif you use a slice object.\n\nIn other words, if you are planning to access only one of the\ninternal arrays from your \"multi array struct\", it is fine to call `items()` directly\nfrom the multi array object. But if you need to access many of the internal arrays\nfrom your \"multi array struct\", then, you will likely need to call `items()` more\nthan once, and, in such circustance, is better to call `items()` through a slice object.\nThe example below demonstrates the use of such object:\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar slice = people.slice();\nfor (slice.items(.age)) |*age| {\n age.* += 10;\n}\nfor (slice.items(.name), slice.items(.age)) |*n,*a| {\n try stdout.print(\n \"Name: {s}, Age: {d}\\n\", .{n.*, a.*}\n );\n}\n```\n:::\n\n\n\n\n\n```\nName: Auguste, Age: 25\nName: Elena, Age: 36\nName: Michael, Age: 74\n```\n\n\n## Conclusion\n\nThere are many other data structures that I did not presented here.\nBut you can check them out at the offical Zig Standard Library documentation page.\nActually, when you get into the [homepage of the documentation](https://ziglang.org/documentation/master/std/#)[^home], the first thing\nthat appears to you in this page, is a list of types and data structures.\n\n\nIn this section you can see a list of the many different data structures available in\nthe Zig Standard Library. There are some very specific structures in this list, like a\n[`BoundedArray` struct](https://ziglang.org/documentation/master/std/#std.bounded_array.BoundedArray)[^bounded]\n, but there is also some more general structures, such as a\n[`PriorityQueue` struct](https://ziglang.org/documentation/master/std/#std.priority_queue.PriorityQueue)[^priority].\n\n\n[^home]: \n[^priority]: .\n[^bounded]: \n\n\n\n\n\n\n", - "supporting": [], + "markdown": "---\nengine: knitr\nknitr: true\nsyntax-definition: \"../Assets/zig.xml\"\n---\n\n\n\n\n\n\n\n\n# Data Structures\n\nIn this chapter, we are going to discuss some Data Structures that are available from\nthe Zig Standard Library, specially `ArrayList` and also `HashMap`. I'm also want\nto talk about one of the key features of Zig in this chapter, which is `comptime`, and\nhow we can use it to create generics in Zig.\n\n\n## Dynamic Arrays {#sec-dynamic-array}\n\nIn high level languages, arrays are usually dynamic. They easily grow\nin size when they have to, and you don't need to worry about it.\nIn contrast, arrays in low level languages are usually static by default.\nThis is the reality of C, C++, Rust and also Zig. Static arrays were presented at\n@sec-arrays, but in this section, we are going to talk about dynamic arrays.\n\nDynamic arrays are simply arrays that can grow in size during the runtime\nof your program. Most low level languages offer some implementation of\na dynamic array in their standard library. C++ have `std::vector`, Rust have `Vec`,\nand Zig have `std.ArrayList`.\n\nThe `std.ArrayList` struct provides a contiguous and growable array for you.\nIt works like any other dinamic array, it allocates a contiguous block of memory, and when this block have no space left,\n`ArrayList` allocates another contiguous and bigger block of memory, copies the\nelements to this new location, and erases (or frees) the previous block of memory.\n\n\n### Capacity vs Length\n\nWhen we talk about dynamic arrays, we have two similar concepts that\nare very essential to how a dynamic array works behind the hood.\nThese concepts are *capacity* and *length*. In some contexts, specially\nin C++, *length* is also called of *size*.\n\nAlthough they look similar, these concepts represent different things\nin the context of dynamic arrays. *Capacity* is the number of items (or elements)\nthat your dynamic array can currently hold without the need to allocate more memory.\n\nIn contrast, the *length* refers to how many elements in the array\nare currently being used, or, in other words, how many elements in this array\nthat you assigned a value to. Every dynamic array works around\na block of allocated memory that represents an array with total capacity of $n$ elements,\nbut only a portion of these $n$ elements are being used most of the time. This portion\nof $n$ is the *length* of the array. So every time you append a new value\nto the array, you are incrementing it's *length* by one.\n\nThis means that a dynamic array usually works with an extra margin, or, an extra space\nwhich is currently empty, but it is waiting and ready to be used. This \"extra space\"\nis essentially the difference between *capacity* and *length*. *Capacity* represents\nthe total number of elements that the array can hold without the need to re-allocate\nor re-expand the array, while the *length* represents how much of this capacity\nis currently being used to hold/store values.\n\n@fig-capacity-length presents this idea visually. Notice that, at first,\nthe capacity of the array is greater than the length of the array.\nSo, the dynamic array have extra space that is currently empty, but it\nis ready to receive a value to be stored.\n\n![Difference between capacity and length in a dynamic array](./../Figures/dynamic-array.png){#fig-capacity-length}\n\nWe can also see at @fig-capacity-length that, when *length* and *capacity* are equal, it means that the array have no space left.\nWe reached the roof of our capacity, and because of that, if we want to store more values\nin this array, we need to expand it. We need to get a bigger space that can hold more values\nthat we currently have.\n\nA dynamic array works by expanding the underlying array, whenever the *length* becomes equal\nto the *capacity* of the array. It basically allocates a new contiguos block of memory that is bigger\nthan the previous one, then, it copies all values that are currently being stored to this new\nlocation (i.e. this new block of memory), then, it frees the previous block of\nmemory. At the end of this process, the new underlying array have a bigger *capacity*, and, therefore,\nthe *length* becomes once again smaller than the *capacity* of the array.\n\nThis is the cycle of an dynamic array. Notice that, throughout this cycle, the *capacity* is always\neither equal to or higher than the *length* of the array. If youh have an `ArrayList` object, let's suppose\nyou named it of `buffer`, you can check the current capacity of your array by accessing the `capacity`\nattribute of your `ArrayList` object, while the current *length* of it is available through the `items.len`\nattribute of your `ArrayList` object.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\n// Check capacity\nbuffer.capacity;\n// Check length\nbuffer.items.len;\n```\n:::\n\n\n\n\n### Creating an `ArrayList` object\n\nIn order to use `ArrayList`, you must provide an allocator object to it.\nRemember, Zig does not have a default memory allocator. And as I described at @sec-allocators, all memory\nallocations must be done by allocator objects that you define, that\nyou have control over. In our example here, I'm going to use\na general purpose allocator, but you can use any other allocator\nof your preference.\n\nWhen you initialize an `ArrayList` object, you must provide the data type of the elements of\nthe array. In other words, this defines the type of data that this array (or container) will\nstore. Therefore, if I provide the `u8` type to it, then, I will create a dynamic\narray of `u8` values. However, if I provide a struct that I defined instead, like the struct `User`\nfrom @sec-structs-and-oop, then, a dynamic array of `User` values\nwill be created. In the example below, with the expression `ArrayList(u8)` we\nare creating a dynamic array of `u8` values.\n\nAfter you provide the data type of the elements of the array, you can initialize\nan `ArrayList` object by either using the `init()` or the `initCapacity()` method.\nThe former method receives only the allocator object\nas input, while the latter method receives both the allocator object and a capacity number as inputs.\nWith the latter method, you not only initialize the struct, but you\nalso set the starting capacity of the allocated array.\n\nUsing the `initCapacity()` method is the preferred way to initialize your dynamic array.\nBecause reallocations, or, in other words, the process of expanding the capacity of the array,\nis always a high cost operation. You should take any possible opportunity to avoid reallocations in\nyour array. If you know how much space your array needs to occupy at the beginning,\nyou should always use `initCapacity()` to create your dynamic array.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n```\n:::\n\n\n\n\n\nIn the example above, the `buffer` object starts as an array of 100 elements. If this\n`buffer` object needs to create more space to accomodate more elements during the runtime of your program, the `ArrayList`\ninternals will perform the necessary actions for you automatically.\nAlso notice the `deinit()` method being used to destroy the `buffer` object at the\nend of the current scope, by freeing all the memory that was allocated for the dynamic\narray stored in this `buffer` object.\n\n\n### Adding new elements to the array\n\nNow that we created our dynamic array, we can start to use it. You can append (a.k.a \"add\")\nnew values to this array by using the `append()` method. This method works the same way\nas the `append()` method from a Python list, or, the `emplace_back()` method from `std::vector` of C++.\nYou provide a single value to this method, and the method appends this value to the array.\n\nYou can also use the `appendSlice()` method to append multiple values at once. You provide\na slice (slices were described at @sec-arrays) to this method, and the method adds all values present\nin this slice to your dynamic array.\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\ntry buffer.append('H');\ntry buffer.append('e');\ntry buffer.append('l');\ntry buffer.append('l');\ntry buffer.append('o');\ntry buffer.appendSlice(\" World!\");\n```\n:::\n\n\n\n\n### Removing elements from the array {#sec-dynamic-array-remove}\n\nYou can use the `pop()` method to \"pop\" or remove\nthe last element in the array. Is worth noting that this method\ndo not change the capacity of the array. It just deletes or erases\nthe last value stored in the array.\n\nAlso, this method returns as result the value that got deleted. That is, you can\nuse this method to both get the last value in the array, and also, remove\nit from the array. It is a \"get and remove value\" type of method.\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst exclamation_mark = buffer.pop();\n```\n:::\n\n\n\n\nNow, if you want to remove specific elements from specific positions\nof your array, you can use the `orderedRemove()` method from your\n`ArrayList` object. With this method, you can provide an index as input,\nthen, the method will delete the value that is at this index in the array.\nThis effectively reduces the *length* of the array everytime you execute\nan `orderedRemove()` operation.\n\nIn the example below, we first create an `ArrayList` object, and we fill it\nwith numbers. Then, we use `orderedRemove()` to remove the value at\nindex 3 in the array, two consecutive times.\n\nAlso, notice that we are assigning the result of `orderedRemove()` to the\nunderscore character. So we are discarding the result value of this method.\nAs the result value, the `orderedRemove()` method returns the value that\ngot deleted, in a similar style to the `pop()` method.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 100);\ndefer buffer.deinit();\n\nfor (0..10) |i| {\n const index: u8 = @intCast(i);\n try buffer.append(index);\n}\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\n_ = buffer.orderedRemove(3);\n_ = buffer.orderedRemove(3);\n\nstd.debug.print(\n \"{any}\\n\", .{buffer.items}\n);\nstd.debug.print(\n \"{any}\\n\", .{buffer.items.len}\n);\n```\n:::\n\n\n\n\n```\n{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }\n{ 0, 1, 2, 5, 6, 7, 8, 9 }\n8\n```\n\nOne key characteristic about `orderedRemove()` is that it preserves the order\nof the values in the array. So, it deletes the value that you asked it to\nremove, but it also makes sure that the order of the values that remain in the array\nstay the same as before.\n\nNow, if you don't care about the order of the values, for example, maybe you want to treat\nyour dynamic array as a set of values, like the `std::unordered_set`\nstructure from C++, you can use the `swapRemove()` method instead. This method\nworks similarly to the `orderedRemove()` method. You give an index to this\nmethod, then, it deletes the value that is at this index in the array.\nBut this method does not preserve the original order of the values that remain\nin the array. As a result, `swapRemove()` is, in general, faster than `orderedRemove()`.\n\n\n### Inserting elements at specific indexes\n\nWhen you need to insert values in the middle of your array,\ninstead of just appending them to the end of the array, you need to use\nthe `insert()` and `insertSlice()` methods, instead of\nthe `append()` and `appendSlice()` methods.\n\nThese two methods work very similarly to `insert()` and `insert_range()`\nfrom the C++ vector class. You provide an index to these methods,\nand they insert the values that you provide at that index in the array.\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar gpa = std.heap.GeneralPurposeAllocator(.{}){};\nconst allocator = gpa.allocator();\nvar buffer = try std.ArrayList(u8)\n .initCapacity(allocator, 10);\ndefer buffer.deinit();\n\ntry buffer.appendSlice(\"My Pedro\");\ntry buffer.insert(4, '3');\ntry buffer.insertSlice(2, \" name\");\nfor (buffer.items) |char| {\n try stdout.print(\"{c}\", .{char});\n}\n```\n:::\n\n\n\n\n```\nMy name P3edro\n```\n\n\n### Conclusion\n\nIf you feel the lack of some other method, I recommend\nyou to read the [official documentation for the `ArrayListAligned`](https://ziglang.org/documentation/master/std/#std.array_list.ArrayListAligned)[^zig-array2]\nstruct, which describes most of the methods available\nthrough the `ArrayList` object.\n\nYou will notice that there is a lot other methods in this page that\nI did not described here, and I recommend you to explore these methods,\nand understand how they work.\n\n[^zig-array2]: \n\n\n\n## Maps or HashTables\n\nSome professionals know this type of data structure by different terms, like \"map\", \"hashmap\" or \"associative arrays\". But most professionals\nknow this structure by the name *hashtable*.\nEvery programming language normally have some implementation of a hashtable in their\nstardard libraries. Python have `dict()`, C++ have `std::map` and `std::unordered_map`, Rust\nhave `HashMap`, Javascript have `Object()` and `Map()`,\nC# have `Hashtable()`, etc.\n\n\n\n### What is a hashtable?\n\nA hashtable is a data structure based on key-value pairs.\nYou provide a key and a value to this structure, then, the hashtable will store\nthe input value at a location that can be identified by the input\nkey that you provided.\nIt does that by using an underlying array and a hash function.\nThese two components are essential to how a hashtable works.\n\nUnder the hood, the hashtable contains an array. This array is where the values\nare stored, and the elements of this array are usually called of *buckets*.\nSo the values that you provide to the hashtable are stored inside buckets,\nand you access each bucket by using an index.\n\nWhen you provide a key to a hashtable, it passes this key to the\nhash function. This hash function uses some sort of hashing algorithm to transform\nthis key into an index. This index is actually an array index. It is a position\nin the underlying array of the hashtable.\nThis is how a key identifies a specific position (or location) inside the hashtable\nstructure.\n\nSo you provide a key to the hashtable, and this key identifies an specific location\ninside the hastable, then, the hashtable takes the input value that you provided,\nand stores this value in the location identified by the input key that you provided.\nYou could say that the key maps to the value stored in the hashtable. You find\nthe value, by using the key that identifies the location where the value is stored.\nThe @fig-hashtable presents this process visually.\n\n\n![A diagram of a Hashtable. Source: Wikipedia, the free encyclopedia.](./../Figures/hashtable.svg){#fig-hashtable}\n\n\nThe operation described in the previous paragraph is normally called an *insertion* operation.\nBecause you are inserting new values into the hashtable.\nBut there are other types of operations in hashtables such as *delete* and *lookup*.\nDelete is self describing, it is when you delete (or remove) a value from the hashtable.\nWhile lookup corresponds to when you retrieve (or look at) a value that is stored in\nthe hashtable, by using the key that identifies the location where this value is stored.\n\nSometimes, instead of storing the values directly, the underlying array of the hashtable might be an array of pointers,\ni.e. the buckets of the array stores pointers that points to the value,\nor also, may be an array of linked lists.\nThese cases are commom on hashtables that allows duplicate keys, or, in other words,\non hashtables that effectively handle \"collisions\" that may arise from the hash function.\n\nDuplicate keys, or this \"collision\" thing that I'm talking about, is when you have two different keys that points to the same location (i.e. to the same index)\nin the underlying array of the hashtable. This might happen depending on the characteristics of the hash function\nthat is being used in the hashtable. Some implementations of the hashtable will actively deal with collisions,\nmeaning that, they will handle this case in some way. For example, the hashtable\nmight transform all buckets into linked lists. Because with a liked list you can store\nmultiple values into a single bucket.\n\nThere are different techniques to handle collisions in hashtables, which I will not describe\nin this book, because it is not our main scope here. But you can find a good description of\nsome of the most commom techniques at the Wikipedia page of hashtables [@wikipedia_hashtables].\n\n\n### Hashtables in Zig {#sec-hashmap}\n\nThe Zig Standard Library provides different implementations of a hashtable,\nlike the struct `HashMap`. Each implementation have it's own cons and pros, which we will\ndiscuss later on, and all of them are available through the `std.hash_map` module.\n\nThe `HashMap` struct is a general-purpose hashtable,\nwhich have very fast operations (lookup, insertion, delete), and also,\nquite high load factors for low memory usage. You can create and provide a context object\nto the `HashMap` constructor. This context object allows you to tailor\nthe behaviour of the hashtable itself, because you can\nprovide a hash function implementation to be used by the hashtable\nthrough this context object.\n\nBut let's not worry about this context object now, because it is meant to be used\nby \"experts in the field of hashtables\". Since we are most likely not\nexperts in this field, we are going to take the easy way to create\na hashtable. Which is by using the `AutoHashMap()` function.\n\n\nThis `AutoHashMap()` function is essentially a \"create a hashtable object that uses the default settings\"\ntype of function. It chooses a context object, and, therefore, a hash function implementation,\nautomatically for you. This function receives two data types as input, the first data type is the data type of the keys\nthat will be used in this hashtable, while the second data type is the data type of that data that will be\nstored inside the hashtable, that is, the data type of the values to be stored.\n\nIn the example below, we are providing the data type `u32` in the first argument, and `u16` in the second argument of this\nfunction. It means that we are going to use `u32` values as keys in this hashtable, while `u16` values are the actual values\nthat are going to be stored into this hashtable.\nAt the end of this process, the `hash_table` object contains a `HashMap` object as output\nthat uses the default context, and the default load factor.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n std.debug.print(\n \"Value at key 50050: {d}\\n\",\n .{hash_table.get(50050).?}\n );\n\n if (hash_table.remove(57709)) {\n std.debug.print(\n \"Value at key 57709 succesfully removed!\\n\",\n .{}\n );\n }\n std.debug.print(\n \"N of values stored: {d}\\n\",\n .{hash_table.count()}\n );\n}\n```\n:::\n\n\n\n\n```\nN of values stored: 3\nValue at key 50050: 55\nValue at key 57709 succesfully removed!\nN of values stored: 2\n```\n\nYou can add/put new values into the hashtable by using the `put()` method. The first argument\nis the key to be used, and the second argument is the actual value that you want to store inside\nthe hashtable. In the example below, we first add the value 89 using the key 54321, next, we add\nthe value 55 using the key 50050, etc.\n\nNotice that we used the method `count()` to see how many values are currently stored in the\nhashtable. After that, we also used the `get()` method to access (or look) at the value stored in\nthe position identified by the key 500050. The output of this `get()` method is an optional value,\nand that is why we use the `?` method at the end to get access to the actual value.\n\nAlso notice that we can remove (or delete) values from a hashtables by using the `remove()` method.\nYou provide the key that identifies the value that you want to delete, then, the method will\ndelete this value and return a `true` value as output. This `true` value essentially tells us\nthat the method succesfully deleted the value.\n\nBut this delete operation might not be always successful. For example, you might provide the wrong\nkey to this method. I mean, maybe you provide\n(either intentionally or unintentionally) a key that points to an empty bucket,\ni.e. a bucket that still doesn't have a value in it.\nIn this case, the `remove()` method would return a `false` value.\n\n\n\n### Iterating through the hashtable\n\nIterating through the keys and values that are currently being stored in\nthe hashtable is a very commom need.\nYou can do that in Zig by using an iterator object that can iterate\nthrough the elements of you hashtable object.\n\nThis iterator object works like any other iterator object that you would\nfind in languages such as C++ and Rust. It is basically a pointer object\nthat points to some value in the container, and has a `next()` method\nthat you can use to navigate (or iterate) through the next values in the\ncontainer.\n\nYou can create such iterator object by using the `iterator()` method of the hashtable object.\nThis method returns an iterator object, from which you can use the `next()` method in conjunction\nwith a while loop to iterate through the elements of your hashtable. The `next()` method returns an optional\n`Entry` value, and therefore, you must unwrap this optional value to get the actual `Entry` value\nfrom which you can access the key and also the value identified by this key.\n\nWith this `Entry` value at hand, you can access the key of this current entry by using the `key_ptr`\nattribute and dereferencing the pointer that lives inside of it, while the value identified by this\nkey is accessed through the `value_ptr` attribute instead, which is also a pointer to be dereferenced.\nThe code example below demonstrates the use of these elements:\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst AutoHashMap = std.hash_map.AutoHashMap;\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var hash_table = AutoHashMap(u32, u16).init(allocator);\n defer hash_table.deinit();\n\n try hash_table.put(54321, 89);\n try hash_table.put(50050, 55);\n try hash_table.put(57709, 41);\n\n var it = hash_table.iterator();\n while (it.next()) |kv| {\n // Access the current key\n std.debug.print(\"Key: {d} | \", .{kv.key_ptr.*});\n // Access the current value\n std.debug.print(\"Value: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n\n\n```\nKey: 54321 | Value: 89\nKey: 50050 | Value: 55\nKey: 57709 | Value: 41\n```\n\n\nIf you want to iterate through only the values or the keys of your hashtable,\nyou can create a key iterator or a value iterator object. These are also iterator\nobjects, which have the same `next()` method that you can use to iterate through the\nsequence of values.\n\nKey iterators are created from the `keyIterator()` method of your\nhashtable object, while value iterators are created from the `valueIterator()` method.\nAll you have to do is to unwrap the value from the `next()` method and deference it\ndirectly to access the key or value that you iterating over.\nThe code example below demonstrates what would this be for a key iterator,\nbut you can replicate the same logic to a value iterator.\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar kit = hash_table.keyIterator();\nwhile (kit.next()) |key| {\n std.debug.print(\"Key: {d}\\n\", .{key.*});\n}\n```\n:::\n\n\n\n\n```\nKey: 54321\nKey: 50050\nKey: 57709\n```\n\n\n### The `ArrayHashMap` hashtable {#sec-array-map}\n\nIf you need to iterate through the elements of your hashtable constantly,\nyou might want to use the `ArrayHashMap` struct for your specific case,\ninstead of going with the usual and general-purpose `HashMap` struct.\n\nThe `ArrayHashMap` struct creates a hashtable that is faster to iterate over.\nThat is why this specific type of hashtable might be valuable to you.\nSome other properties of a `ArrayHashMap` hashtable are:\n\n- the order of insertion is preserved. So the order of the values you find while iterating through this hashtable\nare actually the order in which these values were inserted in the hashtable.\n\n- the key-value pairs are stored sequentially, one after another.\n\n\nYou can create an `ArrayHashMap` object by using, once again, a helper function that\nchooses automatically for you a hash function implementation. This is the\n`AutoArrayHashMap()` function, which works very similarly to the `AutoHashMap()`\nfunction that we presented at @sec-hashmap.\n\nYou provide two data types to this function. The data type of the keys that will be\nused in this hashtable, and the data type of the values that will be stored in\nthis hashtable.\n\nAn `ArrayHashMap` object have essentially the exact same methods from the `HashMap` struct.\nSo you can insert new values into the hashtable by using the `put()` method, you can look (or get)\na value from the hashtable by using the `get()` method. But the `remove()` method is not available\nin this specific type of hashtable.\n\nIn order to delete values from the hashtable, you would use the same methods that you find in\nan `ArrayList` object, i.e. a dynamic array. I presented these methods at @sec-dynamic-array-remove,\nwhich are the `swapRemove()` and `orderedRemove()` methods. These methods have here the same meaning, or,\nthe same effect that they have in an `ArrayList` object.\n\nThis means that, with `swapRemove()` you remove the value from the hashtable, but you do not preserve\nthe order in which the values were inserted into the structure. While `orderedRemove()` is capable\nof retaining the insertion order of these values.\n\nBut instead of providing an index as input to `swapRemove()` or `orderedRemove()`, like I described\nat @sec-dynamic-array-remove, these methods here in an `ArrayHashMap` take a key as input, like\nthe `remove()` method from a `HashMap` object. If you want to provide an index as input, instead\nof a key, you should use the `swapRemoveAt()` and `orderedRemoveAt()` methods.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar hash_table = AutoArrayHashMap(u32, u16)\n .init(allocator);\ndefer hash_table.deinit();\n```\n:::\n\n\n\n\n\n\n### The `StringHashMap` hashtable {#sec-string-hash-map}\n\nOne thing that you will notice in the other two types of hashtables that I\npresented in the last sections, is that neither of them accepts a slice data type\nin their keys.\nWhat this means is that you cannot use a slice value to represent a key in\nthese types of hashtable.\n\nThe most obvious consequence of this, is that you cannot use strings as keys\nin these hashtables. But is extremely commom to use string values as keys\nin hashtables.\n\nTake this very simple Javascript code snippet as an example. We are creating\na simple hashtable object named `people`. Then, we add a new entry to this\nhashtable, which is identified by the string `'Pedro'`. This string is the\nkey in this case, while the object containing different personal information such as\nage, height and city, is the value to be stored in the hashtable.\n\n```js\nvar people = new Object();\npeople['Pedro'] = {\n 'age': 25,\n 'height': 1.67,\n 'city': 'Belo Horizonte'\n};\n```\n\nThis pattern of using strings as keys is very commom in\nall sorts of situations. That is why the Zig Standard Library offers a\nspecific type of hashtable for this purpose, which is created through the `StringHashMap()` function.\nThis function creates a hashtable that uses strings as keys. The only input of this\nfunction is the data type of the values that will be stored into this hashtable.\n\nIn the example below, I'm creating a hashtable to store the ages of different people.\nThe keys to be used in this hashtable are the names of each person, while the value stored in the\nhashtable is the age of the person identified by the key.\n\nThat is why I provide the `u8` data type (which is the data type used by the age values) as input to this `StringHashMap()` function.\nAs the result, it creates a hashtable that uses string values as keys, and, that stores\n`u8` values in it. Notice that an allocator object is provided at the `init()` method of the\nresulting object from the `StringHashMap()` function.\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var ages = std.StringHashMap(u8).init(allocator);\n defer ages.deinit();\n\n try ages.put(\"Pedro\", 25);\n try ages.put(\"Matheus\", 21);\n try ages.put(\"Abgail\", 42);\n\n var it = ages.iterator();\n while (it.next()) |kv| {\n std.debug.print(\"Key: {s} | \", .{kv.key_ptr.*});\n std.debug.print(\"Age: {d}\\n\", .{kv.value_ptr.*});\n }\n}\n```\n:::\n\n\n\n\n```\nKey: Pedro | Age: 25\nKey: Abgail | Age: 42\nKey: Matheus | Age: 21\n```\n\n\n### The `StringArrayHashMap` hashtable\n\nThe Zig Standard Library also provides a type of hashtable that mix the cons and pros of the\ntypes of hashtables that were presented on the previous two sections. That is, a hashtable\nthat uses strings as keys, but also have the advantages from the `ArrayHashMap` struct.\nIn other words, you can have a hashtable that is fast to iterate over,\nthat preserves insertion order, and also, that uses strings as keys.\n\nYou can create such type of hashtable by using the `StringArrayHashMap()` function.\nThis function accepts a data type as input, which is the data type of the values that are\ngoing to be stored inside this hashtable, in the same style as the function presented\nat @sec-string-hash-map.\n\nYou can insert new values into this hashtable by using the same `put()` method that\nI presented at @sec-string-hash-map. And you can also get values from the hashtable\nby using the same `get()` method that I exposed on previous sections.\nLike it's `ArrayHashMap` brother, to delete values from this specific type of hashtable,\nwe also use the `orderedRemove()` and `swapRemove()` methods, with the same effects that\nI described at @sec-array-map.\n\nIf we take the code example that was exposed at @sec-string-hash-map, we can\nachieve the exact same result with `StringArrayHashMap()`. All we have to do\nis to change the use of `StringHashMap()` to `StringArrayHashMap()` at the\nfifth line in this code example. It would change to this:\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar ages = std.StringArrayHashMap(u8).init(allocator);\n```\n:::\n\n\n\n\n\n\n## Linked lists\n\nThe Zig Standard Library provides implementation for both single and doubly linked lists.\nA linked list is a linear data structure that looks like a chain, or, a rope.\nThe main advantage of this data structure is that you normally have fast\ninsertion and deletion operations. But, as a disadvantage, iterating through\nthis data structure is usually not so fast as iterating through an array.\n\nThe idea behind a linked list is basically build a structure that concists of a series of nodes\nconnected to each other by pointers. This means that linked lists are usually not contiguos\nin memory, because each node might be south in memory, but the next node might be north\nin memory, then the next node might be left in memory, anyway, you get it, they can be anywhere.\n\nAt @fig-linked-list we can see a diagram of a singly linked list. Notice that we begin with\na first node. This first node is usually called \"the head of the linked list\". Then, from this\nfirst node we uncover the remaining nodes in the structure, by following the locations pointed\nby the pointers.\n\nEvery node have two things in it. It have the value that is stored in the current node\n, and also have a pointer. This pointer points to the next node in the list. If this pointer\nis null, then, it means that we reached the end of our linked list.\n\n![A diagram of a singly linked list.](./../Figures/linked-list.png){#fig-linked-list}\n\n\nAt @fig-linked-list2 we can see a diagram of a doubly linked list. The only thing that really\nchanges is that every node in the linked list have both a pointer to the previous node,\nand, a pointer to the next node. So every node have now two pointers in it. These are\nusually called the `prev` (for \"previous\") and `next` (for \"next\") pointers of the node.\n\nIn the singly linked list example, we had only one single pointer in each node, and this singular\npointer was always pointing to the next node in the sequence. In other words, singly linked lists\nnormally have only the `next` pointer in them.\n\n![A diagram of a doubly linked list.](./../Figures/doubly-linked-list.png){#fig-linked-list2}\n\n\n\nLinked lists are available in Zig through the functions `SinglyLinkedList()` and\n`DoublyLinkedList()`, for \"singly linked lists\" and \"doubly linked lists\", respectively. These functions are\nactually generic functions, which we are going to talk more about at @sec-generic-fun.\n\nFor now, just understand that, in order to create a linked list object,\nwe begin by providing a data type to these functions. This data type defines\nthe type of data that this linked list will store. In the example below,\nwe are creating a singly linked list capable of storing `u32` values.\nSo each node in this linked list will store a `u32` value.\n\nBoth the `SinglyLinkedList()` and `DoublyLinkedList()` functions returns a type, i.e. a struct definition, as result. This means that\nthe object `Lu32` is actually a type definition, or a struct definition. It defines\nthe type \"singly linked list of `u32` values\".\n\nSo now that we have the definition of the struct, we have to instantiate a `Lu32` object.\nWe normally instantiate struct objects in Zig by using an `init()` method.\nBut in this case, we are instantiating the struct directly, by using an empty\n`struct` literal, in the expression `Lu32{}`.\n\nIn this example, we first create multiple node objects, and after we create them,\nwe start to insert and connect these nodes to build the linked list, using the\n`prepend()` and `insertAfter()` methods. Notice that the `prepend()` method\nis a method from the linked list object, while the `insertAfter()` is a method\npresent in the node objects.\n\nIn essence, the `prepend()` method inserts a node at the beginning of the linked\nlist. In other words, the node that you provide to this method, becomes the new\n\"head node\" of the linked list. It becomes the first node in the list (see @fig-linked-list).\n\nOn the other side, the `insertAfter()` method is used to basically connect two nodes together.\nWhen you provide a node to this method, it creates a pointer to this input node,\nand stores this pointer in the current node, from which the method was called from.\nIn other words, this method creates the pointer that connects these two nodes together\nand stores it in the `next` attribute of the current node.\n\nSince doubly linked list have both a `next` and a `prev` pointers in each node,\nreferring to the next and previous nodes in the sequence, respectively,\nas I described at @fig-linked-list2, a node object created from\na `DoublyLinkedList()` object would have both a\n`insertBefore()` (for `prev`) and a `insertAfter()` (for `next`) methods\navailable.\n\nThis means that, if we used a doubly linked list, we could use the `insertBefore()` method\nto store the pointer to the input node in the `prev` attribute. This would put the input\nnode as the \"previous node\", or, the node before the current node. The `insertAfter()` method\nhave \"after\" in it's name to indicate that this method puts the pointer created to the input\nnode in the `next` attribute of the current node, and as the result, the input node becomes\nthe \"next node\" of the current node.\n\nSince we are using a singly linked list in this example, we have only the `insertAfter()` method\navailable in the node objects that we create from our `Lu32` type.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst SinglyLinkedList = std.SinglyLinkedList;\nconst Lu32 = SinglyLinkedList(u32);\n\npub fn main() !void {\n var list = Lu32{};\n var one = Lu32.Node{ .data = 1 };\n var two = Lu32.Node{ .data = 2 };\n var three = Lu32.Node{ .data = 3 };\n var four = Lu32.Node{ .data = 4 };\n var five = Lu32.Node{ .data = 5 };\n\n list.prepend(&two); // {2}\n two.insertAfter(&five); // {2, 5}\n list.prepend(&one); // {1, 2, 5}\n two.insertAfter(&three); // {1, 2, 3, 5}\n three.insertAfter(&four); // {1, 2, 3, 4, 5}\n}\n```\n:::\n\n\n\n\n\nThere are other methods available from the linked list object, depending if this object is\na singly linked list or a doubly linked list, that might be very useful for you, like:\n\n- `remove()` to remove a specific node from the linked list.\n- `popFirst()` to remove the first node from the linked list.\n- if singly linked list, `len()` to count how many nodes there is in the linked list.\n- if doubly linked list, checkout the `len` attribute to see how many nodes there is in the linked list.\n- if singly linked list, `popFirst()` to remove the first node from the linked list.\n- if doubly linked list, `pop()` and `popFirst()` to remove the last and first nodes from the linked list, respectively.\n- if doubly linked list, `append()` to add a new node to end of the linked list (i.e. inverse of `prepend()`).\n\n\n\n## Multi array structure\n\nZig introduces a new data structure called `MultiArrayList()`. It is a different version of the dynamic array\nthat we have introduced at @sec-dynamic-array. The difference between this structure and the `ArrayList()`\nthat we know from @sec-dynamic-array, is that `MultiArrayList()` creates a separate dynamic array\nfor each field of the struct that you provide as input.\n\nConsider the following code example. We create a new custom struct called `Person`. This\nstruct contains three different data members, or, three different fields. As consequence,\nwhen we provide this `Person` data type as input to `MultiArrayList()`, this\ncreates a \"struct of three different arrays\" called `PersonArray`. In other words,\nthis `PersonArray` is a struct that contains three internal dynamic arrays in it.\nOne array for each field found in the `Person` struct definition.\n\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nconst std = @import(\"std\");\nconst Person = struct {\n name: []const u8,\n age: u8,\n height: f32,\n};\nconst PersonArray = std.MultiArrayList(Person);\n\npub fn main() !void {\n var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n const allocator = gpa.allocator();\n var people = PersonArray{};\n defer people.deinit(allocator);\n\n try people.append(allocator, .{\n .name = \"Auguste\", .age = 15, .height = 1.54\n });\n try people.append(allocator, .{\n .name = \"Elena\", .age = 26, .height = 1.65\n });\n try people.append(allocator, .{\n .name = \"Michael\", .age = 64, .height = 1.87\n });\n}\n```\n:::\n\n\n\n\nIn other words, instead of creating an array of \"persons\", the `MultiArrayList()` function\ncreates a \"struct of arrays\". Each data member of this struct is a different array that stores\nthe values of a specific field from the `Person` struct values that are added (or, appended) to the \"struct of arrays\".\nOne important detail is that each of these separate internal arrays stored inside `PersonArray`\nare dynamic arrays. This means that these arrays can grow automatically as needed, to accomodate\nmore values.\n\nThe @fig-multi-array exposed below presents a diagram that describes the `PersonArray` struct\nthat we have created in the previous code example. Notice that the values of the data members\npresent in each of the three `Person` values that we have appended into the `PersonArray` object\nthat we have instantiated, are scattered across three different internal arrays of the `PersonArray` object.\n\n![A diagram of the `PersonArray` struct.](./../Figures/multi-array.png){#fig-multi-array}\n\nYou can easily access each of these arrays separately, and iterate over the values of each array.\nFor that, you will need to call the `items()` method from the `PersonArray` object, and provide as input\nto this method, the name of the field that you want to iterate over.\nIf you want to iterate through the `.age` array for example, then, you need to call `items(.age)` from\nthe `PersonArray` object, like in the example below:\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nfor (people.items(.age)) |*age| {\n try stdout.print(\"Age: {d}\\n\", .{age.*});\n}\n```\n:::\n\n\n\n\n```\nAge: 15\nAge: 26\nAge: 64\n```\n\n\nIn the above example, we are iterating over the values of the `.age` array, or,\nthe internal array of the `PersonArray` object that contains the values of the `age`\ndata member from the `Person` values that were added to the multi array struct.\n\nIn this example we are calling the `items()` method directly from the `PersonArray`\nobject. However, it is recommended on most situations to call this `items()` method\nfrom a \"slice object\", which you can create from the `slice()` method.\nThe reason for this is that calling `items()` multiple times have better performance\nif you use a slice object.\n\nIn other words, if you are planning to access only one of the\ninternal arrays from your \"multi array struct\", it is fine to call `items()` directly\nfrom the multi array object. But if you need to access many of the internal arrays\nfrom your \"multi array struct\", then, you will likely need to call `items()` more\nthan once, and, in such circustance, is better to call `items()` through a slice object.\nThe example below demonstrates the use of such object:\n\n\n\n\n::: {.cell}\n\n```{.zig .cell-code}\nvar slice = people.slice();\nfor (slice.items(.age)) |*age| {\n age.* += 10;\n}\nfor (slice.items(.name), slice.items(.age)) |*n,*a| {\n try stdout.print(\n \"Name: {s}, Age: {d}\\n\", .{n.*, a.*}\n );\n}\n```\n:::\n\n\n\n\n```\nName: Auguste, Age: 25\nName: Elena, Age: 36\nName: Michael, Age: 74\n```\n\n\n## Conclusion\n\nThere are many other data structures that I did not presented here.\nBut you can check them out at the offical Zig Standard Library documentation page.\nActually, when you get into the [homepage of the documentation](https://ziglang.org/documentation/master/std/#)[^home], the first thing\nthat appears to you in this page, is a list of types and data structures.\n\n\nIn this section you can see a list of the many different data structures available in\nthe Zig Standard Library. There are some very specific structures in this list, like a\n[`BoundedArray` struct](https://ziglang.org/documentation/master/std/#std.bounded_array.BoundedArray)[^bounded]\n, but there is also some more general structures, such as a\n[`PriorityQueue` struct](https://ziglang.org/documentation/master/std/#std.priority_queue.PriorityQueue)[^priority].\n\n\n[^home]: \n[^priority]: .\n[^bounded]: \n\n\n\n\n\n\n", + "supporting": [ + "09-data-structures_files" + ], "filters": [ "rmarkdown/pagebreak.lua" ], diff --git a/docs/Chapters/09-data-structures.html b/docs/Chapters/09-data-structures.html index 44077d6..99f8533 100644 --- a/docs/Chapters/09-data-structures.html +++ b/docs/Chapters/09-data-structures.html @@ -726,7 +726,7 @@

11.4 Multi array structure

Zig introduces a new data structure called MultiArrayList(). It is a different version of the dynamic array that we have introduced at Section 11.1. The difference between this structure and the ArrayList() that we know from Section 11.1, is that MultiArrayList() creates a separate dynamic array for each field of the struct that you provide as input.

-

Consider the following code example. We create a new custom struct called Person. This struct contains three different data members, or, three different fields. As consequence, when we provide this Person data type as input to MultiArrayList(), this creates three different arrays. One array for each field in the struct.

+

Consider the following code example. We create a new custom struct called Person. This struct contains three different data members, or, three different fields. As consequence, when we provide this Person data type as input to MultiArrayList(), this creates a “struct of three different arrays” called PersonArray. In other words, this PersonArray is a struct that contains three internal dynamic arrays in it. One array for each field found in the Person struct definition.

const std = @import("std");
 const Person = struct {
@@ -753,7 +753,7 @@ 

< }); }

-

In other words, instead of creating an array of “persons”, the MultiArrayList() function creates a “struct of arrays”. Each data member of this struct is a different array that stores the values of a specific field from the Person struct values that are added (or, appended) to the “struct of arrays”.

+

In other words, instead of creating an array of “persons”, the MultiArrayList() function creates a “struct of arrays”. Each data member of this struct is a different array that stores the values of a specific field from the Person struct values that are added (or, appended) to the “struct of arrays”. One important detail is that each of these separate internal arrays stored inside PersonArray are dynamic arrays. This means that these arrays can grow automatically as needed, to accomodate more values.

The Figure 11.5 exposed below presents a diagram that describes the PersonArray struct that we have created in the previous code example. Notice that the values of the data members present in each of the three Person values that we have appended into the PersonArray object that we have instantiated, are scattered across three different internal arrays of the PersonArray object.

diff --git a/docs/Figures/buffered-io2.png b/docs/Figures/buffered-io2.png deleted file mode 100644 index ec56591b81ca32066e698d51339c310fd85e022e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38262 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 nsg(X5hrs&$OI!W_>x)CGNjH)qdZna6Xo@Ap - + An Introduction to Zig