~pixelherodev/DSM-9

e01de2e38c206c9df6ca264677d06e777fc9ac4b — Noam Preil a day ago 33de1b5
remove v1
3 files changed, 5 insertions(+), 322 deletions(-)

M sm2.c
M util.c
M util.h
M sm2.c => sm2.c +5 -225
@@ 13,8 13,6 @@

#include <stdio.h>

/* v1 header; this should be removed as soon as v2 is finished */
#include "sm2.h"
/* v2 header */
#include "dsm9.h"



@@ 296,14 294,15 @@ dsm9cardback(dsm9deck *deck, uint32_t index)
{
	/* For this, it'd be more efficient to have id and front stored together - however, this also only uses *eight bytes*, so the effect on the cache is neglible */
	uint32_t start = deck->backs[index];
	uint32_t end = index + 1 != deck->cardnum ? deck->ids[index + 1] : deck->decklen;
	int notlast = index + 1 == deck->cardnum;
	uint32_t end = notlast ? deck->ids[index + 1] : deck->decklen;
	/* If card is invalid, or if the card is new and we cannot stream it, return NULL */
	if(start == (uint32_t)-1 || (start == 0 && !dsm9stream(deck, index)))
		return NULL;
	start = deck->backs[index];
	end = index + 1 != deck->cardnum ? deck->ids[index + 1] : deck->decklen;
	/* Delimiter is three bytes, and we don't want it */
	uint32_t size = end - start - 3;
	end = notlast ? deck->ids[index + 1] : deck->decklen;
	/* unlike name/front, back ends either at line ending or EOF */
	uint32_t size = end - start - (notlast ? 1 : 0);
	char *buf = malloc(size + 1);
	memcpy(buf, deck->deckbuf + start, size);
	buf[size] = 0;


@@ 392,222 391,3 @@ dsm9load(char *basepath, dsm9deck *deck)
	return 1;
}

void sm2_init(struct sm2_instance *instance){
	instance->cards = NULL;
	instance->delimiter = "@@@";
	instance->card_count = 0;
	instance->card_cap = 0;
}

void
card_init(struct sm2_card *card, char *path)
{
	card->field_count = 0;
	card->fields = NULL;
	card->next_due = 0;
	card->interval = 1;
	card->repetitions = 0;
	card->easiness = 2.5;
	card->path = path;
}

static struct sm2_card *sm2_find_card(struct sm2_instance *instance, char *id){
	for(unsigned long i = 0; i < instance->card_count; i += 1)
		if(strcmp(instance->cards[i].id, id) == 0)
 			return &instance->cards[i];
	return NULL;
}

static
struct sm2_card *appendcard(struct sm2_instance *instance)
{
	if(instance->card_count == instance->card_cap){
		instance->card_cap = instance->card_cap * 4 + 8;
		instance->cards = realloc(instance->cards, sizeof(struct sm2_card) * instance->card_cap);
		if(instance->cards == NULL){
			fputs("Out of memory\n", stderr);
			abort();
		}
	}
	instance->card_count += 1;
	return &instance->cards[instance->card_count - 1];
}

