Input consuming.

It's possible that this commit contains errors, since I'm writing this
on a Windows machine and the compiler seems bad. I'll compile this in a
Linux machine and fix any errors present in the following commit.
This commit is contained in:
Miguel M 2023-04-21 17:06:12 +01:00
parent bc3125dcc8
commit fe3d00a5f5
3 changed files with 175 additions and 4 deletions

4
data/test_mat.txt Normal file
View File

@ -0,0 +1,4 @@
3
1 1 -1
555 0.9 +2
-55 2 1555

View File

@ -7,8 +7,9 @@ from sane import *
COMPILER = 'gcc'
COMPILE_FLAGS = ['-g',
'-Wall',
'--std=c99',
'-Wall',
'-Werror',
'-fopenmp']
LINK_FLAGS = []
OBJ_DIR = 'obj'

View File

@ -1,11 +1,177 @@
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>
#include <ctype.h>
#define STB_DS_IMPLEMENTATION
#include "../contrib/stb/stb_ds.h"
// #define STB_DS_IMPLEMENTATION
// #define STBDS_NO_SHORT_NAMES
// #include "../contrib/stb/stb_ds.h"
int main(int argc, char *argv[]) {
#define PRIgridDATA PRIiFAST32
typedef int_fast32_t grid_data_t;
typedef struct
{
// Number of elements in one row.
size_t row_len;
// Pointer to the buffer containing the matrix's characters.
// The data is organized as <string length> <chars...>, such that the `char`s
// are casted to `int_fast32_t` to allow for the mixed types.
grid_data_t *data_head;
// Array of pointers to the start of each entry string.
grid_data_t **entries_head;
// Number of elements.
size_t data_len;
} grid_t;
// Parameters for `increase_input_buffers`.
typedef struct
{
size_t data_cap;
grid_data_t *data_head;
grid_data_t **entries_head;
} increase_input_buffers_params_t;
// Prints a debug view of a `grid_t` to standard output.
void debug_print_grid(grid_t *grid)
{
printf("Grid { row_len: %zu, data_head: %p, entries_head: %p, data_len: %zu }",
(grid->row_len), (void*)(grid->data_head), (void*)(grid->entries_head),
(grid->data_len));
}
// Increases the data buffers used in `parse_input`.
//
// As reallocation will happen, the updated pointers and capacity are returned
// in an updated parameters object.
increase_input_buffers_params_t increase_input_buffers(increase_input_buffers_params_t params)
{
params.data_cap *= 2;
params.data_head = realloc(params.data_head, params.data_cap * sizeof(grid_data_t));
params.entries_head = realloc(params.entries_head, params.data_cap * sizeof(grid_data_t *));
if ((params.data_head == NULL) || (params.entries_head == NULL))
{
printf(
"Failed to reallocate bigger buffer for input data. Was trying to "
"allocate %zu entries, aborting.",
params.data_cap);
exit(EXIT_FAILURE);
}
return params;
}
// Parse the input from standard input.
//
// This function parses an extended matrix (C|l), where C is an n×m matrix, and
// l is an m-sized column vector. This input is given in standard input as
//
// <row length> <whitespace separated entries>
//
// Parsing the entries of the matrix as numeric is unnecessary, since we just
// want to check equality of rows under certain permutations. Therefore, the
// matrix is stored as literal characters.
//
// To make data access O(1), we store both the literal characters, as well as
// indices to the start of each entry. See the `Grid` struct. In particular,
// what we have is contiguous blocks of strings, structured as
//
// <string length> <characters...>
grid_t parse_input(void)
{
size_t row_len;
scanf("%zu", &row_len);
size_t data_cap = 32; // Initial value is arbitrary.
size_t data_len = 0; // Number of characters written so far.
size_t str_len = 0; // Number of strings written so far.
grid_data_t *data_head = malloc(data_cap * sizeof(grid_data_t));
size_t *entries_head = malloc(data_cap * sizeof(size_t));
_Bool spaces = 1;
char scanned;
while ((scanned = scanf("%c", &scanned)) != EOF)
{
if (isspace(scanned))
{
spaces = 1;
}
else
{
// A little input sanitization.
if (scanned == '+')
{
// We can ignore plus signs, assuming we have (\+|\-)?\d+(\.\d+)?(E\d+)?
continue;
}
if (!(isdigit(scanned) || (scanned == '-') || (scanned == '.')))
{
printf(
"Foreign character %c found when processing input, aborting.",
scanned);
exit(EXIT_FAILURE);
}
if (spaces)
{
// New row
str_len += 1;
data_len += 1; // The byte for the string length
// data_head[data_len] is already correctly initialized to 0.
entries_head[str_len - 1] = data_len - 1;
}
spaces = 0;
// We're about to write a new character.
data_len += 1;
// Check if we need to resize the buffer.
if (data_len > data_cap)
{
increase_input_buffers_params_t params = {
.data_cap = data_cap,
.data_head = data_head,
.entries_head = entries_head,
};
params = increase_input_buffers(params);
data_cap = params.data_cap;
data_head = params.data_head;
entries_head = params.entries_head;
}
// Write the character
data_head[data_len - 1] = scanned;
// Increase the length of current string
grid_data_t *cur_len = entries_head[str_len - 1];
*cur_len += 1;
}
} // End of scan loop
// Input sanitization: confirm that the number of entries read is a multiple
// of the number of entries in a row.
if (!((str_len % row_len) == 0))
{
printf("Number of entries is not consistent with provided row length. "
"Got row length of %zu, and read %zu entries. Aborting.",
row_len, str_len);
// No need to free the buffers.
exit(EXIT_FAILURE);
}
grid_t grid = {
.row_len = row_len,
.data_head = data_head,
.entries_head = entries_head,
.data_len = data_len,
};
return grid;
}
int main(int argc, char *argv[])
{
grid_t grid = parse_input();
debug_print_grid(&grid);
return 0;
}