Skip to content

Commit

Permalink
Add list-ops exercise (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
danilopiazza authored Feb 29, 2024
1 parent 892b4b9 commit 74b43cb
Show file tree
Hide file tree
Showing 12 changed files with 4,013 additions and 0 deletions.
13 changes: 13 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,19 @@
"pointers",
"structs"
]
},
{
"slug": "list-ops",
"name": "List Ops",
"uuid": "784f7a0c-bf28-4b99-be6a-cafc3efbca3d",
"practices": [],
"prerequisites": [],
"difficulty": 5,
"topics": [
"arrays",
"functions",
"loops"
]
}
]
},
Expand Down
19 changes: 19 additions & 0 deletions exercises/practice/list-ops/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Instructions

Implement basic list operations.

In functional languages list operations like `length`, `map`, and `reduce` are very common.
Implement a series of basic list operations, without using existing functions.

The precise number and names of the operations to be implemented will be track dependent to avoid conflicts with existing names, but the general operations you will implement include:

- `append` (_given two lists, add all items in the second list to the end of the first list_);
- `concatenate` (_given a series of lists, combine all items in all lists into one flattened list_);
- `filter` (_given a predicate and a list, return the list of all items for which `predicate(item)` is True_);
- `length` (_given a list, return the total number of items within it_);
- `map` (_given a function and a list, return the list of the results of applying `function(item)` on all items_);
- `foldl` (_given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left_);
- `foldr` (_given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right_);
- `reverse` (_given a list, return a list with all the original items, but in reversed order_).

Note, the ordering in which arguments are passed to the fold functions (`foldl`, `foldr`) is significant.
2 changes: 2 additions & 0 deletions exercises/practice/list-ops/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.o
tests
17 changes: 17 additions & 0 deletions exercises/practice/list-ops/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [
"danilopiazza"
],
"files": {
"solution": [
"list_ops.asm"
],
"test": [
"list_ops_test.c"
],
"example": [
".meta/example.asm"
]
},
"blurb": "Implement basic list operations."
}
264 changes: 264 additions & 0 deletions exercises/practice/list-ops/.meta/example.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
;
; Add all items in the second array to the end of the first array.
;
; Parameters:
; rdi - first array
; rsi - number of items in the first array
; rdx - second array
; rcx - number of items in the second array
; r8 - result array
; Returns:
; rax - the number of items in the result array
;
section .text
global append
append:
mov rax, rsi
add rax, rcx ; Set return value

mov r9, rcx ; Save number of items in second array

mov rcx, rsi ; Set first array length
mov rsi, rdi ; Set source to first array
mov rdi, r8 ; Set destination to result array
rep movsd ; Append items from first array

mov rsi, rdx ; Set source to second array
mov rcx, r9 ; Set second array length
rep movsd ; Append items from second array

ret

;
; Return all items for which the predicate is true.
;
; Parameters:
; rdi - array
; rsi - number of items in the array
; rdx - predicate
; rcx - result array
; Returns:
; rax - the number of items in the result array
;
global filter
filter:
push rbx ; Save caller's registers
push r12
push r13
push r14
push r15

xor rbx, rbx ; Initialize number of filtered items

cmp rsi, 0 ; Check if input array is empty
je .loop_end ; If empty, skip loop

mov r12, rdi ; Save input array
mov r13, rsi ; Save input array length
mov r14, rdx ; Save predicate
mov r15, rcx ; Save result array
.loop_start:
mov edi, dword [r12] ; Read value from array
call r14 ; Call predicate
test al, al ; Check if predicate is true
jz .next ; If not, process next item

inc rbx ; Increment number of filtered items
mov eax, dword [r12]
mov dword [r15], eax ; Copy filtered item to result array
add r15, 4 ; Advance result array to next item
.next:
add r12, 4 ; Advance input array to next item
dec r13 ; Decrement remaining number of items
cmp r13, 0 ; See if we reached the end
jne .loop_start ; If items remain, loop back

.loop_end:
mov rax, rbx ; Set return value

pop r15
pop r14
pop r13
pop r12
pop rbx ; Restore caller's registers

ret