int sm2_load_deck(struct sm2_instance *instance, char *deck, int overwrite, char *path){
	char *line = strtok(deck, "\n");
	uint32_t oldcount = instance->card_count;
	struct sm2_card *card;
	while(line != 0){
		if(*line == '#'){
			line = strtok(NULL, "\n");
			continue;
		}
		char *delim = strstr(line, instance->delimiter);
		if(delim == NULL){
			if(overwrite){
				card = sm2_find_card(instance, line);
				if(card == NULL)
					card = appendcard(instance);
			}
			else
				card = appendcard(instance);
			card->id = line;
		} else {
			long len = delim - line;
			char *id = malloc(len + 1);
			strncpy(id, line, len);
			id[len] = 0;
			if(overwrite){
				card = sm2_find_card(instance, line);
				if(card == NULL)
					card = appendcard(instance);
			}
			else
				card = appendcard(instance);
			card->id = id;
		}

		card_init(card, path);

		if(delim == NULL){
			// Only field on the line is ID
			card->id = malloc(strlen(line) + 1);
			strcpy(card->id, line);
			line = strtok(NULL, "\n");
			continue;
		}

		line = delim + strlen(instance->delimiter);
		delim = strstr(line, instance->delimiter);

		while (delim != NULL){
			unsigned long len = delim - line;
			card->field_count += 1;
			card->fields = realloc(card->fields, card->field_count * sizeof(char*));
			card->fields[card->field_count - 1] = malloc(len + 1);
			strncpy(card->fields[card->field_count - 1], line, len);
			card->fields[card->field_count - 1][len] = 0;
			line += len + strlen(instance->delimiter);
			delim = strstr(line, instance->delimiter);
		}

		if(*line != 0){
			card->field_count += 1;
			card->fields = realloc(card->fields, card->field_count * sizeof(char*));
			card->fields[card->field_count - 1] = strdup(line);
		}
		line = strtok(NULL, "\n");
	}
	return instance->card_count - oldcount;
}

void
sm2_update_card(struct sm2_card *card, uint8_t grade, long timestamp)
{
	card->repetitions += 1;
	if(grade < 3){
		card->next_due = 0;
		card->interval = 1;
	} else {
		unsigned long orig_interval = card->interval;
		if(card->repetitions == 1)
			card->interval = 3;
		else if(card->repetitions == 2)
			card->interval = 6;
		else
			card->interval = card->easiness * card->interval;
		float g = grade;
		card->easiness = card->easiness - 0.8 + (0.28 * g) - (0.02 * g * g);
		if(card->easiness < 1.3)
			card->easiness = 1.3;
		card->next_due = (unsigned long)(((double)timestamp) + 60 * 60 * 24 * orig_interval * card->easiness);
	}
}

int sm2_load_logs(struct sm2_instance *instance, char *logs){
	char *line = strtok(logs, "\n");
	unsigned long l = 0;
	int count = 0;
	while(line != NULL){
		l += 1;
		char *delim = strstr(line, instance->delimiter);
		if(delim == NULL){
			fprintf(stderr, "expected three fields on line %lud\n", l);
			return -1;
		}
		long len = delim - line;
		char *id = malloc(len + 1);
		strncpy(id, line, len);
		id[len] = 0;
		line = delim + strlen(instance->delimiter);
		delim = strstr(line, instance->delimiter);
		if(delim == NULL){
			fprintf(stderr, "expected three fields on line %lud, found two", l);
			free(id);
			return -1;
		}
		len = delim - line;
		char *timestamp = malloc(len + 1);
		strncpy(timestamp, line, len);
		timestamp[len] = 0;
		if(strlen(delim+strlen(instance->delimiter)) != 1){
			fprintf(stderr, "grade must be a single digit");			
			free(id);
			free(timestamp);
			return -1;
		}
		uint8_t grade = *(delim + strlen(instance->delimiter)) - '0';
		if(grade > 5){
			fprintf(stderr,"grade must be a single digit between 0 and 5 (inclusive)");			
			free(id);
			free(timestamp);
			return -1;
		}
		struct sm2_card *card = sm2_find_card(instance, id);
		if(card == NULL){
			printf("card '%s' unknown, ignoring log entry...\n", id);
		} else{
			sm2_update_card(card, grade, atol(timestamp));
			count += 1;
		}
		line = strtok(NULL, "\n");
		free(id);
		free(timestamp);
	}
	return count;
}

void sm2_deinit(struct sm2_instance *instance){
	for (unsigned long i = 0; i < instance->card_count; i += 1){
		struct sm2_card *card = &instance->cards[i];	
		for (unsigned long j = 0; j < card->field_count; j += 1){
			free(card->fields[j]);
		}
		free(card->fields);
		free(card->id);
	}
	free(instance->cards);
}

