Added basic string interning
This commit is contained in:
parent
c395cbaeb6
commit
f1edf1c43e
@ -79,6 +79,8 @@ startup :: proc( persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^V
|
||||
verify( alloc_error == .None, "Failed to allocate the general slab allocator" )
|
||||
}
|
||||
|
||||
string_cache = str_cache_init()
|
||||
|
||||
context.user_ptr = state
|
||||
|
||||
input = & input_data[1]
|
||||
@ -143,7 +145,7 @@ startup :: proc( persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^V
|
||||
// path_squidgy_slimes := strings.concatenate( { Path_Assets, "Squidgy Slimes.ttf" } )
|
||||
// font_squidgy_slimes = font_load( path_squidgy_slimes, 24.0, "Squidgy_Slime" )
|
||||
|
||||
path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" }, frame_allocator() )
|
||||
path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" }, transient_allocator() )
|
||||
font_firacode = font_load( path_firacode, 24.0, "FiraCode" )
|
||||
default_font = font_firacode
|
||||
log( "Default font loaded" )
|
||||
@ -152,9 +154,9 @@ startup :: proc( persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^V
|
||||
// Demo project setup
|
||||
{
|
||||
using project
|
||||
path = "./"
|
||||
name = "First Project"
|
||||
workspace.name = "First Workspace"
|
||||
path = str_intern("./")
|
||||
name = str_intern( "First Project" )
|
||||
workspace.name = str_intern( "First Workspace" )
|
||||
{
|
||||
using project.workspace
|
||||
cam = {
|
||||
|
@ -133,6 +133,7 @@ AppConfig :: struct {
|
||||
|
||||
State :: struct {
|
||||
general_slab : Slab,
|
||||
string_cache : StringCache,
|
||||
|
||||
font_provider_data : FontProviderData,
|
||||
|
||||
@ -190,8 +191,8 @@ ProjectConfig :: struct {
|
||||
}
|
||||
|
||||
Project :: struct {
|
||||
path : string,
|
||||
name : string,
|
||||
path : StringCached,
|
||||
name : StringCached,
|
||||
|
||||
config : ProjectConfig,
|
||||
codebase : CodeBase,
|
||||
@ -209,7 +210,7 @@ Frame :: struct
|
||||
}
|
||||
|
||||
Workspace :: struct {
|
||||
name : string,
|
||||
name : StringCached,
|
||||
|
||||
cam : Camera,
|
||||
zoom_target : f32,
|
||||
|
@ -160,6 +160,7 @@ font_load :: proc( path_file : string,
|
||||
rl.UnloadImage( atlas )
|
||||
}
|
||||
|
||||
free_all( context.temp_allocator )
|
||||
return { key, desired_id }
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,11 @@ cm_to_pixels :: proc {
|
||||
range2_cm_to_pixels,
|
||||
}
|
||||
|
||||
draw_text :: proc {
|
||||
draw_text_string,
|
||||
draw_text_string_cached,
|
||||
}
|
||||
|
||||
get_bounds :: proc {
|
||||
view_get_bounds,
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ SlabPolicy :: StackFixed(SlabSizeClass, Slab_Max_Size_Classes)
|
||||
SlabHeader :: struct {
|
||||
backing : Allocator,
|
||||
|
||||
policy : SlabPolicy,
|
||||
policy : SlabPolicy, // TODO(Ed) : Remove this, the policy can't be changed after its been set so its meaningless to have...
|
||||
pools : StackFixed(Pool, Slab_Max_Size_Classes),
|
||||
}
|
||||
|
||||
@ -222,7 +222,6 @@ slab_allocator_proc :: proc(
|
||||
alignment := uint(alignment)
|
||||
old_size := uint(old_size)
|
||||
|
||||
// TODO(Ed) : Compiler bug - Some of these are commented out until I finish resolving issues with the pool allocator
|
||||
switch mode
|
||||
{
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
|
@ -1 +1,87 @@
|
||||
/*
|
||||
This is a quick and dirty string table.
|
||||
IT uses the HMapZPL for the hashtable of strings, and the string's content is stored in a dedicated slab.
|
||||
|
||||
Future Plans (IF needed for performance):
|
||||
The goal is to eventually swap out the slab with possilby a dedicated growing vmem arena for the strings.
|
||||
The table would be swapped with a table stored in the general slab and uses either linear probing or open addressing
|
||||
|
||||
If linear probing, the hash node list per table bucket is store with the strigns in the same arena.
|
||||
If open addressing, we just keep the open addressed array of node slots in the general slab (but hopefully better perf)
|
||||
*/
|
||||
package sectr
|
||||
|
||||
import "core:mem"
|
||||
import "core:slice"
|
||||
import "core:strings"
|
||||
|
||||
StringCached :: struct {
|
||||
str : string,
|
||||
runes : []rune,
|
||||
}
|
||||
|
||||
StringCache :: struct {
|
||||
slab : Slab,
|
||||
table : HMapZPL(StringCached),
|
||||
}
|
||||
|
||||
str_cache_init :: proc( /*allocator : Allocator*/ ) -> ( cache : StringCache ) {
|
||||
alignment := uint(mem.DEFAULT_ALIGNMENT)
|
||||
|
||||
policy : SlabPolicy
|
||||
policy_ptr := & policy
|
||||
push( policy_ptr, SlabSizeClass { 8 * Megabyte, 16, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 8 * Megabyte, 32, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 16 * Megabyte, 64, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 16 * Megabyte, 128, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 16 * Megabyte, 256, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 16 * Megabyte, 512, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 32 * Megabyte, 1 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 32 * Megabyte, 4 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 64 * Megabyte, 16 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 64 * Megabyte, 32 * Kilobyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 64 * Megabyte, 64 * Kilobyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 64 * Megabyte, 128 * Kilobyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 64 * Megabyte, 256 * Kilobyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 64 * Megabyte, 512 * Kilobyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 64 * Megabyte, 1 * Megabyte, alignment })
|
||||
|
||||
header_size :: size_of( Slab )
|
||||
|
||||
alloc_error : AllocatorError
|
||||
cache.slab, alloc_error = slab_init( & policy, allocator = persistent_allocator() )
|
||||
verify(alloc_error == .None, "Failed to initialize the string cache" )
|
||||
|
||||
cache.table, alloc_error = zpl_hmap_init_reserve( StringCached, general_slab_allocator(), 64 * Kilobyte )
|
||||
return
|
||||
}
|
||||
|
||||
// str_cache_intern_string :: proc(
|
||||
// cache : ^StringCache,
|
||||
str_intern :: proc(
|
||||
content : string
|
||||
) -> StringCached
|
||||
{
|
||||
cache := get_state().string_cache
|
||||
|
||||
key := u64( crc32( transmute([]byte) content ))
|
||||
result := zpl_hmap_get( & cache.table, key )
|
||||
if result != nil {
|
||||
return (result ^)
|
||||
}
|
||||
|
||||
length := len(content)
|
||||
str_mem, alloc_error := slab_alloc( cache.slab, uint(length), uint(mem.DEFAULT_ALIGNMENT) )
|
||||
verify( alloc_error == .None, "String cache had a backing allocator error" )
|
||||
|
||||
copy_non_overlapping( raw_data(str_mem), raw_data(content), length )
|
||||
|
||||
runes : []rune
|
||||
runes, alloc_error = to_runes( content, slab_allocator(cache.slab) )
|
||||
verify( alloc_error == .None, "String cache had a backing allocator error" )
|
||||
|
||||
result, alloc_error = zpl_hmap_set( & cache.table, key, StringCached { transmute(string) str_mem, runes } )
|
||||
verify( alloc_error == .None, "String cache had a backing allocator error" )
|
||||
|
||||
return (result ^)
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import "core:dynlib"
|
||||
import "core:io"
|
||||
import fmt_io "core:fmt"
|
||||
str_fmt :: fmt_io.printf
|
||||
str_fmt_alloc :: fmt_io.aprintf
|
||||
str_fmt_tmp :: fmt_io.tprintf
|
||||
str_fmt_builder :: fmt_io.sbprintf
|
||||
import "core:log"
|
||||
@ -251,11 +252,11 @@ main :: proc()
|
||||
}
|
||||
|
||||
timestamp := str_fmt_tmp("%04d-%02d-%02d_%02d-%02d-%02d", year, month, day, hour, min, sec)
|
||||
path_logger_finalized = str_clone( str_fmt_tmp( "%s/sectr_%v.log", Path_Logs, timestamp) )
|
||||
path_logger_finalized = str_fmt_alloc( "%s/sectr_%v.log", Path_Logs, timestamp)
|
||||
}
|
||||
|
||||
logger : sectr.Logger
|
||||
logger_init( & logger, "Sectr Host", str_fmt_tmp( "%s/sectr.log", Path_Logs ) )
|
||||
logger_init( & logger, "Sectr Host", str_fmt_alloc( "%s/sectr.log", Path_Logs ) )
|
||||
context.logger = to_odin_logger( & logger )
|
||||
{
|
||||
// Log System Context
|
||||
|
@ -163,12 +163,12 @@ project_save :: proc( project : ^ Project, archive : ^ ArchiveData = nil )
|
||||
}
|
||||
project_serialize( project, archive )
|
||||
|
||||
if ! os.is_dir( project.path ) {
|
||||
os.make_directory( project.path )
|
||||
verify( cast(b32) os.is_dir( project.path ), "Failed to create project path for saving" )
|
||||
if ! os.is_dir( project.path.str ) {
|
||||
os.make_directory( project.path.str )
|
||||
verify( cast(b32) os.is_dir( project.path.str ), "Failed to create project path for saving" )
|
||||
}
|
||||
|
||||
os.write_entire_file( str_tmp_from_any( project.path, project.name, ".sectr_proj", sep = ""), archive.data )
|
||||
os.write_entire_file( str_tmp_from_any( project.path.str, project.name.str, ".sectr_proj", sep = ""), archive.data )
|
||||
}
|
||||
|
||||
project_load :: proc( path : string, project : ^ Project, archive : ^ ArchiveData = nil )
|
||||
|
@ -33,7 +33,7 @@ debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Co
|
||||
tint = color );
|
||||
}
|
||||
|
||||
debug_draw_text_world :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
draw_text_string :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
state := get_state(); using state
|
||||
|
||||
@ -62,6 +62,33 @@ debug_draw_text_world :: proc( content : string, pos : Vec2, size : f32, color :
|
||||
tint = color );
|
||||
}
|
||||
|
||||
draw_text_string_cached :: proc( content : StringCached, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default ) {
|
||||
state := get_state(); using state
|
||||
|
||||
if len( content.str ) == 0 {
|
||||
return
|
||||
}
|
||||
font := font
|
||||
if font.key == Font_Default.key {
|
||||
// if len(font) == 0 {
|
||||
font = default_font
|
||||
}
|
||||
pos := world_to_screen_pos(pos)
|
||||
|
||||
px_size := size
|
||||
zoom_adjust := px_size * project.workspace.cam.zoom
|
||||
|
||||
runes := content.runes
|
||||
|
||||
rl_font := to_rl_Font(font, zoom_adjust )
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
}
|
||||
|
||||
// Raylib's equivalent doesn't take a length for the string (making it a pain in the ass)
|
||||
// So this is a 1:1 copy except it takes Odin strings
|
||||
measure_text_size :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> AreaSize
|
||||
|
@ -88,7 +88,7 @@ render_mode_2d :: proc()
|
||||
|
||||
rl.BeginMode2D( project.workspace.cam )
|
||||
|
||||
debug_draw_text_world( "This is text in world space", { 0, 200 }, 16.0 )
|
||||
draw_text( "This is text in world space", { 0, 200 }, 16.0 )
|
||||
|
||||
ImguiRender:
|
||||
{
|
||||
|
@ -231,14 +231,10 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
}
|
||||
ui_set_layout( default_layout )
|
||||
|
||||
// First Demo
|
||||
Test_HoverNClick :: false
|
||||
Test_Draggable :: true
|
||||
|
||||
// test_hover_n_click()
|
||||
// test_draggable()
|
||||
|
||||
|
||||
|
||||
}
|
||||
//endregion Imgui Tick
|
||||
|
||||
|
@ -223,7 +223,9 @@ UI_TextAlign :: enum u32 {
|
||||
UI_Box :: struct {
|
||||
// Cache ID
|
||||
key : UI_Key,
|
||||
label : string,
|
||||
// label : string,
|
||||
label : StringCached,
|
||||
text : StringCached,
|
||||
|
||||
// Regenerated per frame.
|
||||
using links : DLL_NodeFull( UI_Box ), // first, last, prev, next
|
||||
@ -354,7 +356,7 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
||||
else {
|
||||
box : UI_Box
|
||||
box.key = key
|
||||
box.label = label
|
||||
box.label = str_intern( label )
|
||||
set_result, set_error = zpl_hmap_set( curr_cache, cast(u64) key, box )
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ test_draggable :: proc()
|
||||
ui := ui_context
|
||||
|
||||
draggable := ui_widget( "Draggable Box!", UI_BoxFlags { .Mouse_Clickable, .Focusable, .Click_To_Focus } )
|
||||
|
||||
if draggable.first_frame {
|
||||
debug.draggable_box_pos = draggable.style.layout.pos
|
||||
debug.draggable_box_size = draggable.style.layout.size
|
||||
|
Loading…
Reference in New Issue
Block a user