initial commit
This commit is contained in:
193
demo.str_cache.c
Normal file
193
demo.str_cache.c
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
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) ];
|
||||
|
Reference in New Issue
Block a user