Przeglądaj źródła

Merge branch 'master' into windows-llvm-13.0.0

gingerBill 2 lat temu
rodzic
commit
321f6d11bc

+ 86 - 0
core/math/math.odin

@@ -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 {

+ 8 - 8
core/path/filepath/walk.odin

@@ -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

+ 50 - 7
core/runtime/dynamic_map_internal.odin

@@ -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
 }
 

+ 6 - 0
core/sys/windows/kernel32.odin

@@ -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,

+ 8 - 0
core/sys/windows/types.odin

@@ -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

+ 12 - 0
core/sys/windows/wgl.odin

@@ -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
+}

+ 5 - 2
src/checker.cpp

@@ -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)) {

+ 4 - 4
src/exact_value.cpp

@@ -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;
 	}

+ 2 - 8
vendor/OpenGL/README.md

@@ -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)
-```
+```

+ 4 - 0
vendor/darwin/Foundation/NSWindow.odin

@@ -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")