From 6c942fb0c6af268ce8b6b07b00dfe46b0b370a14 Mon Sep 17 00:00:00 2001
From: "csander@caltech.edu" <csander@caltech.edu>
Date: Tue, 27 Oct 2020 19:35:53 +0000
Subject: [PATCH] Clean up starter code

---
 Makefile          |   6 +--
 include/memlib.h  |   1 +
 include/mm.h      |  14 ++---
 src/mm-explicit.c | 134 +++++++++++++++++++++++++++++-----------------
 src/mm-implicit.c | 134 +++++++++++++++++++++++++++++-----------------
 5 files changed, 183 insertions(+), 106 deletions(-)

diff --git a/Makefile b/Makefile
index 07e0c4a..c018d53 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the malloc lab driver
 #
 CC = clang
-CFLAGS = -Werror -Wall -Wextra -O3 -g -DDRIVER
+CFLAGS = -Werror -Wall -Wextra -O3 -g
 
 all: bin/mdriver-implicit bin/mdriver-explicit
 
@@ -15,7 +15,7 @@ bin/mdriver-explicit: out/mdriver-explicit.o out/mm-explicit.o out/memlib.o out/
 out/mdriver-implicit.o: driver/mdriver.c
 	$(CC) $(CFLAGS) -c -DSTAGE0 $^ -o $@
 
-out/mdriver-explicit.o: driver/mdriver.c 
+out/mdriver-explicit.o: driver/mdriver.c
 	$(CC) $(CFLAGS) -c -DSTAGE1 $^ -o $@
 
 out/%.o: src/%.c
@@ -25,4 +25,4 @@ out/%.o: driver/%.c
 	$(CC) $(CFLAGS) -c $^ -o $@
 
 clean:
-	rm -f *~ out/*.o bin/*
+	rm -f out/* bin/*
diff --git a/include/memlib.h b/include/memlib.h
index 5321091..f87c2e8 100644
--- a/include/memlib.h
+++ b/include/memlib.h
@@ -1,4 +1,5 @@
 #include <stddef.h>
+#include <sys/types.h>
 
 void mem_init(void);
 void mem_deinit(void);
diff --git a/include/mm.h b/include/mm.h
index 5e06116..e406261 100644
--- a/include/mm.h
+++ b/include/mm.h
@@ -1,14 +1,14 @@
 #ifndef MM_H
 #define MM_H
 
-#include <stdio.h>
 #include <stdbool.h>
+#include <stddef.h>
 
-extern bool mm_init(void);
-extern void *mm_malloc(size_t size);
-extern void mm_free(void *ptr);
-extern void *mm_realloc(void *ptr, size_t size);
-extern void *mm_calloc(size_t nmemb, size_t size);
-extern void mm_checkheap();
+bool mm_init(void);
+void *mm_malloc(size_t size);
+void mm_free(void *ptr);
+void *mm_realloc(void *ptr, size_t size);
+void *mm_calloc(size_t nmemb, size_t size);
+void mm_checkheap(void);
 
 #endif /* MM_H */
diff --git a/src/mm-explicit.c b/src/mm-explicit.c
index d586f0b..82010aa 100644
--- a/src/mm-explicit.c
+++ b/src/mm-explicit.c
@@ -4,120 +4,158 @@
  * TODO (bug): Uh..this is an implicit list???
  */
 
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
 #include <stdint.h>
-#include <stddef.h>
-#include <unistd.h>
 
 #include "mm.h"
 #include "memlib.h"
 
-typedef uint64_t word_t;
-const size_t ALIGNMENT = 2 * sizeof(word_t);
+/** The required alignment of heap payloads */
+const size_t ALIGNMENT = 2 * sizeof(size_t);
 
+/** The layout of each block allocated on the heap */
 typedef struct {
+    /** The size of the block and whether it is allocated (stored in the low bit) */
     size_t header;
-    /*
+    /**
      * We don't know what the size of the payload will be, so we will
      * declare it as a zero-length array.  This allow us to obtain a
      * pointer to the start of the payload.
      */
-    word_t payload[];
+    uint8_t payload[];
 } block_t;
 
