mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Merge branch 'master' of https://github.com/odin-lang/Odin
This commit is contained in:
+8
-7
@@ -243,13 +243,11 @@ default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, a
|
|||||||
return alloc_bytes(new_size, alignment, allocator, loc)
|
return alloc_bytes(new_size, alignment, allocator, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size == 0 {
|
|
||||||
err := free_bytes(old_data, allocator, loc)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if new_size == old_size {
|
if new_size == old_size {
|
||||||
return old_data, .None
|
return old_data, nil
|
||||||
|
}
|
||||||
|
if new_size == 0 {
|
||||||
|
return nil, free_bytes(old_data, allocator, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
new_memory, err := alloc_bytes(new_size, alignment, allocator, loc)
|
new_memory, err := alloc_bytes(new_size, alignment, allocator, loc)
|
||||||
@@ -258,6 +256,9 @@ default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
runtime.copy(new_memory, old_data)
|
runtime.copy(new_memory, old_data)
|
||||||
free_bytes(old_data, allocator, loc)
|
err1 := free_bytes(old_data, allocator, loc)
|
||||||
|
if err == nil {
|
||||||
|
err = err1
|
||||||
|
}
|
||||||
return new_memory, err
|
return new_memory, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,300 @@
|
|||||||
|
package mem_virtual
|
||||||
|
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
|
Arena_Kind :: enum uint {
|
||||||
|
Growing = 0, // chained memory blocks (singly linked list)
|
||||||
|
Static = 1, // fixed reservation sized
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena :: struct {
|
||||||
|
kind: Arena_Kind,
|
||||||
|
curr_block: ^Memory_Block,
|
||||||
|
total_used: uint,
|
||||||
|
total_reserved: uint,
|
||||||
|
minimum_block_size: uint,
|
||||||
|
temp_count: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 1 MiB should be enough to start with
|
||||||
|
DEFAULT_ARENA_STATIC_COMMIT_SIZE :: 1<<20
|
||||||
|
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: DEFAULT_ARENA_STATIC_COMMIT_SIZE
|
||||||
|
|
||||||
|
// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
|
||||||
|
DEFAULT_ARENA_STATIC_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
|
||||||
|
arena.kind = .Growing
|
||||||
|
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
|
||||||
|
arena.total_used = 0
|
||||||
|
arena.total_reserved = arena.curr_block.reserved
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
|
||||||
|
arena.kind = .Static
|
||||||
|
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
||||||
|
arena.total_used = 0
|
||||||
|
arena.total_reserved = arena.curr_block.reserved
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||||
|
assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc)
|
||||||
|
|
||||||
|
size := size
|
||||||
|
if size == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arena.kind {
|
||||||
|
case .Growing:
|
||||||
|
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
|
||||||
|
size = mem.align_forward_uint(size, alignment)
|
||||||
|
if arena.minimum_block_size == 0 {
|
||||||
|
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
block_size := max(size, arena.minimum_block_size)
|
||||||
|
|
||||||
|
new_block := memory_block_alloc(size, block_size, {}) or_return
|
||||||
|
new_block.prev = arena.curr_block
|
||||||
|
arena.curr_block = new_block
|
||||||
|
arena.total_reserved += new_block.reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_used := arena.curr_block.used
|
||||||
|
data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
|
||||||
|
arena.total_used += arena.curr_block.used - prev_used
|
||||||
|
case .Static:
|
||||||
|
if arena.curr_block == nil {
|
||||||
|
if arena.minimum_block_size == 0 {
|
||||||
|
arena.minimum_block_size = DEFAULT_ARENA_STATIC_RESERVE_SIZE
|
||||||
|
}
|
||||||
|
arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return
|
||||||
|
}
|
||||||
|
data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
|
||||||
|
arena.total_used = arena.curr_block.used
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
|
||||||
|
if arena.curr_block != nil {
|
||||||
|
assert(arena.kind == .Static, "expected a .Static arena", loc)
|
||||||
|
|
||||||
|
prev_pos := arena.curr_block.used
|
||||||
|
arena.curr_block.used = clamp(pos, 0, arena.curr_block.reserved)
|
||||||
|
|
||||||
|
if prev_pos < pos {
|
||||||
|
mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:pos-prev_pos])
|
||||||
|
}
|
||||||
|
arena.total_used = arena.curr_block.used
|
||||||
|
return true
|
||||||
|
} else if pos == 0 {
|
||||||
|
arena.total_used = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
|
||||||
|
if free_block := arena.curr_block; free_block != nil {
|
||||||
|
assert(arena.kind == .Growing, "expected a .Growing arena", loc)
|
||||||
|
arena.curr_block = free_block.prev
|
||||||
|
memory_block_dealloc(free_block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_free_all :: proc(arena: ^Arena) {
|
||||||
|
switch arena.kind {
|
||||||
|
case .Growing:
|
||||||
|
for arena.curr_block != nil {
|
||||||
|
arena_growing_free_last_memory_block(arena)
|
||||||
|
}
|
||||||
|
arena.total_reserved = 0
|
||||||
|
case .Static:
|
||||||
|
arena_static_reset_to(arena, 0)
|
||||||
|
}
|
||||||
|
arena.total_used = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_destroy :: proc(arena: ^Arena) {
|
||||||
|
arena_free_all(arena)
|
||||||
|
memory_block_dealloc(arena.curr_block)
|
||||||
|
arena.curr_block = nil
|
||||||
|
arena.total_used = 0
|
||||||
|
arena.total_reserved = 0
|
||||||
|
arena.temp_count = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_growing_bootstrap_new :: proc{
|
||||||
|
arena_growing_bootstrap_new_by_offset,
|
||||||
|
arena_growing_bootstrap_new_by_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_static_bootstrap_new :: proc{
|
||||||
|
arena_static_bootstrap_new_by_offset,
|
||||||
|
arena_static_bootstrap_new_by_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
bootstrap: Arena
|
||||||
|
bootstrap.kind = .Growing
|
||||||
|
bootstrap.minimum_block_size = minimum_block_size
|
||||||
|
|
||||||
|
data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
||||||
|
|
||||||
|
ptr = (^T)(raw_data(data))
|
||||||
|
|
||||||
|
(^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
bootstrap: Arena
|
||||||
|
bootstrap.kind = .Static
|
||||||
|
bootstrap.minimum_block_size = reserved
|
||||||
|
|
||||||
|
data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
||||||
|
|
||||||
|
ptr = (^T)(raw_data(data))
|
||||||
|
|
||||||
|
(^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
||||||
|
return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_allocator :: proc(arena: ^Arena) -> mem.Allocator {
|
||||||
|
return mem.Allocator{arena_allocator_proc, arena}
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||||
|
size, alignment: int,
|
||||||
|
old_memory: rawptr, old_size: int,
|
||||||
|
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||||
|
arena := (^Arena)(allocator_data)
|
||||||
|
|
||||||
|
size, alignment := uint(size), uint(alignment)
|
||||||
|
old_size := uint(old_size)
|
||||||
|
|
||||||
|
switch mode {
|
||||||
|
case .Alloc:
|
||||||
|
return arena_alloc(arena, size, alignment)
|
||||||
|
case .Free:
|
||||||
|
err = .Mode_Not_Implemented
|
||||||
|
case .Free_All:
|
||||||
|
arena_free_all(arena)
|
||||||
|
case .Resize:
|
||||||
|
old_data := ([^]byte)(old_memory)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case old_data == nil:
|
||||||
|
return arena_alloc(arena, size, alignment)
|
||||||
|
case size == old_size:
|
||||||
|
// return old memory
|
||||||
|
data = old_data[:size]
|
||||||
|
return
|
||||||
|
case size == 0:
|
||||||
|
err = .Mode_Not_Implemented
|
||||||
|
return
|
||||||
|
case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
|
||||||
|
// shrink data in-place
|
||||||
|
data = old_data[:size]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
new_memory := arena_alloc(arena, size, alignment) or_return
|
||||||
|
if new_memory == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(new_memory, old_data[:old_size])
|
||||||
|
return new_memory, nil
|
||||||
|
case .Query_Features:
|
||||||
|
set := (^mem.Allocator_Mode_Set)(old_memory)
|
||||||
|
if set != nil {
|
||||||
|
set^ = {.Alloc, .Free_All, .Resize, .Query_Features}
|
||||||
|
}
|
||||||
|
case .Query_Info:
|
||||||
|
err = .Mode_Not_Implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Arena_Temp :: struct {
|
||||||
|
arena: ^Arena,
|
||||||
|
block: ^Memory_Block,
|
||||||
|
used: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
|
||||||
|
assert(arena != nil, "nil arena", loc)
|
||||||
|
temp.arena = arena
|
||||||
|
temp.block = arena.curr_block
|
||||||
|
if arena.curr_block != nil {
|
||||||
|
temp.used = arena.curr_block.used
|
||||||
|
}
|
||||||
|
arena.temp_count += 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||||
|
assert(temp.arena != nil, "nil arena", loc)
|
||||||
|
arena := temp.arena
|
||||||
|
|
||||||
|
memory_block_found := false
|
||||||
|
for block := arena.curr_block; block != nil; block = block.prev {
|
||||||
|
if block == temp.block {
|
||||||
|
memory_block_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !memory_block_found {
|
||||||
|
assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
for arena.curr_block != temp.block {
|
||||||
|
arena_growing_free_last_memory_block(arena)
|
||||||
|
}
|
||||||
|
|
||||||
|
if block := arena.curr_block; block != nil {
|
||||||
|
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
|
||||||
|
amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
|
||||||
|
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
|
||||||
|
block.used = temp.used
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||||
|
arena.temp_count -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) {
|
||||||
|
assert(arena.temp_count == 0, "Arena_Temp not been ended", loc)
|
||||||
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package mem_virtual
|
|
||||||
|
|
||||||
arena_init :: proc{
|
|
||||||
static_arena_init,
|
|
||||||
growing_arena_init,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_temp_begin :: proc{
|
|
||||||
static_arena_temp_begin,
|
|
||||||
growing_arena_temp_begin,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_temp_end :: proc{
|
|
||||||
static_arena_temp_end,
|
|
||||||
growing_arena_temp_end,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_check_temp :: proc{
|
|
||||||
static_arena_check_temp,
|
|
||||||
growing_arena_check_temp,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_allocator :: proc{
|
|
||||||
static_arena_allocator,
|
|
||||||
growing_arena_allocator,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_alloc :: proc{
|
|
||||||
static_arena_alloc,
|
|
||||||
growing_arena_alloc,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_free_all :: proc{
|
|
||||||
static_arena_free_all,
|
|
||||||
growing_arena_free_all,
|
|
||||||
}
|
|
||||||
|
|
||||||
arena_destroy :: proc{
|
|
||||||
static_arena_destroy,
|
|
||||||
growing_arena_destroy,
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package mem_virtual
|
|
||||||
|
|
||||||
import "core:mem"
|
|
||||||
|
|
||||||
Growing_Arena :: struct {
|
|
||||||
curr_block: ^Memory_Block,
|
|
||||||
total_used: uint,
|
|
||||||
total_reserved: uint,
|
|
||||||
|
|
||||||
minimum_block_size: uint,
|
|
||||||
temp_count: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough
|
|
||||||
|
|
||||||
growing_arena_init :: proc(arena: ^Growing_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
|
|
||||||
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
|
|
||||||
arena.total_used = 0
|
|
||||||
arena.total_reserved = arena.curr_block.reserved
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check {
|
|
||||||
alignment_offset := uint(0)
|
|
||||||
ptr := uintptr(arena.curr_block.base[arena.curr_block.used:])
|
|
||||||
mask := uintptr(alignment-1)
|
|
||||||
if ptr & mask != 0 {
|
|
||||||
alignment_offset = uint(alignment) - uint(ptr & mask)
|
|
||||||
}
|
|
||||||
return alignment_offset
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(mem.is_power_of_two(uintptr(alignment)))
|
|
||||||
|
|
||||||
size := uint(0)
|
|
||||||
if arena.curr_block != nil {
|
|
||||||
size = uint(min_size) + align_forward_offset(arena, alignment)
|
|
||||||
}
|
|
||||||
|
|
||||||
if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved {
|
|
||||||
size = uint(mem.align_forward_int(min_size, alignment))
|
|
||||||
arena.minimum_block_size = max(DEFAULT_MINIMUM_BLOCK_SIZE, arena.minimum_block_size)
|
|
||||||
|
|
||||||
block_size := max(size, arena.minimum_block_size)
|
|
||||||
|
|
||||||
new_block := memory_block_alloc(size, block_size, {}) or_return
|
|
||||||
new_block.prev = arena.curr_block
|
|
||||||
arena.curr_block = new_block
|
|
||||||
arena.total_reserved += new_block.reserved
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
data, err = alloc_from_memory_block(arena.curr_block, int(size), alignment)
|
|
||||||
if err == nil {
|
|
||||||
arena.total_used += size
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_free_last_memory_block :: proc(arena: ^Growing_Arena) {
|
|
||||||
free_block := arena.curr_block
|
|
||||||
arena.curr_block = free_block.prev
|
|
||||||
memory_block_dealloc(free_block)
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_free_all :: proc(arena: ^Growing_Arena) {
|
|
||||||
for arena.curr_block != nil {
|
|
||||||
growing_arena_free_last_memory_block(arena)
|
|
||||||
}
|
|
||||||
arena.total_used = 0
|
|
||||||
arena.total_reserved = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_destroy :: proc(arena: ^Growing_Arena) {
|
|
||||||
growing_arena_free_all(arena)
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { bootstrap: Growing_Arena
|
|
||||||
bootstrap.minimum_block_size = minimum_block_size
|
|
||||||
|
|
||||||
data := growing_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
|
||||||
|
|
||||||
ptr = (^T)(raw_data(data))
|
|
||||||
|
|
||||||
(^Growing_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
|
||||||
return growing_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
|
|
||||||
}
|
|
||||||
growing_arena_bootstrap_new :: proc{
|
|
||||||
growing_arena_bootstrap_new_by_offset,
|
|
||||||
growing_arena_bootstrap_new_by_name,
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator {
|
|
||||||
return mem.Allocator{growing_arena_allocator_proc, arena}
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|
||||||
size, alignment: int,
|
|
||||||
old_memory: rawptr, old_size: int,
|
|
||||||
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
arena := (^Growing_Arena)(allocator_data)
|
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case .Alloc:
|
|
||||||
return growing_arena_alloc(arena, size, alignment)
|
|
||||||
case .Free:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
case .Free_All:
|
|
||||||
growing_arena_free_all(arena)
|
|
||||||
return
|
|
||||||
case .Resize:
|
|
||||||
return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, growing_arena_allocator(arena), location)
|
|
||||||
|
|
||||||
case .Query_Features, .Query_Info:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Growing_Arena_Temp :: struct {
|
|
||||||
arena: ^Growing_Arena,
|
|
||||||
block: ^Memory_Block,
|
|
||||||
used: uint,
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_temp_begin :: proc(arena: ^Growing_Arena) -> (temp: Growing_Arena_Temp) {
|
|
||||||
temp.arena = arena
|
|
||||||
temp.block = arena.curr_block
|
|
||||||
if arena.curr_block != nil {
|
|
||||||
temp.used = arena.curr_block.used
|
|
||||||
}
|
|
||||||
arena.temp_count += 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_temp_end :: proc(temp: Growing_Arena_Temp, loc := #caller_location) {
|
|
||||||
assert(temp.arena != nil, "nil arena", loc)
|
|
||||||
arena := temp.arena
|
|
||||||
|
|
||||||
for arena.curr_block != temp.block {
|
|
||||||
growing_arena_free_last_memory_block(arena)
|
|
||||||
}
|
|
||||||
|
|
||||||
if block := arena.curr_block; block != nil {
|
|
||||||
assert(block.used >= temp.used, "out of order use of growing_arena_temp_end", loc)
|
|
||||||
amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
|
|
||||||
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
|
|
||||||
block.used = temp.used
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(arena.temp_count > 0, "double-use of growing_arena_temp_end", loc)
|
|
||||||
arena.temp_count -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
growing_arena_check_temp :: proc(arena: ^Growing_Arena, loc := #caller_location) {
|
|
||||||
assert(arena.temp_count == 0, "Growing_Arena_Temp not been ended", loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
package mem_virtual
|
|
||||||
|
|
||||||
import "core:mem"
|
|
||||||
|
|
||||||
Static_Arena :: struct {
|
|
||||||
block: ^Memory_Block,
|
|
||||||
total_used: uint,
|
|
||||||
total_reserved: uint,
|
|
||||||
|
|
||||||
minimum_block_size: uint,
|
|
||||||
temp_count: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_ARENA_DEFAULT_COMMIT_SIZE :: 1<<20 // 1 MiB should be enough to start with
|
|
||||||
|
|
||||||
// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
|
|
||||||
STATIC_ARENA_DEFAULT_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
|
|
||||||
|
|
||||||
static_arena_init :: proc(arena: ^Static_Arena, reserved: uint, commit_size: uint = STATIC_ARENA_DEFAULT_COMMIT_SIZE) -> (err: Allocator_Error) {
|
|
||||||
arena.block = memory_block_alloc(commit_size, reserved, {}) or_return
|
|
||||||
arena.total_used = 0
|
|
||||||
arena.total_reserved = arena.block.reserved
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_destroy :: proc(arena: ^Static_Arena) {
|
|
||||||
memory_block_dealloc(arena.block)
|
|
||||||
arena^ = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_alloc :: proc(arena: ^Static_Arena, size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
align_forward :: #force_inline proc "contextless" (ptr: uint, align: uint) -> uint {
|
|
||||||
mask := align-1
|
|
||||||
return (ptr + mask) &~ mask
|
|
||||||
}
|
|
||||||
|
|
||||||
if arena.block == nil {
|
|
||||||
reserve_size := max(arena.minimum_block_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE)
|
|
||||||
static_arena_init(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return
|
|
||||||
}
|
|
||||||
|
|
||||||
MINIMUM_ALIGN :: 2*align_of(uintptr)
|
|
||||||
|
|
||||||
defer arena.total_used = arena.block.used
|
|
||||||
return alloc_from_memory_block(arena.block, size, max(MINIMUM_ALIGN, alignment))
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_reset_to :: proc(arena: ^Static_Arena, pos: uint) -> bool {
|
|
||||||
if arena.block != nil {
|
|
||||||
prev_pos := arena.block.used
|
|
||||||
arena.block.used = clamp(pos, 0, arena.block.reserved)
|
|
||||||
|
|
||||||
if prev_pos < pos {
|
|
||||||
mem.zero_slice(arena.block.base[arena.block.used:][:pos-prev_pos])
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} else if pos == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_free_all :: proc(arena: ^Static_Arena) {
|
|
||||||
static_arena_reset_to(arena, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
|
||||||
bootstrap: Static_Arena
|
|
||||||
bootstrap.minimum_block_size = reserved
|
|
||||||
|
|
||||||
data := static_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
|
|
||||||
|
|
||||||
ptr = (^T)(raw_data(data))
|
|
||||||
|
|
||||||
(^Static_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
|
||||||
return static_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
|
|
||||||
}
|
|
||||||
static_arena_bootstrap_new :: proc{
|
|
||||||
static_arena_bootstrap_new_by_offset,
|
|
||||||
static_arena_bootstrap_new_by_name,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_allocator :: proc(arena: ^Static_Arena) -> mem.Allocator {
|
|
||||||
return mem.Allocator{static_arena_allocator_proc, arena}
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|
||||||
size, alignment: int,
|
|
||||||
old_memory: rawptr, old_size: int,
|
|
||||||
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
|
||||||
arena := (^Static_Arena)(allocator_data)
|
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case .Alloc:
|
|
||||||
return static_arena_alloc(arena, size, alignment)
|
|
||||||
case .Free:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
case .Free_All:
|
|
||||||
static_arena_free_all(arena)
|
|
||||||
return
|
|
||||||
case .Resize:
|
|
||||||
return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, static_arena_allocator(arena), location)
|
|
||||||
|
|
||||||
case .Query_Features, .Query_Info:
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = .Mode_Not_Implemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Static_Arena_Temp :: struct {
|
|
||||||
arena: ^Static_Arena,
|
|
||||||
used: uint,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_temp_begin :: proc(arena: ^Static_Arena) -> (temp: Static_Arena_Temp) {
|
|
||||||
temp.arena = arena
|
|
||||||
temp.used = arena.block.used if arena.block != nil else 0
|
|
||||||
arena.temp_count += 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
static_arena_temp_end :: proc(temp: Static_Arena_Temp, loc := #caller_location) {
|
|
||||||
assert(temp.arena != nil, "nil arena", loc)
|
|
||||||
arena := temp.arena
|
|
||||||
|
|
||||||
used := arena.block.used if arena.block != nil else 0
|
|
||||||
|
|
||||||
assert(temp.used >= used, "invalid Static_Arena_Temp", loc)
|
|
||||||
|
|
||||||
static_arena_reset_to(arena, temp.used)
|
|
||||||
|
|
||||||
assert(arena.temp_count > 0, "double-use of static_arena_temp_end", loc)
|
|
||||||
arena.temp_count -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static_arena_check_temp :: proc(arena: ^Static_Arena, loc := #caller_location) {
|
|
||||||
assert(arena.temp_count == 0, "Static_Arena_Temp not been ended", loc)
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package mem_virtual
|
package mem_virtual
|
||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
DEFAULT_PAGE_SIZE := uint(4096)
|
DEFAULT_PAGE_SIZE := uint(4096)
|
||||||
|
|
||||||
@@ -106,7 +107,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
|||||||
return &pmblock.block, nil
|
return &pmblock.block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||||
alignment_offset := uint(0)
|
alignment_offset := uint(0)
|
||||||
ptr := uintptr(block.base[block.used:])
|
ptr := uintptr(block.base[block.used:])
|
||||||
@@ -134,11 +135,14 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
||||||
size := uint(min_size) + alignment_offset
|
size, size_ok := safe_add(min_size, alignment_offset)
|
||||||
|
if !size_ok {
|
||||||
|
err = .Out_Of_Memory
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if block.used + size > block.reserved {
|
if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.reserved {
|
||||||
err = .Out_Of_Memory
|
err = .Out_Of_Memory
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -162,3 +166,10 @@ memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
||||||
|
z, did_overflow := intrinsics.overflow_add(x, y)
|
||||||
|
return z, !did_overflow
|
||||||
|
}
|
||||||
@@ -63,7 +63,6 @@ platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_
|
|||||||
return .Out_Of_Memory
|
return .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
commit(block, to_commit) or_return
|
commit(block, to_commit) or_return
|
||||||
block.committed = to_commit
|
block.committed = to_commit
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -177,7 +177,6 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// merge sort
|
|
||||||
_stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
|
_stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
|
||||||
less :: #force_inline proc(a, b: E, call: P) -> bool {
|
less :: #force_inline proc(a, b: E, call: P) -> bool {
|
||||||
when KIND == .Ordered {
|
when KIND == .Ordered {
|
||||||
@@ -190,7 +189,9 @@ _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (O
|
|||||||
#panic("unhandled Sort_Kind")
|
#panic("unhandled Sort_Kind")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// insertion sort
|
||||||
|
// TODO(bill): use a different algorithm as insertion sort is O(n^2)
|
||||||
n := len(data)
|
n := len(data)
|
||||||
for i in 1..<n {
|
for i in 1..<n {
|
||||||
for j := i; j > 0 && less(data[j], data[j-1], call); j -= 1 {
|
for j := i; j > 0 && less(data[j], data[j-1], call); j -= 1 {
|
||||||
|
|||||||
@@ -19,4 +19,5 @@ foreign shell32 {
|
|||||||
pszPath: LPCWSTR,
|
pszPath: LPCWSTR,
|
||||||
psa: ^SECURITY_ATTRIBUTES,
|
psa: ^SECURITY_ATTRIBUTES,
|
||||||
) -> c_int ---
|
) -> c_int ---
|
||||||
|
SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -925,6 +925,48 @@ NM_FONTCHANGED :: NM_OUTOFMEMORY-22
|
|||||||
NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct
|
NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct
|
||||||
NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM
|
NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM
|
||||||
|
|
||||||
|
PCZZWSTR :: ^WCHAR
|
||||||
|
|
||||||
|
SHFILEOPSTRUCTW :: struct {
|
||||||
|
hwnd: HWND,
|
||||||
|
wFunc: UINT,
|
||||||
|
pFrom: PCZZWSTR,
|
||||||
|
pTo: PCZZWSTR,
|
||||||
|
fFlags: FILEOP_FLAGS,
|
||||||
|
fAnyOperationsAborted: BOOL,
|
||||||
|
hNameMappings: LPVOID,
|
||||||
|
lpszProgressTitle: PCWSTR, // only used if FOF_SIMPLEPROGRESS
|
||||||
|
}
|
||||||
|
LPSHFILEOPSTRUCTW :: ^SHFILEOPSTRUCTW
|
||||||
|
|
||||||
|
// Shell File Operations
|
||||||
|
FO_MOVE :: 0x0001
|
||||||
|
FO_COPY :: 0x0002
|
||||||
|
FO_DELETE :: 0x0003
|
||||||
|
FO_RENAME :: 0x0004
|
||||||
|
|
||||||
|
// SHFILEOPSTRUCT.fFlags and IFileOperation::SetOperationFlags() flag values
|
||||||
|
FOF_MULTIDESTFILES :: 0x0001
|
||||||
|
FOF_CONFIRMMOUSE :: 0x0002
|
||||||
|
FOF_SILENT :: 0x0004 // don't display progress UI (confirm prompts may be displayed still)
|
||||||
|
FOF_RENAMEONCOLLISION :: 0x0008 // automatically rename the source files to avoid the collisions
|
||||||
|
FOF_NOCONFIRMATION :: 0x0010 // don't display confirmation UI, assume "yes" for cases that can be bypassed, "no" for those that can not
|
||||||
|
FOF_WANTMAPPINGHANDLE :: 0x0020 // Fill in SHFILEOPSTRUCT.hNameMappings
|
||||||
|
// Must be freed using SHFreeNameMappings
|
||||||
|
FOF_ALLOWUNDO :: 0x0040 // enable undo including Recycle behavior for IFileOperation::Delete()
|
||||||
|
FOF_FILESONLY :: 0x0080 // only operate on the files (non folders), both files and folders are assumed without this
|
||||||
|
FOF_SIMPLEPROGRESS :: 0x0100 // means don't show names of files
|
||||||
|
FOF_NOCONFIRMMKDIR :: 0x0200 // don't dispplay confirmatino UI before making any needed directories, assume "Yes" in these cases
|
||||||
|
FOF_NOERRORUI :: 0x0400 // don't put up error UI, other UI may be displayed, progress, confirmations
|
||||||
|
FOF_NOCOPYSECURITYATTRIBS :: 0x0800 // dont copy file security attributes (ACLs)
|
||||||
|
FOF_NORECURSION :: 0x1000 // don't recurse into directories for operations that would recurse
|
||||||
|
FOF_NO_CONNECTED_ELEMENTS :: 0x2000 // don't operate on connected elements ("xxx_files" folders that go with .htm files)
|
||||||
|
FOF_WANTNUKEWARNING :: 0x4000 // during delete operation, warn if object is being permanently destroyed instead of recycling (partially overrides FOF_NOCONFIRMATION)
|
||||||
|
FOF_NORECURSEREPARSE :: 0x8000 // deprecated; the operations engine always does the right thing on FolderLink objects (symlinks, reparse points, folder shortcuts)
|
||||||
|
FOF_NO_UI :: (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR) // don't display any UI at all
|
||||||
|
|
||||||
|
FILEOP_FLAGS :: WORD
|
||||||
|
|
||||||
DEVMODEW :: struct {
|
DEVMODEW :: struct {
|
||||||
dmDeviceName: [32]wchar_t,
|
dmDeviceName: [32]wchar_t,
|
||||||
dmSpecVersion: WORD,
|
dmSpecVersion: WORD,
|
||||||
@@ -3190,10 +3232,14 @@ LWSTDAPI :: HRESULT
|
|||||||
|
|
||||||
CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}}
|
CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}}
|
||||||
CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}}
|
CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}}
|
||||||
|
CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
|
||||||
|
|
||||||
IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}}
|
IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}}
|
||||||
IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}}
|
IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}}
|
||||||
IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}}
|
IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}}
|
||||||
|
IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
|
||||||
|
IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}}
|
||||||
|
IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}}
|
||||||
|
|
||||||
IModalWindow :: struct #raw_union {
|
IModalWindow :: struct #raw_union {
|
||||||
#subtype IUnknown: IUnknown,
|
#subtype IUnknown: IUnknown,
|
||||||
@@ -3498,6 +3544,84 @@ IFileSaveDialogVtbl :: struct {
|
|||||||
ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
|
ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ITaskbarList :: struct #raw_union {
|
||||||
|
#subtype IUnknown: IUnknown,
|
||||||
|
using Vtbl: ^ITaskbarListVtbl,
|
||||||
|
}
|
||||||
|
ITaskbarListVtbl :: struct {
|
||||||
|
using IUnknownVtbl: IUnknownVtbl,
|
||||||
|
HrInit: proc "stdcall" (this: ^ITaskbarList) -> HRESULT,
|
||||||
|
AddTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
DeleteTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
ActivateTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
SetActiveAlt: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||||
|
}
|
||||||
|
|
||||||
|
ITaskbarList2 :: struct #raw_union {
|
||||||
|
#subtype ITaskbarList: ITaskbarList,
|
||||||
|
using Vtbl: ^ITaskbarList2Vtbl,
|
||||||
|
}
|
||||||
|
ITaskbarList2Vtbl :: struct {
|
||||||
|
using ITaskbarListVtbl: ITaskbarListVtbl,
|
||||||
|
MarkFullscreenWindow: proc "stdcall" (this: ^ITaskbarList2, hwnd: HWND, fFullscreen: BOOL) -> HRESULT,
|
||||||
|
}
|
||||||
|
|
||||||
|
TBPFLAG :: enum c_int {
|
||||||
|
NOPROGRESS = 0,
|
||||||
|
INDETERMINATE = 0x1,
|
||||||
|
NORMAL = 0x2,
|
||||||
|
ERROR = 0x4,
|
||||||
|
PAUSED = 0x8,
|
||||||
|
}
|
||||||
|
|
||||||
|
THUMBBUTTONFLAGS :: enum c_int {
|
||||||
|
ENABLED = 0,
|
||||||
|
DISABLED = 0x1,
|
||||||
|
DISMISSONCLICK = 0x2,
|
||||||
|
NOBACKGROUND = 0x4,
|
||||||
|
HIDDEN = 0x8,
|
||||||
|
NONINTERACTIVE = 0x10,
|
||||||
|
}
|
||||||
|
|
||||||
|
THUMBBUTTONMASK :: enum c_int {
|
||||||
|
BITMAP = 0x1,
|
||||||
|
ICON = 0x2,
|
||||||
|
TOOLTIP = 0x4,
|
||||||
|
FLAGS = 0x8,
|
||||||
|
}
|
||||||
|
|
||||||
|
THUMBBUTTON :: struct {
|
||||||
|
dwMask: THUMBBUTTONMASK,
|
||||||
|
iId: UINT,
|
||||||
|
iBitmap: UINT,
|
||||||
|
hIcon: HICON,
|
||||||
|
szTip: [260]WCHAR,
|
||||||
|
dwFlags: THUMBBUTTONFLAGS,
|
||||||
|
}
|
||||||
|
LPTHUMBBUTTON :: ^THUMBBUTTON
|
||||||
|
|
||||||
|
HIMAGELIST :: ^IUnknown
|
||||||
|
|
||||||
|
ITaskbarList3 :: struct #raw_union {
|
||||||
|
#subtype ITaskbarList2: ITaskbarList2,
|
||||||
|
using Vtbl: ^ITaskbarList3Vtbl,
|
||||||
|
}
|
||||||
|
ITaskbarList3Vtbl :: struct {
|
||||||
|
using ITaskbarList2Vtbl: ITaskbarList2Vtbl,
|
||||||
|
SetProgressValue: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, ullCompleted: ULONGLONG, ullTotal: ULONGLONG) -> HRESULT,
|
||||||
|
SetProgressState: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, tbpFlags: TBPFLAG) -> HRESULT,
|
||||||
|
RegisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND) -> HRESULT,
|
||||||
|
UnregisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND) -> HRESULT,
|
||||||
|
SetTabOrder: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndInsertBefore: HWND) -> HRESULT,
|
||||||
|
SetTabActive: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND, dwReserved: DWORD) -> HRESULT,
|
||||||
|
ThumbBarAddButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT,
|
||||||
|
ThumbBarUpdateButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT,
|
||||||
|
ThumbBarSetImageList: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, himl: HIMAGELIST) -> HRESULT,
|
||||||
|
SetOverlayIcon: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, hIcon: HICON, pszDescription: LPCWSTR) -> HRESULT,
|
||||||
|
SetThumbnailTooltip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, pszTip: LPCWSTR) -> HRESULT,
|
||||||
|
SetThumbnailClip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, prcClip: ^RECT) -> HRESULT,
|
||||||
|
}
|
||||||
|
|
||||||
MEMORYSTATUSEX :: struct {
|
MEMORYSTATUSEX :: struct {
|
||||||
dwLength: DWORD,
|
dwLength: DWORD,
|
||||||
dwMemoryLoad: DWORD,
|
dwMemoryLoad: DWORD,
|
||||||
|
|||||||
@@ -1488,6 +1488,11 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
if (!(e->flags & EntityFlag_Using)) {
|
if (!(e->flags & EntityFlag_Using)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (is_blank_ident(e->token)) {
|
||||||
|
error(e->token, "'using' a procedure parameter requires a non blank identifier");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
|
bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Type *t = base_type(type_deref(e->type));
|
Type *t = base_type(type_deref(e->type));
|
||||||
|
|||||||
+5
-1
@@ -584,7 +584,11 @@ void check_label(CheckerContext *ctx, Ast *label, Ast *parent) {
|
|||||||
// Returns 'true' for 'continue', 'false' for 'return'
|
// Returns 'true' for 'continue', 'false' for 'return'
|
||||||
bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, bool is_selector, Entity *e) {
|
bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, bool is_selector, Entity *e) {
|
||||||
if (e == nullptr) {
|
if (e == nullptr) {
|
||||||
error(us->token, "'using' applied to an unknown entity");
|
if (is_blank_ident(expr)) {
|
||||||
|
error(us->token, "'using' in a statement is not allowed with the blank identifier '_'");
|
||||||
|
} else {
|
||||||
|
error(us->token, "'using' applied to an unknown entity");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -84,7 +84,7 @@ def convert_type(t, prev_name, curr_name):
|
|||||||
else:
|
else:
|
||||||
ttype = t[:len(t)-1]
|
ttype = t[:len(t)-1]
|
||||||
elem = convert_type(ttype, prev_name, curr_name)
|
elem = convert_type(ttype, prev_name, curr_name)
|
||||||
|
|
||||||
if curr_name.endswith("s") or curr_name.endswith("Table"):
|
if curr_name.endswith("s") or curr_name.endswith("Table"):
|
||||||
if prev_name.endswith("Count") or prev_name.endswith("Counts"):
|
if prev_name.endswith("Count") or prev_name.endswith("Counts"):
|
||||||
pointer = "[^]"
|
pointer = "[^]"
|
||||||
@@ -95,10 +95,10 @@ def convert_type(t, prev_name, curr_name):
|
|||||||
pointer = "[^]"
|
pointer = "[^]"
|
||||||
elif curr_name.startswith("p"):
|
elif curr_name.startswith("p"):
|
||||||
pointer = "[^]"
|
pointer = "[^]"
|
||||||
|
|
||||||
if curr_name and elem.endswith("Flags"):
|
if curr_name and elem.endswith("Flags"):
|
||||||
pointer = "[^]"
|
pointer = "[^]"
|
||||||
|
|
||||||
return "{}{}".format(pointer, elem)
|
return "{}{}".format(pointer, elem)
|
||||||
elif t[0].isupper():
|
elif t[0].isupper():
|
||||||
return t
|
return t
|
||||||
@@ -276,7 +276,7 @@ def parse_enums(f):
|
|||||||
f.write("// Enums\n")
|
f.write("// Enums\n")
|
||||||
|
|
||||||
data = re.findall(r"typedef enum Vk(\w+) {(.+?)} \w+;", src, re.S)
|
data = re.findall(r"typedef enum Vk(\w+) {(.+?)} \w+;", src, re.S)
|
||||||
|
|
||||||
data.sort(key=lambda x: x[0])
|
data.sort(key=lambda x: x[0])
|
||||||
|
|
||||||
generated_flags = set()
|
generated_flags = set()
|
||||||
@@ -458,14 +458,14 @@ def parse_procedures(f):
|
|||||||
|
|
||||||
for rt, name, fields in data:
|
for rt, name, fields in data:
|
||||||
proc_name = no_vk(name)
|
proc_name = no_vk(name)
|
||||||
|
|
||||||
pf = []
|
pf = []
|
||||||
prev_name = ""
|
prev_name = ""
|
||||||
for type_, fname in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:,|$)", fields):
|
for type_, fname in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:,|$)", fields):
|
||||||
curr_name = fix_arg(fname)
|
curr_name = fix_arg(fname)
|
||||||
pf.append((do_type(type_, prev_name, curr_name), curr_name))
|
pf.append((do_type(type_, prev_name, curr_name), curr_name))
|
||||||
prev_name = curr_name
|
prev_name = curr_name
|
||||||
|
|
||||||
data_fields = ', '.join(["{}: {}".format(n, t) for t, n in pf if t != ""])
|
data_fields = ', '.join(["{}: {}".format(n, t) for t, n in pf if t != ""])
|
||||||
|
|
||||||
ts = "proc \"c\" ({})".format(data_fields)
|
ts = "proc \"c\" ({})".format(data_fields)
|
||||||
@@ -510,7 +510,7 @@ def group_functions(f):
|
|||||||
|
|
||||||
if table_name in ('Device', 'Queue', 'CommandBuffer') and name != 'GetDeviceProcAddr':
|
if table_name in ('Device', 'Queue', 'CommandBuffer') and name != 'GetDeviceProcAddr':
|
||||||
group_map["Device"].append(nn)
|
group_map["Device"].append(nn)
|
||||||
elif table_name in ('Instance', 'PhysicalDevice') or name == 'GetDeviceProcAddr':
|
elif table_name in ('Instance', 'PhysicalDevice') and name != 'ProcGetInstanceProcAddr' or name == 'GetDeviceProcAddr':
|
||||||
group_map["Instance"].append(nn)
|
group_map["Instance"].append(nn)
|
||||||
elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or name == 'GetInstanceProcAddr':
|
elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or name == 'GetInstanceProcAddr':
|
||||||
# Skip the allocation function and the dll entry point
|
# Skip the allocation function and the dll entry point
|
||||||
|
|||||||
Vendored
+3
-3
@@ -533,6 +533,7 @@ DeviceMemoryReportCallbackEXT: ProcDeviceMemoryReportCallbackEXT
|
|||||||
EnumerateInstanceExtensionProperties: ProcEnumerateInstanceExtensionProperties
|
EnumerateInstanceExtensionProperties: ProcEnumerateInstanceExtensionProperties
|
||||||
EnumerateInstanceLayerProperties: ProcEnumerateInstanceLayerProperties
|
EnumerateInstanceLayerProperties: ProcEnumerateInstanceLayerProperties
|
||||||
EnumerateInstanceVersion: ProcEnumerateInstanceVersion
|
EnumerateInstanceVersion: ProcEnumerateInstanceVersion
|
||||||
|
GetInstanceProcAddr: ProcGetInstanceProcAddr
|
||||||
|
|
||||||
// Instance Procedures
|
// Instance Procedures
|
||||||
AcquireDrmDisplayEXT: ProcAcquireDrmDisplayEXT
|
AcquireDrmDisplayEXT: ProcAcquireDrmDisplayEXT
|
||||||
@@ -564,7 +565,6 @@ GetDisplayPlaneCapabilities2KHR: ProcGetDisplayP
|
|||||||
GetDisplayPlaneCapabilitiesKHR: ProcGetDisplayPlaneCapabilitiesKHR
|
GetDisplayPlaneCapabilitiesKHR: ProcGetDisplayPlaneCapabilitiesKHR
|
||||||
GetDisplayPlaneSupportedDisplaysKHR: ProcGetDisplayPlaneSupportedDisplaysKHR
|
GetDisplayPlaneSupportedDisplaysKHR: ProcGetDisplayPlaneSupportedDisplaysKHR
|
||||||
GetDrmDisplayEXT: ProcGetDrmDisplayEXT
|
GetDrmDisplayEXT: ProcGetDrmDisplayEXT
|
||||||
GetInstanceProcAddr: ProcGetInstanceProcAddr
|
|
||||||
GetPhysicalDeviceCalibrateableTimeDomainsEXT: ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT
|
GetPhysicalDeviceCalibrateableTimeDomainsEXT: ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT
|
||||||
GetPhysicalDeviceCooperativeMatrixPropertiesNV: ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV
|
GetPhysicalDeviceCooperativeMatrixPropertiesNV: ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV
|
||||||
GetPhysicalDeviceDisplayPlaneProperties2KHR: ProcGetPhysicalDeviceDisplayPlaneProperties2KHR
|
GetPhysicalDeviceDisplayPlaneProperties2KHR: ProcGetPhysicalDeviceDisplayPlaneProperties2KHR
|
||||||
@@ -1045,6 +1045,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
|
|||||||
set_proc_address(&EnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties")
|
set_proc_address(&EnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties")
|
||||||
set_proc_address(&EnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties")
|
set_proc_address(&EnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties")
|
||||||
set_proc_address(&EnumerateInstanceVersion, "vkEnumerateInstanceVersion")
|
set_proc_address(&EnumerateInstanceVersion, "vkEnumerateInstanceVersion")
|
||||||
|
set_proc_address(&GetInstanceProcAddr, "vkGetInstanceProcAddr")
|
||||||
|
|
||||||
// Instance Procedures
|
// Instance Procedures
|
||||||
set_proc_address(&AcquireDrmDisplayEXT, "vkAcquireDrmDisplayEXT")
|
set_proc_address(&AcquireDrmDisplayEXT, "vkAcquireDrmDisplayEXT")
|
||||||
@@ -1076,7 +1077,6 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
|
|||||||
set_proc_address(&GetDisplayPlaneCapabilitiesKHR, "vkGetDisplayPlaneCapabilitiesKHR")
|
set_proc_address(&GetDisplayPlaneCapabilitiesKHR, "vkGetDisplayPlaneCapabilitiesKHR")
|
||||||
set_proc_address(&GetDisplayPlaneSupportedDisplaysKHR, "vkGetDisplayPlaneSupportedDisplaysKHR")
|
set_proc_address(&GetDisplayPlaneSupportedDisplaysKHR, "vkGetDisplayPlaneSupportedDisplaysKHR")
|
||||||
set_proc_address(&GetDrmDisplayEXT, "vkGetDrmDisplayEXT")
|
set_proc_address(&GetDrmDisplayEXT, "vkGetDrmDisplayEXT")
|
||||||
set_proc_address(&GetInstanceProcAddr, "vkGetInstanceProcAddr")
|
|
||||||
set_proc_address(&GetPhysicalDeviceCalibrateableTimeDomainsEXT, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT")
|
set_proc_address(&GetPhysicalDeviceCalibrateableTimeDomainsEXT, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT")
|
||||||
set_proc_address(&GetPhysicalDeviceCooperativeMatrixPropertiesNV, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV")
|
set_proc_address(&GetPhysicalDeviceCooperativeMatrixPropertiesNV, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV")
|
||||||
set_proc_address(&GetPhysicalDeviceDisplayPlaneProperties2KHR, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR")
|
set_proc_address(&GetPhysicalDeviceDisplayPlaneProperties2KHR, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR")
|
||||||
@@ -2839,7 +2839,6 @@ load_proc_addresses_instance :: proc(instance: Instance) {
|
|||||||
GetDisplayPlaneCapabilitiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR")
|
GetDisplayPlaneCapabilitiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR")
|
||||||
GetDisplayPlaneSupportedDisplaysKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR")
|
GetDisplayPlaneSupportedDisplaysKHR = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR")
|
||||||
GetDrmDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkGetDrmDisplayEXT")
|
GetDrmDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkGetDrmDisplayEXT")
|
||||||
GetInstanceProcAddr = auto_cast GetInstanceProcAddr(instance, "vkGetInstanceProcAddr")
|
|
||||||
GetPhysicalDeviceCalibrateableTimeDomainsEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT")
|
GetPhysicalDeviceCalibrateableTimeDomainsEXT = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT")
|
||||||
GetPhysicalDeviceCooperativeMatrixPropertiesNV = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV")
|
GetPhysicalDeviceCooperativeMatrixPropertiesNV = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV")
|
||||||
GetPhysicalDeviceDisplayPlaneProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR")
|
GetPhysicalDeviceDisplayPlaneProperties2KHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR")
|
||||||
@@ -3322,6 +3321,7 @@ load_proc_addresses_global :: proc(vk_get_instance_proc_addr: rawptr) {
|
|||||||
EnumerateInstanceExtensionProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceExtensionProperties")
|
EnumerateInstanceExtensionProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceExtensionProperties")
|
||||||
EnumerateInstanceLayerProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceLayerProperties")
|
EnumerateInstanceLayerProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceLayerProperties")
|
||||||
EnumerateInstanceVersion = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceVersion")
|
EnumerateInstanceVersion = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceVersion")
|
||||||
|
GetInstanceProcAddr = auto_cast GetInstanceProcAddr(nil, "vkGetInstanceProcAddr")
|
||||||
}
|
}
|
||||||
|
|
||||||
load_proc_addresses :: proc{
|
load_proc_addresses :: proc{
|
||||||
|
|||||||
Reference in New Issue
Block a user