Fixed a long-standing issue with the chained hashmap (finally)
This commit is contained in:
		@@ -4,6 +4,8 @@ package VEFontCache
 | 
			
		||||
The choice was made to keep the LRU cache implementation as close to the original as possible.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import "base:runtime"
 | 
			
		||||
 | 
			
		||||
PoolListIter  :: i32
 | 
			
		||||
PoolListValue :: u64
 | 
			
		||||
 | 
			
		||||
@@ -20,9 +22,10 @@ PoolList :: struct {
 | 
			
		||||
	back      : PoolListIter,
 | 
			
		||||
	size      : u32,
 | 
			
		||||
	capacity  : u32,
 | 
			
		||||
	dbg_name  : string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pool_list_init :: proc( pool : ^PoolList, capacity : u32 )
 | 
			
		||||
pool_list_init :: proc( pool : ^PoolList, capacity : u32, dbg_name : string = "" )
 | 
			
		||||
{
 | 
			
		||||
	error : AllocatorError
 | 
			
		||||
	pool.items, error = make( Array( PoolListItem ), u64(capacity) )
 | 
			
		||||
@@ -35,6 +38,7 @@ pool_list_init :: proc( pool : ^PoolList, capacity : u32 )
 | 
			
		||||
 | 
			
		||||
	pool.capacity = capacity
 | 
			
		||||
 | 
			
		||||
	pool.dbg_name = dbg_name
 | 
			
		||||
	using pool
 | 
			
		||||
 | 
			
		||||
	for id in 0 ..< capacity {
 | 
			
		||||
@@ -72,6 +76,9 @@ pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue )
 | 
			
		||||
	items.data[ id ].prev  = -1
 | 
			
		||||
	items.data[ id ].next  = front
 | 
			
		||||
	items.data[ id ].value = value
 | 
			
		||||
	if pool.dbg_name != "" {
 | 
			
		||||
		logf("pool_list: pushed %v into id %v", value, id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if front != -1 do items.data[ front ].prev = id
 | 
			
		||||
	if back  == -1 do back = id
 | 
			
		||||
@@ -98,6 +105,9 @@ pool_list_erase :: proc( pool : ^PoolList, iter : PoolListIter )
 | 
			
		||||
 | 
			
		||||
	iter_node.prev  = -1
 | 
			
		||||
	iter_node.next  = -1
 | 
			
		||||
	// if pool.dbg_name != "" {
 | 
			
		||||
	// 	logf("pool_list: erased %v, at id %v", iter_node.value, iter)
 | 
			
		||||
	// }
 | 
			
		||||
	iter_node.value = 0
 | 
			
		||||
	append( & free_list, iter )
 | 
			
		||||
 | 
			
		||||
@@ -115,34 +125,35 @@ pool_list_peek_back :: proc ( pool : ^PoolList ) -> PoolListValue {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pool_list_pop_back :: proc( pool : ^PoolList ) -> PoolListValue {
 | 
			
		||||
	using pool
 | 
			
		||||
	if size <= 0 do return 0
 | 
			
		||||
	assert( back != -1 )
 | 
			
		||||
	if pool.size <= 0 do return 0
 | 
			
		||||
	assert( pool.back != -1 )
 | 
			
		||||
 | 
			
		||||
	value := items.data[ back ].value
 | 
			
		||||
	pool_list_erase( pool, back )
 | 
			
		||||
	value := pool.items.data[ pool.back ].value
 | 
			
		||||
	pool_list_erase( pool, pool.back )
 | 
			
		||||
	return value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRU_Link :: struct {
 | 
			
		||||
	pad_top : u64,
 | 
			
		||||
	value : i32,
 | 
			
		||||
	ptr   : PoolListIter,
 | 
			
		||||
	pad_bottom : u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRU_Cache :: struct {
 | 
			
		||||
	capacity  : u32,
 | 
			
		||||
	num       : u32,
 | 
			
		||||
	table     : HMapZPL(LRU_Link),
 | 
			
		||||
	table     : HMapChained(LRU_Link),
 | 
			
		||||
	key_queue : PoolList,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRU_init :: proc( cache : ^LRU_Cache, capacity : u32 ) {
 | 
			
		||||
LRU_init :: proc( cache : ^LRU_Cache, capacity : u32, dbg_name : string = "" ) {
 | 
			
		||||
	error : AllocatorError
 | 
			
		||||
	cache.capacity     = capacity
 | 
			
		||||
	cache.table, error = hmap_zpl_init( HMapZPL(LRU_Link), u64( hmap_closest_prime( uint(capacity))) )
 | 
			
		||||
	cache.table, error = make( HMapChained(LRU_Link), hmap_closest_prime( uint(capacity)) )
 | 
			
		||||
	assert( error == .None, "VEFontCache.LRU_init : Failed to allocate cache's table")
 | 
			
		||||
 | 
			
		||||
	pool_list_init( & cache.key_queue, capacity )
 | 
			
		||||
	pool_list_init( & cache.key_queue, capacity, dbg_name = dbg_name )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRU_free :: proc( cache : ^LRU_Cache )
 | 
			
		||||
@@ -152,7 +163,7 @@ LRU_free :: proc( cache : ^LRU_Cache )
 | 
			
		||||
 | 
			
		||||
LRU_reload :: proc( cache : ^LRU_Cache, allocator : Allocator )
 | 
			
		||||
{
 | 
			
		||||
	hmap_zpl_reload( & cache.table, allocator )
 | 
			
		||||
	hmap_chained_reload( cache.table, allocator )
 | 
			
		||||
	pool_list_reload( & cache.key_queue, allocator )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -162,9 +173,13 @@ LRU_hash_key :: #force_inline proc( key : u64 ) -> ( hash : u64 ) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRU_find :: proc( cache : ^LRU_Cache, key : u64 ) -> ^LRU_Link {
 | 
			
		||||
LRU_find :: proc( cache : ^LRU_Cache, key : u64, must_find := false ) -> ^LRU_Link {
 | 
			
		||||
	hash := LRU_hash_key( key )
 | 
			
		||||
	link := get( & cache.table, hash )
 | 
			
		||||
	link := get( cache.table, hash )
 | 
			
		||||
	// if link == nil && must_find {
 | 
			
		||||
	// 	runtime.debug_trap()
 | 
			
		||||
	// 	link = get( cache.table, hash )
 | 
			
		||||
	// }
 | 
			
		||||
	return link
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -186,8 +201,8 @@ LRU_get_next_evicted :: proc( cache : ^LRU_Cache ) -> u64
 | 
			
		||||
	return 0xFFFFFFFFFFFFFFFF
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRU_peek :: proc( cache : ^LRU_Cache, key : u64 ) -> i32 {
 | 
			
		||||
	iter := LRU_find( cache, key )
 | 
			
		||||
LRU_peek :: proc( cache : ^LRU_Cache, key : u64, must_find := false ) -> i32 {
 | 
			
		||||
	iter := LRU_find( cache, key, must_find )
 | 
			
		||||
	if iter == nil {
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
@@ -197,7 +212,7 @@ LRU_peek :: proc( cache : ^LRU_Cache, key : u64 ) -> i32 {
 | 
			
		||||
LRU_put :: proc( cache : ^LRU_Cache, key : u64,  value : i32 ) -> u64
 | 
			
		||||
{
 | 
			
		||||
	hash_key := LRU_hash_key( key )
 | 
			
		||||
	iter     := get( & cache.table, hash_key )
 | 
			
		||||
	iter     := get( cache.table, hash_key )
 | 
			
		||||
	if iter != nil {
 | 
			
		||||
		LRU_refresh( cache, key )
 | 
			
		||||
		iter.value = value
 | 
			
		||||
@@ -209,14 +224,19 @@ LRU_put :: proc( cache : ^LRU_Cache, key : u64,  value : i32 ) -> u64
 | 
			
		||||
		evict = pool_list_pop_back( & cache.key_queue )
 | 
			
		||||
 | 
			
		||||
		evict_hash := LRU_hash_key( evict )
 | 
			
		||||
		hmap_zpl_remove( & cache.table, evict_hash )
 | 
			
		||||
		// if cache.table.dbg_name != "" {
 | 
			
		||||
		// 	logf("%v: Evicted   %v with hash: %v", cache.table.dbg_name, evict, evict_hash)
 | 
			
		||||
		// }
 | 
			
		||||
		hmap_chained_remove( cache.table, evict_hash )
 | 
			
		||||
		cache.num -= 1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool_list_push_front( & cache.key_queue, key )
 | 
			
		||||
	// if cache.table.dbg_name != "" {
 | 
			
		||||
	// 	logf("%v: Pushed   %v with hash: %v", cache.table.dbg_name, key, hash_key )
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	// set( cache.table, hash_key, LRU_Link {
 | 
			
		||||
	set( & cache.table, hash_key, LRU_Link {
 | 
			
		||||
	set( cache.table, hash_key, LRU_Link {
 | 
			
		||||
		value = value,
 | 
			
		||||
		ptr   = cache.key_queue.front
 | 
			
		||||
	})
 | 
			
		||||
@@ -227,6 +247,9 @@ LRU_put :: proc( cache : ^LRU_Cache, key : u64,  value : i32 ) -> u64
 | 
			
		||||
 | 
			
		||||
LRU_refresh :: proc( cache : ^LRU_Cache, key : u64 ) {
 | 
			
		||||
	link := LRU_find( cache, key )
 | 
			
		||||
	// if cache.table.dbg_name != "" {
 | 
			
		||||
	// 	logf("%v: Refreshed %v", cache.table.dbg_name, key)
 | 
			
		||||
	// }
 | 
			
		||||
	pool_list_erase( & cache.key_queue, link.ptr )
 | 
			
		||||
	pool_list_push_front( & cache.key_queue, key )
 | 
			
		||||
	link.ptr = cache.key_queue.front
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ Changes:
 | 
			
		||||
*/
 | 
			
		||||
package VEFontCache
 | 
			
		||||
 | 
			
		||||
import "base:runtime"
 | 
			
		||||
import "core:math"
 | 
			
		||||
import "core:mem"
 | 
			
		||||
 | 
			
		||||
@@ -625,7 +626,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
 | 
			
		||||
			next_evict_codepoint := LRU_get_next_evicted( & region.state )
 | 
			
		||||
			assert( next_evict_codepoint != 0xFFFFFFFFFFFFFFFF )
 | 
			
		||||
 | 
			
		||||
			atlas_index = LRU_peek( & region.state, next_evict_codepoint )
 | 
			
		||||
			atlas_index = LRU_peek( & region.state, next_evict_codepoint, must_find = true )
 | 
			
		||||
			assert( atlas_index != -1 )
 | 
			
		||||
 | 
			
		||||
			evicted := LRU_put( & region.state, lru_code, atlas_index )
 | 
			
		||||
@@ -763,16 +764,17 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -
 | 
			
		||||
	if shape_cache_idx == -1
 | 
			
		||||
	{
 | 
			
		||||
		if shape_cache.next_cache_id < i32(state.capacity) {
 | 
			
		||||
			shape_cache_idx = shape_cache.next_cache_id
 | 
			
		||||
			LRU_put( state, hash, shape_cache_idx )
 | 
			
		||||
			shape_cache_idx            = shape_cache.next_cache_id
 | 
			
		||||
			shape_cache.next_cache_id += 1
 | 
			
		||||
			evicted := LRU_put( state, hash, shape_cache_idx )
 | 
			
		||||
			assert( evicted == hash )
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			next_evict_idx := LRU_get_next_evicted( state )
 | 
			
		||||
			assert( next_evict_idx != 0xFFFFFFFFFFFFFFFF )
 | 
			
		||||
 | 
			
		||||
			shape_cache_idx = LRU_peek( state, next_evict_idx )
 | 
			
		||||
			shape_cache_idx = LRU_peek( state, next_evict_idx, must_find = true )
 | 
			
		||||
			assert( shape_cache_idx != - 1 )
 | 
			
		||||
 | 
			
		||||
			LRU_put( state, hash, shape_cache_idx )
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,8 @@ import "core:mem"
 | 
			
		||||
 | 
			
		||||
Kilobyte :: mem.Kilobyte
 | 
			
		||||
 | 
			
		||||
slice_ptr :: mem.slice_ptr
 | 
			
		||||
 | 
			
		||||
Arena :: mem.Arena
 | 
			
		||||
 | 
			
		||||
arena_allocator :: mem.arena_allocator
 | 
			
		||||
@@ -46,6 +48,7 @@ hmap_chained_destroy :: grime.hmap_chained_destroy
 | 
			
		||||
hmap_chained_init    :: grime.hmap_chained_init
 | 
			
		||||
hmap_chained_get     :: grime.hmap_chained_get
 | 
			
		||||
hmap_chained_remove  :: grime.hmap_chained_remove
 | 
			
		||||
hmap_chained_reload  :: grime.hmap_chained_reload
 | 
			
		||||
hmap_chained_set     :: grime.hmap_chained_set
 | 
			
		||||
hmap_closest_prime   :: grime.hmap_closest_prime
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,8 @@ and direct pointers are kept across the codebase instead of a key to the slot.
 | 
			
		||||
*/
 | 
			
		||||
package grime
 | 
			
		||||
 | 
			
		||||
import "core:mem"
 | 
			
		||||
import "base:runtime"
 | 
			
		||||
import "core:mem"
 | 
			
		||||
 | 
			
		||||
HTable_Minimum_Capacity :: 4 * Kilobyte
 | 
			
		||||
 | 
			
		||||
@@ -26,6 +26,7 @@ HMapChainedSlot :: struct( $Type : typeid ) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HMapChainedHeader :: struct( $ Type : typeid ) {
 | 
			
		||||
	tracker  : MemoryTracker,
 | 
			
		||||
	pool     : Pool,
 | 
			
		||||
	lookup   : [] ^HMapChainedSlot(Type),
 | 
			
		||||
	dbg_name : string,
 | 
			
		||||
@@ -62,7 +63,7 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_
 | 
			
		||||
) -> (table : HMapChained(Type), error : AllocatorError)
 | 
			
		||||
{
 | 
			
		||||
	header_size := size_of(HMapChainedHeader(Type))
 | 
			
		||||
	size  := header_size + int(lookup_capacity) * size_of( ^HMapChainedSlot(Type)) + size_of(int)
 | 
			
		||||
	size  := header_size + int(lookup_capacity) * size_of( ^HMapChainedSlot(Type))
 | 
			
		||||
 | 
			
		||||
	raw_mem : rawptr
 | 
			
		||||
	raw_mem, error = alloc( size, allocator = allocator )
 | 
			
		||||
@@ -79,9 +80,14 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_
 | 
			
		||||
		dbg_name            = str_intern(str_fmt("%v: pool", dbg_name)).str,
 | 
			
		||||
		enable_mem_tracking = enable_mem_tracking,
 | 
			
		||||
	)
 | 
			
		||||
	data          := transmute([^] ^HMapChainedSlot(Type)) (transmute( [^]HMapChainedHeader(Type)) table.header)[1:]
 | 
			
		||||
	data          := transmute(^^HMapChainedSlot(Type)) memory_after_header(table.header)
 | 
			
		||||
	table.lookup   = slice_ptr( data, int(lookup_capacity) )
 | 
			
		||||
	table.dbg_name = dbg_name
 | 
			
		||||
 | 
			
		||||
	if Track_Memory && enable_mem_tracking {
 | 
			
		||||
		memtracker_init( & table.tracker, allocator, Kilobyte * 16, dbg_name )
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -115,9 +121,6 @@ hmap_chained_get :: proc( using self : HMapChained($Type), key : u64) -> ^Type
 | 
			
		||||
{
 | 
			
		||||
	// profile(#procedure)
 | 
			
		||||
	hash_index   := hmap_chained_lookup_id(self, key)
 | 
			
		||||
	// if hash_index == 565 {
 | 
			
		||||
	// 	runtime.debug_trap()
 | 
			
		||||
	// }
 | 
			
		||||
	surface_slot := lookup[hash_index]
 | 
			
		||||
 | 
			
		||||
	if surface_slot == nil {
 | 
			
		||||
@@ -128,9 +131,13 @@ hmap_chained_get :: proc( using self : HMapChained($Type), key : u64) -> ^Type
 | 
			
		||||
		return & surface_slot.value
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for slot := surface_slot.next; slot != nil; slot = slot.next {
 | 
			
		||||
	for slot := surface_slot.next; slot != nil; slot = slot.next
 | 
			
		||||
	{
 | 
			
		||||
		if slot.occupied && slot.key == key {
 | 
			
		||||
			return & surface_slot.value
 | 
			
		||||
			if self.dbg_name != "" && self.tracker.entries.header != nil {
 | 
			
		||||
				logf( "%v: Retrieved %v in lookup[%v] which shows key as %v", self.dbg_name, key, hash_index, slot.key )
 | 
			
		||||
			}
 | 
			
		||||
			return & slot.value
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -139,14 +146,15 @@ hmap_chained_get :: proc( using self : HMapChained($Type), key : u64) -> ^Type
 | 
			
		||||
 | 
			
		||||
hmap_chained_reload :: proc( self : HMapChained($Type), allocator : Allocator )
 | 
			
		||||
{
 | 
			
		||||
	pool_reload(self.pool, allocator)
 | 
			
		||||
	// pool_reload(self.pool, allocator)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if an slot was actually found and marked as vacant
 | 
			
		||||
// Entries already found to be vacant will not return true
 | 
			
		||||
hmap_chained_remove :: proc( self : HMapChained($Type), key : u64 ) -> b32
 | 
			
		||||
{
 | 
			
		||||
	surface_slot := self.lookup[hmap_chained_lookup_id(self, key)]
 | 
			
		||||
	hash_index   := hmap_chained_lookup_id(self, key)
 | 
			
		||||
	surface_slot := self.lookup[hash_index]
 | 
			
		||||
 | 
			
		||||
	if surface_slot == nil {
 | 
			
		||||
		return false
 | 
			
		||||
@@ -154,13 +162,24 @@ hmap_chained_remove :: proc( self : HMapChained($Type), key : u64 ) -> b32
 | 
			
		||||
 | 
			
		||||
	if surface_slot.occupied && surface_slot.key == key {
 | 
			
		||||
		surface_slot.occupied = false
 | 
			
		||||
		surface_slot.value    = {}
 | 
			
		||||
		surface_slot.key      = {}
 | 
			
		||||
		if self.dbg_name != "" && self.tracker.entries.header != nil {
 | 
			
		||||
			logf( "%v: Removed %v in lookup[%v]", self.dbg_name, key, hash_index )
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for slot := surface_slot.next; slot != nil; slot = slot.next 
 | 
			
		||||
	nest_id : i32 = 1
 | 
			
		||||
	for slot := surface_slot.next; slot != nil; slot = slot.next
 | 
			
		||||
	{
 | 
			
		||||
		if slot.occupied && slot.key == key {
 | 
			
		||||
			slot.occupied = false
 | 
			
		||||
			slot.value    = {}
 | 
			
		||||
			slot.key      = {}
 | 
			
		||||
			if self.dbg_name != "" && self.tracker.entries.header != nil {
 | 
			
		||||
				logf( "%v: Removed %v in lookup[%v] nest_id: %v", self.dbg_name, key, hash_index, nest_id )
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -176,62 +195,69 @@ hmap_chained_set :: proc( self : HMapChained($Type), key : u64, value : Type ) -
 | 
			
		||||
	using self
 | 
			
		||||
	hash_index   := hmap_chained_lookup_id(self, key)
 | 
			
		||||
	surface_slot := lookup[hash_index]
 | 
			
		||||
	set_slot :: #force_inline proc( using self : HMapChained(Type),
 | 
			
		||||
		slot  : ^HMapChainedSlot(Type),
 | 
			
		||||
		key   : u64,
 | 
			
		||||
		value : Type
 | 
			
		||||
	) -> (^ Type, AllocatorError )
 | 
			
		||||
	{
 | 
			
		||||
		error := AllocatorError.None
 | 
			
		||||
		if slot.next == nil {
 | 
			
		||||
			block        : []byte
 | 
			
		||||
			block, error = pool_grab(pool, false)
 | 
			
		||||
			next        := transmute( ^HMapChainedSlot(Type)) & block[0]
 | 
			
		||||
			next^ = {}
 | 
			
		||||
			slot.next    = next
 | 
			
		||||
			next.prev    = slot
 | 
			
		||||
		}
 | 
			
		||||
		slot.key      = key
 | 
			
		||||
		slot.value    = value
 | 
			
		||||
		slot.occupied = true
 | 
			
		||||
		return & slot.value, error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if surface_slot == nil {
 | 
			
		||||
		block, error         := pool_grab(pool, false)
 | 
			
		||||
		surface_slot         := transmute( ^HMapChainedSlot(Type)) & block[0]
 | 
			
		||||
	slot_size := size_of(HMapChainedSlot(Type))
 | 
			
		||||
	if surface_slot == nil
 | 
			
		||||
	{
 | 
			
		||||
		block, error := pool_grab(pool, false)
 | 
			
		||||
		surface_slot := transmute( ^HMapChainedSlot(Type)) raw_data(block)
 | 
			
		||||
		surface_slot^ = {}
 | 
			
		||||
 | 
			
		||||
		surface_slot.key      = key
 | 
			
		||||
		surface_slot.value    = value
 | 
			
		||||
		surface_slot.occupied = true
 | 
			
		||||
		if error != AllocatorError.None {
 | 
			
		||||
			ensure(error != AllocatorError.None, "Allocation failure for chained slot in hash table")
 | 
			
		||||
			return nil, error
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lookup[hash_index] = surface_slot
 | 
			
		||||
 | 
			
		||||
		block, error = pool_grab(pool, false)
 | 
			
		||||
		next             := transmute( ^HMapChainedSlot(Type)) & block[0]
 | 
			
		||||
		next^ = {}
 | 
			
		||||
		surface_slot.next = next
 | 
			
		||||
		next.prev         = surface_slot
 | 
			
		||||
		if Track_Memory && tracker.entries.header != nil {
 | 
			
		||||
			memtracker_register_auto_name_slice( & self.tracker, block)
 | 
			
		||||
		}
 | 
			
		||||
		return & surface_slot.value, error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ! surface_slot.occupied
 | 
			
		||||
	{
 | 
			
		||||
		result, error := set_slot( self, surface_slot, key, value)
 | 
			
		||||
		return result, error
 | 
			
		||||
		surface_slot.key      = key
 | 
			
		||||
		surface_slot.value    = value
 | 
			
		||||
		surface_slot.occupied = true
 | 
			
		||||
		if dbg_name != "" && tracker.entries.header != nil {
 | 
			
		||||
			logf( "%v: Set     %v in lookup[%v]", self.dbg_name, key, hash_index )
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return & surface_slot.value, .None
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	slot : ^HMapChainedSlot(Type) = surface_slot.next
 | 
			
		||||
	for ; slot != nil; slot = slot.next
 | 
			
		||||
	slot : ^HMapChainedSlot(Type) = surface_slot
 | 
			
		||||
	nest_id : i32 = 1
 | 
			
		||||
	for ;; slot = slot.next
 | 
			
		||||
	{
 | 
			
		||||
		if !slot.occupied
 | 
			
		||||
		error : AllocatorError
 | 
			
		||||
		if slot.next == nil
 | 
			
		||||
		{
 | 
			
		||||
			result, error := set_slot( self, slot, key, value)
 | 
			
		||||
			return result, error
 | 
			
		||||
			block        : []byte
 | 
			
		||||
			block, error = pool_grab(pool, false)
 | 
			
		||||
			next        := transmute( ^HMapChainedSlot(Type)) raw_data(block)
 | 
			
		||||
 | 
			
		||||
			slot.next      = next
 | 
			
		||||
			slot.next^     = {}
 | 
			
		||||
			slot.next.prev = slot
 | 
			
		||||
			if Track_Memory && tracker.entries.header != nil {
 | 
			
		||||
				memtracker_register_auto_name_slice( & self.tracker, block)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ! slot.next.occupied
 | 
			
		||||
		{
 | 
			
		||||
			slot.next.key      = key
 | 
			
		||||
			slot.next.value    = value
 | 
			
		||||
			slot.next.occupied = true
 | 
			
		||||
			if dbg_name != "" && tracker.entries.header != nil {
 | 
			
		||||
				logf( "%v: Set     %v in lookup[%v] nest_id: %v", self.dbg_name, key, hash_index, nest_id )
 | 
			
		||||
			}
 | 
			
		||||
			return & slot.next.value, .None
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		nest_id += 1
 | 
			
		||||
	}
 | 
			
		||||
	ensure(false, "Somehow got to a null slot that wasn't preemptively allocated from a previus set")
 | 
			
		||||
	return nil, AllocatorError.None
 | 
			
		||||
 
 | 
			
		||||
@@ -276,7 +276,7 @@ varena_allocator_proc :: proc(
 | 
			
		||||
				data = new_region
 | 
			
		||||
				// log( str_fmt_tmp("varena resize (new): old: %p %v new: %p %v", old_memory, old_size, (& data[0]), size))
 | 
			
		||||
 | 
			
		||||
				when Track_Memory {
 | 
			
		||||
				if Track_Memory && arena.tracker.entries.header != nil {
 | 
			
		||||
					memtracker_register_auto_name( & arena.tracker, & data[0], & data[len(data) - 1] )
 | 
			
		||||
				}
 | 
			
		||||
				return
 | 
			
		||||
 
 | 
			
		||||
@@ -128,9 +128,9 @@ setup_memory :: proc( profiler : ^SpallProfiler ) -> ClientMemory
 | 
			
		||||
			sectr.Memory_Reserve_Persistent,
 | 
			
		||||
			sectr.Memory_Commit_Initial_Persistent,
 | 
			
		||||
			growth_policy    = nil,
 | 
			
		||||
			allow_any_resize = false,
 | 
			
		||||
			allow_any_resize = true,
 | 
			
		||||
			dbg_name         = "persistent",
 | 
			
		||||
			enable_mem_tracking = true )
 | 
			
		||||
			enable_mem_tracking = false )
 | 
			
		||||
		verify( alloc_error == .None, "Failed to allocate persistent virtual arena for the sectr module")
 | 
			
		||||
 | 
			
		||||
		frame, alloc_error = varena_init(
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
 | 
			
		||||
		// push( policy_ptr, SlabSizeClass { 512 * Megabyte, 512 * Megabyte, alignment })
 | 
			
		||||
 | 
			
		||||
		alloc_error : AllocatorError
 | 
			
		||||
		persistent_slab, alloc_error = slab_init( policy_ptr, allocator = persistent_allocator(), dbg_name = Persistent_Slab_DBG_Name, enable_mem_tracking = true )
 | 
			
		||||
		persistent_slab, alloc_error = slab_init( policy_ptr, allocator = persistent_allocator(), dbg_name = Persistent_Slab_DBG_Name, enable_mem_tracking = false )
 | 
			
		||||
		verify( alloc_error == .None, "Failed to allocate the persistent slab" )
 | 
			
		||||
 | 
			
		||||
		transient_slab, alloc_error = slab_init( & default_slab_policy, allocator = transient_allocator(), dbg_name = Transient_Slab_DBG_Name )
 | 
			
		||||
@@ -254,23 +254,23 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
 | 
			
		||||
	if true
 | 
			
		||||
	{
 | 
			
		||||
		font_provider_startup()
 | 
			
		||||
		// path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" })
 | 
			
		||||
		// font_rec_mono_semicasual_reg  = font_load( path_rec_mono_semicasual_reg, 24.0, "RecMonoSemiCasual_Regular" )
 | 
			
		||||
		path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" })
 | 
			
		||||
		font_rec_mono_semicasual_reg  = font_load( path_rec_mono_semicasual_reg, 24.0, "RecMonoSemiCasual_Regular" )
 | 
			
		||||
 | 
			
		||||
		// path_squidgy_slimes := strings.concatenate( { Path_Assets, "Squidgy Slimes.ttf" } )
 | 
			
		||||
		// font_squidgy_slimes = font_load( path_squidgy_slimes, 24.0, "Squidgy_Slime" )
 | 
			
		||||
		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" } )
 | 
			
		||||
		font_firacode  = font_load( path_firacode, 24.0, "FiraCode" )
 | 
			
		||||
 | 
			
		||||
		// path_open_sans := strings.concatenate( { Path_Assets, "OpenSans-Regular.ttf" } )
 | 
			
		||||
		// font_open_sans  = font_load( path_open_sans, 24.0, "OpenSans" )
 | 
			
		||||
		path_open_sans := strings.concatenate( { Path_Assets, "OpenSans-Regular.ttf" } )
 | 
			
		||||
		font_open_sans  = font_load( path_open_sans, 24.0, "OpenSans" )
 | 
			
		||||
 | 
			
		||||
		// path_noto_sans := strings.concatenate( { Path_Assets, "NotoSans-Regular.ttf" } )
 | 
			
		||||
		// font_noto_sans  = font_load( path_noto_sans, 24.0, "NotoSans" )
 | 
			
		||||
		path_noto_sans := strings.concatenate( { Path_Assets, "NotoSans-Regular.ttf" } )
 | 
			
		||||
		font_noto_sans  = font_load( path_noto_sans, 24.0, "NotoSans" )
 | 
			
		||||
 | 
			
		||||
		// path_arial_unicode_ms := strings.concatenate( { Path_Assets, "Arial Unicode MS.ttf" } )
 | 
			
		||||
		// font_arial_unicode_ms  = font_load( path_arial_unicode_ms, 24.0, "Arial_Unicode_MS" )
 | 
			
		||||
		path_arial_unicode_ms := strings.concatenate( { Path_Assets, "Arial Unicode MS.ttf" } )
 | 
			
		||||
		font_arial_unicode_ms  = font_load( path_arial_unicode_ms, 24.0, "Arial_Unicode_MS" )
 | 
			
		||||
 | 
			
		||||
		default_font = font_firacode
 | 
			
		||||
		log( "Default font loaded" )
 | 
			
		||||
 
 | 
			
		||||
@@ -125,7 +125,7 @@ render_mode_screenspace :: proc()
 | 
			
		||||
	debug.debug_text_vis = true
 | 
			
		||||
	if debug.debug_text_vis
 | 
			
		||||
	{
 | 
			
		||||
		fps_msg       := str_fmt( "FPS: %0.2f", fps_avg)
 | 
			
		||||
		fps_msg       := str_fmt( "FPS: %d", frame)
 | 
			
		||||
		fps_msg_width := measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x
 | 
			
		||||
		fps_msg_pos   := screen_get_corners().top_right - { fps_msg_width, 0 } - { 5, 5 }
 | 
			
		||||
		debug_draw_text( fps_msg, fps_msg_pos, 38.0, color = Color_Red )
 | 
			
		||||
@@ -133,7 +133,7 @@ render_mode_screenspace :: proc()
 | 
			
		||||
		// debug_text( "Screen Width : %v", rl.GetScreenWidth () )
 | 
			
		||||
		// debug_text( "Screen Height: %v", rl.GetScreenHeight() )
 | 
			
		||||
		// debug_text( "frametime_target_ms       : %f ms", frametime_target_ms )
 | 
			
		||||
		debug_text( "frametime                 : %f ms", frametime_delta_ms )
 | 
			
		||||
		debug_text( "frametime                 : %d ms", frame )
 | 
			
		||||
		// debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms )
 | 
			
		||||
		if replay.mode == ReplayMode.Record {
 | 
			
		||||
			debug_text( "Recording Input")
 | 
			
		||||
 
 | 
			
		||||
@@ -70,10 +70,10 @@ font_provider_startup :: proc()
 | 
			
		||||
	provider_data := & state.font_provider_data; using provider_data
 | 
			
		||||
 | 
			
		||||
	error : AllocatorError
 | 
			
		||||
	font_cache, error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator() /*dbg_name = "font_cache"*/ )
 | 
			
		||||
	font_cache, error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator(), dbg_name = "font_cache" )
 | 
			
		||||
	verify( error == AllocatorError.None, "Failed to allocate font_cache" )
 | 
			
		||||
 | 
			
		||||
	ve.init( & provider_data.ve_font_cache, .STB_TrueType, allocator = persistent_slab_allocator() )
 | 
			
		||||
	ve.init( & provider_data.ve_font_cache, .STB_TrueType, allocator = persistent_allocator() )
 | 
			
		||||
	log("VEFontCached initialized")
 | 
			
		||||
 | 
			
		||||
	ve.configure_snap( & provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) )
 | 
			
		||||
@@ -552,7 +552,7 @@ font_load :: proc(path_file : string,
 | 
			
		||||
 | 
			
		||||
	for font_size : i32 = Font_Size_Interval; font_size <= Font_Largest_Px_Size; font_size += Font_Size_Interval
 | 
			
		||||
	{
 | 
			
		||||
		logf("Loading at size %v", font_size)
 | 
			
		||||
		// logf("Loading at size %v", font_size)
 | 
			
		||||
		id    := (font_size / Font_Size_Interval) + (font_size % Font_Size_Interval)
 | 
			
		||||
		ve_id := & def.size_table[id - 1]
 | 
			
		||||
		ve_id^ = ve.load_font( & provider_data.ve_font_cache, desired_id, font_data, 14.0 )
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user