Compare commits

..

7 Commits

  1. 2
      .gitignore
  2. 1
      CMakeLists.txt
  3. 388
      README.org
  4. BIN
      bootdev-c.png
  5. 0
      src/04-1-enums/color.h
  6. 0
      src/04-1-enums/main.c
  7. 0
      src/04-2-non-default-values/color.h
  8. 0
      src/04-2-non-default-values/main.c
  9. 0
      src/04-3-switch-case/http.c
  10. 0
      src/04-3-switch-case/http.h
  11. 0
      src/04-3-switch-case/main.c
  12. 0
      src/04-4-sizeof-enum/main.c
  13. 0
      src/05-1-union/exercise.c
  14. 0
      src/05-1-union/exercise.h
  15. 0
      src/05-1-union/main.c
  16. 0
      src/05-2-memory-layout/main.c
  17. 0
      src/05-3-5-4-union-size/main.c
  18. 0
      src/05-5-helper-fields/exercise.h
  19. 0
      src/05-5-helper-fields/main.c
  20. 0
      src/06-1-the-stack/exercise.h
  21. 0
      src/06-1-the-stack/main.c
  22. 0
      src/06-2-why-a-stack/main.c
  23. 0
      src/06-3-stack-overflow/main.c
  24. 0
      src/06-4-pointers-to-the-stack/main.c
  25. 4
      src/06-5-the-heap/exercise.c
  26. 0
      src/06-5-the-heap/exercise.h
  27. 0
      src/06-5-the-heap/main.c
  28. 20
      src/06-6-malloc/exercise.c
  29. 1
      src/06-6-malloc/exercise.h
  30. 57
      src/06-6-malloc/main.c
  31. 13
      src/06-7-free/exercise.c
  32. 1
      src/06-7-free/exercise.h
  33. 21
      src/06-7-free/main.c
  34. 5
      src/06-8-big-endian-little-endian/main.c
  35. 8
      src/07-1-pointer-pointers/exercise.c
  36. 4
      src/07-1-pointer-pointers/exercise.h
  37. 39
      src/07-1-pointer-pointers/main.c
  38. 20
      src/07-2-array-of-pointers/exercise.c
  39. 7
      src/07-2-array-of-pointers/exercise.h
  40. 77
      src/07-2-array-of-pointers/main.c
  41. 13
      src/07-3-void-pointers/exercise.c
  42. 22
      src/07-3-void-pointers/exercise.h
  43. 55
      src/07-3-void-pointers/main.c
  44. 16
      src/07-4-swapping-integers/exercise.c
  45. 1
      src/07-4-swapping-integers/exercise.h
  46. 35
      src/07-4-swapping-integers/main.c
  47. 7
      src/07-5-swapping-strings/exercise.c
  48. 1
      src/07-5-swapping-strings/exercise.h
  49. 37
      src/07-5-swapping-strings/main.c
  50. 15
      src/07-6-generic-swap/exercise.c
  51. 3
      src/07-6-generic-swap/exercise.h
  52. 60
      src/07-6-generic-swap/main.c
  53. 39
      src/08-1-low-level-stack/main.c
  54. 19
      src/08-1-low-level-stack/snekstack.c
  55. 9
      src/08-1-low-level-stack/snekstack.h
  56. 88
      src/08-2-stack-push/main.c
  57. 39
      src/08-2-stack-push/snekstack.c
  58. 10
      src/08-2-stack-push/snekstack.h
  59. 121
      src/08-3-stack-pop/main.c
  60. 47
      src/08-3-stack-pop/snekstack.c
  61. 11
      src/08-3-stack-pop/snekstack.h
  62. 88
      src/08-4-stack-free/main.c
  63. 60
      src/08-4-stack-free/snekstack.c
  64. 12
      src/08-4-stack-free/snekstack.h
  65. 10
      src/08-5-dangerous-push/exercise.c
  66. 3
      src/08-5-dangerous-push/exercise.h
  67. 33
      src/08-5-dangerous-push/main.c
  68. 58
      src/08-5-dangerous-push/snekstack.c
  69. 14
      src/08-5-dangerous-push/snekstack.h
  70. 20
      src/08-6-multiple-types/exercise.c
  71. 3
      src/08-6-multiple-types/exercise.h
  72. 34
      src/08-6-multiple-types/main.c
  73. 58
      src/08-6-multiple-types/snekstack.c
  74. 14
      src/08-6-multiple-types/snekstack.h
  75. 30
      src/09-1-snek-objects/main.c
  76. 13
      src/09-1-snek-objects/snekobject.h
  77. 40
      src/09-2-integer/main.c
  78. 11
      src/09-2-integer/snekobject.c
  79. 14
      src/09-2-integer/snekobject.h
  80. 46
      src/09-3-float/main.c
  81. 25
      src/09-3-float/snekobject.c
  82. 17
      src/09-3-float/snekobject.h
  83. 45
      src/09-4-string/main.c
  84. 47
      src/09-4-string/snekobject.c
  85. 20
      src/09-4-string/snekobject.h
  86. 82
      src/09-5-vector3/main.c
  87. 61
      src/09-5-vector3/snekobject.c
  88. 31
      src/09-5-vector3/snekobject.h
  89. 39
      src/09-6-arrays/main.c
  90. 82
      src/09-6-arrays/snekobject.c
  91. 41
      src/09-6-arrays/snekobject.h
  92. 84
      src/09-7-get-and-set/main.c
  93. 102
      src/09-7-get-and-set/snekobject.c
  94. 45
      src/09-7-get-and-set/snekobject.h
  95. 75
      src/09-8-length/main.c
  96. 128
      src/09-8-length/snekobject.c
  97. 46
      src/09-8-length/snekobject.h
  98. 3
      src/10-1-garbage-collector/main.c
  99. 30
      src/10-2-refcounting/main.c
  100. 91
      src/10-2-refcounting/snekobject.c
  101. Some files were not shown because too many files have changed in this diff Show More

