diff --git a/CMakeLists.txt b/CMakeLists.txt index 75b33cb..31994f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ # begin basic metadata cmake_minimum_required(VERSION 3.0) -project(libsaxbospiral VERSION 0.19.3 LANGUAGES C) +project(libsaxbospiral VERSION 0.20.0 LANGUAGES C) # set default C standard to use (C99) set(SAXBOSPIRAL_C_STANDARD "99") @@ -50,7 +50,9 @@ if(CMAKE_SIZEOF_VOID_P LESS 8) message( WARNING "It looks like this system's architecture is not at least 64-bit.\n" - "libsaxbospiral requires a system with an architecture of at least 64 bits!") + "libsaxbospiral requires a system with an architecture of at least 64 bits!\n" + "We'll continue trying to compile anyway, be sure to run the unit tests after." + ) endif() # pass in version of library as preprocessor definitions @@ -123,15 +125,37 @@ install( LIBRARY DESTINATION lib RUNTIME DESTINATION bin ) -# Install main library header files + +# Generate rough (nearest major) version-dependent header installation folder +set( + LIBSAXBOSPIRAL_ROUGH_HEADER_DESTINATION + "saxbospiral-${PROJECT_VERSION_MAJOR}" +) +# Generate precise (major and minor) version-dependent header installation folder +set( + LIBSAXBOSPIRAL_PRECISE_HEADER_DESTINATION + "saxbospiral-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" +) + +# Install main library header files, both to rough and precise install locations +install( + FILES ${LIB_SAXBOSPIRAL_HEADERS} + DESTINATION "include/${LIBSAXBOSPIRAL_ROUGH_HEADER_DESTINATION}" +) +# Install render_backends header files +install( + FILES ${LIB_SAXBOSPIRAL_RENDER_BACKENDS_HEADERS} + DESTINATION "include/${LIBSAXBOSPIRAL_ROUGH_HEADER_DESTINATION}/render_backends" +) + install( FILES ${LIB_SAXBOSPIRAL_HEADERS} - DESTINATION include/saxbospiral + DESTINATION "include/${LIBSAXBOSPIRAL_PRECISE_HEADER_DESTINATION}" ) # Install render_backends header files install( FILES ${LIB_SAXBOSPIRAL_RENDER_BACKENDS_HEADERS} - DESTINATION include/saxbospiral/render_backends + DESTINATION "include/${LIBSAXBOSPIRAL_PRECISE_HEADER_DESTINATION}/render_backends" ) enable_testing() diff --git a/saxbospiral/initialise.c b/saxbospiral/initialise.c index 4c8abd3..2b9bfbf 100644 --- a/saxbospiral/initialise.c +++ b/saxbospiral/initialise.c @@ -20,6 +20,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +#include #include #include @@ -54,8 +55,14 @@ sxbp_spiral_t sxbp_blank_spiral() { * this converts the 0s and 1s in the data into UP, LEFT, DOWN, RIGHT * instructions which are then used to build the pattern. * returns a status_t struct with error information (if needed) + * + * Asserts: + * - That the spiral struct pointed to has its pointer attributes set to NULL */ sxbp_status_t sxbp_init_spiral(sxbp_buffer_t buffer, sxbp_spiral_t* spiral) { + // preconditional assertions + assert(spiral->lines == NULL); + assert(spiral->co_ord_cache.co_ords.items == NULL); // result status object sxbp_status_t result; // number of lines is number of bits of the data, + 1 for the first UP line @@ -67,8 +74,7 @@ sxbp_status_t sxbp_init_spiral(sxbp_buffer_t buffer, sxbp_spiral_t* spiral) { spiral->lines = calloc(sizeof(sxbp_line_t), line_count); // check for memory allocation failure if(spiral->lines == NULL) { - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + result = SXBP_MALLOC_REFUSED; return result; } // First line is always an UP line - this is for orientation purposes @@ -98,7 +104,7 @@ sxbp_status_t sxbp_init_spiral(sxbp_buffer_t buffer, sxbp_spiral_t* spiral) { } } // all ok - result.diagnostic = SXBP_OPERATION_OK; + result = SXBP_OPERATION_OK; return result; } diff --git a/saxbospiral/initialise.h b/saxbospiral/initialise.h index c77e925..e126c09 100644 --- a/saxbospiral/initialise.h +++ b/saxbospiral/initialise.h @@ -49,6 +49,9 @@ sxbp_spiral_t sxbp_blank_spiral(); * this converts the 0s and 1s in the data into UP, LEFT, DOWN, RIGHT * instructions which are then used to build the pattern. * returns a status_t struct with error information (if needed) + * + * Asserts: + * - That the spiral struct pointed to has its pointer attributes set to NULL */ sxbp_status_t sxbp_init_spiral(sxbp_buffer_t buffer, sxbp_spiral_t* spiral); diff --git a/saxbospiral/plot.c b/saxbospiral/plot.c index 103b880..fd92186 100644 --- a/saxbospiral/plot.c +++ b/saxbospiral/plot.c @@ -21,6 +21,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +#include #include #include "saxbospiral.h" @@ -31,8 +32,18 @@ extern "C"{ #endif -// returns the sum of all line lengths within the given indexes +/* + * returns the sum of all line lengths within the given indexes + * + * Asserts: + * - That start and end indexes are less than or equal to the spiral size + * - That spiral.lines is not NULL + */ size_t sxbp_sum_lines(sxbp_spiral_t spiral, size_t start, size_t end) { + // preconditional assertions + assert(start <= spiral.size); + assert(end <= spiral.size); + assert(spiral.lines != NULL); size_t size = 0; for(size_t i = start; i < end; i++) { size += spiral.lines[i].length; @@ -49,13 +60,23 @@ size_t sxbp_sum_lines(sxbp_spiral_t spiral, size_t start, size_t end) { * each line segment is only one unit long, meaning multiple ones are needed for * lines longer than one unit. * returns a status struct with error information (if any) + * + * Asserts: + * - That the output struct's items pointer is NULL + * - That start and end indexes are less than or equal to the spiral size + * - That spiral.lines is not NULL */ sxbp_status_t sxbp_spiral_points( sxbp_spiral_t spiral, sxbp_co_ord_array_t* output, sxbp_co_ord_t start_point, size_t start, size_t end ) { + // preconditional assertions + assert(output->items == NULL); + assert(start <= spiral.size); + assert(end <= spiral.size); + assert(spiral.lines != NULL); // prepare result status - sxbp_status_t result = {{0, 0, 0}, 0}; + sxbp_status_t result; // the amount of space needed is the sum of all line lengths + 1 for end size_t size = sxbp_sum_lines(spiral, start, end) + 1; // allocate memory @@ -63,8 +84,7 @@ sxbp_status_t sxbp_spiral_points( // catch malloc error if(output->items == NULL) { // set error information then early return - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + result = SXBP_MALLOC_REFUSED; return result; } output->size = size; @@ -86,22 +106,29 @@ sxbp_status_t sxbp_spiral_points( } } // all good - result.diagnostic = SXBP_OPERATION_OK; + result = SXBP_OPERATION_OK; return result; } /* - * given a pointer to a spiral struct an limit, which is the index of the last + * given a pointer to a spiral struct and limit, which is the index of the last * line to use, calculate and store the co-ordinates of all line segments that * would make up the spiral if the current lengths and directions were used. * each line segment is only one unit long, meaning multiple ones are needed for * lines longer than one unit. The co-ords are stored in the spiral's * co_ord_cache member and are re-used if they are still valid * returns a status struct with error information (if any) + * + * Asserts: + * - That spiral->lines is not NULL + * - That limit is less than or equal to spiral->size */ sxbp_status_t sxbp_cache_spiral_points(sxbp_spiral_t* spiral, size_t limit) { + // preconditional assertions + assert(spiral->lines != NULL); + assert(limit <= spiral->size); // prepare result status - sxbp_status_t result = {{0, 0, 0}, 0}; + sxbp_status_t result; // the amount of space needed is the sum of all line lengths + 1 for end size_t size = sxbp_sum_lines(*spiral, 0, limit) + 1; // allocate / reallocate memory @@ -122,8 +149,7 @@ sxbp_status_t sxbp_cache_spiral_points(sxbp_spiral_t* spiral, size_t limit) { // catch malloc failure if(spiral->co_ord_cache.co_ords.items == NULL) { // set error information then early return - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + result = SXBP_MALLOC_REFUSED; return result; } spiral->co_ord_cache.co_ords.size = size; @@ -152,7 +178,7 @@ sxbp_status_t sxbp_cache_spiral_points(sxbp_spiral_t* spiral, size_t limit) { *spiral, &missing, current, smallest, limit ); // return errors from previous call if needed - if(calculate_result.diagnostic != SXBP_OPERATION_OK) { + if(calculate_result != SXBP_OPERATION_OK) { return calculate_result; } // add the missing co-ords to the cache @@ -168,7 +194,7 @@ sxbp_status_t sxbp_cache_spiral_points(sxbp_spiral_t* spiral, size_t limit) { limit > spiral->co_ord_cache.validity ) ? limit : spiral->co_ord_cache.validity; // return ok - result.diagnostic = SXBP_OPERATION_OK; + result = SXBP_OPERATION_OK; return result; } diff --git a/saxbospiral/plot.h b/saxbospiral/plot.h index 0a554d4..2449f3c 100644 --- a/saxbospiral/plot.h +++ b/saxbospiral/plot.h @@ -33,7 +33,13 @@ extern "C"{ #endif -// returns the sum of all line lengths within the given indexes +/* + * returns the sum of all line lengths within the given indexes + * + * Asserts: + * - That start and end indexes are less than or equal to the spiral size + * - That spiral.lines is not NULL + */ size_t sxbp_sum_lines(sxbp_spiral_t spiral, size_t start, size_t end); /* @@ -45,6 +51,11 @@ size_t sxbp_sum_lines(sxbp_spiral_t spiral, size_t start, size_t end); * each line segment is only one unit long, meaning multiple ones are needed for * lines longer than one unit. * returns a status struct with error information (if any) + * + * Asserts: + * - That the output struct's items pointer is NULL + * - That start and end indexes are less than or equal to the spiral size + * - That spiral.lines is not NULL */ sxbp_status_t sxbp_spiral_points( sxbp_spiral_t spiral, sxbp_co_ord_array_t* output, @@ -52,13 +63,17 @@ sxbp_status_t sxbp_spiral_points( ); /* - * given a pointer to a spiral struct an limit, which is the index of the last + * given a pointer to a spiral struct and limit, which is the index of the last * line to use, calculate and store the co-ordinates of all line segments that * would make up the spiral if the current lengths and directions were used. * each line segment is only one unit long, meaning multiple ones are needed for - * lines longer than one unit. The co-ords are stored in the - * spiral's co_ord_cache member and are re-used if they are still valid + * lines longer than one unit. The co-ords are stored in the spiral's + * co_ord_cache member and are re-used if they are still valid * returns a status struct with error information (if any) + * + * Asserts: + * - That spiral->lines is not NULL + * - That limit is less than or equal to spiral->size */ sxbp_status_t sxbp_cache_spiral_points(sxbp_spiral_t* spiral, size_t limit); diff --git a/saxbospiral/render.c b/saxbospiral/render.c index 34adf45..e6b5c46 100644 --- a/saxbospiral/render.c +++ b/saxbospiral/render.c @@ -20,6 +20,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +#include #include #include #include @@ -39,8 +40,13 @@ extern "C"{ * corners of the square needed to contain the points. * NOTE: This should NEVER be called with a pointer to anything other than a * 2-item struct of type co_ord_t + * + * Asserts: + * - That spiral.co_ord_cache.co_ords.items is not NULL */ static void get_bounds(sxbp_spiral_t spiral, sxbp_co_ord_t* bounds) { + // preconditional assertions + assert(spiral.co_ord_cache.co_ords.items != NULL); sxbp_tuple_item_t min_x = 0; sxbp_tuple_item_t min_y = 0; sxbp_tuple_item_t max_x = 0; @@ -70,10 +76,17 @@ static void get_bounds(sxbp_spiral_t spiral, sxbp_co_ord_t* bounds) { * given a spiral struct and a pointer to a blank bitmap_t struct, writes data * representing a monochromatic image of the rendered spiral to the bitmap * returns a status struct with error information (if any) + * + * Asserts: + * - That image->pixels is NULL + * - That spiral.lines is not NULL */ sxbp_status_t sxbp_render_spiral(sxbp_spiral_t spiral, sxbp_bitmap_t* image) { + // preconditional assertions + assert(image->pixels == NULL); + assert(spiral.lines != NULL); // create result status struct - sxbp_status_t result = {{0, 0, 0}, 0}; + sxbp_status_t result; // plot co-ords of spiral into it's cache sxbp_cache_spiral_points(&spiral, spiral.size); // get the min and max bounds of the spiral's co-ords @@ -96,8 +109,7 @@ sxbp_status_t sxbp_render_spiral(sxbp_spiral_t spiral, sxbp_bitmap_t* image) { image->pixels = malloc(image->width * sizeof(bool*)); // check for malloc fail if(image->pixels == NULL) { - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + result = SXBP_MALLOC_REFUSED; return result; } for(size_t i = 0; i < image->width; i++) { @@ -108,8 +120,9 @@ sxbp_status_t sxbp_render_spiral(sxbp_spiral_t spiral, sxbp_bitmap_t* image) { for(size_t j = i; j > 0; j--) { free(image->pixels[j]); } - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + // now we need to free() the top-level array + free(image->pixels); + result = SXBP_MALLOC_REFUSED; return result; } } @@ -140,7 +153,7 @@ sxbp_status_t sxbp_render_spiral(sxbp_spiral_t spiral, sxbp_bitmap_t* image) { } } // status ok - result.diagnostic = SXBP_OPERATION_OK; + result = SXBP_OPERATION_OK; return result; } diff --git a/saxbospiral/render.h b/saxbospiral/render.h index 8b422eb..34d5673 100644 --- a/saxbospiral/render.h +++ b/saxbospiral/render.h @@ -43,6 +43,10 @@ typedef struct sxbp_bitmap_t { * given a spiral struct and a pointer to a blank bitmap_t struct, writes data * representing a monochromatic image of the rendered spiral to the bitmap * returns a status struct with error information (if any) + * + * Asserts: + * - That image->pixels is NULL + * - That spiral.lines is not NULL */ sxbp_status_t sxbp_render_spiral(sxbp_spiral_t spiral, sxbp_bitmap_t* image); diff --git a/saxbospiral/render_backends/png_backend.c b/saxbospiral/render_backends/png_backend.c index 45bd03a..b4fb08e 100644 --- a/saxbospiral/render_backends/png_backend.c +++ b/saxbospiral/render_backends/png_backend.c @@ -99,8 +99,7 @@ sxbp_status_t sxbp_write_png_image( png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); // catch malloc fail if(png_ptr == NULL) { - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + result = SXBP_MALLOC_REFUSED; // cleanup cleanup_png_lib(png_ptr, info_ptr, row); return result; @@ -109,8 +108,7 @@ sxbp_status_t sxbp_write_png_image( info_ptr = png_create_info_struct(png_ptr); // catch malloc fail if(info_ptr == NULL) { - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + result = SXBP_MALLOC_REFUSED; // cleanup cleanup_png_lib(png_ptr, info_ptr, row); return result; @@ -159,8 +157,7 @@ sxbp_status_t sxbp_write_png_image( row = (png_bytep) malloc(bitmap.width * sizeof(png_byte)); // catch malloc fail if(row == NULL) { - result.location = SXBP_DEBUG; - result.diagnostic = SXBP_MALLOC_REFUSED; + result = SXBP_MALLOC_REFUSED; // cleanup cleanup_png_lib(png_ptr, info_ptr, row); return result; @@ -178,7 +175,7 @@ sxbp_status_t sxbp_write_png_image( // cleanup cleanup_png_lib(png_ptr, info_ptr, row); // status ok - result.diagnostic = SXBP_OPERATION_OK; + result = SXBP_OPERATION_OK; return result; } diff --git a/saxbospiral/saxbospiral.h b/saxbospiral/saxbospiral.h index 54cc8aa..670ed32 100644 --- a/saxbospiral/saxbospiral.h +++ b/saxbospiral/saxbospiral.h @@ -51,32 +51,13 @@ typedef uint32_t sxbp_version_hash_t; */ sxbp_version_hash_t sxbp_version_hash(sxbp_version_t version); -// struct for storing the location of a DEBUG invocation -typedef struct sxbp_debug_t { - size_t line; - char* file; - const char* function; -} sxbp_debug_t; - -/* - * handy short-hand for debugging purposes - * usage: debug_t debug = DEBUG; - */ -#define SXBP_DEBUG (sxbp_debug_t) { .line = __LINE__, .file = __FILE__, .function = __func__, } - // enum for function error information -typedef enum sxbp_diagnostic_t { +typedef enum sxbp_status_t { SXBP_STATE_UNKNOWN = 0, // unknown, the default state SXBP_OPERATION_FAIL, // generic failure state SXBP_MALLOC_REFUSED, // memory allocation or re-allocation was refused SXBP_IMPOSSIBLE_CONDITION, // condition thought to be impossible detected SXBP_OPERATION_OK, // no problem -} sxbp_diagnostic_t; - -// struct for storing generic diagnostics about function failure reasons -typedef struct sxbp_status_t { - sxbp_debug_t location; // for storing location of error - sxbp_diagnostic_t diagnostic; // for storing error information (if any) } sxbp_status_t; // type for representing a cartesian direction diff --git a/saxbospiral/serialise.c b/saxbospiral/serialise.c index e01a6ec..069817e 100644 --- a/saxbospiral/serialise.c +++ b/saxbospiral/serialise.c @@ -21,6 +21,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +#include #include #include #include @@ -38,8 +39,15 @@ extern "C"{ const size_t SXBP_FILE_HEADER_SIZE = 37; const size_t SXBP_LINE_T_PACK_SIZE = 4; -// loads a 64-bit unsigned integer from buffer starting at given index +/* + * loads a 64-bit unsigned integer from buffer starting at given index + * + * Asserts: + * - That buffer->bytes is not NULL + */ static uint64_t load_uint64_t(sxbp_buffer_t* buffer, size_t start_index) { + // preconditional assertions + assert(buffer->bytes != NULL); uint64_t value = 0; for(size_t i = 0; i < 8; i++) { value |= (buffer->bytes[start_index + i]) << (8 * (7 - i)); @@ -47,8 +55,15 @@ static uint64_t load_uint64_t(sxbp_buffer_t* buffer, size_t start_index) { return value; } -// loads a 32-bit unsigned integer from buffer starting at given index +/* + * loads a 32-bit unsigned integer from buffer starting at given index + * + * Asserts: + * - That buffer->bytes is not NULL + */ static uint32_t load_uint32_t(sxbp_buffer_t* buffer, size_t start_index) { + // preconditional assertions + assert(buffer->bytes != NULL); uint32_t value = 0; for(size_t i = 0; i < 4; i++) { value |= (buffer->bytes[start_index + i]) << (8 * (3 - i)); @@ -56,10 +71,17 @@ static uint32_t load_uint32_t(sxbp_buffer_t* buffer, size_t start_index) { return value; } -// dumps a 64-bit unsigned integer of value to buffer at given index +/* + * dumps a 64-bit unsigned integer of value to buffer at given index + * + * Asserts: + * - That buffer->bytes is not NULL + */ static void dump_uint64_t( uint64_t value, sxbp_buffer_t* buffer, size_t start_index ) { + // preconditional assertions + assert(buffer->bytes != NULL); for(uint8_t i = 0; i < 8; i++) { uint8_t shift = (8 * (7 - i)); buffer->bytes[start_index + i] = (uint8_t)( @@ -68,10 +90,17 @@ static void dump_uint64_t( } } -// dumps a 32-bit unsigned integer of value to buffer at given index +/* + * dumps a 32-bit unsigned integer of value to buffer at given index + * + * Asserts: + * - That buffer->bytes is not NULL + */ static void dump_uint32_t( uint32_t value, sxbp_buffer_t* buffer, size_t start_index ) { + // preconditional assertions + assert(buffer->bytes != NULL); for(uint8_t i = 0; i < 4; i++) { uint8_t shift = (8 * (3 - i)); buffer->bytes[start_index + i] = (uint8_t)( @@ -86,22 +115,27 @@ static void dump_uint32_t( * returns a serialise_result_t struct, which will contain information about * whether the operation was successful or not and information about what went * wrong if it was not successful + * + * Asserts: + * - That buffer.bytes is not NULL + * - That spiral->lines is NULL */ sxbp_serialise_result_t sxbp_load_spiral( sxbp_buffer_t buffer, sxbp_spiral_t* spiral ) { + // preconditional assertions + assert(buffer.bytes != NULL); + assert(spiral->lines == NULL); sxbp_serialise_result_t result; // build struct for returning success / failure // first, if header is too small for header + 1 line, then return early if(buffer.size < SXBP_FILE_HEADER_SIZE + SXBP_LINE_T_PACK_SIZE) { - result.status.location = SXBP_DEBUG; // catch location of error - result.status.diagnostic = SXBP_OPERATION_FAIL; // flag failure + result.status = SXBP_OPERATION_FAIL; // flag failure result.diagnostic = SXBP_DESERIALISE_BAD_HEADER_SIZE; // failure reason return result; } // check for magic number and return early if not right if(strncmp((char*)buffer.bytes, "SAXBOSPIRAL", 11) != 0) { - result.status.location = SXBP_DEBUG; // catch location of error - result.status.diagnostic = SXBP_OPERATION_FAIL; // flag failure + result.status = SXBP_OPERATION_FAIL; // flag failure result.diagnostic = SXBP_DESERIALISE_BAD_MAGIC_NUMBER; // failure reason return result; } @@ -116,8 +150,7 @@ sxbp_serialise_result_t sxbp_load_spiral( // check for version compatibility if(sxbp_version_hash(buffer_version) < sxbp_version_hash(min_version)) { // check failed - result.status.location = SXBP_DEBUG; // catch location of error - result.status.diagnostic = SXBP_OPERATION_FAIL; // flag failure + result.status = SXBP_OPERATION_FAIL; // flag failure result.diagnostic = SXBP_DESERIALISE_BAD_VERSION; // failure reason return result; } @@ -126,8 +159,7 @@ sxbp_serialise_result_t sxbp_load_spiral( // Check that the file data section is large enough for the spiral size if((buffer.size - SXBP_FILE_HEADER_SIZE) != (SXBP_LINE_T_PACK_SIZE * spiral_size)) { // this check failed - result.status.location = SXBP_DEBUG; // catch location of error - result.status.diagnostic = SXBP_OPERATION_FAIL; // flag failure + result.status = SXBP_OPERATION_FAIL; // flag failure result.diagnostic = SXBP_DESERIALISE_BAD_DATA_SIZE; // failure reason return result; } @@ -140,8 +172,7 @@ sxbp_serialise_result_t sxbp_load_spiral( spiral->lines = calloc(sizeof(sxbp_line_t), spiral->size); // catch allocation error if(spiral->lines == NULL) { - result.status.location = SXBP_DEBUG; // catch location of error - result.status.diagnostic = SXBP_MALLOC_REFUSED; // flag failure + result.status = SXBP_MALLOC_REFUSED; // flag failure return result; } // convert each serialised line segment in buffer into a line_t struct @@ -167,7 +198,7 @@ sxbp_serialise_result_t sxbp_load_spiral( } } // return ok status - result.status.diagnostic = SXBP_OPERATION_OK; + result.status = SXBP_OPERATION_OK; return result; } @@ -177,10 +208,17 @@ sxbp_serialise_result_t sxbp_load_spiral( * returns a serialise_result_t struct, which will contain information about * whether the operation was successful or not and information about what went * wrong if it was not successful + * + * Asserts: + * - That spiral.lines is not NULL + * - That buffer->bytes is NULL */ sxbp_serialise_result_t sxbp_dump_spiral( sxbp_spiral_t spiral, sxbp_buffer_t* buffer ) { + // preconditional assertions + assert(buffer->bytes == NULL); + assert(spiral.lines != NULL); sxbp_serialise_result_t result; // build struct for returning success / failure // populate buffer struct, base size on header + spiral size buffer->size = (SXBP_FILE_HEADER_SIZE + (SXBP_LINE_T_PACK_SIZE * spiral.size)); @@ -188,8 +226,7 @@ sxbp_serialise_result_t sxbp_dump_spiral( buffer->bytes = calloc(1, buffer->size); // catch memory allocation failure if(buffer->bytes == NULL) { - result.status.location = SXBP_DEBUG; - result.status.diagnostic = SXBP_MALLOC_REFUSED; + result.status = SXBP_MALLOC_REFUSED; return result; } // write first part of data header (magic number and version info) @@ -224,7 +261,7 @@ sxbp_serialise_result_t sxbp_dump_spiral( } } // return ok status - result.status.diagnostic = SXBP_OPERATION_OK; + result.status = SXBP_OPERATION_OK; return result; } diff --git a/saxbospiral/serialise.h b/saxbospiral/serialise.h index ec63446..fec8841 100644 --- a/saxbospiral/serialise.h +++ b/saxbospiral/serialise.h @@ -61,6 +61,10 @@ extern const size_t SXBP_LINE_T_PACK_SIZE; * returns a serialise_result_t struct, which will contain information about * whether the operation was successful or not and information about what went * wrong if it was not successful + * + * Asserts: + * - That buffer.bytes is not NULL + * - That spiral->lines is NULL */ sxbp_serialise_result_t sxbp_load_spiral( sxbp_buffer_t buffer, sxbp_spiral_t* spiral @@ -72,6 +76,10 @@ sxbp_serialise_result_t sxbp_load_spiral( * returns a serialise_result_t struct, which will contain information about * whether the operation was successful or not and information about what went * wrong if it was not successful + * + * Asserts: + * - That spiral.lines is not NULL + * - That buffer->bytes is NULL */ sxbp_serialise_result_t sxbp_dump_spiral( sxbp_spiral_t spiral, sxbp_buffer_t* buffer diff --git a/saxbospiral/solve.c b/saxbospiral/solve.c index a260e58..0f27568 100644 --- a/saxbospiral/solve.c +++ b/saxbospiral/solve.c @@ -22,6 +22,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +#include #include #include #include @@ -46,8 +47,17 @@ extern "C"{ * Returns boolean on whether or not the spiral collides or not. Also, sets the * collider field in the spiral struct to the index of the colliding line * (if any) + * + * Asserts: + * - That spiral->lines is not NULL + * - That spiral->co_ord_cache.co_ords.items is not NULL + * - That index is less than spiral->size */ static bool spiral_collides(sxbp_spiral_t* spiral, size_t index) { + // preconditional assertions + assert(spiral->lines != NULL); + assert(spiral->co_ord_cache.co_ords.items != NULL); + assert(index < spiral->size); /* * if there are less than 4 lines in the spiral, then there's no way it * can collide, so return false early @@ -115,10 +125,19 @@ static bool spiral_collides(sxbp_spiral_t* spiral, size_t index) { * NOTE: In the context of this function, 'rigid' or 'r' refers to the line that * the newly plotted line has collided with and 'previous' or 'p' refers to the * line before the newly plotted line. + * + * Asserts: + * - That spiral.lines is not NULL + * - That spiral.co_ord_cache.co_ords.items is not NULL + * - That index is less than spiral.size */ static sxbp_length_t suggest_resize( sxbp_spiral_t spiral, size_t index, int perfection_threshold ) { + // preconditional assertions + assert(spiral.lines != NULL); + assert(spiral.co_ord_cache.co_ords.items != NULL); + assert(index < spiral.size); // check if collides or not, return same size if no collision if(spiral.collides) { /* @@ -194,17 +213,24 @@ static sxbp_length_t suggest_resize( * aggressive optimisation) attempt to set the target line to that length, * back-tracking to resize the previous line if it collides. * returns a status struct (used for error information) + * + * Asserts: + * - That spiral->lines is not NULL + * - That index is less than spiral->size */ sxbp_status_t sxbp_resize_spiral( sxbp_spiral_t* spiral, uint64_t index, sxbp_length_t length, int perfection_threshold ) { + // preconditional assertions + assert(spiral->lines != NULL); + assert(index < spiral->size); /* * setup state variables, these are used in place of recursion for managing * state of which line is being resized, and what size it should be. */ // set result status - sxbp_status_t result = {{0, 0, 0}, 0}; + sxbp_status_t result; size_t current_index = index; sxbp_length_t current_length = length; while(true) { @@ -220,7 +246,7 @@ sxbp_status_t sxbp_resize_spiral( // update the spiral's co-ord cache, and catch any errors result = sxbp_cache_spiral_points(spiral, current_index + 1); // return if errors - if(result.diagnostic != SXBP_OPERATION_OK) { + if(result != SXBP_OPERATION_OK) { return result; } spiral->collides = spiral_collides(spiral, current_index); @@ -249,7 +275,7 @@ sxbp_status_t sxbp_resize_spiral( * Return OPERATION_OK from function. */ spiral->solved_count = index + 1; - result.diagnostic = SXBP_OPERATION_OK; + result = SXBP_OPERATION_OK; return result; } } @@ -273,6 +299,9 @@ sxbp_status_t sxbp_resize_spiral( * highest line that will be solved and a void pointer used for accessing the * user data. * returns a status struct (used for error information) + * + * Asserts: + * - That spiral->lines is not NULL */ sxbp_status_t sxbp_plot_spiral( sxbp_spiral_t* spiral, int perfection_threshold, uint64_t max_line, @@ -282,15 +311,17 @@ sxbp_status_t sxbp_plot_spiral( ), void* progress_callback_user_data ) { + // preconditional assertions + assert(spiral->lines != NULL); // set up result status - sxbp_status_t result = {{0, 0, 0}, 0}; + sxbp_status_t result; // get index of highest line to plot uint64_t max_index = (max_line > spiral->size) ? spiral->size : max_line; // calculate the length of each line within range solved_count -> max_index for(size_t i = spiral->solved_count; i < max_index; i++) { result = sxbp_resize_spiral(spiral, i, 1, perfection_threshold); // catch and return error if any - if(result.diagnostic != SXBP_OPERATION_OK) { + if(result != SXBP_OPERATION_OK) { return result; } // call callback if given @@ -299,7 +330,7 @@ sxbp_status_t sxbp_plot_spiral( } } // all ok - result.diagnostic = SXBP_OPERATION_OK; + result = SXBP_OPERATION_OK; return result; } diff --git a/saxbospiral/solve.h b/saxbospiral/solve.h index 5d3046d..0c8799b 100644 --- a/saxbospiral/solve.h +++ b/saxbospiral/solve.h @@ -41,6 +41,10 @@ extern "C"{ * aggressive optimisation) attempt to set the target line to that length, * back-tracking to resize the previous line if it collides. * returns a status struct (used for error information) + * + * Asserts: + * - That spiral->lines is not NULL + * - That index is less than spiral->size */ sxbp_status_t sxbp_resize_spiral( sxbp_spiral_t* spiral, uint64_t index, sxbp_length_t length, @@ -65,6 +69,9 @@ sxbp_status_t sxbp_resize_spiral( * highest line that will be solved and a void pointer used for accessing the * user data. * returns a status struct (used for error information) + * + * Asserts: + * - That spiral->lines is not NULL */ sxbp_status_t sxbp_plot_spiral( sxbp_spiral_t* spiral, int perfection_threshold, uint64_t max_line, diff --git a/tests.c b/tests.c index 9650e53..78f761c 100644 --- a/tests.c +++ b/tests.c @@ -73,7 +73,7 @@ bool test_sxbp_init_spiral() { } // call init_spiral with buffer and write to blank spiral - sxbp_spiral_t output; + sxbp_spiral_t output = sxbp_blank_spiral(); sxbp_init_spiral(buffer, &output); if(output.size != expected.size) { @@ -403,7 +403,7 @@ bool test_sxbp_load_spiral() { } // call load_spiral with buffer and write to output spiral - sxbp_spiral_t output; + sxbp_spiral_t output = sxbp_blank_spiral(); sxbp_load_spiral(buffer, &output); if(output.size != expected.size) { @@ -443,11 +443,11 @@ bool test_sxbp_load_spiral_rejects_missing_magic_number() { ); // call load_spiral with buffer and blank spiral, store result - sxbp_spiral_t output; + sxbp_spiral_t output = sxbp_blank_spiral(); sxbp_serialise_result_t serialise_result = sxbp_load_spiral(buffer, &output); if( - (serialise_result.status.diagnostic != SXBP_OPERATION_FAIL) || + (serialise_result.status != SXBP_OPERATION_FAIL) || (serialise_result.diagnostic != SXBP_DESERIALISE_BAD_MAGIC_NUMBER) ) { result = false; @@ -466,11 +466,11 @@ bool test_sxbp_load_spiral_rejects_too_small_for_header() { buffer.bytes = (uint8_t*)"SAXBOSPIRAL"; // call load_spiral with buffer and blank spiral, store result - sxbp_spiral_t output; + sxbp_spiral_t output = sxbp_blank_spiral(); sxbp_serialise_result_t serialise_result = sxbp_load_spiral(buffer, &output); if( - (serialise_result.status.diagnostic != SXBP_OPERATION_FAIL) || + (serialise_result.status != SXBP_OPERATION_FAIL) || (serialise_result.diagnostic != SXBP_DESERIALISE_BAD_HEADER_SIZE) ) { result = false; @@ -506,11 +506,11 @@ bool test_sxbp_load_spiral_rejects_too_small_data_section() { buffer.bytes[i+25] = data[i]; } // call load_spiral with buffer and blank spiral, store result - sxbp_spiral_t output; + sxbp_spiral_t output = sxbp_blank_spiral(); sxbp_serialise_result_t serialise_result = sxbp_load_spiral(buffer, &output); if( - (serialise_result.status.diagnostic != SXBP_OPERATION_FAIL) || + (serialise_result.status != SXBP_OPERATION_FAIL) || (serialise_result.diagnostic != SXBP_DESERIALISE_BAD_DATA_SIZE) ) { result = false; @@ -546,11 +546,11 @@ bool test_sxbp_load_spiral_rejects_wrong_version() { buffer.bytes[i+25] = data[i]; } // call load_spiral with buffer and blank spiral, store result - sxbp_spiral_t output; + sxbp_spiral_t output = sxbp_blank_spiral(); sxbp_serialise_result_t serialise_result = sxbp_load_spiral(buffer, &output); if( - (serialise_result.status.diagnostic != SXBP_OPERATION_FAIL) || + (serialise_result.status != SXBP_OPERATION_FAIL) || (serialise_result.diagnostic != SXBP_DESERIALISE_BAD_VERSION) ) { result = false; @@ -617,7 +617,7 @@ bool test_sxbp_dump_spiral() { } // call dump_spiral with spiral and write to output buffer - sxbp_buffer_t output; + sxbp_buffer_t output = { .size = 0, .bytes = NULL, }; sxbp_dump_spiral(input, &output); if(output.size != expected.size) {