refactor
This commit is contained in:
parent
7c888a3dd0
commit
5d9fc7d18d
11 changed files with 247 additions and 297 deletions
21
README.md
Normal file
21
README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
```
|
||||
// Generates a random.txt file with parameters specified, and exits
|
||||
// parameters besides N, are only used internally to specify how big are the chunks written
|
||||
<main> -g -N 100000 -b 10 -n 101 -o <filename>
|
||||
|
||||
// Sort the input file, using the temporary dir, and the parameters specified, save to the output file
|
||||
<main> -i <input-file> -o <output-file> -d <tmp dir> -N 100000 -b 10 -n 101
|
||||
|
||||
// If no option is specified, system will prompt for parameters, and use the input data from stdin
|
||||
<main>
|
||||
```
|
||||
|
||||
- option `-i` implies the program is supposed to sort something, and thus is incompatible with `-g`
|
||||
- when a parameter is not specified the default values are used:
|
||||
- i = "1.in"
|
||||
- o = "1.out"
|
||||
- d = "tmp"
|
||||
- g isn't set (false)
|
||||
- N = 100000
|
||||
- b = 10
|
||||
- n = 101
|
||||
43
buffer.c
Normal file
43
buffer.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#include "buffer.h"
|
||||
#include "record.h"
|
||||
#include "status_codes.h"
|
||||
|
||||
buffer create_buffer(int capacity)
|
||||
{
|
||||
buffer out;
|
||||
out.length = 0;
|
||||
out.capacity = capacity;
|
||||
out.location = malloc(sizeof(record) * capacity);
|
||||
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;
|
||||
}
|
||||
12
buffer.h
Normal file
12
buffer.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include "record.h"
|
||||
|
||||
typedef struct {
|
||||
record* location;
|
||||
int length;
|
||||
int capacity;
|
||||
} buffer;
|
||||
|
||||
buffer create_buffer(int capacity);
|
||||
int read_buffer(buffer* buff, FILE* in);
|
||||
int write_buffer(buffer* buff, FILE* in);
|
||||
52
config.c
Normal file
52
config.c
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#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
Normal file
23
config.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#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);
|
||||
221
main.c
221
main.c
|
|
@ -1,167 +1,62 @@
|
|||
#include "buffer.h"
|
||||
#include "config.h"
|
||||
#include "record.h"
|
||||
#include "tape.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "status_codes.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DEFAULT_FILE "tests/1.in"
|
||||
#define DEFAULT_DIR "tmp"
|
||||
#define DEFAULT_NN 100000
|
||||
#define DEFAULT_N 101
|
||||
#define DEFAULT_B 10
|
||||
#define END_PROGRAM -1
|
||||
#define SUCCESS 0
|
||||
#define ERROR -2
|
||||
|
||||
void print_usage()
|
||||
int generate_file(int N, const char* filename)
|
||||
{
|
||||
printf("Options:\n");
|
||||
printf(" -f [filename]\tRead/Generate records from [filename], default %s\n", DEFAULT_FILE);
|
||||
printf(" -d [dirname]\tSet the directory used for temporary files, default %s\n", DEFAULT_DIR);
|
||||
printf(" -N [count]\tSet total number of records, default %d\n", DEFAULT_NN);
|
||||
printf(" -n [count]\tSet blocking factor, default %d\n", DEFAULT_N);
|
||||
printf(" -b [count]\tSet number of buffers, default %d\n", DEFAULT_B);
|
||||
printf(" -r\t randomly generate N records\n");
|
||||
printf(" -h\tShow this help message\n");
|
||||
}
|
||||
srand(time(0));
|
||||
FILE* f = fopen(filename, "w");
|
||||
record rec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FILE* input;
|
||||
char* filename;
|
||||
char* dirname;
|
||||
bool generate_data;
|
||||
bool manual_input;
|
||||
int N; // number of records in a file
|
||||
int b; // blocking factor
|
||||
int n; // number of buffers
|
||||
} options;
|
||||
|
||||
// reads args into opts
|
||||
int process_args(int argc, char** argv, options* opts)
|
||||
{
|
||||
if (opts == NULL) {
|
||||
return ERROR;
|
||||
}
|
||||
opts->input = stdin;
|
||||
opts->filename = DEFAULT_FILE;
|
||||
opts->dirname = DEFAULT_DIR;
|
||||
opts->generate_data = false;
|
||||
opts->manual_input = false;
|
||||
opts->N = DEFAULT_NN;
|
||||
opts->n = DEFAULT_N;
|
||||
opts->b = DEFAULT_B;
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "f:d:N:n:b:rhm")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
opts->filename = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
opts->dirname = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
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 'm':
|
||||
opts->manual_input = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
return END_PROGRAM;
|
||||
case '?':
|
||||
fprintf(stderr, "invalid option, terminating\n");
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
if (opts->manual_input == true && opts->generate_data == true) {
|
||||
fprintf(stderr, "Incompatible arguments: mr, aborting\n");
|
||||
return ERROR;
|
||||
}
|
||||
opts->input = fopen(opts->filename, "r+");
|
||||
if (!opts->input) {
|
||||
opts->input = fopen(opts->filename, "w+");
|
||||
}
|
||||
if (!opts->input) {
|
||||
fprintf(stderr, "Error: Cannot open file '%s'\n", opts->filename);
|
||||
return ERROR;
|
||||
}
|
||||
struct stat st = { 0 };
|
||||
if (stat(opts->dirname, &st) == -1) {
|
||||
mkdir(opts->dirname, 0777);
|
||||
for (int i = 0; i < N; i++) {
|
||||
random_record(&rec);
|
||||
print_record(f, &rec);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void generate_file(options* opts)
|
||||
int sort_file(Configuration* opts)
|
||||
{
|
||||
srand(time(0));
|
||||
record rec;
|
||||
for (int i = 0; i < opts->N; i++) {
|
||||
random_record(&rec);
|
||||
print_record(opts->input, &rec);
|
||||
fprintf(opts->input, "\n");
|
||||
}
|
||||
fseek(opts->input, 0, SEEK_SET);
|
||||
}
|
||||
// create buffer
|
||||
buffer buff = create_buffer(opts->b * opts->n);
|
||||
// open file
|
||||
FILE* in = fopen(opts->input_file, "r");
|
||||
// <stage 1>
|
||||
// while !eof:
|
||||
for (int i = 0; true; i++) {
|
||||
// read buffer
|
||||
int status = read_buffer(&buff, in);
|
||||
printf("buffer i:%d, status: %d\n", i, status);
|
||||
// sort buffer
|
||||
|
||||
void write_file(options* 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;
|
||||
// write run
|
||||
write_buffer(&buff, stdout);
|
||||
if (status != SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// <stage 2>
|
||||
// while tmp:
|
||||
// merge b-1 runs
|
||||
//
|
||||
// close file
|
||||
// free buffer
|
||||
fclose(in);
|
||||
free(buff.location);
|
||||
fclose(a.file);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
options opts;
|
||||
Configuration opts;
|
||||
if (argc <= 1) {
|
||||
// #todo: stdin input
|
||||
fprintf(stderr, "please specify input args\n");
|
||||
return ERROR;
|
||||
}
|
||||
|
|
@ -170,12 +65,42 @@ int main(int argc, char** argv)
|
|||
return result;
|
||||
}
|
||||
if (opts.generate_data) {
|
||||
generate_file(&opts);
|
||||
return SUCCESS;
|
||||
}
|
||||
if (opts.manual_input) {
|
||||
write_file(&opts);
|
||||
return generate_file(opts.N, opts.output_file);
|
||||
}
|
||||
sort_file(&opts);
|
||||
fclose(opts.input);
|
||||
}
|
||||
// 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;
|
||||
// }
|
||||
|
|
|
|||
29
makefile
29
makefile
|
|
@ -1,30 +1,33 @@
|
|||
CFLAGS = -g
|
||||
|
||||
build/main: build/main.o build/tape.o build
|
||||
clang $(CFLAGS) build/main.o build/tape.o -o build/main
|
||||
build/main: build/main.o build/config.o build/buffer.o
|
||||
clang $(CFLAGS) build/main.o build/config.o build/buffer.o -o build/main
|
||||
|
||||
build/main.o: main.c build
|
||||
clang $(CFLAGS) -c main.c -o build/main.o
|
||||
|
||||
build/tape.o: tape.c build
|
||||
clang $(CFLAGS) -c tape.c -o build/tape.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:
|
||||
mkdir -p build
|
||||
|
||||
tests:
|
||||
mkdir -p tests
|
||||
build/run: build
|
||||
mkdir -p build/run
|
||||
|
||||
clean:
|
||||
rm -rf build tests tmp
|
||||
rm -rf build
|
||||
|
||||
run: build/main tests/1.in
|
||||
build/main -f tests/1.in | less
|
||||
build/run/1.in: build/run build/main
|
||||
build/main -g -o build/run/1.in
|
||||
|
||||
run: build/main build/run/1.in
|
||||
build/main -i build/run/1.in | less
|
||||
|
||||
debug: build/main tests/1.in
|
||||
lldb -- build/main -f tests/1.in
|
||||
|
||||
tests/1.in: build/main tests
|
||||
build/main -f tests/1.in -r
|
||||
lldb -- build/main
|
||||
|
||||
.PHONY: clean run debug
|
||||
|
|
|
|||
4
record.h
4
record.h
|
|
@ -28,9 +28,9 @@ static inline int compare_records(const void* a, const void* b)
|
|||
return result;
|
||||
}
|
||||
|
||||
static inline void print_record(FILE* stream, const record* out)
|
||||
static inline int print_record(FILE* stream, const record* out)
|
||||
{
|
||||
fprintf(stream, "%d %d %d %d %d %d",
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
5
status_codes.h
Normal file
5
status_codes.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#define END_PROGRAM -1
|
||||
#define SUCCESS 0
|
||||
#define ERROR -2
|
||||
108
tape.c
108
tape.c
|
|
@ -1,108 +0,0 @@
|
|||
#include "record.h"
|
||||
#include "tape.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int read_buffer(buffer* buff, tape* tape)
|
||||
{
|
||||
int status;
|
||||
record* destination = buff->location;
|
||||
buff->length = 0;
|
||||
while (buff->capacity > buff->length) {
|
||||
status = read_record(tape->file, destination);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
destination++;
|
||||
buff->length++;
|
||||
tape->reads++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_full_buffer(buffer* buff)
|
||||
{
|
||||
for (int i = 0; i < buff->length; i++) {
|
||||
record* current = buff->location;
|
||||
current += i;
|
||||
printf("i: %d\tg: %d\t", i, g(current));
|
||||
print_record(stdout, current);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void print_buffer(buffer* buff)
|
||||
{
|
||||
if (buff->length <= 10) {
|
||||
print_full_buffer(buff);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
record* current = buff->location;
|
||||
current += i;
|
||||
printf("i: %d\tg: %d\t", i, g(current));
|
||||
print_record(stdout, current);
|
||||
printf("\n");
|
||||
}
|
||||
for (int i = buff->length - 5; i < buff->length; i++) {
|
||||
record* current = buff->location;
|
||||
current += i;
|
||||
printf("i: %d\tg: %d\t", i, g(current));
|
||||
print_record(stdout, current);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int write_buffer(buffer* buff, tape* tape)
|
||||
{
|
||||
record* current = buff->location;
|
||||
record* last = current;
|
||||
last += buff->length;
|
||||
while (current < last) {
|
||||
print_record(tape->file, current);
|
||||
fprintf(tape->file, "\n");
|
||||
current++;
|
||||
tape->reads++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
26
tape.h
26
tape.h
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
int reads;
|
||||
int writes;
|
||||
FILE* file;
|
||||
} tape;
|
||||
|
||||
typedef struct {
|
||||
void* location;
|
||||
int length;
|
||||
int capacity;
|
||||
} buffer;
|
||||
|
||||
// sorts the entire buffer
|
||||
void sort_buffer(buffer* buff);
|
||||
|
||||
// reads [capacity] records
|
||||
int read_buffer(buffer* buff, tape* tape);
|
||||
// writes everything
|
||||
int write_buffer(buffer* buff, tape* tape);
|
||||
// for debugging
|
||||
void print_buffer(buffer* buff);
|
||||
|
||||
void clear_tape(tape* tape);
|
||||
Loading…
Add table
Add a link
Reference in a new issue