2
.gitignore vendored

@ -5,3 +5,5 @@
build/ build/
# Files # Files
.DS_Store

1
CMakeLists.txt

@ -33,6 +33,7 @@ foreach(LESSON ${LESSONS})
if(NOT LESSON_SOURCES) if(NOT LESSON_SOURCES)
continue() continue()
endif() endif()
list(APPEND LESSON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/bootlib.c)
# Get last directory name of the path to use as exe # Get last directory name of the path to use as exe
get_filename_component(EXE_NAME ${LESSON} NAME) get_filename_component(EXE_NAME ${LESSON} NAME)

388
README.org

@ -0,0 +1,388 @@
#+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

BIN
bootdev-c.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

0
src/4-1-enums/color.h → src/04-1-enums/color.h

0
src/4-1-enums/main.c → src/04-1-enums/main.c

0
src/4-2-non-default-values/color.h → src/04-2-non-default-values/color.h

0
src/4-2-non-default-values/main.c → src/04-2-non-default-values/main.c

0
src/4-3-switch-case/http.c → src/04-3-switch-case/http.c

0
src/4-3-switch-case/http.h → src/04-3-switch-case/http.h

0
src/4-3-switch-case/main.c → src/04-3-switch-case/main.c

0
src/4-4-sizeof-enum/main.c → src/04-4-sizeof-enum/main.c

0
src/5-1-union/exercise.c → src/05-1-union/exercise.c

0
src/5-1-union/exercise.h → src/05-1-union/exercise.h

0
src/5-1-union/main.c → src/05-1-union/main.c

0
src/5-2-memory-layout/main.c → src/05-2-memory-layout/main.c

0
src/5-3-5-4-union-size/main.c → src/05-3-5-4-union-size/main.c

0
src/5-5-helper-fields/exercise.h → src/05-5-helper-fields/exercise.h

0
src/5-5-helper-fields/main.c → src/05-5-helper-fields/main.c

0
src/6-1-the-stack/exercise.h → src/06-1-the-stack/exercise.h

0
src/6-1-the-stack/main.c → src/06-1-the-stack/main.c

0
src/6-2-why-a-stack/main.c → src/06-2-why-a-stack/main.c

0
src/6-3-stack-overflow/main.c → src/06-3-stack-overflow/main.c

0
src/6-4-pointers-to-the-stack/main.c → src/06-4-pointers-to-the-stack/main.c

4
src/6-5-the-heap/exercise.c → src/06-5-the-heap/exercise.c

@ -4,7 +4,7 @@
char* get_full_greeting(char* greeting, char* name, int size) char* get_full_greeting(char* greeting, char* name, int size)
{ {
char full_greeting[100]; char *full_greeting = (char*)malloc(size * sizeof(char));
snprintf(full_greeting, 100, "%s %s", greeting, name); snprintf(full_greeting, size, "%s %s", greeting, name);
return full_greeting; return full_greeting;
} }

0
src/6-5-the-heap/exercise.h → src/06-5-the-heap/exercise.h

0
src/6-5-the-heap/main.c → src/06-5-the-heap/main.c

20
src/06-6-malloc/exercise.c

@ -0,0 +1,20 @@
#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
src/06-6-malloc/exercise.h

@ -0,0 +1 @@
int *allocate_scalar_array(int size, int multiplier);

57
src/06-6-malloc/main.c

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

13
src/06-7-free/exercise.c

@ -0,0 +1,13 @@
#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
src/06-7-free/exercise.h

