Files
metadesk/source/base/strings.h
T
ed 3e064f6443 progress on sanity_tests.c, adding back md_str8_styllize
Eventually a heavy reduction of base & OS should be provided via libgen or done here to reduce the overall surface area of the library for the user.
Base and os were dragged from raddbg and the original metadesk didn't need as many definitions.
2025-02-13 09:53:46 -05:00

1290 lines
68 KiB
C

#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "context_cracking.h"
# include "linkage.h"
# include "platform.h"
# include "macros.h"
# include "generic_macros.h"
# include "base_types.h"
# include "arena.h"
# include "space.h"
# include "math.h"
# include "toolchain.h"
# include "time.h"
////////////////////////////////
//~ rjf: Third Party Includes
# define STB_SPRINTF_DECORATE(name) md_##name
# include "third_party/stb/stb_sprintf.h"
#endif
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: String Types
typedef struct MD_String8 MD_String8;
struct MD_String8
{
MD_U8* str;
MD_U64 size;
};
typedef struct MD_String16 MD_String16;
struct MD_String16
{
MD_U16* str;
MD_U64 size;
};
typedef struct MD_String32 MD_String32;
struct MD_String32
{
MD_U32* str;
MD_U64 size;
};
////////////////////////////////
//~ rjf: String List & Array Types
typedef struct MD_String8Node MD_String8Node;
struct MD_String8Node
{
MD_String8Node* next;
MD_String8 string;
};
typedef struct MD_String8MetaNode MD_String8MetaNode;
struct MD_String8MetaNode
{
MD_String8MetaNode* next;
MD_String8Node* node;
};
typedef struct MD_String8List MD_String8List;
struct MD_String8List
{
MD_String8Node* first;
MD_String8Node* last;
MD_U64 node_count;
MD_U64 total_size;
};
typedef struct MD_String8Array MD_String8Array;
struct MD_String8Array
{
MD_String8* v;
MD_U64 count;
};
////////////////////////////////
//~ rjf: String Matching, Splitting, & Joining Types
typedef MD_U32 MD_StringMatchFlags;
enum
{
MD_StringMatchFlag_CaseInsensitive = (1 << 0),
MD_StringMatchFlag_RightSideSloppy = (1 << 1),
MD_StringMatchFlag_SlashInsensitive = (1 << 2),
};
typedef MD_U32 MD_StringSplitFlags;
enum
{
MD_StringSplitFlag_KeepEmpties = (1 << 0),
};
typedef enum MD_PathStyle
{
MD_PathStyle_Relative,
MD_PathStyle_WindowsAbsolute,
MD_PathStyle_UnixAbsolute,
#if MD_OS_WINDOWS
MD_PathStyle_SystemAbsolute = MD_PathStyle_WindowsAbsolute
#elif MD_OS_LINUX
MD_PathStyle_SystemAbsolute = MD_PathStyle_UnixAbsolute
#else
# error "absolute path style is undefined for this OS"
#endif
}
MD_PathStyle;
typedef struct MD_StringJoin MD_StringJoin;
struct MD_StringJoin
{
MD_String8 pre;
MD_String8 sep;
MD_String8 post;
};
////////////////////////////////
//~ rjf: UTF Decoding Types
typedef struct MD_UnicodeDecode MD_UnicodeDecode;
struct MD_UnicodeDecode
{
MD_U32 inc;
MD_U32 codepoint;
};
////////////////////////////////
//~ rjf: String Fuzzy Matching Types
typedef struct MD_FuzzyMatchRangeNode MD_FuzzyMatchRangeNode;
struct MD_FuzzyMatchRangeNode
{
MD_FuzzyMatchRangeNode* next;
MD_Rng1U64 range;
};
typedef struct MD_FuzzyMatchRangeList MD_FuzzyMatchRangeList;
struct MD_FuzzyMatchRangeList
{
MD_FuzzyMatchRangeNode* first;
MD_FuzzyMatchRangeNode* last;
MD_U64 count;
MD_U64 needle_part_count;
MD_U64 total_dim;
};
////////////////////////////////
//~ NOTE(allen): String <-> Integer Tables
inline MD_U8
md_integer_symbols(MD_U8 value) {
md_local_persist
MD_U8 lookup_table[16] = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',
};
return lookup_table[value];
}
inline MD_U8
md_base64(MD_U8 value) {
md_local_persist
MD_U8 lookup_table[64] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'_', '$',
};
return lookup_table[value];
}
inline MD_U8
md_base64_reverse(MD_U8 value) {
md_local_persist
MD_U8 lookup_table[128] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,
0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E,
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF,
};
return lookup_table[value];
}
// NOTE(allen): Includes reverses for uppercase and lowercase hex.
inline MD_U8
md_integer_symbol_reverse(MD_U8 value) {
md_local_persist
MD_U8 lookup_table[128] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
return lookup_table[value];
}
////////////////////////////////
//~ rjf: Character Classification & Conversion Functions
inline MD_B32 md_char_is_space (MD_U8 c) { return(c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'); }
inline MD_B32 md_char_is_upper (MD_U8 c) { return('A' <= c && c <= 'Z'); }
inline MD_B32 md_char_is_lower (MD_U8 c) { return('a' <= c && c <= 'z'); }
inline MD_B32 md_char_is_alpha (MD_U8 c) { return(md_char_is_upper(c) || md_char_is_lower(c)); }
inline MD_B32 md_char_is_slash (MD_U8 c) { return(c == '/' || c == '\\'); }
inline MD_U8 md_char_to_lower (MD_U8 c) { if (md_char_is_upper(c)) { c += ('a' - 'A'); } return(c); }
inline MD_U8 md_char_to_upper (MD_U8 c) { if (md_char_is_lower(c)) { c += ('A' - 'a'); } return(c); }
inline MD_U8 md_char_to_correct_slash(MD_U8 c) { if (md_char_is_slash(c)) { c = '/'; } return(c); }
inline MD_B32
md_char_is_digit(MD_U8 c, MD_U32 base) {
MD_B32 result = 0;
if (0 < base && base <= 16) {
MD_U8 val = md_integer_symbol_reverse(c);
if (val < base) {
result = 1;
}
}
return(result);
}
////////////////////////////////
//~ rjf: C-String Measurement
inline MD_U64 md_cstring8_length (MD_U8* c) { MD_U8* p = c; for (; *p != 0; p += 1); return(p - c); }
inline MD_U64 md_cstring16_length(MD_U16* c) { MD_U16* p = c; for (; *p != 0; p += 1); return(p - c); }
inline MD_U64 md_cstring32_length(MD_U32* c) { MD_U32* p = c; for (; *p != 0; p += 1); return(p - c); }
#define md_cstring_length(c) _Generic(c, MD_U8*: md_cstring8_length, MD_U16*: md_cstring16_length, MD_U32*: md_cstring32_length)(c)
////////////////////////////////
//~ rjf: String Constructors
#define md_str8_lit(S) md_str8((MD_U8*)(S), sizeof(S) - 1)
#define md_str8_lit_comp(S) { (MD_U8*)(S), sizeof(S) - 1, }
#define md_str8_varg(S) (int)((S).size), ((S).str)
#define md_str8_array(S, C) md_str8((MD_U8*)(S), sizeof(*(S)) * (C))
#define md_str8_array_fixed(S) md_str8((MD_U8*)(S), sizeof(S))
#define md_str8_struct(S) md_str8((MD_U8*)(S), sizeof(*(S)))
inline MD_String8 md_str8 (MD_U8* str, MD_U64 size) { MD_String8 result = {str, size}; return(result); }
inline MD_String8 md_str8_range (MD_U8* first, MD_U8* one_past_last) { MD_String8 result = {first, (MD_U64)(one_past_last - first)}; return(result); }
inline MD_String8 md_str8_zero (void) { MD_String8 result = {0}; return(result); }
inline MD_String16 md_str16 (MD_U16* str, MD_U64 size) { MD_String16 result = {str, size}; return(result); }
inline MD_String16 md_str16_range (MD_U16* first, MD_U16* one_past_last) { MD_String16 result = {first, (MD_U64)(one_past_last - first)}; return(result); }
inline MD_String16 md_str16_zero (void) { MD_String16 result = {0}; return(result); }
inline MD_String32 md_str32 (MD_U32* str, MD_U64 size) { MD_String32 result = {str, size}; return(result); }
inline MD_String32 md_str32_range (MD_U32* first, MD_U32* one_past_last) { MD_String32 result = {first, (MD_U64)(one_past_last - first)}; return(result); }
inline MD_String32 md_str32_zero (void) { MD_String32 result = {0}; return(result); }
inline MD_String8 md_str8_cstring (char* c) { MD_String8 result = {(MD_U8*) c, md_cstring8_length ((MD_U8*) c)}; return(result); }
inline MD_String16 md_str16_cstring(MD_U16* c) { MD_String16 result = {(MD_U16*)c, md_cstring16_length((MD_U16*)c)}; return(result); }
inline MD_String32 md_str32_cstring(MD_U32* c) { MD_String32 result = {(MD_U32*)c, md_cstring32_length((MD_U32*)c)}; return(result); }
#define md_str_range(str, one_past_last) _Generic(str, MD_U8: md_str8_range, MD_U16: md_str16_range, MD_U32: md_str32_range )(str, one_past_last)
#define md_str_cstring(c) _Generic(c, MD_U8: md_str8_cstring, MD_U16: md_str16_cstring, MD_U32: md_str32_cstring)(c)
MD_String8 md_str8_cstring_capped (void* cstr, void* cap);
MD_String16 md_str16_cstring_capped (void* cstr, void* cap);
MD_String8 md_str8_cstring_capped_reverse(void* raw_start, void* raw_cap);
inline MD_String8
md_str8_cstring_capped(void* cstr, void* cap) {
char* ptr = (char*)cstr;
char* opl = (char*)cap;
for (;ptr < opl && *ptr != 0; ptr += 1);
MD_U64 size = (MD_U64)(ptr - (char *)cstr);
MD_String8 result = {(MD_U8*)cstr, size};
return result;
}
inline MD_String16
md_str16_cstring_capped(void* cstr, void* cap)
{
MD_U16* ptr = (MD_U16*)cstr;
MD_U16* opl = (MD_U16*)cap;
for (;ptr < opl && *ptr != 0; ptr += 1);
MD_U64 size = (MD_U64)(ptr - (MD_U16 *)cstr);
MD_String16 result = md_str16(cstr, size);
return result;
}
inline MD_String8
md_str8_cstring_capped_reverse(void* raw_start, void* raw_cap)
{
MD_U8* start = raw_start;
MD_U8* ptr = raw_cap;
for (; ptr > start; )
{
ptr -= 1;
if (*ptr == '\0') {
break;
}
}
MD_U64 size = (MD_U64)(ptr - start);
MD_String8 result = md_str8(start, size);
return result;
}
////////////////////////////////
//~ rjf: String Formatting & Copying
MD_String8 md_str8_cat__arena (MD_Arena* arena, MD_String8 s1, MD_String8 s2);
MD_String8 md_str8_copy__arena(MD_Arena* arena, MD_String8 s);
MD_String8 md_str8fv__arena (MD_Arena* arena, char* fmt, va_list args);
MD_String8 md_str8f__arena (MD_Arena* arena, char* fmt, ...);
MD_API MD_String8 md_str8_cat__ainfo (MD_AllocatorInfo ainfo, MD_String8 s1, MD_String8 s2);
MD_API MD_String8 md_str8_copy__ainfo(MD_AllocatorInfo ainfo, MD_String8 s);
MD_API MD_String8 md_str8fv__ainfo (MD_AllocatorInfo ainfo, char* fmt, va_list args);
MD_String8 md_str8f__ainfo (MD_AllocatorInfo ainfo, char* fmt, ...);
#define md_str8_cat(allocator, s1, s2) _Generic(allocator, MD_Arena*: md_str8_cat__arena, MD_AllocatorInfo: md_str8_cat__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, s1, s2)
#define md_str8_copy(allocator, s) _Generic(allocator, MD_Arena*: md_str8_copy__arena, MD_AllocatorInfo: md_str8_copy__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, s)
#define md_str8fv(allocator, fmt, args) _Generic(allocator, MD_Arena*: md_str8fv__arena, MD_AllocatorInfo: md_str8fv__ainfo , default: md_assert_generic_sel_fail) md_generic_call(allocator, fmt, args)
#define md_str8f(allocator, fmt, ...) _Generic(allocator, MD_Arena*: md_str8f__arena, MD_AllocatorInfo: md_str8f__ainfo , default: md_assert_generic_sel_fail) md_generic_call(allocator, fmt, __VA_ARGS__)
md_force_inline MD_String8 md_str8_cat__arena (MD_Arena* arena, MD_String8 s1, MD_String8 s2) { return md_str8_cat__ainfo (md_arena_allocator(arena), s1, s2); }
md_force_inline MD_String8 md_str8_copy__arena(MD_Arena* arena, MD_String8 s) { return md_str8_copy__ainfo(md_arena_allocator(arena), s); }
md_force_inline MD_String8 md_str8fv__arena (MD_Arena* arena, char* fmt, va_list args) { return md_str8fv__ainfo (md_arena_allocator(arena), fmt, args); }
inline MD_String8
md_str8f__arena(MD_Arena *arena, char *fmt, ...) {
va_list args;
va_start(args, fmt);
MD_String8 result = md_str8fv(arena, fmt, args);
va_end(args);
return(result);
}
inline MD_String8
md_str8f__ainfo(MD_AllocatorInfo ainfo, char *fmt, ...) {
va_list args;
va_start(args, fmt);
MD_String8 result = md_str8fv(ainfo, fmt, args);
va_end(args);
return(result);
}
////////////////////////////////
//~ rjf: String Slicing
MD_API MD_String8 md_str8_skip_chop_whitespace(MD_String8 string);
MD_String8 md_str8_substr (MD_String8 str, MD_Rng1U64 range);
MD_String8 md_str8_prefix (MD_String8 str, MD_U64 size);
MD_String8 md_str8_skip (MD_String8 str, MD_U64 amt);
MD_String8 md_str8_postfix(MD_String8 str, MD_U64 size);
MD_String8 md_str8_chop (MD_String8 str, MD_U64 amt);
inline MD_String8
md_str8_substr(MD_String8 str, MD_Rng1U64 range){
range.md_min = md_clamp_top(range.md_min, str.size);
range.md_max = md_clamp_top(range.md_max, str.size);
str.str += range.md_min;
str.size = md_dim_1u64(range);
return(str);
}
inline MD_String8
md_str8_prefix(MD_String8 str, MD_U64 size){
str.size = md_clamp_top(size, str.size);
return(str);
}
inline MD_String8
md_str8_skip(MD_String8 str, MD_U64 amt){
amt = md_clamp_top(amt, str.size);
str.str += amt;
str.size -= amt;
return(str);
}
inline MD_String8
md_str8_postfix(MD_String8 str, MD_U64 size){
size = md_clamp_top(size, str.size);
str.str = (str.str + str.size) - size;
str.size = size;
return(str);
}
inline MD_String8
md_str8_chop(MD_String8 str, MD_U64 amt){
amt = md_clamp_top(amt, str.size);
str.size -= amt;
return(str);
}
////////////////////////////////
//~ rjf: String Stylization
inline MD_String8 md_upper_fromstr8__arena (MD_Arena* arena, MD_String8 string) { string = md_str8_copy(arena, string); for(MD_U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = md_char_to_upper(string.str[idx]); } return string; }
inline MD_String8 md_lower_fromstr8__arena (MD_Arena* arena, MD_String8 string) { string = md_str8_copy(arena, string); for(MD_U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = md_char_to_lower(string.str[idx]); } return string; }
inline MD_String8 md_backslashed_from_str8__arena(MD_Arena* arena, MD_String8 string) { string = md_str8_copy(arena, string); for(MD_U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = md_char_is_slash(string.str[idx]) ? '\\' : string.str[idx]; } return string; }
inline MD_String8 md_upper_fromstr8__ainfo (MD_AllocatorInfo ainfo, MD_String8 string) { string = md_str8_copy(ainfo, string); for(MD_U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = md_char_to_upper(string.str[idx]); } return string; }
inline MD_String8 md_lower_fromstr8__ainfo (MD_AllocatorInfo ainfo, MD_String8 string) { string = md_str8_copy(ainfo, string); for(MD_U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = md_char_to_lower(string.str[idx]); } return string; }
inline MD_String8 md_backslashed_from_str8__ainfo(MD_AllocatorInfo ainfo, MD_String8 string) { string = md_str8_copy(ainfo, string); for(MD_U64 idx = 0; idx < string.size; idx += 1) { string.str[idx] = md_char_is_slash(string.str[idx]) ? '\\' : string.str[idx]; } return string; }
#define md_upper_fromstr8(allocator, string) _Generic(allocator, MD_Arena*: md_upper_fromstr8__arena, MD_AllocatorInfo: md_upper_fromstr8__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string)
#define md_lower_fromstr8(allocator, string) _Generic(allocator, MD_Arena*: md_lower_fromstr8__arena, MD_AllocatorInfo: md_lower_fromstr8__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string)
#define md_backslashed_from_str8(allocator, string) _Generic(allocator, MD_Arena*: md_backslashed_from_str8__arena, MD_AllocatorInfo: md_backslashed_from_str8__ainfo , default: md_assert_generic_sel_fail) md_generic_call(allocator, string)
////////////////////////////////
//~ rjf: String Matching
#define md_str8_match_lit(a_lit, b, flags) md_str8_match(md_str8_lit(a_lit), (b), (flags))
#define md_str8_match_cstr(a_cstr, b, flags) md_str8_match(md_str8_cstring(a_cstr), (b), (flags))
#define md_str8_ends_with_lit(string, end_lit, flags) md_str8_ends_with((string), md_str8_lit(end_lit), (flags))
MD_API MD_B32 md_str8_match (MD_String8 a, MD_String8 b, MD_StringMatchFlags flags);
MD_API MD_U64 md_str8_find_needle (MD_String8 string, MD_U64 start_pos, MD_String8 needle, MD_StringMatchFlags flags);
MD_API MD_U64 md_str8_find_needle_reverse(MD_String8 string, MD_U64 start_pos, MD_String8 needle, MD_StringMatchFlags flags);
MD_B32 md_str8_ends_with (MD_String8 string, MD_String8 end, MD_StringMatchFlags flags);
inline MD_B32
md_str8_ends_with(MD_String8 string, MD_String8 end, MD_StringMatchFlags flags) {
MD_String8 postfix = md_str8_postfix(string, end.size);
MD_B32 is_match = md_str8_match(end, postfix, flags);
return is_match;
}
////////////////////////////////
//~ rjf: String <=> Integer Conversions
//- rjf: string -> integer
MD_API MD_S64 md_sign_from_str8 (MD_String8 string, MD_String8* md_string_tail);
MD_API MD_B32 md_str8_is_integer(MD_String8 string, MD_U32 radix);
MD_U64 md_u64_from_str8 (MD_String8 string, MD_U32 radix);
MD_S64 md_s64_from_str8 (MD_String8 string, MD_U32 radix);
MD_U32 md_u32_from_str8 (MD_String8 string, MD_U32 radix);
MD_S32 s32_from_str8 (MD_String8 string, MD_U32 radix);
MD_API MD_B32 md_try_u64_from_str8_c_rules(MD_String8 string, MD_U64* x);
MD_B32 md_try_s64_from_str8_c_rules(MD_String8 string, MD_S64* x);
//- rjf: integer -> string
MD_String8 md_str8_from_memory_size__arena(MD_Arena* arena, MD_SSIZE z);
MD_String8 md_str8_from_u64__arena (MD_Arena* arena, MD_U64 u64, MD_U32 radix, MD_U8 min_digits, MD_U8 digit_group_separator);
MD_String8 md_str8_from_s64__arena (MD_Arena* arena, MD_S64 s64, MD_U32 radix, MD_U8 min_digits, MD_U8 digit_group_separator);
MD_String8 md_str8_from_bits_u32__arena(MD_Arena* arena, MD_U32 x);
MD_String8 md_str8_from_bits_u64__arena(MD_Arena* arena, MD_U64 x);
MD_API MD_String8 md_str8_from_memory_size__ainfo(MD_AllocatorInfo ainfo, MD_SSIZE z);
MD_API MD_String8 md_str8_from_u64__ainfo (MD_AllocatorInfo ainfo, MD_U64 u64, MD_U32 radix, MD_U8 min_digits, MD_U8 digit_group_separator);
MD_API MD_String8 md_str8_from_s64__ainfo (MD_AllocatorInfo ainfo, MD_S64 u64, MD_U32 radix, MD_U8 min_digits, MD_U8 digit_group_separator);
MD_String8 md_str8_from_bits_u32__ainfo(MD_AllocatorInfo ainfo, MD_U32 x);
MD_String8 md_str8_from_bits_u64__ainfo(MD_AllocatorInfo ainfo, MD_U64 x);
#define md_str8_from_memory_size(allocator, z) _Generic(allocator, MD_Arena*: md_str8_from_memory_size__arena, MD_AllocatorInfo: md_str8_from_memory_size__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, z)
#define md_str8_from_u64(allocator, u64, radix, min_digits, digit_group_separator) _Generic(allocator, MD_Arena*: md_str8_from_u64__arena, MD_AllocatorInfo: md_str8_from_u64__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, u64, radix, min_digits, digit_group_separator)
#define md_str8_from_s64(allocator, s64, radix, min_digits, digit_group_separator) _Generic(allocator, MD_Arena*: md_str8_from_s64__arena, MD_AllocatorInfo: md_str8_from_s64__ainfo , default: md_assert_generic_sel_fail) md_generic_call(allocator, s64, radix, min_digits, digit_group_separator)
#define md_str8_from_bits_u32(allocator, x) _Generic(allocator, MD_Arena*: md_str8_from_bits_u32__arena, MD_AllocatorInfo: md_str8_from_bits_u32__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, x)
#define md_str8_from_bits_u64(allocator, x) _Generic(allocator, MD_Arena*: md_str8_from_bits_u64__arena, MD_AllocatorInfo: md_str8_from_bits_u64__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, x)
md_force_inline MD_String8 md_str8_from_memory_size__arena(MD_Arena* arena, MD_SSIZE z) { return md_str8_from_memory_size__ainfo(md_arena_allocator(arena), z); }
md_force_inline MD_String8 md_str8_from_u64__arena (MD_Arena* arena, MD_U64 u64, MD_U32 radix, MD_U8 min_digits, MD_U8 digit_group_separator) { return md_str8_from_u64__ainfo (md_arena_allocator(arena), u64, radix, min_digits, digit_group_separator); }
md_force_inline MD_String8 md_str8_from_s64__arena (MD_Arena* arena, MD_S64 s64, MD_U32 radix, MD_U8 min_digits, MD_U8 digit_group_separator) { return md_str8_from_s64__ainfo (md_arena_allocator(arena), s64, radix, min_digits, digit_group_separator); }
inline MD_S64
md_s64_from_str8(MD_String8 string, MD_U32 radix) {
MD_S64 sign = md_sign_from_str8(string, &string);
MD_S64 x = (MD_S64)md_u64_from_str8(string, radix) * sign;
return(x);
}
inline MD_U64
md_u64_from_str8(MD_String8 string, MD_U32 radix) {
MD_U64 x = 0;
if (1 < radix && radix <= 16) {
for (MD_U64 i = 0; i < string.size; i += 1) {
x *= radix;
x += md_integer_symbol_reverse(string.str[i]&0x7F);
}
}
return(x);
}
inline MD_U32
md_u32_from_str8(MD_String8 string, MD_U32 radix) {
MD_U64 x64 = md_u64_from_str8(string, radix);
MD_U32 x32 = md_safe_cast_u32(x64);
return x32;
}
inline MD_S32
s32_from_str8(MD_String8 string, MD_U32 radix) {
MD_S64 x64 = md_s64_from_str8(string, radix);
MD_S32 x32 = md_safe_cast_s32(x64);
return x32;
}
inline MD_B32
md_try_s64_from_str8_c_rules(MD_String8 string, MD_S64* x) {
MD_String8 md_string_tail = {0};
MD_S64 sign = md_sign_from_str8(string, &md_string_tail);
MD_U64 x_u64 = 0;
MD_B32 is_integer = md_try_u64_from_str8_c_rules(md_string_tail, &x_u64);
*x = x_u64*sign;
return(is_integer);
}
inline MD_String8
md_str8_from_bits_u32__arena(MD_Arena* arena, MD_U32 x)
{
MD_U8 c0 = 'a' + ((x >> 28) & 0xf);
MD_U8 c1 = 'a' + ((x >> 24) & 0xf);
MD_U8 c2 = 'a' + ((x >> 20) & 0xf);
MD_U8 c3 = 'a' + ((x >> 16) & 0xf);
MD_U8 c4 = 'a' + ((x >> 12) & 0xf);
MD_U8 c5 = 'a' + ((x >> 8) & 0xf);
MD_U8 c6 = 'a' + ((x >> 4) & 0xf);
MD_U8 c7 = 'a' + ((x >> 0) & 0xf);
MD_String8 result = md_str8f(arena, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
return result;
}
inline MD_String8
md_str8_from_bits_u64__arena(MD_Arena* arena, MD_U64 x)
{
MD_U8 c0 = 'a' + ((x >> 60) & 0xf);
MD_U8 c1 = 'a' + ((x >> 56) & 0xf);
MD_U8 c2 = 'a' + ((x >> 52) & 0xf);
MD_U8 c3 = 'a' + ((x >> 48) & 0xf);
MD_U8 c4 = 'a' + ((x >> 44) & 0xf);
MD_U8 c5 = 'a' + ((x >> 40) & 0xf);
MD_U8 c6 = 'a' + ((x >> 36) & 0xf);
MD_U8 c7 = 'a' + ((x >> 32) & 0xf);
MD_U8 c8 = 'a' + ((x >> 28) & 0xf);
MD_U8 c9 = 'a' + ((x >> 24) & 0xf);
MD_U8 ca = 'a' + ((x >> 20) & 0xf);
MD_U8 cb = 'a' + ((x >> 16) & 0xf);
MD_U8 cc = 'a' + ((x >> 12) & 0xf);
MD_U8 cd = 'a' + ((x >> 8) & 0xf);
MD_U8 ce = 'a' + ((x >> 4) & 0xf);
MD_U8 cf = 'a' + ((x >> 0) & 0xf);
MD_String8 result = md_str8f(arena,
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf
);
return result;
}
inline MD_String8
md_str8_from_bits_u32__ainfo(MD_AllocatorInfo ainfo, MD_U32 x)
{
MD_U8 c0 = 'a' + ((x >> 28) & 0xf);
MD_U8 c1 = 'a' + ((x >> 24) & 0xf);
MD_U8 c2 = 'a' + ((x >> 20) & 0xf);
MD_U8 c3 = 'a' + ((x >> 16) & 0xf);
MD_U8 c4 = 'a' + ((x >> 12) & 0xf);
MD_U8 c5 = 'a' + ((x >> 8) & 0xf);
MD_U8 c6 = 'a' + ((x >> 4) & 0xf);
MD_U8 c7 = 'a' + ((x >> 0) & 0xf);
MD_String8 result = md_str8f(ainfo, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
return result;
}
inline MD_String8
md_str8_from_bits_u64__ainfo(MD_AllocatorInfo ainfo, MD_U64 x)
{
MD_U8 c0 = 'a' + ((x >> 60) & 0xf);
MD_U8 c1 = 'a' + ((x >> 56) & 0xf);
MD_U8 c2 = 'a' + ((x >> 52) & 0xf);
MD_U8 c3 = 'a' + ((x >> 48) & 0xf);
MD_U8 c4 = 'a' + ((x >> 44) & 0xf);
MD_U8 c5 = 'a' + ((x >> 40) & 0xf);
MD_U8 c6 = 'a' + ((x >> 36) & 0xf);
MD_U8 c7 = 'a' + ((x >> 32) & 0xf);
MD_U8 c8 = 'a' + ((x >> 28) & 0xf);
MD_U8 c9 = 'a' + ((x >> 24) & 0xf);
MD_U8 ca = 'a' + ((x >> 20) & 0xf);
MD_U8 cb = 'a' + ((x >> 16) & 0xf);
MD_U8 cc = 'a' + ((x >> 12) & 0xf);
MD_U8 cd = 'a' + ((x >> 8) & 0xf);
MD_U8 ce = 'a' + ((x >> 4) & 0xf);
MD_U8 cf = 'a' + ((x >> 0) & 0xf);
MD_String8 result = md_str8f(ainfo,
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf
);
return result;
}
////////////////////////////////
//~ rjf: String <=> Float Conversions
MD_F64 md_f64_from_str8(MD_String8 string);
////////////////////////////////
//~ rjf: String List Construction Functions
#define md_str8_list_first(list) ((list)->first ? (list)->first->string : md_str8_zero())
MD_String8Node* md_str8_list_push_node (MD_String8List* list, MD_String8Node* node);
MD_String8Node* md_str8_list_push_node_set_string (MD_String8List* list, MD_String8Node* node, MD_String8 string);
MD_String8Node* md_str8_list_push_node_front (MD_String8List* list, MD_String8Node* node);
MD_String8Node* md_str8_list_push_node_front_set_string(MD_String8List* list, MD_String8Node* node, MD_String8 string);
void md_str8_list_concat_in_place (MD_String8List* list, MD_String8List* to_push);
inline MD_String8Node*
md_str8_list_push_node(MD_String8List* list, MD_String8Node* node) {
md_sll_queue_push(list->first, list->last, node);
list->node_count += 1;
list->total_size += node->string.size;
return(node);
}
inline MD_String8Node*
md_str8_list_push_node_set_string(MD_String8List* list, MD_String8Node* node, MD_String8 string) {
md_sll_queue_push(list->first, list->last, node);
list->node_count += 1;
list->total_size += string.size;
node->string = string;
return(node);
}
inline MD_String8Node*
md_str8_list_push_node_front(MD_String8List* list, MD_String8Node* node) {
md_sll_queue_push_front(list->first, list->last, node);
list->node_count += 1;
list->total_size += node->string.size;
return(node);
}
inline MD_String8Node*
md_str8_list_push_node_front_set_string(MD_String8List* list, MD_String8Node* node, MD_String8 string) {
md_sll_queue_push_front(list->first, list->last, node);
list->node_count += 1;
list->total_size += string.size;
node->string = string;
return(node);
}
MD_String8Node* md_str8_list_aligner__arena(MD_Arena* arena, MD_String8List* list, MD_U64 md_min, MD_U64 align);
MD_String8List md_str8_list_copy__arena (MD_Arena* arena, MD_String8List* list);
MD_String8Node* md_str8_list_push__arena (MD_Arena* arena, MD_String8List* list, MD_String8 string);
MD_String8Node* md_str8_list_push_front__arena (MD_Arena* arena, MD_String8List* list, MD_String8 string);
MD_String8Node* md_str8_list_pushf__arena (MD_Arena* arena, MD_String8List* list, char* fmt, ...);
MD_String8Node* md_str8_list_push_frontf__arena(MD_Arena* arena, MD_String8List* list, char* fmt, ...);
MD_API MD_String8Node* md_str8_list_aligner__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, MD_U64 md_min, MD_U64 align);
MD_API MD_String8List md_str8_list_copy__ainfo (MD_AllocatorInfo ainfo, MD_String8List* list);
MD_String8Node* md_str8_list_push__ainfo (MD_AllocatorInfo ainfo, MD_String8List* list, MD_String8 string);
MD_String8Node* md_str8_list_push_front__ainfo (MD_AllocatorInfo ainfo, MD_String8List* list, MD_String8 string);
MD_String8Node* md_str8_list_pushf__ainfo (MD_AllocatorInfo ainfo, MD_String8List* list, char* fmt, ...);
MD_String8Node* md_str8_list_push_frontf__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, char* fmt, ...);
#define md_str8_list_aligner(allocator, list, md_min, align) _Generic(allocator, MD_Arena*: md_str8_list_aligner__arena, MD_AllocatorInfo: md_str8_list_aligner__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list, md_min, align)
#define md_str8_list_copy(allocator, list) _Generic(allocator, MD_Arena*: md_str8_list_copy__arena, MD_AllocatorInfo: md_str8_list_copy__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list)
#define md_str8_list_push(allocator, list, string) _Generic(allocator, MD_Arena*: md_str8_list_push__arena, MD_AllocatorInfo: md_str8_list_push__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list, string)
#define md_str8_list_push_front(allocator, list, string) _Generic(allocator, MD_Arena*: md_str8_list_push_front__arena, MD_AllocatorInfo: md_str8_list_push_front__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list, string)
#define md_str8_list_pushf(allocator, list, fmt, ...) _Generic(allocator, MD_Arena*: md_str8_list_pushf__arena, MD_AllocatorInfo: md_str8_list_pushf__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list, fmt, __VA_ARGS__)
#define md_str8_list_push_frontf(allocaotr, list, fmt, ...) _Generic(allocator, MD_Arena*: md_str8_list_push_frontf__arena, MD_AllocatorInfo: md_str8_list_push_frontf__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list, fmt, __VA_ARGS__)
md_force_inline MD_String8Node* md_str8_list_ligner__arena (MD_Arena* arena, MD_String8List* list, MD_U64 md_min, MD_U64 align) { return md_str8_list_aligner__ainfo (md_arena_allocator(arena), list, md_min, align); }
md_force_inline MD_String8List md_str8_list_copy__arena (MD_Arena* arena, MD_String8List* list) { return md_str8_list_copy__ainfo (md_arena_allocator(arena), list); }
md_force_inline MD_String8Node* md_str8_list_push__arena (MD_Arena* arena, MD_String8List* list, MD_String8 string) { return md_str8_list_push__ainfo (md_arena_allocator(arena), list, string); }
md_force_inline MD_String8Node* md_str8_list_push_front__arena(MD_Arena* arena, MD_String8List* list, MD_String8 string) { return md_str8_list_push_front__ainfo(md_arena_allocator(arena), list, string); }
inline MD_String8Node*
md_str8_list_pushf__arena(MD_Arena *arena, MD_String8List *list, char *fmt, ...) {
va_list args;
va_start(args, fmt);
MD_String8 string = md_str8fv(arena, fmt, args);
MD_String8Node* result = md_str8_list_push(arena, list, string);
va_end(args);
return(result);
}
inline MD_String8Node*
md_str8_list_push_frontf__arena(MD_Arena *arena, MD_String8List *list, char *fmt, ...) {
va_list args;
va_start(args, fmt);
MD_String8 string = md_str8fv(arena, fmt, args);
MD_String8Node* result = md_str8_list_push_front(arena, list, string);
va_end(args);
return(result);
}
inline MD_String8Node*
md_str8_list_push__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, MD_String8 string) {
MD_String8Node* node = md_alloc_array_no_zero(ainfo, MD_String8Node, 1);
md_str8_list_push_node_set_string(list, node, string);
return(node);
}
inline MD_String8Node*
md_str8_list_push_front__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, MD_String8 string) {
MD_String8Node *node = md_alloc_array_no_zero(ainfo, MD_String8Node, 1);
md_str8_list_push_node_front_set_string(list, node, string);
return(node);
}
inline MD_String8Node*
md_str8_list_pushf__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, char* fmt, ...) {
va_list args;
va_start(args, fmt);
MD_String8 string = md_str8fv(ainfo, fmt, args);
MD_String8Node* result = md_str8_list_push(ainfo, list, string);
va_end(args);
return(result);
}
inline MD_String8Node*
md_str8_list_push_frontf__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, char* fmt, ...) {
va_list args;
va_start(args, fmt);
MD_String8 string = md_str8fv(ainfo, fmt, args);
MD_String8Node* result = md_str8_list_push_front(ainfo, list, string);
va_end(args);
return(result);
}
////////////////////////////////
//~ rjf: String Splitting & Joining
MD_String8List md_str8_split__arena(MD_Arena* arena, MD_String8 string, MD_U8* split_chars, MD_U64 split_char_count, MD_StringSplitFlags flags);
MD_API MD_String8List md_str8_split__ainfo(MD_AllocatorInfo ainfo, MD_String8 string, MD_U8* split_chars, MD_U64 split_char_count, MD_StringSplitFlags flags);
MD_String8List md_str8_split_by_string_chars__arena (MD_Arena* arena, MD_String8 string, MD_String8 split_chars, MD_StringSplitFlags flags);
MD_String8List md_str8_split_by_string_chars__ainfo (MD_AllocatorInfo ainfo, MD_String8 string, MD_String8 split_chars, MD_StringSplitFlags flags);
MD_String8List md_str8_list_split_by_string_chars__arena(MD_Arena* arena, MD_String8List list, MD_String8 split_chars, MD_StringSplitFlags flags);
MD_String8List md_str8_list_split_by_string_chars__ainfo(MD_AllocatorInfo ainfo, MD_String8List list, MD_String8 split_chars, MD_StringSplitFlags flags);
MD_String8 md_str8_list_join__arena (MD_Arena* arena, MD_String8List* list, MD_StringJoin* optional_params);
MD_API MD_String8 md_str8_list_join__ainfo (MD_AllocatorInfo ainfo, MD_String8List* list, MD_StringJoin* optional_params);
void md_str8_list_from_flags__arena(MD_Arena* arena, MD_String8List* list, MD_U32 flags, MD_String8* flag_string_table, MD_U32 flag_string_count);
void md_str8_list_from_flags__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, MD_U32 flags, MD_String8* flag_string_table, MD_U32 flag_string_count);
#define md_str8_split(allocator, string, split_chars, split_char_count, flags) _Generic(allocator, MD_Arena*: md_str8_split__arena, MD_AllocatorInfo: md_str8_split__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string, split_chars, split_char_count, flags)
#define md_str8_split_by_string_chars(allocator, string, split_chars, flags) _Generic(allocator, MD_Arena*: md_str8_split_by_string_chars__arena, MD_AllocatorInfo: md_str8_split_by_string_chars__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string, split_chars, flags)
#define md_str8_list_split_by_string_chars(allocator, list, split_chars, flags) _Generic(allocator, MD_Arena*: md_str8_list_split_by_string_chars__arena, MD_AllocatorInfo: md_str8_list_split_by_string_chars__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list, split_chars, flags)
#define md_str8_list_join(allocator, list, params) _Generic(allocator, MD_Arena*: md_str8_list_join__arena, MD_AllocatorInfo: md_str8_list_join__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list, params )
md_force_inline MD_String8List md_str8_split__arena (MD_Arena* arena, MD_String8 string, MD_U8* split_chars, MD_U64 split_char_count, MD_StringSplitFlags flags) { return md_str8_split__ainfo (md_arena_allocator(arena), string, split_chars, split_char_count, flags); }
md_force_inline MD_String8List md_str8_split_by_string_chars__arena (MD_Arena* arena, MD_String8 string, MD_String8 split_chars, MD_StringSplitFlags flags) { return md_str8_split_by_string_chars__ainfo (md_arena_allocator(arena), string, split_chars, flags); }
md_force_inline MD_String8List md_str8_list_split_by_string_chars__arena(MD_Arena* arena, MD_String8List list, MD_String8 split_chars, MD_StringSplitFlags flags) { return md_str8_list_split_by_string_chars__ainfo (md_arena_allocator(arena), list, split_chars, flags); }
md_force_inline void md_str8_list_from_flags__arena (MD_Arena* arena, MD_String8List* list, MD_U32 flags, MD_String8* flag_string_table, MD_U32 flag_string_count) { md_str8_list_from_flags__ainfo (md_arena_allocator(arena), list, flags, flag_string_table, flag_string_count); }
md_force_inline MD_String8 md_str8_list_join__arena (MD_Arena* arena, MD_String8List* list, MD_StringJoin* optional_params) { return md_str8_list_join__ainfo (md_arena_allocator(arena), list, optional_params); }
inline MD_String8List
md_str8_split_by_string_chars__ainfo(MD_AllocatorInfo ainfo, MD_String8 string, MD_String8 split_chars, MD_StringSplitFlags flags) {
MD_String8List list = md_str8_split(ainfo, string, split_chars.str, split_chars.size, flags);
return list;
}
inline MD_String8List
md_str8_list_split_by_string_chars__ainfo(MD_AllocatorInfo ainfo, MD_String8List list, MD_String8 split_chars, MD_StringSplitFlags flags) {
MD_String8List result = {0};
for (MD_String8Node *node = list.first; node != 0; node = node->next){
MD_String8List split = md_str8_split_by_string_chars(ainfo, node->string, split_chars, flags);
md_str8_list_concat_in_place(&result, &split);
}
return result;
}
void
md_str8_list_from_flags__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list, MD_U32 flags, MD_String8* flag_string_table, MD_U32 flag_string_count) {
for (MD_U32 i = 0; i < flag_string_count; i += 1) {
MD_U32 flag = (1 << i);
if (flags & flag) {
md_str8_list_push(ainfo, list, flag_string_table[i]);
}
}
}
////////////////////////////////
//~ rjf; String Arrays
#define md_str8_array_from_list(allocator, list) _Generic(allocator, MD_Arena*: md_str8_array_from_list__arena, MD_AllocatorInfo: md_str8_array_from_list__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, list)
#define md_str8_array_reserve(allocator, count) _Generic(allocaotr, MD_Arena*: md_str8_array_reserve__arena MD_AllocatorInfo: md_str8_array_reserve__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, count)
inline MD_String8Array
md_str8_array_from_list__ainfo(MD_AllocatorInfo ainfo, MD_String8List* list) {
MD_String8Array array;
array.count = list->node_count;
array.v = md_alloc_array_no_zero(ainfo, MD_String8, array.count);
MD_U64 idx = 0;
for(MD_String8Node *n = list->first; n != 0; n = n->next, idx += 1) {
array.v[idx] = n->string;
}
return array;
}
inline MD_String8Array
md_str8_array_reserve__ainfo(MD_AllocatorInfo ainfo, MD_U64 count) {
MD_String8Array arr;
arr.count = 0;
arr.v = md_alloc_array(ainfo, MD_String8, count);
return arr;
}
md_force_inline MD_String8Array md_str8_array_from_list__arena(MD_Arena* arena, MD_String8List* list) { return md_str8_array_from_list__ainfo(md_arena_allocator(arena), list); }
md_force_inline MD_String8Array md_str8_array_reserve__arena (MD_Arena* arena, MD_U64 count) { return md_str8_array_reserve__ainfo (md_arena_allocator(arena), count); }
////////////////////////////////
//~ rjf: String Path Helpers
MD_API MD_String8 md_str8_chop_last_slash(MD_String8 string);
MD_API MD_String8 md_str8_skip_last_slash(MD_String8 string);
MD_API MD_String8 md_str8_chop_last_dot (MD_String8 string);
MD_API MD_String8 md_str8_skip_last_dot (MD_String8 string);
md_force_inline MD_String8List md_str8_split_path__arena(MD_Arena* arena, MD_String8 string) { MD_String8List result = md_str8_split(arena, string, (MD_U8*)"/\\", 2, 0); return(result); }
md_force_inline MD_String8List md_str8_split_path__ainfo(MD_AllocatorInfo ainfo, MD_String8 string) { MD_String8List result = md_str8_split(ainfo, string, (MD_U8*)"/\\", 2, 0); return(result); }
#define md_str8_split_path(allocator, string) _Generic(allocator, MD_Arena*: md_str8_split_path__arena, MD_AllocatorInfo: md_str8_split_path__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string)
MD_API MD_PathStyle md_path_style_from_str8 (MD_String8 string);
MD_API void md_str8_path_list_resolve_dots_in_place( MD_String8List* path, MD_PathStyle style);
MD_API MD_String8 md_str8_path_list_join_by_style__arena (MD_Arena* arena, MD_String8List* path, MD_PathStyle style);
MD_API MD_String8 md_str8_path_list_join_by_style__ainfo (MD_AllocatorInfo ainfo, MD_String8List* path, MD_PathStyle style);
#define md_str8_path_list_join_by_style(allocator, path, style) _Generic(allocator, MD_Arena*: md_str8_path_list_join_by_style__arena, MD_AllocatorInfo: md_str8_split_path__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, path, style)
md_force_inline MD_String8 md_str8_path_list_join_by_style__arena(MD_Arena* arena, MD_String8List* path, MD_PathStyle style) { return md_str8_path_list_join_by_style__ainfo(md_arena_allocator(arena), path, style); }
////////////////////////////////
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
inline MD_U8
md_utf8_class(MD_U8 value)
{
md_local_persist
MD_U8 lookup_table[32] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5,
};
return lookup_table[value];
}
MD_API MD_UnicodeDecode md_utf8_decode (MD_U8* str, MD_U64 md_max);
MD_UnicodeDecode md_utf16_decode (MD_U16* str, MD_U64 md_max);
MD_API MD_U32 md_utf8_encode (MD_U8* str, MD_U32 codepoint);
MD_API MD_U32 md_utf16_encode (MD_U16* str, MD_U32 codepoint);
MD_U32 md_utf8_from_utf32_single(MD_U8* buffer, MD_U32 character);
inline MD_UnicodeDecode
md_utf16_decode(MD_U16* str, MD_U64 md_max) {
MD_UnicodeDecode result = {1, MD_MAX_U32};
result.codepoint = str[0];
result.inc = 1;
if (md_max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000) {
result.codepoint = ((str[0] - 0xD800) << 10) |
((str[1] - 0xDC00) + 0x10000);
result.inc = 2;
}
return(result);
}
inline MD_U32 md_utf8_from_utf32_single(MD_U8* buffer, MD_U32 character){ return(md_utf8_encode(buffer, character)); }
////////////////////////////////
//~ rjf: Unicode String Conversions
#define md_str8_from_str16(allocator, md_string_in) _Generic(allocator, MD_Arena*: md_str8_from_str16__arena, MD_AllocatorInfo: md_str8_from_str16__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, md_string_in)
#define md_str16_from_str8(allocator, md_string_in) _Generic(allocator, MD_Arena*: md_str16_from_str8__arena, MD_AllocatorInfo: md_str16_from_str8__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, md_string_in)
#define md_str8_from_str32(allocator, md_string_in) _Generic(allocator, MD_Arena*: md_str8_from_str32__arena, MD_AllocatorInfo: md_str8_from_str32__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, md_string_in)
#define md_str32_from_str8(allocator, md_string_in) _Generic(allocator, MD_Arena*: md_str32_from_str8__arena, MD_AllocatorInfo: md_str32_from_str8__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, md_string_in)
MD_API MD_String8 md_str8_from_str16__arena(MD_Arena* arena, MD_String16 in);
MD_API MD_String16 md_str16_from_str8__arena(MD_Arena* arena, MD_String8 in);
MD_API MD_String8 md_str8_from_str32__arena(MD_Arena* arena, MD_String32 in);
MD_API MD_String32 md_str32_from_str8__arena(MD_Arena* arena, MD_String8 in);
MD_API MD_String8 md_str8_from_str16__ainfo(MD_AllocatorInfo ainfo, MD_String16 in);
MD_API MD_String16 md_str16_from_str8__ainfo(MD_AllocatorInfo ainfo, MD_String8 in);
MD_API MD_String8 md_str8_from_str32__ainfo(MD_AllocatorInfo ainfo, MD_String32 in);
MD_API MD_String32 md_str32_from_str8__ainfo(MD_AllocatorInfo ainfo, MD_String8 in);
////////////////////////////////
//~ String -> Enum Conversions
MD_API MD_OperatingSystem md_operating_system_from_string(MD_String8 string);
////////////////////////////////
//~ rjf: Basic Types & Space Enum -> String Conversions
MD_String8 md_string_from_dimension (MD_Dimension dimension);
MD_String8 md_string_from_side (MD_Side side);
MD_String8 md_string_from_operating_system(MD_OperatingSystem os);
MD_String8 md_string_from_architecture (MD_Arch arch);
inline MD_String8
md_string_from_dimension(MD_Dimension dimension) {
md_local_persist MD_String8 strings[] = {
md_str8_lit_comp("X"),
md_str8_lit_comp("Y"),
md_str8_lit_comp("Z"),
md_str8_lit_comp("W"),
};
MD_String8 result = md_str8_lit("error");
if ((MD_U32)dimension < 4) {
result = strings[dimension];
}
return(result);
}
inline MD_String8
md_string_from_side(MD_Side side) {
md_local_persist MD_String8 strings[] = {
md_str8_lit_comp("Min"),
md_str8_lit_comp("Max"),
};
MD_String8 result = md_str8_lit("error");
if ((MD_U32)side < 2) {
result = strings[side];
}
return(result);
}
inline MD_String8
md_string_from_operating_system(MD_OperatingSystem os) {
md_local_persist MD_String8 strings[] = {
md_str8_lit_comp("Null"),
md_str8_lit_comp("Windows"),
md_str8_lit_comp("Linux"),
md_str8_lit_comp("Mac"),
};
MD_String8 result = md_str8_lit("error");
if (os < MD_OperatingSystem_COUNT) {
result = strings[os];
}
return(result);
}
inline MD_String8
md_string_from_architecture(MD_Arch arch) {
md_local_persist MD_String8 strings[] = {
md_str8_lit_comp("Null"),
md_str8_lit_comp("x64"),
md_str8_lit_comp("x86"),
md_str8_lit_comp("arm64"),
md_str8_lit_comp("arm32"),
};
MD_String8 result = md_str8_lit("error");
if (arch < MD_Arch_COUNT) {
result = strings[arch];
}
return(result);
}
////////////////////////////////
//~ rjf: Time Types -> String
inline MD_String8
md_string_from_week_day(MD_WeekDay week_day)
{
md_local_persist MD_String8 strings[] = {
md_str8_lit_comp("Sun"),
md_str8_lit_comp("Mon"),
md_str8_lit_comp("Tue"),
md_str8_lit_comp("Wed"),
md_str8_lit_comp("Thu"),
md_str8_lit_comp("Fri"),
md_str8_lit_comp("Sat"),
};
MD_String8 result = md_str8_lit("Err");
if ((MD_U32)week_day < MD_WeekDay_COUNT) {
result = strings[week_day];
}
return(result);
}
inline MD_String8
md_string_from_month(MD_Month month)
{
md_local_persist MD_String8 strings[] = {
md_str8_lit_comp("Jan"),
md_str8_lit_comp("Feb"),
md_str8_lit_comp("Mar"),
md_str8_lit_comp("Apr"),
md_str8_lit_comp("May"),
md_str8_lit_comp("Jun"),
md_str8_lit_comp("Jul"),
md_str8_lit_comp("Aug"),
md_str8_lit_comp("Sep"),
md_str8_lit_comp("Oct"),
md_str8_lit_comp("Nov"),
md_str8_lit_comp("Dec"),
};
MD_String8 result = md_str8_lit("Err");
if ((MD_U32)month < MD_Month_COUNT) {
result = strings[month];
}
return(result);
}
MD_String8 md_date_time_string__arena (MD_Arena* arena, MD_DateTime* date_time);
MD_String8 md_file_name_date_time_string__arena(MD_Arena* arena, MD_DateTime* date_time);
MD_String8 md_string_from_elapsed_time__arena (MD_Arena* arena, MD_DateTime date_time);
MD_API MD_String8 md_date_time_string__ainfo (MD_AllocatorInfo ainfo, MD_DateTime* date_time);
MD_API MD_String8 md_file_name_date_time_string__ainfo(MD_AllocatorInfo ainfo, MD_DateTime* date_time);
MD_API MD_String8 md_string_from_elapsed_time__ainfo (MD_AllocatorInfo ainfo, MD_DateTime date_time);
#define md_date_time_string(allocator, date_time) _Generic(allocator, MD_Arena*: md_date_time_string__arena, MD_AllocatorInfo: md_date_time_string__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, date_time)
#define file_name_date_time_string(allocator, date_time) _Generic(allocator, MD_Arena*: md_file_name_date_time_string__arena, MD_AllocatorInfo: md_file_name_date_time_string__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, date_time)
#define md_string_from_elapsed_time(allocator, date_time) _Generic(allocator, MD_Arena*: md_string_from_elapsed_time__arena, MD_AllocatorInfo: md_string_from_elapsed_time__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, date_time)
md_force_inline MD_String8 md_push_date_time_string__arena (MD_Arena* arena, MD_DateTime* date_time) { return md_date_time_string__ainfo (md_arena_allocator(arena), date_time); }
md_force_inline MD_String8 md_push_file_name_date_time_string__arena(MD_Arena* arena, MD_DateTime* date_time) { return md_file_name_date_time_string__ainfo(md_arena_allocator(arena), date_time); }
md_force_inline MD_String8 md_string_from_elapsed_time__arena (MD_Arena* arena, MD_DateTime dt) { return md_string_from_elapsed_time__ainfo (md_arena_allocator(arena), dt); }
////////////////////////////////
//~ Globally Unique Ids
inline MD_String8
md_string_from_guid__arena(MD_Arena* arena, MD_Guid guid) {
MD_String8 result = md_str8f(arena,
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.data1,
guid.data2,
guid.data3,
guid.data4[0],
guid.data4[1],
guid.data4[2],
guid.data4[3],
guid.data4[4],
guid.data4[5],
guid.data4[6],
guid.data4[7]
);
return result;
}
inline MD_String8
md_string_from_guid__ainfo(MD_AllocatorInfo ainfo, MD_Guid guid) {
MD_String8 result = md_str8f(ainfo,
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.data1,
guid.data2,
guid.data3,
guid.data4[0],
guid.data4[1],
guid.data4[2],
guid.data4[3],
guid.data4[4],
guid.data4[5],
guid.data4[6],
guid.data4[7]
);
return result;
}
#define md_string_from_guid(allocator, guid) _Generic(allocator, MD_Arena*: md_string_from_guid__arena, MD_AllocatorInfo: md_string_from_guid__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, guid)
inline MD_Guid md_guid_from_string(MD_String8 string) { MD_Guid guid = {0}; md_try_guid_from_string(string, &guid); return guid; }
MD_API MD_B32 md_try_guid_from_string(MD_String8 string, MD_Guid* md_guid_out);
////////////////////////////////
//~ rjf: Basic Text Indentation
MD_String8 md_indented_from_string__arena(MD_Arena* arena, MD_String8 string);
MD_API MD_String8 md_indented_from_string__ainfo(MD_AllocatorInfo arena, MD_String8 string);
#define md_indented_from_string(allocator, string) _Generic(allocator, MD_Arena*: md_indented_from_string__arena, MD_AllocatorInfo: md_indented_from_string__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string)
md_force_inline MD_String8 md_indented_from_string__arena(MD_Arena* arena, MD_String8 string) { return md_indented_from_string__ainfo(md_arena_allocator(arena), string); }
////////////////////////////////
//~ rjf: Text Escaping
MD_String8 md_escaped_from_raw_str8__arena(MD_Arena* arena, MD_String8 string);
MD_API MD_String8 md_escaped_from_raw_str8__ainfo(MD_AllocatorInfo ainfo, MD_String8 string);
MD_String8 md_raw_from__escaped_str8__arena(MD_Arena* arena, MD_String8 string);
MD_API MD_String8 md_raw_from__escaped_str8__ainfo(MD_AllocatorInfo ainfo, MD_String8 string);
#define md_escaped_from_raw_str8(allocator, string) _Generic(allocator, MD_Arena*: md_escaped_from_raw_str8__arena, MD_AllocatorInfo: md_escaped_from_raw_str8__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string)
#define md_raw_from__escaped_str8(allocator, string) _Generic(allocator, MD_Arena*: md_raw_from__escaped_str8__arena, MD_AllocatorInfo: md_raw_from__escaped_str8__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string)
md_force_inline MD_String8 md_escaped_from_raw_str8__arena (MD_Arena* arena, MD_String8 string) { return md_escaped_from_raw_str8__ainfo (md_arena_allocator(arena), string); }
md_force_inline MD_String8 md_raw_from__escaped_str8__arena(MD_Arena* arena, MD_String8 string) { return md_raw_from__escaped_str8__ainfo(md_arena_allocator(arena), string); }
////////////////////////////////
//~ rjf: Text Wrapping
MD_String8List md_wrapped_lines_from_string__arena(MD_Arena* arena, MD_String8 string, MD_U64 first_line_max_width, MD_U64 max_width, MD_U64 wrap_indent);
MD_API MD_String8List md_wrapped_lines_from_string__ainfo(MD_AllocatorInfo ainfo, MD_String8 string, MD_U64 first_line_max_width, MD_U64 max_width, MD_U64 wrap_indent);
#define md_wrapped_lines_from_string(allocator, string, first_line_max_width, max_width, wrap_indent) \
_Generic(allocator, MD_Arena*: md_wrapped_lines_from_string__arena, MD_AllocatorInfo: md_wrapped_lines_from_string__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, string, first_line_max_width, max_width, wrap_indent)
md_force_inline MD_String8List md_wrapped_lines_from_string__arena(MD_Arena* arena, MD_String8 string, MD_U64 first_line_max_width, MD_U64 max_width, MD_U64 wrap_indent)
{ return md_wrapped_lines_from_string__ainfo(md_arena_allocator(arena), string, first_line_max_width, max_width, wrap_indent); }
////////////////////////////////
//~ rjf: String <-> Color
inline MD_String8 md_hex_string_from_rgba_4f32__arena(MD_Arena* arena, MD_Vec4F32 rgba) { MD_String8 hex_string = md_str8f(arena, "%02x%02x%02x%02x", (MD_U8)(rgba.x * 255.f), (MD_U8)(rgba.y * 255.f), (MD_U8)(rgba.z * 255.f), (MD_U8)(rgba.w * 255.f)); return hex_string; }
inline MD_String8 md_hex_string_from_rgba_4f32__ainfo(MD_AllocatorInfo ainfo, MD_Vec4F32 rgba) { MD_String8 hex_string = md_str8f(ainfo, "%02x%02x%02x%02x", (MD_U8)(rgba.x * 255.f), (MD_U8)(rgba.y * 255.f), (MD_U8)(rgba.z * 255.f), (MD_U8)(rgba.w * 255.f)); return hex_string; }
#define md_hex_string_from_rgba_4f32(allocator, rgba) _Generic(allocator, MD_Arena*: md_hex_string_from_rgba_4f32__arena, MD_AllocatorInfo: md_hex_string_from_rgba_4f32__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, rgba)
MD_API MD_Vec4F32 md_rgba_from_hex_string_4f32(MD_String8 hex_string);
////////////////////////////////
//~ rjf: String Fuzzy Matching
MD_FuzzyMatchRangeList md_fuzzy_match_find__arena (MD_Arena* arena, MD_String8 needle, MD_String8 haystack);
MD_API MD_FuzzyMatchRangeList md_fuzzy_match_find__ainfo (MD_AllocatorInfo ainfo, MD_String8 needle, MD_String8 haystack);
MD_FuzzyMatchRangeList md_fuzzy_match_range_list_copy__arena(MD_Arena* arena, MD_FuzzyMatchRangeList* src);
MD_API MD_FuzzyMatchRangeList md_fuzzy_match_range_list_copy__ainfo(MD_AllocatorInfo ainfo, MD_FuzzyMatchRangeList* src);
#define md_fuzzy_match_find(allocator, needle, haystack) _Generic(allocator, MD_Arena*: md_fuzzy_match_find__arena, MD_AllocatorInfo: md_fuzzy_match_find__ainfo) md_generic_call(allocator, needle, haystack)
#define md_fuzzy_match_range_list_copy(allocator, src) _Generic(allocator, MD_Arena*: md_fuzzy_match_range_list_copy__arena, MD_AllocatorInfo: md_fuzzy_match_range_list_copy__ainfo) md_generic_call(allocator, src)
md_force_inline MD_FuzzyMatchRangeList md_fuzzy_match_find__arena (MD_Arena *arena, MD_String8 needle, MD_String8 haystack) { return md_fuzzy_match_find__ainfo (md_arena_allocator(arena), needle, haystack); }
md_force_inline MD_FuzzyMatchRangeList md_fuzzy_match_range_list_copy__arena(MD_Arena* arena, MD_FuzzyMatchRangeList* src) { return md_fuzzy_match_range_list_copy__ainfo(md_arena_allocator(arena), src); }
////////////////////////////////
//~ NOTE(allen): Serialization Helpers
#define md_str8_serial_push_array(allocator, srl, ptr, count) md_str8_serial_push_data (allocator, srl, ptr, sizeof(*(ptr)) * (count))
#define md_str8_serial_push_struct(allocator, srl, ptr) md_str8_serial_push_array(allocator, srl, ptr, 1)
inline void
md_str8_serial_write_to_dst(MD_String8List* srl, void* out) {
MD_U8* ptr = (MD_U8*)out;
for (MD_String8Node *node = srl->first; node != 0; node = node->next)
{
MD_U64 size = node->string.size;
md_memory_copy(ptr, node->string.str, size);
ptr += size;
}
}
void md_str8_serial_begin__arena (MD_Arena* arena, MD_String8List* srl);
MD_String8 md_str8_serial_end__arena (MD_Arena* arena, MD_String8List* srl);
MD_U64 md_str8_serial_push_align__arena (MD_Arena* arena, MD_String8List* srl, MD_U64 align);
void* md_str8_serial_push_size__arena (MD_Arena* arena, MD_String8List* srl, MD_U64 size);
void* md_str8_serial_push_data__arena (MD_Arena* arena, MD_String8List* srl, void* data, MD_U64 size);
void md_str8_serial_push_data_list__arena(MD_Arena* arena, MD_String8List* srl, MD_String8Node* first);
void md_str8_serial_push_u64__arena (MD_Arena* arena, MD_String8List* srl, MD_U64 x);
void md_str8_serial_push_u32__arena (MD_Arena* arena, MD_String8List* srl, MD_U32 x);
void md_str8_serial_push_u16__arena (MD_Arena* arena, MD_String8List* srl, MD_U16 x);
void md_str8_serial_push_u8__arena (MD_Arena* arena, MD_String8List* srl, MD_U8 x);
void md_str8_serial_push_cstr__arena (MD_Arena* arena, MD_String8List* srl, MD_String8 str);
void md_str8_serial_push_string__arena (MD_Arena* arena, MD_String8List* srl, MD_String8 str);
void md_str8_serial_begin__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl);
MD_String8 md_str8_serial_end__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl);
MD_API MD_U64 md_str8_serial_push_align__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U64 align);
MD_API void* md_str8_serial_push_size__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U64 size);
void* md_str8_serial_push_data__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, void* data, MD_U64 size);
void md_str8_serial_push_data_list__ainfo(MD_AllocatorInfo ainfo, MD_String8List* srl, MD_String8Node* first);
MD_API void md_str8_serial_push_u64__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U64 x);
MD_API void md_str8_serial_push_u32__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U32 x);
void md_str8_serial_push_u16__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U16 x);
void md_str8_serial_push_u8__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U8 x);
void md_str8_serial_push_cstr__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_String8 str);
void md_str8_serial_push_string__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_String8 str);
#define md_str8_serial_begin(allocator, srl) _Generic(allocator, MD_Arena*: md_str8_serial_begin__arena, MD_AllocatorInfo: md_str8_serial_begin__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl)
#define md_str8_serial_end(allocator, srl) _Generic(allocator, MD_Arena*: md_str8_serial_end__arena, MD_AllocatorInfo: md_str8_serial_end__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl)
#define md_str8_serial_push_align(allocator, srl, align) _Generic(allocator, MD_Arena*: md_str8_serial_push_align__arena, MD_AllocatorInfo: md_str8_serial_push_align__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, align)
#define md_str8_serial_push_size(allocator, srl, size) _Generic(allocator, MD_Arena*: md_str8_serial_push_size__arena, MD_AllocatorInfo: md_str8_serial_push_size__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, size)
#define md_str8_serial_push_data(allocator, srl, data, usize) _Generic(allocator, MD_Arena*: md_str8_serial_push_data__arena, MD_AllocatorInfo: md_str8_serial_push_data__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, data, usize)
#define md_str8_serial_push_data_list(allocator, srl, first) _Generic(allocator, MD_Arena*: md_str8_serial_push_data_list__arena, MD_AllocatorInfo: md_str8_serial_push_data_list__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, first)
#define md_str8_serial_push_u64(allocator, srl, x) _Generic(allocator, MD_Arena*: md_str8_serial_push_u64__arena, MD_AllocatorInfo: md_str8_serial_push_u64__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, x)
#define md_str8_serial_push_u32(allocator, srl, x) _Generic(allocator, MD_Arena*: md_str8_serial_push_u32__arena, MD_AllocatorInfo: md_str8_serial_push_u32__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, x)
#define md_str8_serial_push_u16(allocator, srl, x) _Generic(allocator, MD_Arena*: md_str8_serial_push_u16__arena, MD_AllocatorInfo: md_str8_serial_push_u16__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, x)
#define md_str8_serial_push_u8(allocator, srl, x) _Generic(allocator, MD_Arena*: md_str8_serial_push_u8__arena, MD_AllocatorInfo: md_str8_serial_push_u8__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, x)
#define md_str8_serial_push_cstr(allocator, srl, str) _Generic(allocator, MD_Arena*: md_str8_serial_push_cstr__arena, MD_AllocatorInfo: md_str8_serial_push_cstr__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, str)
#define md_str8_serial_push_string(allocator, slr, str) _Generic(allocator, MD_Arena*: md_str8_serial_push_string__arena, MD_AllocatorInfo: md_str8_serial_push_string__ainfo, default: md_assert_generic_sel_fail) md_generic_call(allocator, srl, str)
md_force_inline MD_U64 md_str8_serial_push_align__arena(MD_Arena* arena, MD_String8List* srl, MD_U64 align) { return md_str8_serial_push_align__ainfo(md_arena_allocator(arena), srl, align); }
md_force_inline void* md_str8_serial_push_size__arena (MD_Arena* arena, MD_String8List* srl, MD_U64 size) { return md_str8_serial_push_size__ainfo (md_arena_allocator(arena), srl, size); }
md_force_inline void md_str8_serial_push_u64__arena (MD_Arena* arena, MD_String8List* srl, MD_U64 x) { md_str8_serial_push_u64__ainfo (md_arena_allocator(arena), srl, x); }
md_force_inline void md_str8_serial_push_u32__arena (MD_Arena* arena, MD_String8List* srl, MD_U32 x) { md_str8_serial_push_u32__ainfo (md_arena_allocator(arena), srl, x); }
md_force_inline void md_str8_serial_begin__arena(MD_Arena* arena, MD_String8List* srl) { md_str8_serial_begin__ainfo(md_arena_allocator(arena), srl); }
md_force_inline MD_String8 md_str8_serial_end__arena (MD_Arena* arena, MD_String8List* srl) { return md_str8_serial_end__ainfo (md_arena_allocator(arena), srl); }
md_force_inline void md_str8_serial_push_u16__arena (MD_Arena* arena, MD_String8List* srl, MD_U16 x) { md_str8_serial_push_data__arena(arena, srl, &x, sizeof(x)); }
md_force_inline void md_str8_serial_push_u8__arena (MD_Arena* arena, MD_String8List* srl, MD_U8 x) { md_str8_serial_push_data__arena(arena, srl, &x, sizeof(x)); }
md_force_inline void md_str8_serial_push_cstr__arena (MD_Arena* arena, MD_String8List* srl, MD_String8 str) { md_str8_serial_push_data__arena(arena, srl, str.str, str.size); md_str8_serial_push_u8__arena(arena, srl, 0); }
md_force_inline void md_str8_serial_push_string__arena(MD_Arena* arena, MD_String8List* srl, MD_String8 str) { md_str8_serial_push_data__arena(arena, srl, str.str, str.size); }
md_force_inline void md_str8_serial_push_u16__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U16 x) { md_str8_serial_push_data__ainfo(ainfo, srl, &x, sizeof(x)); }
md_force_inline void md_str8_serial_push_u8__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_U8 x) { md_str8_serial_push_data__ainfo(ainfo, srl, &x, sizeof(x)); }
md_force_inline void md_str8_serial_push_cstr__ainfo (MD_AllocatorInfo ainfo, MD_String8List* srl, MD_String8 str) { md_str8_serial_push_data__ainfo(ainfo, srl, str.str, str.size); md_str8_serial_push_u8__ainfo(ainfo, srl, 0); }
md_force_inline void md_str8_serial_push_string__ainfo(MD_AllocatorInfo ainfo, MD_String8List* srl, MD_String8 str) { md_str8_serial_push_data__ainfo(ainfo, srl, str.str, str.size); }
inline void*
md_str8_serial_push_data__arena(MD_Arena* arena, MD_String8List* srl, void* data, MD_U64 size) {
void* result = md_str8_serial_push_size__arena(arena, srl, size);
if(result != 0) {
md_memory_copy(result, data, size);
}
return result;
}
inline void
md_str8_serial_push_data_list__arena(MD_Arena* arena, MD_String8List* srl, MD_String8Node* first) {
for (MD_String8Node* node = first; node != 0; node = node->next) {
md_str8_serial_push_data__arena(arena, srl, node->string.str, node->string.size);
}
}
inline void
md_str8_serial_begin__ainfo(MD_AllocatorInfo ainfo, MD_String8List* srl) {
MD_String8Node* node = md_alloc_array(ainfo, MD_String8Node, 1);
node->string.str = md_alloc_array_no_zero(ainfo, MD_U8, 0);
srl->first = srl->last = node;
srl->node_count = 1;
srl->total_size = 0;
}
inline MD_String8
md_str8_serial_end_alloc(MD_AllocatorInfo ainfo, MD_String8List* srl) {
MD_U64 size = srl->total_size;
MD_U8* out = md_alloc_array_no_zero(ainfo, MD_U8, size);
md_str8_serial_write_to_dst(srl, out);
MD_String8 result = md_str8(out, size);
return result;
}
inline void*
md_str8_serial_push_data__ainfo(MD_AllocatorInfo ainfo, MD_String8List* srl, void* data, MD_U64 size) {
void* result = md_str8_serial_push_size(ainfo, srl, size);
if(result != 0) {
md_memory_copy(result, data, size);
}
return result;
}
inline void
md_str8_serial_push_data_list__ainfo(MD_AllocatorInfo ainfo, MD_String8List* srl, MD_String8Node* first) {
for (MD_String8Node* node = first; node != 0; node = node->next) {
md_str8_serial_push_data__ainfo(ainfo, srl, node->string.str, node->string.size);
}
}
////////////////////////////////
//~ rjf: Deserialization Helpers
#define md_str8_deserial_read_array(string, off, ptr, count) md_str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)) * (count), sizeof( *(ptr)))
#define md_str8_deserial_read_struct(string, off, ptr) md_str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof( *(ptr)))
MD_API MD_U64 md_str8_deserial_read (MD_String8 string, MD_U64 off, void* read_dst, MD_U64 read_size, MD_U64 granularity);
MD_API MD_U64 md_str8_deserial_find_first_match (MD_String8 string, MD_U64 off, MD_U16 scan_val);
void* md_str8_deserial_get_raw_ptr (MD_String8 string, MD_U64 off, MD_U64 size);
MD_API MD_U64 md_str8_deserial_read_cstr (MD_String8 string, MD_U64 off, MD_String8* cstr_out);
MD_API MD_U64 md_str8_deserial_read_windows_utf16_string16(MD_String8 string, MD_U64 off, MD_String16* md_str_out);
MD_U64 md_str8_deserial_read_block (MD_String8 string, MD_U64 off, MD_U64 size, MD_String8* block_out);
MD_API MD_U64 md_str8_deserial_read_uleb128 (MD_String8 string, MD_U64 off, MD_U64* value_out);
MD_API MD_U64 md_str8_deserial_read_sleb128 (MD_String8 string, MD_U64 off, MD_S64* value_out);
inline void* md_str8_deserial_get_raw_ptr(MD_String8 string, MD_U64 off, MD_U64 size) { void* raw_ptr = 0; if (off + size <= string.size) { raw_ptr = string.str + off; } return raw_ptr; }
inline MD_U64 md_str8_deserial_read_block (MD_String8 string, MD_U64 off, MD_U64 size, MD_String8* block_out) { MD_Rng1U64 range = md_rng_1u64(off, off + size); *block_out = md_str8_substr(string, range); return block_out->size; }
////////////////////////////////
// Second-order Generic Selectors
#define md_str8_from(allocator, in) \
_Generic((in), \
MD_SSIZE : _Generic(allocator, MD_Arena*: md_str8_from_memory_size__arena, MD_AllocatorInfo: md_str8_from_memory_size__ainfo, default: md_assert_generic_sel_fail), \
_Generic_L2((in), \
MD_String16: _Generic(allocator, MD_Arena*: md_str8_from_str16__arena, MD_AllocatorInfo: md_str8_from_str16__ainfo, default: md_assert_generic_sel_fail), \
MD_String32: _Generic(allocator, MD_Arena*: md_str8_from_str32__arena, MD_AllocatorInfo: md_str8_from_str32__ainfo, default: md_assert_generic_sel_fail), \
MD_U64 : _Generic(allocator, MD_Arena*: md_str8_from_u64__arena, MD_AllocatorInfo: md_str8_from_u64__ainfo, default: md_assert_generic_sel_fail), \
MD_S64 : _Generic(allocator, MD_Arena*: md_str8_from_s64__arena, MD_AllocatorInfo: md_str8_from_s64__ainfo, default: md_assert_generic_sel_fail), \
default : md_assert_generic_sel_fail) \
) md_generic_call(allocator, in)
#define md_str16_from(allocator, in) \
_Generic(in, \
MD_String8: _Generic(allocator, MD_Arena*: md_str16_from_str8__arena, MD_AllocatorInfo: md_str16_from_str8__ainfo, default: md_assert_generic_sel_fail), \
default: md_assert_generic_sel_fail \
) md_generic_call(allocator, in)