-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* exercises: add linked-list * exercises: linked-list: fix missing reference * exercises: linked-list: fix build with pie * exercises: linked-list: don't use malloc+free and use struc * exercises: linked-list: remove stuct defs in tests * exercises: linked-list: rename struc and move to .bss * exercises: linked-list: no pointers between c and asm * exercises: linked-list: better doc * exercises: linked-list: chore: rebase * exercises: linked-list: update generator
- Loading branch information
Showing
12 changed files
with
4,043 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Instructions | ||
|
||
Implement a doubly linked list. | ||
|
||
Like an array, a linked list is a simple linear data structure. Several | ||
common data types can be implemented using linked lists, like queues, | ||
stacks, and associative arrays. | ||
|
||
A linked list is a collection of data elements called *nodes*. In a | ||
*singly linked list* each node holds a value and a link to the next node. | ||
In a *doubly linked list* each node also holds a link to the previous | ||
node. | ||
|
||
You will write an implementation of a doubly linked list. Implement a | ||
Node to hold a value and pointers to the next and previous nodes. Then | ||
implement a List which holds references to the first and last node and | ||
offers an array-like interface for adding and removing items: | ||
|
||
* `push` (*insert value at back*); | ||
* `pop` (*remove value at back*); | ||
* `shift` (*remove value at front*). | ||
* `unshift` (*insert value at front*); | ||
|
||
To keep your implementation simple, the tests will not cover error | ||
conditions. Specifically: `pop` or `shift` will never be called on an | ||
empty list. | ||
|
||
If you want to know more about linked lists, check [Wikipedia](https://en.wikipedia.org/wiki/Linked_list). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"blurb": "Implement a doubly linked list", | ||
"authors": [ | ||
"sudhackar" | ||
], | ||
"contributors": [], | ||
"files": { | ||
"solution": [ | ||
"linked_list.asm" | ||
], | ||
"test": [ | ||
"linked_list_test.c" | ||
], | ||
"example": [ | ||
".meta/example.asm" | ||
] | ||
}, | ||
"source": "Classic computer science topic" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
default rel | ||
; a Node in the doubly linked-list | ||
struc Node | ||
; pointer to previous node | ||
.Prev: resq 1 | ||
; pointer to next node | ||
.Next: resq 1 | ||
; int data | ||
.Data: resd 1 | ||
endstruc | ||
|
||
; references to start and end of a list | ||
struc List | ||
; pointer to First node in the List | ||
.First resq 1 | ||
; pointer to Last node in the list | ||
.Last resq 1 | ||
endstruc | ||
|
||
section .bss | ||
; store the single instance of List to store pointers to First and Last nodes | ||
list: | ||
resb List_size | ||
; space for 16 nodes which will be "allocated" sequentially | ||
nodes: | ||
resb 0x10*Node_size | ||
; an integer that has the next available node from nodes to "allocate" | ||
currnodeidx: | ||
resq 1 | ||
|
||
section .text | ||
|
||
global list_create | ||
global list_count | ||
global list_push | ||
global list_pop | ||
global list_unshift | ||
global list_shift | ||
global list_delete | ||
global list_destroy | ||
|
||
get_list: | ||
; reset current node index to 0 | ||
mov dword [currnodeidx], 0 | ||
; return pointer to list | ||
lea rax, [list] | ||
ret | ||
get_node: | ||
movsx rax, dword [currnodeidx] | ||
lea edx, [rax+1] | ||
imul rax, rax, Node_size | ||
mov dword [currnodeidx], edx | ||
lea rdx, [nodes] | ||
add rax, rdx | ||
ret | ||
|
||
list_node_create: | ||
mov ecx, edx | ||
call get_node | ||
test rax, rax | ||
je .err | ||
mov qword [rax+Node.Prev], rdi | ||
mov qword [rax+Node.Next], rsi | ||
mov dword [rax+Node.Data], ecx | ||
.err: | ||
ret | ||
list_create: | ||
call get_list | ||
test rax, rax | ||
je .err | ||
mov qword [rax+List.First], 0 | ||
mov qword [rax+List.Last], 0 | ||
.err: | ||
ret | ||
list_count: | ||
lea rax, [list] | ||
test rax, rax | ||
je .fin_loop_count | ||
mov rdi, rax | ||
mov rdx, qword [rdi+List.First] | ||
xor eax, eax | ||
.loop_count: | ||
test rdx, rdx | ||
je .fin_loop_count | ||
mov rdx, qword [rdx+Node.Next] | ||
inc rax | ||
jmp .loop_count | ||
.fin_loop_count: | ||
ret | ||
list_push: | ||
lea rax, [list] | ||
test rax, rax | ||
je .err | ||
mov r8, rax | ||
mov edx, edi | ||
mov rdi, qword [r8+List.Last] | ||
xor esi, esi | ||
call list_node_create | ||
test rax, rax | ||
je .err | ||
cmp qword [r8+List.First], 0 | ||
mov qword [r8+List.Last], rax | ||
jne .first_set | ||
mov qword [r8+List.First], rax | ||
ret | ||
.first_set: | ||
mov rdx, qword [rax+Node.Prev] | ||
mov qword [rdx+Node.Next], rax | ||
.err: | ||
ret | ||
list_pop: | ||
lea rdi, [list] | ||
mov rax, qword [rdi+List.Last] | ||
mov rdx, qword [rax+Node.Prev] | ||
mov r8d, dword [rax+Node.Data] | ||
mov qword [rdi+List.Last], rdx | ||
cmp qword [rdi+List.First], rax | ||
jne .set_prev_next | ||
mov qword [rdi+List.First], 0 | ||
jmp .empty | ||
.set_prev_next: | ||
mov qword [rdx+Node.Next], 0 | ||
.empty: | ||
mov qword [rax+Node.Prev], 0 | ||
mov qword [rax+Node.Next], 0 | ||
mov dword [rax+Node.Data], 0 | ||
mov eax, r8d | ||
ret | ||
list_unshift: | ||
mov edx, edi | ||
lea rdi, [list] | ||
mov rsi, qword [rdi+List.First] | ||
mov r8, rdi | ||
xor edi, edi | ||
call list_node_create | ||
test rax, rax | ||
je .err | ||
cmp qword [r8+List.Last], 0 | ||
mov qword [r8+List.First], rax | ||
jne .set_next_prev | ||
mov qword [r8+List.Last], rax | ||
ret | ||
.set_next_prev: | ||
mov rdx, qword [rax+Node.Next] | ||
mov qword [rdx+Node.Prev], rax | ||
.err: | ||
ret | ||
list_shift: | ||
lea rdi, [list] | ||
mov rax, qword [rdi+List.First] | ||
mov rdx, qword [rax+Node.Next] | ||
mov r8d, dword [rax+Node.Data] | ||
mov qword [rdi+List.First], rdx | ||
cmp qword [rdi+List.Last], rax | ||
jne .set_next_prev | ||
mov qword [rdi+List.Last], 0 | ||
jmp .zero | ||
.set_next_prev: | ||
mov qword [rdx+Node.Prev], 0 | ||
.zero: | ||
mov qword [rax+Node.Prev], 0 | ||
mov qword [rax+Node.Next], 0 | ||
mov dword [rax+Node.Data], 0 | ||
mov eax, r8d | ||
ret | ||
list_delete: | ||
mov esi, edi | ||
lea rdi, [list] | ||
mov r8, qword [rdi+List.First] | ||
mov rax, r8 | ||
.search_loop: | ||
test rax, rax | ||
je .err | ||
mov rdx, qword [rax+Node.Next] | ||
cmp dword [rax+Node.Data], esi | ||
jne .Next | ||
mov rcx, qword [rax+Node.Prev] | ||
cmp rax, r8 | ||
jne .set_prev_next | ||
mov qword [rdi+List.First], rdx | ||
jmp .last_compare | ||
.set_prev_next: | ||
mov qword [rcx+Node.Next], rdx | ||
.last_compare: | ||
cmp qword [rdi+List.Last], rax | ||
jne .set_next_prev | ||
mov qword [rdi+List.Last], rcx | ||
jmp .zero | ||
.set_next_prev: | ||
mov rdx, qword [rax+Node.Next] | ||
mov qword [rdx+Node.Prev], rcx | ||
.zero: | ||
mov qword [rax+Node.Prev], 0 | ||
mov qword [rax+Node.Next], 0 | ||
mov dword [rax+Node.Data], 0 | ||
ret | ||
.Next: | ||
mov rax, rdx | ||
jmp .search_loop | ||
.err: | ||
ret | ||
list_destroy: | ||
call get_list | ||
test rax, rax | ||
je .err | ||
mov rdi, rax | ||
mov rax, qword [rdi+List.First] | ||
.loop: | ||
test rax, rax | ||
je .zero | ||
mov rdx, qword [rax+Node.Next] | ||
mov qword [rax+Node.Prev], 0 | ||
mov qword [rax+Node.Next], 0 | ||
mov dword [rax+Node.Data], 0 | ||
mov rax, rdx | ||
jmp .loop | ||
.zero: | ||
mov qword [rdi+List.First], 0 | ||
mov qword [rdi+List.Last], 0 | ||
.err: | ||
ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# This is an auto-generated file. Regular comments will be removed when this | ||
# file is regenerated. Regenerating will not touch any manually added keys, | ||
# so comments can be added in a "comment" key. | ||
|
||
[7f7e3987-b954-41b8-8084-99beca08752c] | ||
description = "pop gets element from the list" | ||
|
||
[c3f67e5d-cfa2-4c3e-a18f-7ce999c3c885] | ||
description = "push/pop respectively add/remove at the end of the list" | ||
|
||
[00ea24ce-4f5c-4432-abb4-cc6e85462657] | ||
description = "shift gets an element from the list" | ||
|
||
[37962ee0-3324-4a29-b588-5a4c861e6564] | ||
description = "shift gets first element from the list" | ||
|
||
[30a3586b-e9dc-43fb-9a73-2770cec2c718] | ||
description = "unshift adds element at start of the list" | ||
|
||
[042f71e4-a8a7-4cf0-8953-7e4f3a21c42d] | ||
description = "pop, push, shift, and unshift can be used in any order" | ||
|
||
[88f65c0c-4532-4093-8295-2384fb2f37df] | ||
description = "count an empty list" | ||
|
||
[fc055689-5cbe-4cd9-b994-02e2abbb40a5] | ||
description = "count a list with items" | ||
|
||
[8272cef5-130d-40ea-b7f6-5ffd0790d650] | ||
description = "count is correct after mutation" | ||
|
||
[229b8f7a-bd8a-4798-b64f-0dc0bb356d95] | ||
description = "popping to empty doesn't break the list" | ||
|
||
[4e1948b4-514e-424b-a3cf-a1ebbfa2d1ad] | ||
description = "shifting to empty doesn't break the list" | ||
|
||
[e8f7c600-d597-4f79-949d-8ad8bae895a6] | ||
description = "deletes the only element" | ||
|
||
[fd65e422-51f3-45c0-9fd0-c33da638f89b] | ||
description = "deletes the element with the specified value from the list" | ||
|
||
[59db191a-b17f-4ab7-9c5c-60711ec1d013] | ||
description = "deletes the element with the specified value from the list, re-assigns tail" | ||
|
||
[58242222-5d39-415b-951d-8128247f8993] | ||
description = "deletes the element with the specified value from the list, re-assigns head" | ||
|
||
[ee3729ee-3405-4bd2-9bad-de0d4aa5d647] | ||
description = "deletes the first of two elements" | ||
|
||
[47e3b3b4-b82c-4c23-8c1a-ceb9b17cb9fb] | ||
description = "deletes the second of two elements" | ||
|
||
[7b420958-f285-4922-b8f9-10d9dcab5179] | ||
description = "delete does not modify the list if the element is not found" | ||
|
||
[7e04828f-6082-44e3-a059-201c63252a76] | ||
description = "deletes only the first occurrence" |
Oops, something went wrong.