perfaware/part2: Setup haversine parser task

This commit is contained in:
doyle 2023-06-30 21:30:31 +10:00
parent 7dfd1b1927
commit f8ac671e3a
5 changed files with 268 additions and 258 deletions

40
part2/haversine.c Normal file
View File

@ -0,0 +1,40 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <Windows.h>
#include "haversine_stdlib.h"
#include "haversine_stdlib.c"
#include <math.h>
#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;
}

View File

@ -3,154 +3,42 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <Windows.h> #include <Windows.h>
#include "pap2_stdlib.h" #include "haversine_stdlib.h"
#include "pap2_stdlib.c" #include "haversine_stdlib.c"
#include <math.h> #include <math.h>
#include "listing_0065_haversine_formula.cpp"
typedef float f32; #define PRINT_USAGE HAV_PrintLnFmt("Usage: %s [uniform/cluster] [random seed] [number of coordinate pairs to generate]", argv[0])
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) int main(int argc, char **argv)
{ {
// NOTE: Unit Tests // NOTE: Unit Tests
// ========================================================================= // =========================================================================
{ {
{ {
PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("00")); HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("00"));
PAP_ASSERT(result.success); HAV_ASSERT(result.success);
PAP_ASSERT(result.value == 0); HAV_ASSERT(result.value == 0);
} }
{ {
PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("+100")); HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("+100"));
PAP_ASSERT(!result.success); HAV_ASSERT(!result.success);
} }
{ {
PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("100,0")); HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("100,0"));
PAP_ASSERT(!result.success); HAV_ASSERT(!result.success);
} }
{ {
PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("100a")); HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("100a"));
PAP_ASSERT(!result.success); HAV_ASSERT(!result.success);
} }
{ {
PAP_Str8ToU64Result result = PAP_Str8_ToU64(PAP_STR8("3147")); HAV_Str8ToU64Result result = HAV_Str8_ToU64(HAV_STR8("3147"));
PAP_ASSERT(result.success); HAV_ASSERT(result.success);
PAP_ASSERT(result.value == 3147); HAV_ASSERT(result.value == 3147);
} }
} }
@ -161,9 +49,9 @@ int main(int argc, char **argv)
return -1; return -1;
} }
PAP_Str8 arg_uniform_cluster = {argv[1], strlen(argv[1])}; HAV_Str8 arg_uniform_cluster = {argv[1], strlen(argv[1])};
PAP_Str8 arg_random_seed = {argv[2], strlen(argv[2])}; HAV_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_number_of_coordinate_pairs_to_generate = {argv[3], strlen(argv[3])};
typedef enum PointGenerator { typedef enum PointGenerator {
PointGenerator_Invalid, PointGenerator_Invalid,
@ -171,13 +59,13 @@ int main(int argc, char **argv)
PointGenerator_Cluster, PointGenerator_Cluster,
} PointGenerator; } PointGenerator;
PAP_Str8ToU64Result random_seed_u64_result = PAP_Str8_ToU64(arg_random_seed); HAV_Str8ToU64Result random_seed_u64_result = HAV_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 number_of_coordinate_pairs_to_generate_u64_result = HAV_Str8_ToU64(arg_number_of_coordinate_pairs_to_generate);
PointGenerator point_generator = PointGenerator_Invalid; 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; 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; point_generator = PointGenerator_Cluster;
} else { } else {
PRINT_USAGE; PRINT_USAGE;
@ -185,20 +73,20 @@ int main(int argc, char **argv)
} }
if (!random_seed_u64_result.success) { 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; PRINT_USAGE;
return -1; return -1;
} }
if (!number_of_coordinate_pairs_to_generate_u64_result.success) { 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; PRINT_USAGE;
return -1; return -1;
} }
uint32_t const MAX_COORD_PAIRS = 100'000'000; uint32_t const MAX_COORD_PAIRS = 100'000'000;
if (number_of_coordinate_pairs_to_generate_u64_result.value > MAX_COORD_PAIRS) { 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, number_of_coordinate_pairs_to_generate_u64_result.value,
MAX_COORD_PAIRS); MAX_COORD_PAIRS);
PRINT_USAGE; PRINT_USAGE;
@ -239,7 +127,7 @@ int main(int argc, char **argv)
char tmp_buffer[128]; char tmp_buffer[128];
f64 expected_sum = 0; 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 const sum_coefficient = 1.0 / point_count;
f64 point_centre = 0; f64 point_centre = 0;
@ -247,33 +135,33 @@ int main(int argc, char **argv)
f64 point_max_offset = LAT_LON_MAX; f64 point_max_offset = LAT_LON_MAX;
for (int index = 0; index < point_count; index++) { for (int index = 0; index < point_count; index++) {
if (point_generator == PointGenerator_Cluster && (index % points_per_cluster) == 0) { if (point_generator == PointGenerator_Cluster && (index % points_per_cluster) == 0) {
point_centre = PAP_PCG32_PieF64(&rng_state, LAT_LON_MIN, LAT_LON_MAX); point_centre = HAV_PCG32_PieF64(&rng_state, LAT_LON_MIN, LAT_LON_MAX);
point_min_offset = -PAP_PCG32_PieF64(&rng_state, 0, 45); point_min_offset = -HAV_PCG32_PieF64(&rng_state, 0, 45);
point_max_offset = -point_min_offset; point_max_offset = -point_min_offset;
} }
f64 x0 = 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 + PAP_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 + PAP_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 + PAP_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); 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); 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) ? "" : ",")); 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)); HAV_ASSERT(json_line_size < sizeof(tmp_buffer));
PAP_PrintHandle(haversine_json_file_handle, (PAP_Str8){.data = tmp_buffer, .size = json_line_size}); HAV_PrintHandle(haversine_json_file_handle, (HAV_Str8){.data = tmp_buffer, .size = json_line_size});
} }
PAP_PrintHandle(haversine_json_file_handle, PAP_STR8("]}\n")); HAV_PrintHandle(haversine_json_file_handle, HAV_STR8("]}\n"));
PAP_PrintHandle(haversine_f64_file_handle, (PAP_Str8){.data = (char *)&expected_sum, .size = sizeof(expected_sum)}); HAV_PrintHandle(haversine_f64_file_handle, (HAV_Str8){.data = (char *)&expected_sum, .size = sizeof(expected_sum)});
CloseHandle(haversine_json_file_handle); CloseHandle(haversine_json_file_handle);
CloseHandle(haversine_f64_file_handle); CloseHandle(haversine_f64_file_handle);
PAP_PrintLnFmt("Method: %s", (point_generator == PointGenerator_Uniform ? "uniform" : "cluster")); HAV_PrintLnFmt("Method: %s", (point_generator == PointGenerator_Uniform ? "uniform" : "cluster"));
PAP_PrintLnFmt("Seed: %zu", random_seed); HAV_PrintLnFmt("Seed: %zu", random_seed);
PAP_PrintLnFmt("Pair Count: %zu", point_count); HAV_PrintLnFmt("Pair Count: %zu", point_count);
PAP_PrintLnFmt("Expected Sum: %f", expected_sum); HAV_PrintLnFmt("Expected Sum: %f", expected_sum);
return 0; return 0;
} }

