194 lines
5.7 KiB
C
194 lines
5.7 KiB
C
/*
|
|
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.
|
|
*/
|
|
|
|
/*
|
|
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.
|
|
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.
|
|
|
|
AI prompting will be used as a search engine I'll be provding the prompts used to gather specific vendor API information thats not-memorized.
|
|
If the prompt fails it will be noted and I'll fallback to traditional search engines to derive a reference to a specific vendor API document.
|
|
*/
|
|
#if 0
|
|
int main()
|
|
{
|
|
VArena cache_arena; varena_init(cache_arena);
|
|
StrCache cache = strcache_init(varena_ainfo(cache));
|
|
|
|
VArena file_arena; varena_init(file_arena);
|
|
Str path_text = lit("../demo.strcache.c");
|
|
FileContent text_file = file_read_contents(varena_ainfo(file_arena), path_text);
|
|
|
|
Arena ast_arena; arena_init(ast_arena);
|
|
|
|
WATL_ParseOps ops = { .str_cache = &cache, .node_backing = arena_ainfo(ast_arena) }
|
|
WATL_ParsedInfo parsed = watl_parse(text_file.content, ops);
|
|
|
|
watl_dbg_dump(parsed.root);
|
|
strcache_dbg_listing(cache);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
The above makes use of the following core concepts to achieve its net result:
|
|
* Slices
|
|
* Arenas
|
|
* Generic Runtime Allocator Interface
|
|
* Hashing
|
|
|
|
Secondarily for the purposes of using the above sufficiently the following are also utilized:
|
|
* Virtual Address Space
|
|
* Read/Write Files
|
|
* Lexing & Parsing
|
|
* Debug printing
|
|
|
|
TODO(Ed): Do we introduce gencpp in this?
|
|
*/
|
|
|
|
/*
|
|
First thing we'll problably want is a way to deal with text effectively.
|
|
So we'll setup the the minimum for that when dealing with immutable constructs.
|
|
*/
|
|
|
|
// We'll need some minimum set of dependencies to adequately define the constructs.
|
|
// ASSUMING MODERN MSVC TOOLCHAIN.
|
|
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
|
|
#include <intrin.h>
|
|
#include <tmmintrin.h>
|
|
#include <wmmintrin.h>
|
|
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
|
|
typedef unsigned __int8 U8;
|
|
typedef signed __int8 S8;
|
|
typedef unsigned __int16 U16;
|
|
typedef signed __int16 S16;
|
|
typedef unsigned __int32 U32;
|
|
typedef signed __int32 S32;
|
|
typedef unsigned __int64 U64;
|
|
typedef signed __int64 S64;
|
|
|
|
typedef size_t USIZE;
|
|
typedef ptrdiff_t SSIZE;
|
|
|
|
// Functional style cast
|
|
#define cast(type, data) ((type)(data))
|
|
|
|
// Enforces size querying uses SSIZE type.
|
|
#define size_of(data) cast(SSIZE, data)
|
|
|
|
/*
|
|
The first construct we'll utilize is a String Slice.
|
|
In modern programming with the memory sizes utilized, it is more ergonomic to track the length of strings with their pointer.
|
|
Most strings are not stored in some immutable table tracked statically, performance loss in doing so is negligble on modern hardware constraints.
|
|
*/
|
|
|
|
typedef struct Str8 Str8;
|
|
struct Str8 {
|
|
char const* ptr;
|
|
SSIZE len;
|
|
};
|
|
|
|
// 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 };
|
|
|
|
// For now this string can visualized using a debugger.
|
|
// #define DEMO__STR_SLICE
|
|
#ifdef DEMO__STR_SLICE
|
|
int main()
|
|
{
|
|
Str8 first = lit("Our first string as a slice");
|
|
return 0;
|
|
}
|
|
#endif DEMO__STR_SLICE
|
|
|
|
/*
|
|
We now want to be able to read a file. This will be a heavy rabbit-hole as we'll need to setup a basic file interface
|
|
and related definitions for handling the memory.
|
|
|
|
For the purposes of the initial definition we'll introduced fixed-sized memory handling statically allocated onto the stack.
|
|
*/
|
|
|
|
/*
|
|
First off we need to find out how to aquire the contents of a file on Windows.
|
|
|
|
We'll be wrapping the operation in a procedure called file_read_contents. We'll have it take a path and optional arguments (Opts__read_file_contents).
|
|
It will return a result in a composite struct: FileOpResult; which may be expanded as needed in the future.
|
|
*/
|
|
|
|
typedef struct FileOpResult FileOpResult;
|
|
typedef struct Opts__read_file_contents Opts__read_file_contents;
|
|
void file__read_contents(FileOpResult* result, Str8 path, Opts__read_file_contents* opts);
|
|
FileOpResult file_read_contents ( Str8 path, Opts__read_file_contents* opts);
|
|
|
|
/*
|
|
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.
|
|
*/
|
|
|
|
// 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.
|
|
To view or manage any slice of bytes we'll be utilizing a byte slice.
|
|
*/
|
|
typedef struct SliceByte SliceByte;
|
|
struct SliceByte {
|
|
U8* ptr;
|
|
SSIZE len;
|
|
};
|
|
|
|
/*
|
|
To address memory we'll use a memory slice.
|
|
*/
|
|
typedef struct SliceMem SliceMem;
|
|
struct SliceMem {
|
|
void* ptr;
|
|
SSIZE len;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
// 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"
|
|
|
|
|
|
#endif DEMO__FILE_READ_CONTENTS_V1
|
|
|
|
|
|
|
|
#define KILOBTYES(n) (cast(SSIZE, n) << 10)
|
|
#define MEGABYTES(n) (cast(SSIZE, n) << 20)
|
|
#define GIGABYTES(n) (cast(SSIZE, n) << 30)
|
|
#define TERABYTES(n) (cast(SSIZE, n) << 40)
|
|
|
|
/*
|
|
We'll be defining here Fixed-sized memory blocks using typedefs on-demand
|
|
|
|
They will having the following format:
|
|
typedef U8 FMem_<size>KB [ <U8 amount> ];
|
|
*/
|
|
|
|
typedef U8 FMem_1KB [ KILOBTYES(1) ];
|
|
|