const std = @import("std");
const os = std.os;
const mem = std.mem;
const assert = std.debug.assert;
const stdout = std.io.getStdOut().writer();
fn extract_field(row: *[]u8, delim: u8) []u8 {
var p: u64 = 0;
while (p < row.len) {
defer p += 1;
if (row.*[p] == delim) {
const result = row.*[0..p];
row.* = row.*[p + 1 ..];
return result;
}
}
const result = row.*;
row.* = row.*[row.len..];
return result;
}
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const fd = try os.open("matricula.csv", os.O_RDONLY, 0);
defer os.close(fd);
try os.lseek_END(fd, 0);
const length = try os.lseek_CUR_get(fd);
const data = try os.mmap(
null,
length,
os.PROT_READ,
os.MAP_SHARED,
fd,
0,
);
defer os.munmap(data);
var input_stream = data;
var header = extract_field(&input_stream, '\n');
var column_count: u64 = 0;
{
var header_stream = header;
while (header_stream.len > 0) {
var field = extract_field(&header_stream, '|');
column_count += 1;
}
}
var columns = try arena.allocator.alloc([]u8, column_count);
{
var header_stream = header;
for (columns) |*column| {
column.* = extract_field(&header_stream, '|');
}
}
var column_lengths = try arena.allocator.alloc(u64, column_count);
{
var i: u64 = 0;
while (i < column_count) {
defer i += 1;
column_lengths[i] = 0;
}
}
var row_count: u64 = 0;
const data_range = input_stream;
{
while (input_stream.len > 0) {
const row = extract_field(&input_stream, '\n');
row_count += 1;
var row_stream = row;
for (column_lengths) |*column_length| {
const field = extract_field(&row_stream, '|');
column_length.* += field.len;
}
}
}
const output_fd = try os.open("matricula.transposed.csv", os.O_RDWR | os.O_CREAT | os.O_TRUNC, 0o644);
defer os.close(output_fd);
var output_length: u64 = 0;
var column_offsets = try arena.allocator.alloc(u64, column_count);
output_length += header.len;
output_length += 1;
{
var i: u64 = 0;
while (i < column_count) {
defer i += 1;
column_offsets[i] = output_length;
output_length += column_lengths[i] + (row_count - 1);
output_length += 1;
}
}
if ((try os.pwrite(output_fd, &[_]u8{0}, output_length - 1)) != 1) {
unreachable;
}
const output_data = try os.mmap(
null,
output_length,
os.PROT_READ | os.PROT_WRITE,
os.MAP_SHARED,
output_fd,
0,
);
defer os.munmap(output_data);
mem.copy(u8, output_data[0..], header);
output_data[header.len] = '\n';
var column_ranges = try arena.allocator.alloc([]u8, column_count);
{
var i: u64 = 0;
while (i < column_count) {
defer i += 1;
column_ranges[i] = output_data[column_offsets[i]..(column_offsets[i] + column_lengths[i] + row_count)];
}
}
{
input_stream = data_range;
while (input_stream.len > 0) {
const row = extract_field(&input_stream, '\n');
var row_stream = row;
for (column_ranges) |*column_range| {
const field = extract_field(&row_stream, '|');
mem.copy(u8, column_range.*, field);
column_range.* = column_range.*[field.len..];
column_range.*[0] = '|';
column_range.* = column_range.*[1..];
}
}
}
for (column_ranges) |*column_range, i| {
assert(column_ranges[i].len == 0);
output_data[column_offsets[i] + column_lengths[i] + (row_count - 1)] = '\n';
}
}
Comments