View File

@ -1,49 +1,96 @@
// NOTE: Implementation // 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; bool result = lhs.size == rhs.size && memcmp(lhs.data, rhs.data, lhs.size) == 0;
return result; 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; bool result = buffer.data && buffer.size;
return result; 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; result.buffer = buffer;
return result; 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; return result;
} }
uint8_t PAP_BufferIteratorPeekByte(PAP_BufferIterator *it) uint8_t HAV_BufferIteratorPeekByte(HAV_BufferIterator *it)
{ {
PAP_ASSERT(it); HAV_ASSERT(it);
PAP_ASSERT(PAP_BufferIsValid(it->buffer)); HAV_ASSERT(HAV_BufferIsValid(it->buffer));
PAP_ASSERT(it->index < it->buffer.size); HAV_ASSERT(it->index < it->buffer.size);
uint8_t result = it->buffer.data[it->index]; uint8_t result = it->buffer.data[it->index];
return result; 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++; it->index++;
return result; 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 // NOTE: Determine file size
// ========================================================================= // =========================================================================
@ -69,7 +116,7 @@ PAP_Buffer PAP_FileRead(char const *file_path)
// NOTE: Allocate buffer // NOTE: Allocate buffer
// ========================================================================= // =========================================================================
uint64_t file_size = (uint64_t)file_attrib_data.nFileSizeHigh << 32 | (uint64_t)file_attrib_data.nFileSizeLow << 0; 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( char *buffer = VirtualAlloc(
/*LPVOID lpAddress*/ NULL, /*LPVOID lpAddress*/ NULL,
/*SIZE_T dwSize*/ file_size, /*SIZE_T dwSize*/ file_size,
@ -86,7 +133,7 @@ PAP_Buffer PAP_FileRead(char const *file_path)
BOOL read_file_result = ReadFile( BOOL read_file_result = ReadFile(
/*HANDLE hFile*/ file_handle, /*HANDLE hFile*/ file_handle,
/*LPVOID lpBuffer*/ buffer, /*LPVOID lpBuffer*/ buffer,
/*DWORD nNumberOfBytesToRead*/ PAP_CAST(DWORD)file_size, /*DWORD nNumberOfBytesToRead*/ HAV_CAST(DWORD)file_size,
/*LPDWORD lpNumberOfBytesRead*/ &bytes_read, /*LPDWORD lpNumberOfBytesRead*/ &bytes_read,
/*LPOVERLAPPED lpOverlapped*/ NULL /*LPOVERLAPPED lpOverlapped*/ NULL
); );
@ -105,13 +152,13 @@ end:
return result; 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); 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; 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( BOOL write_file_result = WriteFile(
/*HANDLE hFile*/ file_handle, /*HANDLE hFile*/ file_handle,
/*LPVOID lpBuffer*/ buffer, /*LPVOID lpBuffer*/ buffer,
/*DWORD nNumberOfBytesToWrite*/ PAP_CAST(DWORD)buffer_size, /*DWORD nNumberOfBytesToWrite*/ HAV_CAST(DWORD)buffer_size,
/*LPDWORD lpNumberOfBytesWrite*/ &bytes_written, /*LPDWORD lpNumberOfBytesWrite*/ &bytes_written,
/*LPOVERLAPPED lpOverlapped*/ NULL /*LPOVERLAPPED lpOverlapped*/ NULL
); );
PAP_ASSERT(bytes_written == buffer_size); HAV_ASSERT(bytes_written == buffer_size);
result = write_file_result && bytes_written == buffer_size; result = write_file_result && bytes_written == buffer_size;
CloseHandle(file_handle); CloseHandle(file_handle);
return result; return result;
}; };
void PAP_PrintHandle(void *handle, PAP_Str8 string) void HAV_PrintHandle(void *handle, HAV_Str8 string)
{ {
DWORD bytes_written = 0; 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)bytes_written;
} }
void PAP_Print(PAP_Str8 string) void HAV_Print(HAV_Str8 string)
{ {
if (pap_globals.stdout_handle == NULL) { if (pap_globals.stdout_handle == NULL) {
pap_globals.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); 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) { if (pap_globals.write_to_console) {
DWORD chars_written = 0; DWORD chars_written = 0;
WriteConsoleA(pap_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 { } 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_list args, args_copy;
va_start(args, fmt); va_start(args, fmt);
@ -186,23 +233,23 @@ void PAP_PrintFmt(char const *fmt, ...)
va_end(args_copy); va_end(args_copy);
char buffer[8192]; 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) { if (string_size) {
vsnprintf(buffer, sizeof(buffer), fmt, args); vsnprintf(buffer, sizeof(buffer), fmt, args);
PAP_Str8 string = {.data = buffer, .size = string_size}; HAV_Str8 string = {.data = buffer, .size = string_size};
PAP_Print(string); HAV_Print(string);
} }
va_end(args); va_end(args);
} }
void PAP_PrintLn(PAP_Str8 string) void HAV_PrintLn(HAV_Str8 string)
{ {
PAP_Print(string); HAV_Print(string);
PAP_Print(PAP_STR8("\n")); HAV_Print(HAV_STR8("\n"));
} }
void PAP_PrintLnFmt(char const *fmt, ...) void HAV_PrintLnFmt(char const *fmt, ...)
{ {
va_list args, args_copy; va_list args, args_copy;
va_start(args, fmt); va_start(args, fmt);
@ -212,11 +259,11 @@ void PAP_PrintLnFmt(char const *fmt, ...)
va_end(args_copy); va_end(args_copy);
char buffer[8192]; 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) { if (string_size) {
vsnprintf(buffer, sizeof(buffer), fmt, args); vsnprintf(buffer, sizeof(buffer), fmt, args);
PAP_Str8 string = {.data = buffer, .size = string_size}; HAV_Str8 string = {.data = buffer, .size = string_size};
PAP_PrintLn(string); HAV_PrintLn(string);
} }
va_end(args); va_end(args);

102
part2/haversine_stdlib.h Normal file
View File

@ -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, ...);

View File

@ -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, ...);