Merge branch 'master' into windows-llvm-13.0.0

This commit is contained in:
gingerBill
2022-12-07 10:35:13 +00:00
10 changed files with 185 additions and 29 deletions

View File

@@ -114,6 +114,92 @@ exp :: proc{
exp_f64, exp_f64le, exp_f64be,
}
pow10_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(pow10_f16(f16(x))) }
pow10_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(pow10_f16(f16(x))) }
pow10_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(pow10_f32(f32(x))) }
pow10_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(pow10_f32(f32(x))) }
pow10_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(pow10_f64(f64(x))) }
pow10_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(pow10_f64(f64(x))) }
pow10 :: proc{
pow10_f16, pow10_f16le, pow10_f16be,
pow10_f32, pow10_f32le, pow10_f32be,
pow10_f64, pow10_f64le, pow10_f64be,
}
pow10_f16 :: proc "contextless" (n: f16) -> f16 {
@static pow10_pos_tab := [?]f16{
1e00, 1e01, 1e02, 1e03, 1e04,
}
@static pow10_neg_tab := [?]f16{
1e-00, 1e-01, 1e-02, 1e-03, 1e-04, 1e-05, 1e-06, 1e-07,
}
if 0 <= n && n <= 4 {
return pow10_pos_tab[uint(n)]
}
if -7 <= n && n <= 0 {
return pow10_neg_tab[uint(-n)]
}
if n > 0 {
return inf_f16(1)
}
return 0
}
pow10_f32 :: proc "contextless" (n: f32) -> f32 {
@static pow10_pos_tab := [?]f32{
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38,
}
@static pow10_neg_tab := [?]f32{
1e-00, 1e-01, 1e-02, 1e-03, 1e-04, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09,
1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19,
1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29,
1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 1e-39,
1e-40, 1e-41, 1e-42, 1e-43, 1e-44, 1e-45,
}
if 0 <= n && n <= 38 {
return pow10_pos_tab[uint(n)]
}
if -45 <= n && n <= 0 {
return pow10_neg_tab[uint(-n)]
}
if n > 0 {
return inf_f32(1)
}
return 0
}
pow10_f64 :: proc "contextless" (n: f64) -> f64 {
@static pow10_tab := [?]f64{
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
1e30, 1e31,
}
@static pow10_pos_tab32 := [?]f64{
1e00, 1e32, 1e64, 1e96, 1e128, 1e160, 1e192, 1e224, 1e256, 1e288,
}
@static pow10_neg_tab32 := [?]f64{
1e-00, 1e-32, 1e-64, 1e-96, 1e-128, 1e-160, 1e-192, 1e-224, 1e-256, 1e-288, 1e-320,
}
if 0 <= n && n <= 308 {
return pow10_pos_tab32[uint(n)/32] * pow10_tab[uint(n)%32]
}
if -323 <= n && n <= 0 {
return pow10_neg_tab32[uint(-n)/32] / pow10_tab[uint(-n)%32]
}
if n > 0 {
return inf_f64(1)
}
return 0
}
ldexp_f64 :: proc "contextless" (val: f64, exp: int) -> f64 {

View File

@@ -14,7 +14,7 @@ import "core:slice"
// The sole exception is if 'skip_dir' is returned as true:
// when 'skip_dir' is invoked on a directory. 'walk' skips directory contents
// when 'skip_dir' is invoked on a non-directory. 'walk' skips the remaining files in the containing directory
Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool)
Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno, user_data: rawptr) -> (err: os.Errno, skip_dir: bool)
// walk walks the file tree rooted at 'root', calling 'walk_proc' for each file or directory in the tree, including 'root'
// All errors that happen visiting files and directories are filtered by walk_proc
@@ -22,28 +22,28 @@ Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno,
// NOTE: Walking large directories can be inefficient due to the lexical sort
// NOTE: walk does not follow symbolic links
// NOTE: os.File_Info uses the 'context.temp_allocator' to allocate, and will delete when it is done
walk :: proc(root: string, walk_proc: Walk_Proc) -> os.Errno {
walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Errno {
info, err := os.lstat(root, context.temp_allocator)
defer os.file_info_delete(info, context.temp_allocator)
skip_dir: bool
if err != 0 {
err, skip_dir = walk_proc(info, err)
err, skip_dir = walk_proc(info, err, user_data)
} else {
err, skip_dir = _walk(info, walk_proc)
err, skip_dir = _walk(info, walk_proc, user_data)
}
return 0 if skip_dir else err
}
@(private)
_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc) -> (err: os.Errno, skip_dir: bool) {
_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Errno, skip_dir: bool) {
if !info.is_dir {
if info.fullpath == "" && info.name == "" {
// ignore empty things
return
}
return walk_proc(info, 0)
return walk_proc(info, 0, user_data)
}
fis: []os.File_Info
@@ -51,14 +51,14 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc) -> (err: os.Errno, skip_
fis, err = read_dir(info.fullpath, context.temp_allocator)
defer os.file_info_slice_delete(fis, context.temp_allocator)
err1, skip_dir = walk_proc(info, err)
err1, skip_dir = walk_proc(info, err, user_data)
if err != 0 || err1 != 0 || skip_dir {
err = err1
return
}
for fi in fis {
err, skip_dir = _walk(fi, walk_proc)
err, skip_dir = _walk(fi, walk_proc, user_data)
if err != 0 || skip_dir {
if !fi.is_dir || !skip_dir {
return

View File

@@ -230,6 +230,8 @@ map_data :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
Map_Hash :: uintptr
TOMBSTONE_MASK :: 1<<(size_of(Map_Hash)*8 - 1)
// Procedure to check if a slot is empty for a given hash. This is represented
// by the zero value to make the zero value useful. This is a procedure just
// for prose reasons.
@@ -241,14 +243,12 @@ map_hash_is_empty :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
@(require_results)
map_hash_is_deleted :: #force_no_inline proc "contextless" (hash: Map_Hash) -> bool {
// The MSB indicates a tombstone
N :: size_of(Map_Hash)*8 - 1
return hash >> N != 0
return hash & TOMBSTONE_MASK != 0
}
@(require_results)
map_hash_is_valid :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
// The MSB indicates a tombstone
N :: size_of(Map_Hash)*8 - 1
return (hash != 0) & (hash >> N == 0)
return (hash != 0) & (hash & TOMBSTONE_MASK == 0)
}
@@ -627,15 +627,58 @@ map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
@(require_results)
map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (old_k, old_v: uintptr, ok: bool) {
MASK :: 1 << (size_of(Map_Hash)*8 - 1)
index := map_lookup_dynamic(m^, info, k) or_return
ks, vs, hs, _, _ := map_kvh_data_dynamic(m^, info)
hs[index] |= MASK
hs[index] |= TOMBSTONE_MASK
old_k = map_cell_index_dynamic(ks, info.ks, index)
old_v = map_cell_index_dynamic(vs, info.vs, index)
m.len -= 1
ok = true
{ // coalesce tombstones
// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots
// TODO(bill): we should do backward shift deletion and not rely on tombstone slots
mask := (uintptr(1)<<map_log2_cap(m^)) - 1
curr_index := uintptr(index)
// TODO(bill): determine a good value for this empirically
// if we do not implement backward shift deletion
PROBE_COUNT :: 8
for _ in 0..<PROBE_COUNT {
next_index := (curr_index + 1) & mask
if next_index == index {
// looped around
break
}
// if the next element is empty or has zero probe distance, then any lookup
// will always fail on the next, so we can clear both of them
hash := hs[next_index]
if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 {
hs[curr_index] = 0
return
}
// now the next element will have a probe count of at least one,
// so it can use the delete slot instead
hs[curr_index] = hs[next_index]
mem_copy_non_overlapping(
rawptr(map_cell_index_dynamic(ks, info.ks, curr_index)),
rawptr(map_cell_index_dynamic(ks, info.ks, next_index)),
int(info.ks.size_of_type),
)
mem_copy_non_overlapping(
rawptr(map_cell_index_dynamic(vs, info.vs, curr_index)),
rawptr(map_cell_index_dynamic(vs, info.vs, next_index)),
int(info.vs.size_of_type),
)
curr_index = next_index
}
hs[curr_index] |= TOMBSTONE_MASK
}
return
}

View File

@@ -120,6 +120,12 @@ foreign kernel32 {
bManualReset: BOOL,
lpTimerName: LPCWSTR,
) -> HANDLE ---
CreateWaitableTimerExW :: proc(
lpTimerAttributes: LPSECURITY_ATTRIBUTES,
lpTimerName: LPCWSTR,
dwFlags: DWORD,
dwDesiredAccess: DWORD,
) -> HANDLE ---
SetWaitableTimerEx :: proc(
hTimer: HANDLE,
lpDueTime: ^LARGE_INTEGER,

View File

@@ -146,6 +146,13 @@ PSRWLOCK :: ^SRWLOCK
MMRESULT :: UINT
CREATE_WAITABLE_TIMER_MANUAL_RESET :: 0x00000001
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION :: 0x00000002
TIMER_QUERY_STATE :: 0x0001
TIMER_MODIFY_STATE :: 0x0002
TIMER_ALL_ACCESS :: STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | TIMER_QUERY_STATE | TIMER_MODIFY_STATE
SOCKET :: distinct uintptr // TODO
socklen_t :: c_int
ADDRESS_FAMILY :: USHORT
@@ -1254,6 +1261,7 @@ SWP_ASYNCWINDOWPOS :: 0x4000 // same as SWP_CREATESPB
CSIDL_APPDATA :: 0x001a // <user name>\Application Data
CSIDL_COMMON_APPDATA :: 0x0023 // All Users\Application Data
CSIDL_PROFILE :: 0x0028 // <user name>\
HWND_TOP :: HWND( uintptr(0)) // 0
HWND_BOTTOM :: HWND( uintptr(1)) // 1

View File

@@ -85,3 +85,15 @@ foreign Opengl32 {
wglUseFontBitmaps :: proc(hdc: HDC, first, count, list_base: DWORD) -> BOOL ---
wglUseFontOutlines :: proc(hdc: HDC, first, count, list_base: DWORD, deviation, extrusion: f32, format: c.int, gmf: LPGLYPHMETRICSFLOAT) -> BOOL ---
}
// Used by vendor:OpenGL
// https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions#Windows
gl_set_proc_address :: proc(p: rawptr, name: cstring) {
func := wglGetProcAddress(name)
switch uintptr(func) {
case 0, 1, 2, 3, ~uintptr(0):
module := LoadLibraryW(L("opengl32.dll"))
func = GetProcAddress(module, name)
}
(^rawptr)(p)^ = func
}

View File

@@ -3248,9 +3248,8 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
}
DECL_ATTRIBUTE_PROC(var_decl_attribute) {
ExactValue ev = check_decl_attribute_value(c, value);
if (name == ATTRIBUTE_USER_TAG_NAME) {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind != ExactValue_String) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
@@ -3262,6 +3261,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
ac->is_static = true;
return true;
} else if (name == "thread_local") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values");
} else if (c->foreign_context.curr_library) {
@@ -3336,6 +3336,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
}
return true;
} else if (name == "link_name") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
ac->link_name = ev.value_string;
if (!is_foreign_name_valid(ac->link_name)) {
@@ -3346,6 +3347,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
}
return true;
} else if (name == "link_prefix") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
ac->link_prefix = ev.value_string;
if (!is_foreign_name_valid(ac->link_prefix)) {
@@ -3356,6 +3358,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
}
return true;
} else if (name == "link_section") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
ac->link_section = ev.value_string;
if (!is_foreign_name_valid(ac->link_section)) {

View File

@@ -952,15 +952,15 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
case ExactValue_Typeid:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
case Token_CmpEq: return x.value_typeid == y.value_typeid;
case Token_NotEq: return x.value_typeid != y.value_typeid;
}
break;
case ExactValue_Procedure:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
case Token_CmpEq: return x.value_typeid == y.value_typeid;
case Token_NotEq: return x.value_typeid != y.value_typeid;
}
break;
}