@ -0,0 +1 @@
int *allocate_scalar_list(int size, int multiplier);

21
src/06-7-free/main.c

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

5
src/06-8-big-endian-little-endian/main.c

@ -0,0 +1,5 @@
// Q: In a little-endian system, how would the hexadecimal number
// 0xA1B2C3D4 be stored in memory?
// A: 0xD4, 0xC3, 0xB2, 0xA1

8
src/07-1-pointer-pointers/exercise.c

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

4
src/07-1-pointer-pointers/exercise.h

@ -0,0 +1,4 @@
#include <stdio.h>
#include <stdlib.h>
void allocate_int(int **pointer_pointer, int value);

39
src/07-1-pointer-pointers/main.c

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

20
src/07-2-array-of-pointers/exercise.c

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

7
src/07-2-array-of-pointers/exercise.h

@ -0,0 +1,7 @@
typedef struct Token {
char* literal;
int line;
int column;
} token_t;
token_t** create_token_pointer_array(token_t* tokens, size_t count);

77
src/07-2-array-of-pointers/main.c

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

13
src/07-3-void-pointers/exercise.c

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

22
src/07-3-void-pointers/exercise.h

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

55
src/07-3-void-pointers/main.c

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

16
src/07-4-swapping-integers/exercise.c

@ -0,0 +1,16 @@
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
src/07-4-swapping-integers/exercise.h

@ -0,0 +1 @@
void swap_ints(int *a, int *b);

35
src/07-4-swapping-integers/main.c

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

7
src/07-5-swapping-strings/exercise.c

@ -0,0 +1,7 @@
void swap_strings(char **a, char **b) {
if (a == b) return;
char *tmp = *a;
*a = *b;
*b = tmp;
}

1
src/07-5-swapping-strings/exercise.h

@ -0,0 +1 @@
void swap_strings(char **a, char **b);

37
src/07-5-swapping-strings/main.c

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

15
src/07-6-generic-swap/exercise.c

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

3
src/07-6-generic-swap/exercise.h

@ -0,0 +1,3 @@
#include <stdio.h>
void swap(void *vp1, void *vp2, size_t size);

60
src/07-6-generic-swap/main.c

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

39
src/08-1-low-level-stack/main.c

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

19
src/08-1-low-level-stack/snekstack.c

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

9
src/08-1-low-level-stack/snekstack.h

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

88
src/08-2-stack-push/main.c

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

39
src/08-2-stack-push/snekstack.c

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

10
src/08-2-stack-push/snekstack.h

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

121
src/08-3-stack-pop/main.c

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

47
src/08-3-stack-pop/snekstack.c

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

11
src/08-3-stack-pop/snekstack.h

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

88
src/08-4-stack-free/main.c

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

60
src/08-4-stack-free/snekstack.c

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

12
src/08-4-stack-free/snekstack.h

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

10
src/08-5-dangerous-push/exercise.c

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

3
src/08-5-dangerous-push/exercise.h

@ -0,0 +1,3 @@
#include "snekstack.h"
void scary_double_push(my_stack_t *s);

33
src/08-5-dangerous-push/main.c

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

58
src/08-5-dangerous-push/snekstack.c

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

14
src/08-5-dangerous-push/snekstack.h

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

20
src/08-6-multiple-types/exercise.c

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

3
src/08-6-multiple-types/exercise.h

@ -0,0 +1,3 @@
#include "snekstack.h"
void stack_push_multiple_types(my_stack_t *s);

34
src/08-6-multiple-types/main.c

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

58
src/08-6-multiple-types/snekstack.c

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

14
src/08-6-multiple-types/snekstack.h

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

30
src/09-1-snek-objects/main.c

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

13
src/09-1-snek-objects/snekobject.h

@ -0,0 +1,13 @@
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;

40
src/09-2-integer/main.c

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

11
src/09-2-integer/snekobject.c

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

14
src/09-2-integer/snekobject.h

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

46
src/09-3-float/main.c

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

25
src/09-3-float/snekobject.c

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

17
src/09-3-float/snekobject.h

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

45
src/09-4-string/main.c

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

47
src/09-4-string/snekobject.c

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

20
src/09-4-string/snekobject.h

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

82
src/09-5-vector3/main.c

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

61
src/09-5-vector3/snekobject.c

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

31
src/09-5-vector3/snekobject.h

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

39
src/09-6-arrays/main.c

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

82
src/09-6-arrays/snekobject.c

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

41
src/09-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);

84
src/09-7-get-and-set/main.c

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

102
src/09-7-get-and-set/snekobject.c

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

45
src/09-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);

75
src/09-8-length/main.c

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

128
src/09-8-length/snekobject.c

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

46
src/09-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);

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;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save