From f8ac671e3a0b5c6ea36caa219a7fbb33d4edb82b Mon Sep 17 00:00:00 2001 From: doyle Date: Fri, 30 Jun 2023 21:30:31 +1000 Subject: [PATCH] perfaware/part2: Setup haversine parser task --- part2/haversine.c | 40 ++++ part2/haversine_generator.c | 196 +++++--------------- part2/{pap2_stdlib.c => haversine_stdlib.c} | 121 ++++++++---- part2/haversine_stdlib.h | 102 ++++++++++ part2/pap2_stdlib.h | 67 ------- 5 files changed, 268 insertions(+), 258 deletions(-) create mode 100644 part2/haversine.c rename part2/{pap2_stdlib.c => haversine_stdlib.c} (61%) create mode 100644 part2/haversine_stdlib.h delete mode 100644 part2/pap2_stdlib.h diff --git a/part2/haversine.c b/part2/haversine.c new file mode 100644 index 0000000..ad2b822 --- /dev/null +++ b/part2/haversine.c @@ -0,0 +1,40 @@ + +#include +#include +#include +#include +#include "haversine_stdlib.h" +#include "haversine_stdlib.c" +#include +#include "listing_0065_haversine_formula.cpp" + +#define PRINT_USAGE HAV_PrintLnFmt("Usage: %s [haversine_input.json] [answers.f64]", argv[0]) +int main(int argc, char **argv) +{ + // NOTE: Arg Parsing + // ========================================================================= + if (argc != 2 && argc != 3) { + PRINT_USAGE; + return -1; + } + + HAV_Str8 arg_json = {argv[1], strlen(argv[1])}; + HAV_Str8 arg_answers = {0}; + if (argc == 3) { + arg_answers = {.data = argv[2], .size = strlen(argv[2])}; + } + + size_t input_size = 0; + size_t pair_count = 0; + f64 haversine_sum = 0; + f64 reference_haversine_sum = 0; + f64 difference = 0; + HAV_PrintLnFmt("Input size: %zu", input_size); + HAV_PrintLnFmt("Pair count: %zu", pair_count); + HAV_PrintLnFmt("Haversine sum: %f", haversine_sum); + + HAV_PrintLn(HAV_STR8("Validation: ")); + HAV_PrintLnFmt("Reference sum: %f", reference_haversine_sum); + HAV_PrintLnFmt("Difference: %f", difference); + return 0; +} diff --git a/part2/haversine_generator.c b/part2/haversine_generator.c index 1dc2b96..568e3ce 100644 --- a/part2/haversine_generator.c +++ b/part2/haversine_generator.c @@ -3,154 +3,42 @@ #include #include #include -#include "pap2_stdlib.h" -#include "pap2_stdlib.c" +#include "haversine_stdlib.h" +#include "haversine_stdlib.c" #include +#include "listing_0065_haversine_formula.cpp" -typedef float f32; -typedef double f64; - -static f64 Square(f64 A) -{ - f64 Result = (A*A); - return Result; -} - -static f64 RadiansFromDegrees(f64 Degrees) -{ - f64 Result = 0.01745329251994329577 * Degrees; - return Result; -} - -// NOTE(casey): EarthRadius is generally expected to be 6372.8 -static f64 ReferenceHaversine(f64 X0, f64 Y0, f64 X1, f64 Y1, f64 EarthRadius) -{ - /* NOTE(casey): This is not meant to be a "good" way to calculate the Haversine distance. - Instead, it attempts to follow, as closely as possible, the formula used in the real-world - question on which these homework exercises are loosely based. - */ - - f64 lat1 = Y0; - f64 lat2 = Y1; - f64 lon1 = X0; - f64 lon2 = X1; - - f64 dLat = RadiansFromDegrees(lat2 - lat1); - f64 dLon = RadiansFromDegrees(lon2 - lon1); - lat1 = RadiansFromDegrees(lat1); - lat2 = RadiansFromDegrees(lat2); - - f64 a = Square(sin(dLat/2.0)) + cos(lat1)*cos(lat2)*Square(sin(dLon/2)); - f64 c = 2.0*asin(sqrt(a)); - - f64 Result = EarthRadius * c; - - return Result; -} - -bool PAP_CharIsWhiteSpace(char ch) -{ - bool result = ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; - return result; -} - -typedef struct PAP_Str8ToU64Result { - bool success; - uint64_t value; -} PAP_Str8ToU64Result; - -PAP_Str8ToU64Result PAP_Str8_ToU64(PAP_Str8 string) -{ - PAP_Str8ToU64Result result = {0}; - - size_t ch_index = 0; - while (ch_index < string.size && PAP_CharIsWhiteSpace(string.data[ch_index])) - ch_index++; - - for (; ch_index < string.size; ch_index++) { - char ch = string.data[ch_index]; - if (ch >= '0' && ch <= '9') { - result.value = (result.value * 10) + (ch - '0'); - } else { - return result; - } - } - - result.success = true; - return result; -} - -// NOTE: PCG RNG from Demetri Spanos: https://github.com/demetri/scribbles -// pcg32_pie, based on the minimal C version from O'Neill at pcg-random.org; -// I've made a few (subjective) UX improvements for beginner use -// -// I'm not allowing the user to pick the stream/increment constant at all, -// since there is almost never a reason for doing this in common applications. -// This means that the prng state is reduced to a single uint64_t which also -// means we can avoid having a state struct at all. The (fixed) stream constant -// uses the leading hex digits of pi and e multipled by 2^30 (c90fdaa2 and -// adf85459). -// -// I have also added an XOR with the same digits on the output path prior -// to xorshift mixing. This prevents the "surprising" result that the -// first "random 32-bit number" from a (very common) 0 seed is 0. -// -// use: -// uint64_t state = 12345; // whatever you like can go here -// uint32_t some_random_32_bits = pcg32_pie(&state); -// uint32_t more_random_32_bits = pcg32_pie(&state); - -#pragma warning(push) -#pragma warning(disable: 4146) // warning C4146: unary minus operator applied to unsigned type, result still unsigned -uint32_t PAP_PCG32_Pie (uint64_t *state) -{ - uint64_t old = *state ^ 0xc90fdaa2adf85459ULL; - *state = *state * 6364136223846793005ULL + 0xc90fdaa2adf85459ULL; - uint32_t xorshifted = (uint32_t)(((old >> 18u) ^ old) >> 27u); - uint32_t rot = old >> 59u; - return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); -} -#pragma warning(pop) - -f64 PAP_PCG32_PieF64(uint64_t *state, f64 min, f64 max) -{ - uint32_t u32_value = PAP_PCG32_Pie(state); - f64 t01 = PAP_CAST(f64)u32_value / PAP_CAST(f64)PAP_CAST(uint32_t)-1; - f64 result = min + (max - min) * t01; - return result; -} - -#define PRINT_USAGE PAP_PrintLnFmt("Usage: %s [uniform/cluster] [random seed] [number of coordinate pairs to generate]", argv[0]) +#define PRINT_USAGE HAV_PrintLnFmt("Usage: %s [uniform/cluster] [random seed] [number of coordinate pairs to generate]", argv[0]) int main(int argc, char **argv) { // NOTE: Unit Tests // ========================================================================= { { - PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("00")); - PAP_ASSERT(result.success); - PAP_ASSERT(result.value == 0); + HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("00")); + HAV_ASSERT(result.success); + HAV_ASSERT(result.value == 0); } { - PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("+100")); - PAP_ASSERT(!result.success); + HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("+100")); + HAV_ASSERT(!result.success); } { - PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("100,0")); - PAP_ASSERT(!result.success); + HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("100,0")); + HAV_ASSERT(!result.success); } { - PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("100a")); - PAP_ASSERT(!result.success); + HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("100a")); + HAV_ASSERT(!result.success); } { - PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("3147")); - PAP_ASSERT(result.success); - PAP_ASSERT(result.value == 3147); + HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("3147")); + HAV_ASSERT(result.success); + HAV_ASSERT(result.value == 3147); } } @@ -161,9 +49,9 @@ int main(int argc, char **argv) return -1; } - PAP_Str8 arg_uniform_cluster = {argv[1], strlen(argv[1])}; - PAP_Str8 arg_random_seed = {argv[2], strlen(argv[2])}; - PAP_Str8 arg_number_of_coordinate_pairs_to_generate = {argv[3], strlen(argv[3])}; + HAV_Str8 arg_uniform_cluster = {argv[1], strlen(argv[1])}; + HAV_Str8 arg_random_seed = {argv[2], strlen(argv[2])}; + HAV_Str8 arg_number_of_coordinate_pairs_to_generate = {argv[3], strlen(argv[3])}; typedef enum PointGenerator { PointGenerator_Invalid, @@ -171,13 +59,13 @@ int main(int argc, char **argv) PointGenerator_Cluster, } PointGenerator; - PAP_Str8ToU64Result random_seed_u64_result = PAP_Str8_ToU64(arg_random_seed); - PAP_Str8ToU64Result number_of_coordinate_pairs_to_generate_u64_result = PAP_Str8_ToU64(arg_number_of_coordinate_pairs_to_generate); + HAV_Str8ToU64Result random_seed_u64_result = HAV_Str8_ToU64(arg_random_seed); + HAV_Str8ToU64Result number_of_coordinate_pairs_to_generate_u64_result = HAV_Str8_ToU64(arg_number_of_coordinate_pairs_to_generate); PointGenerator point_generator = PointGenerator_Invalid; - if (PAP_Str8_Equals(arg_uniform_cluster, PAP_STR8("uniform"))) { + if (HAV_Str8_Equals(arg_uniform_cluster, HAV_STR8("uniform"))) { point_generator = PointGenerator_Uniform; - } else if (PAP_Str8_Equals(arg_uniform_cluster, PAP_STR8("cluster"))) { + } else if (HAV_Str8_Equals(arg_uniform_cluster, HAV_STR8("cluster"))) { point_generator = PointGenerator_Cluster; } else { PRINT_USAGE; @@ -185,20 +73,20 @@ int main(int argc, char **argv) } if (!random_seed_u64_result.success) { - PAP_PrintLnFmt("Random seed was not a valid U64 value [seed=%.*s]", PAP_STR8_FMT(arg_random_seed)); + HAV_PrintLnFmt("Random seed was not a valid U64 value [seed=%.*s]", HAV_STR8_FMT(arg_random_seed)); PRINT_USAGE; return -1; } if (!number_of_coordinate_pairs_to_generate_u64_result.success) { - PAP_PrintLnFmt("Number of coordinate pairs to generate was not a valid U64 value [seed=%.*s]", PAP_STR8_FMT(arg_number_of_coordinate_pairs_to_generate)); + HAV_PrintLnFmt("Number of coordinate pairs to generate was not a valid U64 value [seed=%.*s]", HAV_STR8_FMT(arg_number_of_coordinate_pairs_to_generate)); PRINT_USAGE; return -1; } uint32_t const MAX_COORD_PAIRS = 100'000'000; if (number_of_coordinate_pairs_to_generate_u64_result.value > MAX_COORD_PAIRS) { - PAP_PrintLnFmt("Maximum number of coordinate pairs exceeded, exiting to avoid accidental large files [requested=%zu, max=%zu]", + HAV_PrintLnFmt("Maximum number of coordinate pairs exceeded, exiting to avoid accidental large files [requested=%zu, max=%zu]", number_of_coordinate_pairs_to_generate_u64_result.value, MAX_COORD_PAIRS); PRINT_USAGE; @@ -239,7 +127,7 @@ int main(int argc, char **argv) char tmp_buffer[128]; f64 expected_sum = 0; - PAP_PrintHandle(haversine_json_file_handle, PAP_STR8("{\"pairs\":[\n")); + HAV_PrintHandle(haversine_json_file_handle, HAV_STR8("{\"pairs\":[\n")); f64 const sum_coefficient = 1.0 / point_count; f64 point_centre = 0; @@ -247,33 +135,33 @@ int main(int argc, char **argv) f64 point_max_offset = LAT_LON_MAX; for (int index = 0; index < point_count; index++) { if (point_generator == PointGenerator_Cluster && (index % points_per_cluster) == 0) { - point_centre = PAP_PCG32_PieF64(&rng_state, LAT_LON_MIN, LAT_LON_MAX); - point_min_offset = -PAP_PCG32_PieF64(&rng_state, 0, 45); + point_centre = HAV_PCG32_PieF64(&rng_state, LAT_LON_MIN, LAT_LON_MAX); + point_min_offset = -HAV_PCG32_PieF64(&rng_state, 0, 45); point_max_offset = -point_min_offset; } - f64 x0 = point_centre + PAP_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); - f64 y0 = point_centre + PAP_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); - f64 x1 = point_centre + PAP_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); - f64 y1 = point_centre + PAP_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); + f64 x0 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); + f64 y0 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); + f64 x1 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); + f64 y1 = point_centre + HAV_PCG32_PieF64(&rng_state, point_min_offset, point_max_offset); f64 haversine_dist = ReferenceHaversine(x0, y0, x1, y1, /*EarthRadius*/ 6372.8); - PAP_PrintHandle(haversine_f64_file_handle, (PAP_Str8){.data = (char *)&haversine_dist, .size = sizeof(haversine_dist)}); + HAV_PrintHandle(haversine_f64_file_handle, (HAV_Str8){.data = (char *)&haversine_dist, .size = sizeof(haversine_dist)}); expected_sum += (sum_coefficient * haversine_dist); size_t json_line_size = snprintf(tmp_buffer, sizeof(tmp_buffer), " {\"x0\": %f, \"y0\": %f, \"x1\": %f, \"y1\": %f}%s\n", x0, y0, x1, y1, (index == (point_count - 1) ? "" : ",")); - PAP_ASSERT(json_line_size < sizeof(tmp_buffer)); - PAP_PrintHandle(haversine_json_file_handle, (PAP_Str8){.data = tmp_buffer, .size = json_line_size}); + HAV_ASSERT(json_line_size < sizeof(tmp_buffer)); + HAV_PrintHandle(haversine_json_file_handle, (HAV_Str8){.data = tmp_buffer, .size = json_line_size}); } - PAP_PrintHandle(haversine_json_file_handle, PAP_STR8("]}\n")); - PAP_PrintHandle(haversine_f64_file_handle, (PAP_Str8){.data = (char *)&expected_sum, .size = sizeof(expected_sum)}); + HAV_PrintHandle(haversine_json_file_handle, HAV_STR8("]}\n")); + HAV_PrintHandle(haversine_f64_file_handle, (HAV_Str8){.data = (char *)&expected_sum, .size = sizeof(expected_sum)}); CloseHandle(haversine_json_file_handle); CloseHandle(haversine_f64_file_handle); - PAP_PrintLnFmt("Method: %s", (point_generator == PointGenerator_Uniform ? "uniform" : "cluster")); - PAP_PrintLnFmt("Seed: %zu", random_seed); - PAP_PrintLnFmt("Pair Count: %zu", point_count); - PAP_PrintLnFmt("Expected Sum: %f", expected_sum); + HAV_PrintLnFmt("Method: %s", (point_generator == PointGenerator_Uniform ? "uniform" : "cluster")); + HAV_PrintLnFmt("Seed: %zu", random_seed); + HAV_PrintLnFmt("Pair Count: %zu", point_count); + HAV_PrintLnFmt("Expected Sum: %f", expected_sum); return 0; } diff --git a/part2/pap2_stdlib.c b/part2/haversine_stdlib.c similarity index 61% rename from part2/pap2_stdlib.c rename to part2/haversine_stdlib.c index 0e48a6a..91bc9d3 100644 --- a/part2/pap2_stdlib.c +++ b/part2/haversine_stdlib.c @@ -1,49 +1,96 @@ // NOTE: Implementation // ============================================================================ -bool PAP_Str8_Equals(PAP_Str8 lhs, PAP_Str8 rhs) +bool HAV_Str8_Equals(HAV_Str8 lhs, HAV_Str8 rhs) { bool result = lhs.size == rhs.size && memcmp(lhs.data, rhs.data, lhs.size) == 0; return result; } -bool PAP_BufferIsValid(PAP_Buffer buffer) +HAV_Str8ToU64Result HAV_Str8_ToU64(HAV_Str8 string) +{ + HAV_Str8ToU64Result result = {0}; + + size_t ch_index = 0; + while (ch_index < string.size && HAV_CharIsWhiteSpace(string.data[ch_index])) + ch_index++; + + for (; ch_index < string.size; ch_index++) { + char ch = string.data[ch_index]; + if (ch >= '0' && ch <= '9') { + result.value = (result.value * 10) + (ch - '0'); + } else { + return result; + } + } + + result.success = true; + return result; +} + +bool HAV_CharIsWhiteSpace(char ch) +{ + bool result = ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; + return result; +} + +#pragma warning(push) +#pragma warning(disable: 4146) // warning C4146: unary minus operator applied to unsigned type, result still unsigned +uint32_t HAV_PCG32_Pie (uint64_t *state) +{ + uint64_t old = *state ^ 0xc90fdaa2adf85459ULL; + *state = *state * 6364136223846793005ULL + 0xc90fdaa2adf85459ULL; + uint32_t xorshifted = (uint32_t)(((old >> 18u) ^ old) >> 27u); + uint32_t rot = old >> 59u; + return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); +} +#pragma warning(pop) + +f64 HAV_PCG32_PieF64(uint64_t *state, f64 min, f64 max) +{ + uint32_t u32_value = HAV_PCG32_Pie(state); + f64 t01 = HAV_CAST(f64)u32_value / HAV_CAST(f64)HAV_CAST(uint32_t)-1; + f64 result = min + (max - min) * t01; + return result; +} + +bool HAV_BufferIsValid(HAV_Buffer buffer) { bool result = buffer.data && buffer.size; return result; } -PAP_BufferIterator PAP_BufferIteratorInit(PAP_Buffer buffer) +HAV_BufferIterator HAV_BufferIteratorInit(HAV_Buffer buffer) { - PAP_BufferIterator result = {0}; + HAV_BufferIterator result = {0}; result.buffer = buffer; return result; } -bool PAP_BufferIteratorHasMoreBytes(PAP_BufferIterator it) +bool HAV_BufferIteratorHasMoreBytes(HAV_BufferIterator it) { - bool result = PAP_BufferIsValid(it.buffer) && it.index < it.buffer.size; + bool result = HAV_BufferIsValid(it.buffer) && it.index < it.buffer.size; return result; } -uint8_t PAP_BufferIteratorPeekByte(PAP_BufferIterator *it) +uint8_t HAV_BufferIteratorPeekByte(HAV_BufferIterator *it) { - PAP_ASSERT(it); - PAP_ASSERT(PAP_BufferIsValid(it->buffer)); - PAP_ASSERT(it->index < it->buffer.size); + HAV_ASSERT(it); + HAV_ASSERT(HAV_BufferIsValid(it->buffer)); + HAV_ASSERT(it->index < it->buffer.size); uint8_t result = it->buffer.data[it->index]; return result; } -uint8_t PAP_BufferIteratorNextByte(PAP_BufferIterator *it) +uint8_t HAV_BufferIteratorNextByte(HAV_BufferIterator *it) { - uint8_t result = PAP_BufferIteratorPeekByte(it); + uint8_t result = HAV_BufferIteratorPeekByte(it); it->index++; return result; } -PAP_Buffer PAP_FileRead(char const *file_path) +HAV_Buffer HAV_FileRead(char const *file_path) { - PAP_Buffer result = {0}; + HAV_Buffer result = {0}; // NOTE: Determine file size // ========================================================================= @@ -69,7 +116,7 @@ PAP_Buffer PAP_FileRead(char const *file_path) // NOTE: Allocate buffer // ========================================================================= uint64_t file_size = (uint64_t)file_attrib_data.nFileSizeHigh << 32 | (uint64_t)file_attrib_data.nFileSizeLow << 0; - PAP_ASSERT(file_size < (DWORD)-1); + HAV_ASSERT(file_size < (DWORD)-1); char *buffer = VirtualAlloc( /*LPVOID lpAddress*/ NULL, /*SIZE_T dwSize*/ file_size, @@ -86,7 +133,7 @@ PAP_Buffer PAP_FileRead(char const *file_path) BOOL read_file_result = ReadFile( /*HANDLE hFile*/ file_handle, /*LPVOID lpBuffer*/ buffer, - /*DWORD nNumberOfBytesToRead*/ PAP_CAST(DWORD)file_size, + /*DWORD nNumberOfBytesToRead*/ HAV_CAST(DWORD)file_size, /*LPDWORD lpNumberOfBytesRead*/ &bytes_read, /*LPOVERLAPPED lpOverlapped*/ NULL ); @@ -105,13 +152,13 @@ end: return result; }; -void PAP_FileFree(PAP_Buffer buffer) +void HAV_FileFree(HAV_Buffer buffer) { - if (PAP_BufferIsValid(buffer)) + if (HAV_BufferIsValid(buffer)) VirtualFree(buffer.data, 0, MEM_RELEASE); } -bool PAP_FileWrite(char const *file_path, void const *buffer, size_t buffer_size) +bool HAV_FileWrite(char const *file_path, void const *buffer, size_t buffer_size) { bool result = false; @@ -136,25 +183,25 @@ bool PAP_FileWrite(char const *file_path, void const *buffer, size_t buffer_size BOOL write_file_result = WriteFile( /*HANDLE hFile*/ file_handle, /*LPVOID lpBuffer*/ buffer, - /*DWORD nNumberOfBytesToWrite*/ PAP_CAST(DWORD)buffer_size, + /*DWORD nNumberOfBytesToWrite*/ HAV_CAST(DWORD)buffer_size, /*LPDWORD lpNumberOfBytesWrite*/ &bytes_written, /*LPOVERLAPPED lpOverlapped*/ NULL ); - PAP_ASSERT(bytes_written == buffer_size); + HAV_ASSERT(bytes_written == buffer_size); result = write_file_result && bytes_written == buffer_size; CloseHandle(file_handle); return result; }; -void PAP_PrintHandle(void *handle, PAP_Str8 string) +void HAV_PrintHandle(void *handle, HAV_Str8 string) { DWORD bytes_written = 0; - WriteFile(handle, string.data, PAP_CAST(DWORD)string.size, &bytes_written, NULL); + WriteFile(handle, string.data, HAV_CAST(DWORD)string.size, &bytes_written, NULL); (void)bytes_written; } -void PAP_Print(PAP_Str8 string) +void HAV_Print(HAV_Str8 string) { if (pap_globals.stdout_handle == NULL) { pap_globals.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); @@ -167,16 +214,16 @@ void PAP_Print(PAP_Str8 string) } - PAP_ASSERT(string.size < PAP_CAST(DWORD)-1); + HAV_ASSERT(string.size < HAV_CAST(DWORD)-1); if (pap_globals.write_to_console) { DWORD chars_written = 0; WriteConsoleA(pap_globals.stdout_handle, string.data, (DWORD)string.size, &chars_written, NULL); } else { - PAP_PrintHandle(pap_globals.stdout_handle, string); + HAV_PrintHandle(pap_globals.stdout_handle, string); } } -void PAP_PrintFmt(char const *fmt, ...) +void HAV_PrintFmt(char const *fmt, ...) { va_list args, args_copy; va_start(args, fmt); @@ -186,23 +233,23 @@ void PAP_PrintFmt(char const *fmt, ...) va_end(args_copy); char buffer[8192]; - PAP_ASSERT(string_size >= 0 && string_size < PAP_ARRAY_UCOUNT(buffer)); + HAV_ASSERT(string_size >= 0 && string_size < HAV_ARRAY_UCOUNT(buffer)); if (string_size) { vsnprintf(buffer, sizeof(buffer), fmt, args); - PAP_Str8 string = {.data = buffer, .size = string_size}; - PAP_Print(string); + HAV_Str8 string = {.data = buffer, .size = string_size}; + HAV_Print(string); } va_end(args); } -void PAP_PrintLn(PAP_Str8 string) +void HAV_PrintLn(HAV_Str8 string) { - PAP_Print(string); - PAP_Print(PAP_STR8("\n")); + HAV_Print(string); + HAV_Print(HAV_STR8("\n")); } -void PAP_PrintLnFmt(char const *fmt, ...) +void HAV_PrintLnFmt(char const *fmt, ...) { va_list args, args_copy; va_start(args, fmt); @@ -212,11 +259,11 @@ void PAP_PrintLnFmt(char const *fmt, ...) va_end(args_copy); char buffer[8192]; - PAP_ASSERT(string_size >= 0 && string_size < PAP_ARRAY_UCOUNT(buffer)); + HAV_ASSERT(string_size >= 0 && string_size < HAV_ARRAY_UCOUNT(buffer)); if (string_size) { vsnprintf(buffer, sizeof(buffer), fmt, args); - PAP_Str8 string = {.data = buffer, .size = string_size}; - PAP_PrintLn(string); + HAV_Str8 string = {.data = buffer, .size = string_size}; + HAV_PrintLn(string); } va_end(args); diff --git a/part2/haversine_stdlib.h b/part2/haversine_stdlib.h new file mode 100644 index 0000000..858fc90 --- /dev/null +++ b/part2/haversine_stdlib.h @@ -0,0 +1,102 @@ +// NOTE: Macros +// ============================================================================ +#define HAV_STRINGIFY2(token) #token +#define HAV_STRINGIFY(token) HAV_STRINGIFY2(token) + +#if defined(NDEBUG) + #define HAV_ASSERT(expr) +#else + #define HAV_ASSERT(expr) \ + if (!(expr)) { \ + HAV_PrintLnFmt("Assertion triggered [file=\"" __FILE__ ":" HAV_STRINGIFY(__LINE__) "\", expr=\"" #expr "\"]"); \ + __debugbreak(); \ + } +#endif + +#define HAV_ARRAY_UCOUNT(array) sizeof((array)) / sizeof((array)[0]) +#define HAV_CAST(Type) (Type) + +typedef float f32; +typedef double f64; + +// NOTE: Globals +// ============================================================================ +typedef struct HAV_Globals { + HANDLE stdout_handle; + bool write_to_console; +} HAV_Globals; + +HAV_Globals pap_globals; + +// NOTE: Strings +// ============================================================================ +typedef struct HAV_Str8 { + char *data; + size_t size; +} HAV_Str8; + +typedef struct HAV_Str8ToU64Result { + bool success; + uint64_t value; +} HAV_Str8ToU64Result; + +#define HAV_STR8(string) (HAV_Str8){.data = (string), .size = HAV_ARRAY_UCOUNT(string) - 1 } +#define HAV_STR8_FMT(string) (int)((string).size), (string).data + +bool HAV_Str8_Equals(HAV_Str8 lhs, HAV_Str8 rhs); +HAV_Str8ToU64Result HAV_Str8_ToU64(HAV_Str8 string); + +bool HAV_CharIsWhiteSpace(char ch); + +// NOTE: PCG32 +// ============================================================================ +// NOTE: PCG RNG from Demetri Spanos: https://github.com/demetri/scribbles +// pcg32_pie, based on the minimal C version from O'Neill at pcg-random.org; +// I've made a few (subjective) UX improvements for beginner use +// +// I'm not allowing the user to pick the stream/increment constant at all, +// since there is almost never a reason for doing this in common applications. +// This means that the prng state is reduced to a single uint64_t which also +// means we can avoid having a state struct at all. The (fixed) stream constant +// uses the leading hex digits of pi and e multipled by 2^30 (c90fdaa2 and +// adf85459). +// +// I have also added an XOR with the same digits on the output path prior +// to xorshift mixing. This prevents the "surprising" result that the +// first "random 32-bit number" from a (very common) 0 seed is 0. +// +// use: +// uint64_t state = 12345; // whatever you like can go here +// uint32_t some_random_32_bits = pcg32_pie(&state); +// uint32_t more_random_32_bits = pcg32_pie(&state); +uint32_t HAV_PCG32_Pie (uint64_t *state); +f64 HAV_PCG32_PieF64(uint64_t *state, f64 min, f64 max); + +// NOTE: Buffer +// ============================================================================ +typedef struct HAV_Buffer { + char *data; + size_t size; +} HAV_Buffer; + +typedef struct HAV_BufferIterator { + HAV_Buffer buffer; + size_t index; +} HAV_BufferIterator; + +bool HAV_BufferIsValid (HAV_Buffer buffer); +HAV_BufferIterator HAV_BufferIteratorInit (HAV_Buffer buffer); +bool HAV_BufferIteratorHasMoreBytes(HAV_BufferIterator it); +uint8_t HAV_BufferIteratorNextByte (HAV_BufferIterator *it); + +// NOTE: File +// ============================================================================ +HAV_Buffer HAV_FileRead (char const *file_path); +void HAV_FileFree (HAV_Buffer buffer); +bool HAV_FileWrite(char const *file_path, void const *buffer, size_t buffer_size); + +// NOTE: Print +// ============================================================================ +void HAV_PrintHandle(void *handle, HAV_Str8 string); +void HAV_PrintLn (HAV_Str8 string); +void HAV_PrintLnFmt (char const *fmt, ...); diff --git a/part2/pap2_stdlib.h b/part2/pap2_stdlib.h deleted file mode 100644 index 8f331c0..0000000 --- a/part2/pap2_stdlib.h +++ /dev/null @@ -1,67 +0,0 @@ -// NOTE: Macros -// ============================================================================ -#define PAP_STRINGIFY2(token) #token -#define PAP_STRINGIFY(token) PAP_STRINGIFY2(token) - -#if defined(NDEBUG) - #define PAP_ASSERT(expr) -#else - #define PAP_ASSERT(expr) \ - if (!(expr)) { \ - PAP_PrintLnFmt("Assertion triggered [file=\"" __FILE__ ":" PAP_STRINGIFY(__LINE__) "\", expr=\"" #expr "\"]"); \ - __debugbreak(); \ - } -#endif - -#define PAP_ARRAY_UCOUNT(array) sizeof((array)) / sizeof((array)[0]) -#define PAP_CAST(Type) (Type) - -// NOTE: Globals -// ============================================================================ -typedef struct PAP_Globals { - HANDLE stdout_handle; - bool write_to_console; -} PAP_Globals; - -PAP_Globals pap_globals; - -// NOTE: Strings -// ============================================================================ -typedef struct PAP_Str8 { - char *data; - size_t size; -} PAP_Str8; - -#define PAP_STR8(string) (PAP_Str8){.data = (string), .size = PAP_ARRAY_UCOUNT(string) - 1 } -#define PAP_STR8_FMT(string) (int)((string).size), (string).data - -bool PAP_Str8_Equals(PAP_Str8 lhs, PAP_Str8 rhs); - -// NOTE: Buffer -// ============================================================================ -typedef struct PAP_Buffer { - char *data; - size_t size; -} PAP_Buffer; - -typedef struct PAP_BufferIterator { - PAP_Buffer buffer; - size_t index; -} PAP_BufferIterator; - -bool PAP_BufferIsValid (PAP_Buffer buffer); -PAP_BufferIterator PAP_BufferIteratorInit (PAP_Buffer buffer); -bool PAP_BufferIteratorHasMoreBytes(PAP_BufferIterator it); -uint8_t PAP_BufferIteratorNextByte (PAP_BufferIterator *it); - -// NOTE: File -// ============================================================================ -PAP_Buffer PAP_FileRead (char const *file_path); -void PAP_FileFree (PAP_Buffer buffer); -bool PAP_FileWrite(char const *file_path, void const *buffer, size_t buffer_size); - -// NOTE: Print -// ============================================================================ -void PAP_PrintHandle(void *handle, PAP_Str8 string); -void PAP_PrintLn (PAP_Str8 string); -void PAP_PrintLnFmt (char const *fmt, ...);