-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhashset.asm
More file actions
710 lines (575 loc) · 15.4 KB
/
Copy pathhashset.asm
File metadata and controls
710 lines (575 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
section .data
; Messages
msg_created: db "HashSet created with capacity: ", 0
msg_added: db "Added: ", 0
msg_removed: db "Removed: ", 0
msg_contains: db "Contains: ", 0
msg_size: db "Size: ", 0
msg_empty: db "HashSet is empty", 10, 0
msg_bucket: db "Bucket ", 0
msg_arrow: db " -> ", 0
msg_newline: db 10, 0
msg_yes: db "Yes", 10, 0
msg_no: db "No", 10, 0
msg_space: db " ", 0
msg_colon: db ": ", 0
msg_true: db "true", 10, 0
msg_false: db "false", 10, 0
DEFAULT_CAPACITY equ 16
; Memory management constants
HEAP_SIZE equ 65536 ; 64KB heap
NODE_SIZE equ 16 ; Size of each node
HASHSET_SIZE equ 24 ; Size of HashSet structure
section .bss
hashset: resq 1 ; Pointer to HashSet structure
temp_buffer: resb 64 ; Temporary buffer for number conversions
heap_memory: resb 65536 ; Static heap memory
heap_ptr: resq 1 ; Current heap pointer
heap_end: resq 1 ; End of heap
section .text
global _start
; ============================================================================
; HashSet Structure Layout:
; Offset 0: buckets pointer (8 bytes)
; Offset 8: capacity (8 bytes)
; Offset 16: size (8 bytes)
; Total: 24 bytes
;
; Node Structure Layout:
; Offset 0: value (8 bytes)
; Offset 8: next pointer (8 bytes)
; Total: 16 bytes
; ============================================================================
_start:
; Initialize heap
call init_heap
; Create HashSet
mov rdi, DEFAULT_CAPACITY
call create_hashset
mov [hashset], rax
; Test operations
; Add elements
mov rdi, [hashset]
mov rsi, 10
call add
mov rdi, [hashset]
mov rsi, 20
call add
mov rdi, [hashset]
mov rsi, 15
call add
mov rdi, [hashset]
mov rsi, 25
call add
mov rdi, [hashset]
mov rsi, 10 ; Duplicate, should not be added
call add
; Display HashSet
mov rdi, [hashset]
call display
; Check if elements exist
mov rdi, [hashset]
mov rsi, 15
call contains
; Result in rax (1 if found, 0 if not)
mov rdi, [hashset]
mov rsi, 100
call contains
; Print size
mov rdi, [hashset]
call get_size
; Size in rax
; Remove element
mov rdi, [hashset]
mov rsi, 20
call remove_element
; Display after removal
mov rdi, [hashset]
call display
; Exit
mov rax, 60
xor rdi, rdi
syscall
; ============================================================================
; init_heap: Initialize the simple heap allocator
; ============================================================================
init_heap:
push rbp
mov rbp, rsp
lea rax, [heap_memory]
mov [heap_ptr], rax
add rax, HEAP_SIZE
mov [heap_end], rax
pop rbp
ret
; ============================================================================
; malloc_simple: Simple memory allocator
; Input: rdi = size to allocate
; Output: rax = pointer to allocated memory, or 0 on failure
; ============================================================================
malloc_simple:
push rbp
mov rbp, rsp
push rbx
mov rbx, [heap_ptr] ; Current heap pointer
mov rax, rbx
add rbx, rdi ; New heap pointer
; Check if we have enough space
cmp rbx, [heap_end]
jg .error
; Update heap pointer
mov [heap_ptr], rbx
; Zero out the allocated memory
push rdi
push rax
mov rcx, rdi
mov rdi, rax
xor al, al
rep stosb
pop rax
pop rdi
jmp .done
.error:
xor rax, rax
.done:
pop rbx
pop rbp
ret
; ============================================================================
; free_simple: Simple memory free (no-op for this implementation)
; Input: rdi = pointer to free
; Note: This implementation uses a simple bump allocator, so free is a no-op
; ============================================================================
free_simple:
push rbp
mov rbp, rsp
; No-op for simple allocator
pop rbp
ret
; ============================================================================
; create_hashset: Create and initialize a new HashSet
; Input: rdi = capacity (number of buckets)
; Output: rax = pointer to HashSet structure, or 0 on failure
; ============================================================================
create_hashset:
push rbp
mov rbp, rsp
push rbx
push r12
mov r12, rdi ; Save capacity
; Allocate HashSet structure (24 bytes)
mov rdi, HASHSET_SIZE
call malloc_simple
test rax, rax
jz .error
mov rbx, rax ; Save HashSet pointer
; Allocate buckets array (capacity * 8 bytes)
mov rdi, r12
shl rdi, 3 ; Multiply by 8
call malloc_simple
test rax, rax
jz .error
; Initialize HashSet structure
mov [rbx], rax ; buckets pointer
mov [rbx + 8], r12 ; capacity
mov qword [rbx + 16], 0 ; size = 0
; Initialize all buckets to NULL
mov rcx, r12
mov rdi, [rbx]
.init_buckets:
mov qword [rdi], 0
add rdi, 8
loop .init_buckets
mov rax, rbx ; Return HashSet pointer
jmp .done
.error:
xor rax, rax ; Return NULL on error
.done:
pop r12
pop rbx
pop rbp
ret
; ============================================================================
; hash_function: Calculate hash value for a given key
; Input: rdi = value to hash, rsi = capacity
; Output: rax = hash value (bucket index)
; ============================================================================
hash_function:
push rbp
mov rbp, rsp
; Simple hash: abs(value) % capacity
mov rax, rdi
cqo ; Sign extend rax to rdx:rax
xor rax, rdx ; Take absolute value
sub rax, rdx
xor rdx, rdx
div rsi ; rax = value / capacity, rdx = value % capacity
mov rax, rdx ; Return remainder
pop rbp
ret
; ============================================================================
; add: Add an element to the HashSet
; Input: rdi = HashSet pointer, rsi = value to add
; Output: rax = 1 if added, 0 if already exists
; ============================================================================
add:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi ; HashSet pointer
mov r12, rsi ; Value to add
; Check if value already exists
mov rdi, rbx
mov rsi, r12
call contains
test rax, rax
jnz .already_exists
; Calculate hash
mov rdi, r12
mov rsi, [rbx + 8] ; capacity
call hash_function
mov r13, rax ; Save hash index
; Allocate new node
mov rdi, NODE_SIZE
call malloc_simple
test rax, rax
jz .error
mov r14, rax ; New node pointer
mov [r14], r12 ; Store value
; Insert at beginning of bucket
mov rax, [rbx] ; buckets array
shl r13, 3 ; index * 8
add rax, r13 ; &buckets[index]
mov rcx, [rax] ; Old head
mov [r14 + 8], rcx ; new_node->next = old_head
mov [rax], r14 ; buckets[index] = new_node
; Increment size
inc qword [rbx + 16]
mov rax, 1 ; Success
jmp .done
.already_exists:
xor rax, rax ; Already exists
jmp .done
.error:
xor rax, rax ; Error
.done:
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
; ============================================================================
; contains: Check if an element exists in the HashSet
; Input: rdi = HashSet pointer, rsi = value to check
; Output: rax = 1 if exists, 0 if not
; ============================================================================
contains:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
mov rbx, rdi ; HashSet pointer
mov r12, rsi ; Value to check
; Calculate hash
mov rdi, r12
mov rsi, [rbx + 8] ; capacity
call hash_function
mov r13, rax ; hash index
; Get bucket head
mov rax, [rbx] ; buckets array
shl r13, 3 ; index * 8
add rax, r13
mov rax, [rax] ; buckets[index]
; Search in bucket
.search_loop:
test rax, rax
jz .not_found
cmp [rax], r12 ; Compare node value
je .found
mov rax, [rax + 8] ; next node
jmp .search_loop
.found:
mov rax, 1
jmp .done
.not_found:
xor rax, rax
.done:
pop r13
pop r12
pop rbx
pop rbp
ret
; ============================================================================
; remove_element: Remove an element from the HashSet
; Input: rdi = HashSet pointer, rsi = value to remove
; Output: rax = 1 if removed, 0 if not found
; ============================================================================
remove_element:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi ; HashSet pointer
mov r12, rsi ; Value to remove
; Calculate hash
mov rdi, r12
mov rsi, [rbx + 8] ; capacity
call hash_function
mov r13, rax ; hash index
; Get bucket head pointer
mov r14, [rbx] ; buckets array
shl r13, 3
add r14, r13 ; &buckets[index]
mov rax, [r14] ; Current node
xor rcx, rcx ; Previous node = NULL
.search_loop:
test rax, rax
jz .not_found
cmp [rax], r12
je .found
mov rcx, rax ; prev = current
mov rax, [rax + 8] ; current = current->next
jmp .search_loop
.found:
; Remove node
test rcx, rcx
jz .remove_head
; Remove from middle/end
mov rdx, [rax + 8] ; next
mov [rcx + 8], rdx ; prev->next = current->next
jmp .free_node
.remove_head:
mov rdx, [rax + 8] ; next
mov [r14], rdx ; buckets[index] = next
.free_node:
mov rdi, rax
call free_simple
; Decrement size
dec qword [rbx + 16]
mov rax, 1
jmp .done
.not_found:
xor rax, rax
.done:
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
; ============================================================================
; get_size: Get the number of elements in the HashSet
; Input: rdi = HashSet pointer
; Output: rax = size
; ============================================================================
get_size:
push rbp
mov rbp, rsp
mov rax, [rdi + 16] ; Return size
pop rbp
ret
; ============================================================================
; display: Display all elements in the HashSet
; Input: rdi = HashSet pointer
; ============================================================================
display:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi ; HashSet pointer
; Check if empty
cmp qword [rbx + 16], 0
je .empty
; Print each bucket
xor r12, r12 ; bucket index = 0
mov r13, [rbx + 8] ; capacity
.bucket_loop:
cmp r12, r13
jge .done
; Get bucket head
mov rax, [rbx] ; buckets array
mov r14, r12
shl r14, 3
add rax, r14
mov r14, [rax] ; bucket head
; Skip empty buckets
test r14, r14
jz .next_bucket
; Print bucket index
mov rdi, r12
call print_number
mov rdi, msg_colon
call print_string
; Print nodes in bucket
.node_loop:
test r14, r14
jz .bucket_end
mov rdi, [r14] ; node value
call print_number
mov rdi, msg_space
call print_string
mov r14, [r14 + 8] ; next node
jmp .node_loop
.bucket_end:
mov rdi, msg_newline
call print_string
.next_bucket:
inc r12
jmp .bucket_loop
.empty:
mov rdi, msg_empty
call print_string
.done:
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
; ============================================================================
; clear: Remove all elements from the HashSet
; Input: rdi = HashSet pointer
; ============================================================================
clear:
push rbp
mov rbp, rsp
push rbx
push r12
push r13
push r14
mov rbx, rdi ; HashSet pointer
xor r12, r12 ; bucket index = 0
mov r13, [rbx + 8] ; capacity
.bucket_loop:
cmp r12, r13
jge .done
; Get bucket head
mov rax, [rbx]
mov r14, r12
shl r14, 3
add rax, r14
mov r14, [rax] ; bucket head
; Clear this bucket
.node_loop:
test r14, r14
jz .next_bucket
mov rcx, [r14 + 8] ; Save next
mov rdi, r14
call free_simple
mov r14, rcx
jmp .node_loop
.next_bucket:
; Set bucket to NULL
mov rax, [rbx]
mov r14, r12
shl r14, 3
add rax, r14
mov qword [rax], 0
inc r12
jmp .bucket_loop
.done:
mov qword [rbx + 16], 0 ; size = 0
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
; ============================================================================
; destroy: Free all memory used by the HashSet
; Input: rdi = HashSet pointer
; ============================================================================
destroy:
push rbp
mov rbp, rsp
push rbx
mov rbx, rdi ; HashSet pointer
; Clear all elements
mov rdi, rbx
call clear
; Free buckets array
mov rdi, [rbx]
call free_simple
; Free HashSet structure
mov rdi, rbx
call free_simple
pop rbx
pop rbp
ret
; ============================================================================
; Helper function: print_number
; Input: rdi = number to print
; ============================================================================
print_number:
push rbp
mov rbp, rsp
push rbx
push r12
mov rax, rdi
lea rbx, [temp_buffer + 63]
mov byte [rbx], 0
dec rbx
mov r12, 10
test rax, rax
jns .convert
neg rax
push rax
mov rax, 1
mov rdi, 1
mov rsi, msg_space
mov rdx, 1
syscall
pop rax
.convert:
xor rdx, rdx
div r12
add dl, '0'
mov [rbx], dl
dec rbx
test rax, rax
jnz .convert
inc rbx
mov rax, 1
mov rdi, 1
mov rsi, rbx
lea rdx, [temp_buffer + 63]
sub rdx, rbx
syscall
pop r12
pop rbx
pop rbp
ret
; ============================================================================
; Helper function: print_string
; Input: rdi = pointer to null-terminated string
; ============================================================================
print_string:
push rbp
mov rbp, rsp
push rbx
mov rbx, rdi
xor rcx, rcx
.strlen:
cmp byte [rbx + rcx], 0
je .print
inc rcx
jmp .strlen
.print:
mov rax, 1
mov rdi, 1
mov rsi, rbx
mov rdx, rcx
syscall
pop rbx
pop rbp
ret