diff --git a/src/array.asm b/src/array.asm index c90ba38..30b4c2c 100644 --- a/src/array.asm +++ b/src/array.asm @@ -7,6 +7,7 @@ ; r5 - Predicate context ; Result: ; r1 - The index of the first element matching the provided predicate function (or -1 if not found) +; flags - 0, if the element does not exist in the array. 1 if the element does exist. ; Clobbers: r2, r3, r4, r5, r6, + what the predicate clobbers ; Info: ; The predicate function should follow the stdlib calling convention @@ -74,4 +75,6 @@ pub find_index: pop r10 pop r11 pop r12 + lsr flags, r1, 31 + xor flags, flags, 1 jmp r13 ; Return diff --git a/src/hashset.asm b/src/hashset.asm new file mode 100644 index 0000000..93d2be0 --- /dev/null +++ b/src/hashset.asm @@ -0,0 +1,227 @@ +;struct Allocator { +; alloc: (U32) -> ptr +; realloc: (ptr, U32) -> ptr +; free: (ptr) -> () +;} + +;struct HashSet { +; buckets: U32 +; alloc_ptr: *Allocator +; hash_ptr: *(Item) -> U32 +; hash_context: U32 +; eq_ptr: *(Item, Item) -> Bool +; eq_context: U32 +; data_ptr: *HashBucket +;} + +;struct HashBucket { +; hash0: U32 +; item0: Item +; hash1: U32 +; item1: Item +; hash2: U32 +; item2: Item +; hash3: U32 +; item3: Item +;} + +; Checks if the hashset contains a specified element +; Arguments: +; r1 - The element to check +; r2 - The pointer to the hashset +; Result: +; r1 - 0, if the element does not exist in the hashset. 1 if the element does exist. +; r2 - The pointer to the hashset +; flags - 0, if the element does not exist in the hashset. 1 if the element does exist. +pub contains: + push r13 + push r8 + push r9 + push r10 + push r11 + push r12 + + mov r8, r1 + mov r9, r2 + + add r3, r2, 8 + load_32 r3, [r3] ; Loading the hash pointer + add r2, r2, 12 + load_32 r2, [r2] ; Loading the hash context + + counter r13 + add r13, r13, 12 + jmp r3 ; Calling the hash function with element in r1, context in r2 + + cmp r1, rz + jne contains_skip_one + add r1, r1, 1 ; If hash is zero, we add 1. That way hash being 0 means the item does not exist at a position + contains_skip_one: + + mov r12, r1 + + add r10, r9, 16 + load_32 r10, [r10] ; Loading the eq pointer + add r11, r9, 20 + load_32 r11, [r11] ; Loading the eq context + + ; We have: + ; item in r8 + ; bucket pointer in r9 + ; eq pointer in r10 + ; eq context in r11 + ; item hash in r12 + + load_32 r2, [r9] ; Loading buckets + sub r2, r2, 1 + and r2, r1, r2 ; bucket_index = hash & (buckets - 1) + + add r3, r9, 24 + load_32 r3, [r3] ; Loading data pointer + lsl r2, r2, 5 ; Each bucket is 32 bytes + push r9 + add r9, r2, r3 ; Pointer to bucket + + load_32 r3, [r9] ; First hash + cmp r3, rz + je contains_notfourth ; If hash is zero, no items left to check + cmp r12, r3 + jne contains_notfirst + ; First item hash passed - checking equality + mov r13, contains_notfirst + jmp contains_eqcheck + + contains_notfirst: + add r9, r9, 8 + load_32 r3, [r9] ; Second hash + cmp r3, rz + je contains_notfourth ; If hash is zero, no items left to check + cmp r12, r3 + jne contains_notsecond + ; Second item hash passed - checking equality + mov r13, contains_notsecond + jmp contains_eqcheck + + contains_notsecond: + add r9, r9, 8 + load_32 r3, [r9] ; Third hash + cmp r3, rz + je contains_notfourth ; If hash is zero, no items left to check + cmp r12, r3 + jne contains_notthird + ; Third item hash passed - checking equality + mov r13, contains_notthird + jmp contains_eqcheck + + contains_notthird: + add r9, r9, 8 + load_32 r3, [r9] ; Fourth hash + cmp r3, rz + je contains_notfourth ; If hash is zero, no items left to check + cmp r12, r3 + jne contains_notfourth + ; Fourth item hash passed - checking equality + mov r13, contains_notfourth + jmp contains_eqcheck + + contains_notfourth: + mov r1, 0 + contains_finish: + pop r2 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop r13 + mov flags, r1 + jmp r13 + + contains_found: + mov r1, 1 + jmp contains_finish + + contains_eqcheck: + add r3, r9, 4 + load_32 r2, [r3] + mov r3, r11 + mov r1, r8 + jmp r10 ; Calling eq check + cmp r1, zr + jne contains_found + jmp r13 + +; Creates a hashset for the specified allocator, hash function and equality function +; Arguments: +; r1 - The pointer to the allocator +; r2 - The hash function +; r3 - The hash function context +; r4 - The equality function +; r5 - The equality function context +; Result: +; r1 - The pointer to the hashset structure +; Info: +; The hash function should follow the stdlib calling convention +; The hash function receives one argument (the value of the item) and should return an integer which remains the same for the lifetime of the value. +; The equality function should follow the stdlib calling convention +; The equality function receives two arguments (the value of the two items) and should return either a zero (when the items are not equal) or any other value (if they are equal). +pub new: + ; First let's free up all the registers + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 ; We will be calling alloc + + mov r8, r1 + mov r9, r2 + mov r10, r3 + mov r11, r4 + mov r12, r5 + + load_32 r5, [r8] ; Loading the alloc function address + mov r1, 28 + counter r13 + add r13, r13, 12 + jmp r5 ; allocating the space for the hashset struct itself + + ; Now r1 has the pointer to memory, r2-r7 are clobbered + + mov r2, 8 + store_32 [r1], r2 ; initial capacity at 8 buckets + + add r1, r1, 4 + store_32 [r1], r8 ; allocator pointer is in r8 + + add r1, r1, 4 + store_32 [r1], r9 ; hash pointer is in r9 + + add r1, r1, 4 + store_32 [r1], r10 ; hash context is in r10 + + add r1, r1, 4 + store_32 [r1], r11 ; eq pointer is in r11 + + add r1, r1, 4 + store_32 [r1], r12 ; eq context is in r12 + + add r12, r1, 4 ; Now r12 is hashset pointer at data_ptr + + load_32 r5, [r8] ; Loading the alloc function address + mov r1, 256 ; 8 buckets * 4 items * 8 bytes per each + counter r13 + add r13, r13, 12 + jmp r5 ; allocating the space for the data + + store_32 [r2], r1 ; data pointer saved + + sub r1, r12, 24 ; Getting the pointer to start of the hashset + + pop r13 ; Everything's set up, return + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + jmp r13 \ No newline at end of file