+/** The first and last blocks on the heap */
 static block_t *mm_heap_first = NULL;
 static block_t *mm_heap_last = NULL;
 
+/** Rounds up `size` to the nearest multiple of `n` */
 static size_t round_up(size_t size, size_t n) {
-    return n * ((size + (n-1)) / n);
-}
-
-static size_t get_size(block_t *block) {
-    return block->header & ~0x7;
+    return (size + (n - 1)) / n * n;
 }
 
+/** Set's a block's header with the given size and allocation state */
 static void set_header(block_t *block, size_t size, bool is_allocated) {
     block->header = size | is_allocated;
 }
 
+/** Extracts a block's size from its header */
+static size_t get_size(block_t *block) {
+    return block->header & ~1;
+}
+
+/** Extracts a block's allocation state from its header */
 static bool is_allocated(block_t *block) {
-    return block->header & 0x1;
+    return block->header & 1;
 }
 
-block_t *find_fit(size_t size) {
-    for (block_t *curr = mm_heap_first; mm_heap_last && curr <= mm_heap_last; curr = ((void *)curr + get_size(curr))) {
-        size_t curr_size = get_size(curr);
-        if (!is_allocated(curr) && curr_size >= size) {
+/**
+ * Finds the first free block in the heap with at least the given size.
+ * If no block is large enough, returns NULL.
+ */
+static block_t *find_fit(size_t size) {
+    // Traverse the blocks in the heap using the implicit list
+    for (
+        block_t *curr = mm_heap_first;
+        mm_heap_last != NULL && curr <= mm_heap_last;
+        curr = (void *) curr + get_size(curr)
+    ) {
+        // If the block is free and large enough for the allocation, return it
+        if (!is_allocated(curr) && get_size(curr) >= size) {
             return curr;
         }
     }
     return NULL;
 }
 
+/** Gets the header corresponding to a given payload pointer */
+static block_t *block_from_payload(void *ptr) {
+    return ptr - offsetof(block_t, payload);
+}
+
 
+/**
+ * mm_init - Initializes the allocator state
+ */
 bool mm_init(void) {
-    mm_heap_first = mem_sbrk(8);
-    set_header(mm_heap_first, 8, true);
+    // We want the first payload to start at ALIGNMENT bytes from the start of the heap
+    void *padding = mem_sbrk(ALIGNMENT - sizeof(block_t));
+    if (padding == (void *) -1) {
+        return false;
+    }
+
+    // Initialize the heap with no blocks
+    mm_heap_first = NULL;
     mm_heap_last = NULL;
     return true;
 }
 
+/**
+ * mm_malloc - Allocates a block with the given size
+ */
 void *mm_malloc(size_t size) {
-    size_t asize = round_up(size + sizeof(word_t), ALIGNMENT);
+    // The block must have enough space for a header and be 16-byte aligned
+    size = round_up(sizeof(block_t) + size, ALIGNMENT);
+
+    // If there is a large enough free block, use it
+    block_t *block = find_fit(size);
+    if (block != NULL) {
+        set_header(block, get_size(block), true);
+        return block->payload;
+    }
 
-    block_t *block = find_fit(asize);
+    // Otherwise, a new block needs to be allocated at the end of the heap
+    block = mem_sbrk(size);
+    if (block == (void *) -1) {
+        return NULL;
+    }
 
-    if (!block) {
-        void * ptr = mem_sbrk(asize);
-        if (ptr == (void *)-1) {
-            return NULL;
-        }
-        mm_heap_last = (block_t *)ptr;
-        block = mm_heap_last;
-        set_header(block, asize, true);
+    // Update mm_heap_first and mm_heap_last since we extended the heap
+    if (mm_heap_first == NULL) {
+        mm_heap_first = block;
     }
+    mm_heap_last = block;
 
-    set_header(block, get_size(block), true);
+    // Initialize the block with the allocated size
+    set_header(block, size, true);
     return block->payload;
 }
 
+/**
+ * mm_free - Releases a block to be reused for future allocations
+ */
 void mm_free(void *ptr) {
-    if (!ptr) {
+    // mm_free(NULL) does nothing
+    if (ptr == NULL) {
         return;
     }
 
-    block_t *block = (block_t *)(ptr - offsetof(block_t, payload));
-    size_t block_size = get_size(block);
-    set_header(block, block_size, false);
+    // Mark the block as unallocated
+    block_t *block = block_from_payload(ptr);
+    set_header(block, get_size(block), false);
 }
 
-/*
+/**
  * mm_realloc - Change the size of the block by mm_mallocing a new block,
  *      copying its data, and mm_freeing the old block.
- **/
+ */
 void *mm_realloc(void *old_ptr, size_t size) {
-    (void)old_ptr;
-    (void)size;
+    (void) old_ptr;
+    (void) size;
     return NULL;
 }
 
-
-/*
+/**
  * mm_calloc - Allocate the block and set it to zero.
  */
 void *mm_calloc(size_t nmemb, size_t size) {
-    (void)nmemb;
-    (void)size;
+    (void) nmemb;
+    (void) size;
     return NULL;
 }
 
-/*
+/**
  * mm_checkheap - So simple, it doesn't need a checker!
  */
-void mm_checkheap() {
+void mm_checkheap(void) {
 
 }
diff --git a/src/mm-implicit.c b/src/mm-implicit.c
index fc84bd2..cdd7763 100644
--- a/src/mm-implicit.c
+++ b/src/mm-implicit.c
@@ -5,120 +5,158 @@
  * TODO (bug): The allocator doesn't re-use space very well...
  */
 
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
 #include <stdint.h>
-#include <stddef.h>
-#include <unistd.h>
 
 #include "mm.h"
 #include "memlib.h"
 
-typedef uint64_t word_t;
-const size_t ALIGNMENT = 2 * sizeof(word_t);
+/** The required alignment of heap payloads */
+const size_t ALIGNMENT = 2 * sizeof(size_t);
 
+/** The layout of each block allocated on the heap */
 typedef struct {
+    /** The size of the block and whether it is allocated (stored in the low bit) */
     size_t header;
-    /*
+    /**
      * We don't know what the size of the payload will be, so we will
      * declare it as a zero-length array.  This allow us to obtain a
      * pointer to the start of the payload.
      */
-    word_t payload[];
+    uint8_t payload[];
 } block_t;
 
+/** The first and last blocks on the heap */
 static block_t *mm_heap_first = NULL;
 static block_t *mm_heap_last = NULL;
 
+/** Rounds up `size` to the nearest multiple of `n` */
 static size_t round_up(size_t size, size_t n) {
-    return n * ((size + (n-1)) / n);
-}
-
-static size_t get_size(block_t *block) {
-    return block->header & ~0x7;
+    return (size + (n - 1)) / n * n;
 }
 
+/** Set's a block's header with the given size and allocation state */
 static void set_header(block_t *block, size_t size, bool is_allocated) {
     block->header = size | is_allocated;
 }
 
+/** Extracts a block's size from its header */
+static size_t get_size(block_t *block) {
+    return block->header & ~1;
+}
+
+/** Extracts a block's allocation state from its header */
 static bool is_allocated(block_t *block) {
-    return block->header & 0x1;
+    return block->header & 1;
 }
 
-block_t *find_fit(size_t size) {
-    for (block_t *curr = mm_heap_first; mm_heap_last && curr <= mm_heap_last; curr = ((void *)curr + get_size(curr))) {
-        size_t curr_size = get_size(curr);
-        if (!is_allocated(curr) && curr_size >= size) {
+/**
+ * Finds the first free block in the heap with at least the given size.
+ * If no block is large enough, returns NULL.
+ */
+static block_t *find_fit(size_t size) {
+    // Traverse the blocks in the heap using the implicit list
+    for (
+        block_t *curr = mm_heap_first;
+        mm_heap_last != NULL && curr <= mm_heap_last;
+        curr = (void *) curr + get_size(curr)
+    ) {
+        // If the block is free and large enough for the allocation, return it
+        if (!is_allocated(curr) && get_size(curr) >= size) {
             return curr;
         }
     }
     return NULL;
 }
 
+/** Gets the header corresponding to a given payload pointer */
+static block_t *block_from_payload(void *ptr) {
+    return ptr - offsetof(block_t, payload);
+}
+
 
+/**
+ * mm_init - Initializes the allocator state
+ */
 bool mm_init(void) {
-    mm_heap_first = mem_sbrk(8);
-    set_header(mm_heap_first, 8, true);
+    // We want the first payload to start at ALIGNMENT bytes from the start of the heap
+    void *padding = mem_sbrk(ALIGNMENT - sizeof(block_t));
+    if (padding == (void *) -1) {
+        return false;
+    }
+
+    // Initialize the heap with no blocks
+    mm_heap_first = NULL;
     mm_heap_last = NULL;
     return true;
 }
 
+/**
+ * mm_malloc - Allocates a block with the given size
+ */
 void *mm_malloc(size_t size) {
-    size_t asize = round_up(size + sizeof(word_t), ALIGNMENT);
+    // The block must have enough space for a header and be 16-byte aligned
+    size = round_up(sizeof(block_t) + size, ALIGNMENT);
+
+    // If there is a large enough free block, use it
+    block_t *block = find_fit(size);
+    if (block != NULL) {
+        set_header(block, get_size(block), true);
+        return block->payload;
+    }
 
-    block_t *block = find_fit(asize);
+    // Otherwise, a new block needs to be allocated at the end of the heap
+    block = mem_sbrk(size);
+    if (block == (void *) -1) {
+        return NULL;
+    }
 
-    if (!block) {
-        void * ptr = mem_sbrk(asize);
-        if (ptr == (void *)-1) {
-            return NULL;
-        }
-        mm_heap_last = (block_t *)ptr;
-        block = mm_heap_last;
-        set_header(block, asize, true);
+    // Update mm_heap_first and mm_heap_last since we extended the heap
+    if (mm_heap_first == NULL) {
+        mm_heap_first = block;
     }
+    mm_heap_last = block;
 
-    set_header(block, get_size(block), true);
+    // Initialize the block with the allocated size
+    set_header(block, size, true);
     return block->payload;
 }
 
+/**
+ * mm_free - Releases a block to be reused for future allocations
+ */
 void mm_free(void *ptr) {
-    if (!ptr) {
+    // mm_free(NULL) does nothing
+    if (ptr == NULL) {
         return;
     }
 
-    block_t *block = (block_t *)(ptr - offsetof(block_t, payload));
-    size_t block_size = get_size(block);
-    set_header(block, block_size, false);
+    // Mark the block as unallocated
+    block_t *block = block_from_payload(ptr);
+    set_header(block, get_size(block), false);
 }
 
-/*
+/**
  * mm_realloc - Change the size of the block by mm_mallocing a new block,
  *      copying its data, and mm_freeing the old block.
- **/
+ */
 void *mm_realloc(void *old_ptr, size_t size) {
-    (void)old_ptr;
-    (void)size;
+    (void) old_ptr;
+    (void) size;
     return NULL;
 }
 
-
-/*
+/**
  * mm_calloc - Allocate the block and set it to zero.
  */
 void *mm_calloc(size_t nmemb, size_t size) {
-    (void)nmemb;
-    (void)size;
+    (void) nmemb;
+    (void) size;
     return NULL;
 }
 
-/*
+/**
  * mm_checkheap - So simple, it doesn't need a checker!
  */
-void mm_checkheap() {
+void mm_checkheap(void) {
 
 }
-- 
GitLab