From 7dfd1b1927fc5255f0de0dd55d2944395676531b Mon Sep 17 00:00:00 2001 From: doyle Date: Mon, 26 Jun 2023 23:51:45 +1000 Subject: [PATCH] perfaware/part2: Write the haversine input generator --- build.bat | 3 +- part2/haversine_generator.c | 279 ++++++++++++++++++++++++++++++++++++ part2/main.c | 55 ------- part2/pap2_stdlib.c | 90 ++++++------ part2/pap2_stdlib.h | 68 +++++---- 5 files changed, 366 insertions(+), 129 deletions(-) create mode 100644 part2/haversine_generator.c delete mode 100644 part2/main.c diff --git a/build.bat b/build.bat index ff71a8c..0dbfe51 100644 --- a/build.bat +++ b/build.bat @@ -319,5 +319,6 @@ REM Part 2 ===================================================================== REM Build ========================================================================================== :part2 pushd %part2_build_dir% -cl %part2_dir%\main.c /W4 /WX /Z7 /nologo || exit /b 1 +cl %part2_dir%\haversine_generator.c /W4 /WX /Z7 /nologo /Fe:haversine_generator_debug || exit /b 1 +cl %part2_dir%\haversine_generator.c /W4 /WX /Z7 /nologo /O2 /Fe:haversine_generator_release || exit /b 1 popd diff --git a/part2/haversine_generator.c b/part2/haversine_generator.c new file mode 100644 index 0000000..1dc2b96 --- /dev/null +++ b/part2/haversine_generator.c @@ -0,0 +1,279 @@ + +#include +#include +#include +#include +#include "pap2_stdlib.h" +#include "pap2_stdlib.c" +#include + +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]) +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); + } + + { + PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("+100")); + PAP_ASSERT(!result.success); + } + + { + PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("100,0")); + PAP_ASSERT(!result.success); + } + + { + PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("100a")); + PAP_ASSERT(!result.success); + } + + { + PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("3147")); + PAP_ASSERT(result.success); + PAP_ASSERT(result.value == 3147); + } + } + + // NOTE: Arg Parsing + // ========================================================================= + if (argc != 4) { + PRINT_USAGE; + 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])}; + + typedef enum PointGenerator { + PointGenerator_Invalid, + PointGenerator_Uniform, + 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); + PointGenerator point_generator = PointGenerator_Invalid; + + if (PAP_Str8_Equals(arg_uniform_cluster, PAP_STR8("uniform"))) { + point_generator = PointGenerator_Uniform; + } else if (PAP_Str8_Equals(arg_uniform_cluster, PAP_STR8("cluster"))) { + point_generator = PointGenerator_Cluster; + } else { + PRINT_USAGE; + return -1; + } + + if (!random_seed_u64_result.success) { + PAP_PrintLnFmt("Random seed was not a valid U64 value [seed=%.*s]", PAP_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)); + 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]", + number_of_coordinate_pairs_to_generate_u64_result.value, + MAX_COORD_PAIRS); + PRINT_USAGE; + return -1; + } + + // NOTE: Generator + // ========================================================================= + uint64_t point_count = number_of_coordinate_pairs_to_generate_u64_result.value; + uint64_t random_seed = random_seed_u64_result.value; + uint64_t rng_state = random_seed; + + HANDLE haversine_json_file_handle = CreateFile( + /*LPCSTR lpFileName*/ "haversine.json", + /*DWORD dwDesiredAccess*/ GENERIC_WRITE, + /*DWORD dwShareMode*/ 0, + /*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ NULL, + /*DWORD dwCreationDisposition*/ CREATE_ALWAYS, + /*DWORD dwFlagsAndAttributes*/ 0, + /*HANDLE hTemplateFile*/ NULL + ); + + HANDLE haversine_f64_file_handle = CreateFile( + /*LPCSTR lpFileName*/ "haversine.f64", + /*DWORD dwDesiredAccess*/ GENERIC_WRITE, + /*DWORD dwShareMode*/ 0, + /*LPSECURITY_ATTRIBUTES lpSecurityAttributes*/ NULL, + /*DWORD dwCreationDisposition*/ CREATE_ALWAYS, + /*DWORD dwFlagsAndAttributes*/ 0, + /*HANDLE hTemplateFile*/ NULL + ); + + f64 const LAT_LON_MIN = -180.0; + f64 const LAT_LON_MAX = 180.0; + + uint64_t const MAX_CLUSTERS = 64; + uint64_t const points_per_cluster = point_count / MAX_CLUSTERS; + + char tmp_buffer[128]; + f64 expected_sum = 0; + PAP_PrintHandle(haversine_json_file_handle, PAP_STR8("{\"pairs\":[\n")); + + f64 const sum_coefficient = 1.0 / point_count; + f64 point_centre = 0; + f64 point_min_offset = LAT_LON_MIN; + 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_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 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)}); + 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}); + } + 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)}); + + 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); + return 0; +} diff --git a/part2/main.c b/part2/main.c deleted file mode 100644 index d5afed4..0000000 --- a/part2/main.c +++ /dev/null @@ -1,55 +0,0 @@ - -#include -#include -#include -#include -#include "pap2_stdlib.h" -#include "pap2_stdlib.c" -#include - -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; -} - -int main(int argc, char **argv) -{ - (void)argc; - (void)argv; - return 0; -} diff --git a/part2/pap2_stdlib.c b/part2/pap2_stdlib.c index d3bc66f..0e48a6a 100644 --- a/part2/pap2_stdlib.c +++ b/part2/pap2_stdlib.c @@ -1,49 +1,49 @@ // NOTE: Implementation // ============================================================================ -bool S86_Str8_Equals(S86_Str8 lhs, S86_Str8 rhs) +bool PAP_Str8_Equals(PAP_Str8 lhs, PAP_Str8 rhs) { bool result = lhs.size == rhs.size && memcmp(lhs.data, rhs.data, lhs.size) == 0; return result; } -bool S86_BufferIsValid(S86_Buffer buffer) +bool PAP_BufferIsValid(PAP_Buffer buffer) { bool result = buffer.data && buffer.size; return result; } -S86_BufferIterator S86_BufferIteratorInit(S86_Buffer buffer) +PAP_BufferIterator PAP_BufferIteratorInit(PAP_Buffer buffer) { - S86_BufferIterator result = {0}; + PAP_BufferIterator result = {0}; result.buffer = buffer; return result; } -bool S86_BufferIteratorHasMoreBytes(S86_BufferIterator it) +bool PAP_BufferIteratorHasMoreBytes(PAP_BufferIterator it) { - bool result = S86_BufferIsValid(it.buffer) && it.index < it.buffer.size; + bool result = PAP_BufferIsValid(it.buffer) && it.index < it.buffer.size; return result; } -uint8_t S86_BufferIteratorPeekByte(S86_BufferIterator *it) +uint8_t PAP_BufferIteratorPeekByte(PAP_BufferIterator *it) { - S86_ASSERT(it); - S86_ASSERT(S86_BufferIsValid(it->buffer)); - S86_ASSERT(it->index < it->buffer.size); + PAP_ASSERT(it); + PAP_ASSERT(PAP_BufferIsValid(it->buffer)); + PAP_ASSERT(it->index < it->buffer.size); uint8_t result = it->buffer.data[it->index]; return result; } -uint8_t S86_BufferIteratorNextByte(S86_BufferIterator *it) +uint8_t PAP_BufferIteratorNextByte(PAP_BufferIterator *it) { - uint8_t result = S86_BufferIteratorPeekByte(it); + uint8_t result = PAP_BufferIteratorPeekByte(it); it->index++; return result; } -S86_Buffer S86_FileRead(char const *file_path) +PAP_Buffer PAP_FileRead(char const *file_path) { - S86_Buffer result = {0}; + PAP_Buffer result = {0}; // NOTE: Determine file size // ========================================================================= @@ -69,7 +69,7 @@ S86_Buffer S86_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; - S86_ASSERT(file_size < (DWORD)-1); + PAP_ASSERT(file_size < (DWORD)-1); char *buffer = VirtualAlloc( /*LPVOID lpAddress*/ NULL, /*SIZE_T dwSize*/ file_size, @@ -86,7 +86,7 @@ S86_Buffer S86_FileRead(char const *file_path) BOOL read_file_result = ReadFile( /*HANDLE hFile*/ file_handle, /*LPVOID lpBuffer*/ buffer, - /*DWORD nNumberOfBytesToRead*/ S86_CAST(DWORD)file_size, + /*DWORD nNumberOfBytesToRead*/ PAP_CAST(DWORD)file_size, /*LPDWORD lpNumberOfBytesRead*/ &bytes_read, /*LPOVERLAPPED lpOverlapped*/ NULL ); @@ -105,13 +105,13 @@ end: return result; }; -void S86_FileFree(S86_Buffer buffer) +void PAP_FileFree(PAP_Buffer buffer) { - if (S86_BufferIsValid(buffer)) + if (PAP_BufferIsValid(buffer)) VirtualFree(buffer.data, 0, MEM_RELEASE); } -bool S86_FileWrite(char const *file_path, void const *buffer, size_t buffer_size) +bool PAP_FileWrite(char const *file_path, void const *buffer, size_t buffer_size) { bool result = false; @@ -136,41 +136,47 @@ bool S86_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*/ S86_CAST(DWORD)buffer_size, + /*DWORD nNumberOfBytesToWrite*/ PAP_CAST(DWORD)buffer_size, /*LPDWORD lpNumberOfBytesWrite*/ &bytes_written, /*LPOVERLAPPED lpOverlapped*/ NULL ); - S86_ASSERT(bytes_written == buffer_size); + PAP_ASSERT(bytes_written == buffer_size); result = write_file_result && bytes_written == buffer_size; CloseHandle(file_handle); return result; }; -void S86_Print(S86_Str8 string) +void PAP_PrintHandle(void *handle, PAP_Str8 string) { - if (s86_globals.stdout_handle == NULL) { - s86_globals.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD bytes_written = 0; + WriteFile(handle, string.data, PAP_CAST(DWORD)string.size, &bytes_written, NULL); + (void)bytes_written; +} + +void PAP_Print(PAP_Str8 string) +{ + if (pap_globals.stdout_handle == NULL) { + pap_globals.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); DWORD mode = 0; BOOL get_console_mode_result = GetConsoleMode( - /*HANDLE hConsoleHandle*/ s86_globals.stdout_handle, + /*HANDLE hConsoleHandle*/ pap_globals.stdout_handle, /*LPDWORD lpMode*/ &mode ); - s86_globals.write_to_console = get_console_mode_result != 0; + pap_globals.write_to_console = get_console_mode_result != 0; } - S86_ASSERT(string.size < S86_CAST(DWORD)-1); - if (s86_globals.write_to_console) { + PAP_ASSERT(string.size < PAP_CAST(DWORD)-1); + if (pap_globals.write_to_console) { DWORD chars_written = 0; - WriteConsoleA(s86_globals.stdout_handle, string.data, (DWORD)string.size, &chars_written, NULL); + WriteConsoleA(pap_globals.stdout_handle, string.data, (DWORD)string.size, &chars_written, NULL); } else { - DWORD bytes_written = 0; - WriteFile(s86_globals.stdout_handle, string.data, (DWORD)string.size, &bytes_written, NULL); + PAP_PrintHandle(pap_globals.stdout_handle, string); } } -void S86_PrintFmt(char const *fmt, ...) +void PAP_PrintFmt(char const *fmt, ...) { va_list args, args_copy; va_start(args, fmt); @@ -180,23 +186,23 @@ void S86_PrintFmt(char const *fmt, ...) va_end(args_copy); char buffer[8192]; - S86_ASSERT(string_size >= 0 && string_size < S86_ARRAY_UCOUNT(buffer)); + PAP_ASSERT(string_size >= 0 && string_size < PAP_ARRAY_UCOUNT(buffer)); if (string_size) { vsnprintf(buffer, sizeof(buffer), fmt, args); - S86_Str8 string = {.data = buffer, .size = string_size}; - S86_Print(string); + PAP_Str8 string = {.data = buffer, .size = string_size}; + PAP_Print(string); } va_end(args); } -void S86_PrintLn(S86_Str8 string) +void PAP_PrintLn(PAP_Str8 string) { - S86_Print(string); - S86_Print(S86_STR8("\n")); + PAP_Print(string); + PAP_Print(PAP_STR8("\n")); } -void S86_PrintLnFmt(char const *fmt, ...) +void PAP_PrintLnFmt(char const *fmt, ...) { va_list args, args_copy; va_start(args, fmt); @@ -206,11 +212,11 @@ void S86_PrintLnFmt(char const *fmt, ...) va_end(args_copy); char buffer[8192]; - S86_ASSERT(string_size >= 0 && string_size < S86_ARRAY_UCOUNT(buffer)); + PAP_ASSERT(string_size >= 0 && string_size < PAP_ARRAY_UCOUNT(buffer)); if (string_size) { vsnprintf(buffer, sizeof(buffer), fmt, args); - S86_Str8 string = {.data = buffer, .size = string_size}; - S86_PrintLn(string); + PAP_Str8 string = {.data = buffer, .size = string_size}; + PAP_PrintLn(string); } va_end(args); diff --git a/part2/pap2_stdlib.h b/part2/pap2_stdlib.h index 6c88eed..8f331c0 100644 --- a/part2/pap2_stdlib.h +++ b/part2/pap2_stdlib.h @@ -1,61 +1,67 @@ // NOTE: Macros // ============================================================================ -#define S86_STRINGIFY2(token) #token -#define S86_STRINGIFY(token) S86_STRINGIFY2(token) -#define S86_ASSERT(expr) \ - if (!(expr)) { \ - S86_PrintLnFmt("Assertion triggered [file=\"" __FILE__ ":" S86_STRINGIFY(__LINE__) "\", expr=\"" #expr "\"]"); \ - __debugbreak(); \ - } \ +#define PAP_STRINGIFY2(token) #token +#define PAP_STRINGIFY(token) PAP_STRINGIFY2(token) -#define S86_ARRAY_UCOUNT(array) sizeof((array)) / sizeof((array)[0]) -#define S86_CAST(Type) (Type) +#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 S86_Globals { +typedef struct PAP_Globals { HANDLE stdout_handle; bool write_to_console; -} S86_Globals; +} PAP_Globals; -S86_Globals s86_globals; +PAP_Globals pap_globals; // NOTE: Strings // ============================================================================ -typedef struct S86_Str8 { +typedef struct PAP_Str8 { char *data; size_t size; -} S86_Str8; +} PAP_Str8; -#define S86_STR8(string) (S86_Str8){.data = (string), .size = S86_ARRAY_UCOUNT(string) - 1 } -#define S86_STR8_FMT(string) (int)((string).size), (string).data +#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 S86_Str8_Equals(S86_Str8 lhs, S86_Str8 rhs); +bool PAP_Str8_Equals(PAP_Str8 lhs, PAP_Str8 rhs); // NOTE: Buffer // ============================================================================ -typedef struct S86_Buffer { +typedef struct PAP_Buffer { char *data; size_t size; -} S86_Buffer; +} PAP_Buffer; -typedef struct S86_BufferIterator { - S86_Buffer buffer; +typedef struct PAP_BufferIterator { + PAP_Buffer buffer; size_t index; -} S86_BufferIterator; +} PAP_BufferIterator; -bool S86_BufferIsValid(S86_Buffer buffer); -S86_BufferIterator S86_BufferIteratorInit(S86_Buffer buffer); -bool S86_BufferIteratorHasMoreBytes(S86_BufferIterator it); -uint8_t S86_BufferIteratorNextByte(S86_BufferIterator *it); +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 // ============================================================================ -S86_Buffer S86_FileRead(char const *file_path); -void S86_FileFree(S86_Buffer buffer); -bool S86_FileWrite(char const *file_path, void const *buffer, size_t buffer_size); +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 S86_PrintLn(S86_Str8 string); -void S86_PrintLnFmt(char const *fmt, ...); +void PAP_PrintHandle(void *handle, PAP_Str8 string); +void PAP_PrintLn (PAP_Str8 string); +void PAP_PrintLnFmt (char const *fmt, ...);