Improve flags in string library

This commit is contained in:
Krzosa Karol
2024-01-13 08:18:39 +01:00
parent eb60189b4b
commit 2cb4160497
12 changed files with 247 additions and 188 deletions

View File

@@ -3,6 +3,6 @@ call ../misc/compile_setup.bat
mkdir build mkdir build
cd build cd build
cl -Fe:bld.exe ../build_tool/build_main.cpp -WX -W3 -wd4200 -diagnostics:column -nologo -Zi -D_CRT_SECURE_NO_WARNINGS cl -Fe:bld.exe ../build_tool/build_main.cpp -FC -WX -W3 -wd4200 -diagnostics:column -nologo -Zi -D_CRT_SECURE_NO_WARNINGS
cd .. cd ..
build\bld.exe build\bld.exe

View File

@@ -8,7 +8,7 @@ int Main() {
Strs files = ListDir("../tests"); Strs files = ListDir("../tests");
CompileFiles(cc, {"../tests/main_core_as_header.cpp", "../core_library/core.c"}); CompileFiles(cc, {"../tests/main_core_as_header.cpp", "../core_library/core.c"});
For(files) { For(files) {
if (S8_Find(it, "test_"_s, 0, 0)) { if (S8_Find(it, "test_"_s)) {
CompileFiles(cc, it); CompileFiles(cc, it);
} }
} }

View File

@@ -43,134 +43,11 @@ DEBUG = -fsanitize=address
#define AND_CL_STRING_TERMINATE_ON_NEW_LINE #define AND_CL_STRING_TERMINATE_ON_NEW_LINE
#include "../standalone_libraries/clexer.c" #include "../standalone_libraries/clexer.c"
#define SRC_CACHE_ENTRY_COUNT 1024
struct SRC_CacheEntry {
uint64_t filepath_hash;
uint64_t file_hash;
uint64_t includes_hash;
uint64_t total_hash;
};
struct SRC_Cache {
int entry_cap;
int entry_len;
SRC_CacheEntry entries[SRC_CACHE_ENTRY_COUNT];
};
double SRC_Time;
SRC_Cache *SRC_InMemoryCache;
SRC_Cache *SRC_FromFileCache;
CL_ArenaTuple SRC_ArenaTuple;
S8_String SRC_CacheFilename;
MA_Arena PernamentArena; MA_Arena PernamentArena;
MA_Arena *Perm = &PernamentArena; MA_Arena *Perm = &PernamentArena;
CL_SearchPaths SRC_SearchPaths = {}; // @todo;
Table<S8_String> CMDLine; Table<S8_String> CMDLine;
void SRC_InitCache(MA_Arena *arena, S8_String cachefilename) { #include "cache.c"
SRC_CacheFilename = cachefilename;
CL_InitDefaultTuple(&SRC_ArenaTuple);
SRC_InMemoryCache = MA_PushStruct(arena, SRC_Cache);
SRC_InMemoryCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
SRC_FromFileCache = MA_PushStruct(arena, SRC_Cache);
SRC_FromFileCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
S8_String cache = OS_ReadFile(arena, SRC_CacheFilename);
if (cache.len) MA_MemoryCopy(SRC_FromFileCache, cache.str, cache.len);
}
void SRC_SaveCache() {
S8_String dump = S8_Make((char *)SRC_InMemoryCache, sizeof(SRC_Cache));
OS_WriteFile(SRC_CacheFilename, dump);
}
SRC_CacheEntry *SRC_AddHash(uint64_t filepath, uint64_t file, uint64_t includes) {
IO_Assert(SRC_InMemoryCache->entry_len + 1 < SRC_InMemoryCache->entry_cap);
SRC_CacheEntry *result = SRC_InMemoryCache->entries + SRC_InMemoryCache->entry_len++;
result->filepath_hash = filepath;
result->file_hash = file;
result->includes_hash = includes;
result->total_hash = HashBytes(result, sizeof(uint64_t) * 3);
return result;
}
SRC_CacheEntry *SRC_FindCache(SRC_Cache *cache, uint64_t filepath_hash) {
for (int cache_i = 0; cache_i < cache->entry_len; cache_i += 1) {
SRC_CacheEntry *it = cache->entries + cache_i;
if (it->filepath_hash == filepath_hash) {
return it;
}
}
return 0;
}
SRC_CacheEntry *SRC_HashFile(S8_String file, char *parent_file) {
char *resolved_file = CL_ResolveFilepath(Perm, &SRC_SearchPaths, file.str, parent_file, false);
if (!resolved_file) {
IO_Printf("Failed to resolve file: %s\n", file.str);
return 0;
}
uint64_t filepath_hash = HashBytes(resolved_file, S8_Length(resolved_file));
SRC_CacheEntry *entry = SRC_FindCache(SRC_InMemoryCache, filepath_hash);
if (entry) return entry;
CL_LexResult *first_lex = CL_LexFile(&SRC_ArenaTuple, resolved_file);
IO_Assert(first_lex);
uint64_t file_hash = HashBytes(first_lex->stream_begin, first_lex->stream - first_lex->stream_begin);
uint64_t includes_hash = 13;
CL_LexList list = CL_MakeLexList(first_lex);
for (CL_IncludeIter iter = CL_IterateIncludes(&list); iter.filename; CL_GetNextInclude(&iter)) {
if (iter.is_system_include) continue;
S8_String file_it = S8_MakeFromChar(iter.filename);
SRC_CacheEntry *cache = SRC_HashFile(file_it, resolved_file);
if (!cache) {
IO_Printf("Missing cache for: %s\n", file_it.str);
continue;
}
includes_hash = HashMix(includes_hash, cache->total_hash);
}
SRC_CacheEntry *result = SRC_AddHash(filepath_hash, file_hash, includes_hash);
return result;
}
bool SRC_WasModified(S8_String file, S8_String artifact_path) {
double time_start = OS_GetTime();
if (OS_FileExists(file) == false) {
IO_Printf("FAILED File doesnt exist: %.*s\n", S8_Expand(file));
exit(0);
}
if (OS_IsAbsolute(file) == false) {
file = OS_GetAbsolutePath(Perm, file);
}
S8_String without_ext = S8_ChopLastPeriod(file);
S8_String name_only = S8_SkipToLastSlash(without_ext);
if (artifact_path.len == 0) artifact_path = S8_Format(Perm, "%.*s.%s", S8_Expand(name_only), IF_WINDOWS_ELSE("obj", "o"));
bool modified = OS_FileExists(artifact_path) == false;
SRC_CacheEntry *in_memory = SRC_HashFile(file, 0);
IO_Assert(in_memory);
if (modified == false) {
SRC_CacheEntry *from_file = SRC_FindCache(SRC_FromFileCache, in_memory->filepath_hash);
if (from_file == 0 || (in_memory->total_hash != from_file->total_hash)) {
modified = true;
}
}
SRC_Time = SRC_Time + (OS_GetTime() - time_start);
return modified;
}
// //
// //

View File

@@ -28,7 +28,7 @@ int main(int argument_count, char **arguments) {
{ {
S8_List files_current_dir = OS_ListDir(Perm, S8_Lit(".."), 0); S8_List files_current_dir = OS_ListDir(Perm, S8_Lit(".."), 0);
for (S8_Node *it = files_current_dir.first; it; it = it->next) { for (S8_Node *it = files_current_dir.first; it; it = it->next) {
if (S8_Find(it->string, S8_Lit("build_file.c"), S8_IGNORE_CASE, 0)) { if (S8_Find(it->string, S8_Lit("build_file.c"), S8_IgnoreCase)) {
build_file = it->string; build_file = it->string;
} }
} }

126
build_tool/cache.c Normal file
View File

@@ -0,0 +1,126 @@
#define SRC_CACHE_ENTRY_COUNT 1024
struct SRC_CacheEntry {
uint64_t filepath_hash;
uint64_t file_hash;
uint64_t includes_hash;
uint64_t total_hash;
};
struct SRC_Cache {
int entry_cap;
int entry_len;
SRC_CacheEntry entries[SRC_CACHE_ENTRY_COUNT];
};
double SRC_Time;
SRC_Cache *SRC_InMemoryCache;
SRC_Cache *SRC_FromFileCache;
CL_ArenaTuple SRC_ArenaTuple;
S8_String SRC_CacheFilename;
CL_SearchPaths SRC_SearchPaths = {}; // @todo;
void SRC_InitCache(MA_Arena *arena, S8_String cachefilename) {
SRC_CacheFilename = cachefilename;
CL_InitDefaultTuple(&SRC_ArenaTuple);
SRC_InMemoryCache = MA_PushStruct(arena, SRC_Cache);
SRC_InMemoryCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
SRC_FromFileCache = MA_PushStruct(arena, SRC_Cache);
SRC_FromFileCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
S8_String cache = OS_ReadFile(arena, SRC_CacheFilename);
if (cache.len) MA_MemoryCopy(SRC_FromFileCache, cache.str, cache.len);
}
void SRC_SaveCache() {
S8_String dump = S8_Make((char *)SRC_InMemoryCache, sizeof(SRC_Cache));
OS_WriteFile(SRC_CacheFilename, dump);
}
SRC_CacheEntry *SRC_AddHash(uint64_t filepath, uint64_t file, uint64_t includes) {
IO_Assert(SRC_InMemoryCache->entry_len + 1 < SRC_InMemoryCache->entry_cap);
SRC_CacheEntry *result = SRC_InMemoryCache->entries + SRC_InMemoryCache->entry_len++;
result->filepath_hash = filepath;
result->file_hash = file;
result->includes_hash = includes;
result->total_hash = HashBytes(result, sizeof(uint64_t) * 3);
return result;
}
SRC_CacheEntry *SRC_FindCache(SRC_Cache *cache, uint64_t filepath_hash) {
for (int cache_i = 0; cache_i < cache->entry_len; cache_i += 1) {
SRC_CacheEntry *it = cache->entries + cache_i;
if (it->filepath_hash == filepath_hash) {
return it;
}
}
return 0;
}
SRC_CacheEntry *SRC_HashFile(S8_String file, char *parent_file) {
char *resolved_file = CL_ResolveFilepath(Perm, &SRC_SearchPaths, file.str, parent_file, false);
if (!resolved_file) {
IO_Printf("Failed to resolve file: %s\n", file.str);
return 0;
}
uint64_t filepath_hash = HashBytes(resolved_file, S8_Length(resolved_file));
SRC_CacheEntry *entry = SRC_FindCache(SRC_InMemoryCache, filepath_hash);
if (entry) return entry;
CL_LexResult *first_lex = CL_LexFile(&SRC_ArenaTuple, resolved_file);
IO_Assert(first_lex);
uint64_t file_hash = HashBytes(first_lex->stream_begin, first_lex->stream - first_lex->stream_begin);
uint64_t includes_hash = 13;
CL_LexList list = CL_MakeLexList(first_lex);
for (CL_IncludeIter iter = CL_IterateIncludes(&list); iter.filename; CL_GetNextInclude(&iter)) {
if (iter.is_system_include) continue;
S8_String file_it = S8_MakeFromChar(iter.filename);
SRC_CacheEntry *cache = SRC_HashFile(file_it, resolved_file);
if (!cache) {
IO_Printf("Missing cache for: %s\n", file_it.str);
continue;
}
includes_hash = HashMix(includes_hash, cache->total_hash);
}
SRC_CacheEntry *result = SRC_AddHash(filepath_hash, file_hash, includes_hash);
return result;
}
bool SRC_WasModified(S8_String file, S8_String artifact_path) {
double time_start = OS_GetTime();
if (OS_FileExists(file) == false) {
IO_Printf("FAILED File doesnt exist: %.*s\n", S8_Expand(file));
exit(0);
}
if (OS_IsAbsolute(file) == false) {
file = OS_GetAbsolutePath(Perm, file);
}
S8_String without_ext = S8_ChopLastPeriod(file);
S8_String name_only = S8_SkipToLastSlash(without_ext);
if (artifact_path.len == 0) artifact_path = S8_Format(Perm, "%.*s.%s", S8_Expand(name_only), IF_WINDOWS_ELSE("obj", "o"));
bool modified = OS_FileExists(artifact_path) == false;
SRC_CacheEntry *in_memory = SRC_HashFile(file, 0);
IO_Assert(in_memory);
if (modified == false) {
SRC_CacheEntry *from_file = SRC_FindCache(SRC_FromFileCache, in_memory->filepath_hash);
if (from_file == 0 || (in_memory->total_hash != from_file->total_hash)) {
modified = true;
}
}
SRC_Time = SRC_Time + (OS_GetTime() - time_start);
return modified;
}

View File

@@ -1,5 +1,19 @@
#include "core.h" /*
@todo
- Rewrite OS_ListDir, no weird flags and conventions, [relative, absolute, is_dir]
- add c++ default args using macros
- Rework string flags
- String should use allocator instead of arena?
- Maybe remove completely null termination from S8_String, I think it might complicate and is error prone because one can sometimes assume it's null terminated and it isn't
- Maybe create a nice C++ binding for strings,
- also add String Arrays and String Builder, temp allocators hook ins for nicer api
- Iterating over unicode codepoints using For
- Redesign clexer because the Arena Tuple is hella weird
- Maybe remove token array stuff, do standard stream thing, then you need one arena ...
- Add filter stuff so we can get includes / comments / normal tokens etc.
*/
#include "core.h"
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#include "../standalone_libraries/stb_sprintf.h" #include "../standalone_libraries/stb_sprintf.h"
#define IO_VSNPRINTF stbsp_vsnprintf #define IO_VSNPRINTF stbsp_vsnprintf
@@ -20,3 +34,7 @@
#include "../standalone_libraries/hash.c" #include "../standalone_libraries/hash.c"
#include "../standalone_libraries/load_library.c" #include "../standalone_libraries/load_library.c"
#include "filesystem.c" #include "filesystem.c"
// #if LANG_CPP
// #include "string.cpp"
// #endif

View File

@@ -12,7 +12,7 @@
#include "../standalone_libraries/load_library.h" #include "../standalone_libraries/load_library.h"
#include "filesystem.h" #include "filesystem.h"
#ifdef __cplusplus #if LANG_CPP
#include "../standalone_libraries/defer.hpp" #include "../standalone_libraries/defer.hpp"
#define TABLE_ASSERT IO_Assert #define TABLE_ASSERT IO_Assert
#define TABLE_Allocator M_Allocator #define TABLE_Allocator M_Allocator
@@ -28,4 +28,5 @@
#define ARRAY_SET_DEFAULT_ALLOCATOR \ #define ARRAY_SET_DEFAULT_ALLOCATOR \
if (!allocator.p) allocator = M_GetSystemAllocator(); if (!allocator.p) allocator = M_GetSystemAllocator();
#include "../standalone_libraries/array.hpp" #include "../standalone_libraries/array.hpp"
// #include "string.hpp"
#endif #endif

View File

@@ -1,7 +1,3 @@
#include "filesystem.h"
#define OS_LENGTHOF(x) ((int64_t)((sizeof(x) / sizeof((x)[0]))))
#ifdef _WIN32 #ifdef _WIN32
#ifndef NOMINMAX #ifndef NOMINMAX
#define NOMINMAX #define NOMINMAX
@@ -47,7 +43,7 @@ OS_API bool OS_IsAbsolute(S8_String path) {
OS_API S8_String OS_GetExePath(MA_Arena *arena) { OS_API S8_String OS_GetExePath(MA_Arena *arena) {
wchar_t wbuffer[1024]; wchar_t wbuffer[1024];
DWORD wsize = GetModuleFileNameW(0, wbuffer, OS_LENGTHOF(wbuffer)); DWORD wsize = GetModuleFileNameW(0, wbuffer, MA_LENGTHOF(wbuffer));
IO_Assert(wsize != 0); IO_Assert(wsize != 0);
S8_String path = UTF_CreateStringFromWidechar(arena, wbuffer, wsize); S8_String path = UTF_CreateStringFromWidechar(arena, wbuffer, wsize);
@@ -64,7 +60,7 @@ OS_API S8_String OS_GetExeDir(MA_Arena *arena) {
OS_API S8_String OS_GetWorkingDir(MA_Arena *arena) { OS_API S8_String OS_GetWorkingDir(MA_Arena *arena) {
wchar_t wbuffer[1024]; wchar_t wbuffer[1024];
DWORD wsize = GetCurrentDirectoryW(OS_LENGTHOF(wbuffer), wbuffer); DWORD wsize = GetCurrentDirectoryW(MA_LENGTHOF(wbuffer), wbuffer);
IO_Assert(wsize != 0); IO_Assert(wsize != 0);
IO_Assert(wsize < 1022); IO_Assert(wsize < 1022);
wbuffer[wsize++] = '/'; wbuffer[wsize++] = '/';
@@ -77,15 +73,15 @@ OS_API S8_String OS_GetWorkingDir(MA_Arena *arena) {
OS_API void OS_SetWorkingDir(S8_String path) { OS_API void OS_SetWorkingDir(S8_String path) {
wchar_t wpath[1024]; wchar_t wpath[1024];
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len); UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
SetCurrentDirectoryW(wpath); SetCurrentDirectoryW(wpath);
} }
OS_API S8_String OS_GetAbsolutePath(MA_Arena *arena, S8_String relative) { OS_API S8_String OS_GetAbsolutePath(MA_Arena *arena, S8_String relative) {
wchar_t wpath[1024]; wchar_t wpath[1024];
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), relative.str, relative.len); UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), relative.str, relative.len);
wchar_t wpath_abs[1024]; wchar_t wpath_abs[1024];
DWORD written = GetFullPathNameW((wchar_t *)wpath, OS_LENGTHOF(wpath_abs), wpath_abs, 0); DWORD written = GetFullPathNameW((wchar_t *)wpath, MA_LENGTHOF(wpath_abs), wpath_abs, 0);
if (written == 0) if (written == 0)
return S8_MakeEmpty(); return S8_MakeEmpty();
S8_String path = UTF_CreateStringFromWidechar(arena, wpath_abs, written); S8_String path = UTF_CreateStringFromWidechar(arena, wpath_abs, written);
@@ -95,7 +91,7 @@ OS_API S8_String OS_GetAbsolutePath(MA_Arena *arena, S8_String relative) {
OS_API bool OS_FileExists(S8_String path) { OS_API bool OS_FileExists(S8_String path) {
wchar_t wbuff[1024]; wchar_t wbuff[1024];
UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), path.str, path.len); UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), path.str, path.len);
DWORD attribs = GetFileAttributesW(wbuff); DWORD attribs = GetFileAttributesW(wbuff);
bool result = attribs == INVALID_FILE_ATTRIBUTES ? false : true; bool result = attribs == INVALID_FILE_ATTRIBUTES ? false : true;
return result; return result;
@@ -103,14 +99,14 @@ OS_API bool OS_FileExists(S8_String path) {
OS_API bool OS_IsDir(S8_String path) { OS_API bool OS_IsDir(S8_String path) {
wchar_t wbuff[1024]; wchar_t wbuff[1024];
UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), path.str, path.len); UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), path.str, path.len);
DWORD dwAttrib = GetFileAttributesW(wbuff); DWORD dwAttrib = GetFileAttributesW(wbuff);
return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY); return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
} }
OS_API bool OS_IsFile(S8_String path) { OS_API bool OS_IsFile(S8_String path) {
wchar_t wbuff[1024]; wchar_t wbuff[1024];
UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), path.str, path.len); UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), path.str, path.len);
DWORD dwAttrib = GetFileAttributesW(wbuff); DWORD dwAttrib = GetFileAttributesW(wbuff);
bool is_file = (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0; bool is_file = (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0;
return dwAttrib != INVALID_FILE_ATTRIBUTES && is_file; return dwAttrib != INVALID_FILE_ATTRIBUTES && is_file;
@@ -143,8 +139,8 @@ OS_API S8_List OS_ListDir(MA_Arena *arena, S8_String path, unsigned flags) {
for (S8_Node *it = dirs_to_read.first; it; it = it->next) { for (S8_Node *it = dirs_to_read.first; it; it = it->next) {
wchar_t wbuff[1024]; wchar_t wbuff[1024];
S8_String modified_path = S8_Format(scratch.arena, "%.*s\\*", (int)it->string.len, it->string.str); S8_String modified_path = S8_Format(scratch.arena, "%.*s\\*", (int)it->string.len, it->string.str);
IO_Assert(modified_path.len < OS_LENGTHOF(wbuff)); IO_Assert(modified_path.len < MA_LENGTHOF(wbuff));
int64_t wsize = UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), modified_path.str, modified_path.len); int64_t wsize = UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), modified_path.str, modified_path.len);
IO_Assert(wsize); IO_Assert(wsize);
WIN32_FIND_DATAW ffd; WIN32_FIND_DATAW ffd;
@@ -197,7 +193,7 @@ OS_API S8_List OS_ListDir(MA_Arena *arena, S8_String path, unsigned flags) {
OS_API OS_Result OS_MakeDir(S8_String path) { OS_API OS_Result OS_MakeDir(S8_String path) {
wchar_t wpath[1024]; wchar_t wpath[1024];
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len); UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
BOOL success = CreateDirectoryW(wpath, NULL); BOOL success = CreateDirectoryW(wpath, NULL);
OS_Result result = OS_SUCCESS; OS_Result result = OS_SUCCESS;
if (success == 0) { if (success == 0) {
@@ -217,10 +213,10 @@ OS_API OS_Result OS_MakeDir(S8_String path) {
OS_API OS_Result OS_CopyFile(S8_String from, S8_String to, bool overwrite) { OS_API OS_Result OS_CopyFile(S8_String from, S8_String to, bool overwrite) {
wchar_t wfrom[1024]; wchar_t wfrom[1024];
UTF_CreateWidecharFromChar(wfrom, OS_LENGTHOF(wfrom), from.str, from.len); UTF_CreateWidecharFromChar(wfrom, MA_LENGTHOF(wfrom), from.str, from.len);
wchar_t wto[1024]; wchar_t wto[1024];
UTF_CreateWidecharFromChar(wto, OS_LENGTHOF(wto), to.str, to.len); UTF_CreateWidecharFromChar(wto, MA_LENGTHOF(wto), to.str, to.len);
BOOL fail_if_exists = !overwrite; BOOL fail_if_exists = !overwrite;
BOOL success = CopyFileW(wfrom, wto, fail_if_exists); BOOL success = CopyFileW(wfrom, wto, fail_if_exists);
@@ -233,7 +229,7 @@ OS_API OS_Result OS_CopyFile(S8_String from, S8_String to, bool overwrite) {
OS_API OS_Result OS_DeleteFile(S8_String path) { OS_API OS_Result OS_DeleteFile(S8_String path) {
wchar_t wpath[1024]; wchar_t wpath[1024];
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len); UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
BOOL success = DeleteFileW(wpath); BOOL success = DeleteFileW(wpath);
OS_Result result = OS_SUCCESS; OS_Result result = OS_SUCCESS;
if (success == 0) if (success == 0)
@@ -247,7 +243,7 @@ OS_API OS_Result OS_DeleteDir(S8_String path, unsigned flags) {
S8_List list = OS_ListDir(scratch.arena, path, OS_RECURSIVE); S8_List list = OS_ListDir(scratch.arena, path, OS_RECURSIVE);
S8_Node *dirs_to_remove = 0; S8_Node *dirs_to_remove = 0;
for (S8_Node *it = list.first; it; it = it->next) { for (S8_Node *it = list.first; it; it = it->next) {
if (!S8_EndsWith(it->string, S8_Lit("/"), S8_IGNORE_CASE)) { if (!S8_EndsWith(it->string, S8_Lit("/"), S8_IgnoreCase)) {
OS_DeleteFile(it->string); OS_DeleteFile(it->string);
} }
else { else {
@@ -264,7 +260,7 @@ OS_API OS_Result OS_DeleteDir(S8_String path, unsigned flags) {
} }
else { else {
wchar_t wpath[1024]; wchar_t wpath[1024];
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len); UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
BOOL success = RemoveDirectoryW(wpath); BOOL success = RemoveDirectoryW(wpath);
OS_Result result = OS_SUCCESS; OS_Result result = OS_SUCCESS;
if (success == 0) if (success == 0)
@@ -275,7 +271,7 @@ OS_API OS_Result OS_DeleteDir(S8_String path, unsigned flags) {
static OS_Result OS__WriteFile(S8_String path, S8_String data, bool append) { static OS_Result OS__WriteFile(S8_String path, S8_String data, bool append) {
wchar_t wpath[1024]; wchar_t wpath[1024];
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len); UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
OS_Result result = OS_FAILURE; OS_Result result = OS_FAILURE;
DWORD access = GENERIC_WRITE; DWORD access = GENERIC_WRITE;
@@ -316,7 +312,7 @@ OS_API S8_String OS_ReadFile(MA_Arena *arena, S8_String path) {
MA_Checkpoint checkpoint = MA_Save(arena); MA_Checkpoint checkpoint = MA_Save(arena);
wchar_t wpath[1024]; wchar_t wpath[1024];
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len); UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
HANDLE handle = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); HANDLE handle = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE) { if (handle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER file_size; LARGE_INTEGER file_size;
@@ -680,7 +676,7 @@ OS_API S8_List S8_SplitOnRegex(MA_Arena *arena, S8_String string, S8_String rege
S8_String before_match = S8_Make(string.str, match.pos); S8_String before_match = S8_Make(string.str, match.pos);
S8_String the_match = S8_Make(string.str + match.pos, match.size); S8_String the_match = S8_Make(string.str + match.pos, match.size);
if (before_match.len) S8_AddNode(arena, &result, before_match); if (before_match.len) S8_AddNode(arena, &result, before_match);
if (flags & S8_SPLIT_INCLUSIVE) { if (flags & S8_SplitFlag_SplitInclusive) {
if (the_match.len) S8_AddNode(arena, &result, the_match); if (the_match.len) S8_AddNode(arena, &result, the_match);
} }
string = S8_Skip(string, match.pos + match.size); string = S8_Skip(string, match.pos + match.size);

View File

@@ -1,4 +1,3 @@
#pragma once
// Quick and dirty filesystem operations // Quick and dirty filesystem operations
#ifndef OS_API #ifndef OS_API

View File

@@ -74,7 +74,7 @@ S8_API bool S8_AreEqual(S8_String a, S8_String b, unsigned ignore_case) {
for (int64_t i = 0; i < a.len; i++) { for (int64_t i = 0; i < a.len; i++) {
char A = a.str[i]; char A = a.str[i];
char B = b.str[i]; char B = b.str[i];
if (ignore_case & S8_IGNORE_CASE) { if (ignore_case) {
A = CHAR_ToLowerCase(A); A = CHAR_ToLowerCase(A);
B = CHAR_ToLowerCase(B); B = CHAR_ToLowerCase(B);
} }
@@ -169,6 +169,10 @@ S8_API S8_String S8_GetPrefix(S8_String string, int64_t len) {
return result; return result;
} }
S8_API S8_String S8_GetNameNoExtension(S8_String s) {
return S8_SkipToLastSlash(S8_ChopLastPeriod(s));
}
S8_API S8_String S8_Slice(S8_String string, int64_t first_index, int64_t one_past_last_index) { S8_API S8_String S8_Slice(S8_String string, int64_t first_index, int64_t one_past_last_index) {
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1; if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
if (first_index < 0) first_index = string.len + first_index; if (first_index < 0) first_index = string.len + first_index;
@@ -245,13 +249,14 @@ S8_API S8_String S8_ToUpperCase(S8_Allocator allocator, S8_String s) {
return copy; return copy;
} }
S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *index_out) { S8_API bool S8_Find(S8_String string, S8_String find, S8_FindFlag flags, int64_t *index_out) {
bool ignore_case = flags & S8_FindFlag_IgnoreCase ? true : false;
bool result = false; bool result = false;
if (flags & S8_MATCH_FIND_LAST) { if (flags & S8_FindFlag_MatchFindLast) {
for (int64_t i = string.len; i != 0; i--) { for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1; int64_t index = i - 1;
S8_String substring = S8_Slice(string, index, index + find.len); S8_String substring = S8_Slice(string, index, index + find.len);
if (S8_AreEqual(substring, find, flags)) { if (S8_AreEqual(substring, find, ignore_case)) {
if (index_out) if (index_out)
*index_out = index; *index_out = index;
result = true; result = true;
@@ -262,7 +267,7 @@ S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *i
else { else {
for (int64_t i = 0; i < string.len; i++) { for (int64_t i = 0; i < string.len; i++) {
S8_String substring = S8_Slice(string, i, i + find.len); S8_String substring = S8_Slice(string, i, i + find.len);
if (S8_AreEqual(substring, find, flags)) { if (S8_AreEqual(substring, find, ignore_case)) {
if (index_out) if (index_out)
*index_out = i; *index_out = i;
result = true; result = true;
@@ -274,14 +279,15 @@ S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *i
return result; return result;
} }
S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags) { S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, S8_SplitFlag flags) {
S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0);
S8_List result = S8_MakeEmptyList(); S8_List result = S8_MakeEmptyList();
int64_t index = 0; int64_t index = 0;
while (S8_Find(string, find, flags, &index)) {
S8_FindFlag find_flag = flags & S8_SplitFlag_IgnoreCase ? S8_FindFlag_IgnoreCase : S8_FindFlag_None;
while (S8_Find(string, find, find_flag, &index)) {
S8_String before_match = S8_Make(string.str, index); S8_String before_match = S8_Make(string.str, index);
S8_AddNode(allocator, &result, before_match); S8_AddNode(allocator, &result, before_match);
if (flags & S8_SPLIT_INCLUSIVE) { if (flags & S8_SplitFlag_SplitInclusive) {
S8_String match = S8_Make(string.str + index, find.len); S8_String match = S8_Make(string.str + index, find.len);
S8_AddNode(allocator, &result, match); S8_AddNode(allocator, &result, match);
} }
@@ -294,7 +300,7 @@ S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find
S8_API S8_String S8_MergeWithSeparator(S8_Allocator allocator, S8_List list, S8_String separator) { S8_API S8_String S8_MergeWithSeparator(S8_Allocator allocator, S8_List list, S8_String separator) {
if (list.node_count == 0) return S8_MakeEmpty(); if (list.node_count == 0) return S8_MakeEmpty();
if (list.char_count == 0) return S8_MakeEmpty(); if (list.char_count == 0) return S8_MakeEmpty();
// S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0);
int64_t base_size = (list.char_count + 1); int64_t base_size = (list.char_count + 1);
int64_t sep_size = (list.node_count - 1) * separator.len; int64_t sep_size = (list.node_count - 1) * separator.len;
int64_t size = base_size + sep_size; int64_t size = base_size + sep_size;
@@ -318,11 +324,11 @@ S8_API S8_String S8_Merge(S8_Allocator allocator, S8_List list) {
return S8_MergeWithSeparator(allocator, list, S8_Lit("")); return S8_MergeWithSeparator(allocator, list, S8_Lit(""));
} }
S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, unsigned flags) { S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, bool ignore_case) {
S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0); S8_SplitFlag split_flag = ignore_case ? S8_SplitFlag_IgnoreCase : S8_SplitFlag_None;
S8_List list = S8_Split(allocator, string, replace, flags | S8_SPLIT_INCLUSIVE); S8_List list = S8_Split(allocator, string, replace, split_flag | S8_SplitFlag_SplitInclusive);
for (S8_Node *it = list.first; it; it = it->next) { for (S8_Node *it = list.first; it; it = it->next) {
if (S8_AreEqual(it->string, replace, flags)) { if (S8_AreEqual(it->string, replace, ignore_case)) {
S8_ReplaceNodeString(&list, it, with); S8_ReplaceNodeString(&list, it, with);
} }
} }
@@ -330,11 +336,12 @@ S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_Stri
return result; return result;
} }
S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags) { // @untested S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, bool ignore_case) { // @untested
S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0);
S8_List result = S8_MakeEmptyList(); S8_List result = S8_MakeEmptyList();
int64_t index = 0; int64_t index = 0;
while (S8_Find(string, find, flags, &index)) {
S8_FindFlag find_flag = ignore_case ? S8_FindFlag_IgnoreCase : 0;
while (S8_Find(string, find, find_flag, &index)) {
S8_String match = S8_Make(string.str + index, find.len); S8_String match = S8_Make(string.str + index, find.len);
S8_AddNode(allocator, &result, match); S8_AddNode(allocator, &result, match);
string = S8_Skip(string, index + find.len); string = S8_Skip(string, index + find.len);
@@ -344,20 +351,20 @@ S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String fi
S8_API S8_String S8_ChopLastSlash(S8_String s) { S8_API S8_String S8_ChopLastSlash(S8_String s) {
S8_String result = s; S8_String result = s;
S8_Find(s, S8_Lit("/"), S8_MATCH_FIND_LAST, &result.len); S8_Find(s, S8_Lit("/"), S8_FindFlag_MatchFindLast, &result.len);
return result; return result;
} }
S8_API S8_String S8_ChopLastPeriod(S8_String s) { S8_API S8_String S8_ChopLastPeriod(S8_String s) {
S8_String result = s; S8_String result = s;
S8_Find(s, S8_Lit("."), S8_MATCH_FIND_LAST, &result.len); S8_Find(s, S8_Lit("."), S8_FindFlag_MatchFindLast, &result.len);
return result; return result;
} }
S8_API S8_String S8_SkipToLastSlash(S8_String s) { S8_API S8_String S8_SkipToLastSlash(S8_String s) {
int64_t pos; int64_t pos;
S8_String result = s; S8_String result = s;
if (S8_Find(s, S8_Lit("/"), S8_MATCH_FIND_LAST, &pos)) { if (S8_Find(s, S8_Lit("/"), S8_FindFlag_MatchFindLast, &pos)) {
result = S8_Skip(result, pos + 1); result = S8_Skip(result, pos + 1);
} }
return result; return result;
@@ -366,7 +373,7 @@ S8_API S8_String S8_SkipToLastSlash(S8_String s) {
S8_API S8_String S8_SkipToLastPeriod(S8_String s) { S8_API S8_String S8_SkipToLastPeriod(S8_String s) {
int64_t pos; int64_t pos;
S8_String result = s; S8_String result = s;
if (S8_Find(s, S8_Lit("."), S8_MATCH_FIND_LAST, &pos)) { if (S8_Find(s, S8_Lit("."), S8_FindFlag_MatchFindLast, &pos)) {
result = S8_Skip(result, pos + 1); result = S8_Skip(result, pos + 1);
} }
return result; return result;

View File

@@ -11,6 +11,12 @@
#endif #endif
#endif #endif
#ifdef __cplusplus
#define S8_IF_CPP(x) x
#else
#define S8_IF_CPP(x)
#endif
#ifndef S8_Allocator #ifndef S8_Allocator
struct MA_Arena; struct MA_Arena;
#define S8_Allocator MA_Arena * #define S8_Allocator MA_Arena *
@@ -19,12 +25,26 @@ struct MA_Arena;
typedef struct S8_String S8_String; typedef struct S8_String S8_String;
typedef struct S8_Node S8_Node; typedef struct S8_Node S8_Node;
typedef struct S8_List S8_List; typedef struct S8_List S8_List;
S8_API int64_t S8_Length(char *string);
struct S8_String { struct S8_String {
char *str; char *str;
int64_t len; int64_t len;
}; };
// #ifdef __cplusplus
// struct String : S8_String {
// String() = default;
// String(char *s) : S8_String{s, S8_Length(s)} {}
// String(char *s, int64_t l) : S8_String{s, l} {}
// String(const char *s) : S8_String{(char *)s, S8_Length((char *)s)} {}
// String(const char *s, int64_t l) : S8_String{(char *)s, l} {}
// String(S8_String s) : S8_String{s.str, s.len} {}
// // @todo add unicode iterator
// };
// #endif
struct S8_Node { struct S8_Node {
S8_Node *next; S8_Node *next;
S8_String string; S8_String string;
@@ -37,11 +57,20 @@ struct S8_List {
S8_Node *last; S8_Node *last;
}; };
const int S8_IgnoreCase = true;
typedef int S8_FindFlag;
enum { enum {
S8_NO_FLAGS = 0, S8_FindFlag_None = 0,
S8_IGNORE_CASE = 1, S8_FindFlag_IgnoreCase = 1,
S8_SPLIT_INCLUSIVE = 4, S8_FindFlag_MatchFindLast = 2,
S8_MATCH_FIND_LAST = 32, };
typedef int S8_SplitFlag;
enum {
S8_SplitFlag_None = 0,
S8_SplitFlag_IgnoreCase = 1,
S8_SplitFlag_SplitInclusive = 2,
}; };
#if defined(__has_attribute) #if defined(__has_attribute)
@@ -80,9 +109,9 @@ S8_API bool CHAR_IsAlphabetic(char a);
S8_API bool CHAR_IsIdent(char a); S8_API bool CHAR_IsIdent(char a);
S8_API bool CHAR_IsDigit(char a); S8_API bool CHAR_IsDigit(char a);
S8_API bool CHAR_IsAlphanumeric(char a); S8_API bool CHAR_IsAlphanumeric(char a);
S8_API bool S8_AreEqual(S8_String a, S8_String b, unsigned ignore_case); S8_API bool S8_AreEqual(S8_String a, S8_String b, unsigned ignore_case S8_IF_CPP(= false));
S8_API bool S8_EndsWith(S8_String a, S8_String end, unsigned ignore_case); S8_API bool S8_EndsWith(S8_String a, S8_String end, unsigned ignore_case S8_IF_CPP(= false));
S8_API bool S8_StartsWith(S8_String a, S8_String start, unsigned ignore_case); S8_API bool S8_StartsWith(S8_String a, S8_String start, unsigned ignore_case S8_IF_CPP(= false));
S8_API S8_String S8_Make(char *str, int64_t len); S8_API S8_String S8_Make(char *str, int64_t len);
S8_API S8_String S8_Copy(S8_Allocator allocator, S8_String string); S8_API S8_String S8_Copy(S8_Allocator allocator, S8_String string);
S8_API void S8_NormalizePath(S8_String s); S8_API void S8_NormalizePath(S8_String s);
@@ -95,26 +124,28 @@ S8_API S8_String S8_Trim(S8_String string);
S8_API S8_String S8_TrimEnd(S8_String string); S8_API S8_String S8_TrimEnd(S8_String string);
S8_API S8_String S8_ToLowerCase(S8_Allocator allocator, S8_String s); S8_API S8_String S8_ToLowerCase(S8_Allocator allocator, S8_String s);
S8_API S8_String S8_ToUpperCase(S8_Allocator allocator, S8_String s); S8_API S8_String S8_ToUpperCase(S8_Allocator allocator, S8_String s);
S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *index_out); S8_API bool S8_Find(S8_String string, S8_String find, S8_FindFlag flags S8_IF_CPP(= S8_FindFlag_None), int64_t *index_out S8_IF_CPP(= 0));
S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags);
S8_API S8_String S8_MergeWithSeparator(S8_Allocator allocator, S8_List list, S8_String separator);
S8_API S8_String S8_Merge(S8_Allocator allocator, S8_List list);
S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, unsigned flags);
S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags);
S8_API S8_String S8_ChopLastSlash(S8_String s); S8_API S8_String S8_ChopLastSlash(S8_String s);
S8_API S8_String S8_ChopLastPeriod(S8_String s); S8_API S8_String S8_ChopLastPeriod(S8_String s);
S8_API S8_String S8_SkipToLastSlash(S8_String s); S8_API S8_String S8_SkipToLastSlash(S8_String s);
S8_API S8_String S8_SkipToLastPeriod(S8_String s); S8_API S8_String S8_SkipToLastPeriod(S8_String s);
S8_API S8_String S8_GetNameNoExt(S8_String s);
S8_API bool S8_IsPointerInside(S8_String string, char *p); S8_API bool S8_IsPointerInside(S8_String string, char *p);
S8_API S8_String S8_SkipToP(S8_String string, char *p); S8_API S8_String S8_SkipToP(S8_String string, char *p);
S8_API S8_String S8_SkipPast(S8_String string, S8_String a); S8_API S8_String S8_SkipPast(S8_String string, S8_String a);
S8_API int64_t S8_Length(char *string);
S8_API int64_t S8_WideLength(wchar_t *string); S8_API int64_t S8_WideLength(wchar_t *string);
S8_API S8_String S8_MakeFromChar(char *string); S8_API S8_String S8_MakeFromChar(char *string);
S8_API S8_String S8_MakeEmpty(void); S8_API S8_String S8_MakeEmpty(void);
S8_API S8_List S8_MakeEmptyList(void); S8_API S8_List S8_MakeEmptyList(void);
S8_API S8_String S8_FormatV(S8_Allocator allocator, const char *str, va_list args1); S8_API S8_String S8_FormatV(S8_Allocator allocator, const char *str, va_list args1);
S8_API S8_String S8_Format(S8_Allocator allocator, const char *str, ...) S8__PrintfFormat(2, 3); S8_API S8_String S8_Format(S8_Allocator allocator, const char *str, ...) S8__PrintfFormat(2, 3);
S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, S8_SplitFlag flags S8_IF_CPP(= S8_SplitFlag_None));
S8_API S8_String S8_MergeWithSeparator(S8_Allocator allocator, S8_List list, S8_String separator S8_IF_CPP(= " "_s));
S8_API S8_String S8_Merge(S8_Allocator allocator, S8_List list);
S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, bool ignore_case S8_IF_CPP(= false));
S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, bool ignore_case S8_IF_CPP(= false));
S8_API S8_Node *S8_CreateNode(S8_Allocator allocator, S8_String string); S8_API S8_Node *S8_CreateNode(S8_Allocator allocator, S8_String string);
S8_API void S8_ReplaceNodeString(S8_List *list, S8_Node *node, S8_String new_string); S8_API void S8_ReplaceNodeString(S8_List *list, S8_Node *node, S8_String new_string);
S8_API void S8_AddExistingNode(S8_List *list, S8_Node *node); S8_API void S8_AddExistingNode(S8_List *list, S8_Node *node);

4
tests/1test_string.cpp Normal file
View File

@@ -0,0 +1,4 @@
#include "../core_library/core.c"
int main() {
}