diff --git a/C/watl.v0.msvc.c b/C/watl.v0.msvc.c index 40bc3aa..67c2f58 100644 --- a/C/watl.v0.msvc.c +++ b/C/watl.v0.msvc.c @@ -1429,11 +1429,11 @@ U64 kt1cx_slot_id(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta m) { return hash_index; } Byte* kt1cx__get(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta m) { - U64 hash_index = kt1cx_slot_id(kt, key, m); - SSIZE cell_offset = hash_index * m.cell_size; - Slice_Byte cell = { & kt.table.ptr[cell_offset], m.cell_size}; // KT1CX_Cell_ cell = kt.table[hash_index] + U64 hash_index = kt1cx_slot_id(kt, key, m); + SSIZE cell_offset = hash_index * m.cell_size; + Byte* cell_cursor = & kt.table.ptr[cell_offset]; // KT1CX_Cell_ cell = kt.table[hash_index] { - Slice_Byte slots = {cell.ptr, m.cell_depth * m.slot_size}; // KT1CX_Slot_[kt.cell_depth] slots = cell.slots + Slice_Byte slots = {cell_cursor, m.cell_depth * m.slot_size}; // KT1CX_Slot_[kt.cell_depth] slots = cell.slots Byte* slot_cursor = slots.ptr; for (; slot_cursor != slice_end(slots); slot_cursor += m.slot_size) { process_slots: @@ -1442,11 +1442,11 @@ Byte* kt1cx__get(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta m) { return slot_cursor; } } - Byte* cell_next = cell.ptr + m.cell_next_offset; // cell.next + Byte* cell_next = cell_cursor + m.cell_next_offset; // cell.next if (cell_next != nullptr) { slots.ptr = cell_next; // slots = cell_next slot_cursor = cell_next; - cell.ptr = cell_next; // cell = cell_next + cell_cursor = cell_next; // cell = cell_next goto process_slots; } else { @@ -1456,11 +1456,11 @@ Byte* kt1cx__get(KT1CX_Byte kt, U64 key, KT1CX_ByteMeta m) { } inline Byte* kt1cx_set(KT1CX_Byte kt, U64 key, Slice_Byte value, AllocatorInfo backing_cells, KT1CX_ByteMeta m) { - U64 hash_index = kt1cx_slot_id(kt, key, m); - SSIZE cell_offset = hash_index * m.cell_size; - Slice_Byte cell = { & kt.table.ptr[cell_offset], m.cell_size}; // KT1CX_Cell_ cell = kt.table[hash_index] + U64 hash_index = kt1cx_slot_id(kt, key, m); + SSIZE cell_offset = hash_index * m.cell_size; + Byte* cell_cursor = & kt.table.ptr[cell_offset]; // KT1CX_Cell_ cell = kt.table[hash_index] { - Slice_Byte slots = {cell.ptr, m.cell_depth * m.slot_size}; // cell.slots + Slice_Byte slots = {cell_cursor, m.cell_depth * m.slot_size}; // cell.slots Byte* slot_cursor = slots.ptr; for (; slot_cursor != slice_end(slots); slot_cursor += m.slot_size) { process_slots: @@ -1474,11 +1474,11 @@ Byte* kt1cx_set(KT1CX_Byte kt, U64 key, Slice_Byte value, AllocatorInfo backing_ return slot_cursor; } } - KT1CX_Byte_Cell curr_cell = { cell.ptr + m.cell_next_offset }; // curr_cell = cell + KT1CX_Byte_Cell curr_cell = { cell_cursor + m.cell_next_offset }; // curr_cell = cell if ( curr_cell.next != nullptr) { slots.ptr = curr_cell.next; slot_cursor = curr_cell.next; - cell.ptr = curr_cell.next; + cell_cursor = curr_cell.next; goto process_slots; } else { @@ -1578,8 +1578,10 @@ Str8 str8_from_u32(AllocatorInfo ainfo, U32 num, U32 radix, U8 min_digits, U8 di } return result; } -Str8 str8__fmt_kt1l(AllocatorInfo ainfo, Slice_Byte buffer, KT1L_Str8 table, Str8 fmt_template) +Str8 str8__fmt_kt1l(AllocatorInfo ainfo, Slice_Byte* _buffer, KT1L_Str8 table, Str8 fmt_template) { + assert(_buffer != nullptr); + Slice_Byte buffer = *_buffer; slice_assert(buffer); slice_assert(table); slice_assert(fmt_template); @@ -1615,7 +1617,7 @@ Str8 str8__fmt_kt1l(AllocatorInfo ainfo, Slice_Byte buffer, KT1L_Str8 table, Str } if (fmt_overflow) continue; // Hashing the potential token and cross checking it with our token table - U64 key = 0; hash64_djb8(& key, (Slice_Byte){ cast(void*, cursor_fmt + 1), potential_token_length}); + U64 key = 0; hash64_djb8(& key, (Slice_Byte){ cast(Byte*, cursor_potential_token), potential_token_length}); Str8* value = nullptr; for (slice_iter(table, token)) { @@ -1629,7 +1631,8 @@ Str8 str8__fmt_kt1l(AllocatorInfo ainfo, Slice_Byte buffer, KT1L_Str8 table, Str { // We're going to appending the string, make sure we have enough space in our buffer. if (ainfo.proc != nullptr && (buffer_remaining - potential_token_length) <= 0) { - buffer = mem_grow(ainfo, buffer, buffer.len + potential_token_length); + buffer = mem_grow(ainfo, buffer, buffer.len + potential_token_length); + buffer_remaining += potential_token_length; } SSIZE left = value->len; U8* cursor_value = value->ptr; @@ -1655,6 +1658,7 @@ Str8 str8__fmt_kt1l(AllocatorInfo ainfo, Slice_Byte buffer, KT1L_Str8 table, Str curr_code = * cursor_fmt; } } + * _buffer = buffer; Str8 result = {buffer.ptr, buffer.len - buffer_remaining}; return result; } @@ -1663,14 +1667,14 @@ Str8 str8__fmt_backed(AllocatorInfo tbl_backing, AllocatorInfo buf_backing, Str8 KT1L_Str8 kt; kt1l_populate_slice_a2(Str8, & kt, tbl_backing, *entries ); SSIZE buf_size = kilo(64); Slice_Byte buffer = mem_alloc(buf_backing, buf_size); - Str8 result = str8__fmt_kt1l(buf_backing, buffer, kt, fmt_template); + Str8 result = str8__fmt_kt1l(buf_backing, & buffer, kt, fmt_template); return result; } Str8 str8__fmt(Str8 fmt_template, Slice_A2_Str8* entries) { local_persist Byte tbl_mem[kilo(32)]; FArena tbl_arena = farena_make(slice_fmem(tbl_mem)); local_persist Byte buf_mem[kilo(64)]; KT1L_Str8 kt = {0}; kt1l_populate_slice_a2(Str8, & kt, ainfo_farena(tbl_arena), *entries ); - Str8 result = str8__fmt_kt1l((AllocatorInfo){0}, slice_fmem(buf_mem), kt, fmt_template); + Str8 result = str8__fmt_kt1l((AllocatorInfo){0}, & slice_fmem(buf_mem), kt, fmt_template); return result; } inline @@ -1792,7 +1796,7 @@ void str8gen__append_fmt(Str8Gen* gen, Str8 fmt_template, Slice_A2_Str8* entries gen->cap = result.len; buffer = (Slice_Byte){ cast(Byte*, gen->ptr + gen->len), gen->cap - gen->len }; } - Str8 result = str8__fmt_kt1l(gen->backing, buffer, kt, fmt_template); + Str8 result = str8__fmt_kt1l(gen->backing, & buffer, kt, fmt_template); gen->len += result.len; } #pragma endregion String Operations diff --git a/Odin/watl.v0.odin b/Odin/watl.v0.odin index 4992124..60866d9 100644 --- a/Odin/watl.v0.odin +++ b/Odin/watl.v0.odin @@ -1007,26 +1007,24 @@ kt1cx_init :: proc(info: KT1CX_Info, m: KT1CX_InfoMeta, result: ^KT1CX_Byte) { result.table = transmute([]byte) table_raw } kt1cx_clear :: proc(kt: KT1CX_Byte, m: KT1CX_ByteMeta) { - cursor := cursor(kt.table) - num_cells := len(kt.table) - table_len := len(kt.table) * m.cell_size - for ; cursor != end(kt.table); cursor = cursor[m.cell_size:] // for cell in kt.table.cells + cell_cursor := cursor(kt.table) + table_len := len(kt.table) * m.cell_size + for ; cell_cursor != end(kt.table); cell_cursor = cell_cursor[m.cell_size:] // for cell, cell_id in kt.table.cells { - cell_cursor := cursor - slots := SliceBytes { cell.data, m.cell_depth * m.slot_size } // slots = cell.slots + slots := SliceBytes { cell_cursor, m.cell_depth * m.slot_size } // slots = cell.slots slot_cursor := slots.data for;; { - slot := transmute([]byte) SliceBytes { slot_cursor, m.slot_size } - zero(slot) - if slot_cursor == end(transmute([]byte) slots) { - next := slot_cursor[m.cell_next_offset:] - if next != nil { - slots.data = next + slot := slice(slot_cursor, m.slot_size) // slot = slots[slot_id] + zero(slot) // slot = {} + if slot_cursor == end(transmute([]byte) slots) { // if slot == end(slot) + next := slot_cursor[m.cell_next_offset:] // next = kt.table.cells[cell_id + 1] + if next != nil { // if next != nil + slots.data = next // slots = next.slots slot_cursor = next continue } } - slot_cursor = slot_cursor[m.slot_size:] + slot_cursor = slot_cursor[m.slot_size:] // slot = slots[slot_id + 1] } } } @@ -1049,11 +1047,11 @@ kt1cx_get :: proc(kt: KT1CX_Byte, key: u64, m: KT1CX_ByteMeta) -> ^byte { } if slot_cursor == end(transmute([]byte) slots) { - cell_next := cell_cursor[m.cell_next_offset:] + cell_next := cell_cursor[m.cell_next_offset:] // cell.next if cell_next != nil { - slots = slice(cell_next, len(slots)) + slots = slice(cell_next, len(slots)) // slots = cell.next slot_cursor = cell_next - cell_cursor = cell_next + cell_cursor = cell_next // cell = cell.next continue } else { @@ -1070,10 +1068,10 @@ kt1cx_set :: proc(kt: KT1CX_Byte, key: u64, value: []byte, backing_cells: Alloca cell := SliceBytes{& kt.table[cell_offset], m.cell_size} { slots := SliceBytes {cell.data, m.cell_depth * m.slot_size} - slot_cursor := uintptr(slots.data) + slot_cursor := slots.data for ;; { - slot := transmute(^KT1CX_Byte_Slot) rawptr(slot_cursor + m.slot_key_offset) + slot := transmute(^KT1CX_Byte_Slot) slot_cursor[m.slot_key_offset:] if slot.occupied == false { slot.occupied = true slot.key = key @@ -1082,24 +1080,24 @@ kt1cx_set :: proc(kt: KT1CX_Byte, key: u64, value: []byte, backing_cells: Alloca else if slot.key == key { return cast(^byte) slot_cursor } - if slot_cursor == uintptr(end(transmute([]byte) slots)) { + if slot_cursor == end(transmute([]byte) slots) { curr_cell := transmute(^KT1CX_Byte_Cell) (uintptr(cell.data) + m.cell_next_offset) if curr_cell != nil { slots.data = curr_cell.next - slot_cursor = uintptr(curr_cell.next) + slot_cursor = curr_cell.next cell.data = curr_cell.next continue } else { new_cell := mem_alloc(backing_cells, m.cell_size) curr_cell.next = raw_data(new_cell) - slot = transmute(^KT1CX_Byte_Slot) rawptr(uintptr(raw_data(new_cell)) + m.slot_key_offset) + slot = transmute(^KT1CX_Byte_Slot) cursor(new_cell)[m.slot_key_offset:] slot.occupied = true slot.key = key return raw_data(new_cell) } } - slot_cursor += uintptr(m.slot_size) + slot_cursor = slot_cursor[m.slot_size:] } return nil } @@ -1188,36 +1186,88 @@ str8_from_u32 :: proc(ainfo: AllocatorInfo, num: u32, radix: u32 = 10, min_digit return result } -str8_fmt_kt1l :: proc(ainfo: AllocatorInfo, buffer: []byte, table: []KT1L_Slot(string), fmt_template: string) -> string { +str8_fmt_kt1l :: proc(ainfo: AllocatorInfo, _buffer: ^[]byte, table: []KT1L_Slot(string), fmt_template: string) -> string { + buffer := _buffer^ slice_assert(buffer) slice_assert(table) string_assert(fmt_template) if ainfo.procedure != nil { assert(.Grow in allocator_query(ainfo).features) } - cursor_buffer := transmute(uintptr) raw_data(buffer) + cursor_buffer := cursor(buffer) buffer_remaining := len(buffer) curr_code := fmt_template[0] - cursor_fmt := transmute(uintptr) raw_data(fmt_template) + cursor_fmt := cursor(transmute([]u8) fmt_template) left_fmt := len(fmt_template) for ; left_fmt > 0 && buffer_remaining > 0; { // Forward until we hit the delimiter '<' or the template's contents are exhausted. - for ; curr_code != '<' && cursor_fmt != cast(uintptr) end(fmt_template); { + for ; curr_code != '<' && cursor_fmt != end(fmt_template); { cursor_buffer = cursor_fmt - cursor_buffer += 1 - cursor_fmt += 1 + cursor_buffer = cursor_buffer[1:] + cursor_fmt = cursor_fmt [1:] + curr_code = cursor_fmt [0] buffer_remaining -= 1 left_fmt -= 1 - curr_code = fmt_template[cursor_fmt] } if curr_code == '<' { - // cursor_potential_token := transmute([^]u8) (cursor_fmt + 1) + cursor_potential_token := cursor_fmt[1:] + potential_token_length := 0 + fmt_overflow := b32(false) + for ;; { + cursor := cursor_potential_token[potential_token_length:] + fmt_overflow = cursor >= end(fmt_template) + found_terminator := cast(b32) (cursor_potential_token[potential_token_length] == '>') + if fmt_overflow || found_terminator do break + potential_token_length += 1 + } + if fmt_overflow do continue + // Hashing the potential token and cross checking it with our token table + key : u64 = 0; hash64_djb8(& key, slice(cursor_fmt, potential_token_length)) + value : ^string = nil + for & token in table + { + // We do a linear iteration instead of a hash table lookup because the user should be never substiuting with more than 100 unqiue tokens.. + if (token.key == key) { + value = & token.value + break + } + } + if value != nil + { + // We're going to appending the string, make sure we have enough space in our buffer. + if ainfo.procedure != nil && (buffer_remaining - potential_token_length) <= 0 { + buffer = mem_grow(ainfo, buffer, len(buffer) + potential_token_length) + buffer_remaining += potential_token_length + } + left := len(value) + cursor_value := cursor(transmute([]u8) value^) + for ; left > 0 && buffer_remaining > 0; { + cursor_buffer = cursor_value + cursor_buffer = cursor_buffer[1:] + cursor_fmt = cursor_fmt [1:] + buffer_remaining -= 1 + left_fmt -= 1 + } + // Sync cursor format to after the processed token + cursor_fmt = cursor_potential_token[potential_token_length + 1:] + curr_code = cursor_fmt[0] + left_fmt -= potential_token_length + 2 // The 2 here are the '<' & '>' delimiters being omitted. + continue + } + cursor_buffer = cursor_fmt + cursor_buffer = cursor_buffer[1:] + cursor_fmt = cursor_fmt [1:] + curr_code = cursor_fmt [0] + buffer_remaining -= 1 + left_fmt -= 1 } } - return {} + _buffer ^ = buffer + result := transmute(string) slice(cursor(buffer), len(buffer) - buffer_remaining) + return result } str8_fmt_backed :: proc(tbl_ainfo, buf_ainfo: AllocatorInfo, fmt_template: string, entries: [][2]string) -> string {