Compare commits
2 Commits
28058cdac3
...
79fa414c7d
Author | SHA1 | Date |
---|---|---|
Miguel M | 79fa414c7d | |
Miguel M | eebca1914d |
|
@ -1,4 +1,47 @@
|
|||
3
|
||||
1 1 -1
|
||||
555 0.9 2
|
||||
-55 2 1555
|
||||
-55 2 1555
|
||||
4 6 9
|
||||
548 210 127
|
||||
0 560 186
|
||||
158 38 975
|
||||
873 377 665
|
||||
103 535 531
|
||||
101 741 950
|
||||
385 641 463
|
||||
861 459 991
|
||||
287 430 146
|
||||
557 652 529
|
||||
775 965 617
|
||||
243 671 96
|
||||
503 453 224
|
||||
748 552 546
|
||||
459 606 237
|
||||
477 489 969
|
||||
868 704 980
|
||||
944 202 840
|
||||
745 346 658
|
||||
946 867 66
|
||||
1 1 -1
|
||||
555 0.9 2
|
||||
-55 2 1555
|
||||
4 6 9
|
||||
548 210 127
|
||||
0 560 186
|
||||
158 38 975
|
||||
873 377 665
|
||||
103 535 531
|
||||
101 741 950
|
||||
385 641 463
|
||||
861 459 991
|
||||
287 430 146
|
||||
557 652 529
|
||||
775 965 617
|
||||
243 671 96
|
||||
503 453 224
|
||||
748 552 546
|
||||
459 606 237
|
||||
477 489 969
|
||||
868 704 980
|
||||
944 202 840
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef __H_MATRIX
|
||||
#define __H_MATRIX
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PRIgridDATA PRIiFAST32
|
||||
typedef int_fast32_t grid_data_t;
|
||||
|
||||
// Struct representing the input matrix.
|
||||
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 indices in `data_head` of the start of each string.
|
||||
size_t *entries_head;
|
||||
// Number of bytes.
|
||||
size_t data_len;
|
||||
// Number of entries.
|
||||
size_t entries_len;
|
||||
} matrix_t;
|
||||
|
||||
// Parameters for `increase_input_buffers`.
|
||||
typedef struct
|
||||
{
|
||||
size_t data_cap;
|
||||
grid_data_t *data_head;
|
||||
size_t *entries_head;
|
||||
} matrix_bufs_t;
|
||||
|
||||
// Prints a debug view of a `matrix_t` to standard output.
|
||||
void debug_print_grid(matrix_t *grid);
|
||||
|
||||
// Parse a matrix from the 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>
|
||||
matrix_t parse_matrix(void);
|
||||
|
||||
#endif // __H_MATRIX
|
5
make.py
5
make.py
|
@ -82,8 +82,9 @@ def clean():
|
|||
|
||||
@recipe(recipe_deps=[link],
|
||||
conditions=[lambda: True],
|
||||
info='Runs the main executable.')
|
||||
info='Runs the main executable with the test matrix as input.')
|
||||
def run():
|
||||
sp.run(EXE_NAME)
|
||||
with open(os.path.join(ROOT, 'data', 'test_mat.txt'), 'r') as test_input:
|
||||
sp.run(os.path.join(ROOT, EXE_NAME), stdin=test_input)
|
||||
|
||||
sane_run(run)
|
||||
|
|
205
src/main.c
205
src/main.c
|
@ -1,213 +1,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <ctype.h>
|
||||
#include "../includes/matrix.h"
|
||||
|
||||
// #define STB_DS_IMPLEMENTATION
|
||||
// #define STBDS_NO_SHORT_NAMES
|
||||
// #include "../contrib/stb/stb_ds.h"
|
||||
|
||||
#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 indices in `data_head` of the start of each string.
|
||||
size_t *entries_head;
|
||||
// Number of bytes.
|
||||
size_t data_len;
|
||||
// Number of entries.
|
||||
size_t entries_len;
|
||||
} grid_t;
|
||||
|
||||
// Parameters for `increase_input_buffers`.
|
||||
typedef struct
|
||||
{
|
||||
size_t data_cap;
|
||||
grid_data_t *data_head;
|
||||
size_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, entries_len: %zu ) { ",
|
||||
(grid->row_len), (void *)(grid->data_head), (void *)(grid->entries_head),
|
||||
(grid->data_len), (grid->entries_len));
|
||||
printf("data: [");
|
||||
size_t str_counter = 0;
|
||||
for (size_t i = 0; i < grid->data_len; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
_Bool is_char = 1;
|
||||
if (grid->entries_len > 0 && str_counter < grid->entries_len) {
|
||||
if ((grid->entries_head)[str_counter] == i) {
|
||||
is_char = 0;
|
||||
str_counter += 1;
|
||||
}
|
||||
}
|
||||
if (is_char) {
|
||||
printf("'%c'", (char)((grid->data_head)[i]));
|
||||
} else {
|
||||
printf("%" PRIgridDATA, (grid->data_head)[i]);
|
||||
}
|
||||
}
|
||||
printf("], entries: [");
|
||||
for (size_t i = 0; i < grid->entries_len; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
printf("%zu", (grid->entries_head)[i]);
|
||||
}
|
||||
printf("] }\n");
|
||||
}
|
||||
|
||||
// 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 entries_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 (scanf("%c", &scanned) != EOF)
|
||||
{
|
||||
if (isspace(scanned))
|
||||
{
|
||||
spaces = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A little input sanitization.
|
||||
if (!(isdigit(scanned) || (scanned == '-') || (scanned == '.')))
|
||||
{
|
||||
printf(
|
||||
"Foreign character %c (%x) found when processing input, aborting.",
|
||||
scanned, scanned);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (spaces)
|
||||
{
|
||||
// New string
|
||||
entries_len += 1;
|
||||
data_len += 1; // The byte for the string length
|
||||
// data_head[data_len] is already correctly initialized to 0.
|
||||
entries_head[entries_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
|
||||
data_head[entries_head[entries_len - 1]] += 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 (!((entries_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, entries_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,
|
||||
.entries_len = entries_len,
|
||||
};
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
grid_t grid = parse_input();
|
||||
matrix_t grid = parse_matrix();
|
||||
debug_print_grid(&grid);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
#include "../includes/matrix.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// Prints a debug view of a `matrix_t` to standard output.
|
||||
void debug_print_grid(matrix_t *matrix)
|
||||
{
|
||||
printf("Grid ( row_len: %zu, data_head: %p, entries_head: %p, data_len: %zu, entries_len: %zu ) { ",
|
||||
(matrix->row_len), (void *)(matrix->data_head), (void *)(matrix->entries_head),
|
||||
(matrix->data_len), (matrix->entries_len));
|
||||
printf("data: [");
|
||||
size_t str_counter = 0;
|
||||
for (size_t i = 0; i < matrix->data_len; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
_Bool is_char = 1;
|
||||
if (matrix->entries_len > 0 && str_counter < matrix->entries_len)
|
||||
{
|
||||
if ((matrix->entries_head)[str_counter] == i)
|
||||
{
|
||||
is_char = 0;
|
||||
str_counter += 1;
|
||||
}
|
||||
}
|
||||
if (is_char)
|
||||
{
|
||||
printf("'%c'", (char)((matrix->data_head)[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%" PRIgridDATA, (matrix->data_head)[i]);
|
||||
}
|
||||
}
|
||||
printf("], entries: [");
|
||||
for (size_t i = 0; i < matrix->entries_len; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
printf("%zu", (matrix->entries_head)[i]);
|
||||
}
|
||||
printf("] }\n");
|
||||
}
|
||||
|
||||
// Increases the data buffers used in `parse_input`.
|
||||
//
|
||||
// As reallocation will happen, the updated pointers and capacity are returned
|
||||
// in an updated parameters object.
|
||||
matrix_bufs_t increase_input_buffers(matrix_bufs_t bufs)
|
||||
{
|
||||
bufs.data_cap *= 2;
|
||||
bufs.data_head = realloc(bufs.data_head, bufs.data_cap * sizeof(grid_data_t));
|
||||
bufs.entries_head = realloc(bufs.entries_head, bufs.data_cap * sizeof(grid_data_t *));
|
||||
if ((bufs.data_head == NULL) || (bufs.entries_head == NULL))
|
||||
{
|
||||
printf(
|
||||
"Failed to reallocate bigger buffer for input data. Was trying to "
|
||||
"allocate %zu entries, aborting.",
|
||||
bufs.data_cap);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return bufs;
|
||||
}
|
||||
|
||||
// Compacts the allocated memory to fit exactly the number of elements.
|
||||
//
|
||||
// As reallocation will happen, the updated pointers and capacity are returned
|
||||
// in an updated parameters object.
|
||||
matrix_bufs_t compact_buffers(matrix_t *matrix) {
|
||||
matrix->data_head = realloc(matrix->data_head, matrix->data_len * sizeof(grid_data_t));
|
||||
matrix->entries_head = realloc(matrix->entries_head, matrix->entries_len * sizeof(grid_data_t *));
|
||||
if ((matrix->data_head == NULL) || (matrix->entries_head == NULL))
|
||||
{
|
||||
printf(
|
||||
"Failed to reallocate matrix data buffers. Was trying to "
|
||||
"allocate for %zu data entries, aborting.",
|
||||
matrix->data_len);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a `matrix_t` by reading from standard input.
|
||||
//
|
||||
// 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...>
|
||||
matrix_t parse_matrix(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 entries_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 (scanf("%c", &scanned) != EOF)
|
||||
{
|
||||
if (isspace(scanned))
|
||||
{
|
||||
spaces = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A little input sanitization.
|
||||
if (!(isdigit(scanned) || (scanned == '-') || (scanned == '.')))
|
||||
{
|
||||
printf(
|
||||
"Foreign character %c (%x) found when processing input, aborting.",
|
||||
scanned, scanned);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (spaces)
|
||||
{
|
||||
// New string
|
||||
entries_len += 1;
|
||||
data_len += 1; // The byte for the string length
|
||||
// data_head[data_len] is already correctly initialized to 0.
|
||||
entries_head[entries_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)
|
||||
{
|
||||
matrix_bufs_t bufs = {
|
||||
.data_cap = data_cap,
|
||||
.data_head = data_head,
|
||||
.entries_head = entries_head,
|
||||
};
|
||||
bufs = increase_input_buffers(bufs);
|
||||
data_cap = bufs.data_cap;
|
||||
data_head = bufs.data_head;
|
||||
entries_head = bufs.entries_head;
|
||||
}
|
||||
|
||||
// Write the character
|
||||
data_head[data_len - 1] = scanned;
|
||||
|
||||
// Increase the length of current string
|
||||
data_head[entries_head[entries_len - 1]] += 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 (!((entries_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, entries_len);
|
||||
// No need to free the buffers.
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
matrix_t matrix = {
|
||||
.row_len = row_len,
|
||||
.data_head = data_head,
|
||||
.entries_head = entries_head,
|
||||
.data_len = data_len,
|
||||
.entries_len = entries_len,
|
||||
};
|
||||
|
||||
compact_buffers(&matrix);
|
||||
|
||||
return matrix;
|
||||
}
|
Loading…
Reference in New Issue