initial
This commit is contained in:
parent
758f733c84
commit
69bc9646e4
11 changed files with 6 additions and 830 deletions
129
buffer.c
129
buffer.c
|
|
@ -1,129 +0,0 @@
|
||||||
#include "buffer.h"
|
|
||||||
#include "record.h"
|
|
||||||
#include "status_codes.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
buffer* create_buffer(int capacity)
|
|
||||||
{
|
|
||||||
buffer* out = malloc(sizeof(buffer));
|
|
||||||
out->length = 0;
|
|
||||||
out->capacity = capacity;
|
|
||||||
out->location = malloc(sizeof(record) * capacity);
|
|
||||||
out->original = true;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_buffer(buffer* buff)
|
|
||||||
{
|
|
||||||
if (buff->original) {
|
|
||||||
free(buff->location);
|
|
||||||
}
|
|
||||||
free(buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer** split_buffer(buffer* original, int pieces)
|
|
||||||
{
|
|
||||||
int size = original->capacity;
|
|
||||||
if (size <= 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
buffer** out = malloc(sizeof(buffer) * pieces);
|
|
||||||
for (int i = 0; i < pieces; i++) {
|
|
||||||
out[i]->length = 0;
|
|
||||||
out[i]->capacity = size;
|
|
||||||
out[i]->original = 0;
|
|
||||||
out[i]->location = original->location;
|
|
||||||
out[i]->location += i * size * sizeof(record);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int read_buffer(buffer* buff, FILE* in)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
record* current = buff->location;
|
|
||||||
buff->length = 0;
|
|
||||||
for (int i = 0; i < buff->capacity; i++) {
|
|
||||||
status = read_record(in, current);
|
|
||||||
if (status != SUCCESS) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
buff->length++;
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_buffer(buffer* buff, FILE* out)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
record* current = buff->location;
|
|
||||||
for (int i = 0; i < buff->length; i++) {
|
|
||||||
status = print_record(out, current);
|
|
||||||
if (status < 0) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_buffer_debug(buffer* buff, FILE* out)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
record* current = buff->location;
|
|
||||||
for (int i = 0; i < buff->length; i++) {
|
|
||||||
fprintf(out, "%d\t", g(current));
|
|
||||||
status = print_record(out, current);
|
|
||||||
if (status < 0) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int partition(record* arr, int start, int end)
|
|
||||||
{
|
|
||||||
int i = start;
|
|
||||||
record* pivot = arr;
|
|
||||||
pivot += end;
|
|
||||||
for (int j = start; j < end; j++) {
|
|
||||||
record* current = arr;
|
|
||||||
current += j;
|
|
||||||
if (compare_records(current, pivot) > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
record* i_rec = arr;
|
|
||||||
i_rec += i;
|
|
||||||
record tmp = *i_rec;
|
|
||||||
*i_rec = *current;
|
|
||||||
*current = tmp;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
record* i_rec = arr;
|
|
||||||
i_rec += i;
|
|
||||||
record tmp = *i_rec;
|
|
||||||
*i_rec = *pivot;
|
|
||||||
*pivot = tmp;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
void quicksort(record* arr, int start, int end, int depth)
|
|
||||||
{
|
|
||||||
if (start >= end || start < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int p = partition(arr, start, end);
|
|
||||||
quicksort(arr, start, p - 1, depth + 1);
|
|
||||||
quicksort(arr, p + 1, end, depth + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sort_buffer(buffer* buff)
|
|
||||||
{
|
|
||||||
quicksort(buff->location, 0, buff->length - 1, 0);
|
|
||||||
}
|
|
||||||
19
buffer.h
19
buffer.h
|
|
@ -1,19 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "record.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
record* location;
|
|
||||||
int length;
|
|
||||||
int capacity;
|
|
||||||
bool original;
|
|
||||||
} buffer;
|
|
||||||
|
|
||||||
buffer* create_buffer(int capacity);
|
|
||||||
void destroy_buffer(buffer* buff);
|
|
||||||
buffer** split_buffer(buffer* original, int pieces);
|
|
||||||
|
|
||||||
int read_buffer(buffer* buff, FILE* in);
|
|
||||||
int write_buffer(buffer* buff, FILE* in);
|
|
||||||
int write_buffer_debug(buffer* buff, FILE* in);
|
|
||||||
void sort_buffer(buffer* buff);
|
|
||||||
52
config.c
52
config.c
|
|
@ -1,52 +0,0 @@
|
||||||
#include "config.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int process_args(int argc, char** argv, Configuration* opts)
|
|
||||||
{
|
|
||||||
opts->input_file = DEFAULT_IN;
|
|
||||||
opts->output_file = DEFAULT_OUT;
|
|
||||||
opts->directory = DEFAULT_DIR;
|
|
||||||
opts->generate_data = false;
|
|
||||||
opts->N = DEFAULT_NN;
|
|
||||||
opts->n = DEFAULT_N;
|
|
||||||
opts->b = DEFAULT_B;
|
|
||||||
int opt;
|
|
||||||
bool input_set = false;
|
|
||||||
while ((opt = getopt(argc, argv, "i:o:d:gN:n:b:")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 'i':
|
|
||||||
opts->input_file = optarg;
|
|
||||||
input_set = true;
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
opts->output_file = optarg;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
opts->directory = optarg;
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
opts->generate_data = true;
|
|
||||||
break;
|
|
||||||
case 'N':
|
|
||||||
opts->N = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
opts->n = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
opts->b = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
printf("wrong argument\n");
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opts->generate_data && input_set) {
|
|
||||||
printf("incompatible arguments\n");
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
23
config.h
23
config.h
|
|
@ -1,23 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "status_codes.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#define DEFAULT_IN "1.in"
|
|
||||||
#define DEFAULT_OUT "1.in"
|
|
||||||
#define DEFAULT_DIR "tmp"
|
|
||||||
#define DEFAULT_NN 100000
|
|
||||||
#define DEFAULT_N 101
|
|
||||||
#define DEFAULT_B 10
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
const char* input_file;
|
|
||||||
const char* output_file;
|
|
||||||
const char* directory;
|
|
||||||
bool generate_data;
|
|
||||||
int N; // number of records in a file
|
|
||||||
int b; // blocking factor
|
|
||||||
int n; // number of buffers
|
|
||||||
} Configuration;
|
|
||||||
|
|
||||||
int process_args(int argc, char** argv, Configuration* opts);
|
|
||||||
78
heap.c
78
heap.c
|
|
@ -1,78 +0,0 @@
|
||||||
#include "heap.h"
|
|
||||||
#include "status_codes.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
heap* create_heap(int size, int (*comparison)(const void* a, const void* b))
|
|
||||||
{
|
|
||||||
heap* out = malloc(sizeof(heap));
|
|
||||||
out->data = malloc(sizeof(void*) * size);
|
|
||||||
out->length = 0;
|
|
||||||
out->capacity = size;
|
|
||||||
out->compare = comparison;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_heap(heap* h)
|
|
||||||
{
|
|
||||||
free(h->data);
|
|
||||||
free(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap(void** a, void** b)
|
|
||||||
{
|
|
||||||
void* tmp = *a;
|
|
||||||
*a = *b;
|
|
||||||
*b = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
int heap_push(heap* h, void* in)
|
|
||||||
{
|
|
||||||
int current = h->length;
|
|
||||||
void** d = h->data;
|
|
||||||
h->length++;
|
|
||||||
d[current] = in;
|
|
||||||
if (current == 0) {
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
int parent = (current - 1) / 2;
|
|
||||||
while (h->compare(d[current], d[parent]) == -1) {
|
|
||||||
swap(&d[current], &d[parent]);
|
|
||||||
current = parent;
|
|
||||||
if (current == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
parent = (current - 1) / 2;
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int heap_pop(heap* h, void** out)
|
|
||||||
{
|
|
||||||
void** d = h->data;
|
|
||||||
*out = d[0];
|
|
||||||
h->length--;
|
|
||||||
if (h->length == 0) {
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
swap(&d[0], &d[h->length]);
|
|
||||||
int current = 0;
|
|
||||||
int left = current * 2 + 1;
|
|
||||||
int right = current * 2 + 2;
|
|
||||||
while (true) {
|
|
||||||
int smallest = current;
|
|
||||||
if (left < h->length && h->compare(d[smallest], d[left]) == 1) {
|
|
||||||
smallest = left;
|
|
||||||
}
|
|
||||||
if (right < h->length && h->compare(d[smallest], d[right]) == 1) {
|
|
||||||
smallest = right;
|
|
||||||
}
|
|
||||||
if (smallest == current) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
swap(&d[smallest], &d[current]);
|
|
||||||
current = smallest;
|
|
||||||
left = current * 2 + 1;
|
|
||||||
right = current * 2 + 2;
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
19
heap.h
19
heap.h
|
|
@ -1,19 +0,0 @@
|
||||||
// doesn't ceck for user erros, so no veryfying that the void* supplied are valid
|
|
||||||
// unsafe for general use, but just fnuctional enough for the purposes of this project
|
|
||||||
// does not maintain ownership of its elements, they are managed by the caller
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "stdbool.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void** data;
|
|
||||||
int length;
|
|
||||||
int capacity;
|
|
||||||
int (*compare)(const void* a, const void* b);
|
|
||||||
} heap;
|
|
||||||
|
|
||||||
heap* create_heap(int size, int (*comparison)(const void* a, const void* b));
|
|
||||||
void destroy_heap(heap* h);
|
|
||||||
|
|
||||||
int heap_pop(heap* h, void** out);
|
|
||||||
int heap_push(heap* h, void* in);
|
|
||||||
302
heap_test.c
302
heap_test.c
|
|
@ -1,302 +0,0 @@
|
||||||
// the tests are ai generated, with prompt based on the heap.h file
|
|
||||||
#include "heap.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
// Comparator for integers
|
|
||||||
int compare_ints(const void* a, const void* b)
|
|
||||||
{
|
|
||||||
int ia = *(const int*)a;
|
|
||||||
int ib = *(const int*)b;
|
|
||||||
return (ia > ib) - (ia < ib);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparator for doubles
|
|
||||||
int compare_doubles(const void* a, const void* b)
|
|
||||||
{
|
|
||||||
double da = *(const double*)a;
|
|
||||||
double db = *(const double*)b;
|
|
||||||
if (da < db)
|
|
||||||
return -1;
|
|
||||||
if (da > db)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test structure
|
|
||||||
typedef struct {
|
|
||||||
int priority;
|
|
||||||
char name[32];
|
|
||||||
} Task;
|
|
||||||
|
|
||||||
// Comparator for tasks (by priority)
|
|
||||||
int compare_tasks(const void* a, const void* b)
|
|
||||||
{
|
|
||||||
const Task* ta = (const Task*)a;
|
|
||||||
const Task* tb = (const Task*)b;
|
|
||||||
return (ta->priority > tb->priority) - (ta->priority < tb->priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_basic_push_pop()
|
|
||||||
{
|
|
||||||
printf("Test: Basic push and pop... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(5, compare_ints);
|
|
||||||
int values[] = { 5, 3, 7, 1, 9 };
|
|
||||||
|
|
||||||
// Push all values
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_push(h, &values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop and verify they come out in sorted order
|
|
||||||
void* out;
|
|
||||||
int expected[] = { 1, 3, 5, 7, 9 };
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == expected[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_single_element()
|
|
||||||
{
|
|
||||||
printf("Test: Single element... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(1, compare_ints);
|
|
||||||
int val = 42;
|
|
||||||
|
|
||||||
heap_push(h, &val);
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == 42);
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_already_sorted()
|
|
||||||
{
|
|
||||||
printf("Test: Already sorted input... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(5, compare_ints);
|
|
||||||
int values[] = { 1, 2, 3, 4, 5 };
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_push(h, &values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_reverse_sorted()
|
|
||||||
{
|
|
||||||
printf("Test: Reverse sorted input... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(5, compare_ints);
|
|
||||||
int values[] = { 5, 4, 3, 2, 1 };
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_push(h, &values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_duplicates()
|
|
||||||
{
|
|
||||||
printf("Test: Duplicate values... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(7, compare_ints);
|
|
||||||
int values[] = { 3, 1, 4, 1, 5, 9, 2 };
|
|
||||||
|
|
||||||
for (int i = 0; i < 7; i++) {
|
|
||||||
heap_push(h, &values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
int expected[] = { 1, 1, 2, 3, 4, 5, 9 };
|
|
||||||
for (int i = 0; i < 7; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == expected[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_with_doubles()
|
|
||||||
{
|
|
||||||
printf("Test: Double precision values... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(5, compare_doubles);
|
|
||||||
double values[] = { 3.14, 1.41, 2.71, 0.57, 1.61 };
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_push(h, &values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
double expected[] = { 0.57, 1.41, 1.61, 2.71, 3.14 };
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(double*)out == expected[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_with_structs()
|
|
||||||
{
|
|
||||||
printf("Test: Custom struct (tasks by priority)... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(4, compare_tasks);
|
|
||||||
Task tasks[] = {
|
|
||||||
{ 3, "Low priority" },
|
|
||||||
{ 1, "High priority" },
|
|
||||||
{ 2, "Medium priority" },
|
|
||||||
{ 1, "Also high priority" }
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
heap_push(h, &tasks[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
int expected_priorities[] = { 1, 1, 2, 3 };
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
Task* t = (Task*)out;
|
|
||||||
assert(t->priority == expected_priorities[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_interleaved_operations()
|
|
||||||
{
|
|
||||||
printf("Test: Interleaved push/pop... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(10, compare_ints);
|
|
||||||
int values[] = { 5, 3, 7, 1, 9, 2, 8, 4, 6, 0 };
|
|
||||||
|
|
||||||
// Push 5, pop 1, push 3 more, pop 2, etc.
|
|
||||||
heap_push(h, &values[0]); // 5
|
|
||||||
heap_push(h, &values[1]); // 3
|
|
||||||
heap_push(h, &values[2]); // 7
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == 3);
|
|
||||||
|
|
||||||
heap_push(h, &values[3]); // 1
|
|
||||||
heap_push(h, &values[4]); // 9
|
|
||||||
heap_push(h, &values[5]); // 2
|
|
||||||
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == 1);
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == 2);
|
|
||||||
|
|
||||||
heap_push(h, &values[6]); // 8
|
|
||||||
heap_push(h, &values[7]); // 4
|
|
||||||
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == 4);
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_large_heap()
|
|
||||||
{
|
|
||||||
printf("Test: Large heap (1000 elements)... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(1000, compare_ints);
|
|
||||||
int* values = malloc(1000 * sizeof(int));
|
|
||||||
|
|
||||||
// Insert values in random-ish order
|
|
||||||
for (int i = 0; i < 1000; i++) {
|
|
||||||
values[i] = (i * 7 + 13) % 1000;
|
|
||||||
heap_push(h, &values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop all and verify sorted
|
|
||||||
void* out;
|
|
||||||
int prev = -1;
|
|
||||||
for (int i = 0; i < 1000; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
int curr = *(int*)out;
|
|
||||||
assert(curr >= prev);
|
|
||||||
prev = curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(values);
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_all_same_values()
|
|
||||||
{
|
|
||||||
printf("Test: All same values... ");
|
|
||||||
|
|
||||||
heap* h = create_heap(5, compare_ints);
|
|
||||||
int val = 42;
|
|
||||||
int values[5];
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
values[i] = val;
|
|
||||||
heap_push(h, &values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* out;
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
heap_pop(h, &out);
|
|
||||||
assert(*(int*)out == 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy_heap(h);
|
|
||||||
printf("PASSED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
printf("Running Min Heap Tests\n");
|
|
||||||
printf("======================\n\n");
|
|
||||||
|
|
||||||
test_basic_push_pop();
|
|
||||||
test_single_element();
|
|
||||||
test_already_sorted();
|
|
||||||
test_reverse_sorted();
|
|
||||||
test_duplicates();
|
|
||||||
test_with_doubles();
|
|
||||||
test_with_structs();
|
|
||||||
test_interleaved_operations();
|
|
||||||
test_large_heap();
|
|
||||||
test_all_same_values();
|
|
||||||
|
|
||||||
printf("\n======================\n");
|
|
||||||
printf("All tests PASSED! ✓\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
120
main.c
120
main.c
|
|
@ -1,120 +0,0 @@
|
||||||
#include "buffer.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "record.h"
|
|
||||||
#include "status_codes.h"
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int generate_file(int N, const char* filename)
|
|
||||||
{
|
|
||||||
srand(time(0));
|
|
||||||
FILE* f = fopen(filename, "w");
|
|
||||||
record rec;
|
|
||||||
|
|
||||||
for (int i = 0; i < N; i++) {
|
|
||||||
random_record(&rec);
|
|
||||||
print_record(f, &rec);
|
|
||||||
fprintf(f, "\n");
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sort_file(Configuration* opts)
|
|
||||||
{
|
|
||||||
buffer* buff = create_buffer(opts->b * opts->n);
|
|
||||||
FILE* in = fopen(opts->input_file, "r");
|
|
||||||
int runs;
|
|
||||||
// <stage 1>
|
|
||||||
for (runs = 0; true; runs++) {
|
|
||||||
// read buffer
|
|
||||||
int status = read_buffer(buff, in);
|
|
||||||
if (status != SUCCESS && status != EOF) {
|
|
||||||
fclose(in);
|
|
||||||
destroy_buffer(buff);
|
|
||||||
}
|
|
||||||
// sort buffer
|
|
||||||
sort_buffer(buff);
|
|
||||||
// write run
|
|
||||||
char* filename = malloc(256);
|
|
||||||
sprintf(filename, "%s/%d", opts->directory, runs);
|
|
||||||
FILE* tmp = fopen(filename, "w");
|
|
||||||
write_buffer(buff, tmp);
|
|
||||||
// write_buffer_debug(buff, stdout);
|
|
||||||
fclose(tmp);
|
|
||||||
free(filename);
|
|
||||||
if (status != SUCCESS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("created runs: %d\n", runs);
|
|
||||||
|
|
||||||
// <stage 2>
|
|
||||||
while (runs > 1) {
|
|
||||||
|
|
||||||
// split buffers
|
|
||||||
// read buffers
|
|
||||||
for (int i = 0; i < opts->b - 1; i++) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// b-1 runs are turned into one, so the total is reduced by b-2
|
|
||||||
runs -= (opts->b - 2);
|
|
||||||
}
|
|
||||||
fclose(in);
|
|
||||||
destroy_buffer(buff);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
Configuration opts;
|
|
||||||
if (argc <= 1) {
|
|
||||||
// #todo: stdin input
|
|
||||||
fprintf(stderr, "please specify input args\n");
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
int result = process_args(argc, argv, &opts);
|
|
||||||
if (result != SUCCESS) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (opts.generate_data) {
|
|
||||||
return generate_file(opts.N, opts.output_file);
|
|
||||||
}
|
|
||||||
sort_file(&opts);
|
|
||||||
}
|
|
||||||
// int sort_block(tape* t, buffer* buff)
|
|
||||||
// {
|
|
||||||
// static int counter = 0;
|
|
||||||
// int status = read_buffer(buff, t);
|
|
||||||
// if (status != SUCCESS && status != EOF) {
|
|
||||||
// fprintf(stderr, "Error reading file: %d\n", status);
|
|
||||||
// return status;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// sort_buffer(buff);
|
|
||||||
// printf("sorted the buffer %d, the results:\n", counter);
|
|
||||||
// print_buffer(buff);
|
|
||||||
// counter++;
|
|
||||||
// return status;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// int sort_file(options* opts)
|
|
||||||
// {
|
|
||||||
// tape a = { 0, 0, opts->input };
|
|
||||||
// buffer buff;
|
|
||||||
// buff.capacity = opts->b * opts->n;
|
|
||||||
// buff.location = malloc(sizeof(record) * buff.capacity);
|
|
||||||
// int status = 0;
|
|
||||||
// while (status == SUCCESS) {
|
|
||||||
// status = sort_block(&a, &buff);
|
|
||||||
// }
|
|
||||||
// if (status != EOF) {
|
|
||||||
// free(buff.location);
|
|
||||||
// fclose(a.file);
|
|
||||||
// return status;
|
|
||||||
// }
|
|
||||||
// free(buff.location);
|
|
||||||
// fclose(a.file);
|
|
||||||
// return SUCCESS;
|
|
||||||
// }
|
|
||||||
31
makefile
31
makefile
|
|
@ -1,19 +1,7 @@
|
||||||
CFLAGS = -g
|
CFLAGS = -g -lc++
|
||||||
|
|
||||||
build/main: build/main.o build/config.o build/buffer.o build/heap.o
|
build/main: main.cpp build
|
||||||
clang $(CFLAGS) build/main.o build/config.o build/buffer.o build/heap.o -o build/main
|
clang $(CFLAGS) main.cpp -o build/main
|
||||||
|
|
||||||
build/main.o: main.c build
|
|
||||||
clang $(CFLAGS) -c main.c -o build/main.o
|
|
||||||
|
|
||||||
build/config.o: config.c build
|
|
||||||
clang $(CFLAGS) -c config.c -o build/config.o
|
|
||||||
|
|
||||||
build/buffer.o: buffer.c build
|
|
||||||
clang $(CFLAGS) -c buffer.c -o build/buffer.o
|
|
||||||
|
|
||||||
build/heap.o: heap.c build
|
|
||||||
clang $(CFLAGS) -c heap.c -o build/heap.o
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
|
|
@ -27,22 +15,15 @@ build/run/tmp: build/run
|
||||||
clean:
|
clean:
|
||||||
rm -rf build
|
rm -rf build
|
||||||
|
|
||||||
|
generate: build/run/1.in
|
||||||
|
|
||||||
build/run/1.in: build/run build/main
|
build/run/1.in: build/run build/main
|
||||||
build/main -g -o build/run/1.in
|
build/main -g -o build/run/1.in
|
||||||
|
|
||||||
run: build/main build/run/1.in build/run/tmp
|
run: build/main build/run/1.in build/run/tmp
|
||||||
build/main -i build/run/1.in -d build/run/tmp | less
|
build/main -i build/run/1.in -d build/run/tmp | less
|
||||||
|
|
||||||
build/heap_test.o: heap_test.c build
|
|
||||||
clang $(CFLAGS) -c heap_test.c -o build/heap_test.o
|
|
||||||
|
|
||||||
build/test: build/heap_test.o build/heap.o
|
|
||||||
clang $(CFLAGS) build/heap_test.o build/heap.o -o build/test
|
|
||||||
|
|
||||||
test: build/test
|
|
||||||
build/test
|
|
||||||
|
|
||||||
debug: build/main tests/1.in
|
debug: build/main tests/1.in
|
||||||
lldb -- build/main
|
lldb -- build/main
|
||||||
|
|
||||||
.PHONY: clean run debug test
|
.PHONY: clean run debug test generate
|
||||||
|
|
|
||||||
57
record.h
57
record.h
|
|
@ -1,57 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int a[5];
|
|
||||||
int x;
|
|
||||||
} record;
|
|
||||||
|
|
||||||
static inline int g(const record* x)
|
|
||||||
{
|
|
||||||
int out = 0;
|
|
||||||
int x_n = 1;
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
out += x->a[i] * x_n;
|
|
||||||
x_n *= x->x;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int compare_records(const void* a, const void* b)
|
|
||||||
{
|
|
||||||
const record* ra = (const record*)a;
|
|
||||||
const record* rb = (const record*)b;
|
|
||||||
int ga = g(ra);
|
|
||||||
int gb = g(rb);
|
|
||||||
int result = (ga > gb) - (ga < gb);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int print_record(FILE* stream, const record* out)
|
|
||||||
{
|
|
||||||
return fprintf(stream, "%d %d %d %d %d %d",
|
|
||||||
out->a[0], out->a[1], out->a[2], out->a[3], out->a[4], out->x);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int read_record(FILE* stream, record* out)
|
|
||||||
{
|
|
||||||
record tmp;
|
|
||||||
int result = fscanf(stream, "%d %d %d %d %d %d", &tmp.a[0], &tmp.a[1], &tmp.a[2], &tmp.a[3], &tmp.a[4], &tmp.x);
|
|
||||||
if (result == 6) {
|
|
||||||
*out = tmp;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (result == EOF) {
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void random_record(record* out)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
out->a[i] = rand();
|
|
||||||
}
|
|
||||||
out->x = rand();
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define END_PROGRAM -1
|
|
||||||
#define SUCCESS 0
|
|
||||||
#define ERROR -2
|
|
||||||
#define NO_SPACE -3
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue