Files

232 lines
7.6 KiB
C

#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "dsl.h"
# include "memory.h"
# include "encoding.h"
# include "hashing.h"
# include "tables.h"
# include "analysis.h"
# include "asm.h"
#endif
// NOTE(rjf): Includes reverses for uppercase and lowercase hex.
RO_ U8 integer_symbol_reverse[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,
};
FI_ B4 char_is_upper(UTF8 c) { return('A' <= c && c <= 'Z'); }
FI_ UTF8 char_to_lower(UTF8 c) { if (char_is_upper(c)) { c += ('a' - 'A'); } return(c); }
FI_ B4 char_is_digit(UTF8 c, U4 base) {
B4 result = 0; if (0 < base && base <= 16) {
if (integer_symbol_reverse[c] < base) result = 1;
}
return result;
}
FI_ UTF8 integer_symbols(UTF8 value) {
LP_ UTF8 lookup_table[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', };
return lookup_table[C_(UTF8, value)];
}
FI_ U8 u8_from_str8(Str8 str, U4 radix) {
U8 x = 0; if(1 < radix && radix <= 16) {
for each_iter(U8, cursor, str.len) {
x *= radix;
x += integer_symbol_reverse[str.ptr[cursor] & 0x7F];
}
}
return x;
}
typedef Struct_(Info_str8_from_u4) {
Str8 prefix;
U4 digit_group_size;
U4 needed_leading_zeros;
U4 size_required;
};
I_ Info_str8_from_u4 str8_from_u4_info(U4 num, U4 radix, U4 min_digits, U4 digit_group_separator)
{
Info_str8_from_u4 info = {0};
LP_ Str8 tbl_prefix[] = { slit8("0x"), slit8("0o"), slit8("0b") };
switch (radix) {
case 16: { info.prefix = tbl_prefix[0]; } break;
case 8: { info.prefix = tbl_prefix[1]; } break;
case 2: { info.prefix = tbl_prefix[2]; } break;
}
info.digit_group_size = 3;
switch (radix) {
default: break;
case 2:
case 8:
case 16: {
info.digit_group_size = 4;
}
break;
}
info.needed_leading_zeros = 0;
{
U4 needed_digits = 1;
{
U4 u32_reduce = num;
for(;;)
{
u32_reduce /= radix;
if (u32_reduce == 0) {
break;
}
needed_digits += 1;
}
}
info.needed_leading_zeros = (min_digits > needed_digits) ? min_digits - needed_digits : 0;
U4 needed_separators = 0;
if (digit_group_separator != 0)
{
needed_separators = (needed_digits + info.needed_leading_zeros) / info.digit_group_size;
if (needed_separators > 0 && (needed_digits + info.needed_leading_zeros) % info.digit_group_size == 0) {
needed_separators -= 1;
}
}
info.size_required = info.prefix.len + info.needed_leading_zeros + needed_separators + needed_digits;
}
return info;
}
I_ Str8 str8_from_u4_buf(Slice buf, U4 num, U4 radix, U4 min_digits, U4 digit_group_separator, Info_str8_from_u4 info)
{
assert(buf.len >= info.size_required);
Str8 result = { C_(UTF8*, buf.ptr), info.size_required };
/*Fill Content*/ {
U4 num_reduce = num;
U4 digits_until_separator = info.digit_group_size;
for (U8 idx = 0; idx < result.len; idx += 1)
{
U8 separator_pos = result.len - idx - 1;
if (digits_until_separator == 0 && digit_group_separator != 0) {
result.ptr[separator_pos] = u1_(digit_group_separator);
digits_until_separator = info.digit_group_size + 1;
}
else {
result.ptr[separator_pos] = (U1) char_to_lower(integer_symbols(u1_(num_reduce % radix)));
num_reduce /= radix;
}
digits_until_separator -= 1;
if (num_reduce == 0) break;
}
for (U8 leading_0_idx = 0; leading_0_idx < info.needed_leading_zeros; leading_0_idx += 1) {
result.ptr[info.prefix.len + leading_0_idx] = '0';
}
}
/*Fill Prefix*/ if (info.prefix.len > 0) { slice_copy(result, info.prefix); }
return result;
}
I_ Str8 str8_fmt_ktl_buf(Slice buffer, KTL_Str8 table, Str8 fmt_template){
slice_assert(buffer);
slice_assert(table);
slice_assert(fmt_template);
UTF8_R cursor_buffer = C_(UTF8_R, buffer.ptr);
U8 buffer_remaining = buffer.len;
UTF8_R cursor_fmt = fmt_template.ptr;
U8 left_fmt = fmt_template.len;
U1x16 needle_lt = splat_u4_u1x16(u4_byte_fill('<'));
U1x16 needle_gt = splat_u4_u1x16(u4_byte_fill('>'));
while (left_fmt && buffer_remaining)
{
// Forward until we hit the delimiter '<' or the template's contents are exhausted.
U8 copy_offset = 0;
if (cursor_fmt[0] == '<') {
UTF8_R sig = cursor_fmt + 1;
U8 sig_max = slice_end(fmt_template) - sig;
U8 sig_len = find_u1_via_u1x16(sig, sig_max, '>', needle_gt);
assert(sig_len < sig_max);
Str8_R value = ktl_str8_find(table, hash64_fnv1a_ret(slice_ut(sig, sig_len), 0));
U8 n = min(buffer_remaining, value->len);
assert((buffer_remaining - n) > 0); mem_copy(u8_(cursor_buffer), u8_(value->ptr), n);
cursor_buffer += n;
buffer_remaining -= n;
cursor_fmt = sig + sig_len + 1;
left_fmt -= sig_len + 2;
continue;
}
U8 n = find_u1_via_u1x16(cursor_fmt, min(left_fmt, buffer_remaining), '<', needle_lt);
assert((buffer_remaining - 1) > 0); n = min(buffer_remaining, n);
mem_copy(u8_(cursor_buffer), u8_(cursor_fmt), n);
cursor_buffer += n;
cursor_fmt += n;
buffer_remaining -= n;
left_fmt -= n;
}
return str8(C_(UTF8*,buffer.ptr), buffer.len - buffer_remaining);
}
typedef Struct_(Str8Gen) { UTF8* ptr; U8 cap, len; };
FI_ Str8Gen str8gen_make(Slice s) { return (Str8Gen){C_(UTF8*,s.ptr), s.len, 0}; }
FI_ Slice str8gen_buf(Str8Gen_R gen) { return (Slice){u8_(gen->ptr) + gen->len, gen->cap - gen->len}; }
FI_ void str8gen_append_str8(Str8Gen_R gen, Str8 str) { assert(gen != nullptr);
U8 ptr = u8_(gen->ptr) + gen->len;
mem_bump_u8(u8_(gen->ptr), gen->cap, & gen->len, str.len);
mem_copy(ptr, u8_(str.ptr), str.len);
}
FI_ void str8gen_append_fmt(Str8Gen_R gen, Str8 fmt, KTL_Str8 tbl) {
Str8 result = str8_fmt_ktl_buf(str8gen_buf(gen), tbl, fmt);
gen->len += result.len;
}
#define str8gen_append_str8_(gen, s) str8gen_append_str8(gen, str8(s))
// Dealing with Wides (UTF16)
typedef U4 UTF16;
typedef Struct_(Str16) { UTF16* ptr; U8 len; };
typedef Str16 Slice_UTF16;
#define str16(p,l) (Str16){p,l}
internal Str16
str16_from_8(FArena* arena, Str8 in) {
Str16 result = {0}; if (in.len) {
U8 pre_pos = farena_save(arena[0]);
U8 cap = in.len * 2;
Slice_U2 str = farena_push_array(arena, U2, cap + 1);
U1* ptr = in.ptr;
U1* opl = ptr + in.len;
U8 size = 0;
UnicodeDecode consume;
for(;ptr < opl; ptr += consume.inc) {
consume = utf8_decode(ptr, opl - ptr);
size += utf16_encode(str.ptr + size, consume.codepoint);
}
str.ptr[size] = 0;
U8 committed = align_pow2((size + 1) * S_(U2), MEM_ALIGNMENT_DEFAULT);
farena_rewind(arena, pre_pos + committed);
result = str16(C_(UTF16*, str.ptr), size);
}
return result;
}
// Formatter where serial operation is done on-demand per-entry.
// enum {
// KTL_Str8FmtEntry_InlaidSize = (S_(Str8) * 2) - S_(Str8Fmt_TokenKind),
// };
// typedef Enum_(U4, Str8Fmt_SerialOpKind) {
// Str8Fmt_TKind_Str8,
// Str8Fmt_Base16_U1,
// Str8Fmt_Base16_U2,
// Str8Fmt_Base10_U4,
// };
// typedef Struct_(KTL_Str8Fmt_SerialOp_Entry) {
// union {
// U1 InlaidData[KTL_Str8FmtEntry_InlaidSize];
// Str8 str;
// void* Ptr;
// };
// Str8Fmt_SerialOpKind kind;
// };
// typedef KTL_Slot_(KTL_Str8Fmt_SerialOp_Entry);