View File

@@ -7,17 +7,11 @@ Includes procedures to load OpenGL function pointers. Currently only supports th
```go
gl.load_up_to(4, 5, proc(p: rawptr, name: cstring) do (cast(^rawptr)p)^ = glfw.GetProcAddress(name); );
```
[odin-glfw](https://github.com/vassvik/odin-glfw) also provides a useful helper you can pass straight to `gl.load_up_to`:
`vendor:glfw` also provides a useful helper you can pass straight to `gl.load_up_to`:
```go
gl.load_up_to(4, 5, glfw.gl_set_proc_address);
```
#### NOTE: It is recommended to put this into the shared collection:
```
cd /path/to/Odin/shared
git clone https://github.com/vassvik/odin-gl.git
```
## Extra utility procedures (Outdated. See the end of `gl.odin`)
Some useful helper procedures can be found in `helpers.odin`, for tasks such as:
@@ -56,4 +50,4 @@ glGetError() returned NO_ERROR
glGetError() returned NO_ERROR
call: glClearColor(0.800, 0.800, 0.800, 1.000)
in: C:/<snip>/main.odin(272:6)
```
```

View File

@@ -124,6 +124,10 @@ Window_contentView :: proc(self: ^Window) -> ^View {
Window_setContentView :: proc(self: ^Window, content_view: ^View) {
msgSend(nil, self, "setContentView:", content_view)
}
@(objc_type=Window, objc_name="contentLayoutRect")
Window_contentLayoutRect :: proc(self: ^Window) -> Rect {
return msgSend(Rect, self, "contentLayoutRect")
}
@(objc_type=Window, objc_name="frame")
Window_frame :: proc(self: ^Window) -> Rect {
return msgSend(Rect, self, "frame")