icfp15/io.cpp

92 lines
1.9 KiB
C++

#include "io.h"
#include <algorithm>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct IOBlock {
IOBlock *next;
ssize_t used, size;
unsigned char data[];
};
IOBlock* newIOBlock() {
const ssize_t amount = 512*1024; // avoid fragmentation: 128kb is the standard M_MMAP_THRESHOLD
IOBlock* b = (IOBlock*) malloc(amount);
if (!b) abort();
b->size = amount - sizeof(*b);
b->used = 0;
b->next = NULL;
return b;
}
// frees block list
static void blocksToVector(IOBlock *blocks, ssize_t total, std::vector<unsigned char> &buf) {
buf.reserve(std::max<ssize_t>(total+1, 512*1024)); // try forcing mmap
buf.resize(total);
(&buf.at(0))[total] = '\0';
ssize_t pos = 0;
IOBlock *prev = 0;
for (IOBlock *cur = blocks; cur; prev = cur, cur = cur->next) {
free(prev);
if (cur->used > 0) {
memcpy(&buf.at(pos), cur->data, cur->used);
pos += cur->used;
}
}
free(prev);
}
void readAll(int fd, std::vector<unsigned char> &buf) {
IOBlock *first = newIOBlock();
IOBlock *cur = first;
ssize_t total = 0;
for (;;) {
ssize_t avail;
for (;;) {
avail = cur->size - cur->used;
if (0 != avail) break;
cur->next = newIOBlock();
cur = cur->next;
}
ssize_t len = read(fd, cur->data + cur->used, avail);
if (0 == len) break; /* eof */
if (0 > len) {
perror("read failed");
abort();
}
cur->used += len;
total += len;
}
blocksToVector(first, total, buf);
}
void readLine(int fd, std::vector<unsigned char> &buf) {
IOBlock *first = newIOBlock();
IOBlock *cur = first;
ssize_t total = 0;
for (;;) {
if (cur->size == cur->used) {
cur->next = newIOBlock();
cur = cur->next;
}
ssize_t len = read(fd, cur->data + cur->used, 1);
if (0 == len) break; /* eof */
if (0 > len) {
perror("read failed");
abort();
}
if (cur->data[cur->used] == '\n' || cur->data[cur->used] == '\r') break;
cur->used += 1;
total += 1;
}
blocksToVector(first, total, buf);
}