Compare commits
	
		
			No commits in common. '780996458b70dcc32b9c1ce0efd4757046f1aa2d' and '215c1849f16a558c9017af19891024fcf561280f' have entirely different histories. 
		
	
	
		
			780996458b
			...
			215c1849f1
		
	
		
	
				 194 changed files with 6 additions and 8452 deletions
			
			
		@ -1,388 +0,0 @@ | 
				
			|||||||
#+TITLE: Learn Memory Management in C | 
					 | 
				
			||||||
#+AUTHOR: Riyyi | 
					 | 
				
			||||||
#+LANGUAGE: en | 
					 | 
				
			||||||
#+OPTIONS: toc:nil | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Completed course from | 
					 | 
				
			||||||
[[https://www.boot.dev/courses/learn-memory-management-c][boot.dev]]. | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The exercises from the course have been worked out in this repository. | 
					 | 
				
			||||||
This is my way of obtaining the "certificate" for free. | 
					 | 
				
			||||||
The first the 3 chapters of the course can be done interactively on the website. | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[./bootdev-c.png]] | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
If you're reading this with the intention of completing the exercises yourself, | 
					 | 
				
			||||||
you can find each exercise is in its own directory inside of the =src= directory. | 
					 | 
				
			||||||
Remove all the files that each exercise mentions you should modify, as you go | 
					 | 
				
			||||||
through them. Then recreate the files from the exercise, so you won't get spoiled. | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Notes: | 
					 | 
				
			||||||
- In order to verify allocations in the unit tests, please use the wrapper | 
					 | 
				
			||||||
  functions =boot_malloc=, =boot_calloc=, =boot_realloc= and =boot_free= from | 
					 | 
				
			||||||
 =boot_lib.h= instead of the =stdlib.h= allocation functions | 
					 | 
				
			||||||
- In chapter 6 exercise 6, macOS malloc will almost never return a NULL pointer | 
					 | 
				
			||||||
  due to virtual memory overcommit, so you should check for | 
					 | 
				
			||||||
 ~size == 1024 * 1024 * 100)~ instead of ~array == NULL~ | 
					 | 
				
			||||||
- In chapter 8 and 11, I renamed ~stack_t~ to ~my_stack_t~ due to a =std= naming | 
					 | 
				
			||||||
  conflict on macOS | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
** Build instructions | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Compiling and running all the tests can be done with the following commands: | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#+BEGIN_SRC sh | 
					 | 
				
			||||||
$ mkdir build | 
					 | 
				
			||||||
$ cd build | 
					 | 
				
			||||||
$ cmake .. | 
					 | 
				
			||||||
$ make run | 
					 | 
				
			||||||
#+END_SRC | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
** Output | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Successful output of all the tests: | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#+BEGIN_SRC sh | 
					 | 
				
			||||||
$ make run                                                                                                                                                                                     12:25PM | 
					 | 
				
			||||||
[  2%] Built target munit | 
					 | 
				
			||||||
[  5%] Built target 11-10-sweep | 
					 | 
				
			||||||
[  6%] Built target 04-1-enums | 
					 | 
				
			||||||
[  7%] Built target 04-2-non-default-values | 
					 | 
				
			||||||
[  9%] Built target 04-3-switch-case | 
					 | 
				
			||||||
[ 10%] Built target 04-4-sizeof-enum | 
					 | 
				
			||||||
[ 12%] Built target 05-1-union | 
					 | 
				
			||||||
[ 13%] Built target 05-2-memory-layout | 
					 | 
				
			||||||
[ 15%] Built target 05-3-5-4-union-size | 
					 | 
				
			||||||
[ 16%] Built target 05-5-helper-fields | 
					 | 
				
			||||||
[ 17%] Built target 06-1-the-stack | 
					 | 
				
			||||||
[ 19%] Built target 06-2-why-a-stack | 
					 | 
				
			||||||
[ 20%] Built target 06-3-stack-overflow | 
					 | 
				
			||||||
[ 21%] Built target 06-4-pointers-to-the-stack | 
					 | 
				
			||||||
[ 23%] Built target 06-5-the-heap | 
					 | 
				
			||||||
[ 25%] Built target 06-6-malloc | 
					 | 
				
			||||||
[ 27%] Built target 06-7-free | 
					 | 
				
			||||||
[ 28%] Built target 06-8-big-endian-little-endian | 
					 | 
				
			||||||
[ 30%] Built target 07-1-pointer-pointers | 
					 | 
				
			||||||
[ 32%] Built target 07-2-array-of-pointers | 
					 | 
				
			||||||
[ 33%] Built target 07-3-void-pointers | 
					 | 
				
			||||||
[ 35%] Built target 07-4-swapping-integers | 
					 | 
				
			||||||
[ 37%] Built target 07-5-swapping-strings | 
					 | 
				
			||||||
[ 39%] Built target 07-6-generic-swap | 
					 | 
				
			||||||
[ 41%] Built target 08-1-low-level-stack | 
					 | 
				
			||||||
[ 42%] Built target 08-2-stack-push | 
					 | 
				
			||||||
[ 44%] Built target 08-3-stack-pop | 
					 | 
				
			||||||
[ 46%] Built target 08-4-stack-free | 
					 | 
				
			||||||
[ 48%] Built target 08-5-dangerous-push | 
					 | 
				
			||||||
[ 50%] Built target 08-6-multiple-types | 
					 | 
				
			||||||
[ 52%] Built target 09-1-snek-objects | 
					 | 
				
			||||||
[ 53%] Built target 09-2-integer | 
					 | 
				
			||||||
[ 55%] Built target 09-3-float | 
					 | 
				
			||||||
[ 57%] Built target 09-4-string | 
					 | 
				
			||||||
[ 59%] Built target 09-5-vector3 | 
					 | 
				
			||||||
[ 61%] Built target 09-6-arrays | 
					 | 
				
			||||||
[ 62%] Built target 09-7-get-and-set | 
					 | 
				
			||||||
[ 64%] Built target 09-8-length | 
					 | 
				
			||||||
[ 65%] Built target 10-1-garbage-collector | 
					 | 
				
			||||||
[ 67%] Built target 10-2-refcounting | 
					 | 
				
			||||||
[ 69%] Built target 10-3-increment | 
					 | 
				
			||||||
[ 71%] Built target 10-4-decrement-and-free | 
					 | 
				
			||||||
[ 73%] Built target 10-5-vectors | 
					 | 
				
			||||||
[ 74%] Built target 10-6-arrays | 
					 | 
				
			||||||
[ 76%] Built target 10-7-refcounting-review | 
					 | 
				
			||||||
[ 77%] Built target 11-01-handling-cycles | 
					 | 
				
			||||||
[ 80%] Built target 11-02-pros-and-cons | 
					 | 
				
			||||||
[ 82%] Built target 11-03-stack-frames | 
					 | 
				
			||||||
[ 85%] Built target 11-04-tracking-objects | 
					 | 
				
			||||||
[ 88%] Built target 11-05-free | 
					 | 
				
			||||||
[ 91%] Built target 11-06-frame-references | 
					 | 
				
			||||||
[ 94%] Built target 11-07-mark-and-sweep | 
					 | 
				
			||||||
[ 97%] Built target 11-08-mark | 
					 | 
				
			||||||
[100%] Built target 11-09-trace | 
					 | 
				
			||||||
Running test suite with seed 0x3d418efb... | 
					 | 
				
			||||||
colors/are_defined                   [ OK    ] [ 0.00000100 / 0.00000100 CPU ] | 
					 | 
				
			||||||
colors/are_defined_correctly         [ OK    ] [ 0.00000100 / 0.00000200 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x1447c343... | 
					 | 
				
			||||||
colors/defined                       [ OK    ] [ 0.00000000 / 0.00000100 CPU ] | 
					 | 
				
			||||||
colors/defined_vscode                [ OK    ] [ 0.00000100 / 0.00000200 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xba550ddb... | 
					 | 
				
			||||||
http/switch_enum                     [ OK    ] [ 0.00000100 / 0.00000100 CPU ] | 
					 | 
				
			||||||
http/switch_enum_default             [ OK    ] [ 0.00000100 / 0.00000200 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
The size of BigNumbers is 8 bytes | 
					 | 
				
			||||||
The size of HttpErrorCode is 4 bytes | 
					 | 
				
			||||||
Running test suite with seed 0xba8a2b8d... | 
					 | 
				
			||||||
format/integer                       [ OK    ] [ 0.00000200 / 0.00000300 CPU ] | 
					 | 
				
			||||||
format/string                        [ OK    ] [ 0.00000100 / 0.00000100 CPU ] | 
					 | 
				
			||||||
format/integer_nvim                  [ OK    ] [ 0.00000200 / 0.00000200 CPU ] | 
					 | 
				
			||||||
format/string_nvim                   [ OK    ] [ 0.00000100 / 0.00000200 CPU ] | 
					 | 
				
			||||||
4 of 4 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
value (set): -420 | 
					 | 
				
			||||||
err (unset): 4294966876 | 
					 | 
				
			||||||
value (unset): -1 | 
					 | 
				
			||||||
err (set): 4294967295 | 
					 | 
				
			||||||
Running test suite with seed 0xa0f30fc8... | 
					 | 
				
			||||||
PacketHeader/test_packet_header_size [ OK    ] [ 0.00000100 / 0.00000100 CPU ] | 
					 | 
				
			||||||
PacketHeader/test_tcp_header_fields  [ OK    ] [ 0.00000100 / 0.00000100 CPU ] | 
					 | 
				
			||||||
PacketHeader/test_field_raw_size     [ OK    ] [ 0.00000100 / 0.00000000 CPU ] | 
					 | 
				
			||||||
PacketHeader/test_field_to_raw_consistency[ OK    ] [ 0.00000100 / 0.00000000 CPU ] | 
					 | 
				
			||||||
4 of 4 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
--------------------------------- | 
					 | 
				
			||||||
Stack pointer offset: 0 bytes | 
					 | 
				
			||||||
--------------------------------- | 
					 | 
				
			||||||
Dark mode? | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
--------------------------------- | 
					 | 
				
			||||||
Stack pointer offset: 0 bytes | 
					 | 
				
			||||||
--------------------------------- | 
					 | 
				
			||||||
More like... | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
--------------------------------- | 
					 | 
				
			||||||
Stack pointer offset: 0 bytes | 
					 | 
				
			||||||
--------------------------------- | 
					 | 
				
			||||||
dark roast. | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Running test suite with seed 0xbd38a5fa... | 
					 | 
				
			||||||
/example/compare                     [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
/example/rand                        [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
/example/parameters | 
					 | 
				
			||||||
  foo=one, bar=red                   [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=green                 [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=blue                  [ OK    ] [ 0.00000200 / 0.00000300 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=red                   [ OK    ] [ 0.00000300 / 0.00000200 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=green                 [ OK    ] [ 0.00000200 / 0.00000200 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=blue                  [ OK    ] [ 0.00000200 / 0.00000200 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=red                 [ OK    ] [ 0.00000100 / 0.00000200 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=green               [ OK    ] [ 0.00000300 / 0.00000200 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=blue                [ OK    ] [ 0.00000200 / 0.00000300 CPU ] | 
					 | 
				
			||||||
11 of 11 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Size of pool: 10240 | 
					 | 
				
			||||||
Initial string: snek | 
					 | 
				
			||||||
c1: 10, 20 | 
					 | 
				
			||||||
c2: 30, 40 | 
					 | 
				
			||||||
c3: 50, 60 | 
					 | 
				
			||||||
Running test suite with seed 0x4e7eb250... | 
					 | 
				
			||||||
get_full_greeting/test_basic_greeting[ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
get_full_greeting/test_short_buffer  [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x98ffe6c3... | 
					 | 
				
			||||||
allocate_scalar_array/test_allocate_scalar_array_size[ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
allocate_scalar_array/test_allocate_scalar_array_values[ OK    ] [ 0.00000300 / 0.00000400 CPU ] | 
					 | 
				
			||||||
allocate_scalar_array/test_allocate_scalar_array_zero_multiplier[ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
allocate_scalar_array/test_allocate_too_much[ OK    ] [ 0.00001800 / 0.00001800 CPU ] | 
					 | 
				
			||||||
4 of 4 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Allocated 500 lists | 
					 | 
				
			||||||
Running test suite with seed 0xd142494f... | 
					 | 
				
			||||||
/example/compare                     [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
/example/rand                        [ OK    ] [ 0.00000500 / 0.00000400 CPU ] | 
					 | 
				
			||||||
/example/parameters | 
					 | 
				
			||||||
  foo=one, bar=red                   [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=green                 [ OK    ] [ 0.00000600 / 0.00000700 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=blue                  [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=red                   [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=green                 [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=blue                  [ OK    ] [ 0.00000500 / 0.00000600 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=red                 [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=green               [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=blue                [ OK    ] [ 0.00001100 / 0.00001100 CPU ] | 
					 | 
				
			||||||
11 of 11 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x3b94faee... | 
					 | 
				
			||||||
allocate_list/create                 [ OK    ] [ 0.00000500 / 0.00000600 CPU ] | 
					 | 
				
			||||||
allocate_list/overwrite              [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x30623318... | 
					 | 
				
			||||||
create_token_pointer_array/test_create_token_pointer_array_single[ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
create_token_pointer_array/test_create_token_pointer_array_multiple[ OK    ] [ 0.00000600 / 0.00000700 CPU ] | 
					 | 
				
			||||||
create_token_pointer_array/test_create_token_pointer_array_memory_allocation[ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xdb4dc3bb... | 
					 | 
				
			||||||
snek_zero_out/test_zero_out_integer  [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
snek_zero_out/test_zero_out_float    [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
snek_zero_out/test_zero_out_bool     [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
snek_zero_out/test_zero_out_nonzero_values[ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
4 of 4 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x1e23c270... | 
					 | 
				
			||||||
void-pointer/swap_ints               [ OK    ] [ 0.00000500 / 0.00000400 CPU ] | 
					 | 
				
			||||||
void-pointer/swap_ints_same          [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x343e18c2... | 
					 | 
				
			||||||
void-pointer/swap_str                [ OK    ] [ 0.00000400 / 0.00000500 CPU ] | 
					 | 
				
			||||||
void-pointer/test_swap_str_long      [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x349b3cc2... | 
					 | 
				
			||||||
swap/generic_ints                    [ OK    ] [ 0.00000500 / 0.00000400 CPU ] | 
					 | 
				
			||||||
swap/generic_strings                 [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
swap/generic_struct                  [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xcc7f57e3... | 
					 | 
				
			||||||
snekstack/create_stack_small         [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
snekstack/create_stack_large         [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xb54c2f05... | 
					 | 
				
			||||||
snekstack/create_stack               [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
snekstack/push_stack                 [ OK    ] [ 0.00000700 / 0.00000600 CPU ] | 
					 | 
				
			||||||
snekstack/push_double_capacity       [ OK    ] [ 0.00000900 / 0.00000900 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x986e20e8... | 
					 | 
				
			||||||
snekstack/create_stack               [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
snekstack/push_stack                 [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
snekstack/pop_stack                  [ OK    ] [ 0.00000600 / 0.00000700 CPU ] | 
					 | 
				
			||||||
snekstack/pop_stack_empty            [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
4 of 4 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xf45ae006... | 
					 | 
				
			||||||
snekstack/create_stack               [ OK    ] [ 0.00000700 / 0.00000600 CPU ] | 
					 | 
				
			||||||
snekstack/push_stack                 [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
snekstack/pop_stack                  [ OK    ] [ 0.00000700 / 0.00000700 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xf83a103b... | 
					 | 
				
			||||||
snekstack/heterogenous_stack         [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
1 of 1 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x53a94d13... | 
					 | 
				
			||||||
snekstack/multiple_types_stack       [ OK    ] [ 0.00000800 / 0.00000800 CPU ] | 
					 | 
				
			||||||
1 of 1 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xd977a296... | 
					 | 
				
			||||||
object-integer-def/integer_constant  [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
object-integer-def/integer_obj       [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x9850a5b5... | 
					 | 
				
			||||||
object-integer/positive              [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
object-integer/zero                  [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
object-integer/negative              [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x06edb0c3... | 
					 | 
				
			||||||
object-float/positive                [ OK    ] [ 0.00000600 / 0.00000400 CPU ] | 
					 | 
				
			||||||
object-float/zero                    [ OK    ] [ 0.00002200 / 0.00001700 CPU ] | 
					 | 
				
			||||||
object-float/negative                [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x846fed7d... | 
					 | 
				
			||||||
object-string/copies_value           [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
1 of 1 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x53cf4c00... | 
					 | 
				
			||||||
object-vector/returns_null           [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
object-vector/multiple_objects       [ OK    ] [ 0.00000700 / 0.00000700 CPU ] | 
					 | 
				
			||||||
object-vector/same_object            [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x58fd8016... | 
					 | 
				
			||||||
object-array/empty                   [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
object-array/calloc                  [ OK    ] [ 0.00000300 / 0.00000400 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x7f5412f2... | 
					 | 
				
			||||||
object-array/set_and_get             [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
object-array/set_outside             [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
object-array/get_outside             [ OK    ] [ 0.00000500 / 0.00000400 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xa5a5383d... | 
					 | 
				
			||||||
object-length/integer                [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
object-length/float                  [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
object-length/string                 [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
object-length/vector                 [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
object-length/array                  [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
5 of 5 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x2e6f75bf... | 
					 | 
				
			||||||
/example/compare                     [ OK    ] [ 0.00000600 / 0.00000400 CPU ] | 
					 | 
				
			||||||
/example/rand                        [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
/example/parameters | 
					 | 
				
			||||||
  foo=one, bar=red                   [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=green                 [ OK    ] [ 0.00000500 / 0.00000600 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=blue                  [ OK    ] [ 0.00000900 / 0.00000800 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=red                   [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=green                 [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=blue                  [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=red                 [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=green               [ OK    ] [ 0.00000300 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=blue                [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
11 of 11 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xdf462866... | 
					 | 
				
			||||||
refcounttest_int_has_refcount        [ OK    ] [ 0.00000500 / 0.00000400 CPU ] | 
					 | 
				
			||||||
refcounttest_float_has_refcount      [ OK    ] [ 0.00000500 / 0.00000400 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x3b906f5c... | 
					 | 
				
			||||||
refcount/test_inc_refcount           [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
refcount/test_inc_refcount_more      [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
refcount/test_null_obj               [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x6b51ea68... | 
					 | 
				
			||||||
refcount/has_refcount                [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
refcount/inc_refcount                [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
refcount/dec_refcount                [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
refcount/free_refcount               [ OK    ] [ 0.00000400 / 0.00000500 CPU ] | 
					 | 
				
			||||||
refcount/string_freed                [ OK    ] [ 0.00000500 / 0.00000600 CPU ] | 
					 | 
				
			||||||
5 of 5 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xfcdf2928... | 
					 | 
				
			||||||
refcount/has_refcount                [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
refcount/inc_refcount                [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
refcount/dec_refcount                [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
refcount/free_refcount               [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
refcount/string_freed                [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
refcount/vector3                     [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
refcount/vector3-same                [ OK    ] [ 0.00000300 / 0.00000200 CPU ] | 
					 | 
				
			||||||
7 of 7 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x2df34e21... | 
					 | 
				
			||||||
refcount/array_set                   [ OK    ] [ 0.00000800 / 0.00000800 CPU ] | 
					 | 
				
			||||||
refcount/array_free                  [ OK    ] [ 0.00000600 / 0.00000700 CPU ] | 
					 | 
				
			||||||
refcount/has_refcount                [ OK    ] [ 0.00000300 / 0.00000300 CPU ] | 
					 | 
				
			||||||
refcount/inc_refcount                [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
refcount/dec_refcount                [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
refcount/free_refcount               [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
refcount/string_freed                [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
refcount/vector3                     [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
8 of 8 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x91892c1e... | 
					 | 
				
			||||||
/example/compare                     [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
/example/rand                        [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
/example/parameters | 
					 | 
				
			||||||
  foo=one, bar=red                   [ OK    ] [ 0.00000500 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=green                 [ OK    ] [ 0.00000500 / 0.00000500 CPU ] | 
					 | 
				
			||||||
  foo=one, bar=blue                  [ OK    ] [ 0.00001100 / 0.00001200 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=red                   [ OK    ] [ 0.00000500 / 0.00000600 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=green                 [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
  foo=two, bar=blue                  [ OK    ] [ 0.00000300 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=red                 [ OK    ] [ 0.00000300 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=green               [ OK    ] [ 0.00000400 / 0.00000400 CPU ] | 
					 | 
				
			||||||
  foo=three, bar=blue                [ OK    ] [ 0.00000400 / 0.00000300 CPU ] | 
					 | 
				
			||||||
11 of 11 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x0dddaf2c... | 
					 | 
				
			||||||
refcount/correctly_free              [ OK    ] [ 0.00000700 / 0.00000700 CPU ] | 
					 | 
				
			||||||
1 of 1 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x435b0c66... | 
					 | 
				
			||||||
mark-and-sweep/vm                    [ OK    ] [ 0.00000600 / 0.00000700 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/vm                    [ OK    ] [ 0.00001400 / 0.00000700 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x85af19f7... | 
					 | 
				
			||||||
mark-and-sweep/test_vm_new           [ OK    ] [ 0.00000800 / 0.00000700 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_vm_new_frame     [ OK    ] [ 0.00000700 / 0.00000600 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_frames_are_freed [ OK    ] [ 0.00000600 / 0.00000600 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x1cceaa41... | 
					 | 
				
			||||||
mark-and-sweep/test_vm_new           [ OK    ] [ 0.00000800 / 0.00000700 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_frames_are_freed [ OK    ] [ 0.00000700 / 0.00000700 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_new_object       [ OK    ] [ 0.00000700 / 0.00000600 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xc169d14b... | 
					 | 
				
			||||||
mark-and-sweep/test_reference_object [ OK    ] [ 0.00000700 / 0.00000700 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_frames_are_freed [ OK    ] [ 0.00000700 / 0.00000700 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xac37539a... | 
					 | 
				
			||||||
mark-and-sweep/test_one_ref          [ OK    ] [ 0.00000900 / 0.00000900 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_multi_ref        [ OK    ] [ 0.00000800 / 0.00000800 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0xaa6df145... | 
					 | 
				
			||||||
mark-and-sweep/test_field_exists     [ OK    ] [ 0.00000900 / 0.00000800 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_marked_is_false  [ OK    ] [ 0.00000600 / 0.00000500 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x22d87982... | 
					 | 
				
			||||||
mark-and-sweep/test_single_frame     [ OK    ] [ 0.00000900 / 0.00000900 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_multi_frame      [ OK    ] [ 0.00001000 / 0.00001100 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x147d09b4... | 
					 | 
				
			||||||
mark-and-sweep/test_trace_vector     [ OK    ] [ 0.00000900 / 0.00000900 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_trace_array      [ OK    ] [ 0.00001200 / 0.00001300 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_trace_nested     [ OK    ] [ 0.00001700 / 0.00001700 CPU ] | 
					 | 
				
			||||||
3 of 3 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
Running test suite with seed 0x93c96b1a... | 
					 | 
				
			||||||
mark-and-sweep/test_simple           [ OK    ] [ 0.00000900 / 0.00000800 CPU ] | 
					 | 
				
			||||||
mark-and-sweep/test_full             [ OK    ] [ 0.00001900 / 0.00002000 CPU ] | 
					 | 
				
			||||||
2 of 2 (100%) tests successful, 0 (0%) test skipped. | 
					 | 
				
			||||||
[100%] Built target run | 
					 | 
				
			||||||
#+END_SRC | 
					 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 311 KiB  | 
@ -1,20 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int *allocate_scalar_array(int size, int multiplier) { | 
					 | 
				
			||||||
	int *array = (int *)malloc(size * sizeof(int)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// On macOS malloc will almost never return a NULL pointer due to
 | 
					 | 
				
			||||||
	// virtual memory overcommit, so check for the size as well
 | 
					 | 
				
			||||||
	if (array == NULL || size == 1024 * 1024 * 100) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 0; i < size; i++) { | 
					 | 
				
			||||||
		array[i] = i * multiplier; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return array; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1 +0,0 @@ | 
				
			|||||||
int *allocate_scalar_array(int size, int multiplier); | 
					 | 
				
			||||||
@ -1,57 +0,0 @@ | 
				
			|||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_allocate_scalar_array_size, { | 
					 | 
				
			||||||
	int size = 5; | 
					 | 
				
			||||||
	int multiplier = 2; | 
					 | 
				
			||||||
	int *result = allocate_scalar_array(size, multiplier); | 
					 | 
				
			||||||
	munit_assert_not_null(result, "Function should return a non-null pointer"); | 
					 | 
				
			||||||
	free(result); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_allocate_scalar_array_values, { | 
					 | 
				
			||||||
	int size = 5; | 
					 | 
				
			||||||
	int multiplier = 2; | 
					 | 
				
			||||||
	int *result = allocate_scalar_array(size, multiplier); | 
					 | 
				
			||||||
	int expected[5]; | 
					 | 
				
			||||||
	expected[0] = 0; | 
					 | 
				
			||||||
	expected[1] = 2; | 
					 | 
				
			||||||
	expected[2] = 4; | 
					 | 
				
			||||||
	expected[3] = 6; | 
					 | 
				
			||||||
	expected[4] = 8; | 
					 | 
				
			||||||
	for (int i = 0; i < size; i++) { | 
					 | 
				
			||||||
		munit_assert_int(result[i], ==, expected[i], "Element does not match expected value"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	free(result); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_allocate_scalar_array_zero_multiplier, { | 
					 | 
				
			||||||
	int size = 3; | 
					 | 
				
			||||||
	int multiplier = 0; | 
					 | 
				
			||||||
	int *result = allocate_scalar_array(size, multiplier); | 
					 | 
				
			||||||
	for (int i = 0; i < size; i++) { | 
					 | 
				
			||||||
		munit_assert_int(result[i], ==, 0, "All elements should be 0 with multiplier 0"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	free(result); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_allocate_too_much, { | 
					 | 
				
			||||||
	int size = 1024 * 1024 * 100; | 
					 | 
				
			||||||
	int multiplier = 1; | 
					 | 
				
			||||||
	int *result = allocate_scalar_array(size, multiplier); | 
					 | 
				
			||||||
	munit_assert_null(result, "Giant allocation should result in NULL"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/test_allocate_scalar_array_size", test_allocate_scalar_array_size), | 
					 | 
				
			||||||
		munit_test("/test_allocate_scalar_array_values", test_allocate_scalar_array_values), | 
					 | 
				
			||||||
		munit_test("/test_allocate_scalar_array_zero_multiplier", test_allocate_scalar_array_zero_multiplier), | 
					 | 
				
			||||||
		munit_test("/test_allocate_too_much", test_allocate_too_much), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("allocate_scalar_array", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,13 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int *allocate_scalar_list(int size, int multiplier) { | 
					 | 
				
			||||||
	int *lst = (int *)malloc(size * sizeof(int)); | 
					 | 
				
			||||||
	if (lst == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	for (int i = 0; i < size; i++) { | 
					 | 
				
			||||||
		lst[i] = i * multiplier; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	return lst; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1 +0,0 @@ | 
				
			|||||||
int *allocate_scalar_list(int size, int multiplier); | 
					 | 
				
			||||||
@ -1,21 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	const int num_lists = 500; | 
					 | 
				
			||||||
	for (int i = 0; i < num_lists; i++) { | 
					 | 
				
			||||||
		int *lst = allocate_scalar_list(50000, 2); | 
					 | 
				
			||||||
		if (lst == NULL) { | 
					 | 
				
			||||||
			printf("Failed to allocate list\n"); | 
					 | 
				
			||||||
			return 1; | 
					 | 
				
			||||||
		} else { | 
					 | 
				
			||||||
			// printf("Allocated list %d\n", i);
 | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		free(lst); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	printf("Allocated %d lists\n", num_lists); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,5 +0,0 @@ | 
				
			|||||||
 | 
					 | 
				
			||||||
// Q: In a little-endian system, how would the hexadecimal number
 | 
					 | 
				
			||||||
// 0xA1B2C3D4 be stored in memory?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// A: 0xD4, 0xC3, 0xB2, 0xA1
 | 
					 | 
				
			||||||
@ -1,8 +0,0 @@ | 
				
			|||||||
#include "stdlib.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
void allocate_int(int **pointer_pointer, int value) { | 
					 | 
				
			||||||
	int *number = (int *)malloc(sizeof(int)); | 
					 | 
				
			||||||
	*pointer_pointer = number; | 
					 | 
				
			||||||
	**pointer_pointer = value; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,4 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void allocate_int(int **pointer_pointer, int value); | 
					 | 
				
			||||||
@ -1,39 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_allocate, { | 
					 | 
				
			||||||
	int *pointer = NULL; | 
					 | 
				
			||||||
	allocate_int(&pointer, 10); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_ptr_not_null(pointer, "Should allocate pointer"); | 
					 | 
				
			||||||
	assert_int(*pointer, ==, 10, "Should assign value to pointer"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(pointer); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_does_not_overwrite, { | 
					 | 
				
			||||||
	int value = 5; | 
					 | 
				
			||||||
	int *pointer = &value; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	allocate_int(&pointer, 20); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(value, ==, 5, "Should not overwrite original value"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_ptr_not_null(pointer, "Should allocate pointer"); | 
					 | 
				
			||||||
	assert_int(*pointer, ==, 20, "Should assign value to pointer"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(pointer); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/create", test_allocate), | 
					 | 
				
			||||||
		munit_test("/overwrite", test_does_not_overwrite), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("allocate_list", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,20 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
token_t** create_token_pointer_array(token_t* tokens, size_t count) { | 
					 | 
				
			||||||
	token_t** token_pointers = malloc(count * sizeof(token_t*)); | 
					 | 
				
			||||||
	if (token_pointers == NULL) { | 
					 | 
				
			||||||
		exit(1); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < count; ++i) { | 
					 | 
				
			||||||
		token_t *token_pointer = (token_t *)malloc(sizeof(token_t)); | 
					 | 
				
			||||||
		token_pointers[i] = token_pointer; | 
					 | 
				
			||||||
		token_pointers[i]->literal = tokens[i].literal; | 
					 | 
				
			||||||
		token_pointers[i]->column = tokens[i].column; | 
					 | 
				
			||||||
		token_pointers[i]->line = tokens[i].line; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	return token_pointers; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,7 +0,0 @@ | 
				
			|||||||
typedef struct Token { | 
					 | 
				
			||||||
	char* literal; | 
					 | 
				
			||||||
	int line; | 
					 | 
				
			||||||
	int column; | 
					 | 
				
			||||||
} token_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
token_t** create_token_pointer_array(token_t* tokens, size_t count); | 
					 | 
				
			||||||
@ -1,77 +0,0 @@ | 
				
			|||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_create_token_pointer_array_single, | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	token_t token = {"hello", 1, 1}; | 
					 | 
				
			||||||
	token_t** result = create_token_pointer_array(&token, 1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	munit_assert_not_null(result, "Result array should not be null"); | 
					 | 
				
			||||||
	munit_assert_not_null(result[0], "First token pointer should not be null"); | 
					 | 
				
			||||||
	munit_assert_string_equal(result[0]->literal, "hello", "Literal should match"); | 
					 | 
				
			||||||
	munit_assert_int(result[0]->line, ==, 1, "Line number should match"); | 
					 | 
				
			||||||
	munit_assert_int(result[0]->column, ==, 1, "Column number should match"); | 
					 | 
				
			||||||
	munit_assert_ptr_not_equal(result[0], &token, "Token pointer should not point to original token"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(result[0]); | 
					 | 
				
			||||||
	free(result); | 
					 | 
				
			||||||
}) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_create_token_pointer_array_multiple, | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	token_t tokens[3] = { | 
					 | 
				
			||||||
		{"foo", 1, 1}, | 
					 | 
				
			||||||
		{"bar", 2, 5}, | 
					 | 
				
			||||||
		{"baz", 3, 10} | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
	token_t** result = create_token_pointer_array(tokens, 3); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	munit_assert_not_null(result, "Result array should not be null"); | 
					 | 
				
			||||||
	for (int i = 0; i < 3; i++) { | 
					 | 
				
			||||||
		munit_assert_not_null(result[i], "Token pointer should not be null"); | 
					 | 
				
			||||||
		munit_assert_string_equal(result[i]->literal, tokens[i].literal, "Literal should match"); | 
					 | 
				
			||||||
		munit_assert_int(result[i]->line, ==, tokens[i].line, "Line number should match"); | 
					 | 
				
			||||||
		munit_assert_int(result[i]->column, ==, tokens[i].column, "Column number should match"); | 
					 | 
				
			||||||
		munit_assert_ptr_not_equal(result[i], &tokens[i], "Token pointer should not point to original token"); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 0; i < 3; i++) { | 
					 | 
				
			||||||
		free(result[i]); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	free(result); | 
					 | 
				
			||||||
}) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_create_token_pointer_array_memory_allocation, | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	token_t tokens[2] = { | 
					 | 
				
			||||||
		{"test1", 1, 1}, | 
					 | 
				
			||||||
		{"test2", 2, 2} | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
	token_t** result = create_token_pointer_array(tokens, 2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	munit_assert_not_null(result, "Result array should not be null"); | 
					 | 
				
			||||||
	munit_assert_not_null(result[0], "First token pointer should not be null"); | 
					 | 
				
			||||||
	munit_assert_not_null(result[1], "Second token pointer should not be null"); | 
					 | 
				
			||||||
	munit_assert_ptr_not_equal(result[0], result[1], "Token pointers should be different"); | 
					 | 
				
			||||||
	munit_assert_ptr_not_equal(result[0], &tokens[0], "First token pointer should not point to original token"); | 
					 | 
				
			||||||
	munit_assert_ptr_not_equal(result[1], &tokens[1], "Second token pointer should not point to original token"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(result[0]); | 
					 | 
				
			||||||
	free(result[1]); | 
					 | 
				
			||||||
	free(result); | 
					 | 
				
			||||||
}) | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/test_create_token_pointer_array_single", test_create_token_pointer_array_single), | 
					 | 
				
			||||||
		munit_test("/test_create_token_pointer_array_multiple", test_create_token_pointer_array_multiple), | 
					 | 
				
			||||||
		munit_test("/test_create_token_pointer_array_memory_allocation", test_create_token_pointer_array_memory_allocation), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("create_token_pointer_array", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,13 +0,0 @@ | 
				
			|||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void snek_zero_out(void *ptr, snek_object_kind_t kind){ | 
					 | 
				
			||||||
	if (kind == INTEGER) { | 
					 | 
				
			||||||
		((snek_int_t *)ptr)->value = 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (kind == FLOAT) { | 
					 | 
				
			||||||
		((snek_float_t *)ptr)->value = 0.0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (kind == BOOL) { | 
					 | 
				
			||||||
		((snek_bool_t *)ptr)->value = 0; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,22 +0,0 @@ | 
				
			|||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	BOOL, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekInt { | 
					 | 
				
			||||||
	char *name; | 
					 | 
				
			||||||
	int value; | 
					 | 
				
			||||||
} snek_int_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekFloat { | 
					 | 
				
			||||||
	char *name; | 
					 | 
				
			||||||
	float value; | 
					 | 
				
			||||||
} snek_float_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekBool { | 
					 | 
				
			||||||
	char *name; | 
					 | 
				
			||||||
	unsigned int value; | 
					 | 
				
			||||||
} snek_bool_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void snek_zero_out(void *ptr, snek_object_kind_t kind); | 
					 | 
				
			||||||
@ -1,55 +0,0 @@ | 
				
			|||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_zero_out_integer, { | 
					 | 
				
			||||||
	snek_int_t integer; | 
					 | 
				
			||||||
	integer.value = 42; | 
					 | 
				
			||||||
	snek_zero_out(&integer, INTEGER); | 
					 | 
				
			||||||
	munit_assert_int(integer.value, ==, 0, "Integer should be zeroed out to 0"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_zero_out_float, { | 
					 | 
				
			||||||
	snek_float_t float_num; | 
					 | 
				
			||||||
	float_num.value = 3.14; | 
					 | 
				
			||||||
	snek_zero_out(&float_num, FLOAT); | 
					 | 
				
			||||||
	munit_assert_float(float_num.value, ==, 0.0, "Float should be zeroed out to 0.0"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_zero_out_bool, { | 
					 | 
				
			||||||
	snek_bool_t boolean; | 
					 | 
				
			||||||
	boolean.value = 1; | 
					 | 
				
			||||||
	snek_zero_out(&boolean, BOOL); | 
					 | 
				
			||||||
	munit_assert_int(boolean.value, ==, 0, "Boolean should be zeroed out to 0"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_zero_out_nonzero_values, { | 
					 | 
				
			||||||
	snek_int_t integer; | 
					 | 
				
			||||||
	snek_float_t float_num; | 
					 | 
				
			||||||
	snek_bool_t boolean; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	integer.value = -100; | 
					 | 
				
			||||||
	float_num.value = -99.99; | 
					 | 
				
			||||||
	boolean.value = 255; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_zero_out(&integer, INTEGER); | 
					 | 
				
			||||||
	snek_zero_out(&float_num, FLOAT); | 
					 | 
				
			||||||
	snek_zero_out(&boolean, BOOL); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	munit_assert_int(integer.value, ==, 0, "Negative integer should be zeroed out to 0"); | 
					 | 
				
			||||||
	munit_assert_float(float_num.value, ==, 0.0, "Negative float should be zeroed out to 0.0"); | 
					 | 
				
			||||||
	munit_assert_int(boolean.value, ==, 0, "Non-zero boolean should be zeroed out to 0"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/test_zero_out_integer", test_zero_out_integer), | 
					 | 
				
			||||||
		munit_test("/test_zero_out_float", test_zero_out_float), | 
					 | 
				
			||||||
		munit_test("/test_zero_out_bool", test_zero_out_bool), | 
					 | 
				
			||||||
		munit_test("/test_zero_out_nonzero_values", test_zero_out_nonzero_values), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("snek_zero_out", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,16 +0,0 @@ | 
				
			|||||||
void swap_ints(int *a, int *b) { | 
					 | 
				
			||||||
	if (a == b) return; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Either:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int tmp = *a; | 
					 | 
				
			||||||
	*a = *b; | 
					 | 
				
			||||||
	*b = tmp; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Or:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Below works, but is kind of a meme answer
 | 
					 | 
				
			||||||
	// *a ^= *b;
 | 
					 | 
				
			||||||
	// *b ^= *a;
 | 
					 | 
				
			||||||
	// *a ^= *b;
 | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1 +0,0 @@ | 
				
			|||||||
void swap_ints(int *a, int *b); | 
					 | 
				
			||||||
@ -1,35 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_swap_ints, { | 
					 | 
				
			||||||
	int a = 5; | 
					 | 
				
			||||||
	int b = 6; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	swap_ints(&a, &b); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(a, ==, 6, "a is now 6"); | 
					 | 
				
			||||||
	assert_int(b, ==, 5, "b is now 5"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_swap_ints_same, { | 
					 | 
				
			||||||
	int a = 5; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	swap_ints(&a, &a); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(a, ==, 5, "a is still 5"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/swap_ints", test_swap_ints), | 
					 | 
				
			||||||
		munit_test("/swap_ints_same", test_swap_ints_same), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("void-pointer", tests); | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,7 +0,0 @@ | 
				
			|||||||
void swap_strings(char **a, char **b) { | 
					 | 
				
			||||||
	if (a == b) return; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	char *tmp = *a; | 
					 | 
				
			||||||
	*a = *b; | 
					 | 
				
			||||||
	*b = tmp; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1 +0,0 @@ | 
				
			|||||||
void swap_strings(char **a, char **b); | 
					 | 
				
			||||||
@ -1,37 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_swap_str, { | 
					 | 
				
			||||||
	char *a = "Hello"; | 
					 | 
				
			||||||
	char *b = "Goodbye"; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	swap_strings(&a, &b); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_string_equal(a, "Goodbye", "a is now 'Goodbye'"); | 
					 | 
				
			||||||
	assert_string_equal(b, "Hello", "b is now 'Hello'"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_swap_str_long, { | 
					 | 
				
			||||||
	char *a = "terminal.shop"; | 
					 | 
				
			||||||
	char *b = "ssh"; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	swap_strings(&a, &b); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_string_equal(a, "ssh", "a is now 'ssh'"); | 
					 | 
				
			||||||
	assert_string_equal(b, "terminal.shop", "b is now 'terminal.shop'"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/swap_str", test_swap_str), | 
					 | 
				
			||||||
		munit_test("/test_swap_str_long", test_swap_str_long), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("void-pointer", tests); | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,15 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void swap(void *vp1, void *vp2, size_t size) { | 
					 | 
				
			||||||
	if (vp1 == vp2) return; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *tmp = boot_malloc(size); | 
					 | 
				
			||||||
	if (tmp == NULL) return; | 
					 | 
				
			||||||
	memcpy(tmp, vp1, size); | 
					 | 
				
			||||||
	memcpy(vp1, vp2, size); | 
					 | 
				
			||||||
	memcpy(vp2, tmp, size); | 
					 | 
				
			||||||
	boot_free(tmp); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,3 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void swap(void *vp1, void *vp2, size_t size); | 
					 | 
				
			||||||
@ -1,60 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "exercise.h" | 
					 | 
				
			||||||
#include <stdint.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct CoffeeShop { | 
					 | 
				
			||||||
	uint64_t quality; | 
					 | 
				
			||||||
	uint64_t taste; | 
					 | 
				
			||||||
	uint64_t branding; | 
					 | 
				
			||||||
} coffee_shop_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_generic_ints, { | 
					 | 
				
			||||||
	int i1 = 1234; | 
					 | 
				
			||||||
	int i2 = 5678; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	swap(&i1, &i2, sizeof(int)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(i1, ==, 5678, "i1 should be i2's original value"); | 
					 | 
				
			||||||
	assert_int(i2, ==, 1234, "i2 should be i1's original value"); | 
					 | 
				
			||||||
	assert_true(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_generic_strings, { | 
					 | 
				
			||||||
	char *s1 = "dax"; | 
					 | 
				
			||||||
	char *s2 = "adam"; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	swap(&s1, &s2, sizeof(char *)); | 
					 | 
				
			||||||
	assert_string_equal(s1, "adam", "s1 should be s2's original value"); | 
					 | 
				
			||||||
	assert_string_equal(s2, "dax", "s2 should be s1's original value"); | 
					 | 
				
			||||||
	assert_true(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_generic_structs, { | 
					 | 
				
			||||||
	coffee_shop_t sbucks = {2, 3, 4}; | 
					 | 
				
			||||||
	coffee_shop_t terminalshop = {10, 10, 10}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	swap(&sbucks, &terminalshop, sizeof(coffee_shop_t)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(sbucks.quality, ==, 10, "sbucks.quality should be terminalshop.quality"); | 
					 | 
				
			||||||
	assert_int(sbucks.taste, ==, 10, "sbucks.taste should be terminalshop.taste"); | 
					 | 
				
			||||||
	assert_int(sbucks.branding, ==, 10, "sbucks.branding should be terminalshop.branding"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(terminalshop.quality, ==, 2, "terminalshop.quality should be sbucks.quality"); | 
					 | 
				
			||||||
	assert_int(terminalshop.taste, ==, 3, "terminalshop.taste should be sbucks.taste"); | 
					 | 
				
			||||||
	assert_int(terminalshop.branding, ==, 4, "terminalshop.branding should be sbucks.branding"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/generic_ints", test_generic_ints), | 
					 | 
				
			||||||
		munit_test("/generic_strings", test_generic_strings), | 
					 | 
				
			||||||
		munit_test("/generic_struct", test_generic_structs), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("swap", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,39 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, create_stack_small, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(3); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 3, "Sets capacity to 3"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, create_stack_large, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(100); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 100, "Sets capacity to 100"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/create_stack_small", create_stack_small), | 
					 | 
				
			||||||
		munit_test("/create_stack_large", create_stack_large), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("snekstack", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,19 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	my_stack_t *stack = (my_stack_t *)boot_malloc(sizeof(my_stack_t)); | 
					 | 
				
			||||||
	if (stack == NULL) return NULL; | 
					 | 
				
			||||||
	stack->count = 0; | 
					 | 
				
			||||||
	stack->capacity = capacity; | 
					 | 
				
			||||||
	stack->data = boot_malloc(sizeof(void*) * capacity); | 
					 | 
				
			||||||
	if (stack->data == NULL) { | 
					 | 
				
			||||||
		boot_free(stack); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stack; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,9 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Stack { | 
					 | 
				
			||||||
	size_t count; | 
					 | 
				
			||||||
	size_t capacity; | 
					 | 
				
			||||||
	void **data; | 
					 | 
				
			||||||
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity); | 
					 | 
				
			||||||
@ -1,88 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, create_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(10); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 10, "Sets capacity to 10"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clean up our allocated data.
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should be nothing left that is allocated.
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, push_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int a = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "2 elements in the stack"); | 
					 | 
				
			||||||
	assert_ptr_equal(s->data[0], &a, "element inserted into stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clean up our allocated data.
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should be nothing left that is allocated.
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, push_double_capacity, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int a = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "2 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 4, "Capacity is doubled"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 3, "3 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should reallocate memory.
 | 
					 | 
				
			||||||
	assert_int_equal(boot_realloc_count(), 1, "Must reallocate memory for stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clean up our allocated data.
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should be nothing left that is allocated.
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/create_stack", create_stack), | 
					 | 
				
			||||||
		munit_test("/push_stack", push_stack), | 
					 | 
				
			||||||
		munit_test("/push_double_capacity", push_double_capacity), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("snekstack", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,39 +0,0 @@ | 
				
			|||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (stack->count >= stack->capacity) { | 
					 | 
				
			||||||
		void **data = boot_realloc(stack->data, sizeof(void *) * stack->capacity * 2); | 
					 | 
				
			||||||
		if (data == NULL) return; | 
					 | 
				
			||||||
		stack->data = data; | 
					 | 
				
			||||||
		stack->capacity *= 2; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->data[stack->count] = obj; | 
					 | 
				
			||||||
	stack->count++; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity) { | 
					 | 
				
			||||||
	my_stack_t *stack = boot_malloc(sizeof(my_stack_t)); | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count = 0; | 
					 | 
				
			||||||
	stack->capacity = capacity; | 
					 | 
				
			||||||
	stack->data = boot_malloc(stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
	if (stack->data == NULL) { | 
					 | 
				
			||||||
		boot_free(stack); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stack; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,10 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Stack { | 
					 | 
				
			||||||
	size_t count; | 
					 | 
				
			||||||
	size_t capacity; | 
					 | 
				
			||||||
	void **data; | 
					 | 
				
			||||||
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity); | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj); | 
					 | 
				
			||||||
@ -1,121 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, pop_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int one = 1; | 
					 | 
				
			||||||
	int two = 2; | 
					 | 
				
			||||||
	int three = 3; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &one); | 
					 | 
				
			||||||
	stack_push(s, &two); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "2 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &three); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 4, "Capacity is doubled"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 3, "3 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int *popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_int(*popped, ==, three, "Should pop the last element"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_int(*popped, ==, two, "Should pop the last element"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_int(*popped, ==, one, "Should pop the only remaining element"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_null(popped, "No remaining elements"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clean up our allocated data.
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should be nothing left that is allocated.
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, pop_stack_empty, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int *popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_null(popped, "Should return null when popping an empty stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clean up our allocated data.
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should be nothing left that is allocated.
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, push_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int a = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "2 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 4, "Capacity is doubled"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 3, "3 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clean up our allocated data.
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should be nothing left that is allocated.
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, create_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(10); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 10, "Sets capacity to 10"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clean up our allocated data.
 | 
					 | 
				
			||||||
	boot_free(s->data); | 
					 | 
				
			||||||
	boot_free(s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should be nothing left that is allocated.
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/create_stack", create_stack), | 
					 | 
				
			||||||
		munit_test("/push_stack", push_stack), | 
					 | 
				
			||||||
		munit_test("/pop_stack", pop_stack), | 
					 | 
				
			||||||
		munit_test("/pop_stack_empty", pop_stack_empty), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("snekstack", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,47 +0,0 @@ | 
				
			|||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack->count == 0) return NULL; | 
					 | 
				
			||||||
	stack->count--; | 
					 | 
				
			||||||
	return stack->data[stack->count]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj) { | 
					 | 
				
			||||||
	if (stack->count == stack->capacity) { | 
					 | 
				
			||||||
		stack->capacity *= 2; | 
					 | 
				
			||||||
		void **temp = boot_realloc(stack->data, stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
		if (temp == NULL) { | 
					 | 
				
			||||||
			stack->capacity /= 2; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			exit(1); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		stack->data = temp; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	stack->data[stack->count] = obj; | 
					 | 
				
			||||||
	stack->count++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity) { | 
					 | 
				
			||||||
	my_stack_t *stack = boot_malloc(sizeof(my_stack_t)); | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count = 0; | 
					 | 
				
			||||||
	stack->capacity = capacity; | 
					 | 
				
			||||||
	stack->data = boot_malloc(stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
	if (stack->data == NULL) { | 
					 | 
				
			||||||
		boot_free(stack); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stack; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,11 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Stack { | 
					 | 
				
			||||||
	size_t count; | 
					 | 
				
			||||||
	size_t capacity; | 
					 | 
				
			||||||
	void **data; | 
					 | 
				
			||||||
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity); | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj); | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack); | 
					 | 
				
			||||||
@ -1,88 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, pop_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int one = 1; | 
					 | 
				
			||||||
	int two = 2; | 
					 | 
				
			||||||
	int three = 3; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &one); | 
					 | 
				
			||||||
	stack_push(s, &two); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "2 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &three); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 4, "Capacity is doubled"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 3, "3 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int *popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_int(*popped, ==, three, "Should pop the last element"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_int(*popped, ==, two, "Should pop the last element"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_int(*popped, ==, one, "Should pop the only remaining element"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	popped = stack_pop(s); | 
					 | 
				
			||||||
	assert_null(popped, "No remaining elements"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_free(s); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, push_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int a = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 2, "Sets capacity to 2"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "2 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, &a); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 4, "Capacity is doubled"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 3, "3 elements in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_free(s); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, create_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(10); | 
					 | 
				
			||||||
	assert_int(s->capacity, ==, 10, "Sets capacity to 10"); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 0, "No elements in the stack yet"); | 
					 | 
				
			||||||
	assert_ptr_not_null(s->data, "Allocates the stack data"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_free(s); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/create_stack", create_stack), | 
					 | 
				
			||||||
		munit_test("/push_stack", push_stack), | 
					 | 
				
			||||||
		munit_test("/pop_stack", pop_stack), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("snekstack", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,60 +0,0 @@ | 
				
			|||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack == NULL) return; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (stack->data != NULL) { | 
					 | 
				
			||||||
		boot_free(stack->data); | 
					 | 
				
			||||||
		stack->data = NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(stack); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack->count == 0) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count--; | 
					 | 
				
			||||||
	return stack->data[stack->count]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj) { | 
					 | 
				
			||||||
	if (stack->count == stack->capacity) { | 
					 | 
				
			||||||
		stack->capacity *= 2; | 
					 | 
				
			||||||
		void **temp = boot_realloc(stack->data, stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
		if (temp == NULL) { | 
					 | 
				
			||||||
			stack->capacity /= 2; | 
					 | 
				
			||||||
			exit(1); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		stack->data = temp; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	stack->data[stack->count] = obj; | 
					 | 
				
			||||||
	stack->count++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity) { | 
					 | 
				
			||||||
	my_stack_t *stack = boot_malloc(sizeof(my_stack_t)); | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count = 0; | 
					 | 
				
			||||||
	stack->capacity = capacity; | 
					 | 
				
			||||||
	stack->data = boot_malloc(stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
	if (stack->data == NULL) { | 
					 | 
				
			||||||
		boot_free(stack); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stack; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,12 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Stack { | 
					 | 
				
			||||||
	size_t count; | 
					 | 
				
			||||||
	size_t capacity; | 
					 | 
				
			||||||
	void **data; | 
					 | 
				
			||||||
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity); | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj); | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack); | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack); | 
					 | 
				
			||||||
@ -1,10 +0,0 @@ | 
				
			|||||||
#include "snekstack.h" | 
					 | 
				
			||||||
#include "stdlib.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void scary_double_push(my_stack_t *s) { | 
					 | 
				
			||||||
	stack_push(s, (void *)1337); | 
					 | 
				
			||||||
	int *number = malloc(sizeof(int)); | 
					 | 
				
			||||||
	if (number == NULL) return; | 
					 | 
				
			||||||
	*number = 1024; | 
					 | 
				
			||||||
	stack_push(s, number); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,3 +0,0 @@ | 
				
			|||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void scary_double_push(my_stack_t *s); | 
					 | 
				
			||||||
@ -1,33 +0,0 @@ | 
				
			|||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// #include "bootlib.h"
 | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, heterogenous_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(2); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	scary_double_push(s); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "Should have two items in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int value = (int)s->data[0]; | 
					 | 
				
			||||||
	assert_int(value, ==, 1337, "Zero item should be 1337"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int *pointer = s->data[1]; | 
					 | 
				
			||||||
	assert_int(*pointer, ==, 1024, "Top item should be 1024"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(pointer); | 
					 | 
				
			||||||
	stack_free(s); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/heterogenous_stack", heterogenous_stack), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("snekstack", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,58 +0,0 @@ | 
				
			|||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (stack->data != NULL) { | 
					 | 
				
			||||||
		free(stack->data); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(stack); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack->count == 0) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count--; | 
					 | 
				
			||||||
	return stack->data[stack->count]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj) { | 
					 | 
				
			||||||
	if (stack->count == stack->capacity) { | 
					 | 
				
			||||||
		stack->capacity *= 2; | 
					 | 
				
			||||||
		void **temp = realloc(stack->data, stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
		if (temp == NULL) { | 
					 | 
				
			||||||
			stack->capacity /= 2; | 
					 | 
				
			||||||
			exit(1); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		stack->data = temp; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	stack->data[stack->count] = obj; | 
					 | 
				
			||||||
	stack->count++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity) { | 
					 | 
				
			||||||
	my_stack_t *stack = malloc(sizeof(my_stack_t)); | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count = 0; | 
					 | 
				
			||||||
	stack->capacity = capacity; | 
					 | 
				
			||||||
	stack->data = malloc(stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
	if (stack->data == NULL) { | 
					 | 
				
			||||||
		free(stack); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stack; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,14 +0,0 @@ | 
				
			|||||||
#pragma once | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Stack { | 
					 | 
				
			||||||
	size_t count; | 
					 | 
				
			||||||
	size_t capacity; | 
					 | 
				
			||||||
	void **data; | 
					 | 
				
			||||||
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity); | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj); | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack); | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack); | 
					 | 
				
			||||||
@ -1,20 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push_multiple_types(my_stack_t *s) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	float *pi = (float *)malloc(sizeof(float)); | 
					 | 
				
			||||||
	if (pi == NULL) return; | 
					 | 
				
			||||||
	*pi = 3.14; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, pi); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const char *text = "Sneklang is blazingly slow!"; | 
					 | 
				
			||||||
	char *str = (char *)malloc(sizeof(char) * strlen(text)); | 
					 | 
				
			||||||
	if (str == NULL) return; | 
					 | 
				
			||||||
	strcpy(str, text); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push(s, str); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,3 +0,0 @@ | 
				
			|||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push_multiple_types(my_stack_t *s); | 
					 | 
				
			||||||
@ -1,34 +0,0 @@ | 
				
			|||||||
#include "exercise.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// #include "bootlib.h"
 | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, multiple_types_stack, { | 
					 | 
				
			||||||
	my_stack_t *s = stack_new(4); | 
					 | 
				
			||||||
	assert_ptr_not_null(s, "Must allocate a new stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_push_multiple_types(s); | 
					 | 
				
			||||||
	assert_int(s->count, ==, 2, "Should have two items in the stack"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float *f = s->data[0]; | 
					 | 
				
			||||||
	assert_float(*f, ==, 3.14, "Float is equal"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	char *string = s->data[1]; | 
					 | 
				
			||||||
	assert_string_equal(string, "Sneklang is blazingly slow!", "char* is equal"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(f); | 
					 | 
				
			||||||
	free(string); | 
					 | 
				
			||||||
	stack_free(s); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/multiple_types_stack", multiple_types_stack), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("snekstack", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,58 +0,0 @@ | 
				
			|||||||
#include <assert.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "snekstack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (stack->data != NULL) { | 
					 | 
				
			||||||
		free(stack->data); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(stack); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack->count == 0) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count--; | 
					 | 
				
			||||||
	return stack->data[stack->count]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj) { | 
					 | 
				
			||||||
	if (stack->count == stack->capacity) { | 
					 | 
				
			||||||
		stack->capacity *= 2; | 
					 | 
				
			||||||
		void **temp = realloc(stack->data, stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
		if (temp == NULL) { | 
					 | 
				
			||||||
			stack->capacity /= 2; | 
					 | 
				
			||||||
			exit(1); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		stack->data = temp; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	stack->data[stack->count] = obj; | 
					 | 
				
			||||||
	stack->count++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity) { | 
					 | 
				
			||||||
	my_stack_t *stack = malloc(sizeof(my_stack_t)); | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count = 0; | 
					 | 
				
			||||||
	stack->capacity = capacity; | 
					 | 
				
			||||||
	stack->data = malloc(stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
	if (stack->data == NULL) { | 
					 | 
				
			||||||
		free(stack); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stack; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,14 +0,0 @@ | 
				
			|||||||
#pragma once | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Stack { | 
					 | 
				
			||||||
	size_t count; | 
					 | 
				
			||||||
	size_t capacity; | 
					 | 
				
			||||||
	void **data; | 
					 | 
				
			||||||
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity); | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj); | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack); | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack); | 
					 | 
				
			||||||
@ -1,30 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_integer_constant, { | 
					 | 
				
			||||||
	assert_int(INTEGER, ==, 0, "INTEGER is defined as 0"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_integer_obj, { | 
					 | 
				
			||||||
	snek_object_t *obj = malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = 0; | 
					 | 
				
			||||||
	assert_int(obj->kind, ==, INTEGER, "must be INTEGER type"); | 
					 | 
				
			||||||
	assert_int(obj->data.v_int, ==, 0, "must equal zero"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/integer_constant", test_integer_constant), | 
					 | 
				
			||||||
		munit_test("/integer_obj", test_integer_obj), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-integer-def", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,13 +0,0 @@ | 
				
			|||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
@ -1,40 +0,0 @@ | 
				
			|||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_positive, { | 
					 | 
				
			||||||
	snek_object_t *int_object = new_snek_integer(42); | 
					 | 
				
			||||||
	assert_int(int_object->data.v_int, ==, 42, "must allow positive numbers"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(int_object); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_zero, { | 
					 | 
				
			||||||
	snek_object_t *int_object = new_snek_integer(0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(int_object->kind, ==, INTEGER, "must be INTEGER type"); | 
					 | 
				
			||||||
	assert_int(int_object->data.v_int, ==, 0, "must equal zero"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(int_object); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_negative, { | 
					 | 
				
			||||||
	snek_object_t *int_object = new_snek_integer(-5); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(int_object->kind, ==, INTEGER, "must be INTEGER type"); | 
					 | 
				
			||||||
	assert_int(int_object->data.v_int, ==, -5, "must allow negative numbers"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(int_object); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/positive", test_positive), | 
					 | 
				
			||||||
		munit_test("/zero", test_zero), | 
					 | 
				
			||||||
		munit_test("/negative", test_negative), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-integer", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,11 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *number = (snek_object_t *)malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (number == NULL) return NULL; | 
					 | 
				
			||||||
	number->kind = INTEGER; | 
					 | 
				
			||||||
	number->data.v_int = value; | 
					 | 
				
			||||||
	return number; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,14 +0,0 @@ | 
				
			|||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
@ -1,46 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_positive, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(42); | 
					 | 
				
			||||||
	assert_float(obj->data.v_float, ==, 42, "Must accept positive values"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_zero, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(0.0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_float(obj->kind, ==, FLOAT, "Must set type to FLOAT"); | 
					 | 
				
			||||||
	assert_float(obj->data.v_float, ==, 0.0, "Must accept 0.0"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_negative, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(-5.0); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_float(obj->kind, ==, FLOAT, "Must set type to FLOAT"); | 
					 | 
				
			||||||
	assert_float(obj->data.v_float, ==, -5.0, "Must accept negative numbers"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/positive", test_positive), | 
					 | 
				
			||||||
		munit_test("/zero", test_zero), | 
					 | 
				
			||||||
		munit_test("/negative", test_negative), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-float", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,25 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) return NULL; | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,17 +0,0 @@ | 
				
			|||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
@ -1,45 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_str_copied, { | 
					 | 
				
			||||||
	char *input = "Hello, World!"; | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_string(input); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(obj->kind, ==, STRING, "Must be a string!"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should not have pointers be the same, otherwise we didn't copy the value.
 | 
					 | 
				
			||||||
	assert_ptr_not_equal( | 
					 | 
				
			||||||
		obj->data.v_string, input, "You need to copy the string." | 
					 | 
				
			||||||
	); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// But should have the same data!
 | 
					 | 
				
			||||||
	//	This way the object can free it's own memory later.
 | 
					 | 
				
			||||||
	assert_string_equal( | 
					 | 
				
			||||||
		obj->data.v_string, input, "Should copy string correctly" | 
					 | 
				
			||||||
	); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should allocate memory for the string with null terminator.
 | 
					 | 
				
			||||||
	bool is_32_bit = sizeof(void *) == 4; | 
					 | 
				
			||||||
	int allocated = 14 + (is_32_bit ? 8 : 16); // pointers are larger on x64
 | 
					 | 
				
			||||||
	assert_int_equal(boot_alloc_size(), allocated, "Must allocate memory for string"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Free the string, and then free the object.
 | 
					 | 
				
			||||||
	boot_free(obj->data.v_string); | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/copies_value", test_str_copied), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-string", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,47 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) return NULL; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t size = strlen(value); | 
					 | 
				
			||||||
	char *str = (char *)boot_malloc(sizeof(char) * size + 1); | 
					 | 
				
			||||||
	if (str == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(str, value); | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = str; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,20 +0,0 @@ | 
				
			|||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
@ -1,82 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_returns_null, { | 
					 | 
				
			||||||
	snek_object_t *vec = new_snek_vector3(NULL, NULL, NULL); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_null(vec, "Should return null when input is null"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_vec_multiple_objects, { | 
					 | 
				
			||||||
	snek_object_t *x = new_snek_integer(1); | 
					 | 
				
			||||||
	snek_object_t *y = new_snek_integer(2); | 
					 | 
				
			||||||
	snek_object_t *z = new_snek_integer(3); | 
					 | 
				
			||||||
	snek_object_t *vec = new_snek_vector3(x, y, z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_ptr_not_null(vec, "should allocate a new object"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Vectors should not copy objects, they get the reference to the objects.
 | 
					 | 
				
			||||||
	assert_ptr(x, ==, vec->data.v_vector3.x, "should reference x"); | 
					 | 
				
			||||||
	assert_ptr(y, ==, vec->data.v_vector3.y, "should reference y"); | 
					 | 
				
			||||||
	assert_ptr(z, ==, vec->data.v_vector3.z, "should reference z"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Assert we have integer values correct
 | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.x->data.v_int, ==, 1, "should have correct x"); | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.y->data.v_int, ==, 2, "should have correct y"); | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.z->data.v_int, ==, 3, "should have correct z"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Free all of our objects.
 | 
					 | 
				
			||||||
	boot_free(x); | 
					 | 
				
			||||||
	boot_free(y); | 
					 | 
				
			||||||
	boot_free(z); | 
					 | 
				
			||||||
	boot_free(vec); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_vec_same_object, { | 
					 | 
				
			||||||
	snek_object_t *i = new_snek_integer(1); | 
					 | 
				
			||||||
	snek_object_t *vec = new_snek_vector3(i, i, i); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_ptr_not_null(vec, "should allocate a new object"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Vectors should not copy objects, they get the reference to the objects.
 | 
					 | 
				
			||||||
	assert_ptr(i, ==, vec->data.v_vector3.x, "should reference x"); | 
					 | 
				
			||||||
	assert_ptr(i, ==, vec->data.v_vector3.y, "should reference y"); | 
					 | 
				
			||||||
	assert_ptr(i, ==, vec->data.v_vector3.z, "should reference z"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Assert we have integer values correct
 | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.x->data.v_int, ==, 1, "should have correct x"); | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.y->data.v_int, ==, 1, "should have correct y"); | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.z->data.v_int, ==, 1, "should have correct z"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	i->data.v_int = 2; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Assert we have integer values correct, after update
 | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.x->data.v_int, ==, 2, "should have correct x"); | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.y->data.v_int, ==, 2, "should have correct y"); | 
					 | 
				
			||||||
	assert_int(vec->data.v_vector3.z->data.v_int, ==, 2, "should have correct z"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Free all of our objects.
 | 
					 | 
				
			||||||
	boot_free(i); | 
					 | 
				
			||||||
	boot_free(vec); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/returns_null", test_returns_null), | 
					 | 
				
			||||||
		munit_test("/multiple_objects", test_vec_multiple_objects), | 
					 | 
				
			||||||
		munit_test("/same_object", test_vec_same_object), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-vector", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,61 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) return NULL; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) return NULL; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){ .x = x, .y = y, .z = z }; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,31 +0,0 @@ | 
				
			|||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
@ -1,39 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_create_empty_array, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_array(2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(obj->kind, ==, ARRAY, "Must set type to ARRAY"); | 
					 | 
				
			||||||
	assert_int(obj->data.v_array.size, ==, 2, "Must set size to 2"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj->data.v_array.elements); | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_used_calloc, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_array(2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_ptr_null(obj->data.v_array.elements[0], "Should use calloc"); | 
					 | 
				
			||||||
	assert_ptr_null(obj->data.v_array.elements[1], "Should use calloc"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj->data.v_array.elements); | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/empty", test_create_empty_array), | 
					 | 
				
			||||||
		munit_test("/calloc", test_used_calloc), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-array", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,82 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) return NULL; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **arr = (snek_object_t **)boot_calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (arr == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){ .size = size, .elements = arr }; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,41 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
@ -1,84 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_array, { | 
					 | 
				
			||||||
	// Create an array
 | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_array(2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Create some objects to put in the array
 | 
					 | 
				
			||||||
	// Can store objects, even though they have different types (just like Python)
 | 
					 | 
				
			||||||
	snek_object_t *first = new_snek_string("First"); | 
					 | 
				
			||||||
	snek_object_t *second = new_snek_integer(3); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(snek_array_set(obj, 0, first)); | 
					 | 
				
			||||||
	assert(snek_array_set(obj, 1, second)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *retrieved_first = snek_array_get(obj, 0); | 
					 | 
				
			||||||
	assert_not_null(retrieved_first, "Should find the first object"); | 
					 | 
				
			||||||
	assert_int(retrieved_first->kind, ==, STRING, "Should be a string"); | 
					 | 
				
			||||||
	assert_ptr(first, ==, retrieved_first, "Should be the same object"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *retrieved_second = snek_array_get(obj, 1); | 
					 | 
				
			||||||
	assert_not_null(retrieved_second, "Should find the second object"); | 
					 | 
				
			||||||
	assert_int(retrieved_second->kind, ==, INTEGER, "Should be a integer"); | 
					 | 
				
			||||||
	assert_ptr(second, ==, retrieved_second, "Should be the same object"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(first->data.v_string); | 
					 | 
				
			||||||
	boot_free(first); | 
					 | 
				
			||||||
	boot_free(second); | 
					 | 
				
			||||||
	boot_free(obj->data.v_array.elements); | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_set_outside_bounds, { | 
					 | 
				
			||||||
	// Create an array
 | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_array(2); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *outside = new_snek_string("First"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Inside of bound
 | 
					 | 
				
			||||||
	assert(snek_array_set(obj, 1, outside)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Outside of bound
 | 
					 | 
				
			||||||
	assert_false(snek_array_set(obj, 100, outside)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Free memory
 | 
					 | 
				
			||||||
	boot_free(outside->data.v_string); | 
					 | 
				
			||||||
	boot_free(outside); | 
					 | 
				
			||||||
	boot_free(obj->data.v_array.elements); | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_get_outside_bounds, { | 
					 | 
				
			||||||
	// Create an array
 | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_array(1); | 
					 | 
				
			||||||
	snek_object_t *first = new_snek_string("First"); | 
					 | 
				
			||||||
	assert(snek_array_set(obj, 0, first)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Outside of bound
 | 
					 | 
				
			||||||
	assert_null(snek_array_get(obj, 1), "Should not access outside the array"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(first->data.v_string); | 
					 | 
				
			||||||
	boot_free(first); | 
					 | 
				
			||||||
	boot_free(obj->data.v_array.elements); | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/set_and_get", test_array), | 
					 | 
				
			||||||
		munit_test("/set_outside", test_set_outside_bounds), | 
					 | 
				
			||||||
		munit_test("/get_outside", test_get_outside_bounds), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-array", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,102 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value) { | 
					 | 
				
			||||||
	if (snek_obj == NULL || value == NULL) return false; | 
					 | 
				
			||||||
	if (snek_obj->kind != ARRAY) return false; | 
					 | 
				
			||||||
	if (snek_obj->data.v_array.size <= index) return false; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_obj->data.v_array.elements[index] = value; | 
					 | 
				
			||||||
	return true; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index) { | 
					 | 
				
			||||||
	if (snek_obj == NULL) return NULL; | 
					 | 
				
			||||||
	if (snek_obj->kind != ARRAY) return NULL; | 
					 | 
				
			||||||
	if (snek_obj->data.v_array.size <= index) return NULL; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return snek_obj->data.v_array.elements[index]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,45 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
@ -1,75 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_integer, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_integer(42); | 
					 | 
				
			||||||
	assert_int(snek_length(obj), ==, 1, "Integers are length 1"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_float, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(3.14); | 
					 | 
				
			||||||
	assert_int(snek_length(obj), ==, 1, "Floats are length 1"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_string, { | 
					 | 
				
			||||||
	snek_object_t *shorter = new_snek_string("hello"); | 
					 | 
				
			||||||
	assert_int(snek_length(shorter), ==, 5, "Should return based on input"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *longer = new_snek_string("hello, world"); | 
					 | 
				
			||||||
	assert_int( | 
					 | 
				
			||||||
			snek_length(longer), ==, strlen("hello, world"), "Should use strlen" | 
					 | 
				
			||||||
	); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(shorter->data.v_string); | 
					 | 
				
			||||||
	boot_free(shorter); | 
					 | 
				
			||||||
	boot_free(longer->data.v_string); | 
					 | 
				
			||||||
	boot_free(longer); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_vector3, { | 
					 | 
				
			||||||
	snek_object_t *i = new_snek_integer(1); | 
					 | 
				
			||||||
	snek_object_t *vec = new_snek_vector3(i, i, i); | 
					 | 
				
			||||||
	assert_int(snek_length(vec), ==, 3, "Vec3 always has length 3"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(i); | 
					 | 
				
			||||||
	boot_free(vec); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_array, { | 
					 | 
				
			||||||
	snek_object_t *i = new_snek_integer(1); | 
					 | 
				
			||||||
	snek_object_t *arr = new_snek_array(4); | 
					 | 
				
			||||||
	assert(snek_array_set(arr, 0, i)); | 
					 | 
				
			||||||
	assert(snek_array_set(arr, 1, i)); | 
					 | 
				
			||||||
	assert(snek_array_set(arr, 2, i)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert_int(snek_length(arr), ==, 4, "Length of array should be its size"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(i); | 
					 | 
				
			||||||
	boot_free(arr->data.v_array.elements); | 
					 | 
				
			||||||
	boot_free(arr); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/integer", test_integer), | 
					 | 
				
			||||||
		munit_test("/float", test_float), | 
					 | 
				
			||||||
		munit_test("/string", test_string), | 
					 | 
				
			||||||
		munit_test("/vector", test_vector3), | 
					 | 
				
			||||||
		munit_test("/array", test_array), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("object-length", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,128 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snek_length(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) return -1; | 
					 | 
				
			||||||
	if (obj->kind == INTEGER || obj->kind == FLOAT) return 1; | 
					 | 
				
			||||||
	if (obj->kind == STRING) return strlen(obj->data.v_string); | 
					 | 
				
			||||||
	if (obj->kind == VECTOR3) return 3; | 
					 | 
				
			||||||
	if (obj->kind == ARRAY) return obj->data.v_array.size; | 
					 | 
				
			||||||
	return -1; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *array, size_t index, snek_object_t *value) { | 
					 | 
				
			||||||
	if (array == NULL || value == NULL) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (array->kind != ARRAY) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (index >= array->data.v_array.size) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set the value directly now (already checked size constraint)
 | 
					 | 
				
			||||||
	array->data.v_array.elements[index] = value; | 
					 | 
				
			||||||
	return true; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *array, size_t index) { | 
					 | 
				
			||||||
	if (array == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (array->kind != ARRAY) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (index >= array->data.v_array.size) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Get the value directly now (already checked size constraint)
 | 
					 | 
				
			||||||
	return array->data.v_array.elements[index]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,46 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
int snek_length(snek_object_t *obj); | 
					 | 
				
			||||||
@ -1,3 +0,0 @@ | 
				
			|||||||
 | 
					 | 
				
			||||||
// Q: Which language makes use of a garbage collector (automatic memory management)?
 | 
					 | 
				
			||||||
// A: Go
 | 
					 | 
				
			||||||
@ -1,30 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// #include "bootlib.h"
 | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_int_has_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_integer(10); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
	free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_float_has_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(42.0); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
	free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("test_int_has_refcount", test_int_has_refcount), | 
					 | 
				
			||||||
		munit_test("test_float_has_refcount", test_float_has_refcount), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("refcount", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,91 +0,0 @@ | 
				
			|||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *_new_snek_object() { | 
					 | 
				
			||||||
	snek_object_t *obj = (snek_object_t *)calloc(1, sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) return NULL; | 
					 | 
				
			||||||
	obj->refcount = 1; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,47 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
	size_t refcount; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
int snek_length(snek_object_t *obj); | 
					 | 
				
			||||||
@ -1,48 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// #include "bootlib.h"
 | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_inc_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_integer(10); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_inc_refcount_more, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 6, "Refcount should be incremented to 6"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_null_obj, { | 
					 | 
				
			||||||
	refcount_inc(NULL); | 
					 | 
				
			||||||
	assert(1); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/test_inc_refcount", test_inc_refcount), | 
					 | 
				
			||||||
		munit_test("/test_inc_refcount_more", test_inc_refcount_more), | 
					 | 
				
			||||||
		munit_test("/test_null_obj", test_null_obj), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("refcount", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,102 +0,0 @@ | 
				
			|||||||
#include "assert.h" | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) return; | 
					 | 
				
			||||||
	obj->refcount++; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *_new_snek_object() { | 
					 | 
				
			||||||
	snek_object_t *obj = calloc(1, sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,49 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
	size_t refcount; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
int snek_length(snek_object_t *obj); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj); | 
					 | 
				
			||||||
@ -1,82 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_int_has_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_integer(10); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_inc_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_dec_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(!boot_is_freed(obj)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Object is still alive, so we will free manually.
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_refcount_free_is_called, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert(boot_is_freed(obj)); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_allocated_string_is_freed, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_string("Hello @wagslane!"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
	assert_string_equal(obj->data.v_string, "Hello @wagslane!", "references str"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert(boot_is_freed(obj)); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/has_refcount", test_int_has_refcount), | 
					 | 
				
			||||||
		munit_test("/inc_refcount", test_inc_refcount), | 
					 | 
				
			||||||
		munit_test("/dec_refcount", test_dec_refcount), | 
					 | 
				
			||||||
		munit_test("/free_refcount", test_refcount_free_is_called), | 
					 | 
				
			||||||
		munit_test("/string_freed", test_allocated_string_is_freed), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("refcount", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,124 +0,0 @@ | 
				
			|||||||
#include "assert.h" | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) return; | 
					 | 
				
			||||||
	obj->refcount--; | 
					 | 
				
			||||||
	if (obj->refcount <= 0) refcount_free(obj); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_free(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) return; | 
					 | 
				
			||||||
	if (obj->kind == INTEGER || obj->kind == FLOAT) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (obj->kind == STRING) { | 
					 | 
				
			||||||
		boot_free(obj->data.v_string); | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *_new_snek_object() { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_calloc(1, sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,51 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
	size_t refcount; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
int snek_length(snek_object_t *obj); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_free(snek_object_t *obj); | 
					 | 
				
			||||||
@ -1,128 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_vector3_refcounting, { | 
					 | 
				
			||||||
	snek_object_t *foo = new_snek_integer(1); | 
					 | 
				
			||||||
	snek_object_t *bar = new_snek_integer(2); | 
					 | 
				
			||||||
	snek_object_t *baz = new_snek_integer(3); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *vec = new_snek_vector3(foo, bar, baz); | 
					 | 
				
			||||||
	assert_int(foo->refcount, ==, 2, "foo is now referenced by vec"); | 
					 | 
				
			||||||
	assert_int(bar->refcount, ==, 2, "bar is now referenced by vec"); | 
					 | 
				
			||||||
	assert_int(baz->refcount, ==, 2, "baz is now referenced by vec"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// `foo` is stil referenced in the `vec`, so it should not be freed.
 | 
					 | 
				
			||||||
	refcount_dec(foo); | 
					 | 
				
			||||||
	assert(!boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(vec); | 
					 | 
				
			||||||
	assert(boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// These are still alive, they have the original reference still.
 | 
					 | 
				
			||||||
	assert(!boot_is_freed(bar)); | 
					 | 
				
			||||||
	assert(!boot_is_freed(baz)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Decrement the last reference to the objects, so they will be freed.
 | 
					 | 
				
			||||||
	refcount_dec(bar); | 
					 | 
				
			||||||
	refcount_dec(baz); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_vector3_refcounting_same, { | 
					 | 
				
			||||||
	snek_object_t *foo = new_snek_integer(1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *vec = new_snek_vector3(foo, foo, foo); | 
					 | 
				
			||||||
	assert_int(foo->refcount, ==, 4, "foo is now referenced by vec x3"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// `foo` is stil referenced in the `vec`, so it should not be freed.
 | 
					 | 
				
			||||||
	refcount_dec(foo); | 
					 | 
				
			||||||
	assert(!boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(vec); | 
					 | 
				
			||||||
	assert(boot_is_freed(foo)); | 
					 | 
				
			||||||
	assert(boot_is_freed(vec)); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_int_has_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_integer(10); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_inc_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_dec_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// assert(!boot_is_freed(obj));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Object is still alive, so we will free manually.
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_refcount_free_is_called, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert(boot_is_freed(obj)); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_allocated_string_is_freed, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_string("Hello @wagslane!"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
	assert_string_equal(obj->data.v_string, "Hello @wagslane!", "references str"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert(boot_is_freed(obj)); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/has_refcount", test_int_has_refcount), | 
					 | 
				
			||||||
		munit_test("/inc_refcount", test_inc_refcount), | 
					 | 
				
			||||||
		munit_test("/dec_refcount", test_dec_refcount), | 
					 | 
				
			||||||
		munit_test("/free_refcount", test_refcount_free_is_called), | 
					 | 
				
			||||||
		munit_test("/string_freed", test_allocated_string_is_freed), | 
					 | 
				
			||||||
		munit_test("/vector3", test_vector3_refcounting), | 
					 | 
				
			||||||
		munit_test("/vector3-same", test_vector3_refcounting_same), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("refcount", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,141 +0,0 @@ | 
				
			|||||||
#include "assert.h" | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *_new_snek_object(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) return NULL; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
	refcount_inc(x); | 
					 | 
				
			||||||
	refcount_inc(y); | 
					 | 
				
			||||||
	refcount_inc(z); | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_free(snek_object_t *obj) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	switch (obj->kind) { | 
					 | 
				
			||||||
	case INTEGER: | 
					 | 
				
			||||||
	case FLOAT: | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	case STRING: | 
					 | 
				
			||||||
		boot_free(obj->data.v_string); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	case VECTOR3: { | 
					 | 
				
			||||||
		refcount_dec(obj->data.v_vector3.x); | 
					 | 
				
			||||||
		refcount_dec(obj->data.v_vector3.y); | 
					 | 
				
			||||||
		refcount_dec(obj->data.v_vector3.z); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	default: | 
					 | 
				
			||||||
		assert(false); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	obj->refcount--; | 
					 | 
				
			||||||
	if (obj->refcount == 0) { | 
					 | 
				
			||||||
		return refcount_free(obj); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *_new_snek_object() { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_calloc(1, sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,51 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
	size_t refcount; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
int snek_length(snek_object_t *obj); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_free(snek_object_t *obj); | 
					 | 
				
			||||||
@ -1,154 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_array_set, { | 
					 | 
				
			||||||
	snek_object_t *foo = new_snek_integer(1); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *array = new_snek_array(1); | 
					 | 
				
			||||||
	snek_array_set(array, 0, foo); | 
					 | 
				
			||||||
	assert_int(foo->refcount, ==, 2, "foo is now referenced by array"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(!boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(foo); | 
					 | 
				
			||||||
	refcount_dec(array); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_array_free, { | 
					 | 
				
			||||||
	snek_object_t *foo = new_snek_integer(1); | 
					 | 
				
			||||||
	snek_object_t *bar = new_snek_integer(2); | 
					 | 
				
			||||||
	snek_object_t *baz = new_snek_integer(3); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *array = new_snek_array(2); | 
					 | 
				
			||||||
	snek_array_set(array, 0, foo); | 
					 | 
				
			||||||
	snek_array_set(array, 1, bar); | 
					 | 
				
			||||||
	assert_int(foo->refcount, ==, 2, "foo is now referenced by array"); | 
					 | 
				
			||||||
	assert_int(bar->refcount, ==, 2, "bar is now referenced by array"); | 
					 | 
				
			||||||
	assert_int(baz->refcount, ==, 1, "baz is not yet referenced by array"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// `foo` is stil referenced in the `array`, so it should not be freed.
 | 
					 | 
				
			||||||
	refcount_dec(foo); | 
					 | 
				
			||||||
	assert(!boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Overwrite index 0, which is `foo`, with `baz`.
 | 
					 | 
				
			||||||
	//	Now `foo` is not referenced by `array`, so it should be freed.
 | 
					 | 
				
			||||||
	snek_array_set(array, 0, baz); | 
					 | 
				
			||||||
	assert(boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(bar); | 
					 | 
				
			||||||
	refcount_dec(baz); | 
					 | 
				
			||||||
	refcount_dec(array); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_vector3_refcounting, { | 
					 | 
				
			||||||
	snek_object_t *foo = new_snek_integer(1); | 
					 | 
				
			||||||
	snek_object_t *bar = new_snek_integer(2); | 
					 | 
				
			||||||
	snek_object_t *baz = new_snek_integer(3); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t *vec = new_snek_vector3(foo, bar, baz); | 
					 | 
				
			||||||
	assert_int(foo->refcount, ==, 2, "foo is now referenced by vec"); | 
					 | 
				
			||||||
	assert_int(bar->refcount, ==, 2, "bar is now referenced by vec"); | 
					 | 
				
			||||||
	assert_int(baz->refcount, ==, 2, "baz is now referenced by vec"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// `foo` is stil referenced in the `vec`, so it should not be freed.
 | 
					 | 
				
			||||||
	refcount_dec(foo); | 
					 | 
				
			||||||
	assert(!boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(vec); | 
					 | 
				
			||||||
	assert(boot_is_freed(foo)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// These are still alive, they have the original reference still.
 | 
					 | 
				
			||||||
	assert(!boot_is_freed(bar)); | 
					 | 
				
			||||||
	assert(!boot_is_freed(baz)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Decrement the last reference to the objects, so they will be freed.
 | 
					 | 
				
			||||||
	refcount_dec(bar); | 
					 | 
				
			||||||
	refcount_dec(baz); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_int_has_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_integer(10); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_inc_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_dec_refcount, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert(!boot_is_freed(obj)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Object is still alive, so we will free manually.
 | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_refcount_free_is_called, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_float(4.20); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert(boot_is_freed(obj)); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_allocated_string_is_freed, { | 
					 | 
				
			||||||
	snek_object_t *obj = new_snek_string("Hello @wagslane!"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_inc(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); | 
					 | 
				
			||||||
	assert_string_equal(obj->data.v_string, "Hello @wagslane!", "references str"); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refcount_dec(obj); | 
					 | 
				
			||||||
	assert(boot_is_freed(obj)); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/array_set", test_array_set), | 
					 | 
				
			||||||
		munit_test("/array_free", test_array_free), | 
					 | 
				
			||||||
		munit_test("/has_refcount", test_int_has_refcount), | 
					 | 
				
			||||||
		munit_test("/inc_refcount", test_inc_refcount), | 
					 | 
				
			||||||
		munit_test("/dec_refcount", test_dec_refcount), | 
					 | 
				
			||||||
		munit_test("/free_refcount", test_refcount_free_is_called), | 
					 | 
				
			||||||
		munit_test("/string_freed", test_allocated_string_is_freed), | 
					 | 
				
			||||||
		munit_test("/vector3", test_vector3_refcounting), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("refcount", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,182 +0,0 @@ | 
				
			|||||||
#include "assert.h" | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	if (snek_obj == NULL || value == NULL) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (snek_obj->kind != ARRAY) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (index >= snek_obj->data.v_array.size) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (snek_obj->data.v_array.elements[index] != NULL) { | 
					 | 
				
			||||||
		refcount_dec(snek_obj->data.v_array.elements[index]); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	snek_obj->data.v_array.elements[index] = value; | 
					 | 
				
			||||||
	refcount_inc(value); | 
					 | 
				
			||||||
	return true; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_free(snek_object_t *obj) | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
	switch (obj->kind) { | 
					 | 
				
			||||||
	case INTEGER: | 
					 | 
				
			||||||
	case FLOAT: | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	case STRING: | 
					 | 
				
			||||||
		boot_free(obj->data.v_string); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	case VECTOR3: { | 
					 | 
				
			||||||
		snek_vector_t vec = obj->data.v_vector3; | 
					 | 
				
			||||||
		refcount_dec(vec.x); | 
					 | 
				
			||||||
		refcount_dec(vec.y); | 
					 | 
				
			||||||
		refcount_dec(vec.z); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	case ARRAY: { | 
					 | 
				
			||||||
		for (int i = 0; i < obj->data.v_array.size; i++) { | 
					 | 
				
			||||||
			refcount_dec(obj->data.v_array.elements[i]); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		boot_free(obj->data.v_array.elements); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	default: | 
					 | 
				
			||||||
		assert(false); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't touch below this line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index) { | 
					 | 
				
			||||||
	if (snek_obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (snek_obj->kind != ARRAY) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (index >= snek_obj->data.v_array.size) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return snek_obj->data.v_array.elements[index]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	obj->refcount--; | 
					 | 
				
			||||||
	if (obj->refcount == 0) { | 
					 | 
				
			||||||
		return refcount_free(obj); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *_new_snek_object() { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_calloc(1, sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
	refcount_inc(x); | 
					 | 
				
			||||||
	refcount_inc(y); | 
					 | 
				
			||||||
	refcount_inc(z); | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,51 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekVector { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekArray { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char* v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
	size_t refcount; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
int snek_length(snek_object_t *obj); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_free(snek_object_t *obj); | 
					 | 
				
			||||||
@ -1,6 +0,0 @@ | 
				
			|||||||
 | 
					 | 
				
			||||||
// Q: Why doesn't the snek_add function need to take care of
 | 
					 | 
				
			||||||
//    garbage collecting the resulting object?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// A: Because we've coded the GC logic to happen automatically whenever a
 | 
					 | 
				
			||||||
//    reference count hits 0
 | 
					 | 
				
			||||||
@ -1,30 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, correctly_free, { | 
					 | 
				
			||||||
	snek_object_t *first = new_snek_array(1); | 
					 | 
				
			||||||
	snek_object_t *second = new_snek_array(1); | 
					 | 
				
			||||||
	// refcounts: first = 1, second = 1
 | 
					 | 
				
			||||||
	snek_array_set(first, 0, second); | 
					 | 
				
			||||||
	// refcounts: first = 1, second = 2
 | 
					 | 
				
			||||||
	snek_array_set(second, 0, first); | 
					 | 
				
			||||||
	// refcounts: first = 2, second = 2
 | 
					 | 
				
			||||||
	refcount_dec(first); | 
					 | 
				
			||||||
	refcount_dec(second); | 
					 | 
				
			||||||
	assert_int(first->refcount, ==, 1, "Refcount first should be 1"); | 
					 | 
				
			||||||
	assert_int(second->refcount, ==, 1, "Refcount second should be 1"); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/correctly_free", correctly_free), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("refcount", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,179 +0,0 @@ | 
				
			|||||||
#include "assert.h" | 
					 | 
				
			||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
#include <string.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "snekobject.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value) { | 
					 | 
				
			||||||
	if (snek_obj == NULL || value == NULL) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (snek_obj->kind != ARRAY) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	if (index >= snek_obj->data.v_array.size) { | 
					 | 
				
			||||||
		return false; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	refcount_inc(value); | 
					 | 
				
			||||||
	if (snek_obj->data.v_array.elements[index] != NULL) { | 
					 | 
				
			||||||
		refcount_dec(snek_obj->data.v_array.elements[index]); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	snek_obj->data.v_array.elements[index] = value; | 
					 | 
				
			||||||
	return true; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_boot_free(snek_object_t *obj) { | 
					 | 
				
			||||||
	switch (obj->kind) { | 
					 | 
				
			||||||
	case INTEGER: | 
					 | 
				
			||||||
	case FLOAT: | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	case STRING: | 
					 | 
				
			||||||
		boot_free(obj->data.v_string); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	case VECTOR3: { | 
					 | 
				
			||||||
		snek_vector_t vec = obj->data.v_vector3; | 
					 | 
				
			||||||
		refcount_dec(vec.x); | 
					 | 
				
			||||||
		refcount_dec(vec.y); | 
					 | 
				
			||||||
		refcount_dec(vec.z); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	case ARRAY: { | 
					 | 
				
			||||||
		snek_array_t array = obj->data.v_array; | 
					 | 
				
			||||||
		for (size_t i = 0; i < array.size; i++) { | 
					 | 
				
			||||||
			refcount_dec(array.elements[i]); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
		boot_free(array.elements); | 
					 | 
				
			||||||
		break; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	default: | 
					 | 
				
			||||||
		assert(false); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	boot_free(obj); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index) { | 
					 | 
				
			||||||
	if (snek_obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (snek_obj->kind != ARRAY) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (index >= snek_obj->data.v_array.size) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return snek_obj->data.v_array.elements[index]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount++; | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj) { | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	obj->refcount--; | 
					 | 
				
			||||||
	if (obj->refcount == 0) { | 
					 | 
				
			||||||
		return refcount_boot_free(obj); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *_new_snek_object() { | 
					 | 
				
			||||||
	snek_object_t *obj = boot_calloc(1, sizeof(snek_object_t)); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->refcount = 1; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); | 
					 | 
				
			||||||
	if (elements == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = ARRAY; | 
					 | 
				
			||||||
	obj->data.v_array = (snek_array_t){.size = size, .elements = elements}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = INTEGER; | 
					 | 
				
			||||||
	obj->data.v_int = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = FLOAT; | 
					 | 
				
			||||||
	obj->data.v_float = value; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value) { | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int len = strlen(value); | 
					 | 
				
			||||||
	char *dst = boot_malloc(len + 1); | 
					 | 
				
			||||||
	if (dst == NULL) { | 
					 | 
				
			||||||
		boot_free(obj); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(dst, value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	obj->kind = STRING; | 
					 | 
				
			||||||
	obj->data.v_string = dst; | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
		snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
) { | 
					 | 
				
			||||||
	if (x == NULL || y == NULL || z == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	snek_object_t *obj = _new_snek_object(); | 
					 | 
				
			||||||
	if (obj == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
	obj->kind = VECTOR3; | 
					 | 
				
			||||||
	obj->data.v_vector3 = (snek_vector_t){.x = x, .y = y, .z = z}; | 
					 | 
				
			||||||
	refcount_inc(x); | 
					 | 
				
			||||||
	refcount_inc(y); | 
					 | 
				
			||||||
	refcount_inc(z); | 
					 | 
				
			||||||
	return obj; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,52 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char *v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	int refcount; | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snek_object_t *new_snek_integer(int value); | 
					 | 
				
			||||||
snek_object_t *new_snek_float(float value); | 
					 | 
				
			||||||
snek_object_t *new_snek_string(char *value); | 
					 | 
				
			||||||
snek_object_t *new_snek_vector3( | 
					 | 
				
			||||||
	snek_object_t *x, snek_object_t *y, snek_object_t *z | 
					 | 
				
			||||||
); | 
					 | 
				
			||||||
snek_object_t *new_snek_array(size_t size); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void refcount_inc(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_dec(snek_object_t *obj); | 
					 | 
				
			||||||
void refcount_free(snek_object_t *obj); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool snek_array_set(snek_object_t *array, size_t index, snek_object_t *value); | 
					 | 
				
			||||||
snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index); | 
					 | 
				
			||||||
@ -1,31 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "munit.h" | 
					 | 
				
			||||||
#include "vm.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(RUN, test_vm_new, { | 
					 | 
				
			||||||
	vm_t *vm = vm_new(); | 
					 | 
				
			||||||
	assert_int(vm->frames->capacity, ==, 8, "frames should have capacity 8"); | 
					 | 
				
			||||||
	assert_int(vm->objects->capacity, ==, 8, "objects should have capacity 8"); | 
					 | 
				
			||||||
	vm_free(vm); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
munit_case(SUBMIT, test_vm_new_free, { | 
					 | 
				
			||||||
	vm_t *vm = vm_new(); | 
					 | 
				
			||||||
	vm_free(vm); | 
					 | 
				
			||||||
	assert(boot_all_freed()); | 
					 | 
				
			||||||
}); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main() { | 
					 | 
				
			||||||
	MunitTest tests[] = { | 
					 | 
				
			||||||
		munit_test("/vm", test_vm_new), | 
					 | 
				
			||||||
		munit_test("/vm", test_vm_new_free), | 
					 | 
				
			||||||
		munit_null_test, | 
					 | 
				
			||||||
	}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MunitSuite suite = munit_suite("mark-and-sweep", tests); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return munit_suite_main(&suite, NULL, 0, NULL); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,38 +0,0 @@ | 
				
			|||||||
#include <stdbool.h> | 
					 | 
				
			||||||
#include <stddef.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "stack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject snek_object_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct { | 
					 | 
				
			||||||
	size_t size; | 
					 | 
				
			||||||
	snek_object_t **elements; | 
					 | 
				
			||||||
} snek_array_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct { | 
					 | 
				
			||||||
	snek_object_t *x; | 
					 | 
				
			||||||
	snek_object_t *y; | 
					 | 
				
			||||||
	snek_object_t *z; | 
					 | 
				
			||||||
} snek_vector_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum SnekObjectKind { | 
					 | 
				
			||||||
	INTEGER, | 
					 | 
				
			||||||
	FLOAT, | 
					 | 
				
			||||||
	STRING, | 
					 | 
				
			||||||
	VECTOR3, | 
					 | 
				
			||||||
	ARRAY, | 
					 | 
				
			||||||
} snek_object_kind_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef union SnekObjectData { | 
					 | 
				
			||||||
	int v_int; | 
					 | 
				
			||||||
	float v_float; | 
					 | 
				
			||||||
	char *v_string; | 
					 | 
				
			||||||
	snek_vector_t v_vector3; | 
					 | 
				
			||||||
	snek_array_t v_array; | 
					 | 
				
			||||||
} snek_object_data_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct SnekObject { | 
					 | 
				
			||||||
	snek_object_kind_t kind; | 
					 | 
				
			||||||
	snek_object_data_t data; | 
					 | 
				
			||||||
} snek_object_t; | 
					 | 
				
			||||||
@ -1,78 +0,0 @@ | 
				
			|||||||
#include <stdio.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "stack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj) { | 
					 | 
				
			||||||
	if (stack->count == stack->capacity) { | 
					 | 
				
			||||||
		// Double stack capacity to avoid reallocing often
 | 
					 | 
				
			||||||
		stack->capacity *= 2; | 
					 | 
				
			||||||
		stack->data = boot_realloc(stack->data, stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
		if (stack->data == NULL) { | 
					 | 
				
			||||||
			// Unable to realloc, just exit :) get gud
 | 
					 | 
				
			||||||
			exit(1); | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->data[stack->count] = obj; | 
					 | 
				
			||||||
	stack->count++; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack->count == 0) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count--; | 
					 | 
				
			||||||
	return stack->data[stack->count]; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack) { | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (stack->data != NULL) { | 
					 | 
				
			||||||
		boot_free(stack->data); | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	boot_free(stack); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_remove_nulls(my_stack_t *stack) { | 
					 | 
				
			||||||
	size_t new_count = 0; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Iterate through the stack and compact non-NULL pointers.
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < stack->count; ++i) { | 
					 | 
				
			||||||
		if (stack->data[i] != NULL) { | 
					 | 
				
			||||||
			stack->data[new_count++] = stack->data[i]; | 
					 | 
				
			||||||
		} | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Update the count to reflect the new number of elements.
 | 
					 | 
				
			||||||
	stack->count = new_count; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Optionally, you might want to zero out the remaining slots.
 | 
					 | 
				
			||||||
	for (size_t i = new_count; i < stack->capacity; ++i) { | 
					 | 
				
			||||||
		stack->data[i] = NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity) { | 
					 | 
				
			||||||
	my_stack_t *stack = boot_malloc(sizeof(my_stack_t)); | 
					 | 
				
			||||||
	if (stack == NULL) { | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack->count = 0; | 
					 | 
				
			||||||
	stack->capacity = capacity; | 
					 | 
				
			||||||
	stack->data = boot_malloc(stack->capacity * sizeof(void *)); | 
					 | 
				
			||||||
	if (stack->data == NULL) { | 
					 | 
				
			||||||
		boot_free(stack); | 
					 | 
				
			||||||
		return NULL; | 
					 | 
				
			||||||
	} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stack; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,16 +0,0 @@ | 
				
			|||||||
#include <stddef.h> | 
					 | 
				
			||||||
#include <stdlib.h> | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Stack { | 
					 | 
				
			||||||
	size_t count; | 
					 | 
				
			||||||
	size_t capacity; | 
					 | 
				
			||||||
	void **data; | 
					 | 
				
			||||||
} my_stack_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my_stack_t *stack_new(size_t capacity); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_push(my_stack_t *stack, void *obj); | 
					 | 
				
			||||||
void *stack_pop(my_stack_t *stack); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void stack_free(my_stack_t *stack); | 
					 | 
				
			||||||
void stack_remove_nulls(my_stack_t *stack); | 
					 | 
				
			||||||
@ -1,19 +0,0 @@ | 
				
			|||||||
#include "bootlib.h" | 
					 | 
				
			||||||
#include "vm.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vm_t *vm_new() { | 
					 | 
				
			||||||
	vm_t * vm = (vm_t *)boot_malloc(sizeof(vm_t)); | 
					 | 
				
			||||||
	if (vm == NULL) return NULL; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vm->frames = stack_new(8); | 
					 | 
				
			||||||
	vm->objects = stack_new(8); | 
					 | 
				
			||||||
	return vm; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void vm_free(vm_t *vm) { | 
					 | 
				
			||||||
	if (vm == NULL) return; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stack_free(vm->frames); | 
					 | 
				
			||||||
	stack_free(vm->objects); | 
					 | 
				
			||||||
	boot_free(vm); | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,9 +0,0 @@ | 
				
			|||||||
#include "stack.h" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct VirtualMachine { | 
					 | 
				
			||||||
	my_stack_t *frames; | 
					 | 
				
			||||||
	my_stack_t *objects; | 
					 | 
				
			||||||
} vm_t; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vm_t *vm_new(); | 
					 | 
				
			||||||
void vm_free(vm_t *vm); | 
					 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
					Loading…
					
					
				
		Reference in new issue