Unlimited font face allocation
This commit is contained in:
parent
ca8d9e2729
commit
cee8ce18cb
|
@ -220,7 +220,7 @@ allocate_markers_state(General_Memory *general, Editing_File *file, u32 new_arra
|
||||||
u32 real_max = (memory_size - sizeof_marker_array)/sizeof(Marker);
|
u32 real_max = (memory_size - sizeof_marker_array)/sizeof(Marker);
|
||||||
Marker_Array *array = (Marker_Array*)general_memory_allocate(general, memory_size);
|
Marker_Array *array = (Marker_Array*)general_memory_allocate(general, memory_size);
|
||||||
|
|
||||||
dll_back_insert(&file->markers.sentinel, array);
|
dll_insert_back(&file->markers.sentinel, array);
|
||||||
array->buffer_id = file->id;
|
array->buffer_id = file->id;
|
||||||
array->count = 0;
|
array->count = 0;
|
||||||
array->sim_max = new_array_max;
|
array->sim_max = new_array_max;
|
||||||
|
|
|
@ -112,8 +112,8 @@ typedef Sys_Font_Load_New_Font_Sig(Font_Load_New_Font_Function, stub);
|
||||||
#define Sys_Font_Get_Count_Sig(n) i32 (n)(void)
|
#define Sys_Font_Get_Count_Sig(n) i32 (n)(void)
|
||||||
typedef Sys_Font_Get_Count_Sig(Font_Get_Count_Function);
|
typedef Sys_Font_Get_Count_Sig(Font_Get_Count_Function);
|
||||||
|
|
||||||
#define Sys_Font_Get_Name_By_ID_Sig(n, out, cap) i32 (n)(Font_ID font_id, char *out, u32 cap)
|
#define Sys_Font_Get_Name_By_ID_Sig(n, font_id, out, cap) i32 (n)(Font_ID font_id, char *out, u32 cap)
|
||||||
typedef Sys_Font_Get_Name_By_ID_Sig(Font_Get_Name_By_ID_Function, out, cap);
|
typedef Sys_Font_Get_Name_By_ID_Sig(Font_Get_Name_By_ID_Function, font_id, out, cap);
|
||||||
|
|
||||||
#define Sys_Font_Get_Pointers_By_ID_Sig(n,font_id) Font_Pointers (n)(Font_ID font_id)
|
#define Sys_Font_Get_Pointers_By_ID_Sig(n,font_id) Font_Pointers (n)(Font_ID font_id)
|
||||||
typedef Sys_Font_Get_Pointers_By_ID_Sig(Font_Get_Pointers_By_ID_Function, font_id);
|
typedef Sys_Font_Get_Pointers_By_ID_Sig(Font_Get_Pointers_By_ID_Function, font_id);
|
||||||
|
|
|
@ -350,6 +350,23 @@ font_load(System_Functions *system, Font_Settings *settings, Font_Metrics *metri
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
|
internal
|
||||||
|
Sys_Font_Allocate_Sig(system_font_allocate, size){
|
||||||
|
umem *size_ptr = 0;
|
||||||
|
void *result = system_memory_allocate(size + sizeof(*size_ptr));
|
||||||
|
size_ptr = (umem*)result;
|
||||||
|
*size_ptr = size + 4;
|
||||||
|
return(size_ptr + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal
|
||||||
|
Sys_Font_Free_Sig(system_font_free, ptr){
|
||||||
|
if (ptr != 0){
|
||||||
|
umem *size_ptr = ((umem*)ptr) - 1;
|
||||||
|
system_memory_free(size_ptr, *size_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Font_Get_Loadable_Count_Sig(system_font_get_loadable_count){
|
Sys_Font_Get_Loadable_Count_Sig(system_font_get_loadable_count){
|
||||||
return(fontvars.loadable_count);
|
return(fontvars.loadable_count);
|
||||||
|
@ -367,23 +384,119 @@ Sys_Font_Get_Loadable_Sig(system_font_get_loadable, i, out){
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Font_Load_New_Font_Sig(system_font_load_new_font, stub){
|
Sys_Font_Load_New_Font_Sig(system_font_load_new_font, stub){
|
||||||
Font_ID new_id = 0;
|
i32 slot_max = fontvars.max_slot_count;
|
||||||
|
Font_Slot_Page *page_with_slot = 0;
|
||||||
|
|
||||||
i32 font_count_max = ArrayCount(fontvars.slots);
|
Assert(fontvars.used_slot_count <= slot_max);
|
||||||
if (fontvars.count < font_count_max){
|
if (fontvars.used_slot_count == slot_max){
|
||||||
i32 index = fontvars.count;
|
i32 memsize = l_round_up_i32(SLOT_PAGE_SIZE, KB(4));
|
||||||
Font_Slot *slot = &fontvars.slots[index];
|
i32 page_count = memsize/SLOT_PAGE_SIZE;
|
||||||
Font_Settings *settings = &slot->settings;
|
void *ptr = system_font_allocate(memsize);
|
||||||
Font_Metrics *metrics = &slot->metrics;
|
memset(ptr, 0, memsize);
|
||||||
Font_Page_Storage *pages = &slot->pages;
|
|
||||||
|
|
||||||
Assert(!slot->is_active);
|
page_with_slot = (Font_Slot_Page*)ptr;
|
||||||
|
|
||||||
|
for (i32 i = 0; i < page_count; ++i){
|
||||||
|
i32 page_slot_count = SLOT_PER_PAGE;
|
||||||
|
|
||||||
|
Font_Slot_Page *page = (Font_Slot_Page*)ptr;
|
||||||
|
page->is_active = (u64*)(page + 1);
|
||||||
|
page->settings = (Font_Settings*)(page->is_active + (page_slot_count + 63)/64);
|
||||||
|
page->metrics = (Font_Metrics*)(page->settings + page_slot_count);
|
||||||
|
page->pages = (Font_Page_Storage*)(page->metrics + page_slot_count);
|
||||||
|
ptr = page->pages + page_slot_count;
|
||||||
|
|
||||||
|
page->used_count = 0;
|
||||||
|
page->fill_count = 0;
|
||||||
|
page->max = page_slot_count;
|
||||||
|
|
||||||
|
dll_insert_back(&fontvars.slot_pages_sentinel, page);
|
||||||
|
if (page->prev == &fontvars.slot_pages_sentinel){
|
||||||
|
page->first_id = 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
page->first_id = page->prev->first_id + page->prev->max;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(allen): Some of the last 64 bits of the is_active array may not line up with actual slots.
|
||||||
|
// Set such bits to 1 to simulate the "slot" being filled for allocation purposes.
|
||||||
|
// TODO(allen): This could be O(log n) instead of O(n) if I end up making bit manipulation helpers someday.
|
||||||
|
u64 last_mask_fill = 0;
|
||||||
|
if (page_slot_count%64 != 0){
|
||||||
|
last_mask_fill = (1LLU << 63);
|
||||||
|
for (i32 spread_step = (page_slot_count%64) - 1;
|
||||||
|
spread_step > 0;
|
||||||
|
--spread_step){
|
||||||
|
last_mask_fill |= (last_mask_fill >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 is_active_max = (page_with_slot->max + 63)/64;
|
||||||
|
page->is_active[is_active_max - 1] = last_mask_fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
fontvars.max_slot_count += page_count*SLOT_PER_PAGE;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for (Font_Slot_Page *page = fontvars.slot_pages_sentinel.next;
|
||||||
|
page != &fontvars.slot_pages_sentinel;
|
||||||
|
page = page->next){
|
||||||
|
if (page->used_count < page->max){
|
||||||
|
page_with_slot = page;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page_with_slot == 0){
|
||||||
|
LOG("Could not get a font slot while loading a font\n");
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert(page_with_slot->used_count < page_with_slot->max);
|
||||||
|
|
||||||
|
// Get a fillable index
|
||||||
|
i32 index = -1;
|
||||||
|
if (page_with_slot->fill_count < page_with_slot->max){
|
||||||
|
index = page_with_slot->fill_count;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
i32 is_active_max = (page_with_slot->max + 63)/64;
|
||||||
|
u64 *is_active_ptr = page_with_slot->is_active;
|
||||||
|
for (i32 i = 0; i < is_active_max; ++i){
|
||||||
|
u64 is_active_v = is_active_ptr[i];
|
||||||
|
if (is_active_v != (~0)){
|
||||||
|
i32 j_stop = 64;
|
||||||
|
if (i + 1 == is_active_max){
|
||||||
|
j_stop = SLOT_PER_PAGE%64;
|
||||||
|
}
|
||||||
|
for (i32 j = 0; j < j_stop; ++j){
|
||||||
|
if ((is_active_v & (1LLU << j)) == 0){
|
||||||
|
index = i*64 + j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the slot pointers.
|
||||||
|
Assert(index != -1);
|
||||||
|
|
||||||
|
u64 *is_active_flags = &page_with_slot->is_active[index/64];
|
||||||
|
u64 is_active_mask = (1LLU << (index % 64));
|
||||||
|
Font_Settings *settings = &page_with_slot->settings[index];
|
||||||
|
Font_Metrics *metrics = &page_with_slot->metrics[index];
|
||||||
|
Font_Page_Storage *pages = &page_with_slot->pages[index];
|
||||||
|
Font_ID new_id = page_with_slot->first_id + index;
|
||||||
|
|
||||||
|
Assert(((*is_active_flags) & is_active_mask) == 0);
|
||||||
|
|
||||||
char *filename = stub->name;
|
char *filename = stub->name;
|
||||||
i32 filename_len = 0;
|
i32 filename_len = 0;
|
||||||
for (;filename[filename_len];++filename_len);
|
for (;filename[filename_len];++filename_len);
|
||||||
|
|
||||||
|
|
||||||
// Initialize Font Parameters
|
// Initialize Font Parameters
|
||||||
Assert(filename_len <= sizeof(settings->stub.name) - 1);
|
Assert(filename_len <= sizeof(settings->stub.name) - 1);
|
||||||
memset(settings, 0, sizeof(*settings));
|
memset(settings, 0, sizeof(*settings));
|
||||||
|
@ -395,48 +508,78 @@ Sys_Font_Load_New_Font_Sig(system_font_load_new_font, stub){
|
||||||
memset(pages, 0, sizeof(*pages));
|
memset(pages, 0, sizeof(*pages));
|
||||||
b32 success = font_load(&sysfunc, settings, metrics, pages);
|
b32 success = font_load(&sysfunc, settings, metrics, pages);
|
||||||
if (success){
|
if (success){
|
||||||
slot->is_active = true;
|
*is_active_flags |= is_active_mask;
|
||||||
new_id = (Font_ID)(index + 1);
|
++fontvars.used_slot_count;
|
||||||
++fontvars.count;
|
++page_with_slot->used_count;
|
||||||
|
if (index >= page_with_slot->fill_count){
|
||||||
|
page_with_slot->fill_count = index + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
new_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return(new_id);
|
return(new_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Font_Get_Count_Sig(system_font_get_count){
|
Sys_Font_Get_Count_Sig(system_font_get_count){
|
||||||
return(fontvars.count);
|
return(fontvars.used_slot_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Font_Slot_Page_And_Index
|
||||||
|
system_font_get_active_location(Font_ID font_id){
|
||||||
|
Font_Slot_Page_And_Index result = {0};
|
||||||
|
|
||||||
|
for (Font_Slot_Page *page = fontvars.slot_pages_sentinel.next;
|
||||||
|
page != &fontvars.slot_pages_sentinel;
|
||||||
|
page = page->next){
|
||||||
|
if (page->first_id <= font_id && font_id < page->first_id + SLOT_PER_PAGE){
|
||||||
|
i32 index = (i32)(font_id - page->first_id);
|
||||||
|
u64 is_active_v = page->is_active[index/64];
|
||||||
|
if ((is_active_v & (1LLU << (index%64))) != 0){
|
||||||
|
result.page = page;
|
||||||
|
result.index = index;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Font_Get_Name_By_ID_Sig(system_font_get_name_by_id, str_out, capacity){
|
Sys_Font_Get_Name_By_ID_Sig(system_font_get_name_by_id, font_id, str_out, capacity){
|
||||||
i32 length = 0;
|
i32 length = 0;
|
||||||
if (0 < font_id && font_id <= (u32)fontvars.count){
|
if (font_id == 0){
|
||||||
u32 index = font_id - 1;
|
return(length);
|
||||||
Font_Slot *slot = &fontvars.slots[index];
|
}
|
||||||
if (slot->is_active){
|
|
||||||
Font_Metrics *metrics = &slot->metrics;
|
Font_Slot_Page_And_Index page_and_index = system_font_get_active_location(font_id);
|
||||||
|
if (page_and_index.page != 0){
|
||||||
|
Font_Metrics *metrics = &page_and_index.page->metrics[page_and_index.index];
|
||||||
length = metrics->name_len;
|
length = metrics->name_len;
|
||||||
copy_partial_cs(str_out, capacity, make_string(metrics->name, length));
|
copy_partial_cs(str_out, capacity, make_string(metrics->name, length));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return(length);
|
return(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Font_Get_Pointers_By_ID_Sig(system_font_get_pointers_by_id, font_id){
|
Sys_Font_Get_Pointers_By_ID_Sig(system_font_get_pointers_by_id, font_id){
|
||||||
Font_Pointers font = {0};
|
Font_Pointers font = {0};
|
||||||
if (0 < font_id && font_id <= (u32)fontvars.count){
|
if (font_id == 0){
|
||||||
u32 index = font_id - 1;
|
return(font);
|
||||||
Font_Slot *slot = &fontvars.slots[index];
|
}
|
||||||
if (slot->is_active){
|
|
||||||
|
Font_Slot_Page_And_Index page_and_index = system_font_get_active_location(font_id);
|
||||||
|
if (page_and_index.page != 0){
|
||||||
font.valid = true;
|
font.valid = true;
|
||||||
font.settings = &slot->settings;
|
font.settings = &page_and_index.page->settings[page_and_index.index];
|
||||||
font.metrics = &slot->metrics;
|
font.metrics = &page_and_index.page->metrics[page_and_index.index];
|
||||||
font.pages = &slot->pages;
|
font.pages = &page_and_index.page->pages[page_and_index.index];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(font);
|
return(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,23 +589,6 @@ Sys_Font_Load_Page_Sig(system_font_load_page, settings, metrics, page, page_numb
|
||||||
font_load_page_layout(settings, metrics, page, page_number);
|
font_load_page_layout(settings, metrics, page, page_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
|
||||||
Sys_Font_Allocate_Sig(system_font_allocate, size){
|
|
||||||
umem *size_ptr = 0;
|
|
||||||
void *result = system_memory_allocate(size + sizeof(*size_ptr));
|
|
||||||
size_ptr = (umem*)result;
|
|
||||||
*size_ptr = size + 4;
|
|
||||||
return(size_ptr + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal
|
|
||||||
Sys_Font_Free_Sig(system_font_free, ptr){
|
|
||||||
if (ptr != 0){
|
|
||||||
umem *size_ptr = ((umem*)ptr) - 1;
|
|
||||||
system_memory_free(size_ptr, *size_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal Font_Setup_List
|
internal Font_Setup_List
|
||||||
|
@ -524,6 +650,9 @@ system_font_init(Font_Functions *font_links, u32 pt_size, b32 use_hinting, Font_
|
||||||
font_links->allocate = system_font_allocate;
|
font_links->allocate = system_font_allocate;
|
||||||
font_links->free = system_font_free;
|
font_links->free = system_font_free;
|
||||||
|
|
||||||
|
// Initialize fontvars
|
||||||
|
memset(&fontvars, 0, sizeof(fontvars));
|
||||||
|
dll_init_sentinel(&fontvars.slot_pages_sentinel);
|
||||||
fontvars.pt_size = pt_size;
|
fontvars.pt_size = pt_size;
|
||||||
fontvars.use_hinting = use_hinting;
|
fontvars.use_hinting = use_hinting;
|
||||||
|
|
||||||
|
@ -568,44 +697,9 @@ system_font_init(Font_Functions *font_links, u32 pt_size, b32 use_hinting, Font_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filling initial fonts
|
// Force load one font.
|
||||||
i32 font_count_max = 1;
|
Font_Setup *first_setup = list.first;
|
||||||
for (Font_Setup *ptr = list.first;
|
system_font_load_new_font(&first_setup->stub);
|
||||||
ptr != 0;
|
|
||||||
ptr = ptr->next){
|
|
||||||
Font_Loadable_Stub *stub = &ptr->stub;
|
|
||||||
|
|
||||||
Font_ID new_id = 0;
|
|
||||||
if (fontvars.count < font_count_max){
|
|
||||||
i32 index = fontvars.count;
|
|
||||||
Font_Slot *slot = &fontvars.slots[index];
|
|
||||||
Font_Settings *settings = &slot->settings;
|
|
||||||
Font_Metrics *metrics = &slot->metrics;
|
|
||||||
Font_Page_Storage *pages = &slot->pages;
|
|
||||||
|
|
||||||
Assert(!slot->is_active);
|
|
||||||
|
|
||||||
char *filename = stub->name;
|
|
||||||
i32 filename_len = 0;
|
|
||||||
for (;filename[filename_len];++filename_len);
|
|
||||||
|
|
||||||
// Initialize Font Parameters
|
|
||||||
Assert(filename_len <= sizeof(settings->stub.name) - 1);
|
|
||||||
memset(settings, 0, sizeof(*settings));
|
|
||||||
memcpy(&settings->stub, stub, sizeof(*stub));
|
|
||||||
settings->pt_size = fontvars.pt_size;
|
|
||||||
settings->use_hinting = fontvars.use_hinting;
|
|
||||||
|
|
||||||
memset(metrics, 0, sizeof(*metrics));
|
|
||||||
memset(pages, 0, sizeof(*pages));
|
|
||||||
b32 success = font_load(&sysfunc, settings, metrics, pages);
|
|
||||||
if (success){
|
|
||||||
slot->is_active = true;
|
|
||||||
new_id = (Font_ID)(index + 1);
|
|
||||||
++fontvars.count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BOTTOM
|
// BOTTOM
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#if !defined(FCODER_FONT_PROVIDER_FREETYPE_H)
|
#if !defined(FCODER_FONT_PROVIDER_FREETYPE_H)
|
||||||
#define FCODER_FONT_PROVIDER_FREETYPE_H
|
#define FCODER_FONT_PROVIDER_FREETYPE_H
|
||||||
|
|
||||||
// NOTE(allen): Implemented by the freetype font provider.
|
|
||||||
struct Font_Slot{
|
struct Font_Slot{
|
||||||
b32 is_active;
|
b32 is_active;
|
||||||
Font_Settings settings;
|
Font_Settings settings;
|
||||||
|
@ -20,9 +19,35 @@ struct Font_Slot{
|
||||||
Font_Page_Storage pages;
|
Font_Page_Storage pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Font_Slot_Page{
|
||||||
|
Font_Slot_Page *next;
|
||||||
|
Font_Slot_Page *prev;
|
||||||
|
|
||||||
|
u64 *is_active;
|
||||||
|
Font_Settings *settings;
|
||||||
|
Font_Metrics *metrics;
|
||||||
|
Font_Page_Storage *pages;
|
||||||
|
|
||||||
|
i32 used_count;
|
||||||
|
i32 fill_count;
|
||||||
|
i32 max;
|
||||||
|
Font_ID first_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Font_Slot_Page_And_Index{
|
||||||
|
Font_Slot_Page *page;
|
||||||
|
i32 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE(allen): SLOT_PER_PAGE must be >= 1
|
||||||
|
global int32_t SLOT_PER_PAGE = 32;
|
||||||
|
global int32_t SLOT_SIZE = sizeof(Font_Settings) + sizeof(Font_Metrics) + sizeof(Font_Page_Storage);
|
||||||
|
global int32_t SLOT_PAGE_SIZE = sizeof(Font_Slot_Page) + ((SLOT_PER_PAGE + 63)/64)*8 + SLOT_PER_PAGE*SLOT_SIZE;
|
||||||
|
|
||||||
struct Font_Vars{
|
struct Font_Vars{
|
||||||
Font_Slot slots[32];
|
Font_Slot_Page slot_pages_sentinel;
|
||||||
i32 count;
|
i32 used_slot_count;
|
||||||
|
i32 max_slot_count;
|
||||||
|
|
||||||
Font_Loadable_Description loadables[4096];
|
Font_Loadable_Description loadables[4096];
|
||||||
i32 loadable_count;
|
i32 loadable_count;
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
// is the same as the type of the next/prev pointers.
|
// is the same as the type of the next/prev pointers.
|
||||||
|
|
||||||
#define dll_init_sentinel(s) (s)->next=(s),(s)->prev=(s)
|
#define dll_init_sentinel(s) (s)->next=(s),(s)->prev=(s)
|
||||||
#define dll_insert(p,v) (v)->next=(p)->next,(v)->prev=(p),(p)->next=(v),(v)->next->prev=(v)
|
#define dll_insert(p,n) (n)->next=(p)->next,(n)->prev=(p),(p)->next=(n),(n)->next->prev=(n)
|
||||||
#define dll_back_insert(p,v) (v)->prev=(p)->prev,(v)->next=(p),(p)->prev=(v),(v)->prev->next=(v)
|
#define dll_insert_back(p,n) (n)->prev=(p)->prev,(n)->next=(p),(p)->prev=(n),(n)->prev->next=(n)
|
||||||
#define dll_remove(v) (v)->next->prev=(v)->prev,(v)->prev->next=(v)->next
|
#define dll_remove(n) (n)->next->prev=(n)->prev,(n)->prev->next=(n)->next
|
||||||
|
|
||||||
// HACK(allen): I don't like this anymore, get rid of it.
|
// HACK(allen): I don't like this anymore, get rid of it.
|
||||||
// for(dll_items(iterator, sentinel_ptr)){...}
|
// for(dll_items(iterator, sentinel_ptr)){...}
|
||||||
|
|
Loading…
Reference in New Issue