;
; Return the results of applying the transform function on all items.
;
; Parameters:
; rdi - array
; rsi - number of items in the array
; rdx - transform function
; rcx - result array
; Returns:
; rax - the number of items in the result array
;
global map
map:
push rbx ; Save caller's registers
push r12
push r13
push r14
push r15

mov rbx, rsi ; Set return value

cmp rsi, 0 ; Check if input array is empty
je .loop_end ; If empty, skip loop

mov r12, rdi ; Save input array
mov r13, rsi ; Save input array length
mov r14, rdx ; Save transform function
mov r15, rcx ; Save result array
.loop_start:
mov edi, dword [r12] ; Read value from array
call r14 ; Call transform function
mov dword [r15], eax ; Copy transformed item to result array

add r12, 4 ; Advance input array to next item
add r15, 4 ; Advance result array to next item
dec r13 ; Decrement remaining number of items
cmp r13, 0 ; See if we reached the end
jne .loop_start ; If items remain, loop back

.loop_end:
mov rax, rbx ; Set return value

pop r15
pop r14
pop r13
pop r12
pop rbx ; Restore caller's registers

ret

;
; Fold (reduce) each item into the accumulator from the left.
;
; Parameters:
; rdi - array
; rsi - number of items in the array
; rdx - initial value
; rcx - accumulator function
; Returns:
; rax - the folded (reduced) value
;
global foldl
foldl:
push rbx ; Save caller's registers
push r12
push r13
push r14

mov rbx, rdx ; Initialize return value

cmp rsi, 0 ; Check if input array is empty
je .loop_end ; If empty, skip loop

mov r12, rdi ; Save input array
mov r13, rsi ; Save input array length
mov r14, rcx ; Save accumulator function
.loop_start:
mov rdi, rbx
mov esi, dword [r12] ; Read value from array
call r14 ; Call accumulator function
mov rbx, rax ; Update return value

add r12, 4 ; Advance input array to next item
dec r13 ; Decrement remaining number of items
cmp r13, 0 ; See if we reached the end
jne .loop_start ; If items remain, loop back

.loop_end:
mov rax, rbx ; Set return value

pop r14
pop r13
pop r12
pop rbx ; Restore caller's registers

ret

;
; Fold (reduce) each item into the accumulator from the right.
;
; Parameters:
; rdi - array
; rsi - number of items in the array
; rdx - initial value
; rcx - accumulator function
; Returns:
; rax - the folded (reduced) value
;
global foldr
foldr:
push rbx ; Save caller's registers
push r12
push r13
push r14

mov rbx, rdx ; Initialize return value

cmp rsi, 0 ; Check if input array is empty
je .loop_end ; If empty, skip loop

lea r12, [rdi + 4*rsi - 4] ; Save end of input array
mov r13, rsi ; Save input array length
mov r14, rcx ; Save accumulator function
.loop_start:
mov rdi, rbx
mov esi, dword [r12] ; Read value from array
call r14 ; Call accumulator function
mov rbx, rax ; Update return value

sub r12, 4 ; Advance input array to previous item
dec r13 ; Decrement remaining number of items
cmp r13, 0 ; See if we reached the end
jne .loop_start ; If items remain, loop back

.loop_end:
mov rax, rbx ; Set return value

pop r14
pop r13
pop r12
pop rbx ; Restore caller's registers

ret

;
; Reverses the order of items in the array.
;
; Parameters:
; rdi - array
; rsi - number of items in the array
; rdx - result array
; Returns:
; rax - the number of items in the result array
;
global reverse
reverse:
mov rax, rsi ; Set return value

cmp rsi, 0 ; Check if input array is empty
je .loop_end ; If empty, skip loop

lea rcx, [rdx + 4*rsi - 4] ; Set end of the result array
.loop_start:
mov edx, dword [rdi] ; Read value from array
mov dword [rcx], edx ; Write value to result array

add rdi, 4 ; Advance input array to next item
sub rcx, 4 ; Advance result array to previous item
dec rsi ; Decrement remaining number of items
cmp rsi, 0 ; See if we reached the end
jne .loop_start ; If items remain, loop back

.loop_end:
ret

%ifidn __OUTPUT_FORMAT__,elf64
section .note.GNU-stack noalloc noexec nowrite progbits
%endif
Loading

0 comments on commit 74b43cb

Please sign in to comment.