feat: update structure
This commit is contained in:
19
cs2106/labs/lab4/bitmap/Makefile
Normal file
19
cs2106/labs/lab4/bitmap/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
.PHONY: run
|
||||
|
||||
bitmap: bitmap.c testmap.c
|
||||
gcc $^ -o $@
|
||||
|
||||
run-bitmap: bitmap
|
||||
./bitmap
|
||||
|
||||
mymalloc: mymalloc.c testmalloc.c bitmap.c
|
||||
gcc $^ -o $@
|
||||
|
||||
run-mymalloc: mymalloc
|
||||
./mymalloc
|
||||
|
||||
harness: harness.c mymalloc.c bitmap.c
|
||||
gcc $^ -o $@
|
||||
|
||||
run-harness: harness
|
||||
./harness
|
||||
BIN
cs2106/labs/lab4/bitmap/bitmap
Executable file
BIN
cs2106/labs/lab4/bitmap/bitmap
Executable file
Binary file not shown.
115
cs2106/labs/lab4/bitmap/bitmap.c
Normal file
115
cs2106/labs/lab4/bitmap/bitmap.c
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "bitmap.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// IMPLEMENTED FOR YOU
|
||||
// Utility function to print out an array of char as bits
|
||||
// Print the entire bitmap. Arguments: The bitmap itself, and the length of the
|
||||
// bitmap Each bit of the bitmap represents 1 byte of memory. 0 = free, 1 =
|
||||
// allocated. map: The bitmap itself, an array of unsigned char.
|
||||
// Each bit of the bitmap represents one byte of memory
|
||||
// len: The length of the bitmap array in characters
|
||||
//
|
||||
// Returns: Nothing
|
||||
void print_map(unsigned char *map, int len) {
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
unsigned char mask = 0b10000000;
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (map[i] & mask)
|
||||
printf("1");
|
||||
else
|
||||
printf("0");
|
||||
mask = mask >> 1;
|
||||
}
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Search the bitmap for the required number of zeroes (representing
|
||||
// free bytes of memory). Returns index of first stretch of 0s
|
||||
// that meet the criteria. You can use this as an index into
|
||||
// an array of char that represents the process heap
|
||||
// bitmap = Bitmap declared as an array of unsigned char
|
||||
// len = Length of bitmap in characters
|
||||
// num_zeroes = Length of string of 0's required
|
||||
// Returns: Index to stretch of 0's of required length, -1 if no such stretch
|
||||
// can be found
|
||||
|
||||
long search_map(unsigned char *bitmap, int len, long num_zeroes) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
unsigned char mask = 0b10000000;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if ((bitmap[i] & mask) == 0) {
|
||||
count++;
|
||||
if (count == num_zeroes) {
|
||||
return i * 8 + j - num_zeroes + 1;
|
||||
}
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
} // main
|
||||
|
||||
// Set map bits to 0 or 1 depending on whether value is non-zero
|
||||
// map = Bitmap, declared as an array of unsigned char
|
||||
// start = Starting index to mark as 1 or 0
|
||||
// length = Number of bits to mark
|
||||
// value = Value to mark the bits as. value = 0 marks the bits
|
||||
// as 0, non-zero marks the bits as 1
|
||||
// Returns: Nothing
|
||||
// start: 7
|
||||
// length: 4
|
||||
// value: 1
|
||||
|
||||
void set_map(unsigned char *map, long start, long length, int value) {
|
||||
// printf("set_map with start=%ld, length=%ld val=%d\n", start, length,
|
||||
// value);
|
||||
int starting_index = start / 8;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
int currIdx = (start + i) / 8;
|
||||
int currOffset = (start + i) % 8;
|
||||
|
||||
int mask = 0b10000000;
|
||||
if (value == 0) {
|
||||
map[currIdx] &= ~(mask >> currOffset);
|
||||
} else {
|
||||
map[currIdx] |= (mask >> currOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// the ~(1<< offset) is a nice trick to create, for example
|
||||
// ~(1 << 2) = 1111 1011
|
||||
// By anding this, you can set the value to 0 for that bit
|
||||
|
||||
// map[char_index + length_index] &= ~(1 << length_offset);
|
||||
// the (1<< offset) is a nice trick to create, for example
|
||||
// (1 << 2) = 0000 0100
|
||||
// likewise, set the given bit to 1
|
||||
// map[char_index + length_index] |= (1 << length_offset);
|
||||
}
|
||||
|
||||
// IMPLEMENTED FOR YOU
|
||||
// Marks a stretch of bits as "1", representing allocated memory
|
||||
// map = Bitmap declared as array of unsigned char
|
||||
// start = Starting index to mark
|
||||
// length = Number of bits to mark as "1"
|
||||
void allocate_map(unsigned char *map, long start, long length) {
|
||||
set_map(map, start, length, 1);
|
||||
}
|
||||
|
||||
// IMPLEMENTED FOR YOU
|
||||
// Marks a stretch of bits as "0", representing allocated memory
|
||||
// map = Bitmap declared as array of unsigned char
|
||||
// start = Starting index to mark
|
||||
// length = Number of bits to mark as "0"
|
||||
void free_map(unsigned char *map, long start, long length) {
|
||||
set_map(map, start, length, 0);
|
||||
}
|
||||
40
cs2106/labs/lab4/bitmap/bitmap.h
Normal file
40
cs2106/labs/lab4/bitmap/bitmap.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Bitmap management
|
||||
|
||||
The bitmap should be an array of unsigned char.
|
||||
|
||||
*/
|
||||
|
||||
// Used by test harness
|
||||
long get_index(void *ptr);
|
||||
|
||||
// Utility function to print out an array of char as bits
|
||||
// Print the entire bitmap. Arguments: The bitmap itself, and the length of the
|
||||
// bitmap Each bit of the bitmap represents 1 byte of memory. 0 = free, 1 =
|
||||
// allocated. map: The bitmap itself, an array of unsigned char.
|
||||
// Each bit of the bitmap represents one byte of memory
|
||||
// len: The length of the bitmap array in characters
|
||||
//
|
||||
// Returns: Nothing
|
||||
void print_map(unsigned char *map, int len);
|
||||
|
||||
// Search the bitmap for the required number of zeroes (representing
|
||||
// free bytes of memory). Returns index of first stretch of 0s
|
||||
// that meet the criteria. You can use this as an index into
|
||||
// an array of char that represents the process heap
|
||||
// bitmap = Bitmap declared as an array of unsigned char
|
||||
// len = Length of bitmap in characters
|
||||
// num_zeroes = Length of string of 0's required
|
||||
// Returns: Index to stretch of 0's of required length
|
||||
long search_map(unsigned char *bitmap, int len, long num_zeroes);
|
||||
|
||||
// Marks a stretch of bits as "1", representing allocated memory
|
||||
// map = Bitmap declared as array of unsigned char
|
||||
// start = Starting index to mark
|
||||
// length = Number of bits to mark as "1"
|
||||
void allocate_map(unsigned char *map, long start, long length);
|
||||
|
||||
// Marks a stretch of bits as "0", representing allocated memory
|
||||
// map = Bitmap declared as array of unsigned char
|
||||
// start = Starting index to mark
|
||||
// length = Number of bits to mark as "0"
|
||||
void free_map(unsigned char *, long, long);
|
||||
BIN
cs2106/labs/lab4/bitmap/harness
Executable file
BIN
cs2106/labs/lab4/bitmap/harness
Executable file
Binary file not shown.
52
cs2106/labs/lab4/bitmap/harness.c
Normal file
52
cs2106/labs/lab4/bitmap/harness.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void *runmalloc(size_t len, long expected_ndx) {
|
||||
|
||||
long ndx;
|
||||
void *ptr;
|
||||
|
||||
printf("Allocate %ld bytes.\n", len);
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
ptr = mymalloc(len);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
ndx = get_index((void *) ptr);
|
||||
printf("\n");
|
||||
assert(ndx == expected_ndx);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void runfree(void *ptr) {
|
||||
printf("Free\n");
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
myfree(ptr);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
ptr1 = runmalloc(4, 0);
|
||||
ptr2 = runmalloc(32, 4);
|
||||
ptr3 = runmalloc(2, 36);
|
||||
runfree(ptr2);
|
||||
ptr2 = runmalloc(12, 4);
|
||||
ptr4 = runmalloc(24, 38);
|
||||
ptr5 = runmalloc(18, 16);
|
||||
runfree(ptr1);
|
||||
ptr1 = runmalloc(2, 0);
|
||||
runfree(ptr1);
|
||||
runfree(ptr2);
|
||||
runfree(ptr3);
|
||||
runfree(ptr4);
|
||||
runfree(ptr5);
|
||||
}
|
||||
|
||||
|
||||
239
cs2106/labs/lab4/bitmap/llist.c
Normal file
239
cs2106/labs/lab4/bitmap/llist.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
//#define DEBUG // Enable debug printing
|
||||
|
||||
// Debug printer
|
||||
|
||||
void dbprintf(char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implements a double linked list.
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data) {
|
||||
TNode *node = malloc(sizeof(TNode));
|
||||
node->key = key;
|
||||
node->pdata = data;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir) {
|
||||
if(*llist == NULL) {
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
(*llist)->tail = *llist;
|
||||
}
|
||||
else
|
||||
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
|
||||
node->next = *llist;
|
||||
(*llist)->prev = node;
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
if(dir == 0)
|
||||
while(trav->next != NULL && trav->key < node->key)
|
||||
trav = trav->next;
|
||||
else if(dir == 1)
|
||||
while(trav->next != NULL && trav->key > node->key)
|
||||
trav = trav->next;
|
||||
|
||||
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
|
||||
(trav->key > node->key && dir == 1))) {
|
||||
trav->next = node;
|
||||
node->prev = trav;
|
||||
|
||||
// Set the tail
|
||||
(*llist)->tail = node;
|
||||
} else {
|
||||
// Insert into the previous space
|
||||
|
||||
node->next = trav;
|
||||
|
||||
if(trav->prev != NULL) {
|
||||
trav->prev->next = node;
|
||||
node->prev = trav->prev;
|
||||
}
|
||||
|
||||
if(trav->next != NULL) {
|
||||
}
|
||||
|
||||
trav->prev = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node) {
|
||||
|
||||
if(*llist == NULL || node == NULL)
|
||||
return;
|
||||
|
||||
if((*llist)->key == node->key) {
|
||||
// Node to be deleted is at the front of the list.
|
||||
*llist = (*llist)->next;
|
||||
|
||||
// Ensure that we don't point to it anymore.
|
||||
if(*llist != NULL)
|
||||
(*llist)->prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
while(trav != NULL && trav->key != node->key)
|
||||
trav = trav->next;
|
||||
|
||||
// We've found the deletion point
|
||||
if(trav != NULL) {
|
||||
trav->prev->next = trav->next;
|
||||
|
||||
if(trav->next != NULL)
|
||||
trav->next->prev = trav->prev;
|
||||
else
|
||||
(*llist)->tail = trav->prev;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key) {
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *trav = llist;
|
||||
|
||||
while(trav != NULL && trav->key != key)
|
||||
trav = trav->next;
|
||||
|
||||
return trav;
|
||||
}
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir) {
|
||||
if(dir == 0) {
|
||||
if(node->prev == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node);
|
||||
}
|
||||
else
|
||||
if(dir == 1) {
|
||||
if(node->next == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node->next);
|
||||
}
|
||||
}
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *)) {
|
||||
TNode *trav = llist;
|
||||
while(trav) {
|
||||
func(trav);
|
||||
trav = trav->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist) {
|
||||
TNode *trav = *llist, *tmp;
|
||||
while(trav) {
|
||||
tmp = trav->next;
|
||||
free(trav);
|
||||
trav = tmp;
|
||||
}
|
||||
|
||||
*llist = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return;
|
||||
|
||||
if(where == FRONT)
|
||||
llist->trav = llist;
|
||||
else
|
||||
if(where == REAR)
|
||||
llist->trav = llist->tail;
|
||||
}
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->prev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
113
cs2106/labs/lab4/bitmap/llist.h
Normal file
113
cs2106/labs/lab4/bitmap/llist.h
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
// Uncomment the next line to enable debug printing
|
||||
#define DEBUG // Enable debug printing
|
||||
|
||||
// The debug printer; used like a normal printf, except
|
||||
// that printing can be turned off by commenting out the
|
||||
// #define DEBUG above.
|
||||
void dbprintf(char *format, ...);
|
||||
|
||||
// You should modify this structure to hold
|
||||
// whatever you need to implement your
|
||||
// memory manager
|
||||
|
||||
typedef struct td {
|
||||
size_t len;
|
||||
} TData;
|
||||
|
||||
|
||||
/* -----------------------------------------
|
||||
BASIC ROUTINES
|
||||
|
||||
Basic linked list routines
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Basic double linked list node.
|
||||
|
||||
typedef struct tn {
|
||||
unsigned int key;
|
||||
TData *pdata; // Pointer to the data you want to store
|
||||
|
||||
struct tn *trav; // Only used in the root for traversal
|
||||
struct tn *tail; // Only used in the root for finding the end of the list
|
||||
struct tn *prev;
|
||||
struct tn *next;
|
||||
} TNode;
|
||||
|
||||
// Insert Direction
|
||||
#define ASCENDING 0
|
||||
#define DESCENDING 1
|
||||
|
||||
// Merge direction
|
||||
#define PRECEDING 0
|
||||
#define SUCCEEDING 1
|
||||
|
||||
// Traverser position
|
||||
#define FRONT 0
|
||||
#define REAR 1
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data);
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir);
|
||||
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node);
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key);
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir);
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist);
|
||||
|
||||
/* -----------------------------------------
|
||||
TRAVERSAL ROUTINES
|
||||
|
||||
Lets you traverse the linked list
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *));
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where);
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist);
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist);
|
||||
BIN
cs2106/labs/lab4/bitmap/mymalloc
Executable file
BIN
cs2106/labs/lab4/bitmap/mymalloc
Executable file
Binary file not shown.
40
cs2106/labs/lab4/bitmap/mymalloc.c
Normal file
40
cs2106/labs/lab4/bitmap/mymalloc.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "mymalloc.h"
|
||||
#include "bitmap.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char _heap[MEMSIZE] = {0};
|
||||
unsigned char _bitmap[BITMAP_SIZE] = {};
|
||||
char lens[MEMSIZE] = {0};
|
||||
|
||||
// Do not change this. Used by the test harness.
|
||||
// You may however use this function in your code if necessary.
|
||||
long get_index(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
else
|
||||
return (long)((char *)ptr - &_heap[0]);
|
||||
}
|
||||
|
||||
void print_memlist() { print_map(_bitmap, BITMAP_SIZE); }
|
||||
|
||||
// Allocates size bytes of memory and returns a pointer
|
||||
// to the first byte.
|
||||
void *mymalloc(size_t size) {
|
||||
long start = search_map(_bitmap, BITMAP_SIZE, size);
|
||||
if (start == -1)
|
||||
return NULL;
|
||||
allocate_map(_bitmap, start, size);
|
||||
lens[start] = size;
|
||||
return (void *)(&_heap[start]);
|
||||
}
|
||||
|
||||
// Frees memory pointer to by ptr.
|
||||
void myfree(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
long ptrIdx = get_index(ptr);
|
||||
long size = lens[ptrIdx];
|
||||
free_map(_bitmap, ptrIdx, size);
|
||||
lens[ptrIdx] = 0;
|
||||
}
|
||||
12
cs2106/labs/lab4/bitmap/mymalloc.h
Normal file
12
cs2106/labs/lab4/bitmap/mymalloc.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "stdio.h"
|
||||
#define MEMSIZE 64 // Size of memory in bytes
|
||||
#define BITMAP_SIZE 8 // Size of Bitmap
|
||||
|
||||
// Used by the test harness
|
||||
long get_index(void *ptr);
|
||||
|
||||
// Debugging routine
|
||||
void print_memlist();
|
||||
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
||||
35
cs2106/labs/lab4/bitmap/testmalloc.c
Normal file
35
cs2106/labs/lab4/bitmap/testmalloc.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "mymalloc.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void testalloc(long size, char *ptrname, char **ptr) {
|
||||
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
|
||||
*ptr = mymalloc(size);
|
||||
|
||||
if (*ptr == NULL)
|
||||
printf("Allocation failed.\n");
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
void testfree(char *ptr, char *ptrname) {
|
||||
printf("\nFreeing %s\n", ptrname);
|
||||
myfree(ptr);
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
int main() {
|
||||
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
testalloc(4, "ptr1", &ptr1);
|
||||
testalloc(32, "ptr2", &ptr2);
|
||||
testalloc(4, "ptr3", &ptr3);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(24, "ptr2", &ptr2);
|
||||
testalloc(6, "ptr4", &ptr4);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(32, "ptr5", &ptr5);
|
||||
testfree(ptr1, "ptr1");
|
||||
testfree(ptr2, "ptr2");
|
||||
testfree(ptr3, "ptr3");
|
||||
testfree(ptr4, "ptr4");
|
||||
testfree(ptr5, "ptr5");
|
||||
}
|
||||
54
cs2106/labs/lab4/bitmap/testmap.c
Normal file
54
cs2106/labs/lab4/bitmap/testmap.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "bitmap.h"
|
||||
|
||||
#define LEN 5
|
||||
|
||||
void print_result(unsigned char *map, int len, long length, long expected) {
|
||||
long ndx = search_map(map, len, length);
|
||||
printf("Length: %ld, Expected: %ld, Actual: %ld\n", length, expected, ndx);
|
||||
|
||||
// This will cause a crash if the index returned does not match what is expected
|
||||
assert(ndx == expected);
|
||||
}
|
||||
|
||||
int main() {
|
||||
unsigned char map[LEN] = {0b11001000, 0b00011111, 0b00001100, 0b11000000, 0b00000001};
|
||||
int ndx;
|
||||
|
||||
printf("\n");
|
||||
print_result(map, LEN, 2, 2);
|
||||
print_result(map, LEN, 4, 5);
|
||||
print_result(map, LEN, 6, 5);
|
||||
print_result(map, LEN, 12, 26);
|
||||
print_result(map, LEN, 128, -1);
|
||||
|
||||
// Allocate map
|
||||
printf("\nAllocating 2 bytes\n");
|
||||
printf("BEFORE: ");
|
||||
print_map(map, LEN);
|
||||
ndx = search_map(map, LEN, 2);
|
||||
allocate_map(map, ndx, 2);
|
||||
printf("AFTER: ");
|
||||
print_map(map, LEN);
|
||||
printf("\n");
|
||||
|
||||
printf("Allocating 12 bytes\n");
|
||||
printf("BEFORE: ");
|
||||
print_map(map, LEN);
|
||||
ndx = search_map(map, LEN, 12);
|
||||
allocate_map(map, ndx, 12);
|
||||
printf("AFTER: ");
|
||||
print_map(map, LEN);
|
||||
printf("\n");
|
||||
print_result(map, LEN, 12, -1);
|
||||
|
||||
printf("Freeing 12 bytes\n");
|
||||
printf("BEFORE: ");
|
||||
print_map(map, LEN);
|
||||
free_map(map, ndx, 12);
|
||||
printf("AFTER: ");
|
||||
print_map(map, LEN);
|
||||
printf("\n");
|
||||
print_result(map, LEN, 12, 26);
|
||||
}
|
||||
13
cs2106/labs/lab4/linkedlist/bf/Makefile
Normal file
13
cs2106/labs/lab4/linkedlist/bf/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
.PHONY: run test
|
||||
|
||||
run: harness-bf
|
||||
./harness-bf
|
||||
|
||||
test: testmalloc
|
||||
./testmalloc
|
||||
|
||||
harness-bf: harness-bf.c llist.c mymalloc.c
|
||||
gcc $^ -o $@
|
||||
|
||||
testmalloc: testmalloc.c mymalloc.c llist.c
|
||||
gcc $^ -o $@
|
||||
55
cs2106/labs/lab4/linkedlist/bf/harness-bf.c
Normal file
55
cs2106/labs/lab4/linkedlist/bf/harness-bf.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void *runmalloc(size_t len, long expected_ndx) {
|
||||
|
||||
long ndx;
|
||||
void *ptr;
|
||||
|
||||
printf("Allocate %ld bytes.\n", len);
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
ptr = mymalloc(len);
|
||||
ndx = get_index((void *) ptr);
|
||||
printf("EXPECTED: %ld ACTUAL: %ld\n", expected_ndx, ndx);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
assert(ndx == expected_ndx);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void runfree(void *ptr) {
|
||||
printf("Free\n");
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
myfree(ptr);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
ptr1 = runmalloc(4, 0);
|
||||
ptr2 = runmalloc(32, 4);
|
||||
ptr3 = runmalloc(2, 36);
|
||||
runfree(ptr2);
|
||||
ptr2 = runmalloc(12, 4);
|
||||
ptr4 = runmalloc(24, 38);
|
||||
ptr5 = runmalloc(18, 16);
|
||||
runfree(ptr1);
|
||||
ptr1 = runmalloc(2, 34);
|
||||
runfree(ptr1);
|
||||
runfree(ptr2);
|
||||
runfree(ptr3);
|
||||
runfree(ptr4);
|
||||
runfree(ptr5);
|
||||
}
|
||||
|
||||
|
||||
239
cs2106/labs/lab4/linkedlist/bf/llist.c
Normal file
239
cs2106/labs/lab4/linkedlist/bf/llist.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
//#define DEBUG // Enable debug printing
|
||||
|
||||
// Debug printer
|
||||
|
||||
void dbprintf(char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implements a double linked list.
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data) {
|
||||
TNode *node = malloc(sizeof(TNode));
|
||||
node->key = key;
|
||||
node->pdata = data;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir) {
|
||||
if(*llist == NULL) {
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
(*llist)->tail = *llist;
|
||||
}
|
||||
else
|
||||
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
|
||||
node->next = *llist;
|
||||
(*llist)->prev = node;
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
if(dir == 0)
|
||||
while(trav->next != NULL && trav->key < node->key)
|
||||
trav = trav->next;
|
||||
else if(dir == 1)
|
||||
while(trav->next != NULL && trav->key > node->key)
|
||||
trav = trav->next;
|
||||
|
||||
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
|
||||
(trav->key > node->key && dir == 1))) {
|
||||
trav->next = node;
|
||||
node->prev = trav;
|
||||
|
||||
// Set the tail
|
||||
(*llist)->tail = node;
|
||||
} else {
|
||||
// Insert into the previous space
|
||||
|
||||
node->next = trav;
|
||||
|
||||
if(trav->prev != NULL) {
|
||||
trav->prev->next = node;
|
||||
node->prev = trav->prev;
|
||||
}
|
||||
|
||||
if(trav->next != NULL) {
|
||||
}
|
||||
|
||||
trav->prev = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node) {
|
||||
|
||||
if(*llist == NULL || node == NULL)
|
||||
return;
|
||||
|
||||
if((*llist)->key == node->key) {
|
||||
// Node to be deleted is at the front of the list.
|
||||
*llist = (*llist)->next;
|
||||
|
||||
// Ensure that we don't point to it anymore.
|
||||
if(*llist != NULL)
|
||||
(*llist)->prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
while(trav != NULL && trav->key != node->key)
|
||||
trav = trav->next;
|
||||
|
||||
// We've found the deletion point
|
||||
if(trav != NULL) {
|
||||
trav->prev->next = trav->next;
|
||||
|
||||
if(trav->next != NULL)
|
||||
trav->next->prev = trav->prev;
|
||||
else
|
||||
(*llist)->tail = trav->prev;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key) {
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *trav = llist;
|
||||
|
||||
while(trav != NULL && trav->key != key)
|
||||
trav = trav->next;
|
||||
|
||||
return trav;
|
||||
}
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir) {
|
||||
if(dir == 0) {
|
||||
if(node->prev == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node);
|
||||
}
|
||||
else
|
||||
if(dir == 1) {
|
||||
if(node->next == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node->next);
|
||||
}
|
||||
}
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *)) {
|
||||
TNode *trav = llist;
|
||||
while(trav) {
|
||||
func(trav);
|
||||
trav = trav->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist) {
|
||||
TNode *trav = *llist, *tmp;
|
||||
while(trav) {
|
||||
tmp = trav->next;
|
||||
free(trav);
|
||||
trav = tmp;
|
||||
}
|
||||
|
||||
*llist = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return;
|
||||
|
||||
if(where == FRONT)
|
||||
llist->trav = llist;
|
||||
else
|
||||
if(where == REAR)
|
||||
llist->trav = llist->tail;
|
||||
}
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->prev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
115
cs2106/labs/lab4/linkedlist/bf/llist.h
Normal file
115
cs2106/labs/lab4/linkedlist/bf/llist.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Uncomment the next line to enable debug printing
|
||||
#define DEBUG // Enable debug printing
|
||||
|
||||
// The debug printer; used like a normal printf, except
|
||||
// that printing can be turned off by commenting out the
|
||||
// #define DEBUG above.
|
||||
void dbprintf(char *format, ...);
|
||||
|
||||
// You should modify this structure to hold
|
||||
// whatever you need to implement your
|
||||
// memory manager. You can delete the
|
||||
// val field. It is only used for testlist.c
|
||||
|
||||
typedef struct td {
|
||||
bool occupied;
|
||||
size_t size;
|
||||
} TData;
|
||||
|
||||
/* -----------------------------------------
|
||||
BASIC ROUTINES
|
||||
|
||||
Basic linked list routines
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Basic double linked list node.
|
||||
|
||||
typedef struct tn {
|
||||
unsigned int key;
|
||||
TData *pdata; // Pointer to the data you want to store
|
||||
|
||||
struct tn *trav; // Only used in the root for traversal
|
||||
struct tn *tail; // Only used in the root for finding the end of the list
|
||||
struct tn *prev;
|
||||
struct tn *next;
|
||||
} TNode;
|
||||
|
||||
// Insert Direction
|
||||
#define ASCENDING 0
|
||||
#define DESCENDING 1
|
||||
|
||||
// Merge direction
|
||||
#define PRECEDING 0
|
||||
#define SUCCEEDING 1
|
||||
|
||||
// Traverser position
|
||||
#define FRONT 0
|
||||
#define REAR 1
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data);
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir);
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node);
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key);
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir);
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist);
|
||||
|
||||
/* -----------------------------------------
|
||||
TRAVERSAL ROUTINES
|
||||
|
||||
Lets you traverse the linked list
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *));
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where);
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist);
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist);
|
||||
103
cs2106/labs/lab4/linkedlist/bf/mymalloc.c
Normal file
103
cs2106/labs/lab4/linkedlist/bf/mymalloc.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "mymalloc.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/_types/_null.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
char _heap[MEMSIZE] = {0};
|
||||
TNode *_memlist = NULL; // To maintain information about length
|
||||
|
||||
// Do not change this. Used by the test harness.
|
||||
// You may however use this function in your code if necessary.
|
||||
long get_index(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
else
|
||||
return (long)((char *)ptr - &_heap[0]);
|
||||
}
|
||||
|
||||
// Allocates size bytes of memory and returns a pointer
|
||||
// to the first byte.
|
||||
void *mymalloc(size_t size) {
|
||||
if (_memlist == NULL) {
|
||||
TData *data = malloc(sizeof(TData));
|
||||
data->occupied = false;
|
||||
data->size = MEMSIZE;
|
||||
_memlist = make_node(0, data);
|
||||
}
|
||||
|
||||
// loop through the list to find a free block
|
||||
// if found, split the block and return the pointer
|
||||
// if not found, return NULL
|
||||
TNode *curr = _memlist;
|
||||
TNode *best = NULL;
|
||||
while (curr != NULL) {
|
||||
if (curr->pdata->occupied == true) {
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (curr->pdata->size < size) {
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (best == NULL) {
|
||||
best = curr;
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (best->pdata->size > curr->pdata->size) {
|
||||
best = curr;
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
if (best == NULL)
|
||||
return NULL;
|
||||
best->pdata->occupied = true;
|
||||
if (best->pdata->size > size) {
|
||||
// Create a new node with the leftover space
|
||||
TData *newData = malloc(sizeof(TData));
|
||||
newData->occupied = false;
|
||||
newData->size = best->pdata->size - size;
|
||||
TNode *newNode = make_node(best->key + size, newData);
|
||||
// insert new node after the current one in the list.
|
||||
insert_node(&_memlist, newNode, 0);
|
||||
// change the size of the current node.
|
||||
best->pdata->size = size;
|
||||
}
|
||||
return &_heap[best->key];
|
||||
}
|
||||
|
||||
// Frees memory pointer to by ptr.
|
||||
void myfree(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
long index = get_index(ptr);
|
||||
TNode *node = find_node(_memlist, index);
|
||||
if (node == NULL)
|
||||
return;
|
||||
node->pdata->occupied = false;
|
||||
// merge with the next node if it is free
|
||||
while (node->next != NULL && node->next->pdata->occupied == false) {
|
||||
node->pdata->size += node->next->pdata->size;
|
||||
merge_node(_memlist, node, 1);
|
||||
}
|
||||
|
||||
while (node->prev != NULL && node->prev->pdata->occupied == false) {
|
||||
TNode *prev = node->prev;
|
||||
prev->pdata->size += node->pdata->size;
|
||||
merge_node(_memlist, node, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void print_node(TNode *node) {
|
||||
printf("Status: %s Start index: %d Length: %zu\n",
|
||||
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
|
||||
node->pdata->size);
|
||||
}
|
||||
|
||||
void print_memlist() { process_list(_memlist, print_node); }
|
||||
7
cs2106/labs/lab4/linkedlist/bf/mymalloc.h
Normal file
7
cs2106/labs/lab4/linkedlist/bf/mymalloc.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#define MEMSIZE 64 * 1024 // Size of memory in bytes
|
||||
|
||||
long get_index(void *ptr);
|
||||
void print_memlist();
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
||||
BIN
cs2106/labs/lab4/linkedlist/bf/testmalloc
Executable file
BIN
cs2106/labs/lab4/linkedlist/bf/testmalloc
Executable file
Binary file not shown.
36
cs2106/labs/lab4/linkedlist/bf/testmalloc.c
Normal file
36
cs2106/labs/lab4/linkedlist/bf/testmalloc.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void testalloc(long size, char *ptrname, char **ptr) {
|
||||
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
|
||||
*ptr = mymalloc(size);
|
||||
|
||||
if(*ptr == NULL)
|
||||
printf("Allocation failed.\n");
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
void testfree(char *ptr, char *ptrname) {
|
||||
printf("\nFreeing %s\n", ptrname);
|
||||
myfree(ptr);
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
int main() {
|
||||
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
testalloc(2048, "ptr1", &ptr1);
|
||||
testalloc(6144, "ptr2", &ptr2);
|
||||
testalloc(1024, "ptr3", &ptr3);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(2048, "ptr2", &ptr2);
|
||||
testalloc(4096, "ptr4", &ptr4);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(3072, "ptr5", &ptr5);
|
||||
testfree(ptr1, "ptr1");
|
||||
testfree(ptr2, "ptr2");
|
||||
testfree(ptr3, "ptr3");
|
||||
testfree(ptr4, "ptr4");
|
||||
testfree(ptr5, "ptr5");
|
||||
|
||||
}
|
||||
14
cs2106/labs/lab4/linkedlist/ff/Makefile
Normal file
14
cs2106/labs/lab4/linkedlist/ff/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
.PHONY: run test
|
||||
|
||||
run: harness-ff
|
||||
./harness-ff
|
||||
|
||||
test: testmalloc
|
||||
./testmalloc
|
||||
|
||||
harness-ff: harness-ff.c llist.c mymalloc.c
|
||||
gcc $^ -o $@
|
||||
|
||||
testmalloc: testmalloc.c mymalloc.c llist.c
|
||||
gcc $^ -o $@
|
||||
|
||||
54
cs2106/labs/lab4/linkedlist/ff/harness-ff.c
Normal file
54
cs2106/labs/lab4/linkedlist/ff/harness-ff.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "llist.h"
|
||||
#include "mymalloc.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void *runmalloc(size_t len, long expected_ndx) {
|
||||
|
||||
long ndx;
|
||||
void *ptr;
|
||||
|
||||
printf("Allocate %ld bytes.\n", len);
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
ptr = mymalloc(len);
|
||||
ndx = get_index((void *)ptr);
|
||||
printf("EXPECTED: %ld ACTUAL: %ld\n", expected_ndx, ndx);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
assert(ndx == expected_ndx);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void runfree(void *ptr) {
|
||||
printf("Free\n");
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
myfree(ptr);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
ptr1 = runmalloc(4, 0);
|
||||
ptr2 = runmalloc(32, 4);
|
||||
ptr3 = runmalloc(2, 36);
|
||||
runfree(ptr2);
|
||||
ptr2 = runmalloc(12, 4);
|
||||
ptr4 = runmalloc(24, 38);
|
||||
ptr5 = runmalloc(18, 16);
|
||||
runfree(ptr1);
|
||||
ptr1 = runmalloc(2, 0);
|
||||
runfree(ptr1);
|
||||
runfree(ptr2);
|
||||
runfree(ptr3);
|
||||
runfree(ptr4);
|
||||
runfree(ptr5);
|
||||
}
|
||||
239
cs2106/labs/lab4/linkedlist/ff/llist.c
Normal file
239
cs2106/labs/lab4/linkedlist/ff/llist.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
//#define DEBUG // Enable debug printing
|
||||
|
||||
// Debug printer
|
||||
|
||||
void dbprintf(char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implements a double linked list.
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data) {
|
||||
TNode *node = malloc(sizeof(TNode));
|
||||
node->key = key;
|
||||
node->pdata = data;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir) {
|
||||
if(*llist == NULL) {
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
(*llist)->tail = *llist;
|
||||
}
|
||||
else
|
||||
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
|
||||
node->next = *llist;
|
||||
(*llist)->prev = node;
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
if(dir == 0)
|
||||
while(trav->next != NULL && trav->key < node->key)
|
||||
trav = trav->next;
|
||||
else if(dir == 1)
|
||||
while(trav->next != NULL && trav->key > node->key)
|
||||
trav = trav->next;
|
||||
|
||||
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
|
||||
(trav->key > node->key && dir == 1))) {
|
||||
trav->next = node;
|
||||
node->prev = trav;
|
||||
|
||||
// Set the tail
|
||||
(*llist)->tail = node;
|
||||
} else {
|
||||
// Insert into the previous space
|
||||
|
||||
node->next = trav;
|
||||
|
||||
if(trav->prev != NULL) {
|
||||
trav->prev->next = node;
|
||||
node->prev = trav->prev;
|
||||
}
|
||||
|
||||
if(trav->next != NULL) {
|
||||
}
|
||||
|
||||
trav->prev = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node) {
|
||||
|
||||
if(*llist == NULL || node == NULL)
|
||||
return;
|
||||
|
||||
if((*llist)->key == node->key) {
|
||||
// Node to be deleted is at the front of the list.
|
||||
*llist = (*llist)->next;
|
||||
|
||||
// Ensure that we don't point to it anymore.
|
||||
if(*llist != NULL)
|
||||
(*llist)->prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
while(trav != NULL && trav->key != node->key)
|
||||
trav = trav->next;
|
||||
|
||||
// We've found the deletion point
|
||||
if(trav != NULL) {
|
||||
trav->prev->next = trav->next;
|
||||
|
||||
if(trav->next != NULL)
|
||||
trav->next->prev = trav->prev;
|
||||
else
|
||||
(*llist)->tail = trav->prev;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key) {
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *trav = llist;
|
||||
|
||||
while(trav != NULL && trav->key != key)
|
||||
trav = trav->next;
|
||||
|
||||
return trav;
|
||||
}
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir) {
|
||||
if(dir == 0) {
|
||||
if(node->prev == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node);
|
||||
}
|
||||
else
|
||||
if(dir == 1) {
|
||||
if(node->next == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node->next);
|
||||
}
|
||||
}
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *)) {
|
||||
TNode *trav = llist;
|
||||
while(trav) {
|
||||
func(trav);
|
||||
trav = trav->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist) {
|
||||
TNode *trav = *llist, *tmp;
|
||||
while(trav) {
|
||||
tmp = trav->next;
|
||||
free(trav);
|
||||
trav = tmp;
|
||||
}
|
||||
|
||||
*llist = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return;
|
||||
|
||||
if(where == FRONT)
|
||||
llist->trav = llist;
|
||||
else
|
||||
if(where == REAR)
|
||||
llist->trav = llist->tail;
|
||||
}
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->prev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
115
cs2106/labs/lab4/linkedlist/ff/llist.h
Normal file
115
cs2106/labs/lab4/linkedlist/ff/llist.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Uncomment the next line to enable debug printing
|
||||
#define DEBUG // Enable debug printing
|
||||
|
||||
// The debug printer; used like a normal printf, except
|
||||
// that printing can be turned off by commenting out the
|
||||
// #define DEBUG above.
|
||||
void dbprintf(char *format, ...);
|
||||
|
||||
// You should modify this structure to hold
|
||||
// whatever you need to implement your
|
||||
// memory manager. You can delete the
|
||||
// val field. It is only used for testlist.c
|
||||
|
||||
typedef struct td {
|
||||
bool occupied;
|
||||
size_t size;
|
||||
} TData;
|
||||
|
||||
/* -----------------------------------------
|
||||
BASIC ROUTINES
|
||||
|
||||
Basic linked list routines
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Basic double linked list node.
|
||||
|
||||
typedef struct tn {
|
||||
unsigned int key;
|
||||
TData *pdata; // Pointer to the data you want to store
|
||||
|
||||
struct tn *trav; // Only used in the root for traversal
|
||||
struct tn *tail; // Only used in the root for finding the end of the list
|
||||
struct tn *prev;
|
||||
struct tn *next;
|
||||
} TNode;
|
||||
|
||||
// Insert Direction
|
||||
#define ASCENDING 0
|
||||
#define DESCENDING 1
|
||||
|
||||
// Merge direction
|
||||
#define PRECEDING 0
|
||||
#define SUCCEEDING 1
|
||||
|
||||
// Traverser position
|
||||
#define FRONT 0
|
||||
#define REAR 1
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data);
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir);
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node);
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key);
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir);
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist);
|
||||
|
||||
/* -----------------------------------------
|
||||
TRAVERSAL ROUTINES
|
||||
|
||||
Lets you traverse the linked list
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *));
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where);
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist);
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist);
|
||||
87
cs2106/labs/lab4/linkedlist/ff/mymalloc.c
Normal file
87
cs2106/labs/lab4/linkedlist/ff/mymalloc.c
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "mymalloc.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/_types/_null.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
char _heap[MEMSIZE] = {0};
|
||||
TNode *_memlist = NULL; // To maintain information about length
|
||||
|
||||
// Do not change this. Used by the test harness.
|
||||
// You may however use this function in your code if necessary.
|
||||
long get_index(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
else
|
||||
return (long)((char *)ptr - &_heap[0]);
|
||||
}
|
||||
|
||||
// Allocates size bytes of memory and returns a pointer
|
||||
// to the first byte.
|
||||
void *mymalloc(size_t size) {
|
||||
if (_memlist == NULL) {
|
||||
TData *data = malloc(sizeof(TData));
|
||||
data->occupied = false;
|
||||
data->size = MEMSIZE;
|
||||
_memlist = make_node(0, data);
|
||||
}
|
||||
|
||||
// loop through the list to find a free block
|
||||
// if found, split the block and return the pointer
|
||||
// if not found, return NULL
|
||||
TNode *curr = _memlist;
|
||||
while (curr != NULL) {
|
||||
TData *data = curr->pdata;
|
||||
if (data->occupied == false && data->size >= size) {
|
||||
data->occupied = true;
|
||||
if (data->size > size) {
|
||||
// Create a new node with the leftover space
|
||||
TData *newData = malloc(sizeof(TData));
|
||||
newData->occupied = false;
|
||||
newData->size = data->size - size;
|
||||
TNode *newNode = make_node(curr->key + size, newData);
|
||||
// insert new node after the current one in the list.
|
||||
insert_node(&_memlist, newNode, 0);
|
||||
// change the size of the current node.
|
||||
data->size = size;
|
||||
}
|
||||
return &_heap[curr->key];
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Frees memory pointer to by ptr.
|
||||
void myfree(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
long index = get_index(ptr);
|
||||
TNode *node = find_node(_memlist, index);
|
||||
if (node == NULL)
|
||||
return;
|
||||
node->pdata->occupied = false;
|
||||
// merge with the next node if it is free
|
||||
while (node->next != NULL && node->next->pdata->occupied == false) {
|
||||
node->pdata->size += node->next->pdata->size;
|
||||
merge_node(_memlist, node, 1);
|
||||
}
|
||||
|
||||
while (node->prev != NULL && node->prev->pdata->occupied == false) {
|
||||
TNode *prev = node->prev;
|
||||
prev->pdata->size += node->pdata->size;
|
||||
merge_node(_memlist, node, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void print_node(TNode *node) {
|
||||
printf("Status: %s Start index: %d Length: %zu\n",
|
||||
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
|
||||
node->pdata->size);
|
||||
}
|
||||
|
||||
void print_memlist() { process_list(_memlist, print_node); }
|
||||
7
cs2106/labs/lab4/linkedlist/ff/mymalloc.h
Normal file
7
cs2106/labs/lab4/linkedlist/ff/mymalloc.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#define MEMSIZE 64 * 1024 // Size of memory in bytes
|
||||
|
||||
long get_index(void *ptr);
|
||||
void print_memlist();
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
||||
BIN
cs2106/labs/lab4/linkedlist/ff/testmalloc
Executable file
BIN
cs2106/labs/lab4/linkedlist/ff/testmalloc
Executable file
Binary file not shown.
35
cs2106/labs/lab4/linkedlist/ff/testmalloc.c
Normal file
35
cs2106/labs/lab4/linkedlist/ff/testmalloc.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "mymalloc.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void testalloc(long size, char *ptrname, char **ptr) {
|
||||
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
|
||||
*ptr = mymalloc(size);
|
||||
|
||||
if (*ptr == NULL)
|
||||
printf("Allocation failed.\n");
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
void testfree(char *ptr, char *ptrname) {
|
||||
printf("\nFreeing %s\n", ptrname);
|
||||
myfree(ptr);
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
int main() {
|
||||
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
testalloc(2048, "ptr1", &ptr1);
|
||||
testalloc(6144, "ptr2", &ptr2);
|
||||
testalloc(1024, "ptr3", &ptr3);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(2048, "ptr2", &ptr2);
|
||||
testalloc(4096, "ptr4", &ptr4);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(3072, "ptr5", &ptr5);
|
||||
testfree(ptr1, "ptr1");
|
||||
testfree(ptr2, "ptr2");
|
||||
testfree(ptr3, "ptr3");
|
||||
testfree(ptr4, "ptr4");
|
||||
testfree(ptr5, "ptr5");
|
||||
}
|
||||
239
cs2106/labs/lab4/linkedlist/llist.c
Normal file
239
cs2106/labs/lab4/linkedlist/llist.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
//#define DEBUG // Enable debug printing
|
||||
|
||||
// Debug printer
|
||||
|
||||
void dbprintf(char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implements a double linked list.
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data) {
|
||||
TNode *node = malloc(sizeof(TNode));
|
||||
node->key = key;
|
||||
node->pdata = data;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir) {
|
||||
if(*llist == NULL) {
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
(*llist)->tail = *llist;
|
||||
}
|
||||
else
|
||||
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
|
||||
node->next = *llist;
|
||||
(*llist)->prev = node;
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
if(dir == 0)
|
||||
while(trav->next != NULL && trav->key < node->key)
|
||||
trav = trav->next;
|
||||
else if(dir == 1)
|
||||
while(trav->next != NULL && trav->key > node->key)
|
||||
trav = trav->next;
|
||||
|
||||
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
|
||||
(trav->key > node->key && dir == 1))) {
|
||||
trav->next = node;
|
||||
node->prev = trav;
|
||||
|
||||
// Set the tail
|
||||
(*llist)->tail = node;
|
||||
} else {
|
||||
// Insert into the previous space
|
||||
|
||||
node->next = trav;
|
||||
|
||||
if(trav->prev != NULL) {
|
||||
trav->prev->next = node;
|
||||
node->prev = trav->prev;
|
||||
}
|
||||
|
||||
if(trav->next != NULL) {
|
||||
}
|
||||
|
||||
trav->prev = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node) {
|
||||
|
||||
if(*llist == NULL || node == NULL)
|
||||
return;
|
||||
|
||||
if((*llist)->key == node->key) {
|
||||
// Node to be deleted is at the front of the list.
|
||||
*llist = (*llist)->next;
|
||||
|
||||
// Ensure that we don't point to it anymore.
|
||||
if(*llist != NULL)
|
||||
(*llist)->prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
while(trav != NULL && trav->key != node->key)
|
||||
trav = trav->next;
|
||||
|
||||
// We've found the deletion point
|
||||
if(trav != NULL) {
|
||||
trav->prev->next = trav->next;
|
||||
|
||||
if(trav->next != NULL)
|
||||
trav->next->prev = trav->prev;
|
||||
else
|
||||
(*llist)->tail = trav->prev;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key) {
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *trav = llist;
|
||||
|
||||
while(trav != NULL && trav->key != key)
|
||||
trav = trav->next;
|
||||
|
||||
return trav;
|
||||
}
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir) {
|
||||
if(dir == 0) {
|
||||
if(node->prev == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node);
|
||||
}
|
||||
else
|
||||
if(dir == 1) {
|
||||
if(node->next == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node->next);
|
||||
}
|
||||
}
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *)) {
|
||||
TNode *trav = llist;
|
||||
while(trav) {
|
||||
func(trav);
|
||||
trav = trav->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist) {
|
||||
TNode *trav = *llist, *tmp;
|
||||
while(trav) {
|
||||
tmp = trav->next;
|
||||
free(trav);
|
||||
trav = tmp;
|
||||
}
|
||||
|
||||
*llist = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return;
|
||||
|
||||
if(where == FRONT)
|
||||
llist->trav = llist;
|
||||
else
|
||||
if(where == REAR)
|
||||
llist->trav = llist->tail;
|
||||
}
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->prev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
114
cs2106/labs/lab4/linkedlist/llist.h
Normal file
114
cs2106/labs/lab4/linkedlist/llist.h
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
// Uncomment the next line to enable debug printing
|
||||
#define DEBUG // Enable debug printing
|
||||
|
||||
// The debug printer; used like a normal printf, except
|
||||
// that printing can be turned off by commenting out the
|
||||
// #define DEBUG above.
|
||||
void dbprintf(char *format, ...);
|
||||
|
||||
// You should modify this structure to hold
|
||||
// whatever you need to implement your
|
||||
// memory manager. You can delete the
|
||||
// val field. It is only used for testlist.c
|
||||
|
||||
typedef struct td {
|
||||
int val;
|
||||
} TData;
|
||||
|
||||
|
||||
/* -----------------------------------------
|
||||
BASIC ROUTINES
|
||||
|
||||
Basic linked list routines
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Basic double linked list node.
|
||||
|
||||
typedef struct tn {
|
||||
unsigned int key;
|
||||
TData *pdata; // Pointer to the data you want to store
|
||||
|
||||
struct tn *trav; // Only used in the root for traversal
|
||||
struct tn *tail; // Only used in the root for finding the end of the list
|
||||
struct tn *prev;
|
||||
struct tn *next;
|
||||
} TNode;
|
||||
|
||||
// Insert Direction
|
||||
#define ASCENDING 0
|
||||
#define DESCENDING 1
|
||||
|
||||
// Merge direction
|
||||
#define PRECEDING 0
|
||||
#define SUCCEEDING 1
|
||||
|
||||
// Traverser position
|
||||
#define FRONT 0
|
||||
#define REAR 1
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data);
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir);
|
||||
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node);
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key);
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir);
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist);
|
||||
|
||||
/* -----------------------------------------
|
||||
TRAVERSAL ROUTINES
|
||||
|
||||
Lets you traverse the linked list
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *));
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where);
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist);
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist);
|
||||
25
cs2106/labs/lab4/linkedlist/mymalloc.c
Normal file
25
cs2106/labs/lab4/linkedlist/mymalloc.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
char _heap[MEMSIZE] = {0};
|
||||
TNode *_memlist = NULL; // To maintain information about length
|
||||
|
||||
// Do not change this. Used by the test harness.
|
||||
// You may however use this function in your code if necessary.
|
||||
long get_index(void *ptr) {
|
||||
if(ptr == NULL)
|
||||
return -1;
|
||||
else
|
||||
return (long) ((char *) ptr - &_heap[0]);
|
||||
}
|
||||
|
||||
// Allocates size bytes of memory and returns a pointer
|
||||
// to the first byte.
|
||||
void *mymalloc(size_t size) {
|
||||
}
|
||||
|
||||
// Frees memory pointer to by ptr.
|
||||
void myfree(void *ptr) {
|
||||
}
|
||||
|
||||
5
cs2106/labs/lab4/linkedlist/mymalloc.h
Normal file
5
cs2106/labs/lab4/linkedlist/mymalloc.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#define MEMSIZE 64 * 1024 // Size of memory in bytes
|
||||
|
||||
long get_index(void *ptr);
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
||||
192
cs2106/labs/lab4/linkedlist/pb/bintree.c
Normal file
192
cs2106/labs/lab4/linkedlist/pb/bintree.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "bintree.h"
|
||||
#include "mymalloc.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ------------------------- DO NOT IMPLEMENT THESE ----------------------
|
||||
|
||||
These are provided "free" to you, and you do not need to implement them,
|
||||
though you MAY need to understand what they do. Some give you hints
|
||||
on how to work with pointers to pointers. You MAY find some of these
|
||||
functions useful.
|
||||
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
// Searches for the node containing "name" in the tree whose root is at "root",
|
||||
// returning both the node ifself in "node", and its parent in "prevnode"
|
||||
// (useful for deleting node). Both "node" and "prevnode" are set to NULL
|
||||
// if name is not found in the tree.
|
||||
|
||||
void findNode(char *name, TTreeNode *root, TTreeNode **node,
|
||||
TTreeNode **prevnode) {
|
||||
|
||||
TTreeNode *trav = root;
|
||||
TTreeNode *prev = NULL;
|
||||
|
||||
while (trav != NULL) {
|
||||
int cmp = strcmp(trav->name, name);
|
||||
|
||||
if (cmp == 0) {
|
||||
*node = trav;
|
||||
*prevnode = prev;
|
||||
return;
|
||||
}
|
||||
|
||||
prev = trav;
|
||||
if (cmp < 0)
|
||||
trav = trav->right;
|
||||
else
|
||||
trav = trav->left;
|
||||
}
|
||||
|
||||
*node = NULL;
|
||||
*prevnode = NULL;
|
||||
}
|
||||
|
||||
// Searches for the node with the smallest value ("smallest node") in the tree
|
||||
// originating at "node". Returns the smallest node and its parent in
|
||||
// "smallest_node" and "parent" respectively.
|
||||
void findSmallest(TTreeNode *node, TTreeNode **smallest_node,
|
||||
TTreeNode **parent) {
|
||||
TTreeNode *trav = node;
|
||||
TTreeNode *prev = NULL;
|
||||
|
||||
if (trav == NULL)
|
||||
return;
|
||||
|
||||
while (trav->left != NULL) {
|
||||
prev = trav;
|
||||
trav = trav->left;
|
||||
}
|
||||
|
||||
*smallest_node = trav;
|
||||
*parent = prev;
|
||||
}
|
||||
|
||||
// Delete a node at "node" with parent node "prevnode"
|
||||
void delNode(TTreeNode *node, TTreeNode *prevnode) {
|
||||
// This is a leaf node
|
||||
if (node->left == NULL && node->right == NULL) {
|
||||
// See whether node is on parent's left or right, and NULL the
|
||||
// corresponding pointer
|
||||
|
||||
int cmp = strcmp(prevnode->name, node->name);
|
||||
|
||||
// Previous node is smaller than this one. This
|
||||
// node is on the right
|
||||
if (cmp < 0)
|
||||
prevnode->right = NULL;
|
||||
else
|
||||
prevnode->left = NULL;
|
||||
|
||||
freenode(node);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// This has a child on the left only
|
||||
if (node->right == NULL) {
|
||||
// Copy the right child over
|
||||
node = node->left;
|
||||
freenode(node->left);
|
||||
return;
|
||||
}
|
||||
|
||||
// This has a child on the right only
|
||||
if (node->left == NULL) {
|
||||
node = node->right;
|
||||
freenode(node->right);
|
||||
return;
|
||||
}
|
||||
|
||||
// This has children on both nodes
|
||||
TTreeNode *smallest, *smallest_parent;
|
||||
findSmallest(node->right, &smallest, &smallest_parent);
|
||||
node = smallest;
|
||||
smallest_parent->left = NULL;
|
||||
freenode(smallest);
|
||||
}
|
||||
|
||||
/* ---------------------------- IMPLEMENT THESE --------------------------- */
|
||||
|
||||
// Create a new node with name set to "name" and
|
||||
// phoneNum set to "phoneNum".
|
||||
void delTree(TTreeNode *root) {
|
||||
// Implement deleting the entire tree, whose
|
||||
// root is at "root".
|
||||
if (root == NULL)
|
||||
return;
|
||||
if (root->left != NULL)
|
||||
delTree(root->left);
|
||||
if (root->right != NULL)
|
||||
delTree(root->right);
|
||||
freenode(root);
|
||||
}
|
||||
|
||||
TTreeNode *makeNewNode(char *name, char *phoneNum) {
|
||||
TTreeNode *node = mymalloc(sizeof(TTreeNode));
|
||||
node->name = mymalloc(strlen(name) + 1);
|
||||
strcpy(node->name, name);
|
||||
strcpy(node->phoneNum, phoneNum);
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
return node;
|
||||
// Implement makeNewNode to create a new
|
||||
// TTreeNode containing name and phoneNum
|
||||
}
|
||||
|
||||
// Add a new node to the tree.
|
||||
// Note that "root" is a POINTER to the tree's root,
|
||||
// not the root itself.
|
||||
|
||||
void addNode(TTreeNode **root, TTreeNode *node) {
|
||||
if (*root == NULL) {
|
||||
*root = node;
|
||||
}
|
||||
|
||||
TTreeNode **trav = root;
|
||||
|
||||
while (1) {
|
||||
|
||||
int cmp = strcmp((*trav)->name, node->name);
|
||||
if (cmp == 0)
|
||||
return;
|
||||
if (cmp > 0) {
|
||||
if ((*trav)->left == NULL)
|
||||
(*trav)->left = node;
|
||||
else {
|
||||
trav = &((*trav)->left);
|
||||
continue;
|
||||
}
|
||||
} else if (cmp < 0) {
|
||||
if ((*trav)->right == NULL)
|
||||
(*trav)->right = node;
|
||||
else {
|
||||
trav = &((*trav)->right);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new node to the tree, where root is
|
||||
// the POINTER to the tree's root.
|
||||
}
|
||||
|
||||
void freenode(TTreeNode *node) {
|
||||
myfree(node->name);
|
||||
myfree(node);
|
||||
// Frees the memory used by node.
|
||||
}
|
||||
|
||||
void print_inorder(TTreeNode *node) {
|
||||
// Implement in-order printing of the tree
|
||||
// Recursion is probably best here.
|
||||
|
||||
if (node == NULL)
|
||||
return;
|
||||
if (node->left != NULL)
|
||||
print_inorder(node->left);
|
||||
printf("Name is %s Number is %s\n", node->name, node->phoneNum);
|
||||
if (node->right != NULL)
|
||||
print_inorder(node->right);
|
||||
}
|
||||
17
cs2106/labs/lab4/linkedlist/pb/bintree.h
Normal file
17
cs2106/labs/lab4/linkedlist/pb/bintree.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct tn {
|
||||
char *name;
|
||||
char phoneNum[9];
|
||||
struct tn *left, *right;
|
||||
} TTreeNode;
|
||||
|
||||
void findNode(char *, TTreeNode *, TTreeNode **, TTreeNode **);
|
||||
void findSmallest(TTreeNode *, TTreeNode **, TTreeNode **);
|
||||
void delNode(TTreeNode *, TTreeNode *);
|
||||
void delTree(TTreeNode *);
|
||||
TTreeNode *makeNewNode(char *, char *);
|
||||
void addNode(TTreeNode **, TTreeNode *);
|
||||
void freenode(TTreeNode *);
|
||||
void print_inorder(TTreeNode *);
|
||||
239
cs2106/labs/lab4/linkedlist/pb/llist.c
Normal file
239
cs2106/labs/lab4/linkedlist/pb/llist.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
//#define DEBUG // Enable debug printing
|
||||
|
||||
// Debug printer
|
||||
|
||||
void dbprintf(char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implements a double linked list.
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data) {
|
||||
TNode *node = malloc(sizeof(TNode));
|
||||
node->key = key;
|
||||
node->pdata = data;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir) {
|
||||
if(*llist == NULL) {
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
(*llist)->tail = *llist;
|
||||
}
|
||||
else
|
||||
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
|
||||
node->next = *llist;
|
||||
(*llist)->prev = node;
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
if(dir == 0)
|
||||
while(trav->next != NULL && trav->key < node->key)
|
||||
trav = trav->next;
|
||||
else if(dir == 1)
|
||||
while(trav->next != NULL && trav->key > node->key)
|
||||
trav = trav->next;
|
||||
|
||||
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
|
||||
(trav->key > node->key && dir == 1))) {
|
||||
trav->next = node;
|
||||
node->prev = trav;
|
||||
|
||||
// Set the tail
|
||||
(*llist)->tail = node;
|
||||
} else {
|
||||
// Insert into the previous space
|
||||
|
||||
node->next = trav;
|
||||
|
||||
if(trav->prev != NULL) {
|
||||
trav->prev->next = node;
|
||||
node->prev = trav->prev;
|
||||
}
|
||||
|
||||
if(trav->next != NULL) {
|
||||
}
|
||||
|
||||
trav->prev = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node) {
|
||||
|
||||
if(*llist == NULL || node == NULL)
|
||||
return;
|
||||
|
||||
if((*llist)->key == node->key) {
|
||||
// Node to be deleted is at the front of the list.
|
||||
*llist = (*llist)->next;
|
||||
|
||||
// Ensure that we don't point to it anymore.
|
||||
if(*llist != NULL)
|
||||
(*llist)->prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
while(trav != NULL && trav->key != node->key)
|
||||
trav = trav->next;
|
||||
|
||||
// We've found the deletion point
|
||||
if(trav != NULL) {
|
||||
trav->prev->next = trav->next;
|
||||
|
||||
if(trav->next != NULL)
|
||||
trav->next->prev = trav->prev;
|
||||
else
|
||||
(*llist)->tail = trav->prev;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key) {
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *trav = llist;
|
||||
|
||||
while(trav != NULL && trav->key != key)
|
||||
trav = trav->next;
|
||||
|
||||
return trav;
|
||||
}
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir) {
|
||||
if(dir == 0) {
|
||||
if(node->prev == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node);
|
||||
}
|
||||
else
|
||||
if(dir == 1) {
|
||||
if(node->next == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node->next);
|
||||
}
|
||||
}
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *)) {
|
||||
TNode *trav = llist;
|
||||
while(trav) {
|
||||
func(trav);
|
||||
trav = trav->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist) {
|
||||
TNode *trav = *llist, *tmp;
|
||||
while(trav) {
|
||||
tmp = trav->next;
|
||||
free(trav);
|
||||
trav = tmp;
|
||||
}
|
||||
|
||||
*llist = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return;
|
||||
|
||||
if(where == FRONT)
|
||||
llist->trav = llist;
|
||||
else
|
||||
if(where == REAR)
|
||||
llist->trav = llist->tail;
|
||||
}
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->prev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
115
cs2106/labs/lab4/linkedlist/pb/llist.h
Normal file
115
cs2106/labs/lab4/linkedlist/pb/llist.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Uncomment the next line to enable debug printing
|
||||
#define DEBUG // Enable debug printing
|
||||
|
||||
// The debug printer; used like a normal printf, except
|
||||
// that printing can be turned off by commenting out the
|
||||
// #define DEBUG above.
|
||||
void dbprintf(char *format, ...);
|
||||
|
||||
// You should modify this structure to hold
|
||||
// whatever you need to implement your
|
||||
// memory manager. You can delete the
|
||||
// val field. It is only used for testlist.c
|
||||
|
||||
typedef struct td {
|
||||
bool occupied;
|
||||
size_t size;
|
||||
} TData;
|
||||
|
||||
/* -----------------------------------------
|
||||
BASIC ROUTINES
|
||||
|
||||
Basic linked list routines
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Basic double linked list node.
|
||||
|
||||
typedef struct tn {
|
||||
unsigned int key;
|
||||
TData *pdata; // Pointer to the data you want to store
|
||||
|
||||
struct tn *trav; // Only used in the root for traversal
|
||||
struct tn *tail; // Only used in the root for finding the end of the list
|
||||
struct tn *prev;
|
||||
struct tn *next;
|
||||
} TNode;
|
||||
|
||||
// Insert Direction
|
||||
#define ASCENDING 0
|
||||
#define DESCENDING 1
|
||||
|
||||
// Merge direction
|
||||
#define PRECEDING 0
|
||||
#define SUCCEEDING 1
|
||||
|
||||
// Traverser position
|
||||
#define FRONT 0
|
||||
#define REAR 1
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data);
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir);
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node);
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key);
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir);
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist);
|
||||
|
||||
/* -----------------------------------------
|
||||
TRAVERSAL ROUTINES
|
||||
|
||||
Lets you traverse the linked list
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *));
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where);
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist);
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist);
|
||||
103
cs2106/labs/lab4/linkedlist/pb/mymalloc.c
Normal file
103
cs2106/labs/lab4/linkedlist/pb/mymalloc.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "mymalloc.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/_types/_null.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
char _heap[MEMSIZE] = {0};
|
||||
TNode *_memlist = NULL; // To maintain information about length
|
||||
|
||||
// Do not change this. Used by the test harness.
|
||||
// You may however use this function in your code if necessary.
|
||||
long get_index(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
else
|
||||
return (long)((char *)ptr - &_heap[0]);
|
||||
}
|
||||
|
||||
// Allocates size bytes of memory and returns a pointer
|
||||
// to the first byte.
|
||||
void *mymalloc(size_t size) {
|
||||
if (_memlist == NULL) {
|
||||
TData *data = malloc(sizeof(TData));
|
||||
data->occupied = false;
|
||||
data->size = MEMSIZE;
|
||||
_memlist = make_node(0, data);
|
||||
}
|
||||
|
||||
// loop through the list to find a free block
|
||||
// if found, split the block and return the pointer
|
||||
// if not found, return NULL
|
||||
TNode *curr = _memlist;
|
||||
TNode *best = NULL;
|
||||
while (curr != NULL) {
|
||||
if (curr->pdata->occupied == true) {
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (curr->pdata->size < size) {
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (best == NULL) {
|
||||
best = curr;
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (best->pdata->size > curr->pdata->size) {
|
||||
best = curr;
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
if (best == NULL)
|
||||
return NULL;
|
||||
best->pdata->occupied = true;
|
||||
if (best->pdata->size > size) {
|
||||
// Create a new node with the leftover space
|
||||
TData *newData = malloc(sizeof(TData));
|
||||
newData->occupied = false;
|
||||
newData->size = best->pdata->size - size;
|
||||
TNode *newNode = make_node(best->key + size, newData);
|
||||
// insert new node after the current one in the list.
|
||||
insert_node(&_memlist, newNode, 0);
|
||||
// change the size of the current node.
|
||||
best->pdata->size = size;
|
||||
}
|
||||
return &_heap[best->key];
|
||||
}
|
||||
|
||||
// Frees memory pointer to by ptr.
|
||||
void myfree(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
long index = get_index(ptr);
|
||||
TNode *node = find_node(_memlist, index);
|
||||
if (node == NULL)
|
||||
return;
|
||||
node->pdata->occupied = false;
|
||||
// merge with the next node if it is free
|
||||
while (node->next != NULL && node->next->pdata->occupied == false) {
|
||||
node->pdata->size += node->next->pdata->size;
|
||||
merge_node(_memlist, node, 1);
|
||||
}
|
||||
|
||||
while (node->prev != NULL && node->prev->pdata->occupied == false) {
|
||||
TNode *prev = node->prev;
|
||||
prev->pdata->size += node->pdata->size;
|
||||
merge_node(_memlist, node, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void print_node(TNode *node) {
|
||||
printf("Status: %s Start index: %d Length: %zu\n",
|
||||
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
|
||||
node->pdata->size);
|
||||
}
|
||||
|
||||
void print_memlist() { process_list(_memlist, print_node); }
|
||||
7
cs2106/labs/lab4/linkedlist/pb/mymalloc.h
Normal file
7
cs2106/labs/lab4/linkedlist/pb/mymalloc.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#define MEMSIZE 64 * 1024 // Size of memory in bytes
|
||||
|
||||
long get_index(void *ptr);
|
||||
void print_memlist();
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
||||
51
cs2106/labs/lab4/linkedlist/pb/phonebook.c
Normal file
51
cs2106/labs/lab4/linkedlist/pb/phonebook.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <stdio.h>
|
||||
#include "phonebook.h"
|
||||
#include "bintree.h"
|
||||
|
||||
static TTreeNode *_root = NULL;
|
||||
|
||||
char *findPerson(char *name)
|
||||
{
|
||||
TTreeNode *node, *prev;
|
||||
findNode(name, _root, &node, &prev);
|
||||
|
||||
if (node != NULL)
|
||||
return node->phoneNum;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_phonebook()
|
||||
{
|
||||
print_inorder(_root);
|
||||
}
|
||||
|
||||
void addPerson(char *name, char *phoneNum)
|
||||
{
|
||||
if (findPerson(name) == NULL)
|
||||
{
|
||||
TTreeNode *node = makeNewNode(name, phoneNum);
|
||||
addNode(&_root, node);
|
||||
}
|
||||
else
|
||||
printf("%s is already in phonebook.\n", name);
|
||||
}
|
||||
|
||||
void delPerson(char *name)
|
||||
{
|
||||
TTreeNode *node, *prevnode;
|
||||
findNode(name, _root, &node, &prevnode);
|
||||
if (node == NULL)
|
||||
{
|
||||
printf("Unable to find %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
delNode(node, prevnode);
|
||||
}
|
||||
|
||||
void delPhonebook()
|
||||
{
|
||||
delTree(_root);
|
||||
_root = NULL;
|
||||
}
|
||||
5
cs2106/labs/lab4/linkedlist/pb/phonebook.h
Normal file
5
cs2106/labs/lab4/linkedlist/pb/phonebook.h
Normal file
@@ -0,0 +1,5 @@
|
||||
char *findPerson(char *);
|
||||
void addPerson(char *, char *);
|
||||
void delPerson(char *);
|
||||
void print_phonebook();
|
||||
void delPhonebook();
|
||||
60
cs2106/labs/lab4/linkedlist/pb/testpb.c
Normal file
60
cs2106/labs/lab4/linkedlist/pb/testpb.c
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <stdio.h>
|
||||
#include "phonebook.h"
|
||||
|
||||
#define ITEMS 5
|
||||
|
||||
typedef struct d
|
||||
{
|
||||
char *name, *tel;
|
||||
} TData;
|
||||
|
||||
void printResult(char *name)
|
||||
{
|
||||
char *result;
|
||||
|
||||
printf("Looking for %s ", name);
|
||||
result = findPerson(name);
|
||||
if (result == NULL)
|
||||
printf("NOT FOUND\n");
|
||||
else
|
||||
printf(" Number is %s\n", result);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
TData data[ITEMS] = {{"Fred Astaire", "95551234"}, {"Jean Valjean", "95558764"}, {"Gal Gadot", "95551123"}, {"Aiken Dueet", "95558876"}, {"Victor Hugo", "95524601"}};
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ITEMS; i++)
|
||||
{
|
||||
printf("Adding %s, phone number %s\n", data[i].name, data[i].tel);
|
||||
addPerson(data[i].name, data[i].tel);
|
||||
}
|
||||
|
||||
printf("\nNow retrieiving stored data.\n");
|
||||
char *result;
|
||||
|
||||
for (i = 0; i < ITEMS; i++)
|
||||
{
|
||||
printResult(data[i].name);
|
||||
}
|
||||
|
||||
printf("\nRetrieving unknown person.\n");
|
||||
printResult("Wee Tu Loh");
|
||||
|
||||
printf("\nPrinting entire phonebook.\n");
|
||||
print_phonebook();
|
||||
|
||||
printf("\nDeleting Aiken Dueet.\n");
|
||||
delPerson("Aiken Dueet");
|
||||
print_phonebook();
|
||||
|
||||
printf("\nDeleting Victor Hugo.\n");
|
||||
delPerson("Victor Hugo");
|
||||
print_phonebook();
|
||||
|
||||
printf("\nDeleting entire phone book.\n");
|
||||
delPhonebook();
|
||||
print_phonebook();
|
||||
}
|
||||
178
cs2106/labs/lab4/linkedlist/testlist.c
Normal file
178
cs2106/labs/lab4/linkedlist/testlist.c
Normal file
@@ -0,0 +1,178 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "llist.h"
|
||||
|
||||
#define COUNT 10
|
||||
|
||||
void print_node(TNode *node) {
|
||||
if(node != NULL)
|
||||
printf("Key: %d\n", node->key);
|
||||
else
|
||||
printf("Unable to find key.\n");
|
||||
}
|
||||
|
||||
void free_data(TNode *node) {
|
||||
free(node->pdata);
|
||||
}
|
||||
|
||||
void trav_list(TNode *llist) {
|
||||
reset_traverser(llist, FRONT);
|
||||
TNode *node;
|
||||
|
||||
do {
|
||||
node = succ(llist);
|
||||
if(node)
|
||||
print_node(node);
|
||||
} while(node != NULL);
|
||||
}
|
||||
|
||||
void rev_trav_list(TNode *llist) {
|
||||
reset_traverser(llist, REAR);
|
||||
TNode *node;
|
||||
|
||||
do{
|
||||
node = pred(llist);
|
||||
if(node)
|
||||
print_node(node);
|
||||
} while(node != NULL);
|
||||
}
|
||||
|
||||
|
||||
int main(){
|
||||
TNode *llist = NULL;
|
||||
|
||||
int test_array[COUNT] = {10, 6, 2, 8, 1, 4, 5, 3, 9, 7};
|
||||
|
||||
// Insert
|
||||
|
||||
char c;
|
||||
printf("Hit enter to start ascending order test\n");
|
||||
scanf("%c", &c);
|
||||
|
||||
int i;
|
||||
printf("Inserting in ascending order\n");
|
||||
TData *data;
|
||||
TNode *node;
|
||||
|
||||
for(i=0; i<COUNT; i++) {
|
||||
data = (TData *) malloc(sizeof(TData));
|
||||
data->val = test_array[i];
|
||||
node = make_node(test_array[i], data);
|
||||
insert_node(&llist, node, ASCENDING);
|
||||
}
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
printf("Printing entire list using reverse traversal\n");
|
||||
rev_trav_list(llist);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 2\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 5\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 22\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Purging list\n");
|
||||
process_list(llist, free_data);
|
||||
purge_list(&llist);
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
printf("Hit enter to start descending order test\n");
|
||||
scanf("%c", &c);
|
||||
|
||||
printf("Inserting in descending order\n");
|
||||
for(i=0; i<COUNT; i++) {
|
||||
TNode *node = make_node(test_array[i], NULL);
|
||||
insert_node(&llist, node, DESCENDING);
|
||||
}
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
printf("Printing entire list using reverse traversal\n");
|
||||
rev_trav_list(llist);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 2\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 5\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 22\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Purging list\n");
|
||||
process_list(llist, free_data);
|
||||
purge_list(&llist);
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
36
cs2106/labs/lab4/linkedlist/testmalloc.c
Normal file
36
cs2106/labs/lab4/linkedlist/testmalloc.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void testalloc(long size, char *ptrname, char **ptr) {
|
||||
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
|
||||
*ptr = mymalloc(size);
|
||||
|
||||
if(*ptr == NULL)
|
||||
printf("Allocation failed.\n");
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
void testfree(char *ptr, char *ptrname) {
|
||||
printf("\nFreeing %s\n", ptrname);
|
||||
myfree(ptr);
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
int main() {
|
||||
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
testalloc(2048, "ptr1", &ptr1);
|
||||
testalloc(6144, "ptr2", &ptr2);
|
||||
testalloc(1024, "ptr3", &ptr3);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(2048, "ptr2", &ptr2);
|
||||
testalloc(4096, "ptr4", &ptr4);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(3072, "ptr5", &ptr5);
|
||||
testfree(ptr1, "ptr1");
|
||||
testfree(ptr2, "ptr2");
|
||||
testfree(ptr3, "ptr3");
|
||||
testfree(ptr4, "ptr4");
|
||||
testfree(ptr5, "ptr5");
|
||||
|
||||
}
|
||||
13
cs2106/labs/lab4/linkedlist/wf/Makefile
Normal file
13
cs2106/labs/lab4/linkedlist/wf/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
.PHONY: run test
|
||||
|
||||
run: harness-wf
|
||||
./harness-wf
|
||||
|
||||
test: testmalloc
|
||||
./testmalloc
|
||||
|
||||
harness-wf: harness-wf.c llist.c mymalloc.c
|
||||
gcc $^ -o $@
|
||||
|
||||
testmalloc: testmalloc.c mymalloc.c llist.c
|
||||
gcc $^ -o $@
|
||||
55
cs2106/labs/lab4/linkedlist/wf/harness-wf.c
Normal file
55
cs2106/labs/lab4/linkedlist/wf/harness-wf.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void *runmalloc(size_t len, long expected_ndx) {
|
||||
|
||||
long ndx;
|
||||
void *ptr;
|
||||
|
||||
printf("Allocate %ld bytes.\n", len);
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
ptr = mymalloc(len);
|
||||
ndx = get_index((void *) ptr);
|
||||
printf("EXPECTED: %ld ACTUAL: %ld\n", expected_ndx, ndx);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
assert(ndx == expected_ndx);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void runfree(void *ptr) {
|
||||
printf("Free\n");
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
myfree(ptr);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
ptr1 = runmalloc(4, 0);
|
||||
ptr2 = runmalloc(32, 4);
|
||||
ptr3 = runmalloc(2, 36);
|
||||
runfree(ptr2);
|
||||
ptr2 = runmalloc(12, 38);
|
||||
ptr4 = runmalloc(24, 50);
|
||||
ptr5 = runmalloc(18, 74);
|
||||
runfree(ptr1);
|
||||
ptr1 = runmalloc(2, 92);
|
||||
runfree(ptr1);
|
||||
runfree(ptr2);
|
||||
runfree(ptr3);
|
||||
runfree(ptr4);
|
||||
runfree(ptr5);
|
||||
}
|
||||
|
||||
|
||||
239
cs2106/labs/lab4/linkedlist/wf/llist.c
Normal file
239
cs2106/labs/lab4/linkedlist/wf/llist.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
//#define DEBUG // Enable debug printing
|
||||
|
||||
// Debug printer
|
||||
|
||||
void dbprintf(char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implements a double linked list.
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data) {
|
||||
TNode *node = malloc(sizeof(TNode));
|
||||
node->key = key;
|
||||
node->pdata = data;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir) {
|
||||
if(*llist == NULL) {
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
(*llist)->tail = *llist;
|
||||
}
|
||||
else
|
||||
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
|
||||
node->next = *llist;
|
||||
(*llist)->prev = node;
|
||||
*llist = node;
|
||||
(*llist)->trav = *llist;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
if(dir == 0)
|
||||
while(trav->next != NULL && trav->key < node->key)
|
||||
trav = trav->next;
|
||||
else if(dir == 1)
|
||||
while(trav->next != NULL && trav->key > node->key)
|
||||
trav = trav->next;
|
||||
|
||||
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
|
||||
(trav->key > node->key && dir == 1))) {
|
||||
trav->next = node;
|
||||
node->prev = trav;
|
||||
|
||||
// Set the tail
|
||||
(*llist)->tail = node;
|
||||
} else {
|
||||
// Insert into the previous space
|
||||
|
||||
node->next = trav;
|
||||
|
||||
if(trav->prev != NULL) {
|
||||
trav->prev->next = node;
|
||||
node->prev = trav->prev;
|
||||
}
|
||||
|
||||
if(trav->next != NULL) {
|
||||
}
|
||||
|
||||
trav->prev = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node) {
|
||||
|
||||
if(*llist == NULL || node == NULL)
|
||||
return;
|
||||
|
||||
if((*llist)->key == node->key) {
|
||||
// Node to be deleted is at the front of the list.
|
||||
*llist = (*llist)->next;
|
||||
|
||||
// Ensure that we don't point to it anymore.
|
||||
if(*llist != NULL)
|
||||
(*llist)->prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
TNode *trav = *llist;
|
||||
|
||||
while(trav != NULL && trav->key != node->key)
|
||||
trav = trav->next;
|
||||
|
||||
// We've found the deletion point
|
||||
if(trav != NULL) {
|
||||
trav->prev->next = trav->next;
|
||||
|
||||
if(trav->next != NULL)
|
||||
trav->next->prev = trav->prev;
|
||||
else
|
||||
(*llist)->tail = trav->prev;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key) {
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *trav = llist;
|
||||
|
||||
while(trav != NULL && trav->key != key)
|
||||
trav = trav->next;
|
||||
|
||||
return trav;
|
||||
}
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir) {
|
||||
if(dir == 0) {
|
||||
if(node->prev == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node);
|
||||
}
|
||||
else
|
||||
if(dir == 1) {
|
||||
if(node->next == NULL)
|
||||
return;
|
||||
|
||||
delete_node(&llist, node->next);
|
||||
}
|
||||
}
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *)) {
|
||||
TNode *trav = llist;
|
||||
while(trav) {
|
||||
func(trav);
|
||||
trav = trav->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist) {
|
||||
TNode *trav = *llist, *tmp;
|
||||
while(trav) {
|
||||
tmp = trav->next;
|
||||
free(trav);
|
||||
trav = tmp;
|
||||
}
|
||||
|
||||
*llist = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return;
|
||||
|
||||
if(where == FRONT)
|
||||
llist->trav = llist;
|
||||
else
|
||||
if(where == REAR)
|
||||
llist->trav = llist->tail;
|
||||
}
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->next;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist)
|
||||
{
|
||||
if(llist == NULL)
|
||||
return NULL;
|
||||
|
||||
TNode *ret = llist->trav;
|
||||
|
||||
if(llist->trav != NULL)
|
||||
llist->trav = llist->trav->prev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
115
cs2106/labs/lab4/linkedlist/wf/llist.h
Normal file
115
cs2106/labs/lab4/linkedlist/wf/llist.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Uncomment the next line to enable debug printing
|
||||
#define DEBUG // Enable debug printing
|
||||
|
||||
// The debug printer; used like a normal printf, except
|
||||
// that printing can be turned off by commenting out the
|
||||
// #define DEBUG above.
|
||||
void dbprintf(char *format, ...);
|
||||
|
||||
// You should modify this structure to hold
|
||||
// whatever you need to implement your
|
||||
// memory manager. You can delete the
|
||||
// val field. It is only used for testlist.c
|
||||
|
||||
typedef struct td {
|
||||
bool occupied;
|
||||
size_t size;
|
||||
} TData;
|
||||
|
||||
/* -----------------------------------------
|
||||
BASIC ROUTINES
|
||||
|
||||
Basic linked list routines
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Basic double linked list node.
|
||||
|
||||
typedef struct tn {
|
||||
unsigned int key;
|
||||
TData *pdata; // Pointer to the data you want to store
|
||||
|
||||
struct tn *trav; // Only used in the root for traversal
|
||||
struct tn *tail; // Only used in the root for finding the end of the list
|
||||
struct tn *prev;
|
||||
struct tn *next;
|
||||
} TNode;
|
||||
|
||||
// Insert Direction
|
||||
#define ASCENDING 0
|
||||
#define DESCENDING 1
|
||||
|
||||
// Merge direction
|
||||
#define PRECEDING 0
|
||||
#define SUCCEEDING 1
|
||||
|
||||
// Traverser position
|
||||
#define FRONT 0
|
||||
#define REAR 1
|
||||
|
||||
// Create a new node. You need to
|
||||
// Create your own TData node, populate
|
||||
// it, then create a new node with a suitable
|
||||
// key. Insertion into the link list is
|
||||
// by ascending order of the key. An example key
|
||||
// might be the starting address of a memory segment.
|
||||
|
||||
TNode *make_node(unsigned int key, TData *data);
|
||||
|
||||
// Inserts a node into the correct point of the
|
||||
// double linked list. The list is sorted
|
||||
// in ascending order of the key. Duplicate keys
|
||||
// are permitted, though not recommended.
|
||||
// llist = Pointer to link list
|
||||
// node = Pointer to node created by make_node
|
||||
// dir = 0: Insert in ascending order
|
||||
// dir = 1: Insert in descending order
|
||||
|
||||
void insert_node(TNode **llist, TNode *node, int dir);
|
||||
|
||||
// Remove a given node from the linked list
|
||||
void delete_node(TNode **llist, TNode *node);
|
||||
|
||||
// Find a node that has the value of key
|
||||
// If there are duplicate keys, the first one encountered
|
||||
// will be returned.
|
||||
TNode *find_node(TNode *llist, unsigned int key);
|
||||
|
||||
// Merge the node provided with either the node after or the node before.
|
||||
// You need to manage merging the data in node->pdata yourself. This code just
|
||||
// deletes the larger of the two nodes.
|
||||
// dir = 0: Merge with node before
|
||||
// dir = 1: Merge with node after
|
||||
|
||||
void merge_node(TNode *llist, TNode *node, int dir);
|
||||
|
||||
// Purge the entire list. You must
|
||||
// free any dynamic data in the TData
|
||||
// struct yourself.
|
||||
void purge_list(TNode **llist);
|
||||
|
||||
/* -----------------------------------------
|
||||
TRAVERSAL ROUTINES
|
||||
|
||||
Lets you traverse the linked list
|
||||
|
||||
---------------------------------------- */
|
||||
|
||||
// Go over every element of llist, and call func
|
||||
// func prototype is void func(TNode *);
|
||||
|
||||
void process_list(TNode *llist, void (*func)(TNode *));
|
||||
|
||||
// Reset traverser
|
||||
// where=0 START: Resets traverser to start of list
|
||||
// where=1 END: Rsets
|
||||
void reset_traverser(TNode *llist, int where);
|
||||
|
||||
// Get the next node
|
||||
TNode *succ(TNode *llist);
|
||||
|
||||
// Get the previous node
|
||||
TNode *pred(TNode *llist);
|
||||
103
cs2106/labs/lab4/linkedlist/wf/mymalloc.c
Normal file
103
cs2106/labs/lab4/linkedlist/wf/mymalloc.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "mymalloc.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/_types/_null.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
char _heap[MEMSIZE] = {0};
|
||||
TNode *_memlist = NULL; // To maintain information about length
|
||||
|
||||
// Do not change this. Used by the test harness.
|
||||
// You may however use this function in your code if necessary.
|
||||
long get_index(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
else
|
||||
return (long)((char *)ptr - &_heap[0]);
|
||||
}
|
||||
|
||||
// Allocates size bytes of memory and returns a pointer
|
||||
// to the first byte.
|
||||
void *mymalloc(size_t size) {
|
||||
if (_memlist == NULL) {
|
||||
TData *data = malloc(sizeof(TData));
|
||||
data->occupied = false;
|
||||
data->size = MEMSIZE;
|
||||
_memlist = make_node(0, data);
|
||||
}
|
||||
|
||||
// loop through the list to find a free block
|
||||
// if found, split the block and return the pointer
|
||||
// if not found, return NULL
|
||||
TNode *curr = _memlist;
|
||||
TNode *best = NULL;
|
||||
while (curr != NULL) {
|
||||
if (curr->pdata->occupied == true) {
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (curr->pdata->size < size) {
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (best == NULL) {
|
||||
best = curr;
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
if (best->pdata->size < curr->pdata->size) {
|
||||
best = curr;
|
||||
curr = curr->next;
|
||||
continue;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
if (best == NULL)
|
||||
return NULL;
|
||||
best->pdata->occupied = true;
|
||||
if (best->pdata->size > size) {
|
||||
// Create a new node with the leftover space
|
||||
TData *newData = malloc(sizeof(TData));
|
||||
newData->occupied = false;
|
||||
newData->size = best->pdata->size - size;
|
||||
TNode *newNode = make_node(best->key + size, newData);
|
||||
// insert new node after the current one in the list.
|
||||
insert_node(&_memlist, newNode, 0);
|
||||
// change the size of the current node.
|
||||
best->pdata->size = size;
|
||||
}
|
||||
return &_heap[best->key];
|
||||
}
|
||||
|
||||
// Frees memory pointer to by ptr.
|
||||
void myfree(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
long index = get_index(ptr);
|
||||
TNode *node = find_node(_memlist, index);
|
||||
if (node == NULL)
|
||||
return;
|
||||
node->pdata->occupied = false;
|
||||
// merge with the next node if it is free
|
||||
while (node->next != NULL && node->next->pdata->occupied == false) {
|
||||
node->pdata->size += node->next->pdata->size;
|
||||
merge_node(_memlist, node, 1);
|
||||
}
|
||||
|
||||
while (node->prev != NULL && node->prev->pdata->occupied == false) {
|
||||
TNode *prev = node->prev;
|
||||
prev->pdata->size += node->pdata->size;
|
||||
merge_node(_memlist, node, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void print_node(TNode *node) {
|
||||
printf("Status: %s Start index: %d Length: %zu\n",
|
||||
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
|
||||
node->pdata->size);
|
||||
}
|
||||
|
||||
void print_memlist() { process_list(_memlist, print_node); }
|
||||
7
cs2106/labs/lab4/linkedlist/wf/mymalloc.h
Normal file
7
cs2106/labs/lab4/linkedlist/wf/mymalloc.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#define MEMSIZE 64 * 1024 // Size of memory in bytes
|
||||
|
||||
long get_index(void *ptr);
|
||||
void print_memlist();
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
||||
BIN
cs2106/labs/lab4/linkedlist/wf/testmalloc
Executable file
BIN
cs2106/labs/lab4/linkedlist/wf/testmalloc
Executable file
Binary file not shown.
36
cs2106/labs/lab4/linkedlist/wf/testmalloc.c
Normal file
36
cs2106/labs/lab4/linkedlist/wf/testmalloc.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void testalloc(long size, char *ptrname, char **ptr) {
|
||||
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
|
||||
*ptr = mymalloc(size);
|
||||
|
||||
if(*ptr == NULL)
|
||||
printf("Allocation failed.\n");
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
void testfree(char *ptr, char *ptrname) {
|
||||
printf("\nFreeing %s\n", ptrname);
|
||||
myfree(ptr);
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
int main() {
|
||||
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
testalloc(2048, "ptr1", &ptr1);
|
||||
testalloc(6144, "ptr2", &ptr2);
|
||||
testalloc(1024, "ptr3", &ptr3);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(2048, "ptr2", &ptr2);
|
||||
testalloc(4096, "ptr4", &ptr4);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(3072, "ptr5", &ptr5);
|
||||
testfree(ptr1, "ptr1");
|
||||
testfree(ptr2, "ptr2");
|
||||
testfree(ptr3, "ptr3");
|
||||
testfree(ptr4, "ptr4");
|
||||
testfree(ptr5, "ptr5");
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user