V1 file read done
This commit is contained in:
parent
42aed25b51
commit
76fbeff084
@ -71,6 +71,7 @@ $compiler_args += $flag_nologo
|
|||||||
|
|
||||||
# Constraints on interpeting all files as C code
|
# Constraints on interpeting all files as C code
|
||||||
$compiler_args += $flag_all_c
|
$compiler_args += $flag_all_c
|
||||||
|
$compiler_args += $flag_c11
|
||||||
# Constraints on C program code-gen
|
# Constraints on C program code-gen
|
||||||
$compiler_args += $flag_exceptions_disabled
|
$compiler_args += $flag_exceptions_disabled
|
||||||
$compiler_args += $flag_RTTI_disabled
|
$compiler_args += $flag_RTTI_disabled
|
||||||
|
211
demo.str_cache.c
211
demo.str_cache.c
@ -1,13 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
A introduction to C11 with a str cache demo.
|
A introduction to C11 with a str cache demo.
|
||||||
Attempting to showcase better conventions and constructs in C; Discovered to me as of 2025 from scouring the internet.
|
Attempting to showcase better conventions and constructs in C; Discovered to me as of 2025 from scouring the internet.
|
||||||
|
|
||||||
|
"C is old and flawed, but your use of it is most likely more flawed. You must have calouses to write with barbed syntax & semantics."
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The below will be implemented within this single file.
|
The below will be implemented within this single file.
|
||||||
Because of this, definitions will be kept on a need-to-have basis to target only one vendor target and toolchain.
|
Because of this, definitions will be kept on a need-to-have basis to target only one vendor target and toolchain.
|
||||||
We will not use nearly any libraries and will be targeting only Windows 11 x64 using MSVC.
|
We will not use nearly any libraries and will be targeting only Windows 11 x64 using MSVC.
|
||||||
|
|
||||||
Even so the constructs defined and their dependencies can be properly abstracted into a ergonomic library for multiple targets with enough time and pain.
|
Even so the constructs defined and their dependencies can be properly abstracted into a ergonomic library for multiple targets with enough time and pain.
|
||||||
|
The difference is just more preprocess conditionals, and how far a library is trying to support a larger range of targets and their age discrpancy.
|
||||||
|
The more minimal the less cruft.
|
||||||
|
|
||||||
Definitions are defined linearly on the file on-demand as needed. Since the file is to be read linearly.
|
Definitions are defined linearly on the file on-demand as needed. Since the file is to be read linearly.
|
||||||
This will cause non-categorical organization so it will be more difficult to sift through if you wanted
|
This will cause non-categorical organization so it will be more difficult to sift through if you wanted
|
||||||
@ -66,7 +71,7 @@ So we'll setup the the minimum for that when dealing with immutable constructs.
|
|||||||
#include <wmmintrin.h>
|
#include <wmmintrin.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
// #include <stdbool.h>
|
||||||
|
|
||||||
typedef unsigned __int8 U8;
|
typedef unsigned __int8 U8;
|
||||||
typedef signed __int8 S8;
|
typedef signed __int8 S8;
|
||||||
@ -80,6 +85,17 @@ typedef signed __int64 S64;
|
|||||||
typedef size_t USIZE;
|
typedef size_t USIZE;
|
||||||
typedef ptrdiff_t SSIZE;
|
typedef ptrdiff_t SSIZE;
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true_overflow,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef S8 B8;
|
||||||
|
typedef S16 B16;
|
||||||
|
typedef S32 B32;
|
||||||
|
|
||||||
// Functional style cast
|
// Functional style cast
|
||||||
#define cast(type, data) ((type)(data))
|
#define cast(type, data) ((type)(data))
|
||||||
|
|
||||||
@ -101,7 +117,7 @@ struct Str8 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// String iterals in C include null-terminators, we aren't interested in preserving that.
|
// String iterals in C include null-terminators, we aren't interested in preserving that.
|
||||||
#define lit(string_literal) (Str8){ string_literal, size_of(string_literal) - 1 };
|
#define lit(string_literal) (Str8){ string_literal, size_of(string_literal) - 1 }
|
||||||
|
|
||||||
// For now this string can visualized using a debugger.
|
// For now this string can visualized using a debugger.
|
||||||
// #define DEMO__STR_SLICE
|
// #define DEMO__STR_SLICE
|
||||||
@ -132,17 +148,7 @@ typedef struct Opts__read_file_contents Opts__read_file_contents;
|
|||||||
void api_file_read_contents(FileOpResult* result, Str8 path, Opts__read_file_contents* opts);
|
void api_file_read_contents(FileOpResult* result, Str8 path, Opts__read_file_contents* opts);
|
||||||
FileOpResult file__read_contents ( Str8 path, Opts__read_file_contents* opts);
|
FileOpResult file__read_contents ( Str8 path, Opts__read_file_contents* opts);
|
||||||
|
|
||||||
#define file_read_contents(path, opts) file__read_contents(path, & (Opts__read_file_contents){0} )
|
#define file_read_contents(path, ...) file__read_contents(path, & (Opts__read_file_contents){__VA_ARGS__} )
|
||||||
|
|
||||||
/*
|
|
||||||
The above is a pattern that can be provided so that whether or not the result is formatted and provided to the user via the stack is entirely optional.
|
|
||||||
It also allows for default parameters to be defined conviently.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Now for our "Version 1"
|
|
||||||
|
|
||||||
#define DEMO__FILE_READ_CONTENTS_V1
|
|
||||||
#ifdef DEMO__FILE_READ_CONTENTS_V1
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The file contents will be returned in bytes.
|
The file contents will be returned in bytes.
|
||||||
@ -163,20 +169,34 @@ struct SliceMem {
|
|||||||
SSIZE len;
|
SSIZE len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FileOpResult
|
/*
|
||||||
{
|
The above is a pattern that can be provided so that whether or not the result is formatted and provided to the user via the stack is entirely optional.
|
||||||
// For now we'll just have the content
|
It also allows for default parameters to be defined conviently.
|
||||||
SliceByte content;
|
*/
|
||||||
};
|
|
||||||
|
|
||||||
struct Opts__read_file_contents
|
|
||||||
{
|
|
||||||
// For now we'll just have the backing memory provided as a slice.
|
|
||||||
SliceMem backing;
|
|
||||||
};
|
|
||||||
|
|
||||||
// We'll utilize the ReadFile procedure within the WinAPI: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
|
// We'll utilize the ReadFile procedure within the WinAPI: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
|
||||||
#include "fileapi.h"
|
#define NOMINMAX
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_MEAN_AND_LEAN
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
#include <timeapi.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include <Shlobj.h>
|
||||||
|
#include <processthreadsapi.h>
|
||||||
|
#pragma comment(lib, "user32")
|
||||||
|
#pragma comment(lib, "winmm")
|
||||||
|
#pragma comment(lib, "shell32")
|
||||||
|
#pragma comment(lib, "advapi32")
|
||||||
|
#pragma comment(lib, "rpcrt4")
|
||||||
|
#pragma comment(lib, "shlwapi")
|
||||||
|
#pragma comment(lib, "comctl32")
|
||||||
|
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // this is required for loading correct comctl32 dll file
|
||||||
|
#undef NOMINMAX
|
||||||
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
|
#undef WIN32_MEAN_AND_LEAN
|
||||||
|
#undef VC_EXTRALEAN
|
||||||
#if 0
|
#if 0
|
||||||
BOOL ReadFile(
|
BOOL ReadFile(
|
||||||
[in] HANDLE hFile,
|
[in] HANDLE hFile,
|
||||||
@ -213,51 +233,142 @@ typedef U8 FMem_<size>KB [ <U8 amount> ];
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
typedef U8 FMem_16KB [ KILOBTYES(16) ];
|
typedef U8 FMem_16KB [ KILOBTYES(16) ];
|
||||||
|
typedef U8 FMem_64KB [ KILOBTYES(64) ];
|
||||||
|
|
||||||
#define typeof __typeof__
|
#define typeof __typeof__
|
||||||
#define fmem_slice(mem) (SliceMem) { mem, size_of(mem) }
|
#define fmem_slice(mem) (SliceMem) { mem, size_of(mem) }
|
||||||
|
|
||||||
// We'll be using an intrinsic for copying memory:
|
// We'll be using an intrinsic for copying memory:
|
||||||
void* memory_copy(void* dest, const void* src, size_t count)
|
void* memory_copy(void* dest, void const* src, SSIZE length)
|
||||||
{
|
{
|
||||||
if (dest == NULL || src == NULL || count == 0) {
|
if (dest == nullptr || src == nullptr || length == 0) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
// https://learn.microsoft.com/en-us/cpp/intrinsics/movsb?view=msvc-170
|
||||||
__movsb((unsigned char*)dest, (const unsigned char*)src, count);
|
__movsb((unsigned char*)dest, (const unsigned char*)src, length);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Often we'll want to check validity of a slice:
|
||||||
|
#define slice_assert(slice) do { \
|
||||||
|
assert(slice.ptr != nullptr); \
|
||||||
|
assert(slice.len > 0); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
void slice_copy(SliceMem dest, SliceMem src) {
|
||||||
|
assert(dest.len >= src.len);
|
||||||
|
slice_assert(dest);
|
||||||
|
slice_assert(src);
|
||||||
|
memory_copy(dest.ptr, src.ptr, src.len);
|
||||||
|
}
|
||||||
|
|
||||||
// Assumes memory is zeroed.
|
// Assumes memory is zeroed.
|
||||||
char const* str8_to_cstr_capped(Str8 content, SliceMem mem)
|
char const* str8_to_cstr_capped(Str8 content, SliceMem mem) {
|
||||||
{
|
|
||||||
assert(mem.len >= content.len);
|
assert(mem.len >= content.len);
|
||||||
memory_copy(mem.ptr, content.ptr, content.ptr);
|
memory_copy(mem.ptr, content.ptr, content.len);
|
||||||
return mem.ptr;
|
return mem.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To support zeroing slices we'll utilize an intrinisc.
|
||||||
|
B32 memory_zero(void* dest, SSIZE length) {
|
||||||
|
if (dest == nullptr || length <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
__stosd((unsigned long*)dest, 0, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slice_zero(SliceMem mem) {
|
||||||
|
slice_assert(mem);
|
||||||
|
memory_zero(mem.ptr, mem.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now for our "Version 1"
|
||||||
|
|
||||||
|
#define DEMO__FILE_READ_CONTENTS_V1
|
||||||
|
#ifdef DEMO__FILE_READ_CONTENTS_V1
|
||||||
|
|
||||||
|
struct FileOpResult
|
||||||
|
{
|
||||||
|
// For now we'll just have the content
|
||||||
|
SliceByte content;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Opts__read_file_contents
|
||||||
|
{
|
||||||
|
// For now we'll just have the backing memory provided as a slice.
|
||||||
|
SliceMem backing;
|
||||||
|
// And whether we should zero the backing.
|
||||||
|
B32 zero_backing;
|
||||||
|
};
|
||||||
|
|
||||||
void api_file_read_contents(FileOpResult* result, Str8 path, Opts__read_file_contents* opts)
|
void api_file_read_contents(FileOpResult* result, Str8 path, Opts__read_file_contents* opts)
|
||||||
{
|
{
|
||||||
|
assert(result != nullptr);
|
||||||
|
assert(opts != nullptr);
|
||||||
|
slice_assert(path);
|
||||||
|
// Backing is required at this point
|
||||||
|
slice_assert(opts->backing);
|
||||||
|
|
||||||
FMem_16KB scratch = {0};
|
FMem_16KB scratch = {0};
|
||||||
char const* path_cstr = str8_to_cstr_capped(path, fmem_slice(scratch) );
|
char const* path_cstr = str8_to_cstr_capped(path, fmem_slice(scratch) );
|
||||||
|
|
||||||
HANDLE id_file = CreateFileA(
|
HANDLE id_file = CreateFileA(
|
||||||
path_cstr,
|
path_cstr,
|
||||||
|
GENERIC_READ,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL
|
||||||
);
|
);
|
||||||
|
B32 open_failed = id_file == INVALID_HANDLE_VALUE;
|
||||||
|
if (open_failed) {
|
||||||
|
DWORD error_code = GetLastError();
|
||||||
|
assert(error_code != 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// BOOL op_result = ReadFile(
|
LARGE_INTEGER file_size = {0};
|
||||||
// id_file,
|
DWORD get_size_failed = ! GetFileSizeEx(id_file, & file_size);
|
||||||
// buffer,
|
if (get_size_failed) {
|
||||||
// to_read,
|
assert(get_size_failed == INVALID_FILE_SIZE);
|
||||||
// read_amount,
|
return;
|
||||||
// nullptr
|
}
|
||||||
// );
|
|
||||||
|
|
||||||
return
|
// Because we are currently using fixed size memory, we need to confirm that we can hold this content.
|
||||||
/*
|
B32 not_enough_backing = opts->backing.len < file_size.QuadPart;
|
||||||
TODO(Ed): You are here
|
if (not_enough_backing) {
|
||||||
*/
|
assert(not_enough_backing);
|
||||||
|
// Otherwise we don't provide a result.
|
||||||
|
result->content = (SliceByte){0};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->zero_backing) {
|
||||||
|
slice_zero(opts->backing);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD amount_read = 0;
|
||||||
|
BOOL read_result = ReadFile(
|
||||||
|
id_file,
|
||||||
|
opts->backing.ptr,
|
||||||
|
file_size.QuadPart,
|
||||||
|
& amount_read,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
CloseHandle(id_file);
|
||||||
|
|
||||||
|
B32 read_failed = ! read_result;
|
||||||
|
read_failed |= amount_read != file_size.QuadPart;
|
||||||
|
if (read_failed) {
|
||||||
|
assert(read_failed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->content.ptr = opts->backing.ptr;
|
||||||
|
result->content.len = file_size.QuadPart;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif DEMO__FILE_READ_CONTENTS_V1
|
#endif DEMO__FILE_READ_CONTENTS_V1
|
||||||
@ -269,3 +380,13 @@ FileOpResult file__read_contents(Str8 path, Opts__read_file_contents* opts) {
|
|||||||
api_file_read_contents(& result, path, opts);
|
api_file_read_contents(& result, path, opts);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// And now to put it all together into a test run in the debugger. Content should be properly formatted if the code is correct.
|
||||||
|
#ifdef DEMO__FILE_READ_CONTENTS_V1
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FMem_64KB read_mem = {0};
|
||||||
|
FileOpResult res = file_read_contents(lit("demo.str_cache.c"), .backing = fmem_slice(read_mem) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user