perfaware/part2: Write the haversine input generator
This commit is contained in:
parent
a4658b1951
commit
7dfd1b1927
@ -319,5 +319,6 @@ REM Part 2 =====================================================================
|
|||||||
REM Build ==========================================================================================
|
REM Build ==========================================================================================
|
||||||
:part2
|
:part2
|
||||||
pushd %part2_build_dir%
|
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
|
popd
|
||||||
|
279
part2/haversine_generator.c
Normal file
279
part2/haversine_generator.c
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include "pap2_stdlib.h"
|
||||||
|
#include "pap2_stdlib.c"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
55
part2/main.c
55
part2/main.c
@ -1,55 +0,0 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <Windows.h>
|
|
||||||
#include "pap2_stdlib.h"
|
|
||||||
#include "pap2_stdlib.c"
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
@ -1,49 +1,49 @@
|
|||||||
// NOTE: Implementation
|
// 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;
|
bool result = lhs.size == rhs.size && memcmp(lhs.data, rhs.data, lhs.size) == 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool S86_BufferIsValid(S86_Buffer buffer)
|
bool PAP_BufferIsValid(PAP_Buffer buffer)
|
||||||
{
|
{
|
||||||
bool result = buffer.data && buffer.size;
|
bool result = buffer.data && buffer.size;
|
||||||
return result;
|
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;
|
result.buffer = buffer;
|
||||||
return result;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t S86_BufferIteratorPeekByte(S86_BufferIterator *it)
|
uint8_t PAP_BufferIteratorPeekByte(PAP_BufferIterator *it)
|
||||||
{
|
{
|
||||||
S86_ASSERT(it);
|
PAP_ASSERT(it);
|
||||||
S86_ASSERT(S86_BufferIsValid(it->buffer));
|
PAP_ASSERT(PAP_BufferIsValid(it->buffer));
|
||||||
S86_ASSERT(it->index < it->buffer.size);
|
PAP_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 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++;
|
it->index++;
|
||||||
return result;
|
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
|
// NOTE: Determine file size
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@ -69,7 +69,7 @@ S86_Buffer S86_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;
|
||||||
S86_ASSERT(file_size < (DWORD)-1);
|
PAP_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 +86,7 @@ S86_Buffer S86_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*/ S86_CAST(DWORD)file_size,
|
/*DWORD nNumberOfBytesToRead*/ PAP_CAST(DWORD)file_size,
|
||||||
/*LPDWORD lpNumberOfBytesRead*/ &bytes_read,
|
/*LPDWORD lpNumberOfBytesRead*/ &bytes_read,
|
||||||
/*LPOVERLAPPED lpOverlapped*/ NULL
|
/*LPOVERLAPPED lpOverlapped*/ NULL
|
||||||
);
|
);
|
||||||
@ -105,13 +105,13 @@ end:
|
|||||||
return result;
|
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);
|
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;
|
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(
|
BOOL write_file_result = WriteFile(
|
||||||
/*HANDLE hFile*/ file_handle,
|
/*HANDLE hFile*/ file_handle,
|
||||||
/*LPVOID lpBuffer*/ buffer,
|
/*LPVOID lpBuffer*/ buffer,
|
||||||
/*DWORD nNumberOfBytesToWrite*/ S86_CAST(DWORD)buffer_size,
|
/*DWORD nNumberOfBytesToWrite*/ PAP_CAST(DWORD)buffer_size,
|
||||||
/*LPDWORD lpNumberOfBytesWrite*/ &bytes_written,
|
/*LPDWORD lpNumberOfBytesWrite*/ &bytes_written,
|
||||||
/*LPOVERLAPPED lpOverlapped*/ NULL
|
/*LPOVERLAPPED lpOverlapped*/ NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
S86_ASSERT(bytes_written == buffer_size);
|
PAP_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 S86_Print(S86_Str8 string)
|
void PAP_PrintHandle(void *handle, PAP_Str8 string)
|
||||||
{
|
{
|
||||||
if (s86_globals.stdout_handle == NULL) {
|
DWORD bytes_written = 0;
|
||||||
s86_globals.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
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;
|
DWORD mode = 0;
|
||||||
BOOL get_console_mode_result = GetConsoleMode(
|
BOOL get_console_mode_result = GetConsoleMode(
|
||||||
/*HANDLE hConsoleHandle*/ s86_globals.stdout_handle,
|
/*HANDLE hConsoleHandle*/ pap_globals.stdout_handle,
|
||||||
/*LPDWORD lpMode*/ &mode
|
/*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);
|
PAP_ASSERT(string.size < PAP_CAST(DWORD)-1);
|
||||||
if (s86_globals.write_to_console) {
|
if (pap_globals.write_to_console) {
|
||||||
DWORD chars_written = 0;
|
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 {
|
} else {
|
||||||
DWORD bytes_written = 0;
|
PAP_PrintHandle(pap_globals.stdout_handle, string);
|
||||||
WriteFile(s86_globals.stdout_handle, string.data, (DWORD)string.size, &bytes_written, NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void S86_PrintFmt(char const *fmt, ...)
|
void PAP_PrintFmt(char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args, args_copy;
|
va_list args, args_copy;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@ -180,23 +186,23 @@ void S86_PrintFmt(char const *fmt, ...)
|
|||||||
va_end(args_copy);
|
va_end(args_copy);
|
||||||
|
|
||||||
char buffer[8192];
|
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) {
|
if (string_size) {
|
||||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
S86_Str8 string = {.data = buffer, .size = string_size};
|
PAP_Str8 string = {.data = buffer, .size = string_size};
|
||||||
S86_Print(string);
|
PAP_Print(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void S86_PrintLn(S86_Str8 string)
|
void PAP_PrintLn(PAP_Str8 string)
|
||||||
{
|
{
|
||||||
S86_Print(string);
|
PAP_Print(string);
|
||||||
S86_Print(S86_STR8("\n"));
|
PAP_Print(PAP_STR8("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void S86_PrintLnFmt(char const *fmt, ...)
|
void PAP_PrintLnFmt(char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args, args_copy;
|
va_list args, args_copy;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@ -206,11 +212,11 @@ void S86_PrintLnFmt(char const *fmt, ...)
|
|||||||
va_end(args_copy);
|
va_end(args_copy);
|
||||||
|
|
||||||
char buffer[8192];
|
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) {
|
if (string_size) {
|
||||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
S86_Str8 string = {.data = buffer, .size = string_size};
|
PAP_Str8 string = {.data = buffer, .size = string_size};
|
||||||
S86_PrintLn(string);
|
PAP_PrintLn(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
@ -1,61 +1,67 @@
|
|||||||
// NOTE: Macros
|
// NOTE: Macros
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
#define S86_STRINGIFY2(token) #token
|
#define PAP_STRINGIFY2(token) #token
|
||||||
#define S86_STRINGIFY(token) S86_STRINGIFY2(token)
|
#define PAP_STRINGIFY(token) PAP_STRINGIFY2(token)
|
||||||
#define S86_ASSERT(expr) \
|
|
||||||
if (!(expr)) { \
|
|
||||||
S86_PrintLnFmt("Assertion triggered [file=\"" __FILE__ ":" S86_STRINGIFY(__LINE__) "\", expr=\"" #expr "\"]"); \
|
|
||||||
__debugbreak(); \
|
|
||||||
} \
|
|
||||||
|
|
||||||
#define S86_ARRAY_UCOUNT(array) sizeof((array)) / sizeof((array)[0])
|
#if defined(NDEBUG)
|
||||||
#define S86_CAST(Type) (Type)
|
#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
|
// NOTE: Globals
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
typedef struct S86_Globals {
|
typedef struct PAP_Globals {
|
||||||
HANDLE stdout_handle;
|
HANDLE stdout_handle;
|
||||||
bool write_to_console;
|
bool write_to_console;
|
||||||
} S86_Globals;
|
} PAP_Globals;
|
||||||
|
|
||||||
S86_Globals s86_globals;
|
PAP_Globals pap_globals;
|
||||||
|
|
||||||
// NOTE: Strings
|
// NOTE: Strings
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
typedef struct S86_Str8 {
|
typedef struct PAP_Str8 {
|
||||||
char *data;
|
char *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
} S86_Str8;
|
} PAP_Str8;
|
||||||
|
|
||||||
#define S86_STR8(string) (S86_Str8){.data = (string), .size = S86_ARRAY_UCOUNT(string) - 1 }
|
#define PAP_STR8(string) (PAP_Str8){.data = (string), .size = PAP_ARRAY_UCOUNT(string) - 1 }
|
||||||
#define S86_STR8_FMT(string) (int)((string).size), (string).data
|
#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
|
// NOTE: Buffer
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
typedef struct S86_Buffer {
|
typedef struct PAP_Buffer {
|
||||||
char *data;
|
char *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
} S86_Buffer;
|
} PAP_Buffer;
|
||||||
|
|
||||||
typedef struct S86_BufferIterator {
|
typedef struct PAP_BufferIterator {
|
||||||
S86_Buffer buffer;
|
PAP_Buffer buffer;
|
||||||
size_t index;
|
size_t index;
|
||||||
} S86_BufferIterator;
|
} PAP_BufferIterator;
|
||||||
|
|
||||||
bool S86_BufferIsValid(S86_Buffer buffer);
|
bool PAP_BufferIsValid (PAP_Buffer buffer);
|
||||||
S86_BufferIterator S86_BufferIteratorInit(S86_Buffer buffer);
|
PAP_BufferIterator PAP_BufferIteratorInit (PAP_Buffer buffer);
|
||||||
bool S86_BufferIteratorHasMoreBytes(S86_BufferIterator it);
|
bool PAP_BufferIteratorHasMoreBytes(PAP_BufferIterator it);
|
||||||
uint8_t S86_BufferIteratorNextByte(S86_BufferIterator *it);
|
uint8_t PAP_BufferIteratorNextByte (PAP_BufferIterator *it);
|
||||||
|
|
||||||
// NOTE: File
|
// NOTE: File
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
S86_Buffer S86_FileRead(char const *file_path);
|
PAP_Buffer PAP_FileRead (char const *file_path);
|
||||||
void S86_FileFree(S86_Buffer buffer);
|
void PAP_FileFree (PAP_Buffer buffer);
|
||||||
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);
|
||||||
|
|
||||||
// NOTE: Print
|
// NOTE: Print
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
void S86_PrintLn(S86_Str8 string);
|
void PAP_PrintHandle(void *handle, PAP_Str8 string);
|
||||||
void S86_PrintLnFmt(char const *fmt, ...);
|
void PAP_PrintLn (PAP_Str8 string);
|
||||||
|
void PAP_PrintLnFmt (char const *fmt, ...);
|
||||||
|
Loading…
Reference in New Issue
Block a user