int sm2_log(struct sm2_instance *instance, char *id, uint8_t grade, long timestamp){
	struct sm2_card *card = sm2_find_card(instance, id);
	if(card == NULL){
		fprintf(stderr, "Card not found: %s", id);
		return -1;
	}
	sm2_update_card(card, grade, timestamp);
	uint32_t len = strlen(card->path);
	char *path = malloc(len + 4 + 1);
	memcpy(path, card->path, len);
	strcpy(path + len, ".log");
	FILE *file = fopen(path, "a");
	free(path);
	if(file == NULL){
		fprintf(stderr, "Failed to open log for %s", card->path);
		return -1;
	}
	fprintf(file, "%s%s%lu%s%u\n", card->id, instance->delimiter, timestamp, instance->delimiter, grade);
	fflush(file);
	fclose(file);
	return 0;
}
\ No newline at end of file

M util.c => util.c +0 -94
@@ 20,8 20,6 @@ exit(int code)

#include <stdio.h>

#include "sm2.h"

char*
aprintf(char *fmt, ...)
{


@@ 72,98 70,6 @@ cleanup:
	return NULL;
}

// log == 1 ? log : deck
long
sm2_load(struct sm2_instance *instance, char *base_path, int log)
{
	long count;
	char *path;
#ifdef _PLAN9_SOURCE
	Biobuf *file;
#else
	FILE *file;
	size_t size = 0;
#endif
	char *line;

	path = aprintf("%s.%s", base_path, log == 1 ? "log" : "deck");
	if(path == NULL)
		return -1;
#ifdef _PLAN9_SOURCE
	file = Bopen(path, OREAD);
#else
	file = fopen(path, "r");
#endif
	free(path);
	if (file == NULL)
		return -1;

	count = 0;
#ifdef _PLAN9_SOURCE
	while((line = Brdstr(file, '\n', 1)) != NULL){
#else
	while(getline(&line, &size, file) != -1){
#endif
		switch(log == 1 ? sm2_load_logs(instance, line) : sm2_load_deck(instance, line, 0, base_path)){
			case -1:
				count = -1;
				break;
			case 1:
				count += 1;
				break;
		}
		if(count < 0)
			return -1;
	}

#ifdef _PLAN9_SOURCE
	Bterm(file);
#else
	fclose(file);
#endif
	return count;
}

struct sm2_card *
h_find_cards(struct sm2_instance *instance, uint32_t now, uint32_t *count)
{
	struct sm2_card card, *cards;
	unsigned long i, j, localcount;
	localcount = 0;
	cards = NULL;
	for(j = 0; j <= 1; j += 1){
		for(i = 0; i < instance->card_count; i += 1){
			card = instance->cards[i];
			if(card.id == NULL){
				fprintf(stderr,"Card is NULL!\n");
				abort();
			}
			if((j == 0 && card.next_due <= now && card.next_due != 0) || (j == 1 && card.next_due == 0)){
				localcount += 1;
				cards = realloc(cards, sizeof(struct sm2_card) * localcount);
				cards[localcount - 1] = card;
			}
		}
	}
	if(count != NULL)
		*count = localcount;
	return cards;
}

void
repetition_sort(struct sm2_card *cards, uint32_t count)
{
	uint32_t i, j;
	struct sm2_card card;
	for(i = 0; i < count; i += 1)
		for(j = i + 1; j < count; j += 1)
			if ((cards[j].repetitions < cards[i].repetitions && cards[j].repetitions != 0) || (cards[j].repetitions > 0 && cards[i].repetitions ==0)) {
				card = cards[i];
				cards[i] = cards[j];
				cards[j] = card;
			}
}

void
pin(int core)
{

M util.h => util.h +0 -3
@@ 1,8 1,5 @@
char* aprintf(char *fmt, ...);
double delta(void);
void repetition_sort(struct sm2_card *cards, uint32_t count);
struct sm2_card *h_find_cards(struct sm2_instance *instance, uint32_t now, uint32_t *count);
long sm2_load(struct sm2_instance *instance, char *base_path, int log);
void pin(int core);
char *readfile(char *path, size_t *size);
#ifdef _PLAN9_SOURCE