|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "circ_buff.h"
|
|
|
|
|
|
|
|
// Defines the circular buffer structure
|
|
|
|
struct circ_buf_t {
|
|
|
|
char** buffer;
|
|
|
|
size_t head;
|
|
|
|
size_t tail;
|
|
|
|
size_t max; // of the buffer
|
|
|
|
size_t el_size;
|
|
|
|
bool full;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Private Functions
|
|
|
|
|
|
|
|
unit_static void advance_pointer(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
if(cbuf->full) {
|
|
|
|
cbuf->tail = (cbuf->tail + 1) % cbuf->max;
|
|
|
|
}
|
|
|
|
|
|
|
|
cbuf->head = (cbuf->head + 1) % cbuf->max;
|
|
|
|
|
|
|
|
// We mark full because we will advance tail on the next time around
|
|
|
|
cbuf->full = (cbuf->head == cbuf->tail);
|
|
|
|
}
|
|
|
|
|
|
|
|
unit_static void retreat_pointer(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
cbuf->full = false;
|
|
|
|
cbuf->tail = (cbuf->tail + 1) % cbuf->max;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compares the buffers cbuf1 and cbuf2. Elements present on cbuf1 that do not
|
|
|
|
// exist on cbuf2 are added to the array add2, elements present on cbuf2 that do
|
|
|
|
// not exist on cbuf1 are added to the array add1.
|
|
|
|
// Both buffers must be ordered on the same way!
|
|
|
|
unit_static void diff_bufs(cbuf_handle_t cbuf1, cbuf_handle_t cbuf2,
|
|
|
|
char*** add1, char*** add2) {
|
|
|
|
assert(cbuf1 && cbuf2 &&
|
|
|
|
(circ_buf_element_size(cbuf1) == circ_buf_element_size(cbuf2)) &&
|
|
|
|
(circ_buf_capacity(cbuf1) == circ_buf_capacity(cbuf2)));
|
|
|
|
|
|
|
|
// Initializes the diff arrays
|
|
|
|
(*add1) = (char **) malloc(circ_buf_capacity(cbuf2) * sizeof(char *));
|
|
|
|
(*add2) = (char **) malloc(circ_buf_capacity(cbuf1) * sizeof(char *));
|
|
|
|
|
|
|
|
char* curr_str1 = (char*) malloc(circ_buf_element_size(cbuf1) * sizeof(char));
|
|
|
|
char* curr_str2 = (char*) malloc(circ_buf_element_size(cbuf2) * sizeof(char));
|
|
|
|
/*uint8_t diff_array_index = 0;
|
|
|
|
for (uint8_t i = 0; i < circ_buf_size(cbuf1); ++i) {
|
|
|
|
// Reads current element of cbuf1
|
|
|
|
circ_buf_read(cbuf1, i, curr_str1);
|
|
|
|
bool element_exists = false;
|
|
|
|
|
|
|
|
for (uint8_t j = 0; j < circ_buf_size(cbuf2); ++j) {
|
|
|
|
circ_buf_read(cbuf2, j, curr_str2);
|
|
|
|
// Checks against cbuf2 elements
|
|
|
|
if (!strcmp(curr_str2, curr_str1)) {
|
|
|
|
element_exists = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!element_exists) {
|
|
|
|
(*add2)[diff_array_index] = (char*) malloc(circ_buf_element_size(cbuf1) * sizeof(char));
|
|
|
|
strcpy((*add2)[diff_array_index], curr_str1);
|
|
|
|
++diff_array_index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(*add1)[diff_array_index] = (char*) malloc(circ_buf_element_size(cbuf1) * sizeof(char));
|
|
|
|
strcpy((*add1)[diff_array_index], EOB);
|
|
|
|
|
|
|
|
diff_array_index = 0;
|
|
|
|
for (uint8_t i = 0; i < circ_buf_size(cbuf2); ++i) {
|
|
|
|
// Reads current element of cbuf2
|
|
|
|
circ_buf_read(cbuf2, i, curr_str2);
|
|
|
|
bool element_exists = false;
|
|
|
|
|
|
|
|
for (uint8_t j = 0; j < circ_buf_size(cbuf1); ++j) {
|
|
|
|
circ_buf_read(cbuf1, j, curr_str1);
|
|
|
|
// Checks against cbuf1 elements
|
|
|
|
if (!strcmp(curr_str1, curr_str2)) {
|
|
|
|
element_exists = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!element_exists) {
|
|
|
|
(*add1)[diff_array_index] = (char*) malloc(circ_buf_element_size(cbuf2) * sizeof(char));
|
|
|
|
strcpy((*add1)[diff_array_index], curr_str2);
|
|
|
|
++diff_array_index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(*add2)[diff_array_index] = (char*) malloc(circ_buf_element_size(cbuf2) * sizeof(char));
|
|
|
|
strcpy((*add2)[diff_array_index], EOB);*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t cbuf1_idx = 0, cbuf2_idx = 0, add1_arr_idx = 0, add2_arr_idx = 0;
|
|
|
|
while ((cbuf1_idx < circ_buf_size(cbuf1)) &&
|
|
|
|
(cbuf2_idx < circ_buf_size(cbuf2))) {
|
|
|
|
circ_buf_read(cbuf1, cbuf1_idx, curr_str1);
|
|
|
|
circ_buf_read(cbuf2, cbuf2_idx, curr_str2);
|
|
|
|
|
|
|
|
int strcmp_res = strcmp(curr_str1, curr_str2);
|
|
|
|
if (!strcmp_res) {
|
|
|
|
++cbuf1_idx;
|
|
|
|
++cbuf2_idx;
|
|
|
|
} else { // TODO: change the inner comparisons (strtok etc)
|
|
|
|
if (strcmp_res < 0) {
|
|
|
|
(*add2)[add2_arr_idx] = (char*) malloc(circ_buf_element_size(cbuf2) * sizeof(char));
|
|
|
|
strcpy((*add2)[add2_arr_idx], curr_str1);
|
|
|
|
++add2_arr_idx;
|
|
|
|
++cbuf1_idx;
|
|
|
|
}
|
|
|
|
else if (strcmp_res > 0) {
|
|
|
|
(*add1)[add1_arr_idx] = (char*) malloc(circ_buf_element_size(cbuf1) * sizeof(char));
|
|
|
|
strcpy((*add1)[add1_arr_idx], curr_str2);
|
|
|
|
++add1_arr_idx;
|
|
|
|
++cbuf2_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (cbuf1_idx < circ_buf_size(cbuf1)) {
|
|
|
|
(*add2)[add2_arr_idx] = (char*) malloc(circ_buf_element_size(cbuf2) * sizeof(char));
|
|
|
|
circ_buf_read(cbuf1, cbuf1_idx, curr_str1);
|
|
|
|
strcpy((*add2)[add2_arr_idx], curr_str1);
|
|
|
|
++add2_arr_idx;
|
|
|
|
++cbuf1_idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (cbuf2_idx < circ_buf_size(cbuf2)) {
|
|
|
|
(*add1)[add1_arr_idx] = (char*) malloc(circ_buf_element_size(cbuf1) * sizeof(char));
|
|
|
|
circ_buf_read(cbuf2, cbuf2_idx, curr_str2);
|
|
|
|
strcpy((*add1)[add1_arr_idx], curr_str2);
|
|
|
|
++add1_arr_idx;
|
|
|
|
++cbuf2_idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*add1)[add1_arr_idx] = (char*) malloc(circ_buf_element_size(cbuf1) * sizeof(char));
|
|
|
|
strcpy((*add1)[add1_arr_idx], EOB);
|
|
|
|
|
|
|
|
(*add2)[add2_arr_idx] = (char*) malloc(circ_buf_element_size(cbuf2) * sizeof(char));
|
|
|
|
strcpy((*add2)[add2_arr_idx], EOB);
|
|
|
|
|
|
|
|
free(curr_str1);
|
|
|
|
free(curr_str2);
|
|
|
|
|
|
|
|
/*uint8_t i = 0;
|
|
|
|
printf("add1:\n");
|
|
|
|
while (strcmp((*add1)[i], EOB)) {
|
|
|
|
printf("%s\n", (*add1)[i]);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
printf("add2:\n");
|
|
|
|
while (strcmp((*add2)[i], EOB)) {
|
|
|
|
printf("%s\n", (*add2)[i]);
|
|
|
|
++i;
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
|
|
|
// APIs
|
|
|
|
|
|
|
|
cbuf_handle_t circ_buf_init(char** buffer, size_t size, size_t element_size) {
|
|
|
|
assert(buffer && size);
|
|
|
|
|
|
|
|
cbuf_handle_t cbuf = malloc(sizeof(circ_buf_t));
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
cbuf->buffer = buffer;
|
|
|
|
cbuf->max = size;
|
|
|
|
cbuf->el_size = element_size;
|
|
|
|
circ_buf_reset(cbuf);
|
|
|
|
|
|
|
|
assert(circ_buf_empty(cbuf));
|
|
|
|
|
|
|
|
return cbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void circ_buf_free(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
free(cbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void circ_buf_reset(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
cbuf->head = 0;
|
|
|
|
cbuf->tail = 0;
|
|
|
|
cbuf->full = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t circ_buf_size(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
size_t size = cbuf->max;
|
|
|
|
|
|
|
|
if(!cbuf->full) {
|
|
|
|
if(cbuf->head >= cbuf->tail) {
|
|
|
|
size = (cbuf->head - cbuf->tail);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
size = (cbuf->max + cbuf->head - cbuf->tail);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t circ_buf_capacity(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
return cbuf->max;
|
|
|
|
}
|
|
|
|
|
|
|
|
void circ_buf_put(cbuf_handle_t cbuf, const char* data) {
|
|
|
|
assert(cbuf && cbuf->buffer);
|
|
|
|
|
|
|
|
strcpy(cbuf->buffer[cbuf->head], data);
|
|
|
|
|
|
|
|
advance_pointer(cbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void circ_buf_mul_add(cbuf_handle_t cbuf, char** data, uint8_t size,
|
|
|
|
int (*compar)(const void* , const void*)) {
|
|
|
|
assert(cbuf && data && cbuf->buffer);
|
|
|
|
|
|
|
|
qsort(data, size, sizeof(char*), compar);
|
|
|
|
|
|
|
|
char* last_element = (char*) malloc(circ_buf_element_size(cbuf) * sizeof(char));
|
|
|
|
for (uint8_t i = 0; i < size; ++i) {
|
|
|
|
circ_buf_read(cbuf, 0, last_element);
|
|
|
|
|
|
|
|
if (compar(&data[i], &last_element) < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
circ_buf_put(cbuf, data[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(last_element);
|
|
|
|
|
|
|
|
int end_buffer_size = circ_buf_size(cbuf);
|
|
|
|
char** temp_array = (char **) malloc(end_buffer_size * sizeof(char *));
|
|
|
|
for (uint8_t buff_el = 0; buff_el < end_buffer_size; ++buff_el) {
|
|
|
|
temp_array[buff_el] = (char *) malloc(circ_buf_element_size(cbuf) * sizeof(char));
|
|
|
|
circ_buf_get(cbuf, temp_array[buff_el]);
|
|
|
|
}
|
|
|
|
|
|
|
|
qsort(temp_array, end_buffer_size, sizeof(char*), compar);
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < end_buffer_size; ++i) {
|
|
|
|
circ_buf_put(cbuf, temp_array[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint8_t buff_el = 0; buff_el < end_buffer_size; ++buff_el) {
|
|
|
|
free(temp_array[buff_el]);
|
|
|
|
}
|
|
|
|
free(temp_array);
|
|
|
|
}
|
|
|
|
|
|
|
|
int circ_buf_get(cbuf_handle_t cbuf, char* data) {
|
|
|
|
assert(cbuf && data && cbuf->buffer);
|
|
|
|
|
|
|
|
int r = -1;
|
|
|
|
|
|
|
|
if(!circ_buf_empty(cbuf)) {
|
|
|
|
strcpy(data, cbuf->buffer[cbuf->tail]);
|
|
|
|
retreat_pointer(cbuf);
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int circ_buf_read(cbuf_handle_t cbuf, size_t position, char* data) {
|
|
|
|
assert(cbuf && data && cbuf->buffer && (position < circ_buf_size(cbuf)));
|
|
|
|
|
|
|
|
int r = -1;
|
|
|
|
|
|
|
|
if(!circ_buf_empty(cbuf)) {
|
|
|
|
strcpy(data, cbuf->buffer[(cbuf->tail + position) % cbuf->max]);
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int circ_buf_serialize(cbuf_handle_t cbuf, char** serialized) {
|
|
|
|
char* temp = (char*) malloc(circ_buf_element_size(cbuf) * sizeof(char));
|
|
|
|
const char separator[2] = "\r";
|
|
|
|
uint8_t char_sum = circ_buf_size(cbuf) - 1;
|
|
|
|
uint8_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < circ_buf_size(cbuf); ++i) {
|
|
|
|
circ_buf_read(cbuf, i, temp);
|
|
|
|
char_sum += strlen(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
(*serialized) = (char*) malloc((char_sum + 1) * sizeof(char));
|
|
|
|
strcpy((*serialized), "");
|
|
|
|
|
|
|
|
for (i = 0; i < circ_buf_size(cbuf) - 1; ++i) {
|
|
|
|
circ_buf_read(cbuf, i, temp);
|
|
|
|
strcat((*serialized), temp);
|
|
|
|
strcat((*serialized), separator);
|
|
|
|
}
|
|
|
|
|
|
|
|
circ_buf_read(cbuf, i, temp);
|
|
|
|
strcat((*serialized), temp);
|
|
|
|
|
|
|
|
free(temp);
|
|
|
|
|
|
|
|
return strlen((*serialized));
|
|
|
|
}
|
|
|
|
|
|
|
|
int circ_buf_deserialize(cbuf_handle_t cbuf, const char* serialized) {
|
|
|
|
char *str = calloc(strlen(serialized) + 1, sizeof(char));
|
|
|
|
strcpy(str, serialized);
|
|
|
|
const char separator[2] = "\r";
|
|
|
|
char* token;
|
|
|
|
|
|
|
|
token = strtok(str, separator);
|
|
|
|
|
|
|
|
while (token != NULL) {
|
|
|
|
circ_buf_put(cbuf, token);
|
|
|
|
token = strtok(NULL, separator);
|
|
|
|
}
|
|
|
|
|
|
|
|
return circ_buf_size(cbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool circ_buf_empty(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
return (!cbuf->full && (cbuf->head == cbuf->tail));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool circ_buf_full(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
return cbuf->full;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t circ_buf_element_size(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
return cbuf->el_size;
|
|
|
|
}
|