Browse Source

Add more exercises

master
Riyyi 1 week ago
parent
commit
0f94ca2909
  1. 261
      README.org
  2. 3
      src/10-1-garbage-collector/main.c
  3. 30
      src/10-2-refcounting/main.c
  4. 91
      src/10-2-refcounting/snekobject.c
  5. 47
      src/10-2-refcounting/snekobject.h
  6. 48
      src/10-3-increment/main.c
  7. 102
      src/10-3-increment/snekobject.c
  8. 49
      src/10-3-increment/snekobject.h
  9. 82
      src/10-4-decrement-and-free/main.c
  10. 123
      src/10-4-decrement-and-free/snekobject.c
  11. 51
      src/10-4-decrement-and-free/snekobject.h
  12. 128
      src/10-5-vectors/main.c
  13. 140
      src/10-5-vectors/snekobject.c
  14. 51
      src/10-5-vectors/snekobject.h
  15. 154
      src/10-6-arrays/main.c
  16. 181
      src/10-6-arrays/snekobject.c
  17. 51
      src/10-6-arrays/snekobject.h
  18. 5
      src/10-7-refcounting-review/main.c
  19. 38
      src/9-6-arrays/main.c
  20. 81
      src/9-6-arrays/snekobject.c
  21. 41
      src/9-6-arrays/snekobject.h
  22. 83
      src/9-7-get-and-set/main.c
  23. 101
      src/9-7-get-and-set/snekobject.c
  24. 45
      src/9-7-get-and-set/snekobject.h
  25. 74
      src/9-8-length/main.c
  26. 127
      src/9-8-length/snekobject.c
  27. 46
      src/9-8-length/snekobject.h
  28. 8
      src/munit.h

261
README.org

@ -42,67 +42,77 @@ Successful output of all the tests:
#+BEGIN_SRC sh #+BEGIN_SRC sh
$ make run 12:25PM $ make run 12:25PM
[ 3%] Built target munit [ 3%] Built target munit
[ 8%] Built target 8-6-multiple-types [ 6%] Built target 9-8-length
[ 11%] Built target 4-1-enums [ 7%] Built target 4-1-enums
[ 14%] Built target 4-2-non-default-values [ 9%] Built target 4-2-non-default-values
[ 17%] Built target 4-3-switch-case [ 12%] Built target 4-3-switch-case
[ 20%] Built target 4-4-sizeof-enum [ 14%] Built target 4-4-sizeof-enum
[ 24%] Built target 5-1-union [ 17%] Built target 5-1-union
[ 26%] Built target 5-2-memory-layout [ 19%] Built target 5-2-memory-layout
[ 29%] Built target 5-3-5-4-union-size [ 21%] Built target 5-3-5-4-union-size
[ 32%] Built target 5-5-helper-fields [ 23%] Built target 5-5-helper-fields
[ 34%] Built target 6-1-the-stack [ 25%] Built target 6-1-the-stack
[ 37%] Built target 6-2-why-a-stack [ 27%] Built target 6-2-why-a-stack
[ 39%] Built target 6-3-stack-overflow [ 29%] Built target 6-3-stack-overflow
[ 42%] Built target 6-4-pointers-to-the-stack [ 31%] Built target 6-4-pointers-to-the-stack
[ 46%] Built target 6-5-the-heap [ 34%] Built target 6-5-the-heap
[ 50%] Built target 6-6-malloc [ 37%] Built target 6-6-malloc
[ 53%] Built target 6-7-free [ 40%] Built target 6-7-free
[ 56%] Built target 6-8-big-endian-little-endian [ 42%] Built target 6-8-big-endian-little-endian
[ 60%] Built target 7-1-pointer-pointers [ 45%] Built target 7-1-pointer-pointers
[ 64%] Built target 7-2-array-of-pointers [ 48%] Built target 7-2-array-of-pointers
[ 67%] Built target 7-3-void-pointers [ 51%] Built target 7-3-void-pointers
[ 71%] Built target 7-4-swapping-integers [ 54%] Built target 7-4-swapping-integers
[ 75%] Built target 7-5-swapping-strings [ 57%] Built target 7-5-swapping-strings
[ 79%] Built target 7-6-generic-swap [ 60%] Built target 7-6-generic-swap
[ 83%] Built target 8-1-low-level-stack [ 63%] Built target 8-1-low-level-stack
[ 87%] Built target 8-2-stack-push [ 66%] Built target 8-2-stack-push
[ 91%] Built target 8-3-stack-pop [ 69%] Built target 8-3-stack-pop
[ 94%] Built target 8-4-stack-free [ 72%] Built target 8-4-stack-free
[100%] Built target 8-5-dangerous-push [ 76%] Built target 8-5-dangerous-push
Running test suite with seed 0x039ca6b1... [ 80%] Built target 8-6-multiple-types
colors/are_defined [ OK ] [ 0.00000100 / 0.00000200 CPU ] [ 82%] Built target 9-1-snek-objects
colors/are_defined_correctly [ OK ] [ 0.00000100 / 0.00000100 CPU ] [ 85%] Built target 9-2-integer
[ 88%] Built target 9-3-float
[ 91%] Built target 9-4-string
[ 94%] Built target 9-5-vector3
[ 97%] Built target 9-6-arrays
[100%] Built target 9-7-get-and-set
Running test suite with seed 0xa13b83c4...
colors/are_defined [ OK ] [ 0.00000100 / 0.00000300 CPU ]
colors/are_defined_correctly [ OK ] [ 0.00000100 / 0.00000200 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. 2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xbf68f4fa... Running test suite with seed 0x9c11f043...
colors/defined [ OK ] [ 0.00000100 / 0.00000100 CPU ] colors/defined [ OK ] [ 0.00000000 / 0.00000000 CPU ]
colors/defined_vscode [ OK ] [ 0.00000100 / 0.00000000 CPU ] colors/defined_vscode [ OK ] [ 0.00000000 / 0.00000000 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. 2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x40b17fef... Running test suite with seed 0xdac57c79...
http/switch_enum [ OK ] [ 0.00000100 / 0.00000200 CPU ] http/switch_enum [ OK ] [ 0.00000100 / 0.00000100 CPU ]
http/switch_enum_default [ OK ] [ 0.00000100 / 0.00000000 CPU ] http/switch_enum_default [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. 2 of 2 (100%) tests successful, 0 (0%) test skipped.
The size of BigNumbers is 8 bytes The size of BigNumbers is 8 bytes
The size of HttpErrorCode is 4 bytes The size of HttpErrorCode is 4 bytes
Running test suite with seed 0xde548fa9... Running test suite with seed 0x85251cb1...
format/integer [ OK ] [ 0.00000200 / 0.00000200 CPU ] format/integer [ OK ] [ 0.00000100 / 0.00000100 CPU ]
format/string [ OK ] [ 0.00000100 / 0.00000100 CPU ] format/string [ OK ] [ 0.00000100 / 0.00000100 CPU ]
format/integer_nvim [ OK ] [ 0.00000100 / 0.00000200 CPU ] format/integer_nvim [ OK ] [ 0.00000100 / 0.00000200 CPU ]
format/string_nvim [ OK ] [ 0.00000200 / 0.00000200 CPU ] format/string_nvim [ OK ] [ 0.00000100 / 0.00000100 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped. 4 of 4 (100%) tests successful, 0 (0%) test skipped.
value (set): -420 value (set): -420
err (unset): 4294966876 err (unset): 4294966876
value (unset): -1 value (unset): -1
err (set): 4294967295 err (set): 4294967295
Running test suite with seed 0xa7197940... Running test suite with seed 0xb2bd8586...
PacketHeader/test_packet_header_size [ OK ] [ 0.00000100 / 0.00000200 CPU ] PacketHeader/test_packet_header_size [ OK ] [ 0.00000100 / 0.00000000 CPU ]
PacketHeader/test_tcp_header_fields [ OK ] [ 0.00000100 / 0.00000100 CPU ] PacketHeader/test_tcp_header_fields [ OK ] [ 0.00000100 / 0.00000100 CPU ]
PacketHeader/test_field_raw_size [ OK ] [ 0.00000000 / 0.00000100 CPU ] PacketHeader/test_field_raw_size [ OK ] [ 0.00000100 / 0.00000100 CPU ]
PacketHeader/test_field_to_raw_consistency[ OK ] [ 0.00000100 / 0.00000100 CPU ] PacketHeader/test_field_to_raw_consistency[ OK ] [ 0.00000100 / 0.00000200 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped. 4 of 4 (100%) tests successful, 0 (0%) test skipped.
--------------------------------- Stack pointer offset: 0 bytes ---------------------------------
Stack pointer offset: 0 bytes
--------------------------------- ---------------------------------
Dark mode? Dark mode?
--------------------------------- ---------------------------------
Stack pointer offset: 0 bytes Stack pointer offset: 0 bytes
--------------------------------- ---------------------------------
@ -112,95 +122,142 @@ More like...
Stack pointer offset: 0 bytes Stack pointer offset: 0 bytes
--------------------------------- ---------------------------------
dark roast. dark roast.
Running test suite with seed 0x7dcfad3b...
/example/compare [ OK ] [ 0.00000100 / 0.00000000 CPU ] Running test suite with seed 0x5ed24c16...
/example/rand [ OK ] [ 0.00000100 / 0.00000000 CPU ] /example/compare [ OK ] [ 0.00000100 / 0.00000200 CPU ]
/example/rand [ OK ] [ 0.00000200 / 0.00000100 CPU ]
/example/parameters /example/parameters
foo=one, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=one, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=one, bar=green [ OK ] [ 0.00000200 / 0.00000300 CPU ] foo=one, bar=green [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=one, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=one, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=two, bar=red [ OK ] [ 0.00000100 / 0.00000200 CPU ] foo=two, bar=red [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=two, bar=green [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=two, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=two, bar=green [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=three, bar=red [ OK ] [ 0.00000100 / 0.00000200 CPU ] foo=two, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=three, bar=green [ OK ] [ 0.00000200 / 0.00000100 CPU ] foo=three, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=three, bar=blue [ OK ] [ 0.00000100 / 0.00000200 CPU ] foo=three, bar=green [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=three, bar=blue [ OK ] [ 0.00000100 / 0.00000000 CPU ]
11 of 11 (100%) tests successful, 0 (0%) test skipped. 11 of 11 (100%) tests successful, 0 (0%) test skipped.
Size of pool: 10240 Size of pool: 10240
Initial string: snek Initial string: snek
c1: 10, 20 c1: 10, 20
c2: 30, 40 c2: 30, 40
c3: 50, 60 Running test suite with seed 0x53c7e720... c3: 50, 60
get_full_greeting/test_basic_greeting[ OK ] [ 0.00000200 / 0.00000300 CPU ] Running test suite with seed 0x08ecbbe7...
get_full_greeting/test_short_buffer [ OK ] [ 0.00000200 / 0.00000200 CPU ] get_full_greeting/test_basic_greeting[ OK ] [ 0.00000200 / 0.00000200 CPU ]
get_full_greeting/test_short_buffer [ OK ] [ 0.00000100 / 0.00000200 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. 2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xee42ee28... Running test suite with seed 0xd953a05a...
allocate_scalar_array/test_allocate_scalar_array_size[ OK ] [ 0.00000100 / 0.00000200 CPU ] allocate_scalar_array/test_allocate_scalar_array_size[ OK ] [ 0.00000100 / 0.00000100 CPU ]
allocate_scalar_array/test_allocate_scalar_array_values[ OK ] [ 0.00000200 / 0.00000100 CPU ] allocate_scalar_array/test_allocate_scalar_array_values[ OK ] [ 0.00000200 / 0.00000100 CPU ]
allocate_scalar_array/test_allocate_scalar_array_zero_multiplier[ OK ] [ 0.00000200 / 0.00000100 CPU ] allocate_scalar_array/test_allocate_scalar_array_zero_multiplier[ OK ] [ 0.00000200 / 0.00000200 CPU ]
allocate_scalar_array/test_allocate_too_much[ OK ] [ 0.00001000 / 0.00000900 CPU ] allocate_scalar_array/test_allocate_too_much[ OK ] [ 0.00001000 / 0.00000900 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped. Allocated 500 lists 4 of 4 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x9d78388e... Allocated 500 lists
Running test suite with seed 0x026c49ea...
/example/compare [ OK ] [ 0.00000100 / 0.00000200 CPU ] /example/compare [ OK ] [ 0.00000100 / 0.00000200 CPU ]
/example/rand [ OK ] [ 0.00000100 / 0.00000200 CPU ] /example/rand [ OK ] [ 0.00000100 / 0.00000200 CPU ]
/example/parameters /example/parameters
foo=one, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=one, bar=red [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=one, bar=green [ OK ] [ 0.00000100 / 0.00000200 CPU ] foo=one, bar=green [ OK ] [ 0.00000100 / 0.00000100 CPU ]
foo=one, bar=blue [ OK ] [ 0.00000200 / 0.00000100 CPU ] foo=one, bar=blue [ OK ] [ 0.00000100 / 0.00000200 CPU ]
foo=two, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=two, bar=red [ OK ] [ 0.00000100 / 0.00000200 CPU ]
foo=two, bar=green [ OK ] [ 0.00000200 / 0.00000000 CPU ] foo=two, bar=blue [ OK ] [ 0.00000200 / 0.00000100 CPU ] foo=two, bar=green [ OK ] [ 0.00000100 / 0.00000200 CPU ]
foo=three, bar=red [ OK ] [ 0.00000100 / 0.00000100 CPU ] foo=two, bar=blue [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=three, bar=green [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=three, bar=red [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=three, bar=green [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=three, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=three, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ]
11 of 11 (100%) tests successful, 0 (0%) test skipped. 11 of 11 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x07fdd526... Running test suite with seed 0xbb38daad...
allocate_list/create [ OK ] [ 0.00000100 / 0.00000000 CPU ] allocate_list/create [ OK ] [ 0.00000100 / 0.00000200 CPU ]
allocate_list/overwrite [ OK ] [ 0.00000100 / 0.00000100 CPU ] 2 of 2 (100%) tests successful, 0 (0%) test skipped. allocate_list/overwrite [ OK ] [ 0.00000100 / 0.00000000 CPU ]
Running test suite with seed 0xf26a30e1... 2 of 2 (100%) tests successful, 0 (0%) test skipped.
create_token_pointer_array/test_create_token_pointer_array_single[ OK ] [ 0.00000200 / 0.00000200 CPU ] Running test suite with seed 0x33807c18...
create_token_pointer_array/test_create_token_pointer_array_multiple[ OK ] [ 0.00000300 / 0.00000200 CPU ] create_token_pointer_array/test_create_token_pointer_array_single[ OK ] [ 0.00000100 / 0.00000200 CPU ]
create_token_pointer_array/test_create_token_pointer_array_memory_allocation[ OK ] [ 0.00000200 / 0.00000300 CPU ] create_token_pointer_array/test_create_token_pointer_array_multiple[ OK ] [ 0.00000200 / 0.00000100 CPU ]
create_token_pointer_array/test_create_token_pointer_array_memory_allocation[ OK ] [ 0.00000200 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped. 3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x4c18af41... Running test suite with seed 0x8614a0d1...
snek_zero_out/test_zero_out_integer [ OK ] [ 0.00000100 / 0.00000100 CPU ] snek_zero_out/test_zero_out_integer [ OK ] [ 0.00000100 / 0.00000100 CPU ]
snek_zero_out/test_zero_out_float [ OK ] [ 0.00000100 / 0.00000200 CPU ] snek_zero_out/test_zero_out_float [ OK ] [ 0.00000100 / 0.00000000 CPU ]
snek_zero_out/test_zero_out_bool [ OK ] [ 0.00000100 / 0.00000000 CPU ] snek_zero_out/test_zero_out_nonzero_values[ OK ] [ 0.00000100 / 0.00000200 CPU ] snek_zero_out/test_zero_out_bool [ OK ] [ 0.00000000 / 0.00000000 CPU ]
snek_zero_out/test_zero_out_nonzero_values[ OK ] [ 0.00000100 / 0.00000000 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped. 4 of 4 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xb0750720... Running test suite with seed 0x2f6f82cf...
void-pointer/swap_ints [ OK ] [ 0.00000100 / 0.00000100 CPU ] void-pointer/swap_ints [ OK ] [ 0.00000000 / 0.00000000 CPU ]
void-pointer/swap_ints_same [ OK ] [ 0.00000100 / 0.00000100 CPU ] void-pointer/swap_ints_same [ OK ] [ 0.00000100 / 0.00000200 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. 2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xc10a0ca0... Running test suite with seed 0x62099957...
void-pointer/swap_str [ OK ] [ 0.00000100 / 0.00000100 CPU ] void-pointer/swap_str [ OK ] [ 0.00000100 / 0.00000100 CPU ]
void-pointer/test_swap_str_long [ OK ] [ 0.00000100 / 0.00000100 CPU ] void-pointer/test_swap_str_long [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. Running test suite with seed 0xa27e09af... 2 of 2 (100%) tests successful, 0 (0%) test skipped.
swap/generic_ints [ OK ] [ 0.00000200 / 0.00000200 CPU ] Running test suite with seed 0x56ef9f75...
swap/generic_strings [ OK ] [ 0.00000200 / 0.00000100 CPU ] swap/generic_ints [ OK ] [ 0.00000100 / 0.00000200 CPU ]
swap/generic_strings [ OK ] [ 0.00000100 / 0.00000100 CPU ]
swap/generic_struct [ OK ] [ 0.00000200 / 0.00000200 CPU ] swap/generic_struct [ OK ] [ 0.00000200 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped. 3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xd1be93bf... Running test suite with seed 0xdf070ee5...
snekstack/create_stack_small [ OK ] [ 0.00000100 / 0.00000000 CPU ] snekstack/create_stack_small [ OK ] [ 0.00000200 / 0.00000200 CPU ]
snekstack/create_stack_large [ OK ] [ 0.00000100 / 0.00000200 CPU ] snekstack/create_stack_large [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. Running test suite with seed 0x92735306... 2 of 2 (100%) tests successful, 0 (0%) test skipped.
snekstack/create_stack [ OK ] [ 0.00000200 / 0.00000100 CPU ] Running test suite with seed 0xa0778dac...
snekstack/create_stack [ OK ] [ 0.00000100 / 0.00000200 CPU ]
snekstack/push_stack [ OK ] [ 0.00000100 / 0.00000200 CPU ] snekstack/push_stack [ OK ] [ 0.00000100 / 0.00000200 CPU ]
snekstack/push_double_capacity [ OK ] [ 0.00000200 / 0.00000200 CPU ] snekstack/push_double_capacity [ OK ] [ 0.00000300 / 0.00000300 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped. 3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xd641eade... Running test suite with seed 0x1df97623...
snekstack/create_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ] snekstack/create_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ]
snekstack/push_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ] snekstack/push_stack [ OK ] [ 0.00000200 / 0.00000300 CPU ]
snekstack/pop_stack [ OK ] [ 0.00000200 / 0.00000100 CPU ] snekstack/pop_stack [ OK ] [ 0.00000100 / 0.00000100 CPU ]
snekstack/pop_stack_empty [ OK ] [ 0.00000200 / 0.00000100 CPU ] snekstack/pop_stack_empty [ OK ] [ 0.00000200 / 0.00000100 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped. 4 of 4 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xd1d1136d... Running test suite with seed 0xc67f74fb...
snekstack/create_stack [ OK ] [ 0.00000200 / 0.00000100 CPU ] snekstack/create_stack [ OK ] [ 0.00000100 / 0.00000100 CPU ]
snekstack/push_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ] snekstack/push_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ]
snekstack/pop_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ] snekstack/pop_stack [ OK ] [ 0.00000100 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped. 3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x5493a18d... Running test suite with seed 0xb607698d...
snekstack/heterogenous_stack [ OK ] [ 0.00000100 / 0.00000200 CPU ] snekstack/heterogenous_stack [ OK ] [ 0.00000200 / 0.00000100 CPU ]
1 of 1 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x4804e928...
snekstack/multiple_types_stack [ OK ] [ 0.00000200 / 0.00000300 CPU ]
1 of 1 (100%) tests successful, 0 (0%) test skipped. 1 of 1 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x0dc3c3f9... Running test suite with seed 0xa5a077a3...
snekstack/multiple_types_stack [ OK ] [ 0.00000300 / 0.00000200 CPU ] object-integer-def/integer_constant [ OK ] [ 0.00000000 / 0.00000100 CPU ]
object-integer-def/integer_obj [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x0a7224ef...
object-integer/positive [ OK ] [ 0.00000100 / 0.00000200 CPU ]
object-integer/zero [ OK ] [ 0.00000100 / 0.00000100 CPU ]
object-integer/negative [ OK ] [ 0.00000100 / 0.00000100 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x748c3598...
object-float/positive [ OK ] [ 0.00000100 / 0.00000200 CPU ]
object-float/zero [ OK ] [ 0.00000100 / 0.00000100 CPU ]
object-float/negative [ OK ] [ 0.00000100 / 0.00000100 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x4632a6a6...
object-string/copies_value [ OK ] [ 0.00000200 / 0.00000200 CPU ]
1 of 1 (100%) tests successful, 0 (0%) test skipped. 1 of 1 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x386735e2...
object-vector/returns_null [ OK ] [ 0.00000100 / 0.00000200 CPU ]
object-vector/multiple_objects [ OK ] [ 0.00000200 / 0.00000200 CPU ]
object-vector/same_object [ OK ] [ 0.00000100 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x4e6badf5...
object-array/empty [ OK ] [ 0.00000100 / 0.00000100 CPU ]
object-array/calloc [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xe9625367...
object-array/set_and_get [ OK ] [ 0.00000200 / 0.00000200 CPU ]
object-array/set_outside [ OK ] [ 0.00000200 / 0.00000300 CPU ]
object-array/get_outside [ OK ] [ 0.00000200 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xa7022b54...
object-length/integer [ OK ] [ 0.00000200 / 0.00000100 CPU ]
object-length/float [ OK ] [ 0.00000200 / 0.00000200 CPU ]
object-length/string [ OK ] [ 0.00000200 / 0.00000200 CPU ]
object-length/vector [ OK ] [ 0.00000200 / 0.00000200 CPU ]
object-length/array [ OK ] [ 0.00000200 / 0.00000100 CPU ]
5 of 5 (100%) tests successful, 0 (0%) test skipped.
[100%] Built target run [100%] Built target run
#+END_SRC #+END_SRC

3
src/10-1-garbage-collector/main.c

@ -0,0 +1,3 @@
// Q: Which language makes use of a garbage collector (automatic memory management)?
// A: Go

30
src/10-2-refcounting/main.c

@ -0,0 +1,30 @@
#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);
}

91
src/10-2-refcounting/snekobject.c

@ -0,0 +1,91 @@
#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;
}

47
src/10-2-refcounting/snekobject.h

@ -0,0 +1,47 @@
#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);

48
src/10-3-increment/main.c

@ -0,0 +1,48 @@
#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);
}

102
src/10-3-increment/snekobject.c

@ -0,0 +1,102 @@
#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;
}

49
src/10-3-increment/snekobject.h

@ -0,0 +1,49 @@
#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);

82
src/10-4-decrement-and-free/main.c

@ -0,0 +1,82 @@
#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(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");
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.
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);
}

123
src/10-4-decrement-and-free/snekobject.c

@ -0,0 +1,123 @@
#include "assert.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.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) {
free(obj);
}
if (obj->kind == STRING) {
free(obj->data.v_string);
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 = 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;
}

51
src/10-4-decrement-and-free/snekobject.h

@ -0,0 +1,51 @@
#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);

128
src/10-5-vectors/main.c

@ -0,0 +1,128 @@
#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");
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");
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.
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);
}

140
src/10-5-vectors/snekobject.c

@ -0,0 +1,140 @@
#include "assert.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.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:
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);
}
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 = 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_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;
}

51
src/10-5-vectors/snekobject.h

@ -0,0 +1,51 @@
#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);

154
src/10-6-arrays/main.c

@ -0,0 +1,154 @@
#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");
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");
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.
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);
}

181
src/10-6-arrays/snekobject.c

@ -0,0 +1,181 @@
#include "assert.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.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:
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]);
}
free(obj->data.v_array.elements);
break;
}
default:
assert(false);
}
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 = 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_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;
}
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;
}

51
src/10-6-arrays/snekobject.h

@ -0,0 +1,51 @@
#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);

5
src/10-7-refcounting-review/main.c

@ -0,0 +1,5 @@
// Q: Why doesn't the snek_add function need to take care of
// garbage collecting the resulting object?
// A:

38
src/9-6-arrays/main.c

@ -0,0 +1,38 @@
#include <stdlib.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");
free(obj->data.v_array.elements);
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");
free(obj->data.v_array.elements);
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);
}

81
src/9-6-arrays/snekobject.c

@ -0,0 +1,81 @@
#include <stdlib.h>
#include <string.h>
#include "snekobject.h"
snek_object_t *new_snek_array(size_t size) {
snek_object_t *obj = (snek_object_t *)malloc(sizeof(snek_object_t));
if (obj == NULL) return NULL;
snek_object_t **arr = (snek_object_t **)calloc(size, sizeof(snek_object_t *));
if (arr == NULL) {
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 = 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 = 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 = 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 = malloc(sizeof(snek_object_t));
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;
}

41
src/9-6-arrays/snekobject.h

@ -0,0 +1,41 @@
#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);

83
src/9-7-get-and-set/main.c

@ -0,0 +1,83 @@
#include <stdlib.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");
free(first->data.v_string);
free(first);
free(second);
free(obj->data.v_array.elements);
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
free(outside->data.v_string);
free(outside);
free(obj->data.v_array.elements);
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");
free(first->data.v_string);
free(first);
free(obj->data.v_array.elements);
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);
}

101
src/9-7-get-and-set/snekobject.c

@ -0,0 +1,101 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.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 = malloc(sizeof(snek_object_t));
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 = 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 = 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 = 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 = malloc(sizeof(snek_object_t));
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;
}

45
src/9-7-get-and-set/snekobject.h

@ -0,0 +1,45 @@
#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);

74
src/9-8-length/main.c

@ -0,0 +1,74 @@
#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");
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");
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"
);
free(shorter->data.v_string);
free(shorter);
free(longer->data.v_string);
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");
free(i);
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");
free(i);
free(arr->data.v_array.elements);
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);
}

127
src/9-8-length/snekobject.c

@ -0,0 +1,127 @@
#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 = malloc(sizeof(snek_object_t));
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;
}
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 = 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 = 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 = 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 = malloc(sizeof(snek_object_t));
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;
}

46
src/9-8-length/snekobject.h

@ -0,0 +1,46 @@
#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);

8
src/munit.h

@ -1,3 +1,4 @@
#define MUNIT_ENABLE_ASSERT_ALIASES
#include "../vendor/munit/munit.h" #include "../vendor/munit/munit.h"
// TJ seems to have added a bunch of macros to the default munit.h, // TJ seems to have added a bunch of macros to the default munit.h,
@ -99,6 +100,9 @@
#undef assert_null #undef assert_null
#define assert_null(PTR, MSG) munit_assert_null(PTR, MSG) #define assert_null(PTR, MSG) munit_assert_null(PTR, MSG)
#undef assert_not_null
#define assert_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG)
// ptr // ptr
#undef munit_assert_ptr_not_equal #undef munit_assert_ptr_not_equal
@ -108,6 +112,10 @@
#undef assert_ptr #undef assert_ptr
#define assert_ptr(A, OP, B, MSG) munit_assert_ptr(A, OP, B) #define assert_ptr(A, OP, B, MSG) munit_assert_ptr(A, OP, B)
#undef assert_ptr_null
#define assert_ptr_null(PTR, MSG) munit_assert_ptr_null(PTR)
// https://github.com/nemequ/munit/pull/73/files
#undef assert_ptr_not_null #undef assert_ptr_not_null
#define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG) #define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG)

Loading…
Cancel
Save