diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9c453331..ca3d87b12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,8 +32,8 @@ jobs: gmake -C vendor/stb/src gmake -C vendor/cgltf/src gmake -C vendor/miniaudio/src - ./odin check examples/all -vet -strict-style -target:netbsd_amd64 - ./odin check examples/all -vet -strict-style -target:netbsd_arm64 + ./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_amd64 + ./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_arm64 ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false ./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false @@ -62,7 +62,7 @@ jobs: gmake -C vendor/stb/src gmake -C vendor/cgltf/src gmake -C vendor/miniaudio/src - ./odin check examples/all -vet -strict-style -target:freebsd_amd64 + ./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64 ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false ./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false @@ -97,7 +97,7 @@ jobs: - name: Download LLVM (MacOS ARM) if: matrix.os == 'macos-14' run: | - brew install llvm@17 + brew install llvm@17 wasmtime echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH - name: Build Odin @@ -135,18 +135,24 @@ jobs: ./run.sh - name: Odin check examples/all for Linux i386 - run: ./odin check examples/all -vet -strict-style -target:linux_i386 + run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_i386 if: matrix.os == 'ubuntu-latest' - name: Odin check examples/all for Linux arm64 - run: ./odin check examples/all -vet -strict-style -target:linux_arm64 + run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_arm64 if: matrix.os == 'ubuntu-latest' - name: Odin check examples/all for FreeBSD amd64 - run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64 + run: ./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64 if: matrix.os == 'ubuntu-latest' - name: Odin check examples/all for OpenBSD amd64 - run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64 + run: ./odin check examples/all -vet -strict-style -disallow-do -target:openbsd_amd64 if: matrix.os == 'ubuntu-latest' + - name: Run demo on WASI WASM32 + run: | + ./odin build examples/demo -target:wasi_wasm32 -vet -strict-style -disallow-do -out:demo.wasm + wasmtime ./demo.wasm + if: matrix.os == 'macos-14' + build_windows: name: Windows Build, Check, and Test runs-on: windows-2022 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 0857e99ad..e4bc5d81c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -50,8 +50,8 @@ jobs: run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 17 - echo "/usr/lib/llvm-17/bin" >> $GITHUB_PATH + sudo ./llvm.sh 18 + echo "/usr/lib/llvm-18/bin" >> $GITHUB_PATH - name: build odin run: make nightly - name: Odin run @@ -82,8 +82,8 @@ jobs: - uses: actions/checkout@v4 - name: Download LLVM and setup PATH run: | - brew install llvm@17 dylibbundler - echo "/usr/local/opt/llvm@17/bin" >> $GITHUB_PATH + brew install llvm@18 dylibbundler + echo "/usr/local/opt/llvm@18/bin" >> $GITHUB_PATH - name: build odin # These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to # not link with libunwind bundled with LLVM but link with libunwind on the system. @@ -116,8 +116,8 @@ jobs: - uses: actions/checkout@v4 - name: Download LLVM and setup PATH run: | - brew install llvm@17 dylibbundler - echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH + brew install llvm@18 dylibbundler + echo "/opt/homebrew/opt/llvm@18/bin" >> $GITHUB_PATH - name: build odin # These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to # not link with libunwind bundled with LLVM but link with libunwind on the system. diff --git a/.gitignore b/.gitignore index 2b6b5281a..c8a66d288 100644 --- a/.gitignore +++ b/.gitignore @@ -303,7 +303,7 @@ bin/ # - Linux/MacOS odin !odin/ -odin.dSYM +**/*.dSYM *.bin demo.bin libLLVM*.so* diff --git a/LLVM-C.dll b/LLVM-C.dll index 6393857b4..ee03a2acd 100644 Binary files a/LLVM-C.dll and b/LLVM-C.dll differ diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 4f6fa2713..8a16ca40e 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -73,6 +73,8 @@ expect :: proc(val, expected_val: T) -> T --- // Linux and Darwin Only syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- +// FreeBSD, NetBSD, et cetera +syscall_bsd :: proc(id: uintptr, args: ..uintptr) -> (uintptr, bool) --- // Atomics @@ -192,7 +194,8 @@ type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) --- type_proc_parameter_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) --- type_proc_return_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) --- -type_struct_field_count :: proc($T: typeid) -> int where type_is_struct(T) --- +type_struct_field_count :: proc($T: typeid) -> int where type_is_struct(T) --- +type_struct_has_implicit_padding :: proc($T: typeid) -> bool where type_is_struct(T) --- type_polymorphic_record_parameter_count :: proc($T: typeid) -> typeid --- type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V --- diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 8671920f5..a758a2fdd 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -299,6 +299,8 @@ when ODIN_OS == .Windows { Thread_Detach = 3, } dll_forward_reason: DLL_Forward_Reason + + dll_instance: rawptr } // IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it) @@ -397,11 +399,34 @@ Logger :: struct { options: Logger_Options, } + +Random_Generator_Mode :: enum { + Read, + Reset, + Query_Info, +} + +Random_Generator_Query_Info_Flag :: enum u32 { + Cryptographic, + Uniform, + External_Entropy, + Resettable, +} +Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32] + +Random_Generator_Proc :: #type proc(data: rawptr, mode: Random_Generator_Mode, p: []byte) + +Random_Generator :: struct { + procedure: Random_Generator_Proc, + data: rawptr, +} + Context :: struct { allocator: Allocator, temp_allocator: Allocator, assertion_failure_proc: Assertion_Failure_Proc, logger: Logger, + random_generator: Random_Generator, user_ptr: rawptr, user_index: int, @@ -708,6 +733,9 @@ __init_context :: proc "contextless" (c: ^Context) { c.logger.procedure = default_logger_proc c.logger.data = nil + + c.random_generator.procedure = default_random_generator_proc + c.random_generator.data = nil } default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! { diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index a9566c831..ff87316f2 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -65,7 +65,7 @@ copy :: proc{copy_slice, copy_from_string} // with the old value, and reducing the length of the dynamic array by 1. // // Note: This is an O(1) operation. -// Note: If you the elements to remain in their order, use `ordered_remove`. +// Note: If you want the elements to remain in their order, use `ordered_remove`. // Note: If the index is out of bounds, this procedure will panic. @builtin unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check { @@ -79,7 +79,7 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_loca // `ordered_remove` removed the element at the specified `index` whilst keeping the order of the other elements. // // Note: This is an O(N) operation. -// Note: If you the elements do not have to remain in their order, prefer `unordered_remove`. +// Note: If the elements do not have to remain in their order, prefer `unordered_remove`. // Note: If the index is out of bounds, this procedure will panic. @builtin ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check { @@ -163,21 +163,43 @@ pop_front_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bo // `clear` will set the length of a passed dynamic array or map to `0` @builtin -clear :: proc{clear_dynamic_array, clear_map} +clear :: proc{ + clear_dynamic_array, + clear_map, + + clear_soa_dynamic_array, +} // `reserve` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`). @builtin -reserve :: proc{reserve_dynamic_array, reserve_map} +reserve :: proc{ + reserve_dynamic_array, + reserve_map, + + reserve_soa, +} @builtin -non_zero_reserve :: proc{non_zero_reserve_dynamic_array} +non_zero_reserve :: proc{ + non_zero_reserve_dynamic_array, + + non_zero_reserve_soa, +} // `resize` will try to resize memory of a passed dynamic array to the requested element count (setting the `len`, and possibly `cap`). @builtin -resize :: proc{resize_dynamic_array} +resize :: proc{ + resize_dynamic_array, + + resize_soa, +} @builtin -non_zero_resize :: proc{non_zero_resize_dynamic_array} +non_zero_resize :: proc{ + non_zero_resize_dynamic_array, + + non_zero_resize_soa, +} // Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity. @builtin @@ -268,7 +290,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat return } -DEFAULT_RESERVE_CAPACITY :: 16 +DEFAULT_DYNAMIC_ARRAY_CAPACITY :: 8 @(require_results) make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { @@ -295,7 +317,7 @@ make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allo // Note: Prefer using the procedure group `make`. @(builtin, require_results) make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { - return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc) + return make_dynamic_array_len_cap(T, 0, 0, allocator, loc) } // `make_dynamic_array_len` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it. @@ -364,6 +386,11 @@ make :: proc{ make_dynamic_array_len_cap, make_map, make_multi_pointer, + + make_soa_slice, + make_soa_dynamic_array, + make_soa_dynamic_array_len, + make_soa_dynamic_array_len_cap, } @@ -423,7 +450,8 @@ _append_elem :: #force_inline proc(array: ^$T/[dynamic]$E, arg: E, should_zero: return 1, nil } else { if cap(array) < len(array)+1 { - cap := 2 * cap(array) + max(8, 1) + // Same behavior as _append_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY. + cap := 2 * cap(array) + DEFAULT_DYNAMIC_ARRAY_CAPACITY // do not 'or_return' here as it could be a partial success if should_zero { @@ -472,7 +500,7 @@ _append_elems :: #force_inline proc(array: ^$T/[dynamic]$E, should_zero: bool, l return arg_len, nil } else { if cap(array) < len(array)+arg_len { - cap := 2 * cap(array) + max(8, arg_len) + cap := 2 * cap(array) + max(DEFAULT_DYNAMIC_ARRAY_CAPACITY, arg_len) // do not 'or_return' here as it could be a partial success if should_zero { @@ -540,8 +568,23 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_ } // The append built-in procedure appends elements to the end of a dynamic array -@builtin append :: proc{append_elem, append_elems, append_elem_string} -@builtin non_zero_append :: proc{non_zero_append_elem, non_zero_append_elems, non_zero_append_elem_string} +@builtin append :: proc{ + append_elem, + append_elems, + append_elem_string, + + append_soa_elem, + append_soa_elems, +} + +@builtin non_zero_append :: proc{ + non_zero_append_elem, + non_zero_append_elems, + non_zero_append_elem_string, + + non_zero_append_soa_elem, + non_zero_append_soa_elems, +} @builtin diff --git a/base/runtime/core_builtin_soa.odin b/base/runtime/core_builtin_soa.odin index 547df0a2b..f1b17cbef 100644 --- a/base/runtime/core_builtin_soa.odin +++ b/base/runtime/core_builtin_soa.odin @@ -55,7 +55,7 @@ raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Sl if array == nil { return nil } - field_count := uintptr(intrinsics.type_struct_field_count(E)) + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr)) return } @@ -64,12 +64,7 @@ raw_soa_footer_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) -> (footer: ^Ra if array == nil { return nil } - field_count: uintptr - when intrinsics.type_is_array(E) { - field_count = len(E) - } else { - field_count = uintptr(intrinsics.type_struct_field_count(E)) - } + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) footer = (^Raw_SOA_Footer_Dynamic_Array)(uintptr(array) + field_count*size_of(rawptr)) return } @@ -98,7 +93,7 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc ti = type_info_base(ti) si := &ti.variant.(Type_Info_Struct) - field_count := uintptr(intrinsics.type_struct_field_count(E)) + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) total_size := 0 for i in 0.. (array: T, err: Allocator_Error) #optional_allocator_error { context.allocator = allocator - reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) or_return + reserve_soa(&array, 0, loc) or_return return array, nil } @@ -187,8 +182,28 @@ resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_locat return nil } +@builtin +non_zero_resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error { + if array == nil { + return nil + } + non_zero_reserve_soa(array, length, loc) or_return + footer := raw_soa_footer(array) + footer.len = length + return nil +} + @builtin reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error { + return _reserve_soa(array, capacity, true, loc) +} + +@builtin +non_zero_reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error { + return _reserve_soa(array, capacity, false, loc) +} + +_reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, zero_memory: bool, loc := #caller_location) -> Allocator_Error { if array == nil { return nil } @@ -213,12 +228,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo ti = type_info_base(ti) si := &ti.variant.(Type_Info_Struct) - field_count: uintptr - when intrinsics.type_is_array(E) { - field_count = len(E) - } else { - field_count = uintptr(intrinsics.type_struct_field_count(E)) - } + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) assert(footer.cap == old_cap) old_size := 0 @@ -238,7 +248,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo old_data := (^rawptr)(array)^ new_bytes := array.allocator.procedure( - array.allocator.data, .Alloc, new_size, max_align, + array.allocator.data, .Alloc if zero_memory else .Alloc_Non_Zeroed, new_size, max_align, nil, old_size, loc, ) or_return new_data := raw_data(new_bytes) @@ -273,15 +283,26 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo return nil } + @builtin -append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { + return _append_soa_elem(array, true, arg, loc) +} + +@builtin +non_zero_append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { + return _append_soa_elem(array, false, arg, loc) +} + +_append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, zero_memory: bool, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { if array == nil { return 0, nil } if cap(array) <= len(array) + 1 { - cap := 2 * cap(array) + 8 - err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success + // Same behavior as append_soa_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY. + cap := 2 * cap(array) + DEFAULT_DYNAMIC_ARRAY_CAPACITY + err = _reserve_soa(array, cap, zero_memory, loc) // do not 'or_return' here as it could be a partial success } footer := raw_soa_footer(array) @@ -290,12 +311,7 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat ti := type_info_of(T) ti = type_info_base(ti) si := &ti.variant.(Type_Info_Struct) - field_count: uintptr - when intrinsics.type_is_array(E) { - field_count = len(E) - } else { - field_count = uintptr(intrinsics.type_struct_field_count(E)) - } + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) data := (^rawptr)(array)^ @@ -326,7 +342,17 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat } @builtin -append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { + return _append_soa_elems(array, true, args=args, loc=loc) +} + +@builtin +non_zero_append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { + return _append_soa_elems(array, false, args=args, loc=loc) +} + + +_append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, zero_memory: bool, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { if array == nil { return } @@ -337,8 +363,8 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l } if cap(array) <= len(array)+arg_len { - cap := 2 * cap(array) + max(8, arg_len) - err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success + cap := 2 * cap(array) + max(DEFAULT_DYNAMIC_ARRAY_CAPACITY, arg_len) + err = _reserve_soa(array, cap, zero_memory, loc) // do not 'or_return' here as it could be a partial success } arg_len = min(cap(array)-len(array), arg_len) @@ -347,7 +373,7 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l ti := type_info_of(typeid_of(T)) ti = type_info_base(ti) si := &ti.variant.(Type_Info_Struct) - field_count := uintptr(intrinsics.type_struct_field_count(E)) + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) data := (^rawptr)(array)^ @@ -389,7 +415,8 @@ append_soa :: proc{ delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { - when intrinsics.type_struct_field_count(E) != 0 { + field_count :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E) + when field_count != 0 { array := array ptr := (^rawptr)(&array)^ free(ptr, allocator, loc) or_return @@ -398,7 +425,8 @@ delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc } delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) -> Allocator_Error { - when intrinsics.type_struct_field_count(E) != 0 { + field_count :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E) + when field_count != 0 { array := array ptr := (^rawptr)(&array)^ footer := raw_soa_footer(&array) @@ -416,7 +444,8 @@ delete_soa :: proc{ clear_soa_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) { - when intrinsics.type_struct_field_count(E) != 0 { + field_count :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E) + when field_count != 0 { footer := raw_soa_footer(array) footer.len = 0 } @@ -438,12 +467,7 @@ into_dynamic_soa :: proc(array: $T/#soa[]$E) -> #soa[dynamic]E { allocator = nil_allocator(), } - field_count: uintptr - when intrinsics.type_is_array(E) { - field_count = len(E) - } else { - field_count = uintptr(intrinsics.type_struct_field_count(E)) - } + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) array := array dynamic_data := ([^]rawptr)(&d)[:field_count] @@ -467,12 +491,7 @@ unordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, index: int, loc := #cal ti = type_info_base(ti) si := &ti.variant.(Type_Info_Struct) - field_count: uintptr - when intrinsics.type_is_array(E) { - field_count = len(E) - } else { - field_count = uintptr(intrinsics.type_struct_field_count(E)) - } + field_count := uintptr(len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)) data := uintptr(array) for i in 0.. b32 { context = default_context() - // Populate Windows DLL-specific global + // Populate Windows DLL-specific globals dll_forward_reason = DLL_Forward_Reason(fdwReason) + dll_instance = hinstDLL switch dll_forward_reason { case .Process_Attach: diff --git a/base/runtime/heap_allocator.odin b/base/runtime/heap_allocator.odin index 75f79ab77..cdad8690e 100644 --- a/base/runtime/heap_allocator.odin +++ b/base/runtime/heap_allocator.odin @@ -97,14 +97,14 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, } -heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { +heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr { return _heap_alloc(size, zero_memory) } -heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { +heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr { return _heap_resize(ptr, new_size) } -heap_free :: proc(ptr: rawptr) { +heap_free :: proc "contextless" (ptr: rawptr) { _heap_free(ptr) } \ No newline at end of file diff --git a/base/runtime/heap_allocator_orca.odin b/base/runtime/heap_allocator_orca.odin index c22a67ca1..9e719bcd0 100644 --- a/base/runtime/heap_allocator_orca.odin +++ b/base/runtime/heap_allocator_orca.odin @@ -9,7 +9,7 @@ foreign { @(link_name="realloc") _orca_realloc :: proc "c" (ptr: rawptr, size: int) -> rawptr --- } -_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { +_heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr { if size <= 0 { return nil } @@ -20,10 +20,10 @@ _heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { } } -_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { +_heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr { return _orca_realloc(ptr, new_size) } -_heap_free :: proc(ptr: rawptr) { +_heap_free :: proc "contextless" (ptr: rawptr) { _orca_free(ptr) } diff --git a/base/runtime/heap_allocator_other.odin b/base/runtime/heap_allocator_other.odin index 74536ada9..8a7ad1a47 100644 --- a/base/runtime/heap_allocator_other.odin +++ b/base/runtime/heap_allocator_other.odin @@ -2,14 +2,17 @@ //+private package runtime -_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { +_heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr { + context = default_context() unimplemented("base:runtime 'heap_alloc' procedure is not supported on this platform") } -_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { +_heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr { + context = default_context() unimplemented("base:runtime 'heap_resize' procedure is not supported on this platform") } -_heap_free :: proc(ptr: rawptr) { +_heap_free :: proc "contextless" (ptr: rawptr) { + context = default_context() unimplemented("base:runtime 'heap_free' procedure is not supported on this platform") } diff --git a/base/runtime/heap_allocator_unix.odin b/base/runtime/heap_allocator_unix.odin index a8a4e9169..60af9e761 100644 --- a/base/runtime/heap_allocator_unix.odin +++ b/base/runtime/heap_allocator_unix.odin @@ -16,7 +16,7 @@ foreign libc { @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr --- } -_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { +_heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr { if size <= 0 { return nil } @@ -27,12 +27,12 @@ _heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { } } -_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { +_heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr { // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on // POSIX platforms. Ensure your caller takes this into account. return _unix_realloc(ptr, new_size) } -_heap_free :: proc(ptr: rawptr) { +_heap_free :: proc "contextless" (ptr: rawptr) { _unix_free(ptr) } diff --git a/base/runtime/heap_allocator_windows.odin b/base/runtime/heap_allocator_windows.odin index 2097c3671..e07df7559 100644 --- a/base/runtime/heap_allocator_windows.odin +++ b/base/runtime/heap_allocator_windows.odin @@ -14,11 +14,11 @@ foreign kernel32 { HeapFree :: proc(hHeap: rawptr, dwFlags: u32, lpMem: rawptr) -> b32 --- } -_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { +_heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr { HEAP_ZERO_MEMORY :: 0x00000008 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY if zero_memory else 0, uint(size)) } -_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { +_heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr { if new_size == 0 { _heap_free(ptr) return nil @@ -30,7 +30,7 @@ _heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { HEAP_ZERO_MEMORY :: 0x00000008 return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, uint(new_size)) } -_heap_free :: proc(ptr: rawptr) { +_heap_free :: proc "contextless" (ptr: rawptr) { if ptr == nil { return } diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 378eea256..1a97ade09 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -1,3 +1,4 @@ +//+vet !cast package runtime import "base:intrinsics" @@ -29,7 +30,7 @@ is_power_of_two_int :: #force_inline proc "contextless" (x: int) -> bool { return (x & (x-1)) == 0 } -align_forward_int :: #force_inline proc(ptr, align: int) -> int { +align_forward_int :: #force_inline proc "odin" (ptr, align: int) -> int { assert(is_power_of_two_int(align)) p := ptr @@ -47,7 +48,7 @@ is_power_of_two_uint :: #force_inline proc "contextless" (x: uint) -> bool { return (x & (x-1)) == 0 } -align_forward_uint :: #force_inline proc(ptr, align: uint) -> uint { +align_forward_uint :: #force_inline proc "odin" (ptr, align: uint) -> uint { assert(is_power_of_two_uint(align)) p := ptr @@ -65,7 +66,7 @@ is_power_of_two_uintptr :: #force_inline proc "contextless" (x: uintptr) -> bool return (x & (x-1)) == 0 } -align_forward_uintptr :: #force_inline proc(ptr, align: uintptr) -> uintptr { +align_forward_uintptr :: #force_inline proc "odin" (ptr, align: uintptr) -> uintptr { assert(is_power_of_two_uintptr(align)) p := ptr @@ -642,21 +643,24 @@ abs_quaternion256 :: #force_inline proc "contextless" (x: quaternion256) -> f64 quo_complex32 :: proc "contextless" (n, m: complex32) -> complex32 { - e, f: f16 + nr, ni := f32(real(n)), f32(imag(n)) + mr, mi := f32(real(m)), f32(imag(m)) - if abs(real(m)) >= abs(imag(m)) { - ratio := imag(m) / real(m) - denom := real(m) + ratio*imag(m) - e = (real(n) + imag(n)*ratio) / denom - f = (imag(n) - real(n)*ratio) / denom + e, f: f32 + + if abs(mr) >= abs(mi) { + ratio := mi / mr + denom := mr + ratio*mi + e = (nr + ni*ratio) / denom + f = (ni - nr*ratio) / denom } else { - ratio := real(m) / imag(m) - denom := imag(m) + ratio*real(m) - e = (real(n)*ratio + imag(n)) / denom - f = (imag(n)*ratio - real(n)) / denom + ratio := mr / mi + denom := mi + ratio*mr + e = (nr*ratio + ni) / denom + f = (ni*ratio - nr) / denom } - return complex(e, f) + return complex(f16(e), f16(f)) } @@ -697,15 +701,15 @@ quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 { } mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { - q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q) - r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r) + q0, q1, q2, q3 := f32(real(q)), f32(imag(q)), f32(jmag(q)), f32(kmag(q)) + r0, r1, r2, r3 := f32(real(r)), f32(imag(r)), f32(jmag(r)), f32(kmag(r)) t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3 t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2 t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1 t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0 - return quaternion(w=t0, x=t1, y=t2, z=t3) + return quaternion(w=f16(t0), x=f16(t1), y=f16(t2), z=f16(t3)) } mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { @@ -733,8 +737,8 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { } quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { - q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q) - r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r) + q0, q1, q2, q3 := f32(real(q)), f32(imag(q)), f32(jmag(q)), f32(kmag(q)) + r0, r1, r2, r3 := f32(real(r)), f32(imag(r)), f32(jmag(r)), f32(kmag(r)) invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3) @@ -743,7 +747,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2 t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2 - return quaternion(w=t0, x=t1, y=t2, z=t3) + return quaternion(w=f16(t0), x=f16(t1), y=f16(t2), z=f16(t3)) } quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { @@ -1012,26 +1016,26 @@ modti3 :: proc "c" (a, b: i128) -> i128 { bn := (b ~ s_b) - s_b r: u128 = --- - _ = udivmod128(transmute(u128)an, transmute(u128)bn, &r) - return (transmute(i128)r ~ s_a) - s_a + _ = udivmod128(u128(an), u128(bn), &r) + return (i128(r) ~ s_a) - s_a } @(link_name="__divmodti4", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) divmodti4 :: proc "c" (a, b: i128, rem: ^i128) -> i128 { - u := udivmod128(transmute(u128)a, transmute(u128)b, cast(^u128)rem) - return transmute(i128)u + u := udivmod128(u128(a), u128(b), (^u128)(rem)) + return i128(u) } @(link_name="__divti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) divti3 :: proc "c" (a, b: i128) -> i128 { - u := udivmodti4(transmute(u128)a, transmute(u128)b, nil) - return transmute(i128)u + u := udivmodti4(u128(a), u128(b), nil) + return i128(u) } @(link_name="__fixdfti", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) -fixdfti :: proc(a: u64) -> i128 { +fixdfti :: proc "c" (a: u64) -> i128 { significandBits :: 52 typeWidth :: (size_of(u64)*8) exponentBits :: (typeWidth - significandBits - 1) diff --git a/base/runtime/os_specific_darwin.odin b/base/runtime/os_specific_darwin.odin index 61c17a597..1bf29e785 100644 --- a/base/runtime/os_specific_darwin.odin +++ b/base/runtime/os_specific_darwin.odin @@ -5,11 +5,24 @@ package runtime import "base:intrinsics" _stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { - WRITE :: 0x2000004 STDERR :: 2 - ret := intrinsics.syscall(WRITE, STDERR, uintptr(raw_data(data)), uintptr(len(data))) - if ret < 0 { - return 0, _OS_Errno(-ret) + when ODIN_NO_CRT { + WRITE :: 0x2000004 + ret := intrinsics.syscall(WRITE, STDERR, uintptr(raw_data(data)), uintptr(len(data))) + if ret < 0 { + return 0, _OS_Errno(-ret) + } + return int(ret), 0 + } else { + foreign { + write :: proc(handle: i32, buffer: [^]byte, count: uint) -> int --- + __error :: proc() -> ^i32 --- + } + + if ret := write(STDERR, raw_data(data), len(data)); ret >= 0 { + return int(ret), 0 + } + + return 0, _OS_Errno(__error()^) } - return int(ret), 0 } diff --git a/base/runtime/os_specific_wasi.odin b/base/runtime/os_specific_wasi.odin index 0e229ac7e..b85d7adea 100644 --- a/base/runtime/os_specific_wasi.odin +++ b/base/runtime/os_specific_wasi.odin @@ -2,10 +2,54 @@ //+private package runtime -import "core:sys/wasm/wasi" +foreign import wasi "wasi_snapshot_preview1" + +@(default_calling_convention="contextless") +foreign wasi { + fd_write :: proc( + fd: i32, + iovs: [][]byte, + n: ^uint, + ) -> u16 --- + + @(private="file") + args_sizes_get :: proc( + num_of_args: ^uint, + size_of_args: ^uint, + ) -> u16 --- + + @(private="file") + args_get :: proc( + argv: [^]cstring, + argv_buf: [^]byte, + ) -> u16 --- +} _stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { - data_iovec := (wasi.ciovec_t)(data) - n, err := wasi.fd_write(1, {data_iovec}) + n: uint + err := fd_write(1, {data}, &n) return int(n), _OS_Errno(err) } + +_wasi_setup_args :: proc() { + num_of_args, size_of_args: uint + if errno := args_sizes_get(&num_of_args, &size_of_args); errno != 0 { + return + } + + err: Allocator_Error + if args__, err = make([]cstring, num_of_args); err != nil { + return + } + + args_buf: []byte + if args_buf, err = make([]byte, size_of_args); err != nil { + delete(args__) + return + } + + if errno := args_get(raw_data(args__), raw_data(args_buf)); errno != 0 { + delete(args__) + delete(args_buf) + } +} diff --git a/base/runtime/print.odin b/base/runtime/print.odin index ed5893e15..0262e8ef6 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -262,7 +262,7 @@ print_typeid :: #force_no_inline proc "contextless" (id: typeid) { } } -@(optimization_mode="size") +@(optimization_mode="favor_size") print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { if ti == nil { print_string("nil") diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin new file mode 100644 index 000000000..0c4c92bd2 --- /dev/null +++ b/base/runtime/random_generator.odin @@ -0,0 +1,127 @@ +package runtime + +import "base:intrinsics" + +@(require_results) +random_generator_read_bytes :: proc(rg: Random_Generator, p: []byte) -> bool { + if rg.procedure != nil { + rg.procedure(rg.data, .Read, p) + return true + } + return false +} + +@(require_results) +random_generator_read_ptr :: proc(rg: Random_Generator, p: rawptr, len: uint) -> bool { + if rg.procedure != nil { + rg.procedure(rg.data, .Read, ([^]byte)(p)[:len]) + return true + } + return false +} + +@(require_results) +random_generator_query_info :: proc(rg: Random_Generator) -> (info: Random_Generator_Query_Info) { + if rg.procedure != nil { + rg.procedure(rg.data, .Query_Info, ([^]byte)(&info)[:size_of(info)]) + } + return +} + + +random_generator_reset_bytes :: proc(rg: Random_Generator, p: []byte) { + if rg.procedure != nil { + rg.procedure(rg.data, .Reset, p) + } +} + +random_generator_reset_u64 :: proc(rg: Random_Generator, p: u64) { + if rg.procedure != nil { + p := p + rg.procedure(rg.data, .Reset, ([^]byte)(&p)[:size_of(p)]) + } +} + + +Default_Random_State :: struct { + state: u64, + inc: u64, +} + +default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte) { + @(require_results) + read_u64 :: proc "contextless" (r: ^Default_Random_State) -> u64 { + old_state := r.state + r.state = old_state * 6364136223846793005 + (r.inc|1) + xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081 + rot := (old_state >> 59) + return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63)) + } + + @(thread_local) + global_rand_seed: Default_Random_State + + init :: proc "contextless" (r: ^Default_Random_State, seed: u64) { + seed := seed + if seed == 0 { + seed = u64(intrinsics.read_cycle_counter()) + } + r.state = 0 + r.inc = (seed << 1) | 1 + _ = read_u64(r) + r.state += seed + _ = read_u64(r) + } + + r: ^Default_Random_State = --- + if data == nil { + r = &global_rand_seed + } else { + r = cast(^Default_Random_State)data + } + + switch mode { + case .Read: + if r.state == 0 && r.inc == 0 { + init(r, 0) + } + + switch len(p) { + case size_of(u64): + // Fast path for a 64-bit destination. + intrinsics.unaligned_store((^u64)(raw_data(p)), read_u64(r)) + case: + // All other cases. + pos := i8(0) + val := u64(0) + for &v in p { + if pos == 0 { + val = read_u64(r) + pos = 7 + } + v = byte(val) + val >>= 8 + pos -= 1 + } + } + + case .Reset: + seed: u64 + mem_copy_non_overlapping(&seed, raw_data(p), min(size_of(seed), len(p))) + init(r, seed) + + case .Query_Info: + if len(p) != size_of(Random_Generator_Query_Info) { + return + } + info := (^Random_Generator_Query_Info)(raw_data(p)) + info^ += {.Uniform, .Resettable} + } +} + +default_random_generator :: proc "contextless" (state: ^Default_Random_State = nil) -> Random_Generator { + return { + procedure = default_random_generator_proc, + data = state, + } +} \ No newline at end of file diff --git a/base/runtime/udivmod128.odin b/base/runtime/udivmod128.odin index eceb815bf..8cc70df55 100644 --- a/base/runtime/udivmod128.odin +++ b/base/runtime/udivmod128.odin @@ -58,7 +58,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 { return u128(n[high] >> _ctz(d[high])) } - sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high]))) + sr = u32(i32(_clz(d[high])) - i32(_clz(n[high]))) if sr > U64_BITS - 2 { if rem != nil { rem^ = a @@ -107,7 +107,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 { r[low] = n[high] >> (sr - U64_BITS) } } else { - sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high]))) + sr = u32(i32(_clz(d[high])) - i32(_clz(n[high]))) if sr > U64_BITS - 1 { if rem != nil { @@ -143,7 +143,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 { r_all = transmute(u128)r s := i128(b - r_all - 1) >> (U128_BITS - 1) carry = u32(s & 1) - r_all -= b & transmute(u128)s + r_all -= b & u128(s) r = transmute([2]u64)r_all } diff --git a/base/runtime/wasm_allocator.odin b/base/runtime/wasm_allocator.odin index 6bca0b3d6..f4b399c47 100644 --- a/base/runtime/wasm_allocator.odin +++ b/base/runtime/wasm_allocator.odin @@ -495,7 +495,7 @@ claim_more_memory :: proc(a: ^WASM_Allocator, num_bytes: uint) -> bool { // we can just extend the spill. spill_end := uintptr(raw_data(a.spill)) + uintptr(len(a.spill)) if spill_end == uintptr(raw_data(allocated)) { - raw_spill := transmute(^Raw_Slice)(&a.spill) + raw_spill := (^Raw_Slice)(&a.spill) raw_spill.len += len(allocated) } else { // Otherwise, we have to "waste" the previous spill. @@ -679,7 +679,7 @@ allocate_memory :: proc(a: ^WASM_Allocator, alignment: uint, size: uint, loc := // but we just had a stale bit set to mark a populated bucket. // Reset the bit to update latest status so that we do not // redundantly look at this bucket again. - a.free_region_buckets_used &= ~(BUCKET_BITMASK_T(1) << bucket_index) + a.free_region_buckets_used &~= BUCKET_BITMASK_T(1) << bucket_index bucket_mask ~= 1 } @@ -760,7 +760,7 @@ free :: proc(a: ^WASM_Allocator, ptr: rawptr, loc := #caller_location) { defer unlock(a) size := region.size - assert(region_is_in_use(region), "double free", loc=loc) + assert(region_is_in_use(region), "double free or corrupt region", loc=loc) prev_region_size_field := ([^]uint)(region)[-1] prev_region_size := prev_region_size_field & ~uint(FREE_REGION_FLAG) diff --git a/bin/llvm/windows/LLVM-C.lib b/bin/llvm/windows/LLVM-C.lib index bd57594f3..0e5b6c624 100644 Binary files a/bin/llvm/windows/LLVM-C.lib and b/bin/llvm/windows/LLVM-C.lib differ diff --git a/bin/llvm/windows/clang_rt.asan-x86_64.lib b/bin/llvm/windows/clang_rt.asan-x86_64.lib index 9b6971395..0b209dc8d 100644 Binary files a/bin/llvm/windows/clang_rt.asan-x86_64.lib and b/bin/llvm/windows/clang_rt.asan-x86_64.lib differ diff --git a/build.bat b/build.bat index 050789bbc..bddde49c8 100644 --- a/build.bat +++ b/build.bat @@ -48,6 +48,9 @@ if "%2" == "1" ( set odin_version_raw="dev-%curr_year%-%curr_month%" set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF +rem Parse source code as utf-8 even on shift-jis and other codepages +rem See https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170 +set compiler_flags= %compiler_flags% /utf-8 set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\" if not exist .git\ goto skip_git_hash @@ -111,7 +114,7 @@ call build_vendor.bat if %errorlevel% neq 0 goto end_of_build rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native -if %release_mode% EQU 0 odin run examples/demo -- Hellope World +if %release_mode% EQU 0 odin run examples/demo -vet -strict-style -- Hellope World del *.obj > NUL 2> NUL diff --git a/build_odin.sh b/build_odin.sh index d2f865e24..125b9335a 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -144,7 +144,7 @@ build_odin() { } run_demo() { - ./odin run examples/demo/demo.odin -file -- Hellope World + ./odin run examples/demo -vet -strict-style -- Hellope World } if [ $# -eq 0 ]; then diff --git a/core/c/libc/signal.odin b/core/c/libc/signal.odin index 1489779fe..c447e3cc3 100644 --- a/core/c/libc/signal.odin +++ b/core/c/libc/signal.odin @@ -34,20 +34,7 @@ when ODIN_OS == .Windows { SIGTERM :: 15 } -when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Haiku || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { - SIG_ERR :: rawptr(~uintptr(0)) - SIG_DFL :: rawptr(uintptr(0)) - SIG_IGN :: rawptr(uintptr(1)) - - SIGABRT :: 6 - SIGFPE :: 8 - SIGILL :: 4 - SIGINT :: 2 - SIGSEGV :: 11 - SIGTERM :: 15 -} - -when ODIN_OS == .Darwin { +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Haiku || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Darwin { SIG_ERR :: rawptr(~uintptr(0)) SIG_DFL :: rawptr(uintptr(0)) SIG_IGN :: rawptr(uintptr(1)) diff --git a/core/compress/common.odin b/core/compress/common.odin index b22172e61..242538e78 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -34,13 +34,13 @@ COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 2 */ when size_of(uintptr) == 8 { - // For 64-bit platforms, we set the default max buffer size to 4 GiB, - // which is GZIP and PKZIP's max payload size. + // For 64-bit platforms, we set the default max buffer size to 4 GiB, + // which is GZIP and PKZIP's max payload size. COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 32)) } else { // For 32-bit platforms, we set the default max buffer size to 512 MiB. - COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29)) + COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29)) } @@ -186,7 +186,7 @@ input_size_from_stream :: proc(z: ^Context_Stream_Input) -> (res: i64, err: Erro input_size :: proc{input_size_from_memory, input_size_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int) -> (res: []u8, err: io.Error) { #no_bounds_check { if len(z.input_data) >= size { @@ -203,7 +203,7 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) { // TODO: REMOVE ALL USE OF context.temp_allocator here // there is literally no need for it @@ -214,13 +214,13 @@ read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int read_slice :: proc{read_slice_from_memory, read_slice_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) { b := read_slice(z, size_of(T)) or_return return (^T)(&b[0])^, nil } -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8, err: io.Error) { #no_bounds_check { if len(z.input_data) >= 1 { @@ -232,7 +232,7 @@ read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8, return 0, .EOF } -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) { b := read_slice_from_stream(z, 1) or_return return b[0], nil @@ -242,7 +242,7 @@ read_u8 :: proc{read_u8_from_memory, read_u8_from_stream} // You would typically only use this at the end of Inflate, to drain bits from the code buffer // preferentially. -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: io.Error) { if z.num_bits >= 8 { res = u8(read_bits_no_refill_lsb(z, 8)) @@ -257,7 +257,7 @@ read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: i return } -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid) -> (res: T, err: io.Error) { size :: size_of(T) @@ -275,7 +275,7 @@ peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_data_at_offset_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) { size :: size_of(T) @@ -293,7 +293,7 @@ peek_data_at_offset_from_memory :: #force_inline proc(z: ^Context_Memory_Input, } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) { size :: size_of(T) @@ -317,7 +317,7 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid return res, .None } -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) { size :: size_of(T) @@ -352,14 +352,14 @@ peek_data :: proc{peek_data_from_memory, peek_data_from_stream, peek_data_at_off // Sliding window read back -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_back_byte :: #force_inline proc(z: ^$C, offset: i64) -> (res: u8, err: io.Error) { // Look back into the sliding window. return z.output.buf[z.bytes_written - offset], .None } // Generalized bit reader LSB -@(optimization_mode="speed") +@(optimization_mode="favor_size") refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width := i8(48)) { refill := u64(width) b := u64(0) @@ -385,7 +385,7 @@ refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width := } // Generalized bit reader LSB -@(optimization_mode="speed") +@(optimization_mode="favor_size") refill_lsb_from_stream :: proc(z: ^Context_Stream_Input, width := i8(24)) { refill := u64(width) @@ -414,13 +414,13 @@ refill_lsb_from_stream :: proc(z: ^Context_Stream_Input, width := i8(24)) { refill_lsb :: proc{refill_lsb_from_memory, refill_lsb_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") consume_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) { z.code_buffer >>= width z.num_bits -= u64(width) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") consume_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) { z.code_buffer >>= width z.num_bits -= u64(width) @@ -428,7 +428,7 @@ consume_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, wid consume_bits_lsb :: proc{consume_bits_lsb_from_memory, consume_bits_lsb_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 { if z.num_bits < u64(width) { refill_lsb(z) @@ -436,7 +436,7 @@ peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: return u32(z.code_buffer &~ (~u64(0) << width)) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 { if z.num_bits < u64(width) { refill_lsb(z) @@ -446,13 +446,13 @@ peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 { assert(z.num_bits >= u64(width)) return u32(z.code_buffer &~ (~u64(0) << width)) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 { assert(z.num_bits >= u64(width)) return u32(z.code_buffer &~ (~u64(0) << width)) @@ -460,14 +460,14 @@ peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Inp peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 { k := #force_inline peek_bits_lsb(z, width) #force_inline consume_bits_lsb(z, width) return k } -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 { k := peek_bits_lsb(z, width) consume_bits_lsb(z, width) @@ -476,14 +476,14 @@ read_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: read_bits_lsb :: proc{read_bits_lsb_from_memory, read_bits_lsb_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 { k := #force_inline peek_bits_no_refill_lsb(z, width) #force_inline consume_bits_lsb(z, width) return k } -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 { k := peek_bits_no_refill_lsb(z, width) consume_bits_lsb(z, width) @@ -493,14 +493,14 @@ read_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Inp read_bits_no_refill_lsb :: proc{read_bits_no_refill_lsb_from_memory, read_bits_no_refill_lsb_from_stream} -@(optimization_mode="speed") +@(optimization_mode="favor_size") discard_to_next_byte_lsb_from_memory :: proc(z: ^Context_Memory_Input) { discard := u8(z.num_bits & 7) #force_inline consume_bits_lsb(z, discard) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) { discard := u8(z.num_bits & 7) consume_bits_lsb(z, discard) diff --git a/core/compress/shoco/shoco.odin b/core/compress/shoco/shoco.odin index 3c1f412ba..269dd8875 100644 --- a/core/compress/shoco/shoco.odin +++ b/core/compress/shoco/shoco.odin @@ -98,7 +98,7 @@ decompress_slice_to_output_buffer :: proc(input: []u8, output: []u8, model := DE validate_model(model) or_return for inp < inp_end { - val := transmute(i8)input[inp] + val := i8(input[inp]) mark := int(-1) for val < 0 { @@ -274,12 +274,9 @@ compress_string_to_buffer :: proc(input: string, output: []u8, model := DEFAULT_ out_ptr := raw_data(output[out:]) switch pack.bytes_packed { - case 4: - intrinsics.unaligned_store(transmute(^u32)out_ptr, code) - case 2: - intrinsics.unaligned_store(transmute(^u16)out_ptr, u16(code)) - case 1: - intrinsics.unaligned_store(transmute(^u8)out_ptr, u8(code)) + case 4: intrinsics.unaligned_store((^u32)(out_ptr), code) + case 2: intrinsics.unaligned_store((^u16)(out_ptr), u16(code)) + case 1: intrinsics.unaligned_store( (^u8)(out_ptr), u8(code)) case: return out, .Unknown_Compression_Method } diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index b7f381f2b..005267d15 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -120,7 +120,7 @@ Huffman_Table :: struct { } // Implementation starts here -@(optimization_mode="speed") +@(optimization_mode="favor_size") z_bit_reverse :: #force_inline proc(n: u16, bits: u8) -> (r: u16) { assert(bits <= 16) // NOTE: Can optimize with llvm.bitreverse.i64 or some bit twiddling @@ -136,7 +136,7 @@ z_bit_reverse :: #force_inline proc(n: u16, bits: u8) -> (r: u16) { } -@(optimization_mode="speed") +@(optimization_mode="favor_size") grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) { /* That we get here at all means that we didn't pass an expected output size, @@ -154,7 +154,7 @@ grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) { TODO: Make these return compress.Error. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_check { /* Resize if needed. @@ -173,7 +173,7 @@ write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_ch return .None } -@(optimization_mode="speed") +@(optimization_mode="favor_size") repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check { /* TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it @@ -201,7 +201,7 @@ repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check return .None } -@(optimization_mode="speed") +@(optimization_mode="favor_size") repl_bytes :: proc(z: ^$C, count: u16, distance: u16) -> (err: io.Error) { /* TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it @@ -234,7 +234,7 @@ allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_T return new(Huffman_Table, allocator), nil } -@(optimization_mode="speed") +@(optimization_mode="favor_size") build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) { sizes: [HUFFMAN_MAX_BITS+1]int next_code: [HUFFMAN_MAX_BITS+1]int @@ -293,7 +293,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) { return nil } -@(optimization_mode="speed") +@(optimization_mode="favor_size") decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check { code := u16(compress.peek_bits_lsb(z,16)) @@ -324,7 +324,7 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro return r, nil } -@(optimization_mode="speed") +@(optimization_mode="favor_size") decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check { if z.num_bits < 16 { if z.num_bits > 63 { @@ -344,7 +344,7 @@ decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bo return decode_huffman_slowpath(z, t) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: Error) #no_bounds_check { #no_bounds_check for { value, e := decode_huffman(z, z_repeat) @@ -413,7 +413,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := false, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check { /* ctx.output must be a bytes.Buffer for now. We'll add a separate implementation that writes to a stream. @@ -486,7 +486,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f // TODO: Check alignment of reserve/resize. -@(optimization_mode="speed") +@(optimization_mode="favor_size") inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check { context.allocator = allocator expected_output_size := expected_output_size diff --git a/core/container/avl/avl.odin b/core/container/avl/avl.odin index 582cd87fd..8a9d1f3d9 100644 --- a/core/container/avl/avl.odin +++ b/core/container/avl/avl.odin @@ -87,7 +87,7 @@ init_cmp :: proc( init_ordered :: proc( t: ^$T/Tree($Value), node_allocator := context.allocator, -) where intrinsics.type_is_ordered_numeric(Value) { +) where intrinsics.type_is_ordered(Value) { init_cmp(t, slice.cmp_proc(Value), node_allocator) } diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index a8720715c..b53bacda7 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -210,8 +210,11 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator ba.max_index = max(idx, ba.max_index) - if set_to{ ba.bits[leg_index] |= 1 << uint(bit_index) } - else { ba.bits[leg_index] &= ~(1 << uint(bit_index)) } + if set_to { + ba.bits[leg_index] |= 1 << uint(bit_index) + } else { + ba.bits[leg_index] &~= 1 << uint(bit_index) + } return true } @@ -253,7 +256,7 @@ Inputs: - index: Which bit in the array */ unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check { - b.bits[bit >> INDEX_SHIFT] &= ~(1 << uint(bit & INDEX_MASK)) + b.bits[bit >> INDEX_SHIFT] &~= 1 << uint(bit & INDEX_MASK) } /* A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative). diff --git a/core/container/lru/lru_cache.odin b/core/container/lru/lru_cache.odin index 23f01fac3..f8aa55dc2 100644 --- a/core/container/lru/lru_cache.odin +++ b/core/container/lru/lru_cache.odin @@ -70,8 +70,7 @@ set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Alloc if c.count == c.capacity { e = c.tail _remove_node(c, e) - } - else { + } else { c.count += 1 e = new(Node(Key, Value), c.node_allocator) or_return } diff --git a/core/container/queue/queue.odin b/core/container/queue/queue.odin index e46dccb33..e7a60dde0 100644 --- a/core/container/queue/queue.odin +++ b/core/container/queue/queue.odin @@ -189,7 +189,7 @@ pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { return } -// Push multiple elements to the front of the queue +// Push multiple elements to the back of the queue push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error) { n := uint(builtin.len(elems)) if space(q^) < int(n) { @@ -241,7 +241,7 @@ clear :: proc(q: ^$Q/Queue($T)) { } -// Internal growinh procedure +// Internal growing procedure _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error { new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2) n := uint(builtin.len(q.data)) diff --git a/core/container/rbtree/rbtree.odin b/core/container/rbtree/rbtree.odin index 8ab131b3b..090551367 100644 --- a/core/container/rbtree/rbtree.odin +++ b/core/container/rbtree/rbtree.odin @@ -29,7 +29,7 @@ Tree :: struct($Key: typeid, $Value: typeid) { _root: ^Node(Key, Value), _node_allocator: runtime.Allocator, - _cmp_fn: proc(Key, Key) -> Ordering, + _cmp_fn: proc(Key, Key) -> Ordering, _size: int, } @@ -79,7 +79,7 @@ init_cmp :: proc(t: ^$T/Tree($Key, $Value), cmp_fn: proc(a, b: Key) -> Ordering, // init_ordered initializes a tree containing ordered keys, with // a comparison function that results in an ascending order sort. -init_ordered :: proc(t: ^$T/Tree($Key, $Value), node_allocator := context.allocator) where intrinsics.type_is_ordered_numeric(Key) { +init_ordered :: proc(t: ^$T/Tree($Key, $Value), node_allocator := context.allocator) where intrinsics.type_is_ordered(Key) { init_cmp(t, slice.cmp_proc(Key), node_allocator) } diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index ecec7b80c..b2068469d 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -119,20 +119,20 @@ consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_l } ordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check { - runtime.bounds_check_error_loc(loc, index, a.len) - if index+1 < a.len { + runtime.bounds_check_error_loc(loc, index, a.len) + if index+1 < a.len { copy(a.data[index:], a.data[index+1:]) } a.len -= 1 } unordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check { - runtime.bounds_check_error_loc(loc, index, a.len) + runtime.bounds_check_error_loc(loc, index, a.len) n := a.len-1 if index != n { a.data[index] = a.data[n] } - a.len -= 1 + a.len -= 1 } clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) { diff --git a/core/container/topological_sort/topological_sort.odin b/core/container/topological_sort/topological_sort.odin index 0d34e8d02..10765958e 100644 --- a/core/container/topological_sort/topological_sort.odin +++ b/core/container/topological_sort/topological_sort.odin @@ -61,7 +61,7 @@ add_dependency :: proc(sorter: ^$S/Sorter($K), key, dependency: K) -> bool { } find.dependents[key] = true - find = &sorter.relations[key] + find = &sorter.relations[key] if find == nil { find = map_insert(&sorter.relations, key, make_relations(sorter)) } diff --git a/core/crypto/_edwards25519/edwards25519.odin b/core/crypto/_edwards25519/edwards25519.odin index 952bb9ef8..6495f7a3a 100644 --- a/core/crypto/_edwards25519/edwards25519.odin +++ b/core/crypto/_edwards25519/edwards25519.odin @@ -110,7 +110,7 @@ ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { if len(b) != 32 { intrinsics.trap() } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) // Do the work in a scratch element, so that ge is unchanged on // failure. @@ -169,7 +169,7 @@ ge_bytes :: proc "contextless" (ge: ^Group_Element, dst: []byte) { if len(dst) != 32 { intrinsics.trap() } - dst_ := transmute(^[32]byte)(raw_data(dst)) + dst_ := (^[32]byte)(raw_data(dst)) // Convert the element to affine (x, y) representation. x, y, z_inv: field.Tight_Field_Element = ---, ---, --- diff --git a/core/crypto/_edwards25519/edwards25519_scalar.odin b/core/crypto/_edwards25519/edwards25519_scalar.odin index 2644fe5f7..e21fa3755 100644 --- a/core/crypto/_edwards25519/edwards25519_scalar.odin +++ b/core/crypto/_edwards25519/edwards25519_scalar.odin @@ -28,7 +28,7 @@ sc_set_bytes :: proc "contextless" (sc: ^Scalar, b: []byte) -> bool { if len(b) != 32 { intrinsics.trap() } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) return field.fe_from_bytes(sc, b_) } @@ -36,7 +36,7 @@ sc_set_bytes_rfc8032 :: proc "contextless" (sc: ^Scalar, b: []byte) { if len(b) != 32 { intrinsics.trap() } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) field.fe_from_bytes_rfc8032(sc, b_) } diff --git a/core/crypto/_fiat/field_curve25519/field.odin b/core/crypto/_fiat/field_curve25519/field.odin index 8a8202ac4..04fc87659 100644 --- a/core/crypto/_fiat/field_curve25519/field.odin +++ b/core/crypto/_fiat/field_curve25519/field.odin @@ -6,13 +6,13 @@ import "core:mem" fe_relax_cast :: #force_inline proc "contextless" ( arg1: ^Tight_Field_Element, ) -> ^Loose_Field_Element { - return transmute(^Loose_Field_Element)(arg1) + return (^Loose_Field_Element)(arg1) } fe_tighten_cast :: #force_inline proc "contextless" ( arg1: ^Loose_Field_Element, ) -> ^Tight_Field_Element { - return transmute(^Tight_Field_Element)(arg1) + return (^Tight_Field_Element)(arg1) } fe_clear :: proc "contextless" ( diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index c50a56b0c..b12046858 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -7,13 +7,13 @@ import "core:mem" fe_relax_cast :: #force_inline proc "contextless" ( arg1: ^Tight_Field_Element, ) -> ^Loose_Field_Element { - return transmute(^Loose_Field_Element)(arg1) + return (^Loose_Field_Element)(arg1) } fe_tighten_cast :: #force_inline proc "contextless" ( arg1: ^Loose_Field_Element, ) -> ^Tight_Field_Element { - return transmute(^Tight_Field_Element)(arg1) + return (^Tight_Field_Element)(arg1) } fe_from_bytes :: #force_inline proc "contextless" ( diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin index f0874cc6d..f83d20dd7 100644 --- a/core/crypto/crypto.odin +++ b/core/crypto/crypto.odin @@ -4,6 +4,7 @@ helper routines. */ package crypto +import "base:runtime" import "core:mem" // compare_constant_time returns 1 iff a and b are equal, 0 otherwise. @@ -58,3 +59,24 @@ rand_bytes :: proc (dst: []byte) { _rand_bytes(dst) } + + +random_generator :: proc() -> runtime.Random_Generator { + return { + procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) { + switch mode { + case .Read: + rand_bytes(p) + case .Reset: + // do nothing + case .Query_Info: + if len(p) != size_of(runtime.Random_Generator_Query_Info) { + return + } + info := (^runtime.Random_Generator_Query_Info)(raw_data(p)) + info^ += {.Uniform, .Cryptographic, .External_Entropy} + } + }, + data = nil, + } +} diff --git a/core/crypto/kmac/kmac.odin b/core/crypto/kmac/kmac.odin index e5be6f91b..711f459b3 100644 --- a/core/crypto/kmac/kmac.odin +++ b/core/crypto/kmac/kmac.odin @@ -61,7 +61,7 @@ init_256 :: proc(ctx: ^Context, key, domain_sep: []byte) { update :: proc(ctx: ^Context, data: []byte) { assert(ctx.is_initialized) - shake.write(transmute(^shake.Context)(ctx), data) + shake.write((^shake.Context)(ctx), data) } // final finalizes the Context, writes the tag to dst, and calls reset @@ -75,7 +75,7 @@ final :: proc(ctx: ^Context, dst: []byte) { panic("crypto/kmac: invalid KMAC tag_size, too short") } - _sha3.final_cshake(transmute(^_sha3.Context)(ctx), dst) + _sha3.final_cshake((^_sha3.Context)(ctx), dst) } // clone clones the Context other into ctx. @@ -84,7 +84,7 @@ clone :: proc(ctx, other: ^Context) { return } - shake.clone(transmute(^shake.Context)(ctx), transmute(^shake.Context)(other)) + shake.clone((^shake.Context)(ctx), (^shake.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to @@ -94,7 +94,7 @@ reset :: proc(ctx: ^Context) { return } - shake.reset(transmute(^shake.Context)(ctx)) + shake.reset((^shake.Context)(ctx)) } @(private) @@ -107,7 +107,7 @@ _init_kmac :: proc(ctx: ^Context, key, s: []byte, sec_strength: int) { panic("crypto/kmac: invalid KMAC key, too short") } - ctx_ := transmute(^_sha3.Context)(ctx) + ctx_ := (^_sha3.Context)(ctx) _sha3.init_cshake(ctx_, N_KMAC, s, sec_strength) _sha3.bytepad(ctx_, [][]byte{key}, _sha3.rate_cshake(sec_strength)) } diff --git a/core/crypto/legacy/keccak/keccak.odin b/core/crypto/legacy/keccak/keccak.odin index 7813a1ab4..6ca66b7ca 100644 --- a/core/crypto/legacy/keccak/keccak.odin +++ b/core/crypto/legacy/keccak/keccak.odin @@ -66,12 +66,12 @@ init_512 :: proc(ctx: ^Context) { @(private) _init :: proc(ctx: ^Context) { ctx.dsbyte = _sha3.DS_KECCAK - _sha3.init(transmute(^_sha3.Context)(ctx)) + _sha3.init((^_sha3.Context)(ctx)) } // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - _sha3.update(transmute(^_sha3.Context)(ctx), data) + _sha3.update((^_sha3.Context)(ctx), data) } // final finalizes the Context, writes the digest to hash, and calls @@ -80,16 +80,16 @@ update :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - _sha3.final(transmute(^_sha3.Context)(ctx), hash, finalize_clone) + _sha3.final((^_sha3.Context)(ctx), hash, finalize_clone) } // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } diff --git a/core/crypto/rand_darwin.odin b/core/crypto/rand_darwin.odin index 56acb5d22..df474bc4c 100644 --- a/core/crypto/rand_darwin.odin +++ b/core/crypto/rand_darwin.odin @@ -11,7 +11,7 @@ HAS_RAND_BYTES :: true _rand_bytes :: proc(dst: []byte) { err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst)) if err != .Success { - msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err)) - fmt.panicf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg) + msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err)) + fmt.panicf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg) } } diff --git a/core/crypto/ristretto255/ristretto255.odin b/core/crypto/ristretto255/ristretto255.odin index d1f2b6ee5..3a2307da0 100644 --- a/core/crypto/ristretto255/ristretto255.odin +++ b/core/crypto/ristretto255/ristretto255.odin @@ -112,7 +112,7 @@ ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { return false } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) s: field.Tight_Field_Element = --- defer field.fe_clear(&s) @@ -297,7 +297,7 @@ ge_bytes :: proc(ge: ^Group_Element, dst: []byte) { // 2. Return the 32-byte little-endian encoding of s. More // specifically, this is the encoding of the canonical // representation of s as an integer between 0 and p-1, inclusive. - dst_ := transmute(^[32]byte)(raw_data(dst)) + dst_ := (^[32]byte)(raw_data(dst)) field.fe_to_bytes(dst_, &tmp) field.fe_clear_vec([]^field.Tight_Field_Element{&u1, &u2, &tmp, &z_inv, &ix0, &iy0, &x, &y}) @@ -417,7 +417,7 @@ ge_is_identity :: proc(ge: ^Group_Element) -> int { @(private) ge_map :: proc "contextless" (ge: ^Group_Element, b: []byte) { - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) // The MAP function is defined on 32-byte strings as: // diff --git a/core/crypto/ristretto255/ristretto255_scalar.odin b/core/crypto/ristretto255/ristretto255_scalar.odin index f581e5963..1ecb490e0 100644 --- a/core/crypto/ristretto255/ristretto255_scalar.odin +++ b/core/crypto/ristretto255/ristretto255_scalar.odin @@ -46,7 +46,7 @@ sc_set_bytes_wide :: proc(sc: ^Scalar, b: []byte) { panic("crypto/ristretto255: invalid wide input size") } - b_ := transmute(^[WIDE_SCALAR_SIZE]byte)(raw_data(b)) + b_ := (^[WIDE_SCALAR_SIZE]byte)(raw_data(b)) grp.sc_set_bytes_wide(sc, b_) } diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index bc3e6e846..78057f1ca 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -68,12 +68,12 @@ init_512 :: proc(ctx: ^Context) { @(private) _init :: proc(ctx: ^Context) { ctx.dsbyte = _sha3.DS_SHA3 - _sha3.init(transmute(^_sha3.Context)(ctx)) + _sha3.init((^_sha3.Context)(ctx)) } // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - _sha3.update(transmute(^_sha3.Context)(ctx), data) + _sha3.update((^_sha3.Context)(ctx), data) } // final finalizes the Context, writes the digest to hash, and calls @@ -82,16 +82,16 @@ update :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - _sha3.final(transmute(^_sha3.Context)(ctx), hash, finalize_clone) + _sha3.final((^_sha3.Context)(ctx), hash, finalize_clone) } // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 7da427485..4160f4cf9 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -24,35 +24,35 @@ Context :: distinct _sha3.Context // init_128 initializes a Context for SHAKE128. init_128 :: proc(ctx: ^Context) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 128) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, nil, 128) } // init_256 initializes a Context for SHAKE256. init_256 :: proc(ctx: ^Context) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 256) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, nil, 256) } // init_cshake_128 initializes a Context for cSHAKE128. init_cshake_128 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 128) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, domain_sep, 128) } // init_cshake_256 initializes a Context for cSHAKE256. init_cshake_256 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 256) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, domain_sep, 256) } // write writes more data into the SHAKE instance. This MUST not be called // after any reads have been done, and attempts to do so will panic. write :: proc(ctx: ^Context, data: []byte) { - _sha3.update(transmute(^_sha3.Context)(ctx), data) + _sha3.update((^_sha3.Context)(ctx), data) } // read reads output from the SHAKE instance. There is no practical upper // limit to the amount of data that can be read from SHAKE. After read has // been called one or more times, further calls to write will panic. read :: proc(ctx: ^Context, dst: []byte) { - ctx_ := transmute(^_sha3.Context)(ctx) + ctx_ := (^_sha3.Context)(ctx) if !ctx.is_finalized { _sha3.shake_xof(ctx_) } @@ -62,11 +62,11 @@ read :: proc(ctx: ^Context, dst: []byte) { // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } diff --git a/core/crypto/tuplehash/tuplehash.odin b/core/crypto/tuplehash/tuplehash.odin index baba1ce59..ed0a3aa87 100644 --- a/core/crypto/tuplehash/tuplehash.odin +++ b/core/crypto/tuplehash/tuplehash.odin @@ -13,19 +13,19 @@ Context :: distinct _sha3.Context // init_128 initializes a Context for TupleHash128 or TupleHashXOF128. init_128 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 128) + _sha3.init_cshake((^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 128) } // init_256 initializes a Context for TupleHash256 or TupleHashXOF256. init_256 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 256) + _sha3.init_cshake((^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 256) } // write_element writes a tuple element into the TupleHash or TupleHashXOF // instance. This MUST not be called after any reads have been done, and // any attempts to do so will panic. write_element :: proc(ctx: ^Context, data: []byte) { - _, _ = _sha3.encode_string(transmute(^_sha3.Context)(ctx), data) + _, _ = _sha3.encode_string((^_sha3.Context)(ctx), data) } // final finalizes the Context, writes the digest to hash, and calls @@ -34,7 +34,7 @@ write_element :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - _sha3.final_cshake(transmute(^_sha3.Context)(ctx), hash, finalize_clone) + _sha3.final_cshake((^_sha3.Context)(ctx), hash, finalize_clone) } // read reads output from the TupleHashXOF instance. There is no practical @@ -42,7 +42,7 @@ final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { // After read has been called one or more times, further calls to // write_element will panic. read :: proc(ctx: ^Context, dst: []byte) { - ctx_ := transmute(^_sha3.Context)(ctx) + ctx_ := (^_sha3.Context)(ctx) if !ctx.is_finalized { _sha3.encode_byte_len(ctx_, 0, false) // right_encode _sha3.shake_xof(ctx_) @@ -53,13 +53,13 @@ read :: proc(ctx: ^Context, dst: []byte) { // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } @(private) diff --git a/core/debug/trace/trace_cpp.odin b/core/debug/trace/trace_cpp.odin index 894046c45..dc723184a 100644 --- a/core/debug/trace/trace_cpp.odin +++ b/core/debug/trace/trace_cpp.odin @@ -78,7 +78,7 @@ _Context :: struct { @(private="package") _init :: proc(ctx: ^Context) -> (ok: bool) { - defer if !ok do destroy(ctx) + defer if !ok { destroy(ctx) } ctx.impl.state = backtrace_create_state("odin-debug-trace", 1, nil, ctx) return ctx.impl.state != nil diff --git a/core/debug/trace/trace_nil.odin b/core/debug/trace/trace_nil.odin index 40478898b..8611d7726 100644 --- a/core/debug/trace/trace_nil.odin +++ b/core/debug/trace/trace_nil.odin @@ -1,6 +1,8 @@ //+build !windows !linux !darwin package debug_trace +import "base:runtime" + _Context :: struct { } @@ -10,9 +12,9 @@ _init :: proc(ctx: ^Context) -> (ok: bool) { _destroy :: proc(ctx: ^Context) -> bool { return true } -_frames :: proc(ctx: ^Context, skip: uint, allocator: runtime.Allocator) -> []Frame { +_frames :: proc(ctx: ^Context, skip: uint, frames_buffer: []Frame) -> []Frame { return nil } -_resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (result: runtime.Source_Code_Location) { +_resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (result: Frame_Location) { return } diff --git a/core/dynlib/lib.odin b/core/dynlib/lib.odin index 3d41cbe2e..09e16002d 100644 --- a/core/dynlib/lib.odin +++ b/core/dynlib/lib.odin @@ -16,15 +16,12 @@ Library :: distinct rawptr Loads a dynamic library from the filesystem. The paramater `global_symbols` makes the symbols in the loaded library available to resolve references in subsequently loaded libraries. -The paramater `global_symbols` is only used for the platforms `linux`, `darwin`, `freebsd` and `openbsd`. +The parameter `global_symbols` is only used for the platforms `linux`, `darwin`, `freebsd` and `openbsd`. On `windows` this paramater is ignored. The underlying behaviour is platform specific. On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlopen`. -On `windows` refer to `LoadLibraryW`. - -**Implicit Allocators** -`context.temp_allocator` +On `windows` refer to `LoadLibraryW`. Also temporarily needs an allocator to convert a string. Example: import "core:dynlib" @@ -79,10 +76,7 @@ Loads the address of a procedure/variable from a dynamic library. The underlying behaviour is platform specific. On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlsym`. -On `windows` refer to `GetProcAddress`. - -**Implicit Allocators** -`context.temp_allocator` +On `windows` refer to `GetProcAddress`. Also temporarily needs an allocator to convert a string. Example: import "core:dynlib" @@ -177,9 +171,7 @@ initialize_symbols :: proc( return count, count > 0 } -/* -Returns an error message for the last failed procedure call. -*/ +// Returns an error message for the last failed procedure call. last_error :: proc() -> string { return _last_error() -} +} \ No newline at end of file diff --git a/core/dynlib/lib_js.odin b/core/dynlib/lib_js.odin index 866874ee8..bfc724c12 100644 --- a/core/dynlib/lib_js.odin +++ b/core/dynlib/lib_js.odin @@ -16,4 +16,4 @@ _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found _last_error :: proc() -> string { return "" -} +} \ No newline at end of file diff --git a/core/dynlib/lib_unix.odin b/core/dynlib/lib_unix.odin index fb0270ea3..8adaadb2d 100644 --- a/core/dynlib/lib_unix.odin +++ b/core/dynlib/lib_unix.odin @@ -26,4 +26,4 @@ _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found _last_error :: proc() -> string { err := os.dlerror() return "unknown" if err == "" else err -} +} \ No newline at end of file diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin index c7bfe1537..b41abe3b2 100644 --- a/core/dynlib/lib_windows.odin +++ b/core/dynlib/lib_windows.odin @@ -4,14 +4,12 @@ package dynlib import win32 "core:sys/windows" import "core:strings" -import "base:runtime" import "core:reflect" -_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) { +_load_library :: proc(path: string, global_symbols := false, allocator := context.temp_allocator) -> (Library, bool) { // NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL - - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - wide_path := win32.utf8_to_wstring(path, context.temp_allocator) + wide_path := win32.utf8_to_wstring(path, allocator) + defer free(wide_path, allocator) handle := cast(Library)win32.LoadLibraryW(wide_path) return handle, handle != nil } @@ -21,9 +19,9 @@ _unload_library :: proc(library: Library) -> bool { return bool(ok) } -_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - c_str := strings.clone_to_cstring(symbol, context.temp_allocator) +_symbol_address :: proc(library: Library, symbol: string, allocator := context.temp_allocator) -> (ptr: rawptr, found: bool) { + c_str := strings.clone_to_cstring(symbol, allocator) + defer delete(c_str, allocator) ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str) found = ptr != nil return @@ -33,4 +31,4 @@ _last_error :: proc() -> string { err := win32.System_Error(win32.GetLastError()) err_msg := reflect.enum_string(err) return "unknown" if err_msg == "" else err_msg -} +} \ No newline at end of file diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 962a3ead4..f3320428d 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -8,141 +8,141 @@ package encoding_base32 // truncate it from the encoded output. ENC_TABLE := [32]byte { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '2', '3', '4', '5', '6', '7', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '2', '3', '4', '5', '6', '7', } PADDING :: '=' DEC_TABLE := [?]u8 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { - out_length := (len(data) + 4) / 5 * 8 - out := make([]byte, out_length) - _encode(out, data) - return string(out) + out_length := (len(data) + 4) / 5 * 8 + out := make([]byte, out_length) + _encode(out, data) + return string(out) } @private _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) { - out := out - data := data + out := out + data := data - for len(data) > 0 { - carry: byte - switch len(data) { - case: - out[7] = ENC_TABLE[data[4] & 0x1f] - carry = data[4] >> 5 - fallthrough - case 4: - out[6] = ENC_TABLE[carry | (data[3] << 3) & 0x1f] - out[5] = ENC_TABLE[(data[3] >> 2) & 0x1f] - carry = data[3] >> 7 - fallthrough - case 3: - out[4] = ENC_TABLE[carry | (data[2] << 1) & 0x1f] - carry = (data[2] >> 4) & 0x1f - fallthrough - case 2: - out[3] = ENC_TABLE[carry | (data[1] << 4) & 0x1f] - out[2] = ENC_TABLE[(data[1] >> 1) & 0x1f] - carry = (data[1] >> 6) & 0x1f - fallthrough - case 1: - out[1] = ENC_TABLE[carry | (data[0] << 2) & 0x1f] - out[0] = ENC_TABLE[data[0] >> 3] - } + for len(data) > 0 { + carry: byte + switch len(data) { + case: + out[7] = ENC_TABLE[data[4] & 0x1f] + carry = data[4] >> 5 + fallthrough + case 4: + out[6] = ENC_TABLE[carry | (data[3] << 3) & 0x1f] + out[5] = ENC_TABLE[(data[3] >> 2) & 0x1f] + carry = data[3] >> 7 + fallthrough + case 3: + out[4] = ENC_TABLE[carry | (data[2] << 1) & 0x1f] + carry = (data[2] >> 4) & 0x1f + fallthrough + case 2: + out[3] = ENC_TABLE[carry | (data[1] << 4) & 0x1f] + out[2] = ENC_TABLE[(data[1] >> 1) & 0x1f] + carry = (data[1] >> 6) & 0x1f + fallthrough + case 1: + out[1] = ENC_TABLE[carry | (data[0] << 2) & 0x1f] + out[0] = ENC_TABLE[data[0] >> 3] + } - if len(data) < 5 { - out[7] = byte(PADDING) - if len(data) < 4 { - out[6] = byte(PADDING) - out[5] = byte(PADDING) - if len(data) < 3 { - out[4] = byte(PADDING) - if len(data) < 2 { - out[3] = byte(PADDING) - out[2] = byte(PADDING) - } - } - } - break - } - data = data[5:] - out = out[8:] - } + if len(data) < 5 { + out[7] = byte(PADDING) + if len(data) < 4 { + out[6] = byte(PADDING) + out[5] = byte(PADDING) + if len(data) < 3 { + out[4] = byte(PADDING) + if len(data) < 2 { + out[3] = byte(PADDING) + out[2] = byte(PADDING) + } + } + } + break + } + data = data[5:] + out = out[8:] + } } decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{ - if len(data) == 0 { - return nil - } + if len(data) == 0 { + return nil + } - outi := 0 - data := data + outi := 0 + data := data - out := make([]byte, len(data) / 8 * 5, allocator) - end := false - for len(data) > 0 && !end { - dbuf : [8]byte - dlen := 8 + out := make([]byte, len(data) / 8 * 5, allocator) + end := false + for len(data) > 0 && !end { + dbuf : [8]byte + dlen := 8 - for j := 0; j < 8; { - if len(data) == 0 { - dlen, end = j, true - break - } - input := data[0] - data = data[1:] - if input == byte(PADDING) && j >= 2 && len(data) < 8 { - assert(!(len(data) + j < 8 - 1), "Corrupted input") - for k := 0; k < 8-1-j; k +=1 { - assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input") - } - dlen, end = j, true - assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input") - break - } - dbuf[j] = DEC_TABLE[input] - assert(dbuf[j] != 0xff, "Corrupted input") - j += 1 - } + for j := 0; j < 8; { + if len(data) == 0 { + dlen, end = j, true + break + } + input := data[0] + data = data[1:] + if input == byte(PADDING) && j >= 2 && len(data) < 8 { + assert(!(len(data) + j < 8 - 1), "Corrupted input") + for k := 0; k < 8-1-j; k +=1 { + assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input") + } + dlen, end = j, true + assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input") + break + } + dbuf[j] = DEC_TABLE[input] + assert(dbuf[j] != 0xff, "Corrupted input") + j += 1 + } - switch dlen { - case 8: - out[outi + 4] = dbuf[6] << 5 | dbuf[7] - fallthrough - case 7: - out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3 - fallthrough - case 5: - out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1 - fallthrough - case 4: - out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4 - fallthrough - case 2: - out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2 - } - outi += 5 - } - return out + switch dlen { + case 8: + out[outi + 4] = dbuf[6] << 5 | dbuf[7] + fallthrough + case 7: + out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3 + fallthrough + case 5: + out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1 + fallthrough + case 4: + out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4 + fallthrough + case 2: + out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2 + } + outi += 5 + } + return out } diff --git a/core/encoding/cbor/coding.odin b/core/encoding/cbor/coding.odin index 07f0637a6..bfeb147c4 100644 --- a/core/encoding/cbor/coding.odin +++ b/core/encoding/cbor/coding.odin @@ -233,7 +233,7 @@ encode_into_encoder :: proc(e: Encoder, v: Value, loc := #caller_location) -> En if .Self_Described_CBOR in e.flags { _encode_u64(e, TAG_SELF_DESCRIBED_CBOR, .Tag) or_return - e.flags &~= { .Self_Described_CBOR } + e.flags -= { .Self_Described_CBOR } } switch v_spec in v { @@ -423,7 +423,7 @@ _decode_bytes :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := c _encode_bytes :: proc(e: Encoder, val: Bytes, major: Major = .Bytes) -> (err: Encode_Error) { assert(len(val) >= 0) _encode_u64(e, u64(len(val)), major) or_return - _, err = io.write_full(e.writer, val[:]) + _, err = io.write_full(e.writer, val[:]) return } @@ -440,7 +440,7 @@ _decode_text :: proc(d: Decoder, add: Add, allocator := context.allocator, loc : } _encode_text :: proc(e: Encoder, val: Text) -> Encode_Error { - return _encode_bytes(e, transmute([]byte)val, .Text) + return _encode_bytes(e, transmute([]byte)val, .Text) } _decode_array_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Array, err: Decode_Error) { @@ -480,10 +480,10 @@ _decode_array :: proc(d: Decoder, add: Add, allocator := context.allocator, loc _encode_array :: proc(e: Encoder, arr: Array) -> Encode_Error { assert(len(arr) >= 0) _encode_u64(e, u64(len(arr)), .Array) - for val in arr { - encode(e, val) or_return - } - return nil + for val in arr { + encode(e, val) or_return + } + return nil } _decode_map_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Map, err: Decode_Error) { @@ -576,7 +576,7 @@ _encode_map :: proc(e: Encoder, m: Map) -> (err: Encode_Error) { encode(e, entry.entry.value) or_return } - return nil + return nil } _decode_tag_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) { @@ -626,7 +626,7 @@ _decode_uint_as_u64 :: proc(r: io.Reader, add: Add) -> (nr: u64, err: Decode_Err _encode_tag :: proc(e: Encoder, val: Tag) -> Encode_Error { _encode_u64(e, val.number, .Tag) or_return - return encode(e, val.value) + return encode(e, val.value) } _decode_simple :: proc(r: io.Reader) -> (v: Simple, err: io.Error) { @@ -739,16 +739,16 @@ _encode_nil :: proc(w: io.Writer) -> io.Error { // Streaming encode_stream_begin :: proc(w: io.Writer, major: Major) -> (err: io.Error) { - assert(major >= Major(.Bytes) && major <= Major(.Map), "illegal stream type") + assert(major >= Major(.Bytes) && major <= Major(.Map), "illegal stream type") - header := (u8(major) << 5) | u8(Add.Length_Unknown) - _, err = io.write_full(w, {header}) + header := (u8(major) << 5) | u8(Add.Length_Unknown) + _, err = io.write_full(w, {header}) return } encode_stream_end :: proc(w: io.Writer) -> io.Error { - header := (u8(Major.Other) << 5) | u8(Add.Break) - _, err := io.write_full(w, {header}) + header := (u8(Major.Other) << 5) | u8(Add.Break) + _, err := io.write_full(w, {header}) return err } @@ -757,8 +757,8 @@ encode_stream_text :: _encode_text encode_stream_array_item :: encode encode_stream_map_entry :: proc(e: Encoder, key: Value, val: Value) -> Encode_Error { - encode(e, key) or_return - return encode(e, val) + encode(e, key) or_return + return encode(e, val) } // For `Bytes` and `Text` strings: Decodes the number of items the header says follows. diff --git a/core/encoding/cbor/doc.odin b/core/encoding/cbor/doc.odin index 937b1b61b..b3fa36130 100644 --- a/core/encoding/cbor/doc.odin +++ b/core/encoding/cbor/doc.odin @@ -77,8 +77,11 @@ You can look at the default tags provided for pointers on how these implementati Example: package main + import "base:intrinsics" + import "core:encoding/cbor" import "core:fmt" + import "core:reflect" import "core:time" Possibilities :: union { @@ -93,9 +96,32 @@ Example: ignore_this: ^Data `cbor:"-"`, // Ignored by implementation. renamed: f32 `cbor:"renamed :)"`, // Renamed when encoded. my_union: Possibilities, // Union support. + + my_raw: [8]u32 `cbor_tag:"raw"`, // Custom tag that just writes the value as bytes. } main :: proc() { + // Example custom tag implementation that instead of breaking down all parts, + // just writes the value as a big byte blob. This is an advanced feature but very powerful. + RAW_TAG_NR :: 200 + cbor.tag_register_number({ + marshal = proc(_: ^cbor.Tag_Implementation, e: cbor.Encoder, v: any) -> cbor.Marshal_Error { + cbor._encode_u8(e.writer, RAW_TAG_NR, .Tag) or_return + return cbor.err_conv(cbor._encode_bytes(e, reflect.as_bytes(v))) + }, + unmarshal = proc(_: ^cbor.Tag_Implementation, d: cbor.Decoder, _: cbor.Tag_Number, v: any) -> (cbor.Unmarshal_Error) { + hdr := cbor._decode_header(d.reader) or_return + maj, add := cbor._header_split(hdr) + if maj != .Bytes { + return .Bad_Tag_Value + } + + bytes := cbor.err_conv(cbor._decode_bytes(d, add, maj)) or_return + intrinsics.mem_copy_non_overlapping(v.data, raw_data(bytes), len(bytes)) + return nil + }, + }, RAW_TAG_NR, "raw") + now := time.Time{_nsec = 1701117968 * 1e9} data := Data{ @@ -105,21 +131,22 @@ Example: ignore_this = &Data{}, renamed = 123123.125, my_union = 3, + my_raw = {1=1, 2=2, 3=3}, } - + // Marshal the struct into binary CBOR. binary, err := cbor.marshal(data, cbor.ENCODE_FULLY_DETERMINISTIC) - assert(err == nil) + fmt.assertf(err == nil, "marshal error: %v", err) defer delete(binary) - + // Decode the binary data into a `cbor.Value`. decoded, derr := cbor.decode(string(binary)) - assert(derr == nil) + fmt.assertf(derr == nil, "decode error: %v", derr) defer cbor.destroy(decoded) // Turn the CBOR into a human readable representation defined as the diagnostic format in [[RFC 8949 Section 8;https://www.rfc-editor.org/rfc/rfc8949.html#name-diagnostic-notation]]. diagnosis, eerr := cbor.to_diagnostic_format(decoded) - assert(eerr == nil) + fmt.assertf(eerr == nil, "to diagnostic error: %v", eerr) defer delete(diagnosis) fmt.println(diagnosis) @@ -127,6 +154,7 @@ Example: Output: { + "my_raw": 200(h'00001000200030000000000000000000'), "my_union": 1010([ "int", 3 diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index 775eafd9c..2cdf384c3 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -54,7 +54,7 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a defer if err != nil { strings.builder_destroy(&b) } - if err = marshal_into_builder(&b, v, flags, temp_allocator, loc=loc); err != nil { + if err = marshal_into_builder(&b, v, flags, temp_allocator); err != nil { return } @@ -63,20 +63,20 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a // Marshals the given value into a CBOR byte stream written to the given builder. // See docs on the `marshal_into` proc group for more info. -marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error { - return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator, loc=loc) +marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error { + return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator) } // Marshals the given value into a CBOR byte stream written to the given writer. // See docs on the `marshal_into` proc group for more info. -marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error { +marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error { encoder := Encoder{flags, w, temp_allocator} - return marshal_into_encoder(encoder, v, loc=loc) + return marshal_into_encoder(encoder, v) } // Marshals the given value into a CBOR byte stream written to the given encoder. // See docs on the `marshal_into` proc group for more info. -marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (err: Marshal_Error) { +marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) { e := e if e.temp_allocator.procedure == nil { @@ -85,7 +85,7 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e if .Self_Described_CBOR in e.flags { err_conv(_encode_u64(e, TAG_SELF_DESCRIBED_CBOR, .Tag)) or_return - e.flags &~= { .Self_Described_CBOR } + e.flags -= { .Self_Described_CBOR } } if v == nil { @@ -97,11 +97,14 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e return impl->marshal(e, v) } - ti := runtime.type_info_base(type_info_of(v.id)) - a := any{v.data, ti.id} + ti := runtime.type_info_core(type_info_of(v.id)) + return _marshal_into_encoder(e, v, ti) +} +_marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (err: Marshal_Error) { + a := any{v.data, ti.id} #partial switch info in ti.variant { - case runtime.Type_Info_Named: + case runtime.Type_Info_Named, runtime.Type_Info_Enum, runtime.Type_Info_Bit_Field: unreachable() case runtime.Type_Info_Pointer: @@ -223,18 +226,38 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e } err_conv(_encode_u64(e, u64(info.count), .Array)) or_return + + if impl, ok := _tag_implementations_type[info.elem.id]; ok { + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) for i in 0.. (e array := (^mem.Raw_Dynamic_Array)(v.data) err_conv(_encode_u64(e, u64(array.len), .Array)) or_return + + if impl, ok := _tag_implementations_type[info.elem.id]; ok { + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) for i in 0.. (e array := (^mem.Raw_Slice)(v.data) err_conv(_encode_u64(e, u64(array.len), .Array)) or_return + + if impl, ok := _tag_implementations_type[info.elem.id]; ok { + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) for i in 0.. (e return marshal_into(e, any{v.data, vti.id}) - case runtime.Type_Info_Enum: - return marshal_into(e, any{v.data, info.base.id}) - case runtime.Type_Info_Bit_Set: // Store bit_set as big endian just like the protocol. do_byte_swap := !reflect.bit_set_is_big_endian(v) diff --git a/core/encoding/cbor/tags.odin b/core/encoding/cbor/tags.odin index 3dc79a5dd..17420af46 100644 --- a/core/encoding/cbor/tags.odin +++ b/core/encoding/cbor/tags.odin @@ -95,7 +95,6 @@ tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string } // Controls initialization of default tag implementations. -// JS and WASI default to a panic allocator so we don't want to do it on those. INITIALIZE_DEFAULT_TAGS :: #config(CBOR_INITIALIZE_DEFAULT_TAGS, !ODIN_DEFAULT_TO_PANIC_ALLOCATOR && !ODIN_DEFAULT_TO_NIL_ALLOCATOR) @(private, init, disabled=!INITIALIZE_DEFAULT_TAGS) diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index c31ba1d92..13350bb85 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -273,13 +273,13 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a // NOTE: Because this is a special type and not to be treated as a general integer, // We only put the value of it in fields that are explicitly of type `Simple`. - switch &dst in v { - case Simple: - dst = decoded - return - case: - return _unsupported(v, hdr, add) - } + switch &dst in v { + case Simple: + dst = decoded + return + case: + return _unsupported(v, hdr, add) + } case .Tag: switch &dst in v { @@ -520,9 +520,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return case reflect.Type_Info_Array: - _, scap := err_conv(_decode_len_container(d, add)) or_return - length := min(scap, t.count) - + length, _ := err_conv(_decode_len_container(d, add)) or_return if length > t.count { return _unsupported(v, hdr) } @@ -534,9 +532,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return case reflect.Type_Info_Enumerated_Array: - _, scap := err_conv(_decode_len_container(d, add)) or_return - length := min(scap, t.count) - + length, _ := err_conv(_decode_len_container(d, add)) or_return if length > t.count { return _unsupported(v, hdr) } @@ -548,9 +544,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return case reflect.Type_Info_Complex: - _, scap := err_conv(_decode_len_container(d, add)) or_return - length := min(scap, 2) - + length, _ := err_conv(_decode_len_container(d, add)) or_return if length > 2 { return _unsupported(v, hdr) } @@ -570,9 +564,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return case reflect.Type_Info_Quaternion: - _, scap := err_conv(_decode_len_container(d, add)) or_return - length := min(scap, 4) - + length, _ := err_conv(_decode_len_container(d, add)) or_return if length > 4 { return _unsupported(v, hdr) } @@ -633,7 +625,7 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, length, _ := err_conv(_decode_len_container(d, add)) or_return unknown := length == -1 fields := reflect.struct_fields_zipped(ti.id) - + for idx := 0; idx < len(fields) && (unknown || idx < length); idx += 1 { // Decode key, keys can only be strings. key: string @@ -646,7 +638,7 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, key = keyv } defer delete(key, context.temp_allocator) - + // Find matching field. use_field_idx := -1 { diff --git a/core/encoding/csv/reader.odin b/core/encoding/csv/reader.odin index 200bf43ea..ebc7b39a0 100644 --- a/core/encoding/csv/reader.odin +++ b/core/encoding/csv/reader.odin @@ -138,7 +138,9 @@ iterator_next :: proc(r: ^Reader) -> (record: []string, idx: int, err: Error, mo return record, r.line_count - 1, r.last_iterator_error, r.last_iterator_error == nil } -// Get last error if we the iterator +// Get last CSV parse error if we ignored it in the iterator loop +// +// for record, row_idx in csv.iterator_next(&r) { ... } iterator_last_error :: proc(r: Reader) -> (err: Error) { return r.last_iterator_error } @@ -169,7 +171,7 @@ is_io_error :: proc(err: Error, io_err: io.Error) -> bool { // read_all reads all the remaining records from r. // Each record is a slice of fields. -// read_all is defined to read until an EOF, and does not treat, and does not treat EOF as an error +// read_all is defined to read until an EOF, and does not treat EOF as an error @(require_results) read_all :: proc(r: ^Reader, allocator := context.allocator) -> ([][]string, Error) { context.allocator = allocator diff --git a/core/encoding/entity/generated.odin b/core/encoding/entity/generated.odin index d2acde20d..0c4742149 100644 --- a/core/encoding/entity/generated.odin +++ b/core/encoding/entity/generated.odin @@ -61,5026 +61,5026 @@ named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { case 'A': switch name { - case "AElig": // LATIN CAPITAL LETTER AE - return rune(0xc6), true - case "AMP": // AMPERSAND - return rune(0x26), true - case "Aacgr": // GREEK CAPITAL LETTER ALPHA WITH TONOS - return rune(0x0386), true - case "Aacute": // LATIN CAPITAL LETTER A WITH ACUTE - return rune(0xc1), true - case "Abreve": // LATIN CAPITAL LETTER A WITH BREVE - return rune(0x0102), true - case "Acirc": // LATIN CAPITAL LETTER A WITH CIRCUMFLEX - return rune(0xc2), true - case "Acy": // CYRILLIC CAPITAL LETTER A - return rune(0x0410), true - case "Afr": // MATHEMATICAL FRAKTUR CAPITAL A - return rune(0x01d504), true - case "Agr": // GREEK CAPITAL LETTER ALPHA - return rune(0x0391), true - case "Agrave": // LATIN CAPITAL LETTER A WITH GRAVE - return rune(0xc0), true - case "Alpha": // GREEK CAPITAL LETTER ALPHA - return rune(0x0391), true - case "Amacr": // LATIN CAPITAL LETTER A WITH MACRON - return rune(0x0100), true - case "And": // DOUBLE LOGICAL AND - return rune(0x2a53), true - case "Aogon": // LATIN CAPITAL LETTER A WITH OGONEK - return rune(0x0104), true - case "Aopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL A - return rune(0x01d538), true - case "ApplyFunction": // FUNCTION APPLICATION - return rune(0x2061), true - case "Aring": // LATIN CAPITAL LETTER A WITH RING ABOVE - return rune(0xc5), true - case "Ascr": // MATHEMATICAL SCRIPT CAPITAL A - return rune(0x01d49c), true - case "Assign": // COLON EQUALS - return rune(0x2254), true - case "Ast": // TWO ASTERISKS ALIGNED VERTICALLY - return rune(0x2051), true - case "Atilde": // LATIN CAPITAL LETTER A WITH TILDE - return rune(0xc3), true - case "Auml": // LATIN CAPITAL LETTER A WITH DIAERESIS - return rune(0xc4), true + case "AElig": // LATIN CAPITAL LETTER AE + return rune(0xc6), true + case "AMP": // AMPERSAND + return rune(0x26), true + case "Aacgr": // GREEK CAPITAL LETTER ALPHA WITH TONOS + return rune(0x0386), true + case "Aacute": // LATIN CAPITAL LETTER A WITH ACUTE + return rune(0xc1), true + case "Abreve": // LATIN CAPITAL LETTER A WITH BREVE + return rune(0x0102), true + case "Acirc": // LATIN CAPITAL LETTER A WITH CIRCUMFLEX + return rune(0xc2), true + case "Acy": // CYRILLIC CAPITAL LETTER A + return rune(0x0410), true + case "Afr": // MATHEMATICAL FRAKTUR CAPITAL A + return rune(0x01d504), true + case "Agr": // GREEK CAPITAL LETTER ALPHA + return rune(0x0391), true + case "Agrave": // LATIN CAPITAL LETTER A WITH GRAVE + return rune(0xc0), true + case "Alpha": // GREEK CAPITAL LETTER ALPHA + return rune(0x0391), true + case "Amacr": // LATIN CAPITAL LETTER A WITH MACRON + return rune(0x0100), true + case "And": // DOUBLE LOGICAL AND + return rune(0x2a53), true + case "Aogon": // LATIN CAPITAL LETTER A WITH OGONEK + return rune(0x0104), true + case "Aopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL A + return rune(0x01d538), true + case "ApplyFunction": // FUNCTION APPLICATION + return rune(0x2061), true + case "Aring": // LATIN CAPITAL LETTER A WITH RING ABOVE + return rune(0xc5), true + case "Ascr": // MATHEMATICAL SCRIPT CAPITAL A + return rune(0x01d49c), true + case "Assign": // COLON EQUALS + return rune(0x2254), true + case "Ast": // TWO ASTERISKS ALIGNED VERTICALLY + return rune(0x2051), true + case "Atilde": // LATIN CAPITAL LETTER A WITH TILDE + return rune(0xc3), true + case "Auml": // LATIN CAPITAL LETTER A WITH DIAERESIS + return rune(0xc4), true } case 'B': switch name { - case "Backslash": // SET MINUS - return rune(0x2216), true - case "Barint": // INTEGRAL WITH DOUBLE STROKE - return rune(0x2a0e), true - case "Barv": // SHORT DOWN TACK WITH OVERBAR - return rune(0x2ae7), true - case "Barwed": // PERSPECTIVE - return rune(0x2306), true - case "Barwedl": // LOGICAL AND WITH DOUBLE OVERBAR - return rune(0x2a5e), true - case "Bcy": // CYRILLIC CAPITAL LETTER BE - return rune(0x0411), true - case "Because": // BECAUSE - return rune(0x2235), true - case "Bernoullis": // SCRIPT CAPITAL B - return rune(0x212c), true - case "Beta": // GREEK CAPITAL LETTER BETA - return rune(0x0392), true - case "Bfr": // MATHEMATICAL FRAKTUR CAPITAL B - return rune(0x01d505), true - case "Bgr": // GREEK CAPITAL LETTER BETA - return rune(0x0392), true - case "Bopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL B - return rune(0x01d539), true - case "Breve": // BREVE - return rune(0x02d8), true - case "Bscr": // SCRIPT CAPITAL B - return rune(0x212c), true - case "Bumpeq": // GEOMETRICALLY EQUIVALENT TO - return rune(0x224e), true - case "Bvert": // BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL - return rune(0x2506), true + case "Backslash": // SET MINUS + return rune(0x2216), true + case "Barint": // INTEGRAL WITH DOUBLE STROKE + return rune(0x2a0e), true + case "Barv": // SHORT DOWN TACK WITH OVERBAR + return rune(0x2ae7), true + case "Barwed": // PERSPECTIVE + return rune(0x2306), true + case "Barwedl": // LOGICAL AND WITH DOUBLE OVERBAR + return rune(0x2a5e), true + case "Bcy": // CYRILLIC CAPITAL LETTER BE + return rune(0x0411), true + case "Because": // BECAUSE + return rune(0x2235), true + case "Bernoullis": // SCRIPT CAPITAL B + return rune(0x212c), true + case "Beta": // GREEK CAPITAL LETTER BETA + return rune(0x0392), true + case "Bfr": // MATHEMATICAL FRAKTUR CAPITAL B + return rune(0x01d505), true + case "Bgr": // GREEK CAPITAL LETTER BETA + return rune(0x0392), true + case "Bopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL B + return rune(0x01d539), true + case "Breve": // BREVE + return rune(0x02d8), true + case "Bscr": // SCRIPT CAPITAL B + return rune(0x212c), true + case "Bumpeq": // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "Bvert": // BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL + return rune(0x2506), true } case 'C': switch name { - case "CHcy": // CYRILLIC CAPITAL LETTER CHE - return rune(0x0427), true - case "COPY": // COPYRIGHT SIGN - return rune(0xa9), true - case "Cacute": // LATIN CAPITAL LETTER C WITH ACUTE - return rune(0x0106), true - case "Cap": // DOUBLE INTERSECTION - return rune(0x22d2), true - case "CapitalDifferentialD": // DOUBLE-STRUCK ITALIC CAPITAL D - return rune(0x2145), true - case "Cayleys": // BLACK-LETTER CAPITAL C - return rune(0x212d), true - case "Ccaron": // LATIN CAPITAL LETTER C WITH CARON - return rune(0x010c), true - case "Ccedil": // LATIN CAPITAL LETTER C WITH CEDILLA - return rune(0xc7), true - case "Ccirc": // LATIN CAPITAL LETTER C WITH CIRCUMFLEX - return rune(0x0108), true - case "Cconint": // VOLUME INTEGRAL - return rune(0x2230), true - case "Cdot": // LATIN CAPITAL LETTER C WITH DOT ABOVE - return rune(0x010a), true - case "Cedilla": // CEDILLA - return rune(0xb8), true - case "CenterDot": // MIDDLE DOT - return rune(0xb7), true - case "Cfr": // BLACK-LETTER CAPITAL C - return rune(0x212d), true - case "Chi": // GREEK CAPITAL LETTER CHI - return rune(0x03a7), true - case "CircleDot": // CIRCLED DOT OPERATOR - return rune(0x2299), true - case "CircleMinus": // CIRCLED MINUS - return rune(0x2296), true - case "CirclePlus": // CIRCLED PLUS - return rune(0x2295), true - case "CircleTimes": // CIRCLED TIMES - return rune(0x2297), true - case "ClockwiseContourIntegral": // CLOCKWISE CONTOUR INTEGRAL - return rune(0x2232), true - case "CloseCurlyDoubleQuote": // RIGHT DOUBLE QUOTATION MARK - return rune(0x201d), true - case "CloseCurlyQuote": // RIGHT SINGLE QUOTATION MARK - return rune(0x2019), true - case "Colon": // PROPORTION - return rune(0x2237), true - case "Colone": // DOUBLE COLON EQUAL - return rune(0x2a74), true - case "Congruent": // IDENTICAL TO - return rune(0x2261), true - case "Conint": // SURFACE INTEGRAL - return rune(0x222f), true - case "ContourIntegral": // CONTOUR INTEGRAL - return rune(0x222e), true - case "Copf": // DOUBLE-STRUCK CAPITAL C - return rune(0x2102), true - case "Coproduct": // N-ARY COPRODUCT - return rune(0x2210), true - case "CounterClockwiseContourIntegral": // ANTICLOCKWISE CONTOUR INTEGRAL - return rune(0x2233), true - case "Cross": // VECTOR OR CROSS PRODUCT - return rune(0x2a2f), true - case "Cscr": // MATHEMATICAL SCRIPT CAPITAL C - return rune(0x01d49e), true - case "Cup": // DOUBLE UNION - return rune(0x22d3), true - case "CupCap": // EQUIVALENT TO - return rune(0x224d), true + case "CHcy": // CYRILLIC CAPITAL LETTER CHE + return rune(0x0427), true + case "COPY": // COPYRIGHT SIGN + return rune(0xa9), true + case "Cacute": // LATIN CAPITAL LETTER C WITH ACUTE + return rune(0x0106), true + case "Cap": // DOUBLE INTERSECTION + return rune(0x22d2), true + case "CapitalDifferentialD": // DOUBLE-STRUCK ITALIC CAPITAL D + return rune(0x2145), true + case "Cayleys": // BLACK-LETTER CAPITAL C + return rune(0x212d), true + case "Ccaron": // LATIN CAPITAL LETTER C WITH CARON + return rune(0x010c), true + case "Ccedil": // LATIN CAPITAL LETTER C WITH CEDILLA + return rune(0xc7), true + case "Ccirc": // LATIN CAPITAL LETTER C WITH CIRCUMFLEX + return rune(0x0108), true + case "Cconint": // VOLUME INTEGRAL + return rune(0x2230), true + case "Cdot": // LATIN CAPITAL LETTER C WITH DOT ABOVE + return rune(0x010a), true + case "Cedilla": // CEDILLA + return rune(0xb8), true + case "CenterDot": // MIDDLE DOT + return rune(0xb7), true + case "Cfr": // BLACK-LETTER CAPITAL C + return rune(0x212d), true + case "Chi": // GREEK CAPITAL LETTER CHI + return rune(0x03a7), true + case "CircleDot": // CIRCLED DOT OPERATOR + return rune(0x2299), true + case "CircleMinus": // CIRCLED MINUS + return rune(0x2296), true + case "CirclePlus": // CIRCLED PLUS + return rune(0x2295), true + case "CircleTimes": // CIRCLED TIMES + return rune(0x2297), true + case "ClockwiseContourIntegral": // CLOCKWISE CONTOUR INTEGRAL + return rune(0x2232), true + case "CloseCurlyDoubleQuote": // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "CloseCurlyQuote": // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "Colon": // PROPORTION + return rune(0x2237), true + case "Colone": // DOUBLE COLON EQUAL + return rune(0x2a74), true + case "Congruent": // IDENTICAL TO + return rune(0x2261), true + case "Conint": // SURFACE INTEGRAL + return rune(0x222f), true + case "ContourIntegral": // CONTOUR INTEGRAL + return rune(0x222e), true + case "Copf": // DOUBLE-STRUCK CAPITAL C + return rune(0x2102), true + case "Coproduct": // N-ARY COPRODUCT + return rune(0x2210), true + case "CounterClockwiseContourIntegral": // ANTICLOCKWISE CONTOUR INTEGRAL + return rune(0x2233), true + case "Cross": // VECTOR OR CROSS PRODUCT + return rune(0x2a2f), true + case "Cscr": // MATHEMATICAL SCRIPT CAPITAL C + return rune(0x01d49e), true + case "Cup": // DOUBLE UNION + return rune(0x22d3), true + case "CupCap": // EQUIVALENT TO + return rune(0x224d), true } case 'D': switch name { - case "DD": // DOUBLE-STRUCK ITALIC CAPITAL D - return rune(0x2145), true - case "DDotrahd": // RIGHTWARDS ARROW WITH DOTTED STEM - return rune(0x2911), true - case "DJcy": // CYRILLIC CAPITAL LETTER DJE - return rune(0x0402), true - case "DScy": // CYRILLIC CAPITAL LETTER DZE - return rune(0x0405), true - case "DZcy": // CYRILLIC CAPITAL LETTER DZHE - return rune(0x040f), true - case "Dagger": // DOUBLE DAGGER - return rune(0x2021), true - case "Darr": // DOWNWARDS TWO HEADED ARROW - return rune(0x21a1), true - case "Dashv": // VERTICAL BAR DOUBLE LEFT TURNSTILE - return rune(0x2ae4), true - case "Dcaron": // LATIN CAPITAL LETTER D WITH CARON - return rune(0x010e), true - case "Dcy": // CYRILLIC CAPITAL LETTER DE - return rune(0x0414), true - case "Del": // NABLA - return rune(0x2207), true - case "Delta": // GREEK CAPITAL LETTER DELTA - return rune(0x0394), true - case "Dfr": // MATHEMATICAL FRAKTUR CAPITAL D - return rune(0x01d507), true - case "Dgr": // GREEK CAPITAL LETTER DELTA - return rune(0x0394), true - case "DiacriticalAcute": // ACUTE ACCENT - return rune(0xb4), true - case "DiacriticalDot": // DOT ABOVE - return rune(0x02d9), true - case "DiacriticalDoubleAcute": // DOUBLE ACUTE ACCENT - return rune(0x02dd), true - case "DiacriticalGrave": // GRAVE ACCENT - return rune(0x60), true - case "DiacriticalTilde": // SMALL TILDE - return rune(0x02dc), true - case "Diamond": // DIAMOND OPERATOR - return rune(0x22c4), true - case "DifferentialD": // DOUBLE-STRUCK ITALIC SMALL D - return rune(0x2146), true - case "Dopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL D - return rune(0x01d53b), true - case "Dot": // DIAERESIS - return rune(0xa8), true - case "DotDot": // COMBINING FOUR DOTS ABOVE - return rune(0x20dc), true - case "DotEqual": // APPROACHES THE LIMIT - return rune(0x2250), true - case "DoubleContourIntegral": // SURFACE INTEGRAL - return rune(0x222f), true - case "DoubleDot": // DIAERESIS - return rune(0xa8), true - case "DoubleDownArrow": // DOWNWARDS DOUBLE ARROW - return rune(0x21d3), true - case "DoubleLeftArrow": // LEFTWARDS DOUBLE ARROW - return rune(0x21d0), true - case "DoubleLeftRightArrow": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true - case "DoubleLeftTee": // VERTICAL BAR DOUBLE LEFT TURNSTILE - return rune(0x2ae4), true - case "DoubleLongLeftArrow": // LONG LEFTWARDS DOUBLE ARROW - return rune(0x27f8), true - case "DoubleLongLeftRightArrow": // LONG LEFT RIGHT DOUBLE ARROW - return rune(0x27fa), true - case "DoubleLongRightArrow": // LONG RIGHTWARDS DOUBLE ARROW - return rune(0x27f9), true - case "DoubleRightArrow": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true - case "DoubleRightTee": // TRUE - return rune(0x22a8), true - case "DoubleUpArrow": // UPWARDS DOUBLE ARROW - return rune(0x21d1), true - case "DoubleUpDownArrow": // UP DOWN DOUBLE ARROW - return rune(0x21d5), true - case "DoubleVerticalBar": // PARALLEL TO - return rune(0x2225), true - case "DownArrow": // DOWNWARDS ARROW - return rune(0x2193), true - case "DownArrowBar": // DOWNWARDS ARROW TO BAR - return rune(0x2913), true - case "DownArrowUpArrow": // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - return rune(0x21f5), true - case "DownBreve": // COMBINING INVERTED BREVE - return rune(0x0311), true - case "DownLeftRightVector": // LEFT BARB DOWN RIGHT BARB DOWN HARPOON - return rune(0x2950), true - case "DownLeftTeeVector": // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295e), true - case "DownLeftVector": // LEFTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21bd), true - case "DownLeftVectorBar": // LEFTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2956), true - case "DownRightTeeVector": // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295f), true - case "DownRightVector": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21c1), true - case "DownRightVectorBar": // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2957), true - case "DownTee": // DOWN TACK - return rune(0x22a4), true - case "DownTeeArrow": // DOWNWARDS ARROW FROM BAR - return rune(0x21a7), true - case "Downarrow": // DOWNWARDS DOUBLE ARROW - return rune(0x21d3), true - case "Dscr": // MATHEMATICAL SCRIPT CAPITAL D - return rune(0x01d49f), true - case "Dstrok": // LATIN CAPITAL LETTER D WITH STROKE - return rune(0x0110), true + case "DD": // DOUBLE-STRUCK ITALIC CAPITAL D + return rune(0x2145), true + case "DDotrahd": // RIGHTWARDS ARROW WITH DOTTED STEM + return rune(0x2911), true + case "DJcy": // CYRILLIC CAPITAL LETTER DJE + return rune(0x0402), true + case "DScy": // CYRILLIC CAPITAL LETTER DZE + return rune(0x0405), true + case "DZcy": // CYRILLIC CAPITAL LETTER DZHE + return rune(0x040f), true + case "Dagger": // DOUBLE DAGGER + return rune(0x2021), true + case "Darr": // DOWNWARDS TWO HEADED ARROW + return rune(0x21a1), true + case "Dashv": // VERTICAL BAR DOUBLE LEFT TURNSTILE + return rune(0x2ae4), true + case "Dcaron": // LATIN CAPITAL LETTER D WITH CARON + return rune(0x010e), true + case "Dcy": // CYRILLIC CAPITAL LETTER DE + return rune(0x0414), true + case "Del": // NABLA + return rune(0x2207), true + case "Delta": // GREEK CAPITAL LETTER DELTA + return rune(0x0394), true + case "Dfr": // MATHEMATICAL FRAKTUR CAPITAL D + return rune(0x01d507), true + case "Dgr": // GREEK CAPITAL LETTER DELTA + return rune(0x0394), true + case "DiacriticalAcute": // ACUTE ACCENT + return rune(0xb4), true + case "DiacriticalDot": // DOT ABOVE + return rune(0x02d9), true + case "DiacriticalDoubleAcute": // DOUBLE ACUTE ACCENT + return rune(0x02dd), true + case "DiacriticalGrave": // GRAVE ACCENT + return rune(0x60), true + case "DiacriticalTilde": // SMALL TILDE + return rune(0x02dc), true + case "Diamond": // DIAMOND OPERATOR + return rune(0x22c4), true + case "DifferentialD": // DOUBLE-STRUCK ITALIC SMALL D + return rune(0x2146), true + case "Dopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL D + return rune(0x01d53b), true + case "Dot": // DIAERESIS + return rune(0xa8), true + case "DotDot": // COMBINING FOUR DOTS ABOVE + return rune(0x20dc), true + case "DotEqual": // APPROACHES THE LIMIT + return rune(0x2250), true + case "DoubleContourIntegral": // SURFACE INTEGRAL + return rune(0x222f), true + case "DoubleDot": // DIAERESIS + return rune(0xa8), true + case "DoubleDownArrow": // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "DoubleLeftArrow": // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "DoubleLeftRightArrow": // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "DoubleLeftTee": // VERTICAL BAR DOUBLE LEFT TURNSTILE + return rune(0x2ae4), true + case "DoubleLongLeftArrow": // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "DoubleLongLeftRightArrow": // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "DoubleLongRightArrow": // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "DoubleRightArrow": // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "DoubleRightTee": // TRUE + return rune(0x22a8), true + case "DoubleUpArrow": // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "DoubleUpDownArrow": // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "DoubleVerticalBar": // PARALLEL TO + return rune(0x2225), true + case "DownArrow": // DOWNWARDS ARROW + return rune(0x2193), true + case "DownArrowBar": // DOWNWARDS ARROW TO BAR + return rune(0x2913), true + case "DownArrowUpArrow": // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + return rune(0x21f5), true + case "DownBreve": // COMBINING INVERTED BREVE + return rune(0x0311), true + case "DownLeftRightVector": // LEFT BARB DOWN RIGHT BARB DOWN HARPOON + return rune(0x2950), true + case "DownLeftTeeVector": // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295e), true + case "DownLeftVector": // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "DownLeftVectorBar": // LEFTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2956), true + case "DownRightTeeVector": // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295f), true + case "DownRightVector": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "DownRightVectorBar": // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2957), true + case "DownTee": // DOWN TACK + return rune(0x22a4), true + case "DownTeeArrow": // DOWNWARDS ARROW FROM BAR + return rune(0x21a7), true + case "Downarrow": // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "Dscr": // MATHEMATICAL SCRIPT CAPITAL D + return rune(0x01d49f), true + case "Dstrok": // LATIN CAPITAL LETTER D WITH STROKE + return rune(0x0110), true } case 'E': switch name { - case "EEacgr": // GREEK CAPITAL LETTER ETA WITH TONOS - return rune(0x0389), true - case "EEgr": // GREEK CAPITAL LETTER ETA - return rune(0x0397), true - case "ENG": // LATIN CAPITAL LETTER ENG - return rune(0x014a), true - case "ETH": // LATIN CAPITAL LETTER ETH - return rune(0xd0), true - case "Eacgr": // GREEK CAPITAL LETTER EPSILON WITH TONOS - return rune(0x0388), true - case "Eacute": // LATIN CAPITAL LETTER E WITH ACUTE - return rune(0xc9), true - case "Ecaron": // LATIN CAPITAL LETTER E WITH CARON - return rune(0x011a), true - case "Ecirc": // LATIN CAPITAL LETTER E WITH CIRCUMFLEX - return rune(0xca), true - case "Ecy": // CYRILLIC CAPITAL LETTER E - return rune(0x042d), true - case "Edot": // LATIN CAPITAL LETTER E WITH DOT ABOVE - return rune(0x0116), true - case "Efr": // MATHEMATICAL FRAKTUR CAPITAL E - return rune(0x01d508), true - case "Egr": // GREEK CAPITAL LETTER EPSILON - return rune(0x0395), true - case "Egrave": // LATIN CAPITAL LETTER E WITH GRAVE - return rune(0xc8), true - case "Element": // ELEMENT OF - return rune(0x2208), true - case "Emacr": // LATIN CAPITAL LETTER E WITH MACRON - return rune(0x0112), true - case "EmptySmallSquare": // WHITE MEDIUM SQUARE - return rune(0x25fb), true - case "EmptyVerySmallSquare": // WHITE SMALL SQUARE - return rune(0x25ab), true - case "Eogon": // LATIN CAPITAL LETTER E WITH OGONEK - return rune(0x0118), true - case "Eopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL E - return rune(0x01d53c), true - case "Epsilon": // GREEK CAPITAL LETTER EPSILON - return rune(0x0395), true - case "Equal": // TWO CONSECUTIVE EQUALS SIGNS - return rune(0x2a75), true - case "EqualTilde": // MINUS TILDE - return rune(0x2242), true - case "Equilibrium": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true - case "Escr": // SCRIPT CAPITAL E - return rune(0x2130), true - case "Esim": // EQUALS SIGN ABOVE TILDE OPERATOR - return rune(0x2a73), true - case "Eta": // GREEK CAPITAL LETTER ETA - return rune(0x0397), true - case "Euml": // LATIN CAPITAL LETTER E WITH DIAERESIS - return rune(0xcb), true - case "Exists": // THERE EXISTS - return rune(0x2203), true - case "ExponentialE": // DOUBLE-STRUCK ITALIC SMALL E - return rune(0x2147), true + case "EEacgr": // GREEK CAPITAL LETTER ETA WITH TONOS + return rune(0x0389), true + case "EEgr": // GREEK CAPITAL LETTER ETA + return rune(0x0397), true + case "ENG": // LATIN CAPITAL LETTER ENG + return rune(0x014a), true + case "ETH": // LATIN CAPITAL LETTER ETH + return rune(0xd0), true + case "Eacgr": // GREEK CAPITAL LETTER EPSILON WITH TONOS + return rune(0x0388), true + case "Eacute": // LATIN CAPITAL LETTER E WITH ACUTE + return rune(0xc9), true + case "Ecaron": // LATIN CAPITAL LETTER E WITH CARON + return rune(0x011a), true + case "Ecirc": // LATIN CAPITAL LETTER E WITH CIRCUMFLEX + return rune(0xca), true + case "Ecy": // CYRILLIC CAPITAL LETTER E + return rune(0x042d), true + case "Edot": // LATIN CAPITAL LETTER E WITH DOT ABOVE + return rune(0x0116), true + case "Efr": // MATHEMATICAL FRAKTUR CAPITAL E + return rune(0x01d508), true + case "Egr": // GREEK CAPITAL LETTER EPSILON + return rune(0x0395), true + case "Egrave": // LATIN CAPITAL LETTER E WITH GRAVE + return rune(0xc8), true + case "Element": // ELEMENT OF + return rune(0x2208), true + case "Emacr": // LATIN CAPITAL LETTER E WITH MACRON + return rune(0x0112), true + case "EmptySmallSquare": // WHITE MEDIUM SQUARE + return rune(0x25fb), true + case "EmptyVerySmallSquare": // WHITE SMALL SQUARE + return rune(0x25ab), true + case "Eogon": // LATIN CAPITAL LETTER E WITH OGONEK + return rune(0x0118), true + case "Eopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL E + return rune(0x01d53c), true + case "Epsilon": // GREEK CAPITAL LETTER EPSILON + return rune(0x0395), true + case "Equal": // TWO CONSECUTIVE EQUALS SIGNS + return rune(0x2a75), true + case "EqualTilde": // MINUS TILDE + return rune(0x2242), true + case "Equilibrium": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "Escr": // SCRIPT CAPITAL E + return rune(0x2130), true + case "Esim": // EQUALS SIGN ABOVE TILDE OPERATOR + return rune(0x2a73), true + case "Eta": // GREEK CAPITAL LETTER ETA + return rune(0x0397), true + case "Euml": // LATIN CAPITAL LETTER E WITH DIAERESIS + return rune(0xcb), true + case "Exists": // THERE EXISTS + return rune(0x2203), true + case "ExponentialE": // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true } case 'F': switch name { - case "Fcy": // CYRILLIC CAPITAL LETTER EF - return rune(0x0424), true - case "Ffr": // MATHEMATICAL FRAKTUR CAPITAL F - return rune(0x01d509), true - case "FilledSmallSquare": // BLACK MEDIUM SQUARE - return rune(0x25fc), true - case "FilledVerySmallSquare": // BLACK SMALL SQUARE - return rune(0x25aa), true - case "Fopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL F - return rune(0x01d53d), true - case "ForAll": // FOR ALL - return rune(0x2200), true - case "Fouriertrf": // SCRIPT CAPITAL F - return rune(0x2131), true - case "Fscr": // SCRIPT CAPITAL F - return rune(0x2131), true + case "Fcy": // CYRILLIC CAPITAL LETTER EF + return rune(0x0424), true + case "Ffr": // MATHEMATICAL FRAKTUR CAPITAL F + return rune(0x01d509), true + case "FilledSmallSquare": // BLACK MEDIUM SQUARE + return rune(0x25fc), true + case "FilledVerySmallSquare": // BLACK SMALL SQUARE + return rune(0x25aa), true + case "Fopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL F + return rune(0x01d53d), true + case "ForAll": // FOR ALL + return rune(0x2200), true + case "Fouriertrf": // SCRIPT CAPITAL F + return rune(0x2131), true + case "Fscr": // SCRIPT CAPITAL F + return rune(0x2131), true } case 'G': switch name { - case "GJcy": // CYRILLIC CAPITAL LETTER GJE - return rune(0x0403), true - case "GT": // GREATER-THAN SIGN - return rune(0x3e), true - case "Game": // TURNED SANS-SERIF CAPITAL G - return rune(0x2141), true - case "Gamma": // GREEK CAPITAL LETTER GAMMA - return rune(0x0393), true - case "Gammad": // GREEK LETTER DIGAMMA - return rune(0x03dc), true - case "Gbreve": // LATIN CAPITAL LETTER G WITH BREVE - return rune(0x011e), true - case "Gcedil": // LATIN CAPITAL LETTER G WITH CEDILLA - return rune(0x0122), true - case "Gcirc": // LATIN CAPITAL LETTER G WITH CIRCUMFLEX - return rune(0x011c), true - case "Gcy": // CYRILLIC CAPITAL LETTER GHE - return rune(0x0413), true - case "Gdot": // LATIN CAPITAL LETTER G WITH DOT ABOVE - return rune(0x0120), true - case "Gfr": // MATHEMATICAL FRAKTUR CAPITAL G - return rune(0x01d50a), true - case "Gg": // VERY MUCH GREATER-THAN - return rune(0x22d9), true - case "Ggr": // GREEK CAPITAL LETTER GAMMA - return rune(0x0393), true - case "Gopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL G - return rune(0x01d53e), true - case "GreaterEqual": // GREATER-THAN OR EQUAL TO - return rune(0x2265), true - case "GreaterEqualLess": // GREATER-THAN EQUAL TO OR LESS-THAN - return rune(0x22db), true - case "GreaterFullEqual": // GREATER-THAN OVER EQUAL TO - return rune(0x2267), true - case "GreaterGreater": // DOUBLE NESTED GREATER-THAN - return rune(0x2aa2), true - case "GreaterLess": // GREATER-THAN OR LESS-THAN - return rune(0x2277), true - case "GreaterSlantEqual": // GREATER-THAN OR SLANTED EQUAL TO - return rune(0x2a7e), true - case "GreaterTilde": // GREATER-THAN OR EQUIVALENT TO - return rune(0x2273), true - case "Gscr": // MATHEMATICAL SCRIPT CAPITAL G - return rune(0x01d4a2), true - case "Gt": // MUCH GREATER-THAN - return rune(0x226b), true + case "GJcy": // CYRILLIC CAPITAL LETTER GJE + return rune(0x0403), true + case "GT": // GREATER-THAN SIGN + return rune(0x3e), true + case "Game": // TURNED SANS-SERIF CAPITAL G + return rune(0x2141), true + case "Gamma": // GREEK CAPITAL LETTER GAMMA + return rune(0x0393), true + case "Gammad": // GREEK LETTER DIGAMMA + return rune(0x03dc), true + case "Gbreve": // LATIN CAPITAL LETTER G WITH BREVE + return rune(0x011e), true + case "Gcedil": // LATIN CAPITAL LETTER G WITH CEDILLA + return rune(0x0122), true + case "Gcirc": // LATIN CAPITAL LETTER G WITH CIRCUMFLEX + return rune(0x011c), true + case "Gcy": // CYRILLIC CAPITAL LETTER GHE + return rune(0x0413), true + case "Gdot": // LATIN CAPITAL LETTER G WITH DOT ABOVE + return rune(0x0120), true + case "Gfr": // MATHEMATICAL FRAKTUR CAPITAL G + return rune(0x01d50a), true + case "Gg": // VERY MUCH GREATER-THAN + return rune(0x22d9), true + case "Ggr": // GREEK CAPITAL LETTER GAMMA + return rune(0x0393), true + case "Gopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL G + return rune(0x01d53e), true + case "GreaterEqual": // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "GreaterEqualLess": // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "GreaterFullEqual": // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "GreaterGreater": // DOUBLE NESTED GREATER-THAN + return rune(0x2aa2), true + case "GreaterLess": // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "GreaterSlantEqual": // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "GreaterTilde": // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "Gscr": // MATHEMATICAL SCRIPT CAPITAL G + return rune(0x01d4a2), true + case "Gt": // MUCH GREATER-THAN + return rune(0x226b), true } case 'H': switch name { - case "HARDcy": // CYRILLIC CAPITAL LETTER HARD SIGN - return rune(0x042a), true - case "Hacek": // CARON - return rune(0x02c7), true - case "Hat": // CIRCUMFLEX ACCENT - return rune(0x5e), true - case "Hcirc": // LATIN CAPITAL LETTER H WITH CIRCUMFLEX - return rune(0x0124), true - case "Hfr": // BLACK-LETTER CAPITAL H - return rune(0x210c), true - case "HilbertSpace": // SCRIPT CAPITAL H - return rune(0x210b), true - case "Hopf": // DOUBLE-STRUCK CAPITAL H - return rune(0x210d), true - case "HorizontalLine": // BOX DRAWINGS LIGHT HORIZONTAL - return rune(0x2500), true - case "Hscr": // SCRIPT CAPITAL H - return rune(0x210b), true - case "Hstrok": // LATIN CAPITAL LETTER H WITH STROKE - return rune(0x0126), true - case "HumpDownHump": // GEOMETRICALLY EQUIVALENT TO - return rune(0x224e), true - case "HumpEqual": // DIFFERENCE BETWEEN - return rune(0x224f), true + case "HARDcy": // CYRILLIC CAPITAL LETTER HARD SIGN + return rune(0x042a), true + case "Hacek": // CARON + return rune(0x02c7), true + case "Hat": // CIRCUMFLEX ACCENT + return rune(0x5e), true + case "Hcirc": // LATIN CAPITAL LETTER H WITH CIRCUMFLEX + return rune(0x0124), true + case "Hfr": // BLACK-LETTER CAPITAL H + return rune(0x210c), true + case "HilbertSpace": // SCRIPT CAPITAL H + return rune(0x210b), true + case "Hopf": // DOUBLE-STRUCK CAPITAL H + return rune(0x210d), true + case "HorizontalLine": // BOX DRAWINGS LIGHT HORIZONTAL + return rune(0x2500), true + case "Hscr": // SCRIPT CAPITAL H + return rune(0x210b), true + case "Hstrok": // LATIN CAPITAL LETTER H WITH STROKE + return rune(0x0126), true + case "HumpDownHump": // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "HumpEqual": // DIFFERENCE BETWEEN + return rune(0x224f), true } case 'I': switch name { - case "IEcy": // CYRILLIC CAPITAL LETTER IE - return rune(0x0415), true - case "IJlig": // LATIN CAPITAL LIGATURE IJ - return rune(0x0132), true - case "IOcy": // CYRILLIC CAPITAL LETTER IO - return rune(0x0401), true - case "Iacgr": // GREEK CAPITAL LETTER IOTA WITH TONOS - return rune(0x038a), true - case "Iacute": // LATIN CAPITAL LETTER I WITH ACUTE - return rune(0xcd), true - case "Icirc": // LATIN CAPITAL LETTER I WITH CIRCUMFLEX - return rune(0xce), true - case "Icy": // CYRILLIC CAPITAL LETTER I - return rune(0x0418), true - case "Idigr": // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA - return rune(0x03aa), true - case "Idot": // LATIN CAPITAL LETTER I WITH DOT ABOVE - return rune(0x0130), true - case "Ifr": // BLACK-LETTER CAPITAL I - return rune(0x2111), true - case "Igr": // GREEK CAPITAL LETTER IOTA - return rune(0x0399), true - case "Igrave": // LATIN CAPITAL LETTER I WITH GRAVE - return rune(0xcc), true - case "Im": // BLACK-LETTER CAPITAL I - return rune(0x2111), true - case "Imacr": // LATIN CAPITAL LETTER I WITH MACRON - return rune(0x012a), true - case "ImaginaryI": // DOUBLE-STRUCK ITALIC SMALL I - return rune(0x2148), true - case "Implies": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true - case "Int": // DOUBLE INTEGRAL - return rune(0x222c), true - case "Integral": // INTEGRAL - return rune(0x222b), true - case "Intersection": // N-ARY INTERSECTION - return rune(0x22c2), true - case "InvisibleComma": // INVISIBLE SEPARATOR - return rune(0x2063), true - case "InvisibleTimes": // INVISIBLE TIMES - return rune(0x2062), true - case "Iogon": // LATIN CAPITAL LETTER I WITH OGONEK - return rune(0x012e), true - case "Iopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL I - return rune(0x01d540), true - case "Iota": // GREEK CAPITAL LETTER IOTA - return rune(0x0399), true - case "Iscr": // SCRIPT CAPITAL I - return rune(0x2110), true - case "Itilde": // LATIN CAPITAL LETTER I WITH TILDE - return rune(0x0128), true - case "Iukcy": // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I - return rune(0x0406), true - case "Iuml": // LATIN CAPITAL LETTER I WITH DIAERESIS - return rune(0xcf), true + case "IEcy": // CYRILLIC CAPITAL LETTER IE + return rune(0x0415), true + case "IJlig": // LATIN CAPITAL LIGATURE IJ + return rune(0x0132), true + case "IOcy": // CYRILLIC CAPITAL LETTER IO + return rune(0x0401), true + case "Iacgr": // GREEK CAPITAL LETTER IOTA WITH TONOS + return rune(0x038a), true + case "Iacute": // LATIN CAPITAL LETTER I WITH ACUTE + return rune(0xcd), true + case "Icirc": // LATIN CAPITAL LETTER I WITH CIRCUMFLEX + return rune(0xce), true + case "Icy": // CYRILLIC CAPITAL LETTER I + return rune(0x0418), true + case "Idigr": // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA + return rune(0x03aa), true + case "Idot": // LATIN CAPITAL LETTER I WITH DOT ABOVE + return rune(0x0130), true + case "Ifr": // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "Igr": // GREEK CAPITAL LETTER IOTA + return rune(0x0399), true + case "Igrave": // LATIN CAPITAL LETTER I WITH GRAVE + return rune(0xcc), true + case "Im": // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "Imacr": // LATIN CAPITAL LETTER I WITH MACRON + return rune(0x012a), true + case "ImaginaryI": // DOUBLE-STRUCK ITALIC SMALL I + return rune(0x2148), true + case "Implies": // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "Int": // DOUBLE INTEGRAL + return rune(0x222c), true + case "Integral": // INTEGRAL + return rune(0x222b), true + case "Intersection": // N-ARY INTERSECTION + return rune(0x22c2), true + case "InvisibleComma": // INVISIBLE SEPARATOR + return rune(0x2063), true + case "InvisibleTimes": // INVISIBLE TIMES + return rune(0x2062), true + case "Iogon": // LATIN CAPITAL LETTER I WITH OGONEK + return rune(0x012e), true + case "Iopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL I + return rune(0x01d540), true + case "Iota": // GREEK CAPITAL LETTER IOTA + return rune(0x0399), true + case "Iscr": // SCRIPT CAPITAL I + return rune(0x2110), true + case "Itilde": // LATIN CAPITAL LETTER I WITH TILDE + return rune(0x0128), true + case "Iukcy": // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I + return rune(0x0406), true + case "Iuml": // LATIN CAPITAL LETTER I WITH DIAERESIS + return rune(0xcf), true } case 'J': switch name { - case "Jcirc": // LATIN CAPITAL LETTER J WITH CIRCUMFLEX - return rune(0x0134), true - case "Jcy": // CYRILLIC CAPITAL LETTER SHORT I - return rune(0x0419), true - case "Jfr": // MATHEMATICAL FRAKTUR CAPITAL J - return rune(0x01d50d), true - case "Jopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL J - return rune(0x01d541), true - case "Jscr": // MATHEMATICAL SCRIPT CAPITAL J - return rune(0x01d4a5), true - case "Jsercy": // CYRILLIC CAPITAL LETTER JE - return rune(0x0408), true - case "Jukcy": // CYRILLIC CAPITAL LETTER UKRAINIAN IE - return rune(0x0404), true + case "Jcirc": // LATIN CAPITAL LETTER J WITH CIRCUMFLEX + return rune(0x0134), true + case "Jcy": // CYRILLIC CAPITAL LETTER SHORT I + return rune(0x0419), true + case "Jfr": // MATHEMATICAL FRAKTUR CAPITAL J + return rune(0x01d50d), true + case "Jopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL J + return rune(0x01d541), true + case "Jscr": // MATHEMATICAL SCRIPT CAPITAL J + return rune(0x01d4a5), true + case "Jsercy": // CYRILLIC CAPITAL LETTER JE + return rune(0x0408), true + case "Jukcy": // CYRILLIC CAPITAL LETTER UKRAINIAN IE + return rune(0x0404), true } case 'K': switch name { - case "KHcy": // CYRILLIC CAPITAL LETTER HA - return rune(0x0425), true - case "KHgr": // GREEK CAPITAL LETTER CHI - return rune(0x03a7), true - case "KJcy": // CYRILLIC CAPITAL LETTER KJE - return rune(0x040c), true - case "Kappa": // GREEK CAPITAL LETTER KAPPA - return rune(0x039a), true - case "Kcedil": // LATIN CAPITAL LETTER K WITH CEDILLA - return rune(0x0136), true - case "Kcy": // CYRILLIC CAPITAL LETTER KA - return rune(0x041a), true - case "Kfr": // MATHEMATICAL FRAKTUR CAPITAL K - return rune(0x01d50e), true - case "Kgr": // GREEK CAPITAL LETTER KAPPA - return rune(0x039a), true - case "Kopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL K - return rune(0x01d542), true - case "Kscr": // MATHEMATICAL SCRIPT CAPITAL K - return rune(0x01d4a6), true + case "KHcy": // CYRILLIC CAPITAL LETTER HA + return rune(0x0425), true + case "KHgr": // GREEK CAPITAL LETTER CHI + return rune(0x03a7), true + case "KJcy": // CYRILLIC CAPITAL LETTER KJE + return rune(0x040c), true + case "Kappa": // GREEK CAPITAL LETTER KAPPA + return rune(0x039a), true + case "Kcedil": // LATIN CAPITAL LETTER K WITH CEDILLA + return rune(0x0136), true + case "Kcy": // CYRILLIC CAPITAL LETTER KA + return rune(0x041a), true + case "Kfr": // MATHEMATICAL FRAKTUR CAPITAL K + return rune(0x01d50e), true + case "Kgr": // GREEK CAPITAL LETTER KAPPA + return rune(0x039a), true + case "Kopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL K + return rune(0x01d542), true + case "Kscr": // MATHEMATICAL SCRIPT CAPITAL K + return rune(0x01d4a6), true } case 'L': switch name { - case "LJcy": // CYRILLIC CAPITAL LETTER LJE - return rune(0x0409), true - case "LT": // LESS-THAN SIGN - return rune(0x3c), true - case "Lacute": // LATIN CAPITAL LETTER L WITH ACUTE - return rune(0x0139), true - case "Lambda": // GREEK CAPITAL LETTER LAMDA - return rune(0x039b), true - case "Lang": // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET - return rune(0x27ea), true - case "Laplacetrf": // SCRIPT CAPITAL L - return rune(0x2112), true - case "Larr": // LEFTWARDS TWO HEADED ARROW - return rune(0x219e), true - case "Lcaron": // LATIN CAPITAL LETTER L WITH CARON - return rune(0x013d), true - case "Lcedil": // LATIN CAPITAL LETTER L WITH CEDILLA - return rune(0x013b), true - case "Lcy": // CYRILLIC CAPITAL LETTER EL - return rune(0x041b), true - case "LeftAngleBracket": // MATHEMATICAL LEFT ANGLE BRACKET - return rune(0x27e8), true - case "LeftArrow": // LEFTWARDS ARROW - return rune(0x2190), true - case "LeftArrowBar": // LEFTWARDS ARROW TO BAR - return rune(0x21e4), true - case "LeftArrowRightArrow": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true - case "LeftCeiling": // LEFT CEILING - return rune(0x2308), true - case "LeftDoubleBracket": // MATHEMATICAL LEFT WHITE SQUARE BRACKET - return rune(0x27e6), true - case "LeftDownTeeVector": // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2961), true - case "LeftDownVector": // DOWNWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21c3), true - case "LeftDownVectorBar": // DOWNWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2959), true - case "LeftFloor": // LEFT FLOOR - return rune(0x230a), true - case "LeftRightArrow": // LEFT RIGHT ARROW - return rune(0x2194), true - case "LeftRightVector": // LEFT BARB UP RIGHT BARB UP HARPOON - return rune(0x294e), true - case "LeftTee": // LEFT TACK - return rune(0x22a3), true - case "LeftTeeArrow": // LEFTWARDS ARROW FROM BAR - return rune(0x21a4), true - case "LeftTeeVector": // LEFTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295a), true - case "LeftTriangle": // NORMAL SUBGROUP OF - return rune(0x22b2), true - case "LeftTriangleBar": // LEFT TRIANGLE BESIDE VERTICAL BAR - return rune(0x29cf), true - case "LeftTriangleEqual": // NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22b4), true - case "LeftUpDownVector": // UP BARB LEFT DOWN BARB LEFT HARPOON - return rune(0x2951), true - case "LeftUpTeeVector": // UPWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2960), true - case "LeftUpVector": // UPWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21bf), true - case "LeftUpVectorBar": // UPWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2958), true - case "LeftVector": // LEFTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21bc), true - case "LeftVectorBar": // LEFTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2952), true - case "Leftarrow": // LEFTWARDS DOUBLE ARROW - return rune(0x21d0), true - case "Leftrightarrow": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true - case "LessEqualGreater": // LESS-THAN EQUAL TO OR GREATER-THAN - return rune(0x22da), true - case "LessFullEqual": // LESS-THAN OVER EQUAL TO - return rune(0x2266), true - case "LessGreater": // LESS-THAN OR GREATER-THAN - return rune(0x2276), true - case "LessLess": // DOUBLE NESTED LESS-THAN - return rune(0x2aa1), true - case "LessSlantEqual": // LESS-THAN OR SLANTED EQUAL TO - return rune(0x2a7d), true - case "LessTilde": // LESS-THAN OR EQUIVALENT TO - return rune(0x2272), true - case "Lfr": // MATHEMATICAL FRAKTUR CAPITAL L - return rune(0x01d50f), true - case "Lgr": // GREEK CAPITAL LETTER LAMDA - return rune(0x039b), true - case "Ll": // VERY MUCH LESS-THAN - return rune(0x22d8), true - case "Lleftarrow": // LEFTWARDS TRIPLE ARROW - return rune(0x21da), true - case "Lmidot": // LATIN CAPITAL LETTER L WITH MIDDLE DOT - return rune(0x013f), true - case "LongLeftArrow": // LONG LEFTWARDS ARROW - return rune(0x27f5), true - case "LongLeftRightArrow": // LONG LEFT RIGHT ARROW - return rune(0x27f7), true - case "LongRightArrow": // LONG RIGHTWARDS ARROW - return rune(0x27f6), true - case "Longleftarrow": // LONG LEFTWARDS DOUBLE ARROW - return rune(0x27f8), true - case "Longleftrightarrow": // LONG LEFT RIGHT DOUBLE ARROW - return rune(0x27fa), true - case "Longrightarrow": // LONG RIGHTWARDS DOUBLE ARROW - return rune(0x27f9), true - case "Lopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL L - return rune(0x01d543), true - case "LowerLeftArrow": // SOUTH WEST ARROW - return rune(0x2199), true - case "LowerRightArrow": // SOUTH EAST ARROW - return rune(0x2198), true - case "Lscr": // SCRIPT CAPITAL L - return rune(0x2112), true - case "Lsh": // UPWARDS ARROW WITH TIP LEFTWARDS - return rune(0x21b0), true - case "Lstrok": // LATIN CAPITAL LETTER L WITH STROKE - return rune(0x0141), true - case "Lt": // MUCH LESS-THAN - return rune(0x226a), true - case "Ltbar": // DOUBLE NESTED LESS-THAN WITH UNDERBAR - return rune(0x2aa3), true + case "LJcy": // CYRILLIC CAPITAL LETTER LJE + return rune(0x0409), true + case "LT": // LESS-THAN SIGN + return rune(0x3c), true + case "Lacute": // LATIN CAPITAL LETTER L WITH ACUTE + return rune(0x0139), true + case "Lambda": // GREEK CAPITAL LETTER LAMDA + return rune(0x039b), true + case "Lang": // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET + return rune(0x27ea), true + case "Laplacetrf": // SCRIPT CAPITAL L + return rune(0x2112), true + case "Larr": // LEFTWARDS TWO HEADED ARROW + return rune(0x219e), true + case "Lcaron": // LATIN CAPITAL LETTER L WITH CARON + return rune(0x013d), true + case "Lcedil": // LATIN CAPITAL LETTER L WITH CEDILLA + return rune(0x013b), true + case "Lcy": // CYRILLIC CAPITAL LETTER EL + return rune(0x041b), true + case "LeftAngleBracket": // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "LeftArrow": // LEFTWARDS ARROW + return rune(0x2190), true + case "LeftArrowBar": // LEFTWARDS ARROW TO BAR + return rune(0x21e4), true + case "LeftArrowRightArrow": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "LeftCeiling": // LEFT CEILING + return rune(0x2308), true + case "LeftDoubleBracket": // MATHEMATICAL LEFT WHITE SQUARE BRACKET + return rune(0x27e6), true + case "LeftDownTeeVector": // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2961), true + case "LeftDownVector": // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "LeftDownVectorBar": // DOWNWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2959), true + case "LeftFloor": // LEFT FLOOR + return rune(0x230a), true + case "LeftRightArrow": // LEFT RIGHT ARROW + return rune(0x2194), true + case "LeftRightVector": // LEFT BARB UP RIGHT BARB UP HARPOON + return rune(0x294e), true + case "LeftTee": // LEFT TACK + return rune(0x22a3), true + case "LeftTeeArrow": // LEFTWARDS ARROW FROM BAR + return rune(0x21a4), true + case "LeftTeeVector": // LEFTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295a), true + case "LeftTriangle": // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "LeftTriangleBar": // LEFT TRIANGLE BESIDE VERTICAL BAR + return rune(0x29cf), true + case "LeftTriangleEqual": // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "LeftUpDownVector": // UP BARB LEFT DOWN BARB LEFT HARPOON + return rune(0x2951), true + case "LeftUpTeeVector": // UPWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2960), true + case "LeftUpVector": // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "LeftUpVectorBar": // UPWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2958), true + case "LeftVector": // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "LeftVectorBar": // LEFTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2952), true + case "Leftarrow": // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "Leftrightarrow": // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "LessEqualGreater": // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "LessFullEqual": // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "LessGreater": // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "LessLess": // DOUBLE NESTED LESS-THAN + return rune(0x2aa1), true + case "LessSlantEqual": // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "LessTilde": // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "Lfr": // MATHEMATICAL FRAKTUR CAPITAL L + return rune(0x01d50f), true + case "Lgr": // GREEK CAPITAL LETTER LAMDA + return rune(0x039b), true + case "Ll": // VERY MUCH LESS-THAN + return rune(0x22d8), true + case "Lleftarrow": // LEFTWARDS TRIPLE ARROW + return rune(0x21da), true + case "Lmidot": // LATIN CAPITAL LETTER L WITH MIDDLE DOT + return rune(0x013f), true + case "LongLeftArrow": // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "LongLeftRightArrow": // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "LongRightArrow": // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "Longleftarrow": // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "Longleftrightarrow": // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "Longrightarrow": // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "Lopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL L + return rune(0x01d543), true + case "LowerLeftArrow": // SOUTH WEST ARROW + return rune(0x2199), true + case "LowerRightArrow": // SOUTH EAST ARROW + return rune(0x2198), true + case "Lscr": // SCRIPT CAPITAL L + return rune(0x2112), true + case "Lsh": // UPWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b0), true + case "Lstrok": // LATIN CAPITAL LETTER L WITH STROKE + return rune(0x0141), true + case "Lt": // MUCH LESS-THAN + return rune(0x226a), true + case "Ltbar": // DOUBLE NESTED LESS-THAN WITH UNDERBAR + return rune(0x2aa3), true } case 'M': switch name { - case "Map": // RIGHTWARDS TWO-HEADED ARROW FROM BAR - return rune(0x2905), true - case "Mapfrom": // LEFTWARDS DOUBLE ARROW FROM BAR - return rune(0x2906), true - case "Mapto": // RIGHTWARDS DOUBLE ARROW FROM BAR - return rune(0x2907), true - case "Mcy": // CYRILLIC CAPITAL LETTER EM - return rune(0x041c), true - case "MediumSpace": // MEDIUM MATHEMATICAL SPACE - return rune(0x205f), true - case "Mellintrf": // SCRIPT CAPITAL M - return rune(0x2133), true - case "Mfr": // MATHEMATICAL FRAKTUR CAPITAL M - return rune(0x01d510), true - case "Mgr": // GREEK CAPITAL LETTER MU - return rune(0x039c), true - case "MinusPlus": // MINUS-OR-PLUS SIGN - return rune(0x2213), true - case "Mopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL M - return rune(0x01d544), true - case "Mscr": // SCRIPT CAPITAL M - return rune(0x2133), true - case "Mu": // GREEK CAPITAL LETTER MU - return rune(0x039c), true + case "Map": // RIGHTWARDS TWO-HEADED ARROW FROM BAR + return rune(0x2905), true + case "Mapfrom": // LEFTWARDS DOUBLE ARROW FROM BAR + return rune(0x2906), true + case "Mapto": // RIGHTWARDS DOUBLE ARROW FROM BAR + return rune(0x2907), true + case "Mcy": // CYRILLIC CAPITAL LETTER EM + return rune(0x041c), true + case "MediumSpace": // MEDIUM MATHEMATICAL SPACE + return rune(0x205f), true + case "Mellintrf": // SCRIPT CAPITAL M + return rune(0x2133), true + case "Mfr": // MATHEMATICAL FRAKTUR CAPITAL M + return rune(0x01d510), true + case "Mgr": // GREEK CAPITAL LETTER MU + return rune(0x039c), true + case "MinusPlus": // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "Mopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL M + return rune(0x01d544), true + case "Mscr": // SCRIPT CAPITAL M + return rune(0x2133), true + case "Mu": // GREEK CAPITAL LETTER MU + return rune(0x039c), true } case 'N': switch name { - case "NJcy": // CYRILLIC CAPITAL LETTER NJE - return rune(0x040a), true - case "Nacute": // LATIN CAPITAL LETTER N WITH ACUTE - return rune(0x0143), true - case "Ncaron": // LATIN CAPITAL LETTER N WITH CARON - return rune(0x0147), true - case "Ncedil": // LATIN CAPITAL LETTER N WITH CEDILLA - return rune(0x0145), true - case "Ncy": // CYRILLIC CAPITAL LETTER EN - return rune(0x041d), true - case "NegativeMediumSpace": // ZERO WIDTH SPACE - return rune(0x200b), true - case "NegativeThickSpace": // ZERO WIDTH SPACE - return rune(0x200b), true - case "NegativeThinSpace": // ZERO WIDTH SPACE - return rune(0x200b), true - case "NegativeVeryThinSpace": // ZERO WIDTH SPACE - return rune(0x200b), true - case "NestedGreaterGreater": // MUCH GREATER-THAN - return rune(0x226b), true - case "NestedLessLess": // MUCH LESS-THAN - return rune(0x226a), true - case "NewLine": // LINE FEED (LF) - return rune(0x0a), true - case "Nfr": // MATHEMATICAL FRAKTUR CAPITAL N - return rune(0x01d511), true - case "Ngr": // GREEK CAPITAL LETTER NU - return rune(0x039d), true - case "NoBreak": // WORD JOINER - return rune(0x2060), true - case "NonBreakingSpace": // NO-BREAK SPACE - return rune(0xa0), true - case "Nopf": // DOUBLE-STRUCK CAPITAL N - return rune(0x2115), true - case "Not": // DOUBLE STROKE NOT SIGN - return rune(0x2aec), true - case "NotCongruent": // NOT IDENTICAL TO - return rune(0x2262), true - case "NotCupCap": // NOT EQUIVALENT TO - return rune(0x226d), true - case "NotDoubleVerticalBar": // NOT PARALLEL TO - return rune(0x2226), true - case "NotElement": // NOT AN ELEMENT OF - return rune(0x2209), true - case "NotEqual": // NOT EQUAL TO - return rune(0x2260), true - case "NotEqualTilde": // MINUS TILDE with slash - return rune(0x2242), true - case "NotExists": // THERE DOES NOT EXIST - return rune(0x2204), true - case "NotGreater": // NOT GREATER-THAN - return rune(0x226f), true - case "NotGreaterEqual": // NEITHER GREATER-THAN NOR EQUAL TO - return rune(0x2271), true - case "NotGreaterFullEqual": // GREATER-THAN OVER EQUAL TO with slash - return rune(0x2267), true - case "NotGreaterGreater": // MUCH GREATER THAN with slash - return rune(0x226b), true - case "NotGreaterLess": // NEITHER GREATER-THAN NOR LESS-THAN - return rune(0x2279), true - case "NotGreaterSlantEqual": // GREATER-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7e), true - case "NotGreaterTilde": // NEITHER GREATER-THAN NOR EQUIVALENT TO - return rune(0x2275), true - case "NotHumpDownHump": // GEOMETRICALLY EQUIVALENT TO with slash - return rune(0x224e), true - case "NotHumpEqual": // DIFFERENCE BETWEEN with slash - return rune(0x224f), true - case "NotLeftTriangle": // NOT NORMAL SUBGROUP OF - return rune(0x22ea), true - case "NotLeftTriangleBar": // LEFT TRIANGLE BESIDE VERTICAL BAR with slash - return rune(0x29cf), true - case "NotLeftTriangleEqual": // NOT NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22ec), true - case "NotLess": // NOT LESS-THAN - return rune(0x226e), true - case "NotLessEqual": // NEITHER LESS-THAN NOR EQUAL TO - return rune(0x2270), true - case "NotLessGreater": // NEITHER LESS-THAN NOR GREATER-THAN - return rune(0x2278), true - case "NotLessLess": // MUCH LESS THAN with slash - return rune(0x226a), true - case "NotLessSlantEqual": // LESS-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7d), true - case "NotLessTilde": // NEITHER LESS-THAN NOR EQUIVALENT TO - return rune(0x2274), true - case "NotNestedGreaterGreater": // DOUBLE NESTED GREATER-THAN with slash - return rune(0x2aa2), true - case "NotNestedLessLess": // DOUBLE NESTED LESS-THAN with slash - return rune(0x2aa1), true - case "NotPrecedes": // DOES NOT PRECEDE - return rune(0x2280), true - case "NotPrecedesEqual": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2aaf), true - case "NotPrecedesSlantEqual": // DOES NOT PRECEDE OR EQUAL - return rune(0x22e0), true - case "NotReverseElement": // DOES NOT CONTAIN AS MEMBER - return rune(0x220c), true - case "NotRightTriangle": // DOES NOT CONTAIN AS NORMAL SUBGROUP - return rune(0x22eb), true - case "NotRightTriangleBar": // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash - return rune(0x29d0), true - case "NotRightTriangleEqual": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - return rune(0x22ed), true - case "NotSquareSubset": // SQUARE IMAGE OF with slash - return rune(0x228f), true - case "NotSquareSubsetEqual": // NOT SQUARE IMAGE OF OR EQUAL TO - return rune(0x22e2), true - case "NotSquareSuperset": // SQUARE ORIGINAL OF with slash - return rune(0x2290), true - case "NotSquareSupersetEqual": // NOT SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x22e3), true - case "NotSubset": // SUBSET OF with vertical line - return rune(0x2282), true - case "NotSubsetEqual": // NEITHER A SUBSET OF NOR EQUAL TO - return rune(0x2288), true - case "NotSucceeds": // DOES NOT SUCCEED - return rune(0x2281), true - case "NotSucceedsEqual": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2ab0), true - case "NotSucceedsSlantEqual": // DOES NOT SUCCEED OR EQUAL - return rune(0x22e1), true - case "NotSucceedsTilde": // SUCCEEDS OR EQUIVALENT TO with slash - return rune(0x227f), true - case "NotSuperset": // SUPERSET OF with vertical line - return rune(0x2283), true - case "NotSupersetEqual": // NEITHER A SUPERSET OF NOR EQUAL TO - return rune(0x2289), true - case "NotTilde": // NOT TILDE - return rune(0x2241), true - case "NotTildeEqual": // NOT ASYMPTOTICALLY EQUAL TO - return rune(0x2244), true - case "NotTildeFullEqual": // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO - return rune(0x2247), true - case "NotTildeTilde": // NOT ALMOST EQUAL TO - return rune(0x2249), true - case "NotVerticalBar": // DOES NOT DIVIDE - return rune(0x2224), true - case "Nscr": // MATHEMATICAL SCRIPT CAPITAL N - return rune(0x01d4a9), true - case "Ntilde": // LATIN CAPITAL LETTER N WITH TILDE - return rune(0xd1), true - case "Nu": // GREEK CAPITAL LETTER NU - return rune(0x039d), true + case "NJcy": // CYRILLIC CAPITAL LETTER NJE + return rune(0x040a), true + case "Nacute": // LATIN CAPITAL LETTER N WITH ACUTE + return rune(0x0143), true + case "Ncaron": // LATIN CAPITAL LETTER N WITH CARON + return rune(0x0147), true + case "Ncedil": // LATIN CAPITAL LETTER N WITH CEDILLA + return rune(0x0145), true + case "Ncy": // CYRILLIC CAPITAL LETTER EN + return rune(0x041d), true + case "NegativeMediumSpace": // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeThickSpace": // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeThinSpace": // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeVeryThinSpace": // ZERO WIDTH SPACE + return rune(0x200b), true + case "NestedGreaterGreater": // MUCH GREATER-THAN + return rune(0x226b), true + case "NestedLessLess": // MUCH LESS-THAN + return rune(0x226a), true + case "NewLine": // LINE FEED (LF) + return rune(0x0a), true + case "Nfr": // MATHEMATICAL FRAKTUR CAPITAL N + return rune(0x01d511), true + case "Ngr": // GREEK CAPITAL LETTER NU + return rune(0x039d), true + case "NoBreak": // WORD JOINER + return rune(0x2060), true + case "NonBreakingSpace": // NO-BREAK SPACE + return rune(0xa0), true + case "Nopf": // DOUBLE-STRUCK CAPITAL N + return rune(0x2115), true + case "Not": // DOUBLE STROKE NOT SIGN + return rune(0x2aec), true + case "NotCongruent": // NOT IDENTICAL TO + return rune(0x2262), true + case "NotCupCap": // NOT EQUIVALENT TO + return rune(0x226d), true + case "NotDoubleVerticalBar": // NOT PARALLEL TO + return rune(0x2226), true + case "NotElement": // NOT AN ELEMENT OF + return rune(0x2209), true + case "NotEqual": // NOT EQUAL TO + return rune(0x2260), true + case "NotEqualTilde": // MINUS TILDE with slash + return rune(0x2242), true + case "NotExists": // THERE DOES NOT EXIST + return rune(0x2204), true + case "NotGreater": // NOT GREATER-THAN + return rune(0x226f), true + case "NotGreaterEqual": // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "NotGreaterFullEqual": // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "NotGreaterGreater": // MUCH GREATER THAN with slash + return rune(0x226b), true + case "NotGreaterLess": // NEITHER GREATER-THAN NOR LESS-THAN + return rune(0x2279), true + case "NotGreaterSlantEqual": // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "NotGreaterTilde": // NEITHER GREATER-THAN NOR EQUIVALENT TO + return rune(0x2275), true + case "NotHumpDownHump": // GEOMETRICALLY EQUIVALENT TO with slash + return rune(0x224e), true + case "NotHumpEqual": // DIFFERENCE BETWEEN with slash + return rune(0x224f), true + case "NotLeftTriangle": // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "NotLeftTriangleBar": // LEFT TRIANGLE BESIDE VERTICAL BAR with slash + return rune(0x29cf), true + case "NotLeftTriangleEqual": // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "NotLess": // NOT LESS-THAN + return rune(0x226e), true + case "NotLessEqual": // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "NotLessGreater": // NEITHER LESS-THAN NOR GREATER-THAN + return rune(0x2278), true + case "NotLessLess": // MUCH LESS THAN with slash + return rune(0x226a), true + case "NotLessSlantEqual": // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "NotLessTilde": // NEITHER LESS-THAN NOR EQUIVALENT TO + return rune(0x2274), true + case "NotNestedGreaterGreater": // DOUBLE NESTED GREATER-THAN with slash + return rune(0x2aa2), true + case "NotNestedLessLess": // DOUBLE NESTED LESS-THAN with slash + return rune(0x2aa1), true + case "NotPrecedes": // DOES NOT PRECEDE + return rune(0x2280), true + case "NotPrecedesEqual": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "NotPrecedesSlantEqual": // DOES NOT PRECEDE OR EQUAL + return rune(0x22e0), true + case "NotReverseElement": // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "NotRightTriangle": // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "NotRightTriangleBar": // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash + return rune(0x29d0), true + case "NotRightTriangleEqual": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "NotSquareSubset": // SQUARE IMAGE OF with slash + return rune(0x228f), true + case "NotSquareSubsetEqual": // NOT SQUARE IMAGE OF OR EQUAL TO + return rune(0x22e2), true + case "NotSquareSuperset": // SQUARE ORIGINAL OF with slash + return rune(0x2290), true + case "NotSquareSupersetEqual": // NOT SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x22e3), true + case "NotSubset": // SUBSET OF with vertical line + return rune(0x2282), true + case "NotSubsetEqual": // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "NotSucceeds": // DOES NOT SUCCEED + return rune(0x2281), true + case "NotSucceedsEqual": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "NotSucceedsSlantEqual": // DOES NOT SUCCEED OR EQUAL + return rune(0x22e1), true + case "NotSucceedsTilde": // SUCCEEDS OR EQUIVALENT TO with slash + return rune(0x227f), true + case "NotSuperset": // SUPERSET OF with vertical line + return rune(0x2283), true + case "NotSupersetEqual": // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "NotTilde": // NOT TILDE + return rune(0x2241), true + case "NotTildeEqual": // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "NotTildeFullEqual": // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + return rune(0x2247), true + case "NotTildeTilde": // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "NotVerticalBar": // DOES NOT DIVIDE + return rune(0x2224), true + case "Nscr": // MATHEMATICAL SCRIPT CAPITAL N + return rune(0x01d4a9), true + case "Ntilde": // LATIN CAPITAL LETTER N WITH TILDE + return rune(0xd1), true + case "Nu": // GREEK CAPITAL LETTER NU + return rune(0x039d), true } case 'O': switch name { - case "OElig": // LATIN CAPITAL LIGATURE OE - return rune(0x0152), true - case "OHacgr": // GREEK CAPITAL LETTER OMEGA WITH TONOS - return rune(0x038f), true - case "OHgr": // GREEK CAPITAL LETTER OMEGA - return rune(0x03a9), true - case "Oacgr": // GREEK CAPITAL LETTER OMICRON WITH TONOS - return rune(0x038c), true - case "Oacute": // LATIN CAPITAL LETTER O WITH ACUTE - return rune(0xd3), true - case "Ocirc": // LATIN CAPITAL LETTER O WITH CIRCUMFLEX - return rune(0xd4), true - case "Ocy": // CYRILLIC CAPITAL LETTER O - return rune(0x041e), true - case "Odblac": // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE - return rune(0x0150), true - case "Ofr": // MATHEMATICAL FRAKTUR CAPITAL O - return rune(0x01d512), true - case "Ogr": // GREEK CAPITAL LETTER OMICRON - return rune(0x039f), true - case "Ograve": // LATIN CAPITAL LETTER O WITH GRAVE - return rune(0xd2), true - case "Omacr": // LATIN CAPITAL LETTER O WITH MACRON - return rune(0x014c), true - case "Omega": // GREEK CAPITAL LETTER OMEGA - return rune(0x03a9), true - case "Omicron": // GREEK CAPITAL LETTER OMICRON - return rune(0x039f), true - case "Oopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL O - return rune(0x01d546), true - case "OpenCurlyDoubleQuote": // LEFT DOUBLE QUOTATION MARK - return rune(0x201c), true - case "OpenCurlyQuote": // LEFT SINGLE QUOTATION MARK - return rune(0x2018), true - case "Or": // DOUBLE LOGICAL OR - return rune(0x2a54), true - case "Oscr": // MATHEMATICAL SCRIPT CAPITAL O - return rune(0x01d4aa), true - case "Oslash": // LATIN CAPITAL LETTER O WITH STROKE - return rune(0xd8), true - case "Otilde": // LATIN CAPITAL LETTER O WITH TILDE - return rune(0xd5), true - case "Otimes": // MULTIPLICATION SIGN IN DOUBLE CIRCLE - return rune(0x2a37), true - case "Ouml": // LATIN CAPITAL LETTER O WITH DIAERESIS - return rune(0xd6), true - case "OverBar": // OVERLINE - return rune(0x203e), true - case "OverBrace": // TOP CURLY BRACKET - return rune(0x23de), true - case "OverBracket": // TOP SQUARE BRACKET - return rune(0x23b4), true - case "OverParenthesis": // TOP PARENTHESIS - return rune(0x23dc), true + case "OElig": // LATIN CAPITAL LIGATURE OE + return rune(0x0152), true + case "OHacgr": // GREEK CAPITAL LETTER OMEGA WITH TONOS + return rune(0x038f), true + case "OHgr": // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "Oacgr": // GREEK CAPITAL LETTER OMICRON WITH TONOS + return rune(0x038c), true + case "Oacute": // LATIN CAPITAL LETTER O WITH ACUTE + return rune(0xd3), true + case "Ocirc": // LATIN CAPITAL LETTER O WITH CIRCUMFLEX + return rune(0xd4), true + case "Ocy": // CYRILLIC CAPITAL LETTER O + return rune(0x041e), true + case "Odblac": // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE + return rune(0x0150), true + case "Ofr": // MATHEMATICAL FRAKTUR CAPITAL O + return rune(0x01d512), true + case "Ogr": // GREEK CAPITAL LETTER OMICRON + return rune(0x039f), true + case "Ograve": // LATIN CAPITAL LETTER O WITH GRAVE + return rune(0xd2), true + case "Omacr": // LATIN CAPITAL LETTER O WITH MACRON + return rune(0x014c), true + case "Omega": // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "Omicron": // GREEK CAPITAL LETTER OMICRON + return rune(0x039f), true + case "Oopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL O + return rune(0x01d546), true + case "OpenCurlyDoubleQuote": // LEFT DOUBLE QUOTATION MARK + return rune(0x201c), true + case "OpenCurlyQuote": // LEFT SINGLE QUOTATION MARK + return rune(0x2018), true + case "Or": // DOUBLE LOGICAL OR + return rune(0x2a54), true + case "Oscr": // MATHEMATICAL SCRIPT CAPITAL O + return rune(0x01d4aa), true + case "Oslash": // LATIN CAPITAL LETTER O WITH STROKE + return rune(0xd8), true + case "Otilde": // LATIN CAPITAL LETTER O WITH TILDE + return rune(0xd5), true + case "Otimes": // MULTIPLICATION SIGN IN DOUBLE CIRCLE + return rune(0x2a37), true + case "Ouml": // LATIN CAPITAL LETTER O WITH DIAERESIS + return rune(0xd6), true + case "OverBar": // OVERLINE + return rune(0x203e), true + case "OverBrace": // TOP CURLY BRACKET + return rune(0x23de), true + case "OverBracket": // TOP SQUARE BRACKET + return rune(0x23b4), true + case "OverParenthesis": // TOP PARENTHESIS + return rune(0x23dc), true } case 'P': switch name { - case "PHgr": // GREEK CAPITAL LETTER PHI - return rune(0x03a6), true - case "PSgr": // GREEK CAPITAL LETTER PSI - return rune(0x03a8), true - case "PartialD": // PARTIAL DIFFERENTIAL - return rune(0x2202), true - case "Pcy": // CYRILLIC CAPITAL LETTER PE - return rune(0x041f), true - case "Pfr": // MATHEMATICAL FRAKTUR CAPITAL P - return rune(0x01d513), true - case "Pgr": // GREEK CAPITAL LETTER PI - return rune(0x03a0), true - case "Phi": // GREEK CAPITAL LETTER PHI - return rune(0x03a6), true - case "Pi": // GREEK CAPITAL LETTER PI - return rune(0x03a0), true - case "PlusMinus": // PLUS-MINUS SIGN - return rune(0xb1), true - case "Poincareplane": // BLACK-LETTER CAPITAL H - return rune(0x210c), true - case "Popf": // DOUBLE-STRUCK CAPITAL P - return rune(0x2119), true - case "Pr": // DOUBLE PRECEDES - return rune(0x2abb), true - case "Precedes": // PRECEDES - return rune(0x227a), true - case "PrecedesEqual": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2aaf), true - case "PrecedesSlantEqual": // PRECEDES OR EQUAL TO - return rune(0x227c), true - case "PrecedesTilde": // PRECEDES OR EQUIVALENT TO - return rune(0x227e), true - case "Prime": // DOUBLE PRIME - return rune(0x2033), true - case "Product": // N-ARY PRODUCT - return rune(0x220f), true - case "Proportion": // PROPORTION - return rune(0x2237), true - case "Proportional": // PROPORTIONAL TO - return rune(0x221d), true - case "Pscr": // MATHEMATICAL SCRIPT CAPITAL P - return rune(0x01d4ab), true - case "Psi": // GREEK CAPITAL LETTER PSI - return rune(0x03a8), true + case "PHgr": // GREEK CAPITAL LETTER PHI + return rune(0x03a6), true + case "PSgr": // GREEK CAPITAL LETTER PSI + return rune(0x03a8), true + case "PartialD": // PARTIAL DIFFERENTIAL + return rune(0x2202), true + case "Pcy": // CYRILLIC CAPITAL LETTER PE + return rune(0x041f), true + case "Pfr": // MATHEMATICAL FRAKTUR CAPITAL P + return rune(0x01d513), true + case "Pgr": // GREEK CAPITAL LETTER PI + return rune(0x03a0), true + case "Phi": // GREEK CAPITAL LETTER PHI + return rune(0x03a6), true + case "Pi": // GREEK CAPITAL LETTER PI + return rune(0x03a0), true + case "PlusMinus": // PLUS-MINUS SIGN + return rune(0xb1), true + case "Poincareplane": // BLACK-LETTER CAPITAL H + return rune(0x210c), true + case "Popf": // DOUBLE-STRUCK CAPITAL P + return rune(0x2119), true + case "Pr": // DOUBLE PRECEDES + return rune(0x2abb), true + case "Precedes": // PRECEDES + return rune(0x227a), true + case "PrecedesEqual": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "PrecedesSlantEqual": // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "PrecedesTilde": // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "Prime": // DOUBLE PRIME + return rune(0x2033), true + case "Product": // N-ARY PRODUCT + return rune(0x220f), true + case "Proportion": // PROPORTION + return rune(0x2237), true + case "Proportional": // PROPORTIONAL TO + return rune(0x221d), true + case "Pscr": // MATHEMATICAL SCRIPT CAPITAL P + return rune(0x01d4ab), true + case "Psi": // GREEK CAPITAL LETTER PSI + return rune(0x03a8), true } case 'Q': switch name { - case "QUOT": // QUOTATION MARK - return rune(0x22), true - case "Qfr": // MATHEMATICAL FRAKTUR CAPITAL Q - return rune(0x01d514), true - case "Qopf": // DOUBLE-STRUCK CAPITAL Q - return rune(0x211a), true - case "Qscr": // MATHEMATICAL SCRIPT CAPITAL Q - return rune(0x01d4ac), true + case "QUOT": // QUOTATION MARK + return rune(0x22), true + case "Qfr": // MATHEMATICAL FRAKTUR CAPITAL Q + return rune(0x01d514), true + case "Qopf": // DOUBLE-STRUCK CAPITAL Q + return rune(0x211a), true + case "Qscr": // MATHEMATICAL SCRIPT CAPITAL Q + return rune(0x01d4ac), true } case 'R': switch name { - case "RBarr": // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - return rune(0x2910), true - case "REG": // REGISTERED SIGN - return rune(0xae), true - case "Racute": // LATIN CAPITAL LETTER R WITH ACUTE - return rune(0x0154), true - case "Rang": // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET - return rune(0x27eb), true - case "Rarr": // RIGHTWARDS TWO HEADED ARROW - return rune(0x21a0), true - case "Rarrtl": // RIGHTWARDS TWO-HEADED ARROW WITH TAIL - return rune(0x2916), true - case "Rcaron": // LATIN CAPITAL LETTER R WITH CARON - return rune(0x0158), true - case "Rcedil": // LATIN CAPITAL LETTER R WITH CEDILLA - return rune(0x0156), true - case "Rcy": // CYRILLIC CAPITAL LETTER ER - return rune(0x0420), true - case "Re": // BLACK-LETTER CAPITAL R - return rune(0x211c), true - case "ReverseElement": // CONTAINS AS MEMBER - return rune(0x220b), true - case "ReverseEquilibrium": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true - case "ReverseUpEquilibrium": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - return rune(0x296f), true - case "Rfr": // BLACK-LETTER CAPITAL R - return rune(0x211c), true - case "Rgr": // GREEK CAPITAL LETTER RHO - return rune(0x03a1), true - case "Rho": // GREEK CAPITAL LETTER RHO - return rune(0x03a1), true - case "RightAngleBracket": // MATHEMATICAL RIGHT ANGLE BRACKET - return rune(0x27e9), true - case "RightArrow": // RIGHTWARDS ARROW - return rune(0x2192), true - case "RightArrowBar": // RIGHTWARDS ARROW TO BAR - return rune(0x21e5), true - case "RightArrowLeftArrow": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true - case "RightCeiling": // RIGHT CEILING - return rune(0x2309), true - case "RightDoubleBracket": // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - return rune(0x27e7), true - case "RightDownTeeVector": // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295d), true - case "RightDownVector": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21c2), true - case "RightDownVectorBar": // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2955), true - case "RightFloor": // RIGHT FLOOR - return rune(0x230b), true - case "RightTee": // RIGHT TACK - return rune(0x22a2), true - case "RightTeeArrow": // RIGHTWARDS ARROW FROM BAR - return rune(0x21a6), true - case "RightTeeVector": // RIGHTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295b), true - case "RightTriangle": // CONTAINS AS NORMAL SUBGROUP - return rune(0x22b3), true - case "RightTriangleBar": // VERTICAL BAR BESIDE RIGHT TRIANGLE - return rune(0x29d0), true - case "RightTriangleEqual": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - return rune(0x22b5), true - case "RightUpDownVector": // UP BARB RIGHT DOWN BARB RIGHT HARPOON - return rune(0x294f), true - case "RightUpTeeVector": // UPWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295c), true - case "RightUpVector": // UPWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21be), true - case "RightUpVectorBar": // UPWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2954), true - case "RightVector": // RIGHTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21c0), true - case "RightVectorBar": // RIGHTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2953), true - case "Rightarrow": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true - case "Ropf": // DOUBLE-STRUCK CAPITAL R - return rune(0x211d), true - case "RoundImplies": // RIGHT DOUBLE ARROW WITH ROUNDED HEAD - return rune(0x2970), true - case "Rrightarrow": // RIGHTWARDS TRIPLE ARROW - return rune(0x21db), true - case "Rscr": // SCRIPT CAPITAL R - return rune(0x211b), true - case "Rsh": // UPWARDS ARROW WITH TIP RIGHTWARDS - return rune(0x21b1), true - case "RuleDelayed": // RULE-DELAYED - return rune(0x29f4), true + case "RBarr": // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW + return rune(0x2910), true + case "REG": // REGISTERED SIGN + return rune(0xae), true + case "Racute": // LATIN CAPITAL LETTER R WITH ACUTE + return rune(0x0154), true + case "Rang": // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET + return rune(0x27eb), true + case "Rarr": // RIGHTWARDS TWO HEADED ARROW + return rune(0x21a0), true + case "Rarrtl": // RIGHTWARDS TWO-HEADED ARROW WITH TAIL + return rune(0x2916), true + case "Rcaron": // LATIN CAPITAL LETTER R WITH CARON + return rune(0x0158), true + case "Rcedil": // LATIN CAPITAL LETTER R WITH CEDILLA + return rune(0x0156), true + case "Rcy": // CYRILLIC CAPITAL LETTER ER + return rune(0x0420), true + case "Re": // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "ReverseElement": // CONTAINS AS MEMBER + return rune(0x220b), true + case "ReverseEquilibrium": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "ReverseUpEquilibrium": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x296f), true + case "Rfr": // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "Rgr": // GREEK CAPITAL LETTER RHO + return rune(0x03a1), true + case "Rho": // GREEK CAPITAL LETTER RHO + return rune(0x03a1), true + case "RightAngleBracket": // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "RightArrow": // RIGHTWARDS ARROW + return rune(0x2192), true + case "RightArrowBar": // RIGHTWARDS ARROW TO BAR + return rune(0x21e5), true + case "RightArrowLeftArrow": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "RightCeiling": // RIGHT CEILING + return rune(0x2309), true + case "RightDoubleBracket": // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + return rune(0x27e7), true + case "RightDownTeeVector": // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295d), true + case "RightDownVector": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "RightDownVectorBar": // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2955), true + case "RightFloor": // RIGHT FLOOR + return rune(0x230b), true + case "RightTee": // RIGHT TACK + return rune(0x22a2), true + case "RightTeeArrow": // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "RightTeeVector": // RIGHTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295b), true + case "RightTriangle": // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "RightTriangleBar": // VERTICAL BAR BESIDE RIGHT TRIANGLE + return rune(0x29d0), true + case "RightTriangleEqual": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "RightUpDownVector": // UP BARB RIGHT DOWN BARB RIGHT HARPOON + return rune(0x294f), true + case "RightUpTeeVector": // UPWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295c), true + case "RightUpVector": // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "RightUpVectorBar": // UPWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2954), true + case "RightVector": // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "RightVectorBar": // RIGHTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2953), true + case "Rightarrow": // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "Ropf": // DOUBLE-STRUCK CAPITAL R + return rune(0x211d), true + case "RoundImplies": // RIGHT DOUBLE ARROW WITH ROUNDED HEAD + return rune(0x2970), true + case "Rrightarrow": // RIGHTWARDS TRIPLE ARROW + return rune(0x21db), true + case "Rscr": // SCRIPT CAPITAL R + return rune(0x211b), true + case "Rsh": // UPWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b1), true + case "RuleDelayed": // RULE-DELAYED + return rune(0x29f4), true } case 'S': switch name { - case "SHCHcy": // CYRILLIC CAPITAL LETTER SHCHA - return rune(0x0429), true - case "SHcy": // CYRILLIC CAPITAL LETTER SHA - return rune(0x0428), true - case "SOFTcy": // CYRILLIC CAPITAL LETTER SOFT SIGN - return rune(0x042c), true - case "Sacute": // LATIN CAPITAL LETTER S WITH ACUTE - return rune(0x015a), true - case "Sc": // DOUBLE SUCCEEDS - return rune(0x2abc), true - case "Scaron": // LATIN CAPITAL LETTER S WITH CARON - return rune(0x0160), true - case "Scedil": // LATIN CAPITAL LETTER S WITH CEDILLA - return rune(0x015e), true - case "Scirc": // LATIN CAPITAL LETTER S WITH CIRCUMFLEX - return rune(0x015c), true - case "Scy": // CYRILLIC CAPITAL LETTER ES - return rune(0x0421), true - case "Sfr": // MATHEMATICAL FRAKTUR CAPITAL S - return rune(0x01d516), true - case "Sgr": // GREEK CAPITAL LETTER SIGMA - return rune(0x03a3), true - case "ShortDownArrow": // DOWNWARDS ARROW - return rune(0x2193), true - case "ShortLeftArrow": // LEFTWARDS ARROW - return rune(0x2190), true - case "ShortRightArrow": // RIGHTWARDS ARROW - return rune(0x2192), true - case "ShortUpArrow": // UPWARDS ARROW - return rune(0x2191), true - case "Sigma": // GREEK CAPITAL LETTER SIGMA - return rune(0x03a3), true - case "SmallCircle": // RING OPERATOR - return rune(0x2218), true - case "Sopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL S - return rune(0x01d54a), true - case "Sqrt": // SQUARE ROOT - return rune(0x221a), true - case "Square": // WHITE SQUARE - return rune(0x25a1), true - case "SquareIntersection": // SQUARE CAP - return rune(0x2293), true - case "SquareSubset": // SQUARE IMAGE OF - return rune(0x228f), true - case "SquareSubsetEqual": // SQUARE IMAGE OF OR EQUAL TO - return rune(0x2291), true - case "SquareSuperset": // SQUARE ORIGINAL OF - return rune(0x2290), true - case "SquareSupersetEqual": // SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x2292), true - case "SquareUnion": // SQUARE CUP - return rune(0x2294), true - case "Sscr": // MATHEMATICAL SCRIPT CAPITAL S - return rune(0x01d4ae), true - case "Star": // STAR OPERATOR - return rune(0x22c6), true - case "Sub": // DOUBLE SUBSET - return rune(0x22d0), true - case "Subset": // DOUBLE SUBSET - return rune(0x22d0), true - case "SubsetEqual": // SUBSET OF OR EQUAL TO - return rune(0x2286), true - case "Succeeds": // SUCCEEDS - return rune(0x227b), true - case "SucceedsEqual": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2ab0), true - case "SucceedsSlantEqual": // SUCCEEDS OR EQUAL TO - return rune(0x227d), true - case "SucceedsTilde": // SUCCEEDS OR EQUIVALENT TO - return rune(0x227f), true - case "SuchThat": // CONTAINS AS MEMBER - return rune(0x220b), true - case "Sum": // N-ARY SUMMATION - return rune(0x2211), true - case "Sup": // DOUBLE SUPERSET - return rune(0x22d1), true - case "Superset": // SUPERSET OF - return rune(0x2283), true - case "SupersetEqual": // SUPERSET OF OR EQUAL TO - return rune(0x2287), true - case "Supset": // DOUBLE SUPERSET - return rune(0x22d1), true + case "SHCHcy": // CYRILLIC CAPITAL LETTER SHCHA + return rune(0x0429), true + case "SHcy": // CYRILLIC CAPITAL LETTER SHA + return rune(0x0428), true + case "SOFTcy": // CYRILLIC CAPITAL LETTER SOFT SIGN + return rune(0x042c), true + case "Sacute": // LATIN CAPITAL LETTER S WITH ACUTE + return rune(0x015a), true + case "Sc": // DOUBLE SUCCEEDS + return rune(0x2abc), true + case "Scaron": // LATIN CAPITAL LETTER S WITH CARON + return rune(0x0160), true + case "Scedil": // LATIN CAPITAL LETTER S WITH CEDILLA + return rune(0x015e), true + case "Scirc": // LATIN CAPITAL LETTER S WITH CIRCUMFLEX + return rune(0x015c), true + case "Scy": // CYRILLIC CAPITAL LETTER ES + return rune(0x0421), true + case "Sfr": // MATHEMATICAL FRAKTUR CAPITAL S + return rune(0x01d516), true + case "Sgr": // GREEK CAPITAL LETTER SIGMA + return rune(0x03a3), true + case "ShortDownArrow": // DOWNWARDS ARROW + return rune(0x2193), true + case "ShortLeftArrow": // LEFTWARDS ARROW + return rune(0x2190), true + case "ShortRightArrow": // RIGHTWARDS ARROW + return rune(0x2192), true + case "ShortUpArrow": // UPWARDS ARROW + return rune(0x2191), true + case "Sigma": // GREEK CAPITAL LETTER SIGMA + return rune(0x03a3), true + case "SmallCircle": // RING OPERATOR + return rune(0x2218), true + case "Sopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL S + return rune(0x01d54a), true + case "Sqrt": // SQUARE ROOT + return rune(0x221a), true + case "Square": // WHITE SQUARE + return rune(0x25a1), true + case "SquareIntersection": // SQUARE CAP + return rune(0x2293), true + case "SquareSubset": // SQUARE IMAGE OF + return rune(0x228f), true + case "SquareSubsetEqual": // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "SquareSuperset": // SQUARE ORIGINAL OF + return rune(0x2290), true + case "SquareSupersetEqual": // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "SquareUnion": // SQUARE CUP + return rune(0x2294), true + case "Sscr": // MATHEMATICAL SCRIPT CAPITAL S + return rune(0x01d4ae), true + case "Star": // STAR OPERATOR + return rune(0x22c6), true + case "Sub": // DOUBLE SUBSET + return rune(0x22d0), true + case "Subset": // DOUBLE SUBSET + return rune(0x22d0), true + case "SubsetEqual": // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "Succeeds": // SUCCEEDS + return rune(0x227b), true + case "SucceedsEqual": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "SucceedsSlantEqual": // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "SucceedsTilde": // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "SuchThat": // CONTAINS AS MEMBER + return rune(0x220b), true + case "Sum": // N-ARY SUMMATION + return rune(0x2211), true + case "Sup": // DOUBLE SUPERSET + return rune(0x22d1), true + case "Superset": // SUPERSET OF + return rune(0x2283), true + case "SupersetEqual": // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "Supset": // DOUBLE SUPERSET + return rune(0x22d1), true } case 'T': switch name { - case "THORN": // LATIN CAPITAL LETTER THORN - return rune(0xde), true - case "THgr": // GREEK CAPITAL LETTER THETA - return rune(0x0398), true - case "TRADE": // TRADE MARK SIGN - return rune(0x2122), true - case "TSHcy": // CYRILLIC CAPITAL LETTER TSHE - return rune(0x040b), true - case "TScy": // CYRILLIC CAPITAL LETTER TSE - return rune(0x0426), true - case "Tab": // CHARACTER TABULATION - return rune(0x09), true - case "Tau": // GREEK CAPITAL LETTER TAU - return rune(0x03a4), true - case "Tcaron": // LATIN CAPITAL LETTER T WITH CARON - return rune(0x0164), true - case "Tcedil": // LATIN CAPITAL LETTER T WITH CEDILLA - return rune(0x0162), true - case "Tcy": // CYRILLIC CAPITAL LETTER TE - return rune(0x0422), true - case "Tfr": // MATHEMATICAL FRAKTUR CAPITAL T - return rune(0x01d517), true - case "Tgr": // GREEK CAPITAL LETTER TAU - return rune(0x03a4), true - case "Therefore": // THEREFORE - return rune(0x2234), true - case "Theta": // GREEK CAPITAL LETTER THETA - return rune(0x0398), true - case "Thetav": // GREEK CAPITAL THETA SYMBOL - return rune(0x03f4), true - case "ThickSpace": // space of width 5/18 em - return rune(0x205f), true - case "ThinSpace": // THIN SPACE - return rune(0x2009), true - case "Tilde": // TILDE OPERATOR - return rune(0x223c), true - case "TildeEqual": // ASYMPTOTICALLY EQUAL TO - return rune(0x2243), true - case "TildeFullEqual": // APPROXIMATELY EQUAL TO - return rune(0x2245), true - case "TildeTilde": // ALMOST EQUAL TO - return rune(0x2248), true - case "Topf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL T - return rune(0x01d54b), true - case "TripleDot": // COMBINING THREE DOTS ABOVE - return rune(0x20db), true - case "Tscr": // MATHEMATICAL SCRIPT CAPITAL T - return rune(0x01d4af), true - case "Tstrok": // LATIN CAPITAL LETTER T WITH STROKE - return rune(0x0166), true + case "THORN": // LATIN CAPITAL LETTER THORN + return rune(0xde), true + case "THgr": // GREEK CAPITAL LETTER THETA + return rune(0x0398), true + case "TRADE": // TRADE MARK SIGN + return rune(0x2122), true + case "TSHcy": // CYRILLIC CAPITAL LETTER TSHE + return rune(0x040b), true + case "TScy": // CYRILLIC CAPITAL LETTER TSE + return rune(0x0426), true + case "Tab": // CHARACTER TABULATION + return rune(0x09), true + case "Tau": // GREEK CAPITAL LETTER TAU + return rune(0x03a4), true + case "Tcaron": // LATIN CAPITAL LETTER T WITH CARON + return rune(0x0164), true + case "Tcedil": // LATIN CAPITAL LETTER T WITH CEDILLA + return rune(0x0162), true + case "Tcy": // CYRILLIC CAPITAL LETTER TE + return rune(0x0422), true + case "Tfr": // MATHEMATICAL FRAKTUR CAPITAL T + return rune(0x01d517), true + case "Tgr": // GREEK CAPITAL LETTER TAU + return rune(0x03a4), true + case "Therefore": // THEREFORE + return rune(0x2234), true + case "Theta": // GREEK CAPITAL LETTER THETA + return rune(0x0398), true + case "Thetav": // GREEK CAPITAL THETA SYMBOL + return rune(0x03f4), true + case "ThickSpace": // space of width 5/18 em + return rune(0x205f), true + case "ThinSpace": // THIN SPACE + return rune(0x2009), true + case "Tilde": // TILDE OPERATOR + return rune(0x223c), true + case "TildeEqual": // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "TildeFullEqual": // APPROXIMATELY EQUAL TO + return rune(0x2245), true + case "TildeTilde": // ALMOST EQUAL TO + return rune(0x2248), true + case "Topf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL T + return rune(0x01d54b), true + case "TripleDot": // COMBINING THREE DOTS ABOVE + return rune(0x20db), true + case "Tscr": // MATHEMATICAL SCRIPT CAPITAL T + return rune(0x01d4af), true + case "Tstrok": // LATIN CAPITAL LETTER T WITH STROKE + return rune(0x0166), true } case 'U': switch name { - case "Uacgr": // GREEK CAPITAL LETTER UPSILON WITH TONOS - return rune(0x038e), true - case "Uacute": // LATIN CAPITAL LETTER U WITH ACUTE - return rune(0xda), true - case "Uarr": // UPWARDS TWO HEADED ARROW - return rune(0x219f), true - case "Uarrocir": // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE - return rune(0x2949), true - case "Ubrcy": // CYRILLIC CAPITAL LETTER SHORT U - return rune(0x040e), true - case "Ubreve": // LATIN CAPITAL LETTER U WITH BREVE - return rune(0x016c), true - case "Ucirc": // LATIN CAPITAL LETTER U WITH CIRCUMFLEX - return rune(0xdb), true - case "Ucy": // CYRILLIC CAPITAL LETTER U - return rune(0x0423), true - case "Udblac": // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE - return rune(0x0170), true - case "Udigr": // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA - return rune(0x03ab), true - case "Ufr": // MATHEMATICAL FRAKTUR CAPITAL U - return rune(0x01d518), true - case "Ugr": // GREEK CAPITAL LETTER UPSILON - return rune(0x03a5), true - case "Ugrave": // LATIN CAPITAL LETTER U WITH GRAVE - return rune(0xd9), true - case "Umacr": // LATIN CAPITAL LETTER U WITH MACRON - return rune(0x016a), true - case "UnderBar": // LOW LINE - return rune(0x5f), true - case "UnderBrace": // BOTTOM CURLY BRACKET - return rune(0x23df), true - case "UnderBracket": // BOTTOM SQUARE BRACKET - return rune(0x23b5), true - case "UnderParenthesis": // BOTTOM PARENTHESIS - return rune(0x23dd), true - case "Union": // N-ARY UNION - return rune(0x22c3), true - case "UnionPlus": // MULTISET UNION - return rune(0x228e), true - case "Uogon": // LATIN CAPITAL LETTER U WITH OGONEK - return rune(0x0172), true - case "Uopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL U - return rune(0x01d54c), true - case "UpArrow": // UPWARDS ARROW - return rune(0x2191), true - case "UpArrowBar": // UPWARDS ARROW TO BAR - return rune(0x2912), true - case "UpArrowDownArrow": // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - return rune(0x21c5), true - case "UpDownArrow": // UP DOWN ARROW - return rune(0x2195), true - case "UpEquilibrium": // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - return rune(0x296e), true - case "UpTee": // UP TACK - return rune(0x22a5), true - case "UpTeeArrow": // UPWARDS ARROW FROM BAR - return rune(0x21a5), true - case "Uparrow": // UPWARDS DOUBLE ARROW - return rune(0x21d1), true - case "Updownarrow": // UP DOWN DOUBLE ARROW - return rune(0x21d5), true - case "UpperLeftArrow": // NORTH WEST ARROW - return rune(0x2196), true - case "UpperRightArrow": // NORTH EAST ARROW - return rune(0x2197), true - case "Upsi": // GREEK UPSILON WITH HOOK SYMBOL - return rune(0x03d2), true - case "Upsilon": // GREEK CAPITAL LETTER UPSILON - return rune(0x03a5), true - case "Uring": // LATIN CAPITAL LETTER U WITH RING ABOVE - return rune(0x016e), true - case "Uscr": // MATHEMATICAL SCRIPT CAPITAL U - return rune(0x01d4b0), true - case "Utilde": // LATIN CAPITAL LETTER U WITH TILDE - return rune(0x0168), true - case "Uuml": // LATIN CAPITAL LETTER U WITH DIAERESIS - return rune(0xdc), true + case "Uacgr": // GREEK CAPITAL LETTER UPSILON WITH TONOS + return rune(0x038e), true + case "Uacute": // LATIN CAPITAL LETTER U WITH ACUTE + return rune(0xda), true + case "Uarr": // UPWARDS TWO HEADED ARROW + return rune(0x219f), true + case "Uarrocir": // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE + return rune(0x2949), true + case "Ubrcy": // CYRILLIC CAPITAL LETTER SHORT U + return rune(0x040e), true + case "Ubreve": // LATIN CAPITAL LETTER U WITH BREVE + return rune(0x016c), true + case "Ucirc": // LATIN CAPITAL LETTER U WITH CIRCUMFLEX + return rune(0xdb), true + case "Ucy": // CYRILLIC CAPITAL LETTER U + return rune(0x0423), true + case "Udblac": // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE + return rune(0x0170), true + case "Udigr": // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA + return rune(0x03ab), true + case "Ufr": // MATHEMATICAL FRAKTUR CAPITAL U + return rune(0x01d518), true + case "Ugr": // GREEK CAPITAL LETTER UPSILON + return rune(0x03a5), true + case "Ugrave": // LATIN CAPITAL LETTER U WITH GRAVE + return rune(0xd9), true + case "Umacr": // LATIN CAPITAL LETTER U WITH MACRON + return rune(0x016a), true + case "UnderBar": // LOW LINE + return rune(0x5f), true + case "UnderBrace": // BOTTOM CURLY BRACKET + return rune(0x23df), true + case "UnderBracket": // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "UnderParenthesis": // BOTTOM PARENTHESIS + return rune(0x23dd), true + case "Union": // N-ARY UNION + return rune(0x22c3), true + case "UnionPlus": // MULTISET UNION + return rune(0x228e), true + case "Uogon": // LATIN CAPITAL LETTER U WITH OGONEK + return rune(0x0172), true + case "Uopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL U + return rune(0x01d54c), true + case "UpArrow": // UPWARDS ARROW + return rune(0x2191), true + case "UpArrowBar": // UPWARDS ARROW TO BAR + return rune(0x2912), true + case "UpArrowDownArrow": // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + return rune(0x21c5), true + case "UpDownArrow": // UP DOWN ARROW + return rune(0x2195), true + case "UpEquilibrium": // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x296e), true + case "UpTee": // UP TACK + return rune(0x22a5), true + case "UpTeeArrow": // UPWARDS ARROW FROM BAR + return rune(0x21a5), true + case "Uparrow": // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "Updownarrow": // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "UpperLeftArrow": // NORTH WEST ARROW + return rune(0x2196), true + case "UpperRightArrow": // NORTH EAST ARROW + return rune(0x2197), true + case "Upsi": // GREEK UPSILON WITH HOOK SYMBOL + return rune(0x03d2), true + case "Upsilon": // GREEK CAPITAL LETTER UPSILON + return rune(0x03a5), true + case "Uring": // LATIN CAPITAL LETTER U WITH RING ABOVE + return rune(0x016e), true + case "Uscr": // MATHEMATICAL SCRIPT CAPITAL U + return rune(0x01d4b0), true + case "Utilde": // LATIN CAPITAL LETTER U WITH TILDE + return rune(0x0168), true + case "Uuml": // LATIN CAPITAL LETTER U WITH DIAERESIS + return rune(0xdc), true } case 'V': switch name { - case "VDash": // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE - return rune(0x22ab), true - case "Vbar": // DOUBLE UP TACK - return rune(0x2aeb), true - case "Vcy": // CYRILLIC CAPITAL LETTER VE - return rune(0x0412), true - case "Vdash": // FORCES - return rune(0x22a9), true - case "Vdashl": // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL - return rune(0x2ae6), true - case "Vee": // N-ARY LOGICAL OR - return rune(0x22c1), true - case "Verbar": // DOUBLE VERTICAL LINE - return rune(0x2016), true - case "Vert": // DOUBLE VERTICAL LINE - return rune(0x2016), true - case "VerticalBar": // DIVIDES - return rune(0x2223), true - case "VerticalLine": // VERTICAL LINE - return rune(0x7c), true - case "VerticalSeparator": // LIGHT VERTICAL BAR - return rune(0x2758), true - case "VerticalTilde": // WREATH PRODUCT - return rune(0x2240), true - case "VeryThinSpace": // HAIR SPACE - return rune(0x200a), true - case "Vfr": // MATHEMATICAL FRAKTUR CAPITAL V - return rune(0x01d519), true - case "Vopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL V - return rune(0x01d54d), true - case "Vscr": // MATHEMATICAL SCRIPT CAPITAL V - return rune(0x01d4b1), true - case "Vvdash": // TRIPLE VERTICAL BAR RIGHT TURNSTILE - return rune(0x22aa), true + case "VDash": // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + return rune(0x22ab), true + case "Vbar": // DOUBLE UP TACK + return rune(0x2aeb), true + case "Vcy": // CYRILLIC CAPITAL LETTER VE + return rune(0x0412), true + case "Vdash": // FORCES + return rune(0x22a9), true + case "Vdashl": // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL + return rune(0x2ae6), true + case "Vee": // N-ARY LOGICAL OR + return rune(0x22c1), true + case "Verbar": // DOUBLE VERTICAL LINE + return rune(0x2016), true + case "Vert": // DOUBLE VERTICAL LINE + return rune(0x2016), true + case "VerticalBar": // DIVIDES + return rune(0x2223), true + case "VerticalLine": // VERTICAL LINE + return rune(0x7c), true + case "VerticalSeparator": // LIGHT VERTICAL BAR + return rune(0x2758), true + case "VerticalTilde": // WREATH PRODUCT + return rune(0x2240), true + case "VeryThinSpace": // HAIR SPACE + return rune(0x200a), true + case "Vfr": // MATHEMATICAL FRAKTUR CAPITAL V + return rune(0x01d519), true + case "Vopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL V + return rune(0x01d54d), true + case "Vscr": // MATHEMATICAL SCRIPT CAPITAL V + return rune(0x01d4b1), true + case "Vvdash": // TRIPLE VERTICAL BAR RIGHT TURNSTILE + return rune(0x22aa), true } case 'W': switch name { - case "Wcirc": // LATIN CAPITAL LETTER W WITH CIRCUMFLEX - return rune(0x0174), true - case "Wedge": // N-ARY LOGICAL AND - return rune(0x22c0), true - case "Wfr": // MATHEMATICAL FRAKTUR CAPITAL W - return rune(0x01d51a), true - case "Wopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL W - return rune(0x01d54e), true - case "Wscr": // MATHEMATICAL SCRIPT CAPITAL W - return rune(0x01d4b2), true + case "Wcirc": // LATIN CAPITAL LETTER W WITH CIRCUMFLEX + return rune(0x0174), true + case "Wedge": // N-ARY LOGICAL AND + return rune(0x22c0), true + case "Wfr": // MATHEMATICAL FRAKTUR CAPITAL W + return rune(0x01d51a), true + case "Wopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL W + return rune(0x01d54e), true + case "Wscr": // MATHEMATICAL SCRIPT CAPITAL W + return rune(0x01d4b2), true } case 'X': switch name { - case "Xfr": // MATHEMATICAL FRAKTUR CAPITAL X - return rune(0x01d51b), true - case "Xgr": // GREEK CAPITAL LETTER XI - return rune(0x039e), true - case "Xi": // GREEK CAPITAL LETTER XI - return rune(0x039e), true - case "Xopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL X - return rune(0x01d54f), true - case "Xscr": // MATHEMATICAL SCRIPT CAPITAL X - return rune(0x01d4b3), true + case "Xfr": // MATHEMATICAL FRAKTUR CAPITAL X + return rune(0x01d51b), true + case "Xgr": // GREEK CAPITAL LETTER XI + return rune(0x039e), true + case "Xi": // GREEK CAPITAL LETTER XI + return rune(0x039e), true + case "Xopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL X + return rune(0x01d54f), true + case "Xscr": // MATHEMATICAL SCRIPT CAPITAL X + return rune(0x01d4b3), true } case 'Y': switch name { - case "YAcy": // CYRILLIC CAPITAL LETTER YA - return rune(0x042f), true - case "YIcy": // CYRILLIC CAPITAL LETTER YI - return rune(0x0407), true - case "YUcy": // CYRILLIC CAPITAL LETTER YU - return rune(0x042e), true - case "Yacute": // LATIN CAPITAL LETTER Y WITH ACUTE - return rune(0xdd), true - case "Ycirc": // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX - return rune(0x0176), true - case "Ycy": // CYRILLIC CAPITAL LETTER YERU - return rune(0x042b), true - case "Yfr": // MATHEMATICAL FRAKTUR CAPITAL Y - return rune(0x01d51c), true - case "Yopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y - return rune(0x01d550), true - case "Yscr": // MATHEMATICAL SCRIPT CAPITAL Y - return rune(0x01d4b4), true - case "Yuml": // LATIN CAPITAL LETTER Y WITH DIAERESIS - return rune(0x0178), true + case "YAcy": // CYRILLIC CAPITAL LETTER YA + return rune(0x042f), true + case "YIcy": // CYRILLIC CAPITAL LETTER YI + return rune(0x0407), true + case "YUcy": // CYRILLIC CAPITAL LETTER YU + return rune(0x042e), true + case "Yacute": // LATIN CAPITAL LETTER Y WITH ACUTE + return rune(0xdd), true + case "Ycirc": // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX + return rune(0x0176), true + case "Ycy": // CYRILLIC CAPITAL LETTER YERU + return rune(0x042b), true + case "Yfr": // MATHEMATICAL FRAKTUR CAPITAL Y + return rune(0x01d51c), true + case "Yopf": // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y + return rune(0x01d550), true + case "Yscr": // MATHEMATICAL SCRIPT CAPITAL Y + return rune(0x01d4b4), true + case "Yuml": // LATIN CAPITAL LETTER Y WITH DIAERESIS + return rune(0x0178), true } case 'Z': switch name { - case "ZHcy": // CYRILLIC CAPITAL LETTER ZHE - return rune(0x0416), true - case "Zacute": // LATIN CAPITAL LETTER Z WITH ACUTE - return rune(0x0179), true - case "Zcaron": // LATIN CAPITAL LETTER Z WITH CARON - return rune(0x017d), true - case "Zcy": // CYRILLIC CAPITAL LETTER ZE - return rune(0x0417), true - case "Zdot": // LATIN CAPITAL LETTER Z WITH DOT ABOVE - return rune(0x017b), true - case "ZeroWidthSpace": // ZERO WIDTH SPACE - return rune(0x200b), true - case "Zeta": // GREEK CAPITAL LETTER ZETA - return rune(0x0396), true - case "Zfr": // BLACK-LETTER CAPITAL Z - return rune(0x2128), true - case "Zgr": // GREEK CAPITAL LETTER ZETA - return rune(0x0396), true - case "Zopf": // DOUBLE-STRUCK CAPITAL Z - return rune(0x2124), true - case "Zscr": // MATHEMATICAL SCRIPT CAPITAL Z - return rune(0x01d4b5), true + case "ZHcy": // CYRILLIC CAPITAL LETTER ZHE + return rune(0x0416), true + case "Zacute": // LATIN CAPITAL LETTER Z WITH ACUTE + return rune(0x0179), true + case "Zcaron": // LATIN CAPITAL LETTER Z WITH CARON + return rune(0x017d), true + case "Zcy": // CYRILLIC CAPITAL LETTER ZE + return rune(0x0417), true + case "Zdot": // LATIN CAPITAL LETTER Z WITH DOT ABOVE + return rune(0x017b), true + case "ZeroWidthSpace": // ZERO WIDTH SPACE + return rune(0x200b), true + case "Zeta": // GREEK CAPITAL LETTER ZETA + return rune(0x0396), true + case "Zfr": // BLACK-LETTER CAPITAL Z + return rune(0x2128), true + case "Zgr": // GREEK CAPITAL LETTER ZETA + return rune(0x0396), true + case "Zopf": // DOUBLE-STRUCK CAPITAL Z + return rune(0x2124), true + case "Zscr": // MATHEMATICAL SCRIPT CAPITAL Z + return rune(0x01d4b5), true } case 'a': switch name { - case "aacgr": // GREEK SMALL LETTER ALPHA WITH TONOS - return rune(0x03ac), true - case "aacute": // LATIN SMALL LETTER A WITH ACUTE - return rune(0xe1), true - case "abreve": // LATIN SMALL LETTER A WITH BREVE - return rune(0x0103), true - case "ac": // INVERTED LAZY S - return rune(0x223e), true - case "acE": // INVERTED LAZY S with double underline - return rune(0x223e), true - case "acd": // SINE WAVE - return rune(0x223f), true - case "acirc": // LATIN SMALL LETTER A WITH CIRCUMFLEX - return rune(0xe2), true - case "actuary": // COMBINING ANNUITY SYMBOL - return rune(0x20e7), true - case "acute": // ACUTE ACCENT - return rune(0xb4), true - case "acy": // CYRILLIC SMALL LETTER A - return rune(0x0430), true - case "aelig": // LATIN SMALL LETTER AE - return rune(0xe6), true - case "af": // FUNCTION APPLICATION - return rune(0x2061), true - case "afr": // MATHEMATICAL FRAKTUR SMALL A - return rune(0x01d51e), true - case "agr": // GREEK SMALL LETTER ALPHA - return rune(0x03b1), true - case "agrave": // LATIN SMALL LETTER A WITH GRAVE - return rune(0xe0), true - case "alefsym": // ALEF SYMBOL - return rune(0x2135), true - case "aleph": // ALEF SYMBOL - return rune(0x2135), true - case "alpha": // GREEK SMALL LETTER ALPHA - return rune(0x03b1), true - case "amacr": // LATIN SMALL LETTER A WITH MACRON - return rune(0x0101), true - case "amalg": // AMALGAMATION OR COPRODUCT - return rune(0x2a3f), true - case "amp": // AMPERSAND - return rune(0x26), true - case "and": // LOGICAL AND - return rune(0x2227), true - case "andand": // TWO INTERSECTING LOGICAL AND - return rune(0x2a55), true - case "andd": // LOGICAL AND WITH HORIZONTAL DASH - return rune(0x2a5c), true - case "andslope": // SLOPING LARGE AND - return rune(0x2a58), true - case "andv": // LOGICAL AND WITH MIDDLE STEM - return rune(0x2a5a), true - case "ang": // ANGLE - return rune(0x2220), true - case "ang90": // RIGHT ANGLE - return rune(0x221f), true - case "angdnl": // TURNED ANGLE - return rune(0x29a2), true - case "angdnr": // ACUTE ANGLE - return rune(0x299f), true - case "ange": // ANGLE WITH UNDERBAR - return rune(0x29a4), true - case "angle": // ANGLE - return rune(0x2220), true - case "angles": // ANGLE WITH S INSIDE - return rune(0x299e), true - case "angmsd": // MEASURED ANGLE - return rune(0x2221), true - case "angmsdaa": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT - return rune(0x29a8), true - case "angmsdab": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT - return rune(0x29a9), true - case "angmsdac": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT - return rune(0x29aa), true - case "angmsdad": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT - return rune(0x29ab), true - case "angmsdae": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP - return rune(0x29ac), true - case "angmsdaf": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP - return rune(0x29ad), true - case "angmsdag": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN - return rune(0x29ae), true - case "angmsdah": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN - return rune(0x29af), true - case "angrt": // RIGHT ANGLE - return rune(0x221f), true - case "angrtvb": // RIGHT ANGLE WITH ARC - return rune(0x22be), true - case "angrtvbd": // MEASURED RIGHT ANGLE WITH DOT - return rune(0x299d), true - case "angsph": // SPHERICAL ANGLE - return rune(0x2222), true - case "angst": // LATIN CAPITAL LETTER A WITH RING ABOVE - return rune(0xc5), true - case "angupl": // REVERSED ANGLE - return rune(0x29a3), true - case "angzarr": // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW - return rune(0x237c), true - case "aogon": // LATIN SMALL LETTER A WITH OGONEK - return rune(0x0105), true - case "aopf": // MATHEMATICAL DOUBLE-STRUCK SMALL A - return rune(0x01d552), true - case "ap": // ALMOST EQUAL TO - return rune(0x2248), true - case "apE": // APPROXIMATELY EQUAL OR EQUAL TO - return rune(0x2a70), true - case "apacir": // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT - return rune(0x2a6f), true - case "ape": // ALMOST EQUAL OR EQUAL TO - return rune(0x224a), true - case "apid": // TRIPLE TILDE - return rune(0x224b), true - case "apos": // APOSTROPHE - return rune(0x27), true - case "approx": // ALMOST EQUAL TO - return rune(0x2248), true - case "approxeq": // ALMOST EQUAL OR EQUAL TO - return rune(0x224a), true - case "aring": // LATIN SMALL LETTER A WITH RING ABOVE - return rune(0xe5), true - case "arrllsr": // LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW - return rune(0x2943), true - case "arrlrsl": // RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW - return rune(0x2942), true - case "arrsrll": // SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW - return rune(0x2944), true - case "ascr": // MATHEMATICAL SCRIPT SMALL A - return rune(0x01d4b6), true - case "ast": // ASTERISK - return rune(0x2a), true - case "astb": // SQUARED ASTERISK - return rune(0x29c6), true - case "asymp": // ALMOST EQUAL TO - return rune(0x2248), true - case "asympeq": // EQUIVALENT TO - return rune(0x224d), true - case "atilde": // LATIN SMALL LETTER A WITH TILDE - return rune(0xe3), true - case "auml": // LATIN SMALL LETTER A WITH DIAERESIS - return rune(0xe4), true - case "awconint": // ANTICLOCKWISE CONTOUR INTEGRAL - return rune(0x2233), true - case "awint": // ANTICLOCKWISE INTEGRATION - return rune(0x2a11), true + case "aacgr": // GREEK SMALL LETTER ALPHA WITH TONOS + return rune(0x03ac), true + case "aacute": // LATIN SMALL LETTER A WITH ACUTE + return rune(0xe1), true + case "abreve": // LATIN SMALL LETTER A WITH BREVE + return rune(0x0103), true + case "ac": // INVERTED LAZY S + return rune(0x223e), true + case "acE": // INVERTED LAZY S with double underline + return rune(0x223e), true + case "acd": // SINE WAVE + return rune(0x223f), true + case "acirc": // LATIN SMALL LETTER A WITH CIRCUMFLEX + return rune(0xe2), true + case "actuary": // COMBINING ANNUITY SYMBOL + return rune(0x20e7), true + case "acute": // ACUTE ACCENT + return rune(0xb4), true + case "acy": // CYRILLIC SMALL LETTER A + return rune(0x0430), true + case "aelig": // LATIN SMALL LETTER AE + return rune(0xe6), true + case "af": // FUNCTION APPLICATION + return rune(0x2061), true + case "afr": // MATHEMATICAL FRAKTUR SMALL A + return rune(0x01d51e), true + case "agr": // GREEK SMALL LETTER ALPHA + return rune(0x03b1), true + case "agrave": // LATIN SMALL LETTER A WITH GRAVE + return rune(0xe0), true + case "alefsym": // ALEF SYMBOL + return rune(0x2135), true + case "aleph": // ALEF SYMBOL + return rune(0x2135), true + case "alpha": // GREEK SMALL LETTER ALPHA + return rune(0x03b1), true + case "amacr": // LATIN SMALL LETTER A WITH MACRON + return rune(0x0101), true + case "amalg": // AMALGAMATION OR COPRODUCT + return rune(0x2a3f), true + case "amp": // AMPERSAND + return rune(0x26), true + case "and": // LOGICAL AND + return rune(0x2227), true + case "andand": // TWO INTERSECTING LOGICAL AND + return rune(0x2a55), true + case "andd": // LOGICAL AND WITH HORIZONTAL DASH + return rune(0x2a5c), true + case "andslope": // SLOPING LARGE AND + return rune(0x2a58), true + case "andv": // LOGICAL AND WITH MIDDLE STEM + return rune(0x2a5a), true + case "ang": // ANGLE + return rune(0x2220), true + case "ang90": // RIGHT ANGLE + return rune(0x221f), true + case "angdnl": // TURNED ANGLE + return rune(0x29a2), true + case "angdnr": // ACUTE ANGLE + return rune(0x299f), true + case "ange": // ANGLE WITH UNDERBAR + return rune(0x29a4), true + case "angle": // ANGLE + return rune(0x2220), true + case "angles": // ANGLE WITH S INSIDE + return rune(0x299e), true + case "angmsd": // MEASURED ANGLE + return rune(0x2221), true + case "angmsdaa": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT + return rune(0x29a8), true + case "angmsdab": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT + return rune(0x29a9), true + case "angmsdac": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT + return rune(0x29aa), true + case "angmsdad": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT + return rune(0x29ab), true + case "angmsdae": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP + return rune(0x29ac), true + case "angmsdaf": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP + return rune(0x29ad), true + case "angmsdag": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN + return rune(0x29ae), true + case "angmsdah": // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN + return rune(0x29af), true + case "angrt": // RIGHT ANGLE + return rune(0x221f), true + case "angrtvb": // RIGHT ANGLE WITH ARC + return rune(0x22be), true + case "angrtvbd": // MEASURED RIGHT ANGLE WITH DOT + return rune(0x299d), true + case "angsph": // SPHERICAL ANGLE + return rune(0x2222), true + case "angst": // LATIN CAPITAL LETTER A WITH RING ABOVE + return rune(0xc5), true + case "angupl": // REVERSED ANGLE + return rune(0x29a3), true + case "angzarr": // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW + return rune(0x237c), true + case "aogon": // LATIN SMALL LETTER A WITH OGONEK + return rune(0x0105), true + case "aopf": // MATHEMATICAL DOUBLE-STRUCK SMALL A + return rune(0x01d552), true + case "ap": // ALMOST EQUAL TO + return rune(0x2248), true + case "apE": // APPROXIMATELY EQUAL OR EQUAL TO + return rune(0x2a70), true + case "apacir": // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT + return rune(0x2a6f), true + case "ape": // ALMOST EQUAL OR EQUAL TO + return rune(0x224a), true + case "apid": // TRIPLE TILDE + return rune(0x224b), true + case "apos": // APOSTROPHE + return rune(0x27), true + case "approx": // ALMOST EQUAL TO + return rune(0x2248), true + case "approxeq": // ALMOST EQUAL OR EQUAL TO + return rune(0x224a), true + case "aring": // LATIN SMALL LETTER A WITH RING ABOVE + return rune(0xe5), true + case "arrllsr": // LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW + return rune(0x2943), true + case "arrlrsl": // RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW + return rune(0x2942), true + case "arrsrll": // SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW + return rune(0x2944), true + case "ascr": // MATHEMATICAL SCRIPT SMALL A + return rune(0x01d4b6), true + case "ast": // ASTERISK + return rune(0x2a), true + case "astb": // SQUARED ASTERISK + return rune(0x29c6), true + case "asymp": // ALMOST EQUAL TO + return rune(0x2248), true + case "asympeq": // EQUIVALENT TO + return rune(0x224d), true + case "atilde": // LATIN SMALL LETTER A WITH TILDE + return rune(0xe3), true + case "auml": // LATIN SMALL LETTER A WITH DIAERESIS + return rune(0xe4), true + case "awconint": // ANTICLOCKWISE CONTOUR INTEGRAL + return rune(0x2233), true + case "awint": // ANTICLOCKWISE INTEGRATION + return rune(0x2a11), true } case 'b': switch name { - case "b.Delta": // MATHEMATICAL BOLD CAPITAL DELTA - return rune(0x01d6ab), true - case "b.Gamma": // MATHEMATICAL BOLD CAPITAL GAMMA - return rune(0x01d6aa), true - case "b.Gammad": // MATHEMATICAL BOLD CAPITAL DIGAMMA - return rune(0x01d7ca), true - case "b.Lambda": // MATHEMATICAL BOLD CAPITAL LAMDA - return rune(0x01d6b2), true - case "b.Omega": // MATHEMATICAL BOLD CAPITAL OMEGA - return rune(0x01d6c0), true - case "b.Phi": // MATHEMATICAL BOLD CAPITAL PHI - return rune(0x01d6bd), true - case "b.Pi": // MATHEMATICAL BOLD CAPITAL PI - return rune(0x01d6b7), true - case "b.Psi": // MATHEMATICAL BOLD CAPITAL PSI - return rune(0x01d6bf), true - case "b.Sigma": // MATHEMATICAL BOLD CAPITAL SIGMA - return rune(0x01d6ba), true - case "b.Theta": // MATHEMATICAL BOLD CAPITAL THETA - return rune(0x01d6af), true - case "b.Upsi": // MATHEMATICAL BOLD CAPITAL UPSILON - return rune(0x01d6bc), true - case "b.Xi": // MATHEMATICAL BOLD CAPITAL XI - return rune(0x01d6b5), true - case "b.alpha": // MATHEMATICAL BOLD SMALL ALPHA - return rune(0x01d6c2), true - case "b.beta": // MATHEMATICAL BOLD SMALL BETA - return rune(0x01d6c3), true - case "b.chi": // MATHEMATICAL BOLD SMALL CHI - return rune(0x01d6d8), true - case "b.delta": // MATHEMATICAL BOLD SMALL DELTA - return rune(0x01d6c5), true - case "b.epsi": // MATHEMATICAL BOLD SMALL EPSILON - return rune(0x01d6c6), true - case "b.epsiv": // MATHEMATICAL BOLD EPSILON SYMBOL - return rune(0x01d6dc), true - case "b.eta": // MATHEMATICAL BOLD SMALL ETA - return rune(0x01d6c8), true - case "b.gamma": // MATHEMATICAL BOLD SMALL GAMMA - return rune(0x01d6c4), true - case "b.gammad": // MATHEMATICAL BOLD SMALL DIGAMMA - return rune(0x01d7cb), true - case "b.iota": // MATHEMATICAL BOLD SMALL IOTA - return rune(0x01d6ca), true - case "b.kappa": // MATHEMATICAL BOLD SMALL KAPPA - return rune(0x01d6cb), true - case "b.kappav": // MATHEMATICAL BOLD KAPPA SYMBOL - return rune(0x01d6de), true - case "b.lambda": // MATHEMATICAL BOLD SMALL LAMDA - return rune(0x01d6cc), true - case "b.mu": // MATHEMATICAL BOLD SMALL MU - return rune(0x01d6cd), true - case "b.nu": // MATHEMATICAL BOLD SMALL NU - return rune(0x01d6ce), true - case "b.omega": // MATHEMATICAL BOLD SMALL OMEGA - return rune(0x01d6da), true - case "b.phi": // MATHEMATICAL BOLD SMALL PHI - return rune(0x01d6d7), true - case "b.phiv": // MATHEMATICAL BOLD PHI SYMBOL - return rune(0x01d6df), true - case "b.pi": // MATHEMATICAL BOLD SMALL PI - return rune(0x01d6d1), true - case "b.piv": // MATHEMATICAL BOLD PI SYMBOL - return rune(0x01d6e1), true - case "b.psi": // MATHEMATICAL BOLD SMALL PSI - return rune(0x01d6d9), true - case "b.rho": // MATHEMATICAL BOLD SMALL RHO - return rune(0x01d6d2), true - case "b.rhov": // MATHEMATICAL BOLD RHO SYMBOL - return rune(0x01d6e0), true - case "b.sigma": // MATHEMATICAL BOLD SMALL SIGMA - return rune(0x01d6d4), true - case "b.sigmav": // MATHEMATICAL BOLD SMALL FINAL SIGMA - return rune(0x01d6d3), true - case "b.tau": // MATHEMATICAL BOLD SMALL TAU - return rune(0x01d6d5), true - case "b.thetas": // MATHEMATICAL BOLD SMALL THETA - return rune(0x01d6c9), true - case "b.thetav": // MATHEMATICAL BOLD THETA SYMBOL - return rune(0x01d6dd), true - case "b.upsi": // MATHEMATICAL BOLD SMALL UPSILON - return rune(0x01d6d6), true - case "b.xi": // MATHEMATICAL BOLD SMALL XI - return rune(0x01d6cf), true - case "b.zeta": // MATHEMATICAL BOLD SMALL ZETA - return rune(0x01d6c7), true - case "bNot": // REVERSED DOUBLE STROKE NOT SIGN - return rune(0x2aed), true - case "backcong": // ALL EQUAL TO - return rune(0x224c), true - case "backepsilon": // GREEK REVERSED LUNATE EPSILON SYMBOL - return rune(0x03f6), true - case "backprime": // REVERSED PRIME - return rune(0x2035), true - case "backsim": // REVERSED TILDE - return rune(0x223d), true - case "backsimeq": // REVERSED TILDE EQUALS - return rune(0x22cd), true - case "barV": // DOUBLE DOWN TACK - return rune(0x2aea), true - case "barvee": // NOR - return rune(0x22bd), true - case "barwed": // PROJECTIVE - return rune(0x2305), true - case "barwedge": // PROJECTIVE - return rune(0x2305), true - case "bbrk": // BOTTOM SQUARE BRACKET - return rune(0x23b5), true - case "bbrktbrk": // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET - return rune(0x23b6), true - case "bcong": // ALL EQUAL TO - return rune(0x224c), true - case "bcy": // CYRILLIC SMALL LETTER BE - return rune(0x0431), true - case "bdlhar": // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2961), true - case "bdquo": // DOUBLE LOW-9 QUOTATION MARK - return rune(0x201e), true - case "bdrhar": // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295d), true - case "becaus": // BECAUSE - return rune(0x2235), true - case "because": // BECAUSE - return rune(0x2235), true - case "bemptyv": // REVERSED EMPTY SET - return rune(0x29b0), true - case "bepsi": // GREEK REVERSED LUNATE EPSILON SYMBOL - return rune(0x03f6), true - case "bernou": // SCRIPT CAPITAL B - return rune(0x212c), true - case "beta": // GREEK SMALL LETTER BETA - return rune(0x03b2), true - case "beth": // BET SYMBOL - return rune(0x2136), true - case "between": // BETWEEN - return rune(0x226c), true - case "bfr": // MATHEMATICAL FRAKTUR SMALL B - return rune(0x01d51f), true - case "bgr": // GREEK SMALL LETTER BETA - return rune(0x03b2), true - case "bigcap": // N-ARY INTERSECTION - return rune(0x22c2), true - case "bigcirc": // LARGE CIRCLE - return rune(0x25ef), true - case "bigcup": // N-ARY UNION - return rune(0x22c3), true - case "bigodot": // N-ARY CIRCLED DOT OPERATOR - return rune(0x2a00), true - case "bigoplus": // N-ARY CIRCLED PLUS OPERATOR - return rune(0x2a01), true - case "bigotimes": // N-ARY CIRCLED TIMES OPERATOR - return rune(0x2a02), true - case "bigsqcup": // N-ARY SQUARE UNION OPERATOR - return rune(0x2a06), true - case "bigstar": // BLACK STAR - return rune(0x2605), true - case "bigtriangledown": // WHITE DOWN-POINTING TRIANGLE - return rune(0x25bd), true - case "bigtriangleup": // WHITE UP-POINTING TRIANGLE - return rune(0x25b3), true - case "biguplus": // N-ARY UNION OPERATOR WITH PLUS - return rune(0x2a04), true - case "bigvee": // N-ARY LOGICAL OR - return rune(0x22c1), true - case "bigwedge": // N-ARY LOGICAL AND - return rune(0x22c0), true - case "bkarow": // RIGHTWARDS DOUBLE DASH ARROW - return rune(0x290d), true - case "blacklozenge": // BLACK LOZENGE - return rune(0x29eb), true - case "blacksquare": // BLACK SMALL SQUARE - return rune(0x25aa), true - case "blacktriangle": // BLACK UP-POINTING SMALL TRIANGLE - return rune(0x25b4), true - case "blacktriangledown": // BLACK DOWN-POINTING SMALL TRIANGLE - return rune(0x25be), true - case "blacktriangleleft": // BLACK LEFT-POINTING SMALL TRIANGLE - return rune(0x25c2), true - case "blacktriangleright": // BLACK RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b8), true - case "blank": // BLANK SYMBOL - return rune(0x2422), true - case "bldhar": // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295e), true - case "blk12": // MEDIUM SHADE - return rune(0x2592), true - case "blk14": // LIGHT SHADE - return rune(0x2591), true - case "blk34": // DARK SHADE - return rune(0x2593), true - case "block": // FULL BLOCK - return rune(0x2588), true - case "bluhar": // LEFTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295a), true - case "bne": // EQUALS SIGN with reverse slash - return rune(0x3d), true - case "bnequiv": // IDENTICAL TO with reverse slash - return rune(0x2261), true - case "bnot": // REVERSED NOT SIGN - return rune(0x2310), true - case "bopf": // MATHEMATICAL DOUBLE-STRUCK SMALL B - return rune(0x01d553), true - case "bot": // UP TACK - return rune(0x22a5), true - case "bottom": // UP TACK - return rune(0x22a5), true - case "bowtie": // BOWTIE - return rune(0x22c8), true - case "boxDL": // BOX DRAWINGS DOUBLE DOWN AND LEFT - return rune(0x2557), true - case "boxDR": // BOX DRAWINGS DOUBLE DOWN AND RIGHT - return rune(0x2554), true - case "boxDl": // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE - return rune(0x2556), true - case "boxDr": // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE - return rune(0x2553), true - case "boxH": // BOX DRAWINGS DOUBLE HORIZONTAL - return rune(0x2550), true - case "boxHD": // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL - return rune(0x2566), true - case "boxHU": // BOX DRAWINGS DOUBLE UP AND HORIZONTAL - return rune(0x2569), true - case "boxHd": // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE - return rune(0x2564), true - case "boxHu": // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE - return rune(0x2567), true - case "boxUL": // BOX DRAWINGS DOUBLE UP AND LEFT - return rune(0x255d), true - case "boxUR": // BOX DRAWINGS DOUBLE UP AND RIGHT - return rune(0x255a), true - case "boxUl": // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE - return rune(0x255c), true - case "boxUr": // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE - return rune(0x2559), true - case "boxV": // BOX DRAWINGS DOUBLE VERTICAL - return rune(0x2551), true - case "boxVH": // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL - return rune(0x256c), true - case "boxVL": // BOX DRAWINGS DOUBLE VERTICAL AND LEFT - return rune(0x2563), true - case "boxVR": // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT - return rune(0x2560), true - case "boxVh": // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE - return rune(0x256b), true - case "boxVl": // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE - return rune(0x2562), true - case "boxVr": // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE - return rune(0x255f), true - case "boxbox": // TWO JOINED SQUARES - return rune(0x29c9), true - case "boxdL": // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE - return rune(0x2555), true - case "boxdR": // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE - return rune(0x2552), true - case "boxdl": // BOX DRAWINGS LIGHT DOWN AND LEFT - return rune(0x2510), true - case "boxdr": // BOX DRAWINGS LIGHT DOWN AND RIGHT - return rune(0x250c), true - case "boxh": // BOX DRAWINGS LIGHT HORIZONTAL - return rune(0x2500), true - case "boxhD": // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE - return rune(0x2565), true - case "boxhU": // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE - return rune(0x2568), true - case "boxhd": // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - return rune(0x252c), true - case "boxhu": // BOX DRAWINGS LIGHT UP AND HORIZONTAL - return rune(0x2534), true - case "boxminus": // SQUARED MINUS - return rune(0x229f), true - case "boxplus": // SQUARED PLUS - return rune(0x229e), true - case "boxtimes": // SQUARED TIMES - return rune(0x22a0), true - case "boxuL": // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE - return rune(0x255b), true - case "boxuR": // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE - return rune(0x2558), true - case "boxul": // BOX DRAWINGS LIGHT UP AND LEFT - return rune(0x2518), true - case "boxur": // BOX DRAWINGS LIGHT UP AND RIGHT - return rune(0x2514), true - case "boxv": // BOX DRAWINGS LIGHT VERTICAL - return rune(0x2502), true - case "boxvH": // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE - return rune(0x256a), true - case "boxvL": // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE - return rune(0x2561), true - case "boxvR": // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE - return rune(0x255e), true - case "boxvh": // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - return rune(0x253c), true - case "boxvl": // BOX DRAWINGS LIGHT VERTICAL AND LEFT - return rune(0x2524), true - case "boxvr": // BOX DRAWINGS LIGHT VERTICAL AND RIGHT - return rune(0x251c), true - case "bprime": // REVERSED PRIME - return rune(0x2035), true - case "brdhar": // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR - return rune(0x295f), true - case "breve": // BREVE - return rune(0x02d8), true - case "bruhar": // RIGHTWARDS HARPOON WITH BARB UP FROM BAR - return rune(0x295b), true - case "brvbar": // BROKEN BAR - return rune(0xa6), true - case "bscr": // MATHEMATICAL SCRIPT SMALL B - return rune(0x01d4b7), true - case "bsemi": // REVERSED SEMICOLON - return rune(0x204f), true - case "bsim": // REVERSED TILDE - return rune(0x223d), true - case "bsime": // REVERSED TILDE EQUALS - return rune(0x22cd), true - case "bsol": // REVERSE SOLIDUS - return rune(0x5c), true - case "bsolb": // SQUARED FALLING DIAGONAL SLASH - return rune(0x29c5), true - case "bsolhsub": // REVERSE SOLIDUS PRECEDING SUBSET - return rune(0x27c8), true - case "btimes": // SEMIDIRECT PRODUCT WITH BOTTOM CLOSED - return rune(0x2a32), true - case "bulhar": // UPWARDS HARPOON WITH BARB LEFT FROM BAR - return rune(0x2960), true - case "bull": // BULLET - return rune(0x2022), true - case "bullet": // BULLET - return rune(0x2022), true - case "bump": // GEOMETRICALLY EQUIVALENT TO - return rune(0x224e), true - case "bumpE": // EQUALS SIGN WITH BUMPY ABOVE - return rune(0x2aae), true - case "bumpe": // DIFFERENCE BETWEEN - return rune(0x224f), true - case "bumpeq": // DIFFERENCE BETWEEN - return rune(0x224f), true - case "burhar": // UPWARDS HARPOON WITH BARB RIGHT FROM BAR - return rune(0x295c), true + case "b.Delta": // MATHEMATICAL BOLD CAPITAL DELTA + return rune(0x01d6ab), true + case "b.Gamma": // MATHEMATICAL BOLD CAPITAL GAMMA + return rune(0x01d6aa), true + case "b.Gammad": // MATHEMATICAL BOLD CAPITAL DIGAMMA + return rune(0x01d7ca), true + case "b.Lambda": // MATHEMATICAL BOLD CAPITAL LAMDA + return rune(0x01d6b2), true + case "b.Omega": // MATHEMATICAL BOLD CAPITAL OMEGA + return rune(0x01d6c0), true + case "b.Phi": // MATHEMATICAL BOLD CAPITAL PHI + return rune(0x01d6bd), true + case "b.Pi": // MATHEMATICAL BOLD CAPITAL PI + return rune(0x01d6b7), true + case "b.Psi": // MATHEMATICAL BOLD CAPITAL PSI + return rune(0x01d6bf), true + case "b.Sigma": // MATHEMATICAL BOLD CAPITAL SIGMA + return rune(0x01d6ba), true + case "b.Theta": // MATHEMATICAL BOLD CAPITAL THETA + return rune(0x01d6af), true + case "b.Upsi": // MATHEMATICAL BOLD CAPITAL UPSILON + return rune(0x01d6bc), true + case "b.Xi": // MATHEMATICAL BOLD CAPITAL XI + return rune(0x01d6b5), true + case "b.alpha": // MATHEMATICAL BOLD SMALL ALPHA + return rune(0x01d6c2), true + case "b.beta": // MATHEMATICAL BOLD SMALL BETA + return rune(0x01d6c3), true + case "b.chi": // MATHEMATICAL BOLD SMALL CHI + return rune(0x01d6d8), true + case "b.delta": // MATHEMATICAL BOLD SMALL DELTA + return rune(0x01d6c5), true + case "b.epsi": // MATHEMATICAL BOLD SMALL EPSILON + return rune(0x01d6c6), true + case "b.epsiv": // MATHEMATICAL BOLD EPSILON SYMBOL + return rune(0x01d6dc), true + case "b.eta": // MATHEMATICAL BOLD SMALL ETA + return rune(0x01d6c8), true + case "b.gamma": // MATHEMATICAL BOLD SMALL GAMMA + return rune(0x01d6c4), true + case "b.gammad": // MATHEMATICAL BOLD SMALL DIGAMMA + return rune(0x01d7cb), true + case "b.iota": // MATHEMATICAL BOLD SMALL IOTA + return rune(0x01d6ca), true + case "b.kappa": // MATHEMATICAL BOLD SMALL KAPPA + return rune(0x01d6cb), true + case "b.kappav": // MATHEMATICAL BOLD KAPPA SYMBOL + return rune(0x01d6de), true + case "b.lambda": // MATHEMATICAL BOLD SMALL LAMDA + return rune(0x01d6cc), true + case "b.mu": // MATHEMATICAL BOLD SMALL MU + return rune(0x01d6cd), true + case "b.nu": // MATHEMATICAL BOLD SMALL NU + return rune(0x01d6ce), true + case "b.omega": // MATHEMATICAL BOLD SMALL OMEGA + return rune(0x01d6da), true + case "b.phi": // MATHEMATICAL BOLD SMALL PHI + return rune(0x01d6d7), true + case "b.phiv": // MATHEMATICAL BOLD PHI SYMBOL + return rune(0x01d6df), true + case "b.pi": // MATHEMATICAL BOLD SMALL PI + return rune(0x01d6d1), true + case "b.piv": // MATHEMATICAL BOLD PI SYMBOL + return rune(0x01d6e1), true + case "b.psi": // MATHEMATICAL BOLD SMALL PSI + return rune(0x01d6d9), true + case "b.rho": // MATHEMATICAL BOLD SMALL RHO + return rune(0x01d6d2), true + case "b.rhov": // MATHEMATICAL BOLD RHO SYMBOL + return rune(0x01d6e0), true + case "b.sigma": // MATHEMATICAL BOLD SMALL SIGMA + return rune(0x01d6d4), true + case "b.sigmav": // MATHEMATICAL BOLD SMALL FINAL SIGMA + return rune(0x01d6d3), true + case "b.tau": // MATHEMATICAL BOLD SMALL TAU + return rune(0x01d6d5), true + case "b.thetas": // MATHEMATICAL BOLD SMALL THETA + return rune(0x01d6c9), true + case "b.thetav": // MATHEMATICAL BOLD THETA SYMBOL + return rune(0x01d6dd), true + case "b.upsi": // MATHEMATICAL BOLD SMALL UPSILON + return rune(0x01d6d6), true + case "b.xi": // MATHEMATICAL BOLD SMALL XI + return rune(0x01d6cf), true + case "b.zeta": // MATHEMATICAL BOLD SMALL ZETA + return rune(0x01d6c7), true + case "bNot": // REVERSED DOUBLE STROKE NOT SIGN + return rune(0x2aed), true + case "backcong": // ALL EQUAL TO + return rune(0x224c), true + case "backepsilon": // GREEK REVERSED LUNATE EPSILON SYMBOL + return rune(0x03f6), true + case "backprime": // REVERSED PRIME + return rune(0x2035), true + case "backsim": // REVERSED TILDE + return rune(0x223d), true + case "backsimeq": // REVERSED TILDE EQUALS + return rune(0x22cd), true + case "barV": // DOUBLE DOWN TACK + return rune(0x2aea), true + case "barvee": // NOR + return rune(0x22bd), true + case "barwed": // PROJECTIVE + return rune(0x2305), true + case "barwedge": // PROJECTIVE + return rune(0x2305), true + case "bbrk": // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "bbrktbrk": // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET + return rune(0x23b6), true + case "bcong": // ALL EQUAL TO + return rune(0x224c), true + case "bcy": // CYRILLIC SMALL LETTER BE + return rune(0x0431), true + case "bdlhar": // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2961), true + case "bdquo": // DOUBLE LOW-9 QUOTATION MARK + return rune(0x201e), true + case "bdrhar": // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295d), true + case "becaus": // BECAUSE + return rune(0x2235), true + case "because": // BECAUSE + return rune(0x2235), true + case "bemptyv": // REVERSED EMPTY SET + return rune(0x29b0), true + case "bepsi": // GREEK REVERSED LUNATE EPSILON SYMBOL + return rune(0x03f6), true + case "bernou": // SCRIPT CAPITAL B + return rune(0x212c), true + case "beta": // GREEK SMALL LETTER BETA + return rune(0x03b2), true + case "beth": // BET SYMBOL + return rune(0x2136), true + case "between": // BETWEEN + return rune(0x226c), true + case "bfr": // MATHEMATICAL FRAKTUR SMALL B + return rune(0x01d51f), true + case "bgr": // GREEK SMALL LETTER BETA + return rune(0x03b2), true + case "bigcap": // N-ARY INTERSECTION + return rune(0x22c2), true + case "bigcirc": // LARGE CIRCLE + return rune(0x25ef), true + case "bigcup": // N-ARY UNION + return rune(0x22c3), true + case "bigodot": // N-ARY CIRCLED DOT OPERATOR + return rune(0x2a00), true + case "bigoplus": // N-ARY CIRCLED PLUS OPERATOR + return rune(0x2a01), true + case "bigotimes": // N-ARY CIRCLED TIMES OPERATOR + return rune(0x2a02), true + case "bigsqcup": // N-ARY SQUARE UNION OPERATOR + return rune(0x2a06), true + case "bigstar": // BLACK STAR + return rune(0x2605), true + case "bigtriangledown": // WHITE DOWN-POINTING TRIANGLE + return rune(0x25bd), true + case "bigtriangleup": // WHITE UP-POINTING TRIANGLE + return rune(0x25b3), true + case "biguplus": // N-ARY UNION OPERATOR WITH PLUS + return rune(0x2a04), true + case "bigvee": // N-ARY LOGICAL OR + return rune(0x22c1), true + case "bigwedge": // N-ARY LOGICAL AND + return rune(0x22c0), true + case "bkarow": // RIGHTWARDS DOUBLE DASH ARROW + return rune(0x290d), true + case "blacklozenge": // BLACK LOZENGE + return rune(0x29eb), true + case "blacksquare": // BLACK SMALL SQUARE + return rune(0x25aa), true + case "blacktriangle": // BLACK UP-POINTING SMALL TRIANGLE + return rune(0x25b4), true + case "blacktriangledown": // BLACK DOWN-POINTING SMALL TRIANGLE + return rune(0x25be), true + case "blacktriangleleft": // BLACK LEFT-POINTING SMALL TRIANGLE + return rune(0x25c2), true + case "blacktriangleright": // BLACK RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b8), true + case "blank": // BLANK SYMBOL + return rune(0x2422), true + case "bldhar": // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295e), true + case "blk12": // MEDIUM SHADE + return rune(0x2592), true + case "blk14": // LIGHT SHADE + return rune(0x2591), true + case "blk34": // DARK SHADE + return rune(0x2593), true + case "block": // FULL BLOCK + return rune(0x2588), true + case "bluhar": // LEFTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295a), true + case "bne": // EQUALS SIGN with reverse slash + return rune(0x3d), true + case "bnequiv": // IDENTICAL TO with reverse slash + return rune(0x2261), true + case "bnot": // REVERSED NOT SIGN + return rune(0x2310), true + case "bopf": // MATHEMATICAL DOUBLE-STRUCK SMALL B + return rune(0x01d553), true + case "bot": // UP TACK + return rune(0x22a5), true + case "bottom": // UP TACK + return rune(0x22a5), true + case "bowtie": // BOWTIE + return rune(0x22c8), true + case "boxDL": // BOX DRAWINGS DOUBLE DOWN AND LEFT + return rune(0x2557), true + case "boxDR": // BOX DRAWINGS DOUBLE DOWN AND RIGHT + return rune(0x2554), true + case "boxDl": // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + return rune(0x2556), true + case "boxDr": // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + return rune(0x2553), true + case "boxH": // BOX DRAWINGS DOUBLE HORIZONTAL + return rune(0x2550), true + case "boxHD": // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + return rune(0x2566), true + case "boxHU": // BOX DRAWINGS DOUBLE UP AND HORIZONTAL + return rune(0x2569), true + case "boxHd": // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + return rune(0x2564), true + case "boxHu": // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + return rune(0x2567), true + case "boxUL": // BOX DRAWINGS DOUBLE UP AND LEFT + return rune(0x255d), true + case "boxUR": // BOX DRAWINGS DOUBLE UP AND RIGHT + return rune(0x255a), true + case "boxUl": // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + return rune(0x255c), true + case "boxUr": // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + return rune(0x2559), true + case "boxV": // BOX DRAWINGS DOUBLE VERTICAL + return rune(0x2551), true + case "boxVH": // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + return rune(0x256c), true + case "boxVL": // BOX DRAWINGS DOUBLE VERTICAL AND LEFT + return rune(0x2563), true + case "boxVR": // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + return rune(0x2560), true + case "boxVh": // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + return rune(0x256b), true + case "boxVl": // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + return rune(0x2562), true + case "boxVr": // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + return rune(0x255f), true + case "boxbox": // TWO JOINED SQUARES + return rune(0x29c9), true + case "boxdL": // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + return rune(0x2555), true + case "boxdR": // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + return rune(0x2552), true + case "boxdl": // BOX DRAWINGS LIGHT DOWN AND LEFT + return rune(0x2510), true + case "boxdr": // BOX DRAWINGS LIGHT DOWN AND RIGHT + return rune(0x250c), true + case "boxh": // BOX DRAWINGS LIGHT HORIZONTAL + return rune(0x2500), true + case "boxhD": // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + return rune(0x2565), true + case "boxhU": // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + return rune(0x2568), true + case "boxhd": // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + return rune(0x252c), true + case "boxhu": // BOX DRAWINGS LIGHT UP AND HORIZONTAL + return rune(0x2534), true + case "boxminus": // SQUARED MINUS + return rune(0x229f), true + case "boxplus": // SQUARED PLUS + return rune(0x229e), true + case "boxtimes": // SQUARED TIMES + return rune(0x22a0), true + case "boxuL": // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + return rune(0x255b), true + case "boxuR": // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + return rune(0x2558), true + case "boxul": // BOX DRAWINGS LIGHT UP AND LEFT + return rune(0x2518), true + case "boxur": // BOX DRAWINGS LIGHT UP AND RIGHT + return rune(0x2514), true + case "boxv": // BOX DRAWINGS LIGHT VERTICAL + return rune(0x2502), true + case "boxvH": // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + return rune(0x256a), true + case "boxvL": // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + return rune(0x2561), true + case "boxvR": // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + return rune(0x255e), true + case "boxvh": // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + return rune(0x253c), true + case "boxvl": // BOX DRAWINGS LIGHT VERTICAL AND LEFT + return rune(0x2524), true + case "boxvr": // BOX DRAWINGS LIGHT VERTICAL AND RIGHT + return rune(0x251c), true + case "bprime": // REVERSED PRIME + return rune(0x2035), true + case "brdhar": // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295f), true + case "breve": // BREVE + return rune(0x02d8), true + case "bruhar": // RIGHTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295b), true + case "brvbar": // BROKEN BAR + return rune(0xa6), true + case "bscr": // MATHEMATICAL SCRIPT SMALL B + return rune(0x01d4b7), true + case "bsemi": // REVERSED SEMICOLON + return rune(0x204f), true + case "bsim": // REVERSED TILDE + return rune(0x223d), true + case "bsime": // REVERSED TILDE EQUALS + return rune(0x22cd), true + case "bsol": // REVERSE SOLIDUS + return rune(0x5c), true + case "bsolb": // SQUARED FALLING DIAGONAL SLASH + return rune(0x29c5), true + case "bsolhsub": // REVERSE SOLIDUS PRECEDING SUBSET + return rune(0x27c8), true + case "btimes": // SEMIDIRECT PRODUCT WITH BOTTOM CLOSED + return rune(0x2a32), true + case "bulhar": // UPWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2960), true + case "bull": // BULLET + return rune(0x2022), true + case "bullet": // BULLET + return rune(0x2022), true + case "bump": // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "bumpE": // EQUALS SIGN WITH BUMPY ABOVE + return rune(0x2aae), true + case "bumpe": // DIFFERENCE BETWEEN + return rune(0x224f), true + case "bumpeq": // DIFFERENCE BETWEEN + return rune(0x224f), true + case "burhar": // UPWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295c), true } case 'c': switch name { - case "cacute": // LATIN SMALL LETTER C WITH ACUTE - return rune(0x0107), true - case "cap": // INTERSECTION - return rune(0x2229), true - case "capand": // INTERSECTION WITH LOGICAL AND - return rune(0x2a44), true - case "capbrcup": // INTERSECTION ABOVE BAR ABOVE UNION - return rune(0x2a49), true - case "capcap": // INTERSECTION BESIDE AND JOINED WITH INTERSECTION - return rune(0x2a4b), true - case "capcup": // INTERSECTION ABOVE UNION - return rune(0x2a47), true - case "capdot": // INTERSECTION WITH DOT - return rune(0x2a40), true - case "capint": // INTEGRAL WITH INTERSECTION - return rune(0x2a19), true - case "caps": // INTERSECTION with serifs - return rune(0x2229), true - case "caret": // CARET INSERTION POINT - return rune(0x2041), true - case "caron": // CARON - return rune(0x02c7), true - case "ccaps": // CLOSED INTERSECTION WITH SERIFS - return rune(0x2a4d), true - case "ccaron": // LATIN SMALL LETTER C WITH CARON - return rune(0x010d), true - case "ccedil": // LATIN SMALL LETTER C WITH CEDILLA - return rune(0xe7), true - case "ccirc": // LATIN SMALL LETTER C WITH CIRCUMFLEX - return rune(0x0109), true - case "ccups": // CLOSED UNION WITH SERIFS - return rune(0x2a4c), true - case "ccupssm": // CLOSED UNION WITH SERIFS AND SMASH PRODUCT - return rune(0x2a50), true - case "cdot": // LATIN SMALL LETTER C WITH DOT ABOVE - return rune(0x010b), true - case "cedil": // CEDILLA - return rune(0xb8), true - case "cemptyv": // EMPTY SET WITH SMALL CIRCLE ABOVE - return rune(0x29b2), true - case "cent": // CENT SIGN - return rune(0xa2), true - case "centerdot": // MIDDLE DOT - return rune(0xb7), true - case "cfr": // MATHEMATICAL FRAKTUR SMALL C - return rune(0x01d520), true - case "chcy": // CYRILLIC SMALL LETTER CHE - return rune(0x0447), true - case "check": // CHECK MARK - return rune(0x2713), true - case "checkmark": // CHECK MARK - return rune(0x2713), true - case "chi": // GREEK SMALL LETTER CHI - return rune(0x03c7), true - case "cir": // WHITE CIRCLE - return rune(0x25cb), true - case "cirE": // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT - return rune(0x29c3), true - case "cirb": // SQUARED SMALL CIRCLE - return rune(0x29c7), true - case "circ": // MODIFIER LETTER CIRCUMFLEX ACCENT - return rune(0x02c6), true - case "circeq": // RING EQUAL TO - return rune(0x2257), true - case "circlearrowleft": // ANTICLOCKWISE OPEN CIRCLE ARROW - return rune(0x21ba), true - case "circlearrowright": // CLOCKWISE OPEN CIRCLE ARROW - return rune(0x21bb), true - case "circledR": // REGISTERED SIGN - return rune(0xae), true - case "circledS": // CIRCLED LATIN CAPITAL LETTER S - return rune(0x24c8), true - case "circledast": // CIRCLED ASTERISK OPERATOR - return rune(0x229b), true - case "circledcirc": // CIRCLED RING OPERATOR - return rune(0x229a), true - case "circleddash": // CIRCLED DASH - return rune(0x229d), true - case "cirdarr": // WHITE CIRCLE WITH DOWN ARROW - return rune(0x29ec), true - case "cire": // RING EQUAL TO - return rune(0x2257), true - case "cirerr": // ERROR-BARRED WHITE CIRCLE - return rune(0x29f2), true - case "cirfdarr": // BLACK CIRCLE WITH DOWN ARROW - return rune(0x29ed), true - case "cirferr": // ERROR-BARRED BLACK CIRCLE - return rune(0x29f3), true - case "cirfnint": // CIRCULATION FUNCTION - return rune(0x2a10), true - case "cirmid": // VERTICAL LINE WITH CIRCLE ABOVE - return rune(0x2aef), true - case "cirscir": // CIRCLE WITH SMALL CIRCLE TO THE RIGHT - return rune(0x29c2), true - case "closur": // CLOSE UP - return rune(0x2050), true - case "clubs": // BLACK CLUB SUIT - return rune(0x2663), true - case "clubsuit": // BLACK CLUB SUIT - return rune(0x2663), true - case "colon": // COLON - return rune(0x3a), true - case "colone": // COLON EQUALS - return rune(0x2254), true - case "coloneq": // COLON EQUALS - return rune(0x2254), true - case "comma": // COMMA - return rune(0x2c), true - case "commat": // COMMERCIAL AT - return rune(0x40), true - case "comp": // COMPLEMENT - return rune(0x2201), true - case "compfn": // RING OPERATOR - return rune(0x2218), true - case "complement": // COMPLEMENT - return rune(0x2201), true - case "complexes": // DOUBLE-STRUCK CAPITAL C - return rune(0x2102), true - case "cong": // APPROXIMATELY EQUAL TO - return rune(0x2245), true - case "congdot": // CONGRUENT WITH DOT ABOVE - return rune(0x2a6d), true - case "conint": // CONTOUR INTEGRAL - return rune(0x222e), true - case "copf": // MATHEMATICAL DOUBLE-STRUCK SMALL C - return rune(0x01d554), true - case "coprod": // N-ARY COPRODUCT - return rune(0x2210), true - case "copy": // COPYRIGHT SIGN - return rune(0xa9), true - case "copysr": // SOUND RECORDING COPYRIGHT - return rune(0x2117), true - case "crarr": // DOWNWARDS ARROW WITH CORNER LEFTWARDS - return rune(0x21b5), true - case "cross": // BALLOT X - return rune(0x2717), true - case "cscr": // MATHEMATICAL SCRIPT SMALL C - return rune(0x01d4b8), true - case "csub": // CLOSED SUBSET - return rune(0x2acf), true - case "csube": // CLOSED SUBSET OR EQUAL TO - return rune(0x2ad1), true - case "csup": // CLOSED SUPERSET - return rune(0x2ad0), true - case "csupe": // CLOSED SUPERSET OR EQUAL TO - return rune(0x2ad2), true - case "ctdot": // MIDLINE HORIZONTAL ELLIPSIS - return rune(0x22ef), true - case "cudarrl": // RIGHT-SIDE ARC CLOCKWISE ARROW - return rune(0x2938), true - case "cudarrr": // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS - return rune(0x2935), true - case "cuepr": // EQUAL TO OR PRECEDES - return rune(0x22de), true - case "cuesc": // EQUAL TO OR SUCCEEDS - return rune(0x22df), true - case "cularr": // ANTICLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b6), true - case "cularrp": // TOP ARC ANTICLOCKWISE ARROW WITH PLUS - return rune(0x293d), true - case "cup": // UNION - return rune(0x222a), true - case "cupbrcap": // UNION ABOVE BAR ABOVE INTERSECTION - return rune(0x2a48), true - case "cupcap": // UNION ABOVE INTERSECTION - return rune(0x2a46), true - case "cupcup": // UNION BESIDE AND JOINED WITH UNION - return rune(0x2a4a), true - case "cupdot": // MULTISET MULTIPLICATION - return rune(0x228d), true - case "cupint": // INTEGRAL WITH UNION - return rune(0x2a1a), true - case "cupor": // UNION WITH LOGICAL OR - return rune(0x2a45), true - case "cupre": // PRECEDES OR EQUAL TO - return rune(0x227c), true - case "cups": // UNION with serifs - return rune(0x222a), true - case "curarr": // CLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b7), true - case "curarrm": // TOP ARC CLOCKWISE ARROW WITH MINUS - return rune(0x293c), true - case "curlyeqprec": // EQUAL TO OR PRECEDES - return rune(0x22de), true - case "curlyeqsucc": // EQUAL TO OR SUCCEEDS - return rune(0x22df), true - case "curlyvee": // CURLY LOGICAL OR - return rune(0x22ce), true - case "curlywedge": // CURLY LOGICAL AND - return rune(0x22cf), true - case "curren": // CURRENCY SIGN - return rune(0xa4), true - case "curvearrowleft": // ANTICLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b6), true - case "curvearrowright": // CLOCKWISE TOP SEMICIRCLE ARROW - return rune(0x21b7), true - case "cuvee": // CURLY LOGICAL OR - return rune(0x22ce), true - case "cuwed": // CURLY LOGICAL AND - return rune(0x22cf), true - case "cwconint": // CLOCKWISE CONTOUR INTEGRAL - return rune(0x2232), true - case "cwint": // CLOCKWISE INTEGRAL - return rune(0x2231), true - case "cylcty": // CYLINDRICITY - return rune(0x232d), true + case "cacute": // LATIN SMALL LETTER C WITH ACUTE + return rune(0x0107), true + case "cap": // INTERSECTION + return rune(0x2229), true + case "capand": // INTERSECTION WITH LOGICAL AND + return rune(0x2a44), true + case "capbrcup": // INTERSECTION ABOVE BAR ABOVE UNION + return rune(0x2a49), true + case "capcap": // INTERSECTION BESIDE AND JOINED WITH INTERSECTION + return rune(0x2a4b), true + case "capcup": // INTERSECTION ABOVE UNION + return rune(0x2a47), true + case "capdot": // INTERSECTION WITH DOT + return rune(0x2a40), true + case "capint": // INTEGRAL WITH INTERSECTION + return rune(0x2a19), true + case "caps": // INTERSECTION with serifs + return rune(0x2229), true + case "caret": // CARET INSERTION POINT + return rune(0x2041), true + case "caron": // CARON + return rune(0x02c7), true + case "ccaps": // CLOSED INTERSECTION WITH SERIFS + return rune(0x2a4d), true + case "ccaron": // LATIN SMALL LETTER C WITH CARON + return rune(0x010d), true + case "ccedil": // LATIN SMALL LETTER C WITH CEDILLA + return rune(0xe7), true + case "ccirc": // LATIN SMALL LETTER C WITH CIRCUMFLEX + return rune(0x0109), true + case "ccups": // CLOSED UNION WITH SERIFS + return rune(0x2a4c), true + case "ccupssm": // CLOSED UNION WITH SERIFS AND SMASH PRODUCT + return rune(0x2a50), true + case "cdot": // LATIN SMALL LETTER C WITH DOT ABOVE + return rune(0x010b), true + case "cedil": // CEDILLA + return rune(0xb8), true + case "cemptyv": // EMPTY SET WITH SMALL CIRCLE ABOVE + return rune(0x29b2), true + case "cent": // CENT SIGN + return rune(0xa2), true + case "centerdot": // MIDDLE DOT + return rune(0xb7), true + case "cfr": // MATHEMATICAL FRAKTUR SMALL C + return rune(0x01d520), true + case "chcy": // CYRILLIC SMALL LETTER CHE + return rune(0x0447), true + case "check": // CHECK MARK + return rune(0x2713), true + case "checkmark": // CHECK MARK + return rune(0x2713), true + case "chi": // GREEK SMALL LETTER CHI + return rune(0x03c7), true + case "cir": // WHITE CIRCLE + return rune(0x25cb), true + case "cirE": // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT + return rune(0x29c3), true + case "cirb": // SQUARED SMALL CIRCLE + return rune(0x29c7), true + case "circ": // MODIFIER LETTER CIRCUMFLEX ACCENT + return rune(0x02c6), true + case "circeq": // RING EQUAL TO + return rune(0x2257), true + case "circlearrowleft": // ANTICLOCKWISE OPEN CIRCLE ARROW + return rune(0x21ba), true + case "circlearrowright": // CLOCKWISE OPEN CIRCLE ARROW + return rune(0x21bb), true + case "circledR": // REGISTERED SIGN + return rune(0xae), true + case "circledS": // CIRCLED LATIN CAPITAL LETTER S + return rune(0x24c8), true + case "circledast": // CIRCLED ASTERISK OPERATOR + return rune(0x229b), true + case "circledcirc": // CIRCLED RING OPERATOR + return rune(0x229a), true + case "circleddash": // CIRCLED DASH + return rune(0x229d), true + case "cirdarr": // WHITE CIRCLE WITH DOWN ARROW + return rune(0x29ec), true + case "cire": // RING EQUAL TO + return rune(0x2257), true + case "cirerr": // ERROR-BARRED WHITE CIRCLE + return rune(0x29f2), true + case "cirfdarr": // BLACK CIRCLE WITH DOWN ARROW + return rune(0x29ed), true + case "cirferr": // ERROR-BARRED BLACK CIRCLE + return rune(0x29f3), true + case "cirfnint": // CIRCULATION FUNCTION + return rune(0x2a10), true + case "cirmid": // VERTICAL LINE WITH CIRCLE ABOVE + return rune(0x2aef), true + case "cirscir": // CIRCLE WITH SMALL CIRCLE TO THE RIGHT + return rune(0x29c2), true + case "closur": // CLOSE UP + return rune(0x2050), true + case "clubs": // BLACK CLUB SUIT + return rune(0x2663), true + case "clubsuit": // BLACK CLUB SUIT + return rune(0x2663), true + case "colon": // COLON + return rune(0x3a), true + case "colone": // COLON EQUALS + return rune(0x2254), true + case "coloneq": // COLON EQUALS + return rune(0x2254), true + case "comma": // COMMA + return rune(0x2c), true + case "commat": // COMMERCIAL AT + return rune(0x40), true + case "comp": // COMPLEMENT + return rune(0x2201), true + case "compfn": // RING OPERATOR + return rune(0x2218), true + case "complement": // COMPLEMENT + return rune(0x2201), true + case "complexes": // DOUBLE-STRUCK CAPITAL C + return rune(0x2102), true + case "cong": // APPROXIMATELY EQUAL TO + return rune(0x2245), true + case "congdot": // CONGRUENT WITH DOT ABOVE + return rune(0x2a6d), true + case "conint": // CONTOUR INTEGRAL + return rune(0x222e), true + case "copf": // MATHEMATICAL DOUBLE-STRUCK SMALL C + return rune(0x01d554), true + case "coprod": // N-ARY COPRODUCT + return rune(0x2210), true + case "copy": // COPYRIGHT SIGN + return rune(0xa9), true + case "copysr": // SOUND RECORDING COPYRIGHT + return rune(0x2117), true + case "crarr": // DOWNWARDS ARROW WITH CORNER LEFTWARDS + return rune(0x21b5), true + case "cross": // BALLOT X + return rune(0x2717), true + case "cscr": // MATHEMATICAL SCRIPT SMALL C + return rune(0x01d4b8), true + case "csub": // CLOSED SUBSET + return rune(0x2acf), true + case "csube": // CLOSED SUBSET OR EQUAL TO + return rune(0x2ad1), true + case "csup": // CLOSED SUPERSET + return rune(0x2ad0), true + case "csupe": // CLOSED SUPERSET OR EQUAL TO + return rune(0x2ad2), true + case "ctdot": // MIDLINE HORIZONTAL ELLIPSIS + return rune(0x22ef), true + case "cudarrl": // RIGHT-SIDE ARC CLOCKWISE ARROW + return rune(0x2938), true + case "cudarrr": // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS + return rune(0x2935), true + case "cuepr": // EQUAL TO OR PRECEDES + return rune(0x22de), true + case "cuesc": // EQUAL TO OR SUCCEEDS + return rune(0x22df), true + case "cularr": // ANTICLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b6), true + case "cularrp": // TOP ARC ANTICLOCKWISE ARROW WITH PLUS + return rune(0x293d), true + case "cup": // UNION + return rune(0x222a), true + case "cupbrcap": // UNION ABOVE BAR ABOVE INTERSECTION + return rune(0x2a48), true + case "cupcap": // UNION ABOVE INTERSECTION + return rune(0x2a46), true + case "cupcup": // UNION BESIDE AND JOINED WITH UNION + return rune(0x2a4a), true + case "cupdot": // MULTISET MULTIPLICATION + return rune(0x228d), true + case "cupint": // INTEGRAL WITH UNION + return rune(0x2a1a), true + case "cupor": // UNION WITH LOGICAL OR + return rune(0x2a45), true + case "cupre": // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "cups": // UNION with serifs + return rune(0x222a), true + case "curarr": // CLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b7), true + case "curarrm": // TOP ARC CLOCKWISE ARROW WITH MINUS + return rune(0x293c), true + case "curlyeqprec": // EQUAL TO OR PRECEDES + return rune(0x22de), true + case "curlyeqsucc": // EQUAL TO OR SUCCEEDS + return rune(0x22df), true + case "curlyvee": // CURLY LOGICAL OR + return rune(0x22ce), true + case "curlywedge": // CURLY LOGICAL AND + return rune(0x22cf), true + case "curren": // CURRENCY SIGN + return rune(0xa4), true + case "curvearrowleft": // ANTICLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b6), true + case "curvearrowright": // CLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b7), true + case "cuvee": // CURLY LOGICAL OR + return rune(0x22ce), true + case "cuwed": // CURLY LOGICAL AND + return rune(0x22cf), true + case "cwconint": // CLOCKWISE CONTOUR INTEGRAL + return rune(0x2232), true + case "cwint": // CLOCKWISE INTEGRAL + return rune(0x2231), true + case "cylcty": // CYLINDRICITY + return rune(0x232d), true } case 'd': switch name { - case "dAarr": // DOWNWARDS TRIPLE ARROW - return rune(0x290b), true - case "dArr": // DOWNWARDS DOUBLE ARROW - return rune(0x21d3), true - case "dHar": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - return rune(0x2965), true - case "dagger": // DAGGER - return rune(0x2020), true - case "dalembrt": // SQUARE WITH CONTOURED OUTLINE - return rune(0x29e0), true - case "daleth": // DALET SYMBOL - return rune(0x2138), true - case "darr": // DOWNWARDS ARROW - return rune(0x2193), true - case "darr2": // DOWNWARDS PAIRED ARROWS - return rune(0x21ca), true - case "darrb": // DOWNWARDS ARROW TO BAR - return rune(0x2913), true - case "darrln": // DOWNWARDS ARROW WITH HORIZONTAL STROKE - return rune(0x2908), true - case "dash": // HYPHEN - return rune(0x2010), true - case "dashV": // DOUBLE VERTICAL BAR LEFT TURNSTILE - return rune(0x2ae3), true - case "dashv": // LEFT TACK - return rune(0x22a3), true - case "dbkarow": // RIGHTWARDS TRIPLE DASH ARROW - return rune(0x290f), true - case "dblac": // DOUBLE ACUTE ACCENT - return rune(0x02dd), true - case "dcaron": // LATIN SMALL LETTER D WITH CARON - return rune(0x010f), true - case "dcy": // CYRILLIC SMALL LETTER DE - return rune(0x0434), true - case "dd": // DOUBLE-STRUCK ITALIC SMALL D - return rune(0x2146), true - case "ddagger": // DOUBLE DAGGER - return rune(0x2021), true - case "ddarr": // DOWNWARDS PAIRED ARROWS - return rune(0x21ca), true - case "ddotseq": // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - return rune(0x2a77), true - case "deg": // DEGREE SIGN - return rune(0xb0), true - case "delta": // GREEK SMALL LETTER DELTA - return rune(0x03b4), true - case "demptyv": // EMPTY SET WITH OVERBAR - return rune(0x29b1), true - case "dfisht": // DOWN FISH TAIL - return rune(0x297f), true - case "dfr": // MATHEMATICAL FRAKTUR SMALL D - return rune(0x01d521), true - case "dgr": // GREEK SMALL LETTER DELTA - return rune(0x03b4), true - case "dharl": // DOWNWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21c3), true - case "dharr": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21c2), true - case "diam": // DIAMOND OPERATOR - return rune(0x22c4), true - case "diamdarr": // BLACK DIAMOND WITH DOWN ARROW - return rune(0x29ea), true - case "diamerr": // ERROR-BARRED WHITE DIAMOND - return rune(0x29f0), true - case "diamerrf": // ERROR-BARRED BLACK DIAMOND - return rune(0x29f1), true - case "diamond": // DIAMOND OPERATOR - return rune(0x22c4), true - case "diamondsuit": // BLACK DIAMOND SUIT - return rune(0x2666), true - case "diams": // BLACK DIAMOND SUIT - return rune(0x2666), true - case "die": // DIAERESIS - return rune(0xa8), true - case "digamma": // GREEK SMALL LETTER DIGAMMA - return rune(0x03dd), true - case "disin": // ELEMENT OF WITH LONG HORIZONTAL STROKE - return rune(0x22f2), true - case "div": // DIVISION SIGN - return rune(0xf7), true - case "divide": // DIVISION SIGN - return rune(0xf7), true - case "divideontimes": // DIVISION TIMES - return rune(0x22c7), true - case "divonx": // DIVISION TIMES - return rune(0x22c7), true - case "djcy": // CYRILLIC SMALL LETTER DJE - return rune(0x0452), true - case "dlarr": // SOUTH WEST ARROW - return rune(0x2199), true - case "dlcorn": // BOTTOM LEFT CORNER - return rune(0x231e), true - case "dlcrop": // BOTTOM LEFT CROP - return rune(0x230d), true - case "dlharb": // DOWNWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2959), true - case "dollar": // DOLLAR SIGN - return rune(0x24), true - case "dopf": // MATHEMATICAL DOUBLE-STRUCK SMALL D - return rune(0x01d555), true - case "dot": // DOT ABOVE - return rune(0x02d9), true - case "doteq": // APPROACHES THE LIMIT - return rune(0x2250), true - case "doteqdot": // GEOMETRICALLY EQUAL TO - return rune(0x2251), true - case "dotminus": // DOT MINUS - return rune(0x2238), true - case "dotplus": // DOT PLUS - return rune(0x2214), true - case "dotsquare": // SQUARED DOT OPERATOR - return rune(0x22a1), true - case "doublebarwedge": // PERSPECTIVE - return rune(0x2306), true - case "downarrow": // DOWNWARDS ARROW - return rune(0x2193), true - case "downdownarrows": // DOWNWARDS PAIRED ARROWS - return rune(0x21ca), true - case "downharpoonleft": // DOWNWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21c3), true - case "downharpoonright": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21c2), true - case "drarr": // SOUTH EAST ARROW - return rune(0x2198), true - case "drbkarow": // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - return rune(0x2910), true - case "drcorn": // BOTTOM RIGHT CORNER - return rune(0x231f), true - case "drcrop": // BOTTOM RIGHT CROP - return rune(0x230c), true - case "drharb": // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2955), true - case "dscr": // MATHEMATICAL SCRIPT SMALL D - return rune(0x01d4b9), true - case "dscy": // CYRILLIC SMALL LETTER DZE - return rune(0x0455), true - case "dsol": // SOLIDUS WITH OVERBAR - return rune(0x29f6), true - case "dstrok": // LATIN SMALL LETTER D WITH STROKE - return rune(0x0111), true - case "dtdot": // DOWN RIGHT DIAGONAL ELLIPSIS - return rune(0x22f1), true - case "dtri": // WHITE DOWN-POINTING SMALL TRIANGLE - return rune(0x25bf), true - case "dtrif": // BLACK DOWN-POINTING SMALL TRIANGLE - return rune(0x25be), true - case "dtrilf": // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK - return rune(0x29e8), true - case "dtrirf": // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK - return rune(0x29e9), true - case "duarr": // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - return rune(0x21f5), true - case "duhar": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - return rune(0x296f), true - case "dumap": // DOUBLE-ENDED MULTIMAP - return rune(0x29df), true - case "dwangle": // OBLIQUE ANGLE OPENING UP - return rune(0x29a6), true - case "dzcy": // CYRILLIC SMALL LETTER DZHE - return rune(0x045f), true - case "dzigrarr": // LONG RIGHTWARDS SQUIGGLE ARROW - return rune(0x27ff), true + case "dAarr": // DOWNWARDS TRIPLE ARROW + return rune(0x290b), true + case "dArr": // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "dHar": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x2965), true + case "dagger": // DAGGER + return rune(0x2020), true + case "dalembrt": // SQUARE WITH CONTOURED OUTLINE + return rune(0x29e0), true + case "daleth": // DALET SYMBOL + return rune(0x2138), true + case "darr": // DOWNWARDS ARROW + return rune(0x2193), true + case "darr2": // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "darrb": // DOWNWARDS ARROW TO BAR + return rune(0x2913), true + case "darrln": // DOWNWARDS ARROW WITH HORIZONTAL STROKE + return rune(0x2908), true + case "dash": // HYPHEN + return rune(0x2010), true + case "dashV": // DOUBLE VERTICAL BAR LEFT TURNSTILE + return rune(0x2ae3), true + case "dashv": // LEFT TACK + return rune(0x22a3), true + case "dbkarow": // RIGHTWARDS TRIPLE DASH ARROW + return rune(0x290f), true + case "dblac": // DOUBLE ACUTE ACCENT + return rune(0x02dd), true + case "dcaron": // LATIN SMALL LETTER D WITH CARON + return rune(0x010f), true + case "dcy": // CYRILLIC SMALL LETTER DE + return rune(0x0434), true + case "dd": // DOUBLE-STRUCK ITALIC SMALL D + return rune(0x2146), true + case "ddagger": // DOUBLE DAGGER + return rune(0x2021), true + case "ddarr": // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "ddotseq": // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW + return rune(0x2a77), true + case "deg": // DEGREE SIGN + return rune(0xb0), true + case "delta": // GREEK SMALL LETTER DELTA + return rune(0x03b4), true + case "demptyv": // EMPTY SET WITH OVERBAR + return rune(0x29b1), true + case "dfisht": // DOWN FISH TAIL + return rune(0x297f), true + case "dfr": // MATHEMATICAL FRAKTUR SMALL D + return rune(0x01d521), true + case "dgr": // GREEK SMALL LETTER DELTA + return rune(0x03b4), true + case "dharl": // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "dharr": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "diam": // DIAMOND OPERATOR + return rune(0x22c4), true + case "diamdarr": // BLACK DIAMOND WITH DOWN ARROW + return rune(0x29ea), true + case "diamerr": // ERROR-BARRED WHITE DIAMOND + return rune(0x29f0), true + case "diamerrf": // ERROR-BARRED BLACK DIAMOND + return rune(0x29f1), true + case "diamond": // DIAMOND OPERATOR + return rune(0x22c4), true + case "diamondsuit": // BLACK DIAMOND SUIT + return rune(0x2666), true + case "diams": // BLACK DIAMOND SUIT + return rune(0x2666), true + case "die": // DIAERESIS + return rune(0xa8), true + case "digamma": // GREEK SMALL LETTER DIGAMMA + return rune(0x03dd), true + case "disin": // ELEMENT OF WITH LONG HORIZONTAL STROKE + return rune(0x22f2), true + case "div": // DIVISION SIGN + return rune(0xf7), true + case "divide": // DIVISION SIGN + return rune(0xf7), true + case "divideontimes": // DIVISION TIMES + return rune(0x22c7), true + case "divonx": // DIVISION TIMES + return rune(0x22c7), true + case "djcy": // CYRILLIC SMALL LETTER DJE + return rune(0x0452), true + case "dlarr": // SOUTH WEST ARROW + return rune(0x2199), true + case "dlcorn": // BOTTOM LEFT CORNER + return rune(0x231e), true + case "dlcrop": // BOTTOM LEFT CROP + return rune(0x230d), true + case "dlharb": // DOWNWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2959), true + case "dollar": // DOLLAR SIGN + return rune(0x24), true + case "dopf": // MATHEMATICAL DOUBLE-STRUCK SMALL D + return rune(0x01d555), true + case "dot": // DOT ABOVE + return rune(0x02d9), true + case "doteq": // APPROACHES THE LIMIT + return rune(0x2250), true + case "doteqdot": // GEOMETRICALLY EQUAL TO + return rune(0x2251), true + case "dotminus": // DOT MINUS + return rune(0x2238), true + case "dotplus": // DOT PLUS + return rune(0x2214), true + case "dotsquare": // SQUARED DOT OPERATOR + return rune(0x22a1), true + case "doublebarwedge": // PERSPECTIVE + return rune(0x2306), true + case "downarrow": // DOWNWARDS ARROW + return rune(0x2193), true + case "downdownarrows": // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "downharpoonleft": // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "downharpoonright": // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "drarr": // SOUTH EAST ARROW + return rune(0x2198), true + case "drbkarow": // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW + return rune(0x2910), true + case "drcorn": // BOTTOM RIGHT CORNER + return rune(0x231f), true + case "drcrop": // BOTTOM RIGHT CROP + return rune(0x230c), true + case "drharb": // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2955), true + case "dscr": // MATHEMATICAL SCRIPT SMALL D + return rune(0x01d4b9), true + case "dscy": // CYRILLIC SMALL LETTER DZE + return rune(0x0455), true + case "dsol": // SOLIDUS WITH OVERBAR + return rune(0x29f6), true + case "dstrok": // LATIN SMALL LETTER D WITH STROKE + return rune(0x0111), true + case "dtdot": // DOWN RIGHT DIAGONAL ELLIPSIS + return rune(0x22f1), true + case "dtri": // WHITE DOWN-POINTING SMALL TRIANGLE + return rune(0x25bf), true + case "dtrif": // BLACK DOWN-POINTING SMALL TRIANGLE + return rune(0x25be), true + case "dtrilf": // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK + return rune(0x29e8), true + case "dtrirf": // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK + return rune(0x29e9), true + case "duarr": // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + return rune(0x21f5), true + case "duhar": // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x296f), true + case "dumap": // DOUBLE-ENDED MULTIMAP + return rune(0x29df), true + case "dwangle": // OBLIQUE ANGLE OPENING UP + return rune(0x29a6), true + case "dzcy": // CYRILLIC SMALL LETTER DZHE + return rune(0x045f), true + case "dzigrarr": // LONG RIGHTWARDS SQUIGGLE ARROW + return rune(0x27ff), true } case 'e': switch name { - case "eDDot": // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - return rune(0x2a77), true - case "eDot": // GEOMETRICALLY EQUAL TO - return rune(0x2251), true - case "eacgr": // GREEK SMALL LETTER EPSILON WITH TONOS - return rune(0x03ad), true - case "eacute": // LATIN SMALL LETTER E WITH ACUTE - return rune(0xe9), true - case "easter": // EQUALS WITH ASTERISK - return rune(0x2a6e), true - case "ecaron": // LATIN SMALL LETTER E WITH CARON - return rune(0x011b), true - case "ecir": // RING IN EQUAL TO - return rune(0x2256), true - case "ecirc": // LATIN SMALL LETTER E WITH CIRCUMFLEX - return rune(0xea), true - case "ecolon": // EQUALS COLON - return rune(0x2255), true - case "ecy": // CYRILLIC SMALL LETTER E - return rune(0x044d), true - case "edot": // LATIN SMALL LETTER E WITH DOT ABOVE - return rune(0x0117), true - case "ee": // DOUBLE-STRUCK ITALIC SMALL E - return rune(0x2147), true - case "eeacgr": // GREEK SMALL LETTER ETA WITH TONOS - return rune(0x03ae), true - case "eegr": // GREEK SMALL LETTER ETA - return rune(0x03b7), true - case "efDot": // APPROXIMATELY EQUAL TO OR THE IMAGE OF - return rune(0x2252), true - case "efr": // MATHEMATICAL FRAKTUR SMALL E - return rune(0x01d522), true - case "eg": // DOUBLE-LINE EQUAL TO OR GREATER-THAN - return rune(0x2a9a), true - case "egr": // GREEK SMALL LETTER EPSILON - return rune(0x03b5), true - case "egrave": // LATIN SMALL LETTER E WITH GRAVE - return rune(0xe8), true - case "egs": // SLANTED EQUAL TO OR GREATER-THAN - return rune(0x2a96), true - case "egsdot": // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE - return rune(0x2a98), true - case "el": // DOUBLE-LINE EQUAL TO OR LESS-THAN - return rune(0x2a99), true - case "elinters": // ELECTRICAL INTERSECTION - return rune(0x23e7), true - case "ell": // SCRIPT SMALL L - return rune(0x2113), true - case "els": // SLANTED EQUAL TO OR LESS-THAN - return rune(0x2a95), true - case "elsdot": // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE - return rune(0x2a97), true - case "emacr": // LATIN SMALL LETTER E WITH MACRON - return rune(0x0113), true - case "empty": // EMPTY SET - return rune(0x2205), true - case "emptyset": // EMPTY SET - return rune(0x2205), true - case "emptyv": // EMPTY SET - return rune(0x2205), true - case "emsp": // EM SPACE - return rune(0x2003), true - case "emsp13": // THREE-PER-EM SPACE - return rune(0x2004), true - case "emsp14": // FOUR-PER-EM SPACE - return rune(0x2005), true - case "eng": // LATIN SMALL LETTER ENG - return rune(0x014b), true - case "ensp": // EN SPACE - return rune(0x2002), true - case "eogon": // LATIN SMALL LETTER E WITH OGONEK - return rune(0x0119), true - case "eopf": // MATHEMATICAL DOUBLE-STRUCK SMALL E - return rune(0x01d556), true - case "epar": // EQUAL AND PARALLEL TO - return rune(0x22d5), true - case "eparsl": // EQUALS SIGN AND SLANTED PARALLEL - return rune(0x29e3), true - case "eplus": // EQUALS SIGN ABOVE PLUS SIGN - return rune(0x2a71), true - case "epsi": // GREEK SMALL LETTER EPSILON - return rune(0x03b5), true - case "epsilon": // GREEK SMALL LETTER EPSILON - return rune(0x03b5), true - case "epsis": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true - case "epsiv": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true - case "eqcirc": // RING IN EQUAL TO - return rune(0x2256), true - case "eqcolon": // EQUALS COLON - return rune(0x2255), true - case "eqeq": // TWO CONSECUTIVE EQUALS SIGNS - return rune(0x2a75), true - case "eqsim": // MINUS TILDE - return rune(0x2242), true - case "eqslantgtr": // SLANTED EQUAL TO OR GREATER-THAN - return rune(0x2a96), true - case "eqslantless": // SLANTED EQUAL TO OR LESS-THAN - return rune(0x2a95), true - case "equals": // EQUALS SIGN - return rune(0x3d), true - case "equest": // QUESTIONED EQUAL TO - return rune(0x225f), true - case "equiv": // IDENTICAL TO - return rune(0x2261), true - case "equivDD": // EQUIVALENT WITH FOUR DOTS ABOVE - return rune(0x2a78), true - case "eqvparsl": // IDENTICAL TO AND SLANTED PARALLEL - return rune(0x29e5), true - case "erDot": // IMAGE OF OR APPROXIMATELY EQUAL TO - return rune(0x2253), true - case "erarr": // EQUALS SIGN ABOVE RIGHTWARDS ARROW - return rune(0x2971), true - case "escr": // SCRIPT SMALL E - return rune(0x212f), true - case "esdot": // APPROACHES THE LIMIT - return rune(0x2250), true - case "esim": // MINUS TILDE - return rune(0x2242), true - case "eta": // GREEK SMALL LETTER ETA - return rune(0x03b7), true - case "eth": // LATIN SMALL LETTER ETH - return rune(0xf0), true - case "euml": // LATIN SMALL LETTER E WITH DIAERESIS - return rune(0xeb), true - case "euro": // EURO SIGN - return rune(0x20ac), true - case "excl": // EXCLAMATION MARK - return rune(0x21), true - case "exist": // THERE EXISTS - return rune(0x2203), true - case "expectation": // SCRIPT CAPITAL E - return rune(0x2130), true - case "exponentiale": // DOUBLE-STRUCK ITALIC SMALL E - return rune(0x2147), true + case "eDDot": // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW + return rune(0x2a77), true + case "eDot": // GEOMETRICALLY EQUAL TO + return rune(0x2251), true + case "eacgr": // GREEK SMALL LETTER EPSILON WITH TONOS + return rune(0x03ad), true + case "eacute": // LATIN SMALL LETTER E WITH ACUTE + return rune(0xe9), true + case "easter": // EQUALS WITH ASTERISK + return rune(0x2a6e), true + case "ecaron": // LATIN SMALL LETTER E WITH CARON + return rune(0x011b), true + case "ecir": // RING IN EQUAL TO + return rune(0x2256), true + case "ecirc": // LATIN SMALL LETTER E WITH CIRCUMFLEX + return rune(0xea), true + case "ecolon": // EQUALS COLON + return rune(0x2255), true + case "ecy": // CYRILLIC SMALL LETTER E + return rune(0x044d), true + case "edot": // LATIN SMALL LETTER E WITH DOT ABOVE + return rune(0x0117), true + case "ee": // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true + case "eeacgr": // GREEK SMALL LETTER ETA WITH TONOS + return rune(0x03ae), true + case "eegr": // GREEK SMALL LETTER ETA + return rune(0x03b7), true + case "efDot": // APPROXIMATELY EQUAL TO OR THE IMAGE OF + return rune(0x2252), true + case "efr": // MATHEMATICAL FRAKTUR SMALL E + return rune(0x01d522), true + case "eg": // DOUBLE-LINE EQUAL TO OR GREATER-THAN + return rune(0x2a9a), true + case "egr": // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "egrave": // LATIN SMALL LETTER E WITH GRAVE + return rune(0xe8), true + case "egs": // SLANTED EQUAL TO OR GREATER-THAN + return rune(0x2a96), true + case "egsdot": // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE + return rune(0x2a98), true + case "el": // DOUBLE-LINE EQUAL TO OR LESS-THAN + return rune(0x2a99), true + case "elinters": // ELECTRICAL INTERSECTION + return rune(0x23e7), true + case "ell": // SCRIPT SMALL L + return rune(0x2113), true + case "els": // SLANTED EQUAL TO OR LESS-THAN + return rune(0x2a95), true + case "elsdot": // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE + return rune(0x2a97), true + case "emacr": // LATIN SMALL LETTER E WITH MACRON + return rune(0x0113), true + case "empty": // EMPTY SET + return rune(0x2205), true + case "emptyset": // EMPTY SET + return rune(0x2205), true + case "emptyv": // EMPTY SET + return rune(0x2205), true + case "emsp": // EM SPACE + return rune(0x2003), true + case "emsp13": // THREE-PER-EM SPACE + return rune(0x2004), true + case "emsp14": // FOUR-PER-EM SPACE + return rune(0x2005), true + case "eng": // LATIN SMALL LETTER ENG + return rune(0x014b), true + case "ensp": // EN SPACE + return rune(0x2002), true + case "eogon": // LATIN SMALL LETTER E WITH OGONEK + return rune(0x0119), true + case "eopf": // MATHEMATICAL DOUBLE-STRUCK SMALL E + return rune(0x01d556), true + case "epar": // EQUAL AND PARALLEL TO + return rune(0x22d5), true + case "eparsl": // EQUALS SIGN AND SLANTED PARALLEL + return rune(0x29e3), true + case "eplus": // EQUALS SIGN ABOVE PLUS SIGN + return rune(0x2a71), true + case "epsi": // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "epsilon": // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "epsis": // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "epsiv": // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "eqcirc": // RING IN EQUAL TO + return rune(0x2256), true + case "eqcolon": // EQUALS COLON + return rune(0x2255), true + case "eqeq": // TWO CONSECUTIVE EQUALS SIGNS + return rune(0x2a75), true + case "eqsim": // MINUS TILDE + return rune(0x2242), true + case "eqslantgtr": // SLANTED EQUAL TO OR GREATER-THAN + return rune(0x2a96), true + case "eqslantless": // SLANTED EQUAL TO OR LESS-THAN + return rune(0x2a95), true + case "equals": // EQUALS SIGN + return rune(0x3d), true + case "equest": // QUESTIONED EQUAL TO + return rune(0x225f), true + case "equiv": // IDENTICAL TO + return rune(0x2261), true + case "equivDD": // EQUIVALENT WITH FOUR DOTS ABOVE + return rune(0x2a78), true + case "eqvparsl": // IDENTICAL TO AND SLANTED PARALLEL + return rune(0x29e5), true + case "erDot": // IMAGE OF OR APPROXIMATELY EQUAL TO + return rune(0x2253), true + case "erarr": // EQUALS SIGN ABOVE RIGHTWARDS ARROW + return rune(0x2971), true + case "escr": // SCRIPT SMALL E + return rune(0x212f), true + case "esdot": // APPROACHES THE LIMIT + return rune(0x2250), true + case "esim": // MINUS TILDE + return rune(0x2242), true + case "eta": // GREEK SMALL LETTER ETA + return rune(0x03b7), true + case "eth": // LATIN SMALL LETTER ETH + return rune(0xf0), true + case "euml": // LATIN SMALL LETTER E WITH DIAERESIS + return rune(0xeb), true + case "euro": // EURO SIGN + return rune(0x20ac), true + case "excl": // EXCLAMATION MARK + return rune(0x21), true + case "exist": // THERE EXISTS + return rune(0x2203), true + case "expectation": // SCRIPT CAPITAL E + return rune(0x2130), true + case "exponentiale": // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true } case 'f': switch name { - case "fallingdotseq": // APPROXIMATELY EQUAL TO OR THE IMAGE OF - return rune(0x2252), true - case "fbowtie": // BLACK BOWTIE - return rune(0x29d3), true - case "fcy": // CYRILLIC SMALL LETTER EF - return rune(0x0444), true - case "fdiag": // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - return rune(0x2572), true - case "fdiordi": // FALLING DIAGONAL CROSSING RISING DIAGONAL - return rune(0x292c), true - case "fdonearr": // FALLING DIAGONAL CROSSING NORTH EAST ARROW - return rune(0x292f), true - case "female": // FEMALE SIGN - return rune(0x2640), true - case "ffilig": // LATIN SMALL LIGATURE FFI - return rune(0xfb03), true - case "fflig": // LATIN SMALL LIGATURE FF - return rune(0xfb00), true - case "ffllig": // LATIN SMALL LIGATURE FFL - return rune(0xfb04), true - case "ffr": // MATHEMATICAL FRAKTUR SMALL F - return rune(0x01d523), true - case "fhrglass": // BLACK HOURGLASS - return rune(0x29d7), true - case "filig": // LATIN SMALL LIGATURE FI - return rune(0xfb01), true - case "fjlig": // fj ligature - return rune(0x66), true - case "flat": // MUSIC FLAT SIGN - return rune(0x266d), true - case "fllig": // LATIN SMALL LIGATURE FL - return rune(0xfb02), true - case "fltns": // WHITE PARALLELOGRAM - return rune(0x25b1), true - case "fnof": // LATIN SMALL LETTER F WITH HOOK - return rune(0x0192), true - case "fopf": // MATHEMATICAL DOUBLE-STRUCK SMALL F - return rune(0x01d557), true - case "forall": // FOR ALL - return rune(0x2200), true - case "fork": // PITCHFORK - return rune(0x22d4), true - case "forkv": // ELEMENT OF OPENING DOWNWARDS - return rune(0x2ad9), true - case "fpartint": // FINITE PART INTEGRAL - return rune(0x2a0d), true - case "frac12": // VULGAR FRACTION ONE HALF - return rune(0xbd), true - case "frac13": // VULGAR FRACTION ONE THIRD - return rune(0x2153), true - case "frac14": // VULGAR FRACTION ONE QUARTER - return rune(0xbc), true - case "frac15": // VULGAR FRACTION ONE FIFTH - return rune(0x2155), true - case "frac16": // VULGAR FRACTION ONE SIXTH - return rune(0x2159), true - case "frac18": // VULGAR FRACTION ONE EIGHTH - return rune(0x215b), true - case "frac23": // VULGAR FRACTION TWO THIRDS - return rune(0x2154), true - case "frac25": // VULGAR FRACTION TWO FIFTHS - return rune(0x2156), true - case "frac34": // VULGAR FRACTION THREE QUARTERS - return rune(0xbe), true - case "frac35": // VULGAR FRACTION THREE FIFTHS - return rune(0x2157), true - case "frac38": // VULGAR FRACTION THREE EIGHTHS - return rune(0x215c), true - case "frac45": // VULGAR FRACTION FOUR FIFTHS - return rune(0x2158), true - case "frac56": // VULGAR FRACTION FIVE SIXTHS - return rune(0x215a), true - case "frac58": // VULGAR FRACTION FIVE EIGHTHS - return rune(0x215d), true - case "frac78": // VULGAR FRACTION SEVEN EIGHTHS - return rune(0x215e), true - case "frasl": // FRACTION SLASH - return rune(0x2044), true - case "frown": // FROWN - return rune(0x2322), true - case "fscr": // MATHEMATICAL SCRIPT SMALL F - return rune(0x01d4bb), true + case "fallingdotseq": // APPROXIMATELY EQUAL TO OR THE IMAGE OF + return rune(0x2252), true + case "fbowtie": // BLACK BOWTIE + return rune(0x29d3), true + case "fcy": // CYRILLIC SMALL LETTER EF + return rune(0x0444), true + case "fdiag": // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + return rune(0x2572), true + case "fdiordi": // FALLING DIAGONAL CROSSING RISING DIAGONAL + return rune(0x292c), true + case "fdonearr": // FALLING DIAGONAL CROSSING NORTH EAST ARROW + return rune(0x292f), true + case "female": // FEMALE SIGN + return rune(0x2640), true + case "ffilig": // LATIN SMALL LIGATURE FFI + return rune(0xfb03), true + case "fflig": // LATIN SMALL LIGATURE FF + return rune(0xfb00), true + case "ffllig": // LATIN SMALL LIGATURE FFL + return rune(0xfb04), true + case "ffr": // MATHEMATICAL FRAKTUR SMALL F + return rune(0x01d523), true + case "fhrglass": // BLACK HOURGLASS + return rune(0x29d7), true + case "filig": // LATIN SMALL LIGATURE FI + return rune(0xfb01), true + case "fjlig": // fj ligature + return rune(0x66), true + case "flat": // MUSIC FLAT SIGN + return rune(0x266d), true + case "fllig": // LATIN SMALL LIGATURE FL + return rune(0xfb02), true + case "fltns": // WHITE PARALLELOGRAM + return rune(0x25b1), true + case "fnof": // LATIN SMALL LETTER F WITH HOOK + return rune(0x0192), true + case "fopf": // MATHEMATICAL DOUBLE-STRUCK SMALL F + return rune(0x01d557), true + case "forall": // FOR ALL + return rune(0x2200), true + case "fork": // PITCHFORK + return rune(0x22d4), true + case "forkv": // ELEMENT OF OPENING DOWNWARDS + return rune(0x2ad9), true + case "fpartint": // FINITE PART INTEGRAL + return rune(0x2a0d), true + case "frac12": // VULGAR FRACTION ONE HALF + return rune(0xbd), true + case "frac13": // VULGAR FRACTION ONE THIRD + return rune(0x2153), true + case "frac14": // VULGAR FRACTION ONE QUARTER + return rune(0xbc), true + case "frac15": // VULGAR FRACTION ONE FIFTH + return rune(0x2155), true + case "frac16": // VULGAR FRACTION ONE SIXTH + return rune(0x2159), true + case "frac18": // VULGAR FRACTION ONE EIGHTH + return rune(0x215b), true + case "frac23": // VULGAR FRACTION TWO THIRDS + return rune(0x2154), true + case "frac25": // VULGAR FRACTION TWO FIFTHS + return rune(0x2156), true + case "frac34": // VULGAR FRACTION THREE QUARTERS + return rune(0xbe), true + case "frac35": // VULGAR FRACTION THREE FIFTHS + return rune(0x2157), true + case "frac38": // VULGAR FRACTION THREE EIGHTHS + return rune(0x215c), true + case "frac45": // VULGAR FRACTION FOUR FIFTHS + return rune(0x2158), true + case "frac56": // VULGAR FRACTION FIVE SIXTHS + return rune(0x215a), true + case "frac58": // VULGAR FRACTION FIVE EIGHTHS + return rune(0x215d), true + case "frac78": // VULGAR FRACTION SEVEN EIGHTHS + return rune(0x215e), true + case "frasl": // FRACTION SLASH + return rune(0x2044), true + case "frown": // FROWN + return rune(0x2322), true + case "fscr": // MATHEMATICAL SCRIPT SMALL F + return rune(0x01d4bb), true } case 'g': switch name { - case "gE": // GREATER-THAN OVER EQUAL TO - return rune(0x2267), true - case "gEl": // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - return rune(0x2a8c), true - case "gacute": // LATIN SMALL LETTER G WITH ACUTE - return rune(0x01f5), true - case "gamma": // GREEK SMALL LETTER GAMMA - return rune(0x03b3), true - case "gammad": // GREEK SMALL LETTER DIGAMMA - return rune(0x03dd), true - case "gap": // GREATER-THAN OR APPROXIMATE - return rune(0x2a86), true - case "gbreve": // LATIN SMALL LETTER G WITH BREVE - return rune(0x011f), true - case "gcedil": // LATIN SMALL LETTER G WITH CEDILLA - return rune(0x0123), true - case "gcirc": // LATIN SMALL LETTER G WITH CIRCUMFLEX - return rune(0x011d), true - case "gcy": // CYRILLIC SMALL LETTER GHE - return rune(0x0433), true - case "gdot": // LATIN SMALL LETTER G WITH DOT ABOVE - return rune(0x0121), true - case "ge": // GREATER-THAN OR EQUAL TO - return rune(0x2265), true - case "gel": // GREATER-THAN EQUAL TO OR LESS-THAN - return rune(0x22db), true - case "geq": // GREATER-THAN OR EQUAL TO - return rune(0x2265), true - case "geqq": // GREATER-THAN OVER EQUAL TO - return rune(0x2267), true - case "geqslant": // GREATER-THAN OR SLANTED EQUAL TO - return rune(0x2a7e), true - case "ges": // GREATER-THAN OR SLANTED EQUAL TO - return rune(0x2a7e), true - case "gescc": // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - return rune(0x2aa9), true - case "gesdot": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - return rune(0x2a80), true - case "gesdoto": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - return rune(0x2a82), true - case "gesdotol": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT - return rune(0x2a84), true - case "gesl": // GREATER-THAN slanted EQUAL TO OR LESS-THAN - return rune(0x22db), true - case "gesles": // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL - return rune(0x2a94), true - case "gfr": // MATHEMATICAL FRAKTUR SMALL G - return rune(0x01d524), true - case "gg": // MUCH GREATER-THAN - return rune(0x226b), true - case "ggg": // VERY MUCH GREATER-THAN - return rune(0x22d9), true - case "ggr": // GREEK SMALL LETTER GAMMA - return rune(0x03b3), true - case "gimel": // GIMEL SYMBOL - return rune(0x2137), true - case "gjcy": // CYRILLIC SMALL LETTER GJE - return rune(0x0453), true - case "gl": // GREATER-THAN OR LESS-THAN - return rune(0x2277), true - case "glE": // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL - return rune(0x2a92), true - case "gla": // GREATER-THAN BESIDE LESS-THAN - return rune(0x2aa5), true - case "glj": // GREATER-THAN OVERLAPPING LESS-THAN - return rune(0x2aa4), true - case "gnE": // GREATER-THAN BUT NOT EQUAL TO - return rune(0x2269), true - case "gnap": // GREATER-THAN AND NOT APPROXIMATE - return rune(0x2a8a), true - case "gnapprox": // GREATER-THAN AND NOT APPROXIMATE - return rune(0x2a8a), true - case "gne": // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a88), true - case "gneq": // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a88), true - case "gneqq": // GREATER-THAN BUT NOT EQUAL TO - return rune(0x2269), true - case "gnsim": // GREATER-THAN BUT NOT EQUIVALENT TO - return rune(0x22e7), true - case "gopf": // MATHEMATICAL DOUBLE-STRUCK SMALL G - return rune(0x01d558), true - case "grave": // GRAVE ACCENT - return rune(0x60), true - case "gscr": // SCRIPT SMALL G - return rune(0x210a), true - case "gsdot": // GREATER-THAN WITH DOT - return rune(0x22d7), true - case "gsim": // GREATER-THAN OR EQUIVALENT TO - return rune(0x2273), true - case "gsime": // GREATER-THAN ABOVE SIMILAR OR EQUAL - return rune(0x2a8e), true - case "gsiml": // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN - return rune(0x2a90), true - case "gt": // GREATER-THAN SIGN - return rune(0x3e), true - case "gtcc": // GREATER-THAN CLOSED BY CURVE - return rune(0x2aa7), true - case "gtcir": // GREATER-THAN WITH CIRCLE INSIDE - return rune(0x2a7a), true - case "gtdot": // GREATER-THAN WITH DOT - return rune(0x22d7), true - case "gtlPar": // DOUBLE LEFT ARC GREATER-THAN BRACKET - return rune(0x2995), true - case "gtquest": // GREATER-THAN WITH QUESTION MARK ABOVE - return rune(0x2a7c), true - case "gtrapprox": // GREATER-THAN OR APPROXIMATE - return rune(0x2a86), true - case "gtrarr": // GREATER-THAN ABOVE RIGHTWARDS ARROW - return rune(0x2978), true - case "gtrdot": // GREATER-THAN WITH DOT - return rune(0x22d7), true - case "gtreqless": // GREATER-THAN EQUAL TO OR LESS-THAN - return rune(0x22db), true - case "gtreqqless": // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - return rune(0x2a8c), true - case "gtrless": // GREATER-THAN OR LESS-THAN - return rune(0x2277), true - case "gtrpar": // SPHERICAL ANGLE OPENING LEFT - return rune(0x29a0), true - case "gtrsim": // GREATER-THAN OR EQUIVALENT TO - return rune(0x2273), true - case "gvertneqq": // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2269), true - case "gvnE": // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2269), true + case "gE": // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "gEl": // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + return rune(0x2a8c), true + case "gacute": // LATIN SMALL LETTER G WITH ACUTE + return rune(0x01f5), true + case "gamma": // GREEK SMALL LETTER GAMMA + return rune(0x03b3), true + case "gammad": // GREEK SMALL LETTER DIGAMMA + return rune(0x03dd), true + case "gap": // GREATER-THAN OR APPROXIMATE + return rune(0x2a86), true + case "gbreve": // LATIN SMALL LETTER G WITH BREVE + return rune(0x011f), true + case "gcedil": // LATIN SMALL LETTER G WITH CEDILLA + return rune(0x0123), true + case "gcirc": // LATIN SMALL LETTER G WITH CIRCUMFLEX + return rune(0x011d), true + case "gcy": // CYRILLIC SMALL LETTER GHE + return rune(0x0433), true + case "gdot": // LATIN SMALL LETTER G WITH DOT ABOVE + return rune(0x0121), true + case "ge": // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "gel": // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "geq": // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "geqq": // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "geqslant": // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "ges": // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "gescc": // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + return rune(0x2aa9), true + case "gesdot": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + return rune(0x2a80), true + case "gesdoto": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + return rune(0x2a82), true + case "gesdotol": // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT + return rune(0x2a84), true + case "gesl": // GREATER-THAN slanted EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "gesles": // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL + return rune(0x2a94), true + case "gfr": // MATHEMATICAL FRAKTUR SMALL G + return rune(0x01d524), true + case "gg": // MUCH GREATER-THAN + return rune(0x226b), true + case "ggg": // VERY MUCH GREATER-THAN + return rune(0x22d9), true + case "ggr": // GREEK SMALL LETTER GAMMA + return rune(0x03b3), true + case "gimel": // GIMEL SYMBOL + return rune(0x2137), true + case "gjcy": // CYRILLIC SMALL LETTER GJE + return rune(0x0453), true + case "gl": // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "glE": // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL + return rune(0x2a92), true + case "gla": // GREATER-THAN BESIDE LESS-THAN + return rune(0x2aa5), true + case "glj": // GREATER-THAN OVERLAPPING LESS-THAN + return rune(0x2aa4), true + case "gnE": // GREATER-THAN BUT NOT EQUAL TO + return rune(0x2269), true + case "gnap": // GREATER-THAN AND NOT APPROXIMATE + return rune(0x2a8a), true + case "gnapprox": // GREATER-THAN AND NOT APPROXIMATE + return rune(0x2a8a), true + case "gne": // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a88), true + case "gneq": // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a88), true + case "gneqq": // GREATER-THAN BUT NOT EQUAL TO + return rune(0x2269), true + case "gnsim": // GREATER-THAN BUT NOT EQUIVALENT TO + return rune(0x22e7), true + case "gopf": // MATHEMATICAL DOUBLE-STRUCK SMALL G + return rune(0x01d558), true + case "grave": // GRAVE ACCENT + return rune(0x60), true + case "gscr": // SCRIPT SMALL G + return rune(0x210a), true + case "gsdot": // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gsim": // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "gsime": // GREATER-THAN ABOVE SIMILAR OR EQUAL + return rune(0x2a8e), true + case "gsiml": // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN + return rune(0x2a90), true + case "gt": // GREATER-THAN SIGN + return rune(0x3e), true + case "gtcc": // GREATER-THAN CLOSED BY CURVE + return rune(0x2aa7), true + case "gtcir": // GREATER-THAN WITH CIRCLE INSIDE + return rune(0x2a7a), true + case "gtdot": // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gtlPar": // DOUBLE LEFT ARC GREATER-THAN BRACKET + return rune(0x2995), true + case "gtquest": // GREATER-THAN WITH QUESTION MARK ABOVE + return rune(0x2a7c), true + case "gtrapprox": // GREATER-THAN OR APPROXIMATE + return rune(0x2a86), true + case "gtrarr": // GREATER-THAN ABOVE RIGHTWARDS ARROW + return rune(0x2978), true + case "gtrdot": // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gtreqless": // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "gtreqqless": // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + return rune(0x2a8c), true + case "gtrless": // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "gtrpar": // SPHERICAL ANGLE OPENING LEFT + return rune(0x29a0), true + case "gtrsim": // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "gvertneqq": // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2269), true + case "gvnE": // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2269), true } case 'h': switch name { - case "hArr": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true - case "hairsp": // HAIR SPACE - return rune(0x200a), true - case "half": // VULGAR FRACTION ONE HALF - return rune(0xbd), true - case "hamilt": // SCRIPT CAPITAL H - return rune(0x210b), true - case "hardcy": // CYRILLIC SMALL LETTER HARD SIGN - return rune(0x044a), true - case "harr": // LEFT RIGHT ARROW - return rune(0x2194), true - case "harrcir": // LEFT RIGHT ARROW THROUGH SMALL CIRCLE - return rune(0x2948), true - case "harrw": // LEFT RIGHT WAVE ARROW - return rune(0x21ad), true - case "hbar": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true - case "hcirc": // LATIN SMALL LETTER H WITH CIRCUMFLEX - return rune(0x0125), true - case "hearts": // BLACK HEART SUIT - return rune(0x2665), true - case "heartsuit": // BLACK HEART SUIT - return rune(0x2665), true - case "hellip": // HORIZONTAL ELLIPSIS - return rune(0x2026), true - case "hercon": // HERMITIAN CONJUGATE MATRIX - return rune(0x22b9), true - case "hfr": // MATHEMATICAL FRAKTUR SMALL H - return rune(0x01d525), true - case "hksearow": // SOUTH EAST ARROW WITH HOOK - return rune(0x2925), true - case "hkswarow": // SOUTH WEST ARROW WITH HOOK - return rune(0x2926), true - case "hoarr": // LEFT RIGHT OPEN-HEADED ARROW - return rune(0x21ff), true - case "homtht": // HOMOTHETIC - return rune(0x223b), true - case "hookleftarrow": // LEFTWARDS ARROW WITH HOOK - return rune(0x21a9), true - case "hookrightarrow": // RIGHTWARDS ARROW WITH HOOK - return rune(0x21aa), true - case "hopf": // MATHEMATICAL DOUBLE-STRUCK SMALL H - return rune(0x01d559), true - case "horbar": // HORIZONTAL BAR - return rune(0x2015), true - case "hrglass": // WHITE HOURGLASS - return rune(0x29d6), true - case "hscr": // MATHEMATICAL SCRIPT SMALL H - return rune(0x01d4bd), true - case "hslash": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true - case "hstrok": // LATIN SMALL LETTER H WITH STROKE - return rune(0x0127), true - case "htimes": // VECTOR OR CROSS PRODUCT - return rune(0x2a2f), true - case "hybull": // HYPHEN BULLET - return rune(0x2043), true - case "hyphen": // HYPHEN - return rune(0x2010), true + case "hArr": // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "hairsp": // HAIR SPACE + return rune(0x200a), true + case "half": // VULGAR FRACTION ONE HALF + return rune(0xbd), true + case "hamilt": // SCRIPT CAPITAL H + return rune(0x210b), true + case "hardcy": // CYRILLIC SMALL LETTER HARD SIGN + return rune(0x044a), true + case "harr": // LEFT RIGHT ARROW + return rune(0x2194), true + case "harrcir": // LEFT RIGHT ARROW THROUGH SMALL CIRCLE + return rune(0x2948), true + case "harrw": // LEFT RIGHT WAVE ARROW + return rune(0x21ad), true + case "hbar": // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "hcirc": // LATIN SMALL LETTER H WITH CIRCUMFLEX + return rune(0x0125), true + case "hearts": // BLACK HEART SUIT + return rune(0x2665), true + case "heartsuit": // BLACK HEART SUIT + return rune(0x2665), true + case "hellip": // HORIZONTAL ELLIPSIS + return rune(0x2026), true + case "hercon": // HERMITIAN CONJUGATE MATRIX + return rune(0x22b9), true + case "hfr": // MATHEMATICAL FRAKTUR SMALL H + return rune(0x01d525), true + case "hksearow": // SOUTH EAST ARROW WITH HOOK + return rune(0x2925), true + case "hkswarow": // SOUTH WEST ARROW WITH HOOK + return rune(0x2926), true + case "hoarr": // LEFT RIGHT OPEN-HEADED ARROW + return rune(0x21ff), true + case "homtht": // HOMOTHETIC + return rune(0x223b), true + case "hookleftarrow": // LEFTWARDS ARROW WITH HOOK + return rune(0x21a9), true + case "hookrightarrow": // RIGHTWARDS ARROW WITH HOOK + return rune(0x21aa), true + case "hopf": // MATHEMATICAL DOUBLE-STRUCK SMALL H + return rune(0x01d559), true + case "horbar": // HORIZONTAL BAR + return rune(0x2015), true + case "hrglass": // WHITE HOURGLASS + return rune(0x29d6), true + case "hscr": // MATHEMATICAL SCRIPT SMALL H + return rune(0x01d4bd), true + case "hslash": // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "hstrok": // LATIN SMALL LETTER H WITH STROKE + return rune(0x0127), true + case "htimes": // VECTOR OR CROSS PRODUCT + return rune(0x2a2f), true + case "hybull": // HYPHEN BULLET + return rune(0x2043), true + case "hyphen": // HYPHEN + return rune(0x2010), true } case 'i': switch name { - case "iacgr": // GREEK SMALL LETTER IOTA WITH TONOS - return rune(0x03af), true - case "iacute": // LATIN SMALL LETTER I WITH ACUTE - return rune(0xed), true - case "ic": // INVISIBLE SEPARATOR - return rune(0x2063), true - case "icirc": // LATIN SMALL LETTER I WITH CIRCUMFLEX - return rune(0xee), true - case "icy": // CYRILLIC SMALL LETTER I - return rune(0x0438), true - case "idiagr": // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS - return rune(0x0390), true - case "idigr": // GREEK SMALL LETTER IOTA WITH DIALYTIKA - return rune(0x03ca), true - case "iecy": // CYRILLIC SMALL LETTER IE - return rune(0x0435), true - case "iexcl": // INVERTED EXCLAMATION MARK - return rune(0xa1), true - case "iff": // LEFT RIGHT DOUBLE ARROW - return rune(0x21d4), true - case "ifr": // MATHEMATICAL FRAKTUR SMALL I - return rune(0x01d526), true - case "igr": // GREEK SMALL LETTER IOTA - return rune(0x03b9), true - case "igrave": // LATIN SMALL LETTER I WITH GRAVE - return rune(0xec), true - case "ii": // DOUBLE-STRUCK ITALIC SMALL I - return rune(0x2148), true - case "iiiint": // QUADRUPLE INTEGRAL OPERATOR - return rune(0x2a0c), true - case "iiint": // TRIPLE INTEGRAL - return rune(0x222d), true - case "iinfin": // INCOMPLETE INFINITY - return rune(0x29dc), true - case "iiota": // TURNED GREEK SMALL LETTER IOTA - return rune(0x2129), true - case "ijlig": // LATIN SMALL LIGATURE IJ - return rune(0x0133), true - case "imacr": // LATIN SMALL LETTER I WITH MACRON - return rune(0x012b), true - case "image": // BLACK-LETTER CAPITAL I - return rune(0x2111), true - case "imagline": // SCRIPT CAPITAL I - return rune(0x2110), true - case "imagpart": // BLACK-LETTER CAPITAL I - return rune(0x2111), true - case "imath": // LATIN SMALL LETTER DOTLESS I - return rune(0x0131), true - case "imof": // IMAGE OF - return rune(0x22b7), true - case "imped": // LATIN CAPITAL LETTER Z WITH STROKE - return rune(0x01b5), true - case "in": // ELEMENT OF - return rune(0x2208), true - case "incare": // CARE OF - return rune(0x2105), true - case "infin": // INFINITY - return rune(0x221e), true - case "infintie": // TIE OVER INFINITY - return rune(0x29dd), true - case "inodot": // LATIN SMALL LETTER DOTLESS I - return rune(0x0131), true - case "int": // INTEGRAL - return rune(0x222b), true - case "intcal": // INTERCALATE - return rune(0x22ba), true - case "integers": // DOUBLE-STRUCK CAPITAL Z - return rune(0x2124), true - case "intercal": // INTERCALATE - return rune(0x22ba), true - case "intlarhk": // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK - return rune(0x2a17), true - case "intprod": // INTERIOR PRODUCT - return rune(0x2a3c), true - case "iocy": // CYRILLIC SMALL LETTER IO - return rune(0x0451), true - case "iogon": // LATIN SMALL LETTER I WITH OGONEK - return rune(0x012f), true - case "iopf": // MATHEMATICAL DOUBLE-STRUCK SMALL I - return rune(0x01d55a), true - case "iota": // GREEK SMALL LETTER IOTA - return rune(0x03b9), true - case "iprod": // INTERIOR PRODUCT - return rune(0x2a3c), true - case "iprodr": // RIGHTHAND INTERIOR PRODUCT - return rune(0x2a3d), true - case "iquest": // INVERTED QUESTION MARK - return rune(0xbf), true - case "iscr": // MATHEMATICAL SCRIPT SMALL I - return rune(0x01d4be), true - case "isin": // ELEMENT OF - return rune(0x2208), true - case "isinE": // ELEMENT OF WITH TWO HORIZONTAL STROKES - return rune(0x22f9), true - case "isindot": // ELEMENT OF WITH DOT ABOVE - return rune(0x22f5), true - case "isins": // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22f4), true - case "isinsv": // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22f3), true - case "isinv": // ELEMENT OF - return rune(0x2208), true - case "isinvb": // ELEMENT OF WITH UNDERBAR - return rune(0x22f8), true - case "it": // INVISIBLE TIMES - return rune(0x2062), true - case "itilde": // LATIN SMALL LETTER I WITH TILDE - return rune(0x0129), true - case "iukcy": // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - return rune(0x0456), true - case "iuml": // LATIN SMALL LETTER I WITH DIAERESIS - return rune(0xef), true + case "iacgr": // GREEK SMALL LETTER IOTA WITH TONOS + return rune(0x03af), true + case "iacute": // LATIN SMALL LETTER I WITH ACUTE + return rune(0xed), true + case "ic": // INVISIBLE SEPARATOR + return rune(0x2063), true + case "icirc": // LATIN SMALL LETTER I WITH CIRCUMFLEX + return rune(0xee), true + case "icy": // CYRILLIC SMALL LETTER I + return rune(0x0438), true + case "idiagr": // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + return rune(0x0390), true + case "idigr": // GREEK SMALL LETTER IOTA WITH DIALYTIKA + return rune(0x03ca), true + case "iecy": // CYRILLIC SMALL LETTER IE + return rune(0x0435), true + case "iexcl": // INVERTED EXCLAMATION MARK + return rune(0xa1), true + case "iff": // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "ifr": // MATHEMATICAL FRAKTUR SMALL I + return rune(0x01d526), true + case "igr": // GREEK SMALL LETTER IOTA + return rune(0x03b9), true + case "igrave": // LATIN SMALL LETTER I WITH GRAVE + return rune(0xec), true + case "ii": // DOUBLE-STRUCK ITALIC SMALL I + return rune(0x2148), true + case "iiiint": // QUADRUPLE INTEGRAL OPERATOR + return rune(0x2a0c), true + case "iiint": // TRIPLE INTEGRAL + return rune(0x222d), true + case "iinfin": // INCOMPLETE INFINITY + return rune(0x29dc), true + case "iiota": // TURNED GREEK SMALL LETTER IOTA + return rune(0x2129), true + case "ijlig": // LATIN SMALL LIGATURE IJ + return rune(0x0133), true + case "imacr": // LATIN SMALL LETTER I WITH MACRON + return rune(0x012b), true + case "image": // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "imagline": // SCRIPT CAPITAL I + return rune(0x2110), true + case "imagpart": // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "imath": // LATIN SMALL LETTER DOTLESS I + return rune(0x0131), true + case "imof": // IMAGE OF + return rune(0x22b7), true + case "imped": // LATIN CAPITAL LETTER Z WITH STROKE + return rune(0x01b5), true + case "in": // ELEMENT OF + return rune(0x2208), true + case "incare": // CARE OF + return rune(0x2105), true + case "infin": // INFINITY + return rune(0x221e), true + case "infintie": // TIE OVER INFINITY + return rune(0x29dd), true + case "inodot": // LATIN SMALL LETTER DOTLESS I + return rune(0x0131), true + case "int": // INTEGRAL + return rune(0x222b), true + case "intcal": // INTERCALATE + return rune(0x22ba), true + case "integers": // DOUBLE-STRUCK CAPITAL Z + return rune(0x2124), true + case "intercal": // INTERCALATE + return rune(0x22ba), true + case "intlarhk": // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK + return rune(0x2a17), true + case "intprod": // INTERIOR PRODUCT + return rune(0x2a3c), true + case "iocy": // CYRILLIC SMALL LETTER IO + return rune(0x0451), true + case "iogon": // LATIN SMALL LETTER I WITH OGONEK + return rune(0x012f), true + case "iopf": // MATHEMATICAL DOUBLE-STRUCK SMALL I + return rune(0x01d55a), true + case "iota": // GREEK SMALL LETTER IOTA + return rune(0x03b9), true + case "iprod": // INTERIOR PRODUCT + return rune(0x2a3c), true + case "iprodr": // RIGHTHAND INTERIOR PRODUCT + return rune(0x2a3d), true + case "iquest": // INVERTED QUESTION MARK + return rune(0xbf), true + case "iscr": // MATHEMATICAL SCRIPT SMALL I + return rune(0x01d4be), true + case "isin": // ELEMENT OF + return rune(0x2208), true + case "isinE": // ELEMENT OF WITH TWO HORIZONTAL STROKES + return rune(0x22f9), true + case "isindot": // ELEMENT OF WITH DOT ABOVE + return rune(0x22f5), true + case "isins": // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22f4), true + case "isinsv": // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22f3), true + case "isinv": // ELEMENT OF + return rune(0x2208), true + case "isinvb": // ELEMENT OF WITH UNDERBAR + return rune(0x22f8), true + case "it": // INVISIBLE TIMES + return rune(0x2062), true + case "itilde": // LATIN SMALL LETTER I WITH TILDE + return rune(0x0129), true + case "iukcy": // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + return rune(0x0456), true + case "iuml": // LATIN SMALL LETTER I WITH DIAERESIS + return rune(0xef), true } case 'j': switch name { - case "jcirc": // LATIN SMALL LETTER J WITH CIRCUMFLEX - return rune(0x0135), true - case "jcy": // CYRILLIC SMALL LETTER SHORT I - return rune(0x0439), true - case "jfr": // MATHEMATICAL FRAKTUR SMALL J - return rune(0x01d527), true - case "jmath": // LATIN SMALL LETTER DOTLESS J - return rune(0x0237), true - case "jnodot": // LATIN SMALL LETTER DOTLESS J - return rune(0x0237), true - case "jopf": // MATHEMATICAL DOUBLE-STRUCK SMALL J - return rune(0x01d55b), true - case "jscr": // MATHEMATICAL SCRIPT SMALL J - return rune(0x01d4bf), true - case "jsercy": // CYRILLIC SMALL LETTER JE - return rune(0x0458), true - case "jukcy": // CYRILLIC SMALL LETTER UKRAINIAN IE - return rune(0x0454), true + case "jcirc": // LATIN SMALL LETTER J WITH CIRCUMFLEX + return rune(0x0135), true + case "jcy": // CYRILLIC SMALL LETTER SHORT I + return rune(0x0439), true + case "jfr": // MATHEMATICAL FRAKTUR SMALL J + return rune(0x01d527), true + case "jmath": // LATIN SMALL LETTER DOTLESS J + return rune(0x0237), true + case "jnodot": // LATIN SMALL LETTER DOTLESS J + return rune(0x0237), true + case "jopf": // MATHEMATICAL DOUBLE-STRUCK SMALL J + return rune(0x01d55b), true + case "jscr": // MATHEMATICAL SCRIPT SMALL J + return rune(0x01d4bf), true + case "jsercy": // CYRILLIC SMALL LETTER JE + return rune(0x0458), true + case "jukcy": // CYRILLIC SMALL LETTER UKRAINIAN IE + return rune(0x0454), true } case 'k': switch name { - case "kappa": // GREEK SMALL LETTER KAPPA - return rune(0x03ba), true - case "kappav": // GREEK KAPPA SYMBOL - return rune(0x03f0), true - case "kcedil": // LATIN SMALL LETTER K WITH CEDILLA - return rune(0x0137), true - case "kcy": // CYRILLIC SMALL LETTER KA - return rune(0x043a), true - case "kfr": // MATHEMATICAL FRAKTUR SMALL K - return rune(0x01d528), true - case "kgr": // GREEK SMALL LETTER KAPPA - return rune(0x03ba), true - case "kgreen": // LATIN SMALL LETTER KRA - return rune(0x0138), true - case "khcy": // CYRILLIC SMALL LETTER HA - return rune(0x0445), true - case "khgr": // GREEK SMALL LETTER CHI - return rune(0x03c7), true - case "kjcy": // CYRILLIC SMALL LETTER KJE - return rune(0x045c), true - case "kopf": // MATHEMATICAL DOUBLE-STRUCK SMALL K - return rune(0x01d55c), true - case "koppa": // GREEK LETTER KOPPA - return rune(0x03de), true - case "kscr": // MATHEMATICAL SCRIPT SMALL K - return rune(0x01d4c0), true + case "kappa": // GREEK SMALL LETTER KAPPA + return rune(0x03ba), true + case "kappav": // GREEK KAPPA SYMBOL + return rune(0x03f0), true + case "kcedil": // LATIN SMALL LETTER K WITH CEDILLA + return rune(0x0137), true + case "kcy": // CYRILLIC SMALL LETTER KA + return rune(0x043a), true + case "kfr": // MATHEMATICAL FRAKTUR SMALL K + return rune(0x01d528), true + case "kgr": // GREEK SMALL LETTER KAPPA + return rune(0x03ba), true + case "kgreen": // LATIN SMALL LETTER KRA + return rune(0x0138), true + case "khcy": // CYRILLIC SMALL LETTER HA + return rune(0x0445), true + case "khgr": // GREEK SMALL LETTER CHI + return rune(0x03c7), true + case "kjcy": // CYRILLIC SMALL LETTER KJE + return rune(0x045c), true + case "kopf": // MATHEMATICAL DOUBLE-STRUCK SMALL K + return rune(0x01d55c), true + case "koppa": // GREEK LETTER KOPPA + return rune(0x03de), true + case "kscr": // MATHEMATICAL SCRIPT SMALL K + return rune(0x01d4c0), true } case 'l': switch name { - case "lAarr": // LEFTWARDS TRIPLE ARROW - return rune(0x21da), true - case "lArr": // LEFTWARDS DOUBLE ARROW - return rune(0x21d0), true - case "lAtail": // LEFTWARDS DOUBLE ARROW-TAIL - return rune(0x291b), true - case "lBarr": // LEFTWARDS TRIPLE DASH ARROW - return rune(0x290e), true - case "lE": // LESS-THAN OVER EQUAL TO - return rune(0x2266), true - case "lEg": // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - return rune(0x2a8b), true - case "lHar": // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN - return rune(0x2962), true - case "lacute": // LATIN SMALL LETTER L WITH ACUTE - return rune(0x013a), true - case "laemptyv": // EMPTY SET WITH LEFT ARROW ABOVE - return rune(0x29b4), true - case "lagran": // SCRIPT CAPITAL L - return rune(0x2112), true - case "lambda": // GREEK SMALL LETTER LAMDA - return rune(0x03bb), true - case "lang": // MATHEMATICAL LEFT ANGLE BRACKET - return rune(0x27e8), true - case "langd": // LEFT ANGLE BRACKET WITH DOT - return rune(0x2991), true - case "langle": // MATHEMATICAL LEFT ANGLE BRACKET - return rune(0x27e8), true - case "lap": // LESS-THAN OR APPROXIMATE - return rune(0x2a85), true - case "laquo": // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - return rune(0xab), true - case "larr": // LEFTWARDS ARROW - return rune(0x2190), true - case "larr2": // LEFTWARDS PAIRED ARROWS - return rune(0x21c7), true - case "larrb": // LEFTWARDS ARROW TO BAR - return rune(0x21e4), true - case "larrbfs": // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND - return rune(0x291f), true - case "larrfs": // LEFTWARDS ARROW TO BLACK DIAMOND - return rune(0x291d), true - case "larrhk": // LEFTWARDS ARROW WITH HOOK - return rune(0x21a9), true - case "larrlp": // LEFTWARDS ARROW WITH LOOP - return rune(0x21ab), true - case "larrpl": // LEFT-SIDE ARC ANTICLOCKWISE ARROW - return rune(0x2939), true - case "larrsim": // LEFTWARDS ARROW ABOVE TILDE OPERATOR - return rune(0x2973), true - case "larrtl": // LEFTWARDS ARROW WITH TAIL - return rune(0x21a2), true - case "lat": // LARGER THAN - return rune(0x2aab), true - case "latail": // LEFTWARDS ARROW-TAIL - return rune(0x2919), true - case "late": // LARGER THAN OR EQUAL TO - return rune(0x2aad), true - case "lates": // LARGER THAN OR slanted EQUAL - return rune(0x2aad), true - case "lbarr": // LEFTWARDS DOUBLE DASH ARROW - return rune(0x290c), true - case "lbbrk": // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT - return rune(0x2772), true - case "lbrace": // LEFT CURLY BRACKET - return rune(0x7b), true - case "lbrack": // LEFT SQUARE BRACKET - return rune(0x5b), true - case "lbrke": // LEFT SQUARE BRACKET WITH UNDERBAR - return rune(0x298b), true - case "lbrksld": // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - return rune(0x298f), true - case "lbrkslu": // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER - return rune(0x298d), true - case "lcaron": // LATIN SMALL LETTER L WITH CARON - return rune(0x013e), true - case "lcedil": // LATIN SMALL LETTER L WITH CEDILLA - return rune(0x013c), true - case "lceil": // LEFT CEILING - return rune(0x2308), true - case "lcub": // LEFT CURLY BRACKET - return rune(0x7b), true - case "lcy": // CYRILLIC SMALL LETTER EL - return rune(0x043b), true - case "ldca": // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS - return rune(0x2936), true - case "ldharb": // LEFTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2956), true - case "ldot": // LESS-THAN WITH DOT - return rune(0x22d6), true - case "ldquo": // LEFT DOUBLE QUOTATION MARK - return rune(0x201c), true - case "ldquor": // DOUBLE LOW-9 QUOTATION MARK - return rune(0x201e), true - case "ldrdhar": // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - return rune(0x2967), true - case "ldrdshar": // LEFT BARB DOWN RIGHT BARB DOWN HARPOON - return rune(0x2950), true - case "ldrushar": // LEFT BARB DOWN RIGHT BARB UP HARPOON - return rune(0x294b), true - case "ldsh": // DOWNWARDS ARROW WITH TIP LEFTWARDS - return rune(0x21b2), true - case "le": // LESS-THAN OR EQUAL TO - return rune(0x2264), true - case "leftarrow": // LEFTWARDS ARROW - return rune(0x2190), true - case "leftarrowtail": // LEFTWARDS ARROW WITH TAIL - return rune(0x21a2), true - case "leftharpoondown": // LEFTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21bd), true - case "leftharpoonup": // LEFTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21bc), true - case "leftleftarrows": // LEFTWARDS PAIRED ARROWS - return rune(0x21c7), true - case "leftrightarrow": // LEFT RIGHT ARROW - return rune(0x2194), true - case "leftrightarrows": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true - case "leftrightharpoons": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true - case "leftrightsquigarrow": // LEFT RIGHT WAVE ARROW - return rune(0x21ad), true - case "leftthreetimes": // LEFT SEMIDIRECT PRODUCT - return rune(0x22cb), true - case "leg": // LESS-THAN EQUAL TO OR GREATER-THAN - return rune(0x22da), true - case "leq": // LESS-THAN OR EQUAL TO - return rune(0x2264), true - case "leqq": // LESS-THAN OVER EQUAL TO - return rune(0x2266), true - case "leqslant": // LESS-THAN OR SLANTED EQUAL TO - return rune(0x2a7d), true - case "les": // LESS-THAN OR SLANTED EQUAL TO - return rune(0x2a7d), true - case "lescc": // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - return rune(0x2aa8), true - case "lesdot": // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - return rune(0x2a7f), true - case "lesdoto": // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - return rune(0x2a81), true - case "lesdotor": // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT - return rune(0x2a83), true - case "lesg": // LESS-THAN slanted EQUAL TO OR GREATER-THAN - return rune(0x22da), true - case "lesges": // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL - return rune(0x2a93), true - case "lessapprox": // LESS-THAN OR APPROXIMATE - return rune(0x2a85), true - case "lessdot": // LESS-THAN WITH DOT - return rune(0x22d6), true - case "lesseqgtr": // LESS-THAN EQUAL TO OR GREATER-THAN - return rune(0x22da), true - case "lesseqqgtr": // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - return rune(0x2a8b), true - case "lessgtr": // LESS-THAN OR GREATER-THAN - return rune(0x2276), true - case "lesssim": // LESS-THAN OR EQUIVALENT TO - return rune(0x2272), true - case "lfbowtie": // BOWTIE WITH LEFT HALF BLACK - return rune(0x29d1), true - case "lfisht": // LEFT FISH TAIL - return rune(0x297c), true - case "lfloor": // LEFT FLOOR - return rune(0x230a), true - case "lfr": // MATHEMATICAL FRAKTUR SMALL L - return rune(0x01d529), true - case "lftimes": // TIMES WITH LEFT HALF BLACK - return rune(0x29d4), true - case "lg": // LESS-THAN OR GREATER-THAN - return rune(0x2276), true - case "lgE": // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL - return rune(0x2a91), true - case "lgr": // GREEK SMALL LETTER LAMDA - return rune(0x03bb), true - case "lhard": // LEFTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21bd), true - case "lharu": // LEFTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21bc), true - case "lharul": // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - return rune(0x296a), true - case "lhblk": // LOWER HALF BLOCK - return rune(0x2584), true - case "ljcy": // CYRILLIC SMALL LETTER LJE - return rune(0x0459), true - case "ll": // MUCH LESS-THAN - return rune(0x226a), true - case "llarr": // LEFTWARDS PAIRED ARROWS - return rune(0x21c7), true - case "llcorner": // BOTTOM LEFT CORNER - return rune(0x231e), true - case "llhard": // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - return rune(0x296b), true - case "lltri": // LOWER LEFT TRIANGLE - return rune(0x25fa), true - case "lltrif": // BLACK LOWER LEFT TRIANGLE - return rune(0x25e3), true - case "lmidot": // LATIN SMALL LETTER L WITH MIDDLE DOT - return rune(0x0140), true - case "lmoust": // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - return rune(0x23b0), true - case "lmoustache": // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - return rune(0x23b0), true - case "lnE": // LESS-THAN BUT NOT EQUAL TO - return rune(0x2268), true - case "lnap": // LESS-THAN AND NOT APPROXIMATE - return rune(0x2a89), true - case "lnapprox": // LESS-THAN AND NOT APPROXIMATE - return rune(0x2a89), true - case "lne": // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a87), true - case "lneq": // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - return rune(0x2a87), true - case "lneqq": // LESS-THAN BUT NOT EQUAL TO - return rune(0x2268), true - case "lnsim": // LESS-THAN BUT NOT EQUIVALENT TO - return rune(0x22e6), true - case "loang": // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET - return rune(0x27ec), true - case "loarr": // LEFTWARDS OPEN-HEADED ARROW - return rune(0x21fd), true - case "lobrk": // MATHEMATICAL LEFT WHITE SQUARE BRACKET - return rune(0x27e6), true - case "locub": // LEFT WHITE CURLY BRACKET - return rune(0x2983), true - case "longleftarrow": // LONG LEFTWARDS ARROW - return rune(0x27f5), true - case "longleftrightarrow": // LONG LEFT RIGHT ARROW - return rune(0x27f7), true - case "longmapsto": // LONG RIGHTWARDS ARROW FROM BAR - return rune(0x27fc), true - case "longrightarrow": // LONG RIGHTWARDS ARROW - return rune(0x27f6), true - case "looparrowleft": // LEFTWARDS ARROW WITH LOOP - return rune(0x21ab), true - case "looparrowright": // RIGHTWARDS ARROW WITH LOOP - return rune(0x21ac), true - case "lopar": // LEFT WHITE PARENTHESIS - return rune(0x2985), true - case "lopf": // MATHEMATICAL DOUBLE-STRUCK SMALL L - return rune(0x01d55d), true - case "loplus": // PLUS SIGN IN LEFT HALF CIRCLE - return rune(0x2a2d), true - case "lotimes": // MULTIPLICATION SIGN IN LEFT HALF CIRCLE - return rune(0x2a34), true - case "lowast": // LOW ASTERISK - return rune(0x204e), true - case "lowbar": // LOW LINE - return rune(0x5f), true - case "lowint": // INTEGRAL WITH UNDERBAR - return rune(0x2a1c), true - case "loz": // LOZENGE - return rune(0x25ca), true - case "lozenge": // LOZENGE - return rune(0x25ca), true - case "lozf": // BLACK LOZENGE - return rune(0x29eb), true - case "lpar": // LEFT PARENTHESIS - return rune(0x28), true - case "lpargt": // SPHERICAL ANGLE OPENING LEFT - return rune(0x29a0), true - case "lparlt": // LEFT ARC LESS-THAN BRACKET - return rune(0x2993), true - case "lrarr": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true - case "lrarr2": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - return rune(0x21c6), true - case "lrcorner": // BOTTOM RIGHT CORNER - return rune(0x231f), true - case "lrhar": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true - case "lrhar2": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - return rune(0x21cb), true - case "lrhard": // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - return rune(0x296d), true - case "lrm": // LEFT-TO-RIGHT MARK - return rune(0x200e), true - case "lrtri": // RIGHT TRIANGLE - return rune(0x22bf), true - case "lsaquo": // SINGLE LEFT-POINTING ANGLE QUOTATION MARK - return rune(0x2039), true - case "lscr": // MATHEMATICAL SCRIPT SMALL L - return rune(0x01d4c1), true - case "lsh": // UPWARDS ARROW WITH TIP LEFTWARDS - return rune(0x21b0), true - case "lsim": // LESS-THAN OR EQUIVALENT TO - return rune(0x2272), true - case "lsime": // LESS-THAN ABOVE SIMILAR OR EQUAL - return rune(0x2a8d), true - case "lsimg": // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN - return rune(0x2a8f), true - case "lsqb": // LEFT SQUARE BRACKET - return rune(0x5b), true - case "lsquo": // LEFT SINGLE QUOTATION MARK - return rune(0x2018), true - case "lsquor": // SINGLE LOW-9 QUOTATION MARK - return rune(0x201a), true - case "lstrok": // LATIN SMALL LETTER L WITH STROKE - return rune(0x0142), true - case "lt": // LESS-THAN SIGN - return rune(0x3c), true - case "ltcc": // LESS-THAN CLOSED BY CURVE - return rune(0x2aa6), true - case "ltcir": // LESS-THAN WITH CIRCLE INSIDE - return rune(0x2a79), true - case "ltdot": // LESS-THAN WITH DOT - return rune(0x22d6), true - case "lthree": // LEFT SEMIDIRECT PRODUCT - return rune(0x22cb), true - case "ltimes": // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT - return rune(0x22c9), true - case "ltlarr": // LESS-THAN ABOVE LEFTWARDS ARROW - return rune(0x2976), true - case "ltquest": // LESS-THAN WITH QUESTION MARK ABOVE - return rune(0x2a7b), true - case "ltrPar": // DOUBLE RIGHT ARC LESS-THAN BRACKET - return rune(0x2996), true - case "ltri": // WHITE LEFT-POINTING SMALL TRIANGLE - return rune(0x25c3), true - case "ltrie": // NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22b4), true - case "ltrif": // BLACK LEFT-POINTING SMALL TRIANGLE - return rune(0x25c2), true - case "ltrivb": // LEFT TRIANGLE BESIDE VERTICAL BAR - return rune(0x29cf), true - case "luharb": // LEFTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2952), true - case "lurdshar": // LEFT BARB UP RIGHT BARB DOWN HARPOON - return rune(0x294a), true - case "luruhar": // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP - return rune(0x2966), true - case "lurushar": // LEFT BARB UP RIGHT BARB UP HARPOON - return rune(0x294e), true - case "lvertneqq": // LESS-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2268), true - case "lvnE": // LESS-THAN BUT NOT EQUAL TO - with vertical stroke - return rune(0x2268), true + case "lAarr": // LEFTWARDS TRIPLE ARROW + return rune(0x21da), true + case "lArr": // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "lAtail": // LEFTWARDS DOUBLE ARROW-TAIL + return rune(0x291b), true + case "lBarr": // LEFTWARDS TRIPLE DASH ARROW + return rune(0x290e), true + case "lE": // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "lEg": // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + return rune(0x2a8b), true + case "lHar": // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN + return rune(0x2962), true + case "lacute": // LATIN SMALL LETTER L WITH ACUTE + return rune(0x013a), true + case "laemptyv": // EMPTY SET WITH LEFT ARROW ABOVE + return rune(0x29b4), true + case "lagran": // SCRIPT CAPITAL L + return rune(0x2112), true + case "lambda": // GREEK SMALL LETTER LAMDA + return rune(0x03bb), true + case "lang": // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "langd": // LEFT ANGLE BRACKET WITH DOT + return rune(0x2991), true + case "langle": // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "lap": // LESS-THAN OR APPROXIMATE + return rune(0x2a85), true + case "laquo": // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + return rune(0xab), true + case "larr": // LEFTWARDS ARROW + return rune(0x2190), true + case "larr2": // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "larrb": // LEFTWARDS ARROW TO BAR + return rune(0x21e4), true + case "larrbfs": // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND + return rune(0x291f), true + case "larrfs": // LEFTWARDS ARROW TO BLACK DIAMOND + return rune(0x291d), true + case "larrhk": // LEFTWARDS ARROW WITH HOOK + return rune(0x21a9), true + case "larrlp": // LEFTWARDS ARROW WITH LOOP + return rune(0x21ab), true + case "larrpl": // LEFT-SIDE ARC ANTICLOCKWISE ARROW + return rune(0x2939), true + case "larrsim": // LEFTWARDS ARROW ABOVE TILDE OPERATOR + return rune(0x2973), true + case "larrtl": // LEFTWARDS ARROW WITH TAIL + return rune(0x21a2), true + case "lat": // LARGER THAN + return rune(0x2aab), true + case "latail": // LEFTWARDS ARROW-TAIL + return rune(0x2919), true + case "late": // LARGER THAN OR EQUAL TO + return rune(0x2aad), true + case "lates": // LARGER THAN OR slanted EQUAL + return rune(0x2aad), true + case "lbarr": // LEFTWARDS DOUBLE DASH ARROW + return rune(0x290c), true + case "lbbrk": // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + return rune(0x2772), true + case "lbrace": // LEFT CURLY BRACKET + return rune(0x7b), true + case "lbrack": // LEFT SQUARE BRACKET + return rune(0x5b), true + case "lbrke": // LEFT SQUARE BRACKET WITH UNDERBAR + return rune(0x298b), true + case "lbrksld": // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + return rune(0x298f), true + case "lbrkslu": // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER + return rune(0x298d), true + case "lcaron": // LATIN SMALL LETTER L WITH CARON + return rune(0x013e), true + case "lcedil": // LATIN SMALL LETTER L WITH CEDILLA + return rune(0x013c), true + case "lceil": // LEFT CEILING + return rune(0x2308), true + case "lcub": // LEFT CURLY BRACKET + return rune(0x7b), true + case "lcy": // CYRILLIC SMALL LETTER EL + return rune(0x043b), true + case "ldca": // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS + return rune(0x2936), true + case "ldharb": // LEFTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2956), true + case "ldot": // LESS-THAN WITH DOT + return rune(0x22d6), true + case "ldquo": // LEFT DOUBLE QUOTATION MARK + return rune(0x201c), true + case "ldquor": // DOUBLE LOW-9 QUOTATION MARK + return rune(0x201e), true + case "ldrdhar": // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + return rune(0x2967), true + case "ldrdshar": // LEFT BARB DOWN RIGHT BARB DOWN HARPOON + return rune(0x2950), true + case "ldrushar": // LEFT BARB DOWN RIGHT BARB UP HARPOON + return rune(0x294b), true + case "ldsh": // DOWNWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b2), true + case "le": // LESS-THAN OR EQUAL TO + return rune(0x2264), true + case "leftarrow": // LEFTWARDS ARROW + return rune(0x2190), true + case "leftarrowtail": // LEFTWARDS ARROW WITH TAIL + return rune(0x21a2), true + case "leftharpoondown": // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "leftharpoonup": // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "leftleftarrows": // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "leftrightarrow": // LEFT RIGHT ARROW + return rune(0x2194), true + case "leftrightarrows": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "leftrightharpoons": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "leftrightsquigarrow": // LEFT RIGHT WAVE ARROW + return rune(0x21ad), true + case "leftthreetimes": // LEFT SEMIDIRECT PRODUCT + return rune(0x22cb), true + case "leg": // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "leq": // LESS-THAN OR EQUAL TO + return rune(0x2264), true + case "leqq": // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "leqslant": // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "les": // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "lescc": // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + return rune(0x2aa8), true + case "lesdot": // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + return rune(0x2a7f), true + case "lesdoto": // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + return rune(0x2a81), true + case "lesdotor": // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT + return rune(0x2a83), true + case "lesg": // LESS-THAN slanted EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "lesges": // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL + return rune(0x2a93), true + case "lessapprox": // LESS-THAN OR APPROXIMATE + return rune(0x2a85), true + case "lessdot": // LESS-THAN WITH DOT + return rune(0x22d6), true + case "lesseqgtr": // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "lesseqqgtr": // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + return rune(0x2a8b), true + case "lessgtr": // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "lesssim": // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "lfbowtie": // BOWTIE WITH LEFT HALF BLACK + return rune(0x29d1), true + case "lfisht": // LEFT FISH TAIL + return rune(0x297c), true + case "lfloor": // LEFT FLOOR + return rune(0x230a), true + case "lfr": // MATHEMATICAL FRAKTUR SMALL L + return rune(0x01d529), true + case "lftimes": // TIMES WITH LEFT HALF BLACK + return rune(0x29d4), true + case "lg": // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "lgE": // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL + return rune(0x2a91), true + case "lgr": // GREEK SMALL LETTER LAMDA + return rune(0x03bb), true + case "lhard": // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "lharu": // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "lharul": // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + return rune(0x296a), true + case "lhblk": // LOWER HALF BLOCK + return rune(0x2584), true + case "ljcy": // CYRILLIC SMALL LETTER LJE + return rune(0x0459), true + case "ll": // MUCH LESS-THAN + return rune(0x226a), true + case "llarr": // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "llcorner": // BOTTOM LEFT CORNER + return rune(0x231e), true + case "llhard": // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + return rune(0x296b), true + case "lltri": // LOWER LEFT TRIANGLE + return rune(0x25fa), true + case "lltrif": // BLACK LOWER LEFT TRIANGLE + return rune(0x25e3), true + case "lmidot": // LATIN SMALL LETTER L WITH MIDDLE DOT + return rune(0x0140), true + case "lmoust": // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION + return rune(0x23b0), true + case "lmoustache": // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION + return rune(0x23b0), true + case "lnE": // LESS-THAN BUT NOT EQUAL TO + return rune(0x2268), true + case "lnap": // LESS-THAN AND NOT APPROXIMATE + return rune(0x2a89), true + case "lnapprox": // LESS-THAN AND NOT APPROXIMATE + return rune(0x2a89), true + case "lne": // LESS-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a87), true + case "lneq": // LESS-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a87), true + case "lneqq": // LESS-THAN BUT NOT EQUAL TO + return rune(0x2268), true + case "lnsim": // LESS-THAN BUT NOT EQUIVALENT TO + return rune(0x22e6), true + case "loang": // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET + return rune(0x27ec), true + case "loarr": // LEFTWARDS OPEN-HEADED ARROW + return rune(0x21fd), true + case "lobrk": // MATHEMATICAL LEFT WHITE SQUARE BRACKET + return rune(0x27e6), true + case "locub": // LEFT WHITE CURLY BRACKET + return rune(0x2983), true + case "longleftarrow": // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "longleftrightarrow": // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "longmapsto": // LONG RIGHTWARDS ARROW FROM BAR + return rune(0x27fc), true + case "longrightarrow": // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "looparrowleft": // LEFTWARDS ARROW WITH LOOP + return rune(0x21ab), true + case "looparrowright": // RIGHTWARDS ARROW WITH LOOP + return rune(0x21ac), true + case "lopar": // LEFT WHITE PARENTHESIS + return rune(0x2985), true + case "lopf": // MATHEMATICAL DOUBLE-STRUCK SMALL L + return rune(0x01d55d), true + case "loplus": // PLUS SIGN IN LEFT HALF CIRCLE + return rune(0x2a2d), true + case "lotimes": // MULTIPLICATION SIGN IN LEFT HALF CIRCLE + return rune(0x2a34), true + case "lowast": // LOW ASTERISK + return rune(0x204e), true + case "lowbar": // LOW LINE + return rune(0x5f), true + case "lowint": // INTEGRAL WITH UNDERBAR + return rune(0x2a1c), true + case "loz": // LOZENGE + return rune(0x25ca), true + case "lozenge": // LOZENGE + return rune(0x25ca), true + case "lozf": // BLACK LOZENGE + return rune(0x29eb), true + case "lpar": // LEFT PARENTHESIS + return rune(0x28), true + case "lpargt": // SPHERICAL ANGLE OPENING LEFT + return rune(0x29a0), true + case "lparlt": // LEFT ARC LESS-THAN BRACKET + return rune(0x2993), true + case "lrarr": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "lrarr2": // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "lrcorner": // BOTTOM RIGHT CORNER + return rune(0x231f), true + case "lrhar": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "lrhar2": // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "lrhard": // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + return rune(0x296d), true + case "lrm": // LEFT-TO-RIGHT MARK + return rune(0x200e), true + case "lrtri": // RIGHT TRIANGLE + return rune(0x22bf), true + case "lsaquo": // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + return rune(0x2039), true + case "lscr": // MATHEMATICAL SCRIPT SMALL L + return rune(0x01d4c1), true + case "lsh": // UPWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b0), true + case "lsim": // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "lsime": // LESS-THAN ABOVE SIMILAR OR EQUAL + return rune(0x2a8d), true + case "lsimg": // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN + return rune(0x2a8f), true + case "lsqb": // LEFT SQUARE BRACKET + return rune(0x5b), true + case "lsquo": // LEFT SINGLE QUOTATION MARK + return rune(0x2018), true + case "lsquor": // SINGLE LOW-9 QUOTATION MARK + return rune(0x201a), true + case "lstrok": // LATIN SMALL LETTER L WITH STROKE + return rune(0x0142), true + case "lt": // LESS-THAN SIGN + return rune(0x3c), true + case "ltcc": // LESS-THAN CLOSED BY CURVE + return rune(0x2aa6), true + case "ltcir": // LESS-THAN WITH CIRCLE INSIDE + return rune(0x2a79), true + case "ltdot": // LESS-THAN WITH DOT + return rune(0x22d6), true + case "lthree": // LEFT SEMIDIRECT PRODUCT + return rune(0x22cb), true + case "ltimes": // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + return rune(0x22c9), true + case "ltlarr": // LESS-THAN ABOVE LEFTWARDS ARROW + return rune(0x2976), true + case "ltquest": // LESS-THAN WITH QUESTION MARK ABOVE + return rune(0x2a7b), true + case "ltrPar": // DOUBLE RIGHT ARC LESS-THAN BRACKET + return rune(0x2996), true + case "ltri": // WHITE LEFT-POINTING SMALL TRIANGLE + return rune(0x25c3), true + case "ltrie": // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "ltrif": // BLACK LEFT-POINTING SMALL TRIANGLE + return rune(0x25c2), true + case "ltrivb": // LEFT TRIANGLE BESIDE VERTICAL BAR + return rune(0x29cf), true + case "luharb": // LEFTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2952), true + case "lurdshar": // LEFT BARB UP RIGHT BARB DOWN HARPOON + return rune(0x294a), true + case "luruhar": // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP + return rune(0x2966), true + case "lurushar": // LEFT BARB UP RIGHT BARB UP HARPOON + return rune(0x294e), true + case "lvertneqq": // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2268), true + case "lvnE": // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2268), true } case 'm': switch name { - case "mDDot": // GEOMETRIC PROPORTION - return rune(0x223a), true - case "macr": // MACRON - return rune(0xaf), true - case "male": // MALE SIGN - return rune(0x2642), true - case "malt": // MALTESE CROSS - return rune(0x2720), true - case "maltese": // MALTESE CROSS - return rune(0x2720), true - case "map": // RIGHTWARDS ARROW FROM BAR - return rune(0x21a6), true - case "mapsto": // RIGHTWARDS ARROW FROM BAR - return rune(0x21a6), true - case "mapstodown": // DOWNWARDS ARROW FROM BAR - return rune(0x21a7), true - case "mapstoleft": // LEFTWARDS ARROW FROM BAR - return rune(0x21a4), true - case "mapstoup": // UPWARDS ARROW FROM BAR - return rune(0x21a5), true - case "marker": // BLACK VERTICAL RECTANGLE - return rune(0x25ae), true - case "mcomma": // MINUS SIGN WITH COMMA ABOVE - return rune(0x2a29), true - case "mcy": // CYRILLIC SMALL LETTER EM - return rune(0x043c), true - case "mdash": // EM DASH - return rune(0x2014), true - case "measuredangle": // MEASURED ANGLE - return rune(0x2221), true - case "mfr": // MATHEMATICAL FRAKTUR SMALL M - return rune(0x01d52a), true - case "mgr": // GREEK SMALL LETTER MU - return rune(0x03bc), true - case "mho": // INVERTED OHM SIGN - return rune(0x2127), true - case "micro": // MICRO SIGN - return rune(0xb5), true - case "mid": // DIVIDES - return rune(0x2223), true - case "midast": // ASTERISK - return rune(0x2a), true - case "midcir": // VERTICAL LINE WITH CIRCLE BELOW - return rune(0x2af0), true - case "middot": // MIDDLE DOT - return rune(0xb7), true - case "minus": // MINUS SIGN - return rune(0x2212), true - case "minusb": // SQUARED MINUS - return rune(0x229f), true - case "minusd": // DOT MINUS - return rune(0x2238), true - case "minusdu": // MINUS SIGN WITH DOT BELOW - return rune(0x2a2a), true - case "mlcp": // TRANSVERSAL INTERSECTION - return rune(0x2adb), true - case "mldr": // HORIZONTAL ELLIPSIS - return rune(0x2026), true - case "mnplus": // MINUS-OR-PLUS SIGN - return rune(0x2213), true - case "models": // MODELS - return rune(0x22a7), true - case "mopf": // MATHEMATICAL DOUBLE-STRUCK SMALL M - return rune(0x01d55e), true - case "mp": // MINUS-OR-PLUS SIGN - return rune(0x2213), true - case "mscr": // MATHEMATICAL SCRIPT SMALL M - return rune(0x01d4c2), true - case "mstpos": // INVERTED LAZY S - return rune(0x223e), true - case "mu": // GREEK SMALL LETTER MU - return rune(0x03bc), true - case "multimap": // MULTIMAP - return rune(0x22b8), true - case "mumap": // MULTIMAP - return rune(0x22b8), true + case "mDDot": // GEOMETRIC PROPORTION + return rune(0x223a), true + case "macr": // MACRON + return rune(0xaf), true + case "male": // MALE SIGN + return rune(0x2642), true + case "malt": // MALTESE CROSS + return rune(0x2720), true + case "maltese": // MALTESE CROSS + return rune(0x2720), true + case "map": // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "mapsto": // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "mapstodown": // DOWNWARDS ARROW FROM BAR + return rune(0x21a7), true + case "mapstoleft": // LEFTWARDS ARROW FROM BAR + return rune(0x21a4), true + case "mapstoup": // UPWARDS ARROW FROM BAR + return rune(0x21a5), true + case "marker": // BLACK VERTICAL RECTANGLE + return rune(0x25ae), true + case "mcomma": // MINUS SIGN WITH COMMA ABOVE + return rune(0x2a29), true + case "mcy": // CYRILLIC SMALL LETTER EM + return rune(0x043c), true + case "mdash": // EM DASH + return rune(0x2014), true + case "measuredangle": // MEASURED ANGLE + return rune(0x2221), true + case "mfr": // MATHEMATICAL FRAKTUR SMALL M + return rune(0x01d52a), true + case "mgr": // GREEK SMALL LETTER MU + return rune(0x03bc), true + case "mho": // INVERTED OHM SIGN + return rune(0x2127), true + case "micro": // MICRO SIGN + return rune(0xb5), true + case "mid": // DIVIDES + return rune(0x2223), true + case "midast": // ASTERISK + return rune(0x2a), true + case "midcir": // VERTICAL LINE WITH CIRCLE BELOW + return rune(0x2af0), true + case "middot": // MIDDLE DOT + return rune(0xb7), true + case "minus": // MINUS SIGN + return rune(0x2212), true + case "minusb": // SQUARED MINUS + return rune(0x229f), true + case "minusd": // DOT MINUS + return rune(0x2238), true + case "minusdu": // MINUS SIGN WITH DOT BELOW + return rune(0x2a2a), true + case "mlcp": // TRANSVERSAL INTERSECTION + return rune(0x2adb), true + case "mldr": // HORIZONTAL ELLIPSIS + return rune(0x2026), true + case "mnplus": // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "models": // MODELS + return rune(0x22a7), true + case "mopf": // MATHEMATICAL DOUBLE-STRUCK SMALL M + return rune(0x01d55e), true + case "mp": // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "mscr": // MATHEMATICAL SCRIPT SMALL M + return rune(0x01d4c2), true + case "mstpos": // INVERTED LAZY S + return rune(0x223e), true + case "mu": // GREEK SMALL LETTER MU + return rune(0x03bc), true + case "multimap": // MULTIMAP + return rune(0x22b8), true + case "mumap": // MULTIMAP + return rune(0x22b8), true } case 'n': switch name { - case "nGg": // VERY MUCH GREATER-THAN with slash - return rune(0x22d9), true - case "nGt": // MUCH GREATER THAN with vertical line - return rune(0x226b), true - case "nGtv": // MUCH GREATER THAN with slash - return rune(0x226b), true - case "nLeftarrow": // LEFTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cd), true - case "nLeftrightarrow": // LEFT RIGHT DOUBLE ARROW WITH STROKE - return rune(0x21ce), true - case "nLl": // VERY MUCH LESS-THAN with slash - return rune(0x22d8), true - case "nLt": // MUCH LESS THAN with vertical line - return rune(0x226a), true - case "nLtv": // MUCH LESS THAN with slash - return rune(0x226a), true - case "nRightarrow": // RIGHTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cf), true - case "nVDash": // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE - return rune(0x22af), true - case "nVdash": // DOES NOT FORCE - return rune(0x22ae), true - case "nabla": // NABLA - return rune(0x2207), true - case "nacute": // LATIN SMALL LETTER N WITH ACUTE - return rune(0x0144), true - case "nang": // ANGLE with vertical line - return rune(0x2220), true - case "nap": // NOT ALMOST EQUAL TO - return rune(0x2249), true - case "napE": // APPROXIMATELY EQUAL OR EQUAL TO with slash - return rune(0x2a70), true - case "napid": // TRIPLE TILDE with slash - return rune(0x224b), true - case "napos": // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE - return rune(0x0149), true - case "napprox": // NOT ALMOST EQUAL TO - return rune(0x2249), true - case "natur": // MUSIC NATURAL SIGN - return rune(0x266e), true - case "natural": // MUSIC NATURAL SIGN - return rune(0x266e), true - case "naturals": // DOUBLE-STRUCK CAPITAL N - return rune(0x2115), true - case "nbsp": // NO-BREAK SPACE - return rune(0xa0), true - case "nbump": // GEOMETRICALLY EQUIVALENT TO with slash - return rune(0x224e), true - case "nbumpe": // DIFFERENCE BETWEEN with slash - return rune(0x224f), true - case "ncap": // INTERSECTION WITH OVERBAR - return rune(0x2a43), true - case "ncaron": // LATIN SMALL LETTER N WITH CARON - return rune(0x0148), true - case "ncedil": // LATIN SMALL LETTER N WITH CEDILLA - return rune(0x0146), true - case "ncong": // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO - return rune(0x2247), true - case "ncongdot": // CONGRUENT WITH DOT ABOVE with slash - return rune(0x2a6d), true - case "ncup": // UNION WITH OVERBAR - return rune(0x2a42), true - case "ncy": // CYRILLIC SMALL LETTER EN - return rune(0x043d), true - case "ndash": // EN DASH - return rune(0x2013), true - case "ne": // NOT EQUAL TO - return rune(0x2260), true - case "neArr": // NORTH EAST DOUBLE ARROW - return rune(0x21d7), true - case "nearhk": // NORTH EAST ARROW WITH HOOK - return rune(0x2924), true - case "nearr": // NORTH EAST ARROW - return rune(0x2197), true - case "nearrow": // NORTH EAST ARROW - return rune(0x2197), true - case "nedot": // APPROACHES THE LIMIT with slash - return rune(0x2250), true - case "neonwarr": // NORTH EAST ARROW CROSSING NORTH WEST ARROW - return rune(0x2931), true - case "neosearr": // NORTH EAST ARROW CROSSING SOUTH EAST ARROW - return rune(0x292e), true - case "nequiv": // NOT IDENTICAL TO - return rune(0x2262), true - case "nesear": // NORTH EAST ARROW AND SOUTH EAST ARROW - return rune(0x2928), true - case "nesim": // MINUS TILDE with slash - return rune(0x2242), true - case "neswsarr": // NORTH EAST AND SOUTH WEST ARROW - return rune(0x2922), true - case "nexist": // THERE DOES NOT EXIST - return rune(0x2204), true - case "nexists": // THERE DOES NOT EXIST - return rune(0x2204), true - case "nfr": // MATHEMATICAL FRAKTUR SMALL N - return rune(0x01d52b), true - case "ngE": // GREATER-THAN OVER EQUAL TO with slash - return rune(0x2267), true - case "nge": // NEITHER GREATER-THAN NOR EQUAL TO - return rune(0x2271), true - case "ngeq": // NEITHER GREATER-THAN NOR EQUAL TO - return rune(0x2271), true - case "ngeqq": // GREATER-THAN OVER EQUAL TO with slash - return rune(0x2267), true - case "ngeqslant": // GREATER-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7e), true - case "nges": // GREATER-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7e), true - case "ngr": // GREEK SMALL LETTER NU - return rune(0x03bd), true - case "ngsim": // NEITHER GREATER-THAN NOR EQUIVALENT TO - return rune(0x2275), true - case "ngt": // NOT GREATER-THAN - return rune(0x226f), true - case "ngtr": // NOT GREATER-THAN - return rune(0x226f), true - case "nhArr": // LEFT RIGHT DOUBLE ARROW WITH STROKE - return rune(0x21ce), true - case "nharr": // LEFT RIGHT ARROW WITH STROKE - return rune(0x21ae), true - case "nhpar": // PARALLEL WITH HORIZONTAL STROKE - return rune(0x2af2), true - case "ni": // CONTAINS AS MEMBER - return rune(0x220b), true - case "nis": // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22fc), true - case "nisd": // CONTAINS WITH LONG HORIZONTAL STROKE - return rune(0x22fa), true - case "niv": // CONTAINS AS MEMBER - return rune(0x220b), true - case "njcy": // CYRILLIC SMALL LETTER NJE - return rune(0x045a), true - case "nlArr": // LEFTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cd), true - case "nlE": // LESS-THAN OVER EQUAL TO with slash - return rune(0x2266), true - case "nlarr": // LEFTWARDS ARROW WITH STROKE - return rune(0x219a), true - case "nldr": // TWO DOT LEADER - return rune(0x2025), true - case "nle": // NEITHER LESS-THAN NOR EQUAL TO - return rune(0x2270), true - case "nleftarrow": // LEFTWARDS ARROW WITH STROKE - return rune(0x219a), true - case "nleftrightarrow": // LEFT RIGHT ARROW WITH STROKE - return rune(0x21ae), true - case "nleq": // NEITHER LESS-THAN NOR EQUAL TO - return rune(0x2270), true - case "nleqq": // LESS-THAN OVER EQUAL TO with slash - return rune(0x2266), true - case "nleqslant": // LESS-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7d), true - case "nles": // LESS-THAN OR SLANTED EQUAL TO with slash - return rune(0x2a7d), true - case "nless": // NOT LESS-THAN - return rune(0x226e), true - case "nlsim": // NEITHER LESS-THAN NOR EQUIVALENT TO - return rune(0x2274), true - case "nlt": // NOT LESS-THAN - return rune(0x226e), true - case "nltri": // NOT NORMAL SUBGROUP OF - return rune(0x22ea), true - case "nltrie": // NOT NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22ec), true - case "nltrivb": // LEFT TRIANGLE BESIDE VERTICAL BAR with slash - return rune(0x29cf), true - case "nmid": // DOES NOT DIVIDE - return rune(0x2224), true - case "nopf": // MATHEMATICAL DOUBLE-STRUCK SMALL N - return rune(0x01d55f), true - case "not": // NOT SIGN - return rune(0xac), true - case "notin": // NOT AN ELEMENT OF - return rune(0x2209), true - case "notinE": // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash - return rune(0x22f9), true - case "notindot": // ELEMENT OF WITH DOT ABOVE with slash - return rune(0x22f5), true - case "notinva": // NOT AN ELEMENT OF - return rune(0x2209), true - case "notinvb": // SMALL ELEMENT OF WITH OVERBAR - return rune(0x22f7), true - case "notinvc": // ELEMENT OF WITH OVERBAR - return rune(0x22f6), true - case "notni": // DOES NOT CONTAIN AS MEMBER - return rune(0x220c), true - case "notniva": // DOES NOT CONTAIN AS MEMBER - return rune(0x220c), true - case "notnivb": // SMALL CONTAINS WITH OVERBAR - return rune(0x22fe), true - case "notnivc": // CONTAINS WITH OVERBAR - return rune(0x22fd), true - case "npar": // NOT PARALLEL TO - return rune(0x2226), true - case "nparallel": // NOT PARALLEL TO - return rune(0x2226), true - case "nparsl": // DOUBLE SOLIDUS OPERATOR with reverse slash - return rune(0x2afd), true - case "npart": // PARTIAL DIFFERENTIAL with slash - return rune(0x2202), true - case "npolint": // LINE INTEGRATION NOT INCLUDING THE POLE - return rune(0x2a14), true - case "npr": // DOES NOT PRECEDE - return rune(0x2280), true - case "nprcue": // DOES NOT PRECEDE OR EQUAL - return rune(0x22e0), true - case "npre": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2aaf), true - case "nprec": // DOES NOT PRECEDE - return rune(0x2280), true - case "npreceq": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2aaf), true - case "nprsim": // PRECEDES OR EQUIVALENT TO with slash - return rune(0x227e), true - case "nrArr": // RIGHTWARDS DOUBLE ARROW WITH STROKE - return rune(0x21cf), true - case "nrarr": // RIGHTWARDS ARROW WITH STROKE - return rune(0x219b), true - case "nrarrc": // WAVE ARROW POINTING DIRECTLY RIGHT with slash - return rune(0x2933), true - case "nrarrw": // RIGHTWARDS WAVE ARROW with slash - return rune(0x219d), true - case "nrightarrow": // RIGHTWARDS ARROW WITH STROKE - return rune(0x219b), true - case "nrtri": // DOES NOT CONTAIN AS NORMAL SUBGROUP - return rune(0x22eb), true - case "nrtrie": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - return rune(0x22ed), true - case "nsGt": // DOUBLE NESTED GREATER-THAN with slash - return rune(0x2aa2), true - case "nsLt": // DOUBLE NESTED LESS-THAN with slash - return rune(0x2aa1), true - case "nsc": // DOES NOT SUCCEED - return rune(0x2281), true - case "nsccue": // DOES NOT SUCCEED OR EQUAL - return rune(0x22e1), true - case "nsce": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2ab0), true - case "nscr": // MATHEMATICAL SCRIPT SMALL N - return rune(0x01d4c3), true - case "nscsim": // SUCCEEDS OR EQUIVALENT TO with slash - return rune(0x227f), true - case "nshortmid": // DOES NOT DIVIDE - return rune(0x2224), true - case "nshortparallel": // NOT PARALLEL TO - return rune(0x2226), true - case "nsim": // NOT TILDE - return rune(0x2241), true - case "nsime": // NOT ASYMPTOTICALLY EQUAL TO - return rune(0x2244), true - case "nsimeq": // NOT ASYMPTOTICALLY EQUAL TO - return rune(0x2244), true - case "nsmid": // DOES NOT DIVIDE - return rune(0x2224), true - case "nspar": // NOT PARALLEL TO - return rune(0x2226), true - case "nsqsub": // SQUARE IMAGE OF with slash - return rune(0x228f), true - case "nsqsube": // NOT SQUARE IMAGE OF OR EQUAL TO - return rune(0x22e2), true - case "nsqsup": // SQUARE ORIGINAL OF with slash - return rune(0x2290), true - case "nsqsupe": // NOT SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x22e3), true - case "nsub": // NOT A SUBSET OF - return rune(0x2284), true - case "nsubE": // SUBSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac5), true - case "nsube": // NEITHER A SUBSET OF NOR EQUAL TO - return rune(0x2288), true - case "nsubset": // SUBSET OF with vertical line - return rune(0x2282), true - case "nsubseteq": // NEITHER A SUBSET OF NOR EQUAL TO - return rune(0x2288), true - case "nsubseteqq": // SUBSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac5), true - case "nsucc": // DOES NOT SUCCEED - return rune(0x2281), true - case "nsucceq": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - return rune(0x2ab0), true - case "nsup": // NOT A SUPERSET OF - return rune(0x2285), true - case "nsupE": // SUPERSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac6), true - case "nsupe": // NEITHER A SUPERSET OF NOR EQUAL TO - return rune(0x2289), true - case "nsupset": // SUPERSET OF with vertical line - return rune(0x2283), true - case "nsupseteq": // NEITHER A SUPERSET OF NOR EQUAL TO - return rune(0x2289), true - case "nsupseteqq": // SUPERSET OF ABOVE EQUALS SIGN with slash - return rune(0x2ac6), true - case "ntgl": // NEITHER GREATER-THAN NOR LESS-THAN - return rune(0x2279), true - case "ntilde": // LATIN SMALL LETTER N WITH TILDE - return rune(0xf1), true - case "ntlg": // NEITHER LESS-THAN NOR GREATER-THAN - return rune(0x2278), true - case "ntriangleleft": // NOT NORMAL SUBGROUP OF - return rune(0x22ea), true - case "ntrianglelefteq": // NOT NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22ec), true - case "ntriangleright": // DOES NOT CONTAIN AS NORMAL SUBGROUP - return rune(0x22eb), true - case "ntrianglerighteq": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - return rune(0x22ed), true - case "nu": // GREEK SMALL LETTER NU - return rune(0x03bd), true - case "num": // NUMBER SIGN - return rune(0x23), true - case "numero": // NUMERO SIGN - return rune(0x2116), true - case "numsp": // FIGURE SPACE - return rune(0x2007), true - case "nvDash": // NOT TRUE - return rune(0x22ad), true - case "nvHarr": // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE - return rune(0x2904), true - case "nvap": // EQUIVALENT TO with vertical line - return rune(0x224d), true - case "nvbrtri": // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash - return rune(0x29d0), true - case "nvdash": // DOES NOT PROVE - return rune(0x22ac), true - case "nvge": // GREATER-THAN OR EQUAL TO with vertical line - return rune(0x2265), true - case "nvgt": // GREATER-THAN SIGN with vertical line - return rune(0x3e), true - case "nvinfin": // INFINITY NEGATED WITH VERTICAL BAR - return rune(0x29de), true - case "nvlArr": // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE - return rune(0x2902), true - case "nvle": // LESS-THAN OR EQUAL TO with vertical line - return rune(0x2264), true - case "nvlt": // LESS-THAN SIGN with vertical line - return rune(0x3c), true - case "nvltrie": // NORMAL SUBGROUP OF OR EQUAL TO with vertical line - return rune(0x22b4), true - case "nvrArr": // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE - return rune(0x2903), true - case "nvrtrie": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line - return rune(0x22b5), true - case "nvsim": // TILDE OPERATOR with vertical line - return rune(0x223c), true - case "nwArr": // NORTH WEST DOUBLE ARROW - return rune(0x21d6), true - case "nwarhk": // NORTH WEST ARROW WITH HOOK - return rune(0x2923), true - case "nwarr": // NORTH WEST ARROW - return rune(0x2196), true - case "nwarrow": // NORTH WEST ARROW - return rune(0x2196), true - case "nwnear": // NORTH WEST ARROW AND NORTH EAST ARROW - return rune(0x2927), true - case "nwonearr": // NORTH WEST ARROW CROSSING NORTH EAST ARROW - return rune(0x2932), true - case "nwsesarr": // NORTH WEST AND SOUTH EAST ARROW - return rune(0x2921), true + case "nGg": // VERY MUCH GREATER-THAN with slash + return rune(0x22d9), true + case "nGt": // MUCH GREATER THAN with vertical line + return rune(0x226b), true + case "nGtv": // MUCH GREATER THAN with slash + return rune(0x226b), true + case "nLeftarrow": // LEFTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cd), true + case "nLeftrightarrow": // LEFT RIGHT DOUBLE ARROW WITH STROKE + return rune(0x21ce), true + case "nLl": // VERY MUCH LESS-THAN with slash + return rune(0x22d8), true + case "nLt": // MUCH LESS THAN with vertical line + return rune(0x226a), true + case "nLtv": // MUCH LESS THAN with slash + return rune(0x226a), true + case "nRightarrow": // RIGHTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cf), true + case "nVDash": // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + return rune(0x22af), true + case "nVdash": // DOES NOT FORCE + return rune(0x22ae), true + case "nabla": // NABLA + return rune(0x2207), true + case "nacute": // LATIN SMALL LETTER N WITH ACUTE + return rune(0x0144), true + case "nang": // ANGLE with vertical line + return rune(0x2220), true + case "nap": // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "napE": // APPROXIMATELY EQUAL OR EQUAL TO with slash + return rune(0x2a70), true + case "napid": // TRIPLE TILDE with slash + return rune(0x224b), true + case "napos": // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + return rune(0x0149), true + case "napprox": // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "natur": // MUSIC NATURAL SIGN + return rune(0x266e), true + case "natural": // MUSIC NATURAL SIGN + return rune(0x266e), true + case "naturals": // DOUBLE-STRUCK CAPITAL N + return rune(0x2115), true + case "nbsp": // NO-BREAK SPACE + return rune(0xa0), true + case "nbump": // GEOMETRICALLY EQUIVALENT TO with slash + return rune(0x224e), true + case "nbumpe": // DIFFERENCE BETWEEN with slash + return rune(0x224f), true + case "ncap": // INTERSECTION WITH OVERBAR + return rune(0x2a43), true + case "ncaron": // LATIN SMALL LETTER N WITH CARON + return rune(0x0148), true + case "ncedil": // LATIN SMALL LETTER N WITH CEDILLA + return rune(0x0146), true + case "ncong": // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + return rune(0x2247), true + case "ncongdot": // CONGRUENT WITH DOT ABOVE with slash + return rune(0x2a6d), true + case "ncup": // UNION WITH OVERBAR + return rune(0x2a42), true + case "ncy": // CYRILLIC SMALL LETTER EN + return rune(0x043d), true + case "ndash": // EN DASH + return rune(0x2013), true + case "ne": // NOT EQUAL TO + return rune(0x2260), true + case "neArr": // NORTH EAST DOUBLE ARROW + return rune(0x21d7), true + case "nearhk": // NORTH EAST ARROW WITH HOOK + return rune(0x2924), true + case "nearr": // NORTH EAST ARROW + return rune(0x2197), true + case "nearrow": // NORTH EAST ARROW + return rune(0x2197), true + case "nedot": // APPROACHES THE LIMIT with slash + return rune(0x2250), true + case "neonwarr": // NORTH EAST ARROW CROSSING NORTH WEST ARROW + return rune(0x2931), true + case "neosearr": // NORTH EAST ARROW CROSSING SOUTH EAST ARROW + return rune(0x292e), true + case "nequiv": // NOT IDENTICAL TO + return rune(0x2262), true + case "nesear": // NORTH EAST ARROW AND SOUTH EAST ARROW + return rune(0x2928), true + case "nesim": // MINUS TILDE with slash + return rune(0x2242), true + case "neswsarr": // NORTH EAST AND SOUTH WEST ARROW + return rune(0x2922), true + case "nexist": // THERE DOES NOT EXIST + return rune(0x2204), true + case "nexists": // THERE DOES NOT EXIST + return rune(0x2204), true + case "nfr": // MATHEMATICAL FRAKTUR SMALL N + return rune(0x01d52b), true + case "ngE": // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "nge": // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "ngeq": // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "ngeqq": // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "ngeqslant": // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "nges": // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "ngr": // GREEK SMALL LETTER NU + return rune(0x03bd), true + case "ngsim": // NEITHER GREATER-THAN NOR EQUIVALENT TO + return rune(0x2275), true + case "ngt": // NOT GREATER-THAN + return rune(0x226f), true + case "ngtr": // NOT GREATER-THAN + return rune(0x226f), true + case "nhArr": // LEFT RIGHT DOUBLE ARROW WITH STROKE + return rune(0x21ce), true + case "nharr": // LEFT RIGHT ARROW WITH STROKE + return rune(0x21ae), true + case "nhpar": // PARALLEL WITH HORIZONTAL STROKE + return rune(0x2af2), true + case "ni": // CONTAINS AS MEMBER + return rune(0x220b), true + case "nis": // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22fc), true + case "nisd": // CONTAINS WITH LONG HORIZONTAL STROKE + return rune(0x22fa), true + case "niv": // CONTAINS AS MEMBER + return rune(0x220b), true + case "njcy": // CYRILLIC SMALL LETTER NJE + return rune(0x045a), true + case "nlArr": // LEFTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cd), true + case "nlE": // LESS-THAN OVER EQUAL TO with slash + return rune(0x2266), true + case "nlarr": // LEFTWARDS ARROW WITH STROKE + return rune(0x219a), true + case "nldr": // TWO DOT LEADER + return rune(0x2025), true + case "nle": // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "nleftarrow": // LEFTWARDS ARROW WITH STROKE + return rune(0x219a), true + case "nleftrightarrow": // LEFT RIGHT ARROW WITH STROKE + return rune(0x21ae), true + case "nleq": // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "nleqq": // LESS-THAN OVER EQUAL TO with slash + return rune(0x2266), true + case "nleqslant": // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "nles": // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "nless": // NOT LESS-THAN + return rune(0x226e), true + case "nlsim": // NEITHER LESS-THAN NOR EQUIVALENT TO + return rune(0x2274), true + case "nlt": // NOT LESS-THAN + return rune(0x226e), true + case "nltri": // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "nltrie": // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "nltrivb": // LEFT TRIANGLE BESIDE VERTICAL BAR with slash + return rune(0x29cf), true + case "nmid": // DOES NOT DIVIDE + return rune(0x2224), true + case "nopf": // MATHEMATICAL DOUBLE-STRUCK SMALL N + return rune(0x01d55f), true + case "not": // NOT SIGN + return rune(0xac), true + case "notin": // NOT AN ELEMENT OF + return rune(0x2209), true + case "notinE": // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash + return rune(0x22f9), true + case "notindot": // ELEMENT OF WITH DOT ABOVE with slash + return rune(0x22f5), true + case "notinva": // NOT AN ELEMENT OF + return rune(0x2209), true + case "notinvb": // SMALL ELEMENT OF WITH OVERBAR + return rune(0x22f7), true + case "notinvc": // ELEMENT OF WITH OVERBAR + return rune(0x22f6), true + case "notni": // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "notniva": // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "notnivb": // SMALL CONTAINS WITH OVERBAR + return rune(0x22fe), true + case "notnivc": // CONTAINS WITH OVERBAR + return rune(0x22fd), true + case "npar": // NOT PARALLEL TO + return rune(0x2226), true + case "nparallel": // NOT PARALLEL TO + return rune(0x2226), true + case "nparsl": // DOUBLE SOLIDUS OPERATOR with reverse slash + return rune(0x2afd), true + case "npart": // PARTIAL DIFFERENTIAL with slash + return rune(0x2202), true + case "npolint": // LINE INTEGRATION NOT INCLUDING THE POLE + return rune(0x2a14), true + case "npr": // DOES NOT PRECEDE + return rune(0x2280), true + case "nprcue": // DOES NOT PRECEDE OR EQUAL + return rune(0x22e0), true + case "npre": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "nprec": // DOES NOT PRECEDE + return rune(0x2280), true + case "npreceq": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "nprsim": // PRECEDES OR EQUIVALENT TO with slash + return rune(0x227e), true + case "nrArr": // RIGHTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cf), true + case "nrarr": // RIGHTWARDS ARROW WITH STROKE + return rune(0x219b), true + case "nrarrc": // WAVE ARROW POINTING DIRECTLY RIGHT with slash + return rune(0x2933), true + case "nrarrw": // RIGHTWARDS WAVE ARROW with slash + return rune(0x219d), true + case "nrightarrow": // RIGHTWARDS ARROW WITH STROKE + return rune(0x219b), true + case "nrtri": // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "nrtrie": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "nsGt": // DOUBLE NESTED GREATER-THAN with slash + return rune(0x2aa2), true + case "nsLt": // DOUBLE NESTED LESS-THAN with slash + return rune(0x2aa1), true + case "nsc": // DOES NOT SUCCEED + return rune(0x2281), true + case "nsccue": // DOES NOT SUCCEED OR EQUAL + return rune(0x22e1), true + case "nsce": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "nscr": // MATHEMATICAL SCRIPT SMALL N + return rune(0x01d4c3), true + case "nscsim": // SUCCEEDS OR EQUIVALENT TO with slash + return rune(0x227f), true + case "nshortmid": // DOES NOT DIVIDE + return rune(0x2224), true + case "nshortparallel": // NOT PARALLEL TO + return rune(0x2226), true + case "nsim": // NOT TILDE + return rune(0x2241), true + case "nsime": // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "nsimeq": // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "nsmid": // DOES NOT DIVIDE + return rune(0x2224), true + case "nspar": // NOT PARALLEL TO + return rune(0x2226), true + case "nsqsub": // SQUARE IMAGE OF with slash + return rune(0x228f), true + case "nsqsube": // NOT SQUARE IMAGE OF OR EQUAL TO + return rune(0x22e2), true + case "nsqsup": // SQUARE ORIGINAL OF with slash + return rune(0x2290), true + case "nsqsupe": // NOT SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x22e3), true + case "nsub": // NOT A SUBSET OF + return rune(0x2284), true + case "nsubE": // SUBSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac5), true + case "nsube": // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "nsubset": // SUBSET OF with vertical line + return rune(0x2282), true + case "nsubseteq": // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "nsubseteqq": // SUBSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac5), true + case "nsucc": // DOES NOT SUCCEED + return rune(0x2281), true + case "nsucceq": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "nsup": // NOT A SUPERSET OF + return rune(0x2285), true + case "nsupE": // SUPERSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac6), true + case "nsupe": // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "nsupset": // SUPERSET OF with vertical line + return rune(0x2283), true + case "nsupseteq": // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "nsupseteqq": // SUPERSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac6), true + case "ntgl": // NEITHER GREATER-THAN NOR LESS-THAN + return rune(0x2279), true + case "ntilde": // LATIN SMALL LETTER N WITH TILDE + return rune(0xf1), true + case "ntlg": // NEITHER LESS-THAN NOR GREATER-THAN + return rune(0x2278), true + case "ntriangleleft": // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "ntrianglelefteq": // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "ntriangleright": // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "ntrianglerighteq": // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "nu": // GREEK SMALL LETTER NU + return rune(0x03bd), true + case "num": // NUMBER SIGN + return rune(0x23), true + case "numero": // NUMERO SIGN + return rune(0x2116), true + case "numsp": // FIGURE SPACE + return rune(0x2007), true + case "nvDash": // NOT TRUE + return rune(0x22ad), true + case "nvHarr": // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2904), true + case "nvap": // EQUIVALENT TO with vertical line + return rune(0x224d), true + case "nvbrtri": // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash + return rune(0x29d0), true + case "nvdash": // DOES NOT PROVE + return rune(0x22ac), true + case "nvge": // GREATER-THAN OR EQUAL TO with vertical line + return rune(0x2265), true + case "nvgt": // GREATER-THAN SIGN with vertical line + return rune(0x3e), true + case "nvinfin": // INFINITY NEGATED WITH VERTICAL BAR + return rune(0x29de), true + case "nvlArr": // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2902), true + case "nvle": // LESS-THAN OR EQUAL TO with vertical line + return rune(0x2264), true + case "nvlt": // LESS-THAN SIGN with vertical line + return rune(0x3c), true + case "nvltrie": // NORMAL SUBGROUP OF OR EQUAL TO with vertical line + return rune(0x22b4), true + case "nvrArr": // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2903), true + case "nvrtrie": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line + return rune(0x22b5), true + case "nvsim": // TILDE OPERATOR with vertical line + return rune(0x223c), true + case "nwArr": // NORTH WEST DOUBLE ARROW + return rune(0x21d6), true + case "nwarhk": // NORTH WEST ARROW WITH HOOK + return rune(0x2923), true + case "nwarr": // NORTH WEST ARROW + return rune(0x2196), true + case "nwarrow": // NORTH WEST ARROW + return rune(0x2196), true + case "nwnear": // NORTH WEST ARROW AND NORTH EAST ARROW + return rune(0x2927), true + case "nwonearr": // NORTH WEST ARROW CROSSING NORTH EAST ARROW + return rune(0x2932), true + case "nwsesarr": // NORTH WEST AND SOUTH EAST ARROW + return rune(0x2921), true } case 'o': switch name { - case "oS": // CIRCLED LATIN CAPITAL LETTER S - return rune(0x24c8), true - case "oacgr": // GREEK SMALL LETTER OMICRON WITH TONOS - return rune(0x03cc), true - case "oacute": // LATIN SMALL LETTER O WITH ACUTE - return rune(0xf3), true - case "oast": // CIRCLED ASTERISK OPERATOR - return rune(0x229b), true - case "obsol": // CIRCLED REVERSE SOLIDUS - return rune(0x29b8), true - case "ocir": // CIRCLED RING OPERATOR - return rune(0x229a), true - case "ocirc": // LATIN SMALL LETTER O WITH CIRCUMFLEX - return rune(0xf4), true - case "ocy": // CYRILLIC SMALL LETTER O - return rune(0x043e), true - case "odash": // CIRCLED DASH - return rune(0x229d), true - case "odblac": // LATIN SMALL LETTER O WITH DOUBLE ACUTE - return rune(0x0151), true - case "odiv": // CIRCLED DIVISION SIGN - return rune(0x2a38), true - case "odot": // CIRCLED DOT OPERATOR - return rune(0x2299), true - case "odsold": // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN - return rune(0x29bc), true - case "oelig": // LATIN SMALL LIGATURE OE - return rune(0x0153), true - case "ofcir": // CIRCLED BULLET - return rune(0x29bf), true - case "ofr": // MATHEMATICAL FRAKTUR SMALL O - return rune(0x01d52c), true - case "ogon": // OGONEK - return rune(0x02db), true - case "ogr": // GREEK SMALL LETTER OMICRON - return rune(0x03bf), true - case "ograve": // LATIN SMALL LETTER O WITH GRAVE - return rune(0xf2), true - case "ogt": // CIRCLED GREATER-THAN - return rune(0x29c1), true - case "ohacgr": // GREEK SMALL LETTER OMEGA WITH TONOS - return rune(0x03ce), true - case "ohbar": // CIRCLE WITH HORIZONTAL BAR - return rune(0x29b5), true - case "ohgr": // GREEK SMALL LETTER OMEGA - return rune(0x03c9), true - case "ohm": // GREEK CAPITAL LETTER OMEGA - return rune(0x03a9), true - case "oint": // CONTOUR INTEGRAL - return rune(0x222e), true - case "olarr": // ANTICLOCKWISE OPEN CIRCLE ARROW - return rune(0x21ba), true - case "olcir": // CIRCLED WHITE BULLET - return rune(0x29be), true - case "olcross": // CIRCLE WITH SUPERIMPOSED X - return rune(0x29bb), true - case "oline": // OVERLINE - return rune(0x203e), true - case "olt": // CIRCLED LESS-THAN - return rune(0x29c0), true - case "omacr": // LATIN SMALL LETTER O WITH MACRON - return rune(0x014d), true - case "omega": // GREEK SMALL LETTER OMEGA - return rune(0x03c9), true - case "omicron": // GREEK SMALL LETTER OMICRON - return rune(0x03bf), true - case "omid": // CIRCLED VERTICAL BAR - return rune(0x29b6), true - case "ominus": // CIRCLED MINUS - return rune(0x2296), true - case "oopf": // MATHEMATICAL DOUBLE-STRUCK SMALL O - return rune(0x01d560), true - case "opar": // CIRCLED PARALLEL - return rune(0x29b7), true - case "operp": // CIRCLED PERPENDICULAR - return rune(0x29b9), true - case "opfgamma": // DOUBLE-STRUCK SMALL GAMMA - return rune(0x213d), true - case "opfpi": // DOUBLE-STRUCK CAPITAL PI - return rune(0x213f), true - case "opfsum": // DOUBLE-STRUCK N-ARY SUMMATION - return rune(0x2140), true - case "oplus": // CIRCLED PLUS - return rune(0x2295), true - case "or": // LOGICAL OR - return rune(0x2228), true - case "orarr": // CLOCKWISE OPEN CIRCLE ARROW - return rune(0x21bb), true - case "ord": // LOGICAL OR WITH HORIZONTAL DASH - return rune(0x2a5d), true - case "order": // SCRIPT SMALL O - return rune(0x2134), true - case "orderof": // SCRIPT SMALL O - return rune(0x2134), true - case "ordf": // FEMININE ORDINAL INDICATOR - return rune(0xaa), true - case "ordm": // MASCULINE ORDINAL INDICATOR - return rune(0xba), true - case "origof": // ORIGINAL OF - return rune(0x22b6), true - case "oror": // TWO INTERSECTING LOGICAL OR - return rune(0x2a56), true - case "orslope": // SLOPING LARGE OR - return rune(0x2a57), true - case "orv": // LOGICAL OR WITH MIDDLE STEM - return rune(0x2a5b), true - case "oscr": // SCRIPT SMALL O - return rune(0x2134), true - case "oslash": // LATIN SMALL LETTER O WITH STROKE - return rune(0xf8), true - case "osol": // CIRCLED DIVISION SLASH - return rune(0x2298), true - case "otilde": // LATIN SMALL LETTER O WITH TILDE - return rune(0xf5), true - case "otimes": // CIRCLED TIMES - return rune(0x2297), true - case "otimesas": // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT - return rune(0x2a36), true - case "ouml": // LATIN SMALL LETTER O WITH DIAERESIS - return rune(0xf6), true - case "ovbar": // APL FUNCTIONAL SYMBOL CIRCLE STILE - return rune(0x233d), true - case "ovrbrk": // TOP SQUARE BRACKET - return rune(0x23b4), true - case "ovrcub": // TOP CURLY BRACKET - return rune(0x23de), true - case "ovrpar": // TOP PARENTHESIS - return rune(0x23dc), true - case "oxuarr": // UP ARROW THROUGH CIRCLE - return rune(0x29bd), true + case "oS": // CIRCLED LATIN CAPITAL LETTER S + return rune(0x24c8), true + case "oacgr": // GREEK SMALL LETTER OMICRON WITH TONOS + return rune(0x03cc), true + case "oacute": // LATIN SMALL LETTER O WITH ACUTE + return rune(0xf3), true + case "oast": // CIRCLED ASTERISK OPERATOR + return rune(0x229b), true + case "obsol": // CIRCLED REVERSE SOLIDUS + return rune(0x29b8), true + case "ocir": // CIRCLED RING OPERATOR + return rune(0x229a), true + case "ocirc": // LATIN SMALL LETTER O WITH CIRCUMFLEX + return rune(0xf4), true + case "ocy": // CYRILLIC SMALL LETTER O + return rune(0x043e), true + case "odash": // CIRCLED DASH + return rune(0x229d), true + case "odblac": // LATIN SMALL LETTER O WITH DOUBLE ACUTE + return rune(0x0151), true + case "odiv": // CIRCLED DIVISION SIGN + return rune(0x2a38), true + case "odot": // CIRCLED DOT OPERATOR + return rune(0x2299), true + case "odsold": // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN + return rune(0x29bc), true + case "oelig": // LATIN SMALL LIGATURE OE + return rune(0x0153), true + case "ofcir": // CIRCLED BULLET + return rune(0x29bf), true + case "ofr": // MATHEMATICAL FRAKTUR SMALL O + return rune(0x01d52c), true + case "ogon": // OGONEK + return rune(0x02db), true + case "ogr": // GREEK SMALL LETTER OMICRON + return rune(0x03bf), true + case "ograve": // LATIN SMALL LETTER O WITH GRAVE + return rune(0xf2), true + case "ogt": // CIRCLED GREATER-THAN + return rune(0x29c1), true + case "ohacgr": // GREEK SMALL LETTER OMEGA WITH TONOS + return rune(0x03ce), true + case "ohbar": // CIRCLE WITH HORIZONTAL BAR + return rune(0x29b5), true + case "ohgr": // GREEK SMALL LETTER OMEGA + return rune(0x03c9), true + case "ohm": // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "oint": // CONTOUR INTEGRAL + return rune(0x222e), true + case "olarr": // ANTICLOCKWISE OPEN CIRCLE ARROW + return rune(0x21ba), true + case "olcir": // CIRCLED WHITE BULLET + return rune(0x29be), true + case "olcross": // CIRCLE WITH SUPERIMPOSED X + return rune(0x29bb), true + case "oline": // OVERLINE + return rune(0x203e), true + case "olt": // CIRCLED LESS-THAN + return rune(0x29c0), true + case "omacr": // LATIN SMALL LETTER O WITH MACRON + return rune(0x014d), true + case "omega": // GREEK SMALL LETTER OMEGA + return rune(0x03c9), true + case "omicron": // GREEK SMALL LETTER OMICRON + return rune(0x03bf), true + case "omid": // CIRCLED VERTICAL BAR + return rune(0x29b6), true + case "ominus": // CIRCLED MINUS + return rune(0x2296), true + case "oopf": // MATHEMATICAL DOUBLE-STRUCK SMALL O + return rune(0x01d560), true + case "opar": // CIRCLED PARALLEL + return rune(0x29b7), true + case "operp": // CIRCLED PERPENDICULAR + return rune(0x29b9), true + case "opfgamma": // DOUBLE-STRUCK SMALL GAMMA + return rune(0x213d), true + case "opfpi": // DOUBLE-STRUCK CAPITAL PI + return rune(0x213f), true + case "opfsum": // DOUBLE-STRUCK N-ARY SUMMATION + return rune(0x2140), true + case "oplus": // CIRCLED PLUS + return rune(0x2295), true + case "or": // LOGICAL OR + return rune(0x2228), true + case "orarr": // CLOCKWISE OPEN CIRCLE ARROW + return rune(0x21bb), true + case "ord": // LOGICAL OR WITH HORIZONTAL DASH + return rune(0x2a5d), true + case "order": // SCRIPT SMALL O + return rune(0x2134), true + case "orderof": // SCRIPT SMALL O + return rune(0x2134), true + case "ordf": // FEMININE ORDINAL INDICATOR + return rune(0xaa), true + case "ordm": // MASCULINE ORDINAL INDICATOR + return rune(0xba), true + case "origof": // ORIGINAL OF + return rune(0x22b6), true + case "oror": // TWO INTERSECTING LOGICAL OR + return rune(0x2a56), true + case "orslope": // SLOPING LARGE OR + return rune(0x2a57), true + case "orv": // LOGICAL OR WITH MIDDLE STEM + return rune(0x2a5b), true + case "oscr": // SCRIPT SMALL O + return rune(0x2134), true + case "oslash": // LATIN SMALL LETTER O WITH STROKE + return rune(0xf8), true + case "osol": // CIRCLED DIVISION SLASH + return rune(0x2298), true + case "otilde": // LATIN SMALL LETTER O WITH TILDE + return rune(0xf5), true + case "otimes": // CIRCLED TIMES + return rune(0x2297), true + case "otimesas": // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT + return rune(0x2a36), true + case "ouml": // LATIN SMALL LETTER O WITH DIAERESIS + return rune(0xf6), true + case "ovbar": // APL FUNCTIONAL SYMBOL CIRCLE STILE + return rune(0x233d), true + case "ovrbrk": // TOP SQUARE BRACKET + return rune(0x23b4), true + case "ovrcub": // TOP CURLY BRACKET + return rune(0x23de), true + case "ovrpar": // TOP PARENTHESIS + return rune(0x23dc), true + case "oxuarr": // UP ARROW THROUGH CIRCLE + return rune(0x29bd), true } case 'p': switch name { - case "par": // PARALLEL TO - return rune(0x2225), true - case "para": // PILCROW SIGN - return rune(0xb6), true - case "parallel": // PARALLEL TO - return rune(0x2225), true - case "parsim": // PARALLEL WITH TILDE OPERATOR - return rune(0x2af3), true - case "parsl": // DOUBLE SOLIDUS OPERATOR - return rune(0x2afd), true - case "part": // PARTIAL DIFFERENTIAL - return rune(0x2202), true - case "pcy": // CYRILLIC SMALL LETTER PE - return rune(0x043f), true - case "percnt": // PERCENT SIGN - return rune(0x25), true - case "period": // FULL STOP - return rune(0x2e), true - case "permil": // PER MILLE SIGN - return rune(0x2030), true - case "perp": // UP TACK - return rune(0x22a5), true - case "pertenk": // PER TEN THOUSAND SIGN - return rune(0x2031), true - case "pfr": // MATHEMATICAL FRAKTUR SMALL P - return rune(0x01d52d), true - case "pgr": // GREEK SMALL LETTER PI - return rune(0x03c0), true - case "phgr": // GREEK SMALL LETTER PHI - return rune(0x03c6), true - case "phi": // GREEK SMALL LETTER PHI - return rune(0x03c6), true - case "phis": // GREEK PHI SYMBOL - return rune(0x03d5), true - case "phiv": // GREEK PHI SYMBOL - return rune(0x03d5), true - case "phmmat": // SCRIPT CAPITAL M - return rune(0x2133), true - case "phone": // BLACK TELEPHONE - return rune(0x260e), true - case "pi": // GREEK SMALL LETTER PI - return rune(0x03c0), true - case "pitchfork": // PITCHFORK - return rune(0x22d4), true - case "piv": // GREEK PI SYMBOL - return rune(0x03d6), true - case "planck": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true - case "planckh": // PLANCK CONSTANT - return rune(0x210e), true - case "plankv": // PLANCK CONSTANT OVER TWO PI - return rune(0x210f), true - case "plus": // PLUS SIGN - return rune(0x2b), true - case "plusacir": // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE - return rune(0x2a23), true - case "plusb": // SQUARED PLUS - return rune(0x229e), true - case "pluscir": // PLUS SIGN WITH SMALL CIRCLE ABOVE - return rune(0x2a22), true - case "plusdo": // DOT PLUS - return rune(0x2214), true - case "plusdu": // PLUS SIGN WITH DOT BELOW - return rune(0x2a25), true - case "pluse": // PLUS SIGN ABOVE EQUALS SIGN - return rune(0x2a72), true - case "plusmn": // PLUS-MINUS SIGN - return rune(0xb1), true - case "plussim": // PLUS SIGN WITH TILDE BELOW - return rune(0x2a26), true - case "plustrif": // PLUS SIGN WITH BLACK TRIANGLE - return rune(0x2a28), true - case "plustwo": // PLUS SIGN WITH SUBSCRIPT TWO - return rune(0x2a27), true - case "pm": // PLUS-MINUS SIGN - return rune(0xb1), true - case "pointint": // INTEGRAL AROUND A POINT OPERATOR - return rune(0x2a15), true - case "popf": // MATHEMATICAL DOUBLE-STRUCK SMALL P - return rune(0x01d561), true - case "pound": // POUND SIGN - return rune(0xa3), true - case "pr": // PRECEDES - return rune(0x227a), true - case "prE": // PRECEDES ABOVE EQUALS SIGN - return rune(0x2ab3), true - case "prap": // PRECEDES ABOVE ALMOST EQUAL TO - return rune(0x2ab7), true - case "prcue": // PRECEDES OR EQUAL TO - return rune(0x227c), true - case "pre": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2aaf), true - case "prec": // PRECEDES - return rune(0x227a), true - case "precapprox": // PRECEDES ABOVE ALMOST EQUAL TO - return rune(0x2ab7), true - case "preccurlyeq": // PRECEDES OR EQUAL TO - return rune(0x227c), true - case "preceq": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2aaf), true - case "precnapprox": // PRECEDES ABOVE NOT ALMOST EQUAL TO - return rune(0x2ab9), true - case "precneqq": // PRECEDES ABOVE NOT EQUAL TO - return rune(0x2ab5), true - case "precnsim": // PRECEDES BUT NOT EQUIVALENT TO - return rune(0x22e8), true - case "precsim": // PRECEDES OR EQUIVALENT TO - return rune(0x227e), true - case "prime": // PRIME - return rune(0x2032), true - case "primes": // DOUBLE-STRUCK CAPITAL P - return rune(0x2119), true - case "prnE": // PRECEDES ABOVE NOT EQUAL TO - return rune(0x2ab5), true - case "prnap": // PRECEDES ABOVE NOT ALMOST EQUAL TO - return rune(0x2ab9), true - case "prnsim": // PRECEDES BUT NOT EQUIVALENT TO - return rune(0x22e8), true - case "prod": // N-ARY PRODUCT - return rune(0x220f), true - case "profalar": // ALL AROUND-PROFILE - return rune(0x232e), true - case "profline": // ARC - return rune(0x2312), true - case "profsurf": // SEGMENT - return rune(0x2313), true - case "prop": // PROPORTIONAL TO - return rune(0x221d), true - case "propto": // PROPORTIONAL TO - return rune(0x221d), true - case "prsim": // PRECEDES OR EQUIVALENT TO - return rune(0x227e), true - case "prurel": // PRECEDES UNDER RELATION - return rune(0x22b0), true - case "pscr": // MATHEMATICAL SCRIPT SMALL P - return rune(0x01d4c5), true - case "psgr": // GREEK SMALL LETTER PSI - return rune(0x03c8), true - case "psi": // GREEK SMALL LETTER PSI - return rune(0x03c8), true - case "puncsp": // PUNCTUATION SPACE - return rune(0x2008), true + case "par": // PARALLEL TO + return rune(0x2225), true + case "para": // PILCROW SIGN + return rune(0xb6), true + case "parallel": // PARALLEL TO + return rune(0x2225), true + case "parsim": // PARALLEL WITH TILDE OPERATOR + return rune(0x2af3), true + case "parsl": // DOUBLE SOLIDUS OPERATOR + return rune(0x2afd), true + case "part": // PARTIAL DIFFERENTIAL + return rune(0x2202), true + case "pcy": // CYRILLIC SMALL LETTER PE + return rune(0x043f), true + case "percnt": // PERCENT SIGN + return rune(0x25), true + case "period": // FULL STOP + return rune(0x2e), true + case "permil": // PER MILLE SIGN + return rune(0x2030), true + case "perp": // UP TACK + return rune(0x22a5), true + case "pertenk": // PER TEN THOUSAND SIGN + return rune(0x2031), true + case "pfr": // MATHEMATICAL FRAKTUR SMALL P + return rune(0x01d52d), true + case "pgr": // GREEK SMALL LETTER PI + return rune(0x03c0), true + case "phgr": // GREEK SMALL LETTER PHI + return rune(0x03c6), true + case "phi": // GREEK SMALL LETTER PHI + return rune(0x03c6), true + case "phis": // GREEK PHI SYMBOL + return rune(0x03d5), true + case "phiv": // GREEK PHI SYMBOL + return rune(0x03d5), true + case "phmmat": // SCRIPT CAPITAL M + return rune(0x2133), true + case "phone": // BLACK TELEPHONE + return rune(0x260e), true + case "pi": // GREEK SMALL LETTER PI + return rune(0x03c0), true + case "pitchfork": // PITCHFORK + return rune(0x22d4), true + case "piv": // GREEK PI SYMBOL + return rune(0x03d6), true + case "planck": // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "planckh": // PLANCK CONSTANT + return rune(0x210e), true + case "plankv": // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "plus": // PLUS SIGN + return rune(0x2b), true + case "plusacir": // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE + return rune(0x2a23), true + case "plusb": // SQUARED PLUS + return rune(0x229e), true + case "pluscir": // PLUS SIGN WITH SMALL CIRCLE ABOVE + return rune(0x2a22), true + case "plusdo": // DOT PLUS + return rune(0x2214), true + case "plusdu": // PLUS SIGN WITH DOT BELOW + return rune(0x2a25), true + case "pluse": // PLUS SIGN ABOVE EQUALS SIGN + return rune(0x2a72), true + case "plusmn": // PLUS-MINUS SIGN + return rune(0xb1), true + case "plussim": // PLUS SIGN WITH TILDE BELOW + return rune(0x2a26), true + case "plustrif": // PLUS SIGN WITH BLACK TRIANGLE + return rune(0x2a28), true + case "plustwo": // PLUS SIGN WITH SUBSCRIPT TWO + return rune(0x2a27), true + case "pm": // PLUS-MINUS SIGN + return rune(0xb1), true + case "pointint": // INTEGRAL AROUND A POINT OPERATOR + return rune(0x2a15), true + case "popf": // MATHEMATICAL DOUBLE-STRUCK SMALL P + return rune(0x01d561), true + case "pound": // POUND SIGN + return rune(0xa3), true + case "pr": // PRECEDES + return rune(0x227a), true + case "prE": // PRECEDES ABOVE EQUALS SIGN + return rune(0x2ab3), true + case "prap": // PRECEDES ABOVE ALMOST EQUAL TO + return rune(0x2ab7), true + case "prcue": // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "pre": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "prec": // PRECEDES + return rune(0x227a), true + case "precapprox": // PRECEDES ABOVE ALMOST EQUAL TO + return rune(0x2ab7), true + case "preccurlyeq": // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "preceq": // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "precnapprox": // PRECEDES ABOVE NOT ALMOST EQUAL TO + return rune(0x2ab9), true + case "precneqq": // PRECEDES ABOVE NOT EQUAL TO + return rune(0x2ab5), true + case "precnsim": // PRECEDES BUT NOT EQUIVALENT TO + return rune(0x22e8), true + case "precsim": // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "prime": // PRIME + return rune(0x2032), true + case "primes": // DOUBLE-STRUCK CAPITAL P + return rune(0x2119), true + case "prnE": // PRECEDES ABOVE NOT EQUAL TO + return rune(0x2ab5), true + case "prnap": // PRECEDES ABOVE NOT ALMOST EQUAL TO + return rune(0x2ab9), true + case "prnsim": // PRECEDES BUT NOT EQUIVALENT TO + return rune(0x22e8), true + case "prod": // N-ARY PRODUCT + return rune(0x220f), true + case "profalar": // ALL AROUND-PROFILE + return rune(0x232e), true + case "profline": // ARC + return rune(0x2312), true + case "profsurf": // SEGMENT + return rune(0x2313), true + case "prop": // PROPORTIONAL TO + return rune(0x221d), true + case "propto": // PROPORTIONAL TO + return rune(0x221d), true + case "prsim": // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "prurel": // PRECEDES UNDER RELATION + return rune(0x22b0), true + case "pscr": // MATHEMATICAL SCRIPT SMALL P + return rune(0x01d4c5), true + case "psgr": // GREEK SMALL LETTER PSI + return rune(0x03c8), true + case "psi": // GREEK SMALL LETTER PSI + return rune(0x03c8), true + case "puncsp": // PUNCTUATION SPACE + return rune(0x2008), true } case 'q': switch name { - case "qfr": // MATHEMATICAL FRAKTUR SMALL Q - return rune(0x01d52e), true - case "qint": // QUADRUPLE INTEGRAL OPERATOR - return rune(0x2a0c), true - case "qopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Q - return rune(0x01d562), true - case "qprime": // QUADRUPLE PRIME - return rune(0x2057), true - case "qscr": // MATHEMATICAL SCRIPT SMALL Q - return rune(0x01d4c6), true - case "quaternions": // DOUBLE-STRUCK CAPITAL H - return rune(0x210d), true - case "quatint": // QUATERNION INTEGRAL OPERATOR - return rune(0x2a16), true - case "quest": // QUESTION MARK - return rune(0x3f), true - case "questeq": // QUESTIONED EQUAL TO - return rune(0x225f), true - case "quot": // QUOTATION MARK - return rune(0x22), true + case "qfr": // MATHEMATICAL FRAKTUR SMALL Q + return rune(0x01d52e), true + case "qint": // QUADRUPLE INTEGRAL OPERATOR + return rune(0x2a0c), true + case "qopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Q + return rune(0x01d562), true + case "qprime": // QUADRUPLE PRIME + return rune(0x2057), true + case "qscr": // MATHEMATICAL SCRIPT SMALL Q + return rune(0x01d4c6), true + case "quaternions": // DOUBLE-STRUCK CAPITAL H + return rune(0x210d), true + case "quatint": // QUATERNION INTEGRAL OPERATOR + return rune(0x2a16), true + case "quest": // QUESTION MARK + return rune(0x3f), true + case "questeq": // QUESTIONED EQUAL TO + return rune(0x225f), true + case "quot": // QUOTATION MARK + return rune(0x22), true } case 'r': switch name { - case "rAarr": // RIGHTWARDS TRIPLE ARROW - return rune(0x21db), true - case "rArr": // RIGHTWARDS DOUBLE ARROW - return rune(0x21d2), true - case "rAtail": // RIGHTWARDS DOUBLE ARROW-TAIL - return rune(0x291c), true - case "rBarr": // RIGHTWARDS TRIPLE DASH ARROW - return rune(0x290f), true - case "rHar": // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - return rune(0x2964), true - case "race": // REVERSED TILDE with underline - return rune(0x223d), true - case "racute": // LATIN SMALL LETTER R WITH ACUTE - return rune(0x0155), true - case "radic": // SQUARE ROOT - return rune(0x221a), true - case "raemptyv": // EMPTY SET WITH RIGHT ARROW ABOVE - return rune(0x29b3), true - case "rang": // MATHEMATICAL RIGHT ANGLE BRACKET - return rune(0x27e9), true - case "rangd": // RIGHT ANGLE BRACKET WITH DOT - return rune(0x2992), true - case "range": // REVERSED ANGLE WITH UNDERBAR - return rune(0x29a5), true - case "rangle": // MATHEMATICAL RIGHT ANGLE BRACKET - return rune(0x27e9), true - case "raquo": // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - return rune(0xbb), true - case "rarr": // RIGHTWARDS ARROW - return rune(0x2192), true - case "rarr2": // RIGHTWARDS PAIRED ARROWS - return rune(0x21c9), true - case "rarr3": // THREE RIGHTWARDS ARROWS - return rune(0x21f6), true - case "rarrap": // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO - return rune(0x2975), true - case "rarrb": // RIGHTWARDS ARROW TO BAR - return rune(0x21e5), true - case "rarrbfs": // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND - return rune(0x2920), true - case "rarrc": // WAVE ARROW POINTING DIRECTLY RIGHT - return rune(0x2933), true - case "rarrfs": // RIGHTWARDS ARROW TO BLACK DIAMOND - return rune(0x291e), true - case "rarrhk": // RIGHTWARDS ARROW WITH HOOK - return rune(0x21aa), true - case "rarrlp": // RIGHTWARDS ARROW WITH LOOP - return rune(0x21ac), true - case "rarrpl": // RIGHTWARDS ARROW WITH PLUS BELOW - return rune(0x2945), true - case "rarrsim": // RIGHTWARDS ARROW ABOVE TILDE OPERATOR - return rune(0x2974), true - case "rarrtl": // RIGHTWARDS ARROW WITH TAIL - return rune(0x21a3), true - case "rarrw": // RIGHTWARDS WAVE ARROW - return rune(0x219d), true - case "rarrx": // RIGHTWARDS ARROW THROUGH X - return rune(0x2947), true - case "ratail": // RIGHTWARDS ARROW-TAIL - return rune(0x291a), true - case "ratio": // RATIO - return rune(0x2236), true - case "rationals": // DOUBLE-STRUCK CAPITAL Q - return rune(0x211a), true - case "rbarr": // RIGHTWARDS DOUBLE DASH ARROW - return rune(0x290d), true - case "rbbrk": // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT - return rune(0x2773), true - case "rbrace": // RIGHT CURLY BRACKET - return rune(0x7d), true - case "rbrack": // RIGHT SQUARE BRACKET - return rune(0x5d), true - case "rbrke": // RIGHT SQUARE BRACKET WITH UNDERBAR - return rune(0x298c), true - case "rbrksld": // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - return rune(0x298e), true - case "rbrkslu": // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER - return rune(0x2990), true - case "rcaron": // LATIN SMALL LETTER R WITH CARON - return rune(0x0159), true - case "rcedil": // LATIN SMALL LETTER R WITH CEDILLA - return rune(0x0157), true - case "rceil": // RIGHT CEILING - return rune(0x2309), true - case "rcub": // RIGHT CURLY BRACKET - return rune(0x7d), true - case "rcy": // CYRILLIC SMALL LETTER ER - return rune(0x0440), true - case "rdca": // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS - return rune(0x2937), true - case "rdharb": // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR - return rune(0x2957), true - case "rdiag": // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT - return rune(0x2571), true - case "rdiofdi": // RISING DIAGONAL CROSSING FALLING DIAGONAL - return rune(0x292b), true - case "rdldhar": // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN - return rune(0x2969), true - case "rdosearr": // RISING DIAGONAL CROSSING SOUTH EAST ARROW - return rune(0x2930), true - case "rdquo": // RIGHT DOUBLE QUOTATION MARK - return rune(0x201d), true - case "rdquor": // RIGHT DOUBLE QUOTATION MARK - return rune(0x201d), true - case "rdsh": // DOWNWARDS ARROW WITH TIP RIGHTWARDS - return rune(0x21b3), true - case "real": // BLACK-LETTER CAPITAL R - return rune(0x211c), true - case "realine": // SCRIPT CAPITAL R - return rune(0x211b), true - case "realpart": // BLACK-LETTER CAPITAL R - return rune(0x211c), true - case "reals": // DOUBLE-STRUCK CAPITAL R - return rune(0x211d), true - case "rect": // WHITE RECTANGLE - return rune(0x25ad), true - case "reg": // REGISTERED SIGN - return rune(0xae), true - case "rfbowtie": // BOWTIE WITH RIGHT HALF BLACK - return rune(0x29d2), true - case "rfisht": // RIGHT FISH TAIL - return rune(0x297d), true - case "rfloor": // RIGHT FLOOR - return rune(0x230b), true - case "rfr": // MATHEMATICAL FRAKTUR SMALL R - return rune(0x01d52f), true - case "rftimes": // TIMES WITH RIGHT HALF BLACK - return rune(0x29d5), true - case "rgr": // GREEK SMALL LETTER RHO - return rune(0x03c1), true - case "rhard": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21c1), true - case "rharu": // RIGHTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21c0), true - case "rharul": // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - return rune(0x296c), true - case "rho": // GREEK SMALL LETTER RHO - return rune(0x03c1), true - case "rhov": // GREEK RHO SYMBOL - return rune(0x03f1), true - case "rightarrow": // RIGHTWARDS ARROW - return rune(0x2192), true - case "rightarrowtail": // RIGHTWARDS ARROW WITH TAIL - return rune(0x21a3), true - case "rightharpoondown": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - return rune(0x21c1), true - case "rightharpoonup": // RIGHTWARDS HARPOON WITH BARB UPWARDS - return rune(0x21c0), true - case "rightleftarrows": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true - case "rightleftharpoons": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true - case "rightrightarrows": // RIGHTWARDS PAIRED ARROWS - return rune(0x21c9), true - case "rightsquigarrow": // RIGHTWARDS WAVE ARROW - return rune(0x219d), true - case "rightthreetimes": // RIGHT SEMIDIRECT PRODUCT - return rune(0x22cc), true - case "rimply": // RIGHT DOUBLE ARROW WITH ROUNDED HEAD - return rune(0x2970), true - case "ring": // RING ABOVE - return rune(0x02da), true - case "risingdotseq": // IMAGE OF OR APPROXIMATELY EQUAL TO - return rune(0x2253), true - case "rlarr": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true - case "rlarr2": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - return rune(0x21c4), true - case "rlhar": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true - case "rlhar2": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - return rune(0x21cc), true - case "rlm": // RIGHT-TO-LEFT MARK - return rune(0x200f), true - case "rmoust": // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - return rune(0x23b1), true - case "rmoustache": // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - return rune(0x23b1), true - case "rnmid": // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH - return rune(0x2aee), true - case "roang": // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET - return rune(0x27ed), true - case "roarr": // RIGHTWARDS OPEN-HEADED ARROW - return rune(0x21fe), true - case "robrk": // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - return rune(0x27e7), true - case "rocub": // RIGHT WHITE CURLY BRACKET - return rune(0x2984), true - case "ropar": // RIGHT WHITE PARENTHESIS - return rune(0x2986), true - case "ropf": // MATHEMATICAL DOUBLE-STRUCK SMALL R - return rune(0x01d563), true - case "roplus": // PLUS SIGN IN RIGHT HALF CIRCLE - return rune(0x2a2e), true - case "rotimes": // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE - return rune(0x2a35), true - case "rpar": // RIGHT PARENTHESIS - return rune(0x29), true - case "rpargt": // RIGHT ARC GREATER-THAN BRACKET - return rune(0x2994), true - case "rppolint": // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE - return rune(0x2a12), true - case "rrarr": // RIGHTWARDS PAIRED ARROWS - return rune(0x21c9), true - case "rsaquo": // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - return rune(0x203a), true - case "rscr": // MATHEMATICAL SCRIPT SMALL R - return rune(0x01d4c7), true - case "rsh": // UPWARDS ARROW WITH TIP RIGHTWARDS - return rune(0x21b1), true - case "rsolbar": // REVERSE SOLIDUS WITH HORIZONTAL STROKE - return rune(0x29f7), true - case "rsqb": // RIGHT SQUARE BRACKET - return rune(0x5d), true - case "rsquo": // RIGHT SINGLE QUOTATION MARK - return rune(0x2019), true - case "rsquor": // RIGHT SINGLE QUOTATION MARK - return rune(0x2019), true - case "rthree": // RIGHT SEMIDIRECT PRODUCT - return rune(0x22cc), true - case "rtimes": // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT - return rune(0x22ca), true - case "rtri": // WHITE RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b9), true - case "rtrie": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - return rune(0x22b5), true - case "rtrif": // BLACK RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b8), true - case "rtriltri": // RIGHT TRIANGLE ABOVE LEFT TRIANGLE - return rune(0x29ce), true - case "ruharb": // RIGHTWARDS HARPOON WITH BARB UP TO BAR - return rune(0x2953), true - case "ruluhar": // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP - return rune(0x2968), true - case "rx": // PRESCRIPTION TAKE - return rune(0x211e), true + case "rAarr": // RIGHTWARDS TRIPLE ARROW + return rune(0x21db), true + case "rArr": // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "rAtail": // RIGHTWARDS DOUBLE ARROW-TAIL + return rune(0x291c), true + case "rBarr": // RIGHTWARDS TRIPLE DASH ARROW + return rune(0x290f), true + case "rHar": // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + return rune(0x2964), true + case "race": // REVERSED TILDE with underline + return rune(0x223d), true + case "racute": // LATIN SMALL LETTER R WITH ACUTE + return rune(0x0155), true + case "radic": // SQUARE ROOT + return rune(0x221a), true + case "raemptyv": // EMPTY SET WITH RIGHT ARROW ABOVE + return rune(0x29b3), true + case "rang": // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "rangd": // RIGHT ANGLE BRACKET WITH DOT + return rune(0x2992), true + case "range": // REVERSED ANGLE WITH UNDERBAR + return rune(0x29a5), true + case "rangle": // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "raquo": // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + return rune(0xbb), true + case "rarr": // RIGHTWARDS ARROW + return rune(0x2192), true + case "rarr2": // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rarr3": // THREE RIGHTWARDS ARROWS + return rune(0x21f6), true + case "rarrap": // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO + return rune(0x2975), true + case "rarrb": // RIGHTWARDS ARROW TO BAR + return rune(0x21e5), true + case "rarrbfs": // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND + return rune(0x2920), true + case "rarrc": // WAVE ARROW POINTING DIRECTLY RIGHT + return rune(0x2933), true + case "rarrfs": // RIGHTWARDS ARROW TO BLACK DIAMOND + return rune(0x291e), true + case "rarrhk": // RIGHTWARDS ARROW WITH HOOK + return rune(0x21aa), true + case "rarrlp": // RIGHTWARDS ARROW WITH LOOP + return rune(0x21ac), true + case "rarrpl": // RIGHTWARDS ARROW WITH PLUS BELOW + return rune(0x2945), true + case "rarrsim": // RIGHTWARDS ARROW ABOVE TILDE OPERATOR + return rune(0x2974), true + case "rarrtl": // RIGHTWARDS ARROW WITH TAIL + return rune(0x21a3), true + case "rarrw": // RIGHTWARDS WAVE ARROW + return rune(0x219d), true + case "rarrx": // RIGHTWARDS ARROW THROUGH X + return rune(0x2947), true + case "ratail": // RIGHTWARDS ARROW-TAIL + return rune(0x291a), true + case "ratio": // RATIO + return rune(0x2236), true + case "rationals": // DOUBLE-STRUCK CAPITAL Q + return rune(0x211a), true + case "rbarr": // RIGHTWARDS DOUBLE DASH ARROW + return rune(0x290d), true + case "rbbrk": // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + return rune(0x2773), true + case "rbrace": // RIGHT CURLY BRACKET + return rune(0x7d), true + case "rbrack": // RIGHT SQUARE BRACKET + return rune(0x5d), true + case "rbrke": // RIGHT SQUARE BRACKET WITH UNDERBAR + return rune(0x298c), true + case "rbrksld": // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + return rune(0x298e), true + case "rbrkslu": // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER + return rune(0x2990), true + case "rcaron": // LATIN SMALL LETTER R WITH CARON + return rune(0x0159), true + case "rcedil": // LATIN SMALL LETTER R WITH CEDILLA + return rune(0x0157), true + case "rceil": // RIGHT CEILING + return rune(0x2309), true + case "rcub": // RIGHT CURLY BRACKET + return rune(0x7d), true + case "rcy": // CYRILLIC SMALL LETTER ER + return rune(0x0440), true + case "rdca": // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS + return rune(0x2937), true + case "rdharb": // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2957), true + case "rdiag": // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + return rune(0x2571), true + case "rdiofdi": // RISING DIAGONAL CROSSING FALLING DIAGONAL + return rune(0x292b), true + case "rdldhar": // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN + return rune(0x2969), true + case "rdosearr": // RISING DIAGONAL CROSSING SOUTH EAST ARROW + return rune(0x2930), true + case "rdquo": // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "rdquor": // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "rdsh": // DOWNWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b3), true + case "real": // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "realine": // SCRIPT CAPITAL R + return rune(0x211b), true + case "realpart": // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "reals": // DOUBLE-STRUCK CAPITAL R + return rune(0x211d), true + case "rect": // WHITE RECTANGLE + return rune(0x25ad), true + case "reg": // REGISTERED SIGN + return rune(0xae), true + case "rfbowtie": // BOWTIE WITH RIGHT HALF BLACK + return rune(0x29d2), true + case "rfisht": // RIGHT FISH TAIL + return rune(0x297d), true + case "rfloor": // RIGHT FLOOR + return rune(0x230b), true + case "rfr": // MATHEMATICAL FRAKTUR SMALL R + return rune(0x01d52f), true + case "rftimes": // TIMES WITH RIGHT HALF BLACK + return rune(0x29d5), true + case "rgr": // GREEK SMALL LETTER RHO + return rune(0x03c1), true + case "rhard": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "rharu": // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "rharul": // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + return rune(0x296c), true + case "rho": // GREEK SMALL LETTER RHO + return rune(0x03c1), true + case "rhov": // GREEK RHO SYMBOL + return rune(0x03f1), true + case "rightarrow": // RIGHTWARDS ARROW + return rune(0x2192), true + case "rightarrowtail": // RIGHTWARDS ARROW WITH TAIL + return rune(0x21a3), true + case "rightharpoondown": // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "rightharpoonup": // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "rightleftarrows": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rightleftharpoons": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rightrightarrows": // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rightsquigarrow": // RIGHTWARDS WAVE ARROW + return rune(0x219d), true + case "rightthreetimes": // RIGHT SEMIDIRECT PRODUCT + return rune(0x22cc), true + case "rimply": // RIGHT DOUBLE ARROW WITH ROUNDED HEAD + return rune(0x2970), true + case "ring": // RING ABOVE + return rune(0x02da), true + case "risingdotseq": // IMAGE OF OR APPROXIMATELY EQUAL TO + return rune(0x2253), true + case "rlarr": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rlarr2": // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rlhar": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rlhar2": // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rlm": // RIGHT-TO-LEFT MARK + return rune(0x200f), true + case "rmoust": // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION + return rune(0x23b1), true + case "rmoustache": // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION + return rune(0x23b1), true + case "rnmid": // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH + return rune(0x2aee), true + case "roang": // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET + return rune(0x27ed), true + case "roarr": // RIGHTWARDS OPEN-HEADED ARROW + return rune(0x21fe), true + case "robrk": // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + return rune(0x27e7), true + case "rocub": // RIGHT WHITE CURLY BRACKET + return rune(0x2984), true + case "ropar": // RIGHT WHITE PARENTHESIS + return rune(0x2986), true + case "ropf": // MATHEMATICAL DOUBLE-STRUCK SMALL R + return rune(0x01d563), true + case "roplus": // PLUS SIGN IN RIGHT HALF CIRCLE + return rune(0x2a2e), true + case "rotimes": // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE + return rune(0x2a35), true + case "rpar": // RIGHT PARENTHESIS + return rune(0x29), true + case "rpargt": // RIGHT ARC GREATER-THAN BRACKET + return rune(0x2994), true + case "rppolint": // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE + return rune(0x2a12), true + case "rrarr": // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rsaquo": // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + return rune(0x203a), true + case "rscr": // MATHEMATICAL SCRIPT SMALL R + return rune(0x01d4c7), true + case "rsh": // UPWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b1), true + case "rsolbar": // REVERSE SOLIDUS WITH HORIZONTAL STROKE + return rune(0x29f7), true + case "rsqb": // RIGHT SQUARE BRACKET + return rune(0x5d), true + case "rsquo": // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "rsquor": // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "rthree": // RIGHT SEMIDIRECT PRODUCT + return rune(0x22cc), true + case "rtimes": // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + return rune(0x22ca), true + case "rtri": // WHITE RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b9), true + case "rtrie": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "rtrif": // BLACK RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b8), true + case "rtriltri": // RIGHT TRIANGLE ABOVE LEFT TRIANGLE + return rune(0x29ce), true + case "ruharb": // RIGHTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2953), true + case "ruluhar": // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP + return rune(0x2968), true + case "rx": // PRESCRIPTION TAKE + return rune(0x211e), true } case 's': switch name { - case "sacute": // LATIN SMALL LETTER S WITH ACUTE - return rune(0x015b), true - case "samalg": // N-ARY COPRODUCT - return rune(0x2210), true - case "sampi": // GREEK LETTER SAMPI - return rune(0x03e0), true - case "sbquo": // SINGLE LOW-9 QUOTATION MARK - return rune(0x201a), true - case "sbsol": // SMALL REVERSE SOLIDUS - return rune(0xfe68), true - case "sc": // SUCCEEDS - return rune(0x227b), true - case "scE": // SUCCEEDS ABOVE EQUALS SIGN - return rune(0x2ab4), true - case "scap": // SUCCEEDS ABOVE ALMOST EQUAL TO - return rune(0x2ab8), true - case "scaron": // LATIN SMALL LETTER S WITH CARON - return rune(0x0161), true - case "sccue": // SUCCEEDS OR EQUAL TO - return rune(0x227d), true - case "sce": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2ab0), true - case "scedil": // LATIN SMALL LETTER S WITH CEDILLA - return rune(0x015f), true - case "scirc": // LATIN SMALL LETTER S WITH CIRCUMFLEX - return rune(0x015d), true - case "scnE": // SUCCEEDS ABOVE NOT EQUAL TO - return rune(0x2ab6), true - case "scnap": // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - return rune(0x2aba), true - case "scnsim": // SUCCEEDS BUT NOT EQUIVALENT TO - return rune(0x22e9), true - case "scpolint": // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE - return rune(0x2a13), true - case "scsim": // SUCCEEDS OR EQUIVALENT TO - return rune(0x227f), true - case "scy": // CYRILLIC SMALL LETTER ES - return rune(0x0441), true - case "sdot": // DOT OPERATOR - return rune(0x22c5), true - case "sdotb": // SQUARED DOT OPERATOR - return rune(0x22a1), true - case "sdote": // EQUALS SIGN WITH DOT BELOW - return rune(0x2a66), true - case "seArr": // SOUTH EAST DOUBLE ARROW - return rune(0x21d8), true - case "searhk": // SOUTH EAST ARROW WITH HOOK - return rune(0x2925), true - case "searr": // SOUTH EAST ARROW - return rune(0x2198), true - case "searrow": // SOUTH EAST ARROW - return rune(0x2198), true - case "sect": // SECTION SIGN - return rune(0xa7), true - case "semi": // SEMICOLON - return rune(0x3b), true - case "seonearr": // SOUTH EAST ARROW CROSSING NORTH EAST ARROW - return rune(0x292d), true - case "seswar": // SOUTH EAST ARROW AND SOUTH WEST ARROW - return rune(0x2929), true - case "setminus": // SET MINUS - return rune(0x2216), true - case "setmn": // SET MINUS - return rune(0x2216), true - case "sext": // SIX POINTED BLACK STAR - return rune(0x2736), true - case "sfgr": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true - case "sfr": // MATHEMATICAL FRAKTUR SMALL S - return rune(0x01d530), true - case "sfrown": // FROWN - return rune(0x2322), true - case "sgr": // GREEK SMALL LETTER SIGMA - return rune(0x03c3), true - case "sharp": // MUSIC SHARP SIGN - return rune(0x266f), true - case "shchcy": // CYRILLIC SMALL LETTER SHCHA - return rune(0x0449), true - case "shcy": // CYRILLIC SMALL LETTER SHA - return rune(0x0448), true - case "shortmid": // DIVIDES - return rune(0x2223), true - case "shortparallel": // PARALLEL TO - return rune(0x2225), true - case "shuffle": // SHUFFLE PRODUCT - return rune(0x29e2), true - case "shy": // SOFT HYPHEN - return rune(0xad), true - case "sigma": // GREEK SMALL LETTER SIGMA - return rune(0x03c3), true - case "sigmaf": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true - case "sigmav": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true - case "sim": // TILDE OPERATOR - return rune(0x223c), true - case "simdot": // TILDE OPERATOR WITH DOT ABOVE - return rune(0x2a6a), true - case "sime": // ASYMPTOTICALLY EQUAL TO - return rune(0x2243), true - case "simeq": // ASYMPTOTICALLY EQUAL TO - return rune(0x2243), true - case "simg": // SIMILAR OR GREATER-THAN - return rune(0x2a9e), true - case "simgE": // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN - return rune(0x2aa0), true - case "siml": // SIMILAR OR LESS-THAN - return rune(0x2a9d), true - case "simlE": // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN - return rune(0x2a9f), true - case "simne": // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO - return rune(0x2246), true - case "simplus": // PLUS SIGN WITH TILDE ABOVE - return rune(0x2a24), true - case "simrarr": // TILDE OPERATOR ABOVE RIGHTWARDS ARROW - return rune(0x2972), true - case "slarr": // LEFTWARDS ARROW - return rune(0x2190), true - case "slint": // INTEGRAL AVERAGE WITH SLASH - return rune(0x2a0f), true - case "smallsetminus": // SET MINUS - return rune(0x2216), true - case "smashp": // SMASH PRODUCT - return rune(0x2a33), true - case "smeparsl": // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE - return rune(0x29e4), true - case "smid": // DIVIDES - return rune(0x2223), true - case "smile": // SMILE - return rune(0x2323), true - case "smt": // SMALLER THAN - return rune(0x2aaa), true - case "smte": // SMALLER THAN OR EQUAL TO - return rune(0x2aac), true - case "smtes": // SMALLER THAN OR slanted EQUAL - return rune(0x2aac), true - case "softcy": // CYRILLIC SMALL LETTER SOFT SIGN - return rune(0x044c), true - case "sol": // SOLIDUS - return rune(0x2f), true - case "solb": // SQUARED RISING DIAGONAL SLASH - return rune(0x29c4), true - case "solbar": // APL FUNCTIONAL SYMBOL SLASH BAR - return rune(0x233f), true - case "sopf": // MATHEMATICAL DOUBLE-STRUCK SMALL S - return rune(0x01d564), true - case "spades": // BLACK SPADE SUIT - return rune(0x2660), true - case "spadesuit": // BLACK SPADE SUIT - return rune(0x2660), true - case "spar": // PARALLEL TO - return rune(0x2225), true - case "sqcap": // SQUARE CAP - return rune(0x2293), true - case "sqcaps": // SQUARE CAP with serifs - return rune(0x2293), true - case "sqcup": // SQUARE CUP - return rune(0x2294), true - case "sqcups": // SQUARE CUP with serifs - return rune(0x2294), true - case "sqsub": // SQUARE IMAGE OF - return rune(0x228f), true - case "sqsube": // SQUARE IMAGE OF OR EQUAL TO - return rune(0x2291), true - case "sqsubset": // SQUARE IMAGE OF - return rune(0x228f), true - case "sqsubseteq": // SQUARE IMAGE OF OR EQUAL TO - return rune(0x2291), true - case "sqsup": // SQUARE ORIGINAL OF - return rune(0x2290), true - case "sqsupe": // SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x2292), true - case "sqsupset": // SQUARE ORIGINAL OF - return rune(0x2290), true - case "sqsupseteq": // SQUARE ORIGINAL OF OR EQUAL TO - return rune(0x2292), true - case "squ": // WHITE SQUARE - return rune(0x25a1), true - case "square": // WHITE SQUARE - return rune(0x25a1), true - case "squarf": // BLACK SMALL SQUARE - return rune(0x25aa), true - case "squb": // SQUARED SQUARE - return rune(0x29c8), true - case "squerr": // ERROR-BARRED WHITE SQUARE - return rune(0x29ee), true - case "squf": // BLACK SMALL SQUARE - return rune(0x25aa), true - case "squferr": // ERROR-BARRED BLACK SQUARE - return rune(0x29ef), true - case "srarr": // RIGHTWARDS ARROW - return rune(0x2192), true - case "sscr": // MATHEMATICAL SCRIPT SMALL S - return rune(0x01d4c8), true - case "ssetmn": // SET MINUS - return rune(0x2216), true - case "ssmile": // SMILE - return rune(0x2323), true - case "sstarf": // STAR OPERATOR - return rune(0x22c6), true - case "star": // WHITE STAR - return rune(0x2606), true - case "starf": // BLACK STAR - return rune(0x2605), true - case "stigma": // GREEK LETTER STIGMA - return rune(0x03da), true - case "straightepsilon": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true - case "straightphi": // GREEK PHI SYMBOL - return rune(0x03d5), true - case "strns": // MACRON - return rune(0xaf), true - case "sub": // SUBSET OF - return rune(0x2282), true - case "subE": // SUBSET OF ABOVE EQUALS SIGN - return rune(0x2ac5), true - case "subdot": // SUBSET WITH DOT - return rune(0x2abd), true - case "sube": // SUBSET OF OR EQUAL TO - return rune(0x2286), true - case "subedot": // SUBSET OF OR EQUAL TO WITH DOT ABOVE - return rune(0x2ac3), true - case "submult": // SUBSET WITH MULTIPLICATION SIGN BELOW - return rune(0x2ac1), true - case "subnE": // SUBSET OF ABOVE NOT EQUAL TO - return rune(0x2acb), true - case "subne": // SUBSET OF WITH NOT EQUAL TO - return rune(0x228a), true - case "subplus": // SUBSET WITH PLUS SIGN BELOW - return rune(0x2abf), true - case "subrarr": // SUBSET ABOVE RIGHTWARDS ARROW - return rune(0x2979), true - case "subset": // SUBSET OF - return rune(0x2282), true - case "subseteq": // SUBSET OF OR EQUAL TO - return rune(0x2286), true - case "subseteqq": // SUBSET OF ABOVE EQUALS SIGN - return rune(0x2ac5), true - case "subsetneq": // SUBSET OF WITH NOT EQUAL TO - return rune(0x228a), true - case "subsetneqq": // SUBSET OF ABOVE NOT EQUAL TO - return rune(0x2acb), true - case "subsim": // SUBSET OF ABOVE TILDE OPERATOR - return rune(0x2ac7), true - case "subsub": // SUBSET ABOVE SUBSET - return rune(0x2ad5), true - case "subsup": // SUBSET ABOVE SUPERSET - return rune(0x2ad3), true - case "succ": // SUCCEEDS - return rune(0x227b), true - case "succapprox": // SUCCEEDS ABOVE ALMOST EQUAL TO - return rune(0x2ab8), true - case "succcurlyeq": // SUCCEEDS OR EQUAL TO - return rune(0x227d), true - case "succeq": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - return rune(0x2ab0), true - case "succnapprox": // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - return rune(0x2aba), true - case "succneqq": // SUCCEEDS ABOVE NOT EQUAL TO - return rune(0x2ab6), true - case "succnsim": // SUCCEEDS BUT NOT EQUIVALENT TO - return rune(0x22e9), true - case "succsim": // SUCCEEDS OR EQUIVALENT TO - return rune(0x227f), true - case "sum": // N-ARY SUMMATION - return rune(0x2211), true - case "sumint": // SUMMATION WITH INTEGRAL - return rune(0x2a0b), true - case "sung": // EIGHTH NOTE - return rune(0x266a), true - case "sup": // SUPERSET OF - return rune(0x2283), true - case "sup1": // SUPERSCRIPT ONE - return rune(0xb9), true - case "sup2": // SUPERSCRIPT TWO - return rune(0xb2), true - case "sup3": // SUPERSCRIPT THREE - return rune(0xb3), true - case "supE": // SUPERSET OF ABOVE EQUALS SIGN - return rune(0x2ac6), true - case "supdot": // SUPERSET WITH DOT - return rune(0x2abe), true - case "supdsub": // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET - return rune(0x2ad8), true - case "supe": // SUPERSET OF OR EQUAL TO - return rune(0x2287), true - case "supedot": // SUPERSET OF OR EQUAL TO WITH DOT ABOVE - return rune(0x2ac4), true - case "suphsol": // SUPERSET PRECEDING SOLIDUS - return rune(0x27c9), true - case "suphsub": // SUPERSET BESIDE SUBSET - return rune(0x2ad7), true - case "suplarr": // SUPERSET ABOVE LEFTWARDS ARROW - return rune(0x297b), true - case "supmult": // SUPERSET WITH MULTIPLICATION SIGN BELOW - return rune(0x2ac2), true - case "supnE": // SUPERSET OF ABOVE NOT EQUAL TO - return rune(0x2acc), true - case "supne": // SUPERSET OF WITH NOT EQUAL TO - return rune(0x228b), true - case "supplus": // SUPERSET WITH PLUS SIGN BELOW - return rune(0x2ac0), true - case "supset": // SUPERSET OF - return rune(0x2283), true - case "supseteq": // SUPERSET OF OR EQUAL TO - return rune(0x2287), true - case "supseteqq": // SUPERSET OF ABOVE EQUALS SIGN - return rune(0x2ac6), true - case "supsetneq": // SUPERSET OF WITH NOT EQUAL TO - return rune(0x228b), true - case "supsetneqq": // SUPERSET OF ABOVE NOT EQUAL TO - return rune(0x2acc), true - case "supsim": // SUPERSET OF ABOVE TILDE OPERATOR - return rune(0x2ac8), true - case "supsub": // SUPERSET ABOVE SUBSET - return rune(0x2ad4), true - case "supsup": // SUPERSET ABOVE SUPERSET - return rune(0x2ad6), true - case "swArr": // SOUTH WEST DOUBLE ARROW - return rune(0x21d9), true - case "swarhk": // SOUTH WEST ARROW WITH HOOK - return rune(0x2926), true - case "swarr": // SOUTH WEST ARROW - return rune(0x2199), true - case "swarrow": // SOUTH WEST ARROW - return rune(0x2199), true - case "swnwar": // SOUTH WEST ARROW AND NORTH WEST ARROW - return rune(0x292a), true - case "szlig": // LATIN SMALL LETTER SHARP S - return rune(0xdf), true + case "sacute": // LATIN SMALL LETTER S WITH ACUTE + return rune(0x015b), true + case "samalg": // N-ARY COPRODUCT + return rune(0x2210), true + case "sampi": // GREEK LETTER SAMPI + return rune(0x03e0), true + case "sbquo": // SINGLE LOW-9 QUOTATION MARK + return rune(0x201a), true + case "sbsol": // SMALL REVERSE SOLIDUS + return rune(0xfe68), true + case "sc": // SUCCEEDS + return rune(0x227b), true + case "scE": // SUCCEEDS ABOVE EQUALS SIGN + return rune(0x2ab4), true + case "scap": // SUCCEEDS ABOVE ALMOST EQUAL TO + return rune(0x2ab8), true + case "scaron": // LATIN SMALL LETTER S WITH CARON + return rune(0x0161), true + case "sccue": // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "sce": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "scedil": // LATIN SMALL LETTER S WITH CEDILLA + return rune(0x015f), true + case "scirc": // LATIN SMALL LETTER S WITH CIRCUMFLEX + return rune(0x015d), true + case "scnE": // SUCCEEDS ABOVE NOT EQUAL TO + return rune(0x2ab6), true + case "scnap": // SUCCEEDS ABOVE NOT ALMOST EQUAL TO + return rune(0x2aba), true + case "scnsim": // SUCCEEDS BUT NOT EQUIVALENT TO + return rune(0x22e9), true + case "scpolint": // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE + return rune(0x2a13), true + case "scsim": // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "scy": // CYRILLIC SMALL LETTER ES + return rune(0x0441), true + case "sdot": // DOT OPERATOR + return rune(0x22c5), true + case "sdotb": // SQUARED DOT OPERATOR + return rune(0x22a1), true + case "sdote": // EQUALS SIGN WITH DOT BELOW + return rune(0x2a66), true + case "seArr": // SOUTH EAST DOUBLE ARROW + return rune(0x21d8), true + case "searhk": // SOUTH EAST ARROW WITH HOOK + return rune(0x2925), true + case "searr": // SOUTH EAST ARROW + return rune(0x2198), true + case "searrow": // SOUTH EAST ARROW + return rune(0x2198), true + case "sect": // SECTION SIGN + return rune(0xa7), true + case "semi": // SEMICOLON + return rune(0x3b), true + case "seonearr": // SOUTH EAST ARROW CROSSING NORTH EAST ARROW + return rune(0x292d), true + case "seswar": // SOUTH EAST ARROW AND SOUTH WEST ARROW + return rune(0x2929), true + case "setminus": // SET MINUS + return rune(0x2216), true + case "setmn": // SET MINUS + return rune(0x2216), true + case "sext": // SIX POINTED BLACK STAR + return rune(0x2736), true + case "sfgr": // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sfr": // MATHEMATICAL FRAKTUR SMALL S + return rune(0x01d530), true + case "sfrown": // FROWN + return rune(0x2322), true + case "sgr": // GREEK SMALL LETTER SIGMA + return rune(0x03c3), true + case "sharp": // MUSIC SHARP SIGN + return rune(0x266f), true + case "shchcy": // CYRILLIC SMALL LETTER SHCHA + return rune(0x0449), true + case "shcy": // CYRILLIC SMALL LETTER SHA + return rune(0x0448), true + case "shortmid": // DIVIDES + return rune(0x2223), true + case "shortparallel": // PARALLEL TO + return rune(0x2225), true + case "shuffle": // SHUFFLE PRODUCT + return rune(0x29e2), true + case "shy": // SOFT HYPHEN + return rune(0xad), true + case "sigma": // GREEK SMALL LETTER SIGMA + return rune(0x03c3), true + case "sigmaf": // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sigmav": // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sim": // TILDE OPERATOR + return rune(0x223c), true + case "simdot": // TILDE OPERATOR WITH DOT ABOVE + return rune(0x2a6a), true + case "sime": // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "simeq": // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "simg": // SIMILAR OR GREATER-THAN + return rune(0x2a9e), true + case "simgE": // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN + return rune(0x2aa0), true + case "siml": // SIMILAR OR LESS-THAN + return rune(0x2a9d), true + case "simlE": // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN + return rune(0x2a9f), true + case "simne": // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO + return rune(0x2246), true + case "simplus": // PLUS SIGN WITH TILDE ABOVE + return rune(0x2a24), true + case "simrarr": // TILDE OPERATOR ABOVE RIGHTWARDS ARROW + return rune(0x2972), true + case "slarr": // LEFTWARDS ARROW + return rune(0x2190), true + case "slint": // INTEGRAL AVERAGE WITH SLASH + return rune(0x2a0f), true + case "smallsetminus": // SET MINUS + return rune(0x2216), true + case "smashp": // SMASH PRODUCT + return rune(0x2a33), true + case "smeparsl": // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE + return rune(0x29e4), true + case "smid": // DIVIDES + return rune(0x2223), true + case "smile": // SMILE + return rune(0x2323), true + case "smt": // SMALLER THAN + return rune(0x2aaa), true + case "smte": // SMALLER THAN OR EQUAL TO + return rune(0x2aac), true + case "smtes": // SMALLER THAN OR slanted EQUAL + return rune(0x2aac), true + case "softcy": // CYRILLIC SMALL LETTER SOFT SIGN + return rune(0x044c), true + case "sol": // SOLIDUS + return rune(0x2f), true + case "solb": // SQUARED RISING DIAGONAL SLASH + return rune(0x29c4), true + case "solbar": // APL FUNCTIONAL SYMBOL SLASH BAR + return rune(0x233f), true + case "sopf": // MATHEMATICAL DOUBLE-STRUCK SMALL S + return rune(0x01d564), true + case "spades": // BLACK SPADE SUIT + return rune(0x2660), true + case "spadesuit": // BLACK SPADE SUIT + return rune(0x2660), true + case "spar": // PARALLEL TO + return rune(0x2225), true + case "sqcap": // SQUARE CAP + return rune(0x2293), true + case "sqcaps": // SQUARE CAP with serifs + return rune(0x2293), true + case "sqcup": // SQUARE CUP + return rune(0x2294), true + case "sqcups": // SQUARE CUP with serifs + return rune(0x2294), true + case "sqsub": // SQUARE IMAGE OF + return rune(0x228f), true + case "sqsube": // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "sqsubset": // SQUARE IMAGE OF + return rune(0x228f), true + case "sqsubseteq": // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "sqsup": // SQUARE ORIGINAL OF + return rune(0x2290), true + case "sqsupe": // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "sqsupset": // SQUARE ORIGINAL OF + return rune(0x2290), true + case "sqsupseteq": // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "squ": // WHITE SQUARE + return rune(0x25a1), true + case "square": // WHITE SQUARE + return rune(0x25a1), true + case "squarf": // BLACK SMALL SQUARE + return rune(0x25aa), true + case "squb": // SQUARED SQUARE + return rune(0x29c8), true + case "squerr": // ERROR-BARRED WHITE SQUARE + return rune(0x29ee), true + case "squf": // BLACK SMALL SQUARE + return rune(0x25aa), true + case "squferr": // ERROR-BARRED BLACK SQUARE + return rune(0x29ef), true + case "srarr": // RIGHTWARDS ARROW + return rune(0x2192), true + case "sscr": // MATHEMATICAL SCRIPT SMALL S + return rune(0x01d4c8), true + case "ssetmn": // SET MINUS + return rune(0x2216), true + case "ssmile": // SMILE + return rune(0x2323), true + case "sstarf": // STAR OPERATOR + return rune(0x22c6), true + case "star": // WHITE STAR + return rune(0x2606), true + case "starf": // BLACK STAR + return rune(0x2605), true + case "stigma": // GREEK LETTER STIGMA + return rune(0x03da), true + case "straightepsilon": // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "straightphi": // GREEK PHI SYMBOL + return rune(0x03d5), true + case "strns": // MACRON + return rune(0xaf), true + case "sub": // SUBSET OF + return rune(0x2282), true + case "subE": // SUBSET OF ABOVE EQUALS SIGN + return rune(0x2ac5), true + case "subdot": // SUBSET WITH DOT + return rune(0x2abd), true + case "sube": // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "subedot": // SUBSET OF OR EQUAL TO WITH DOT ABOVE + return rune(0x2ac3), true + case "submult": // SUBSET WITH MULTIPLICATION SIGN BELOW + return rune(0x2ac1), true + case "subnE": // SUBSET OF ABOVE NOT EQUAL TO + return rune(0x2acb), true + case "subne": // SUBSET OF WITH NOT EQUAL TO + return rune(0x228a), true + case "subplus": // SUBSET WITH PLUS SIGN BELOW + return rune(0x2abf), true + case "subrarr": // SUBSET ABOVE RIGHTWARDS ARROW + return rune(0x2979), true + case "subset": // SUBSET OF + return rune(0x2282), true + case "subseteq": // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "subseteqq": // SUBSET OF ABOVE EQUALS SIGN + return rune(0x2ac5), true + case "subsetneq": // SUBSET OF WITH NOT EQUAL TO + return rune(0x228a), true + case "subsetneqq": // SUBSET OF ABOVE NOT EQUAL TO + return rune(0x2acb), true + case "subsim": // SUBSET OF ABOVE TILDE OPERATOR + return rune(0x2ac7), true + case "subsub": // SUBSET ABOVE SUBSET + return rune(0x2ad5), true + case "subsup": // SUBSET ABOVE SUPERSET + return rune(0x2ad3), true + case "succ": // SUCCEEDS + return rune(0x227b), true + case "succapprox": // SUCCEEDS ABOVE ALMOST EQUAL TO + return rune(0x2ab8), true + case "succcurlyeq": // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "succeq": // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "succnapprox": // SUCCEEDS ABOVE NOT ALMOST EQUAL TO + return rune(0x2aba), true + case "succneqq": // SUCCEEDS ABOVE NOT EQUAL TO + return rune(0x2ab6), true + case "succnsim": // SUCCEEDS BUT NOT EQUIVALENT TO + return rune(0x22e9), true + case "succsim": // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "sum": // N-ARY SUMMATION + return rune(0x2211), true + case "sumint": // SUMMATION WITH INTEGRAL + return rune(0x2a0b), true + case "sung": // EIGHTH NOTE + return rune(0x266a), true + case "sup": // SUPERSET OF + return rune(0x2283), true + case "sup1": // SUPERSCRIPT ONE + return rune(0xb9), true + case "sup2": // SUPERSCRIPT TWO + return rune(0xb2), true + case "sup3": // SUPERSCRIPT THREE + return rune(0xb3), true + case "supE": // SUPERSET OF ABOVE EQUALS SIGN + return rune(0x2ac6), true + case "supdot": // SUPERSET WITH DOT + return rune(0x2abe), true + case "supdsub": // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET + return rune(0x2ad8), true + case "supe": // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "supedot": // SUPERSET OF OR EQUAL TO WITH DOT ABOVE + return rune(0x2ac4), true + case "suphsol": // SUPERSET PRECEDING SOLIDUS + return rune(0x27c9), true + case "suphsub": // SUPERSET BESIDE SUBSET + return rune(0x2ad7), true + case "suplarr": // SUPERSET ABOVE LEFTWARDS ARROW + return rune(0x297b), true + case "supmult": // SUPERSET WITH MULTIPLICATION SIGN BELOW + return rune(0x2ac2), true + case "supnE": // SUPERSET OF ABOVE NOT EQUAL TO + return rune(0x2acc), true + case "supne": // SUPERSET OF WITH NOT EQUAL TO + return rune(0x228b), true + case "supplus": // SUPERSET WITH PLUS SIGN BELOW + return rune(0x2ac0), true + case "supset": // SUPERSET OF + return rune(0x2283), true + case "supseteq": // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "supseteqq": // SUPERSET OF ABOVE EQUALS SIGN + return rune(0x2ac6), true + case "supsetneq": // SUPERSET OF WITH NOT EQUAL TO + return rune(0x228b), true + case "supsetneqq": // SUPERSET OF ABOVE NOT EQUAL TO + return rune(0x2acc), true + case "supsim": // SUPERSET OF ABOVE TILDE OPERATOR + return rune(0x2ac8), true + case "supsub": // SUPERSET ABOVE SUBSET + return rune(0x2ad4), true + case "supsup": // SUPERSET ABOVE SUPERSET + return rune(0x2ad6), true + case "swArr": // SOUTH WEST DOUBLE ARROW + return rune(0x21d9), true + case "swarhk": // SOUTH WEST ARROW WITH HOOK + return rune(0x2926), true + case "swarr": // SOUTH WEST ARROW + return rune(0x2199), true + case "swarrow": // SOUTH WEST ARROW + return rune(0x2199), true + case "swnwar": // SOUTH WEST ARROW AND NORTH WEST ARROW + return rune(0x292a), true + case "szlig": // LATIN SMALL LETTER SHARP S + return rune(0xdf), true } case 't': switch name { - case "target": // POSITION INDICATOR - return rune(0x2316), true - case "tau": // GREEK SMALL LETTER TAU - return rune(0x03c4), true - case "tbrk": // TOP SQUARE BRACKET - return rune(0x23b4), true - case "tcaron": // LATIN SMALL LETTER T WITH CARON - return rune(0x0165), true - case "tcedil": // LATIN SMALL LETTER T WITH CEDILLA - return rune(0x0163), true - case "tcy": // CYRILLIC SMALL LETTER TE - return rune(0x0442), true - case "tdot": // COMBINING THREE DOTS ABOVE - return rune(0x20db), true - case "telrec": // TELEPHONE RECORDER - return rune(0x2315), true - case "tfr": // MATHEMATICAL FRAKTUR SMALL T - return rune(0x01d531), true - case "tgr": // GREEK SMALL LETTER TAU - return rune(0x03c4), true - case "there4": // THEREFORE - return rune(0x2234), true - case "therefore": // THEREFORE - return rune(0x2234), true - case "thermod": // THERMODYNAMIC - return rune(0x29e7), true - case "theta": // GREEK SMALL LETTER THETA - return rune(0x03b8), true - case "thetas": // GREEK SMALL LETTER THETA - return rune(0x03b8), true - case "thetasym": // GREEK THETA SYMBOL - return rune(0x03d1), true - case "thetav": // GREEK THETA SYMBOL - return rune(0x03d1), true - case "thgr": // GREEK SMALL LETTER THETA - return rune(0x03b8), true - case "thickapprox": // ALMOST EQUAL TO - return rune(0x2248), true - case "thicksim": // TILDE OPERATOR - return rune(0x223c), true - case "thinsp": // THIN SPACE - return rune(0x2009), true - case "thkap": // ALMOST EQUAL TO - return rune(0x2248), true - case "thksim": // TILDE OPERATOR - return rune(0x223c), true - case "thorn": // LATIN SMALL LETTER THORN - return rune(0xfe), true - case "tilde": // SMALL TILDE - return rune(0x02dc), true - case "timeint": // INTEGRAL WITH TIMES SIGN - return rune(0x2a18), true - case "times": // MULTIPLICATION SIGN - return rune(0xd7), true - case "timesb": // SQUARED TIMES - return rune(0x22a0), true - case "timesbar": // MULTIPLICATION SIGN WITH UNDERBAR - return rune(0x2a31), true - case "timesd": // MULTIPLICATION SIGN WITH DOT ABOVE - return rune(0x2a30), true - case "tint": // TRIPLE INTEGRAL - return rune(0x222d), true - case "toea": // NORTH EAST ARROW AND SOUTH EAST ARROW - return rune(0x2928), true - case "top": // DOWN TACK - return rune(0x22a4), true - case "topbot": // APL FUNCTIONAL SYMBOL I-BEAM - return rune(0x2336), true - case "topcir": // DOWN TACK WITH CIRCLE BELOW - return rune(0x2af1), true - case "topf": // MATHEMATICAL DOUBLE-STRUCK SMALL T - return rune(0x01d565), true - case "topfork": // PITCHFORK WITH TEE TOP - return rune(0x2ada), true - case "tosa": // SOUTH EAST ARROW AND SOUTH WEST ARROW - return rune(0x2929), true - case "tprime": // TRIPLE PRIME - return rune(0x2034), true - case "trade": // TRADE MARK SIGN - return rune(0x2122), true - case "triS": // S IN TRIANGLE - return rune(0x29cc), true - case "triangle": // WHITE UP-POINTING SMALL TRIANGLE - return rune(0x25b5), true - case "triangledown": // WHITE DOWN-POINTING SMALL TRIANGLE - return rune(0x25bf), true - case "triangleleft": // WHITE LEFT-POINTING SMALL TRIANGLE - return rune(0x25c3), true - case "trianglelefteq": // NORMAL SUBGROUP OF OR EQUAL TO - return rune(0x22b4), true - case "triangleq": // DELTA EQUAL TO - return rune(0x225c), true - case "triangleright": // WHITE RIGHT-POINTING SMALL TRIANGLE - return rune(0x25b9), true - case "trianglerighteq": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - return rune(0x22b5), true - case "tribar": // TRIANGLE WITH UNDERBAR - return rune(0x29cb), true - case "tridot": // WHITE UP-POINTING TRIANGLE WITH DOT - return rune(0x25ec), true - case "tridoto": // TRIANGLE WITH DOT ABOVE - return rune(0x29ca), true - case "trie": // DELTA EQUAL TO - return rune(0x225c), true - case "triminus": // MINUS SIGN IN TRIANGLE - return rune(0x2a3a), true - case "triplus": // PLUS SIGN IN TRIANGLE - return rune(0x2a39), true - case "trisb": // TRIANGLE WITH SERIFS AT BOTTOM - return rune(0x29cd), true - case "tritime": // MULTIPLICATION SIGN IN TRIANGLE - return rune(0x2a3b), true - case "trpezium": // WHITE TRAPEZIUM - return rune(0x23e2), true - case "tscr": // MATHEMATICAL SCRIPT SMALL T - return rune(0x01d4c9), true - case "tscy": // CYRILLIC SMALL LETTER TSE - return rune(0x0446), true - case "tshcy": // CYRILLIC SMALL LETTER TSHE - return rune(0x045b), true - case "tstrok": // LATIN SMALL LETTER T WITH STROKE - return rune(0x0167), true - case "tverbar": // TRIPLE VERTICAL BAR DELIMITER - return rune(0x2980), true - case "twixt": // BETWEEN - return rune(0x226c), true - case "twoheadleftarrow": // LEFTWARDS TWO HEADED ARROW - return rune(0x219e), true - case "twoheadrightarrow": // RIGHTWARDS TWO HEADED ARROW - return rune(0x21a0), true + case "target": // POSITION INDICATOR + return rune(0x2316), true + case "tau": // GREEK SMALL LETTER TAU + return rune(0x03c4), true + case "tbrk": // TOP SQUARE BRACKET + return rune(0x23b4), true + case "tcaron": // LATIN SMALL LETTER T WITH CARON + return rune(0x0165), true + case "tcedil": // LATIN SMALL LETTER T WITH CEDILLA + return rune(0x0163), true + case "tcy": // CYRILLIC SMALL LETTER TE + return rune(0x0442), true + case "tdot": // COMBINING THREE DOTS ABOVE + return rune(0x20db), true + case "telrec": // TELEPHONE RECORDER + return rune(0x2315), true + case "tfr": // MATHEMATICAL FRAKTUR SMALL T + return rune(0x01d531), true + case "tgr": // GREEK SMALL LETTER TAU + return rune(0x03c4), true + case "there4": // THEREFORE + return rune(0x2234), true + case "therefore": // THEREFORE + return rune(0x2234), true + case "thermod": // THERMODYNAMIC + return rune(0x29e7), true + case "theta": // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thetas": // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thetasym": // GREEK THETA SYMBOL + return rune(0x03d1), true + case "thetav": // GREEK THETA SYMBOL + return rune(0x03d1), true + case "thgr": // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thickapprox": // ALMOST EQUAL TO + return rune(0x2248), true + case "thicksim": // TILDE OPERATOR + return rune(0x223c), true + case "thinsp": // THIN SPACE + return rune(0x2009), true + case "thkap": // ALMOST EQUAL TO + return rune(0x2248), true + case "thksim": // TILDE OPERATOR + return rune(0x223c), true + case "thorn": // LATIN SMALL LETTER THORN + return rune(0xfe), true + case "tilde": // SMALL TILDE + return rune(0x02dc), true + case "timeint": // INTEGRAL WITH TIMES SIGN + return rune(0x2a18), true + case "times": // MULTIPLICATION SIGN + return rune(0xd7), true + case "timesb": // SQUARED TIMES + return rune(0x22a0), true + case "timesbar": // MULTIPLICATION SIGN WITH UNDERBAR + return rune(0x2a31), true + case "timesd": // MULTIPLICATION SIGN WITH DOT ABOVE + return rune(0x2a30), true + case "tint": // TRIPLE INTEGRAL + return rune(0x222d), true + case "toea": // NORTH EAST ARROW AND SOUTH EAST ARROW + return rune(0x2928), true + case "top": // DOWN TACK + return rune(0x22a4), true + case "topbot": // APL FUNCTIONAL SYMBOL I-BEAM + return rune(0x2336), true + case "topcir": // DOWN TACK WITH CIRCLE BELOW + return rune(0x2af1), true + case "topf": // MATHEMATICAL DOUBLE-STRUCK SMALL T + return rune(0x01d565), true + case "topfork": // PITCHFORK WITH TEE TOP + return rune(0x2ada), true + case "tosa": // SOUTH EAST ARROW AND SOUTH WEST ARROW + return rune(0x2929), true + case "tprime": // TRIPLE PRIME + return rune(0x2034), true + case "trade": // TRADE MARK SIGN + return rune(0x2122), true + case "triS": // S IN TRIANGLE + return rune(0x29cc), true + case "triangle": // WHITE UP-POINTING SMALL TRIANGLE + return rune(0x25b5), true + case "triangledown": // WHITE DOWN-POINTING SMALL TRIANGLE + return rune(0x25bf), true + case "triangleleft": // WHITE LEFT-POINTING SMALL TRIANGLE + return rune(0x25c3), true + case "trianglelefteq": // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "triangleq": // DELTA EQUAL TO + return rune(0x225c), true + case "triangleright": // WHITE RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b9), true + case "trianglerighteq": // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "tribar": // TRIANGLE WITH UNDERBAR + return rune(0x29cb), true + case "tridot": // WHITE UP-POINTING TRIANGLE WITH DOT + return rune(0x25ec), true + case "tridoto": // TRIANGLE WITH DOT ABOVE + return rune(0x29ca), true + case "trie": // DELTA EQUAL TO + return rune(0x225c), true + case "triminus": // MINUS SIGN IN TRIANGLE + return rune(0x2a3a), true + case "triplus": // PLUS SIGN IN TRIANGLE + return rune(0x2a39), true + case "trisb": // TRIANGLE WITH SERIFS AT BOTTOM + return rune(0x29cd), true + case "tritime": // MULTIPLICATION SIGN IN TRIANGLE + return rune(0x2a3b), true + case "trpezium": // WHITE TRAPEZIUM + return rune(0x23e2), true + case "tscr": // MATHEMATICAL SCRIPT SMALL T + return rune(0x01d4c9), true + case "tscy": // CYRILLIC SMALL LETTER TSE + return rune(0x0446), true + case "tshcy": // CYRILLIC SMALL LETTER TSHE + return rune(0x045b), true + case "tstrok": // LATIN SMALL LETTER T WITH STROKE + return rune(0x0167), true + case "tverbar": // TRIPLE VERTICAL BAR DELIMITER + return rune(0x2980), true + case "twixt": // BETWEEN + return rune(0x226c), true + case "twoheadleftarrow": // LEFTWARDS TWO HEADED ARROW + return rune(0x219e), true + case "twoheadrightarrow": // RIGHTWARDS TWO HEADED ARROW + return rune(0x21a0), true } case 'u': switch name { - case "uAarr": // UPWARDS TRIPLE ARROW - return rune(0x290a), true - case "uArr": // UPWARDS DOUBLE ARROW - return rune(0x21d1), true - case "uHar": // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - return rune(0x2963), true - case "uacgr": // GREEK SMALL LETTER UPSILON WITH TONOS - return rune(0x03cd), true - case "uacute": // LATIN SMALL LETTER U WITH ACUTE - return rune(0xfa), true - case "uarr": // UPWARDS ARROW - return rune(0x2191), true - case "uarr2": // UPWARDS PAIRED ARROWS - return rune(0x21c8), true - case "uarrb": // UPWARDS ARROW TO BAR - return rune(0x2912), true - case "uarrln": // UPWARDS ARROW WITH HORIZONTAL STROKE - return rune(0x2909), true - case "ubrcy": // CYRILLIC SMALL LETTER SHORT U - return rune(0x045e), true - case "ubreve": // LATIN SMALL LETTER U WITH BREVE - return rune(0x016d), true - case "ucirc": // LATIN SMALL LETTER U WITH CIRCUMFLEX - return rune(0xfb), true - case "ucy": // CYRILLIC SMALL LETTER U - return rune(0x0443), true - case "udarr": // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - return rune(0x21c5), true - case "udblac": // LATIN SMALL LETTER U WITH DOUBLE ACUTE - return rune(0x0171), true - case "udhar": // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - return rune(0x296e), true - case "udiagr": // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS - return rune(0x03b0), true - case "udigr": // GREEK SMALL LETTER UPSILON WITH DIALYTIKA - return rune(0x03cb), true - case "udrbrk": // BOTTOM SQUARE BRACKET - return rune(0x23b5), true - case "udrcub": // BOTTOM CURLY BRACKET - return rune(0x23df), true - case "udrpar": // BOTTOM PARENTHESIS - return rune(0x23dd), true - case "ufisht": // UP FISH TAIL - return rune(0x297e), true - case "ufr": // MATHEMATICAL FRAKTUR SMALL U - return rune(0x01d532), true - case "ugr": // GREEK SMALL LETTER UPSILON - return rune(0x03c5), true - case "ugrave": // LATIN SMALL LETTER U WITH GRAVE - return rune(0xf9), true - case "uharl": // UPWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21bf), true - case "uharr": // UPWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21be), true - case "uhblk": // UPPER HALF BLOCK - return rune(0x2580), true - case "ulcorn": // TOP LEFT CORNER - return rune(0x231c), true - case "ulcorner": // TOP LEFT CORNER - return rune(0x231c), true - case "ulcrop": // TOP LEFT CROP - return rune(0x230f), true - case "uldlshar": // UP BARB LEFT DOWN BARB LEFT HARPOON - return rune(0x2951), true - case "ulharb": // UPWARDS HARPOON WITH BARB LEFT TO BAR - return rune(0x2958), true - case "ultri": // UPPER LEFT TRIANGLE - return rune(0x25f8), true - case "umacr": // LATIN SMALL LETTER U WITH MACRON - return rune(0x016b), true - case "uml": // DIAERESIS - return rune(0xa8), true - case "uogon": // LATIN SMALL LETTER U WITH OGONEK - return rune(0x0173), true - case "uopf": // MATHEMATICAL DOUBLE-STRUCK SMALL U - return rune(0x01d566), true - case "uparrow": // UPWARDS ARROW - return rune(0x2191), true - case "updownarrow": // UP DOWN ARROW - return rune(0x2195), true - case "upharpoonleft": // UPWARDS HARPOON WITH BARB LEFTWARDS - return rune(0x21bf), true - case "upharpoonright": // UPWARDS HARPOON WITH BARB RIGHTWARDS - return rune(0x21be), true - case "upint": // INTEGRAL WITH OVERBAR - return rune(0x2a1b), true - case "uplus": // MULTISET UNION - return rune(0x228e), true - case "upsi": // GREEK SMALL LETTER UPSILON - return rune(0x03c5), true - case "upsih": // GREEK UPSILON WITH HOOK SYMBOL - return rune(0x03d2), true - case "upsilon": // GREEK SMALL LETTER UPSILON - return rune(0x03c5), true - case "upuparrows": // UPWARDS PAIRED ARROWS - return rune(0x21c8), true - case "urcorn": // TOP RIGHT CORNER - return rune(0x231d), true - case "urcorner": // TOP RIGHT CORNER - return rune(0x231d), true - case "urcrop": // TOP RIGHT CROP - return rune(0x230e), true - case "urdrshar": // UP BARB RIGHT DOWN BARB RIGHT HARPOON - return rune(0x294f), true - case "urharb": // UPWARDS HARPOON WITH BARB RIGHT TO BAR - return rune(0x2954), true - case "uring": // LATIN SMALL LETTER U WITH RING ABOVE - return rune(0x016f), true - case "urtri": // UPPER RIGHT TRIANGLE - return rune(0x25f9), true - case "urtrif": // BLACK UPPER RIGHT TRIANGLE - return rune(0x25e5), true - case "uscr": // MATHEMATICAL SCRIPT SMALL U - return rune(0x01d4ca), true - case "utdot": // UP RIGHT DIAGONAL ELLIPSIS - return rune(0x22f0), true - case "utilde": // LATIN SMALL LETTER U WITH TILDE - return rune(0x0169), true - case "utri": // WHITE UP-POINTING SMALL TRIANGLE - return rune(0x25b5), true - case "utrif": // BLACK UP-POINTING SMALL TRIANGLE - return rune(0x25b4), true - case "uuarr": // UPWARDS PAIRED ARROWS - return rune(0x21c8), true - case "uuml": // LATIN SMALL LETTER U WITH DIAERESIS - return rune(0xfc), true - case "uwangle": // OBLIQUE ANGLE OPENING DOWN - return rune(0x29a7), true + case "uAarr": // UPWARDS TRIPLE ARROW + return rune(0x290a), true + case "uArr": // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "uHar": // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x2963), true + case "uacgr": // GREEK SMALL LETTER UPSILON WITH TONOS + return rune(0x03cd), true + case "uacute": // LATIN SMALL LETTER U WITH ACUTE + return rune(0xfa), true + case "uarr": // UPWARDS ARROW + return rune(0x2191), true + case "uarr2": // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "uarrb": // UPWARDS ARROW TO BAR + return rune(0x2912), true + case "uarrln": // UPWARDS ARROW WITH HORIZONTAL STROKE + return rune(0x2909), true + case "ubrcy": // CYRILLIC SMALL LETTER SHORT U + return rune(0x045e), true + case "ubreve": // LATIN SMALL LETTER U WITH BREVE + return rune(0x016d), true + case "ucirc": // LATIN SMALL LETTER U WITH CIRCUMFLEX + return rune(0xfb), true + case "ucy": // CYRILLIC SMALL LETTER U + return rune(0x0443), true + case "udarr": // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + return rune(0x21c5), true + case "udblac": // LATIN SMALL LETTER U WITH DOUBLE ACUTE + return rune(0x0171), true + case "udhar": // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x296e), true + case "udiagr": // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + return rune(0x03b0), true + case "udigr": // GREEK SMALL LETTER UPSILON WITH DIALYTIKA + return rune(0x03cb), true + case "udrbrk": // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "udrcub": // BOTTOM CURLY BRACKET + return rune(0x23df), true + case "udrpar": // BOTTOM PARENTHESIS + return rune(0x23dd), true + case "ufisht": // UP FISH TAIL + return rune(0x297e), true + case "ufr": // MATHEMATICAL FRAKTUR SMALL U + return rune(0x01d532), true + case "ugr": // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "ugrave": // LATIN SMALL LETTER U WITH GRAVE + return rune(0xf9), true + case "uharl": // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "uharr": // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "uhblk": // UPPER HALF BLOCK + return rune(0x2580), true + case "ulcorn": // TOP LEFT CORNER + return rune(0x231c), true + case "ulcorner": // TOP LEFT CORNER + return rune(0x231c), true + case "ulcrop": // TOP LEFT CROP + return rune(0x230f), true + case "uldlshar": // UP BARB LEFT DOWN BARB LEFT HARPOON + return rune(0x2951), true + case "ulharb": // UPWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2958), true + case "ultri": // UPPER LEFT TRIANGLE + return rune(0x25f8), true + case "umacr": // LATIN SMALL LETTER U WITH MACRON + return rune(0x016b), true + case "uml": // DIAERESIS + return rune(0xa8), true + case "uogon": // LATIN SMALL LETTER U WITH OGONEK + return rune(0x0173), true + case "uopf": // MATHEMATICAL DOUBLE-STRUCK SMALL U + return rune(0x01d566), true + case "uparrow": // UPWARDS ARROW + return rune(0x2191), true + case "updownarrow": // UP DOWN ARROW + return rune(0x2195), true + case "upharpoonleft": // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "upharpoonright": // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "upint": // INTEGRAL WITH OVERBAR + return rune(0x2a1b), true + case "uplus": // MULTISET UNION + return rune(0x228e), true + case "upsi": // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "upsih": // GREEK UPSILON WITH HOOK SYMBOL + return rune(0x03d2), true + case "upsilon": // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "upuparrows": // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "urcorn": // TOP RIGHT CORNER + return rune(0x231d), true + case "urcorner": // TOP RIGHT CORNER + return rune(0x231d), true + case "urcrop": // TOP RIGHT CROP + return rune(0x230e), true + case "urdrshar": // UP BARB RIGHT DOWN BARB RIGHT HARPOON + return rune(0x294f), true + case "urharb": // UPWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2954), true + case "uring": // LATIN SMALL LETTER U WITH RING ABOVE + return rune(0x016f), true + case "urtri": // UPPER RIGHT TRIANGLE + return rune(0x25f9), true + case "urtrif": // BLACK UPPER RIGHT TRIANGLE + return rune(0x25e5), true + case "uscr": // MATHEMATICAL SCRIPT SMALL U + return rune(0x01d4ca), true + case "utdot": // UP RIGHT DIAGONAL ELLIPSIS + return rune(0x22f0), true + case "utilde": // LATIN SMALL LETTER U WITH TILDE + return rune(0x0169), true + case "utri": // WHITE UP-POINTING SMALL TRIANGLE + return rune(0x25b5), true + case "utrif": // BLACK UP-POINTING SMALL TRIANGLE + return rune(0x25b4), true + case "uuarr": // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "uuml": // LATIN SMALL LETTER U WITH DIAERESIS + return rune(0xfc), true + case "uwangle": // OBLIQUE ANGLE OPENING DOWN + return rune(0x29a7), true } case 'v': switch name { - case "vArr": // UP DOWN DOUBLE ARROW - return rune(0x21d5), true - case "vBar": // SHORT UP TACK WITH UNDERBAR - return rune(0x2ae8), true - case "vBarv": // SHORT UP TACK ABOVE SHORT DOWN TACK - return rune(0x2ae9), true - case "vDash": // TRUE - return rune(0x22a8), true - case "vDdash": // VERTICAL BAR TRIPLE RIGHT TURNSTILE - return rune(0x2ae2), true - case "vangrt": // RIGHT ANGLE VARIANT WITH SQUARE - return rune(0x299c), true - case "varepsilon": // GREEK LUNATE EPSILON SYMBOL - return rune(0x03f5), true - case "varkappa": // GREEK KAPPA SYMBOL - return rune(0x03f0), true - case "varnothing": // EMPTY SET - return rune(0x2205), true - case "varphi": // GREEK PHI SYMBOL - return rune(0x03d5), true - case "varpi": // GREEK PI SYMBOL - return rune(0x03d6), true - case "varpropto": // PROPORTIONAL TO - return rune(0x221d), true - case "varr": // UP DOWN ARROW - return rune(0x2195), true - case "varrho": // GREEK RHO SYMBOL - return rune(0x03f1), true - case "varsigma": // GREEK SMALL LETTER FINAL SIGMA - return rune(0x03c2), true - case "varsubsetneq": // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228a), true - case "varsubsetneqq": // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acb), true - case "varsupsetneq": // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228b), true - case "varsupsetneqq": // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acc), true - case "vartheta": // GREEK THETA SYMBOL - return rune(0x03d1), true - case "vartriangleleft": // NORMAL SUBGROUP OF - return rune(0x22b2), true - case "vartriangleright": // CONTAINS AS NORMAL SUBGROUP - return rune(0x22b3), true - case "vbrtri": // VERTICAL BAR BESIDE RIGHT TRIANGLE - return rune(0x29d0), true - case "vcy": // CYRILLIC SMALL LETTER VE - return rune(0x0432), true - case "vdash": // RIGHT TACK - return rune(0x22a2), true - case "vee": // LOGICAL OR - return rune(0x2228), true - case "veeBar": // LOGICAL OR WITH DOUBLE UNDERBAR - return rune(0x2a63), true - case "veebar": // XOR - return rune(0x22bb), true - case "veeeq": // EQUIANGULAR TO - return rune(0x225a), true - case "vellip": // VERTICAL ELLIPSIS - return rune(0x22ee), true - case "vellip4": // DOTTED FENCE - return rune(0x2999), true - case "vellipv": // TRIPLE COLON OPERATOR - return rune(0x2af6), true - case "verbar": // VERTICAL LINE - return rune(0x7c), true - case "vert": // VERTICAL LINE - return rune(0x7c), true - case "vert3": // TRIPLE VERTICAL BAR BINARY RELATION - return rune(0x2af4), true - case "vfr": // MATHEMATICAL FRAKTUR SMALL V - return rune(0x01d533), true - case "vldash": // LEFT SQUARE BRACKET LOWER CORNER - return rune(0x23a3), true - case "vltri": // NORMAL SUBGROUP OF - return rune(0x22b2), true - case "vnsub": // SUBSET OF with vertical line - return rune(0x2282), true - case "vnsup": // SUPERSET OF with vertical line - return rune(0x2283), true - case "vopf": // MATHEMATICAL DOUBLE-STRUCK SMALL V - return rune(0x01d567), true - case "vprime": // PRIME - return rune(0x2032), true - case "vprop": // PROPORTIONAL TO - return rune(0x221d), true - case "vrtri": // CONTAINS AS NORMAL SUBGROUP - return rune(0x22b3), true - case "vscr": // MATHEMATICAL SCRIPT SMALL V - return rune(0x01d4cb), true - case "vsubnE": // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acb), true - case "vsubne": // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228a), true - case "vsupnE": // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - return rune(0x2acc), true - case "vsupne": // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members - return rune(0x228b), true - case "vzigzag": // VERTICAL ZIGZAG LINE - return rune(0x299a), true + case "vArr": // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "vBar": // SHORT UP TACK WITH UNDERBAR + return rune(0x2ae8), true + case "vBarv": // SHORT UP TACK ABOVE SHORT DOWN TACK + return rune(0x2ae9), true + case "vDash": // TRUE + return rune(0x22a8), true + case "vDdash": // VERTICAL BAR TRIPLE RIGHT TURNSTILE + return rune(0x2ae2), true + case "vangrt": // RIGHT ANGLE VARIANT WITH SQUARE + return rune(0x299c), true + case "varepsilon": // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "varkappa": // GREEK KAPPA SYMBOL + return rune(0x03f0), true + case "varnothing": // EMPTY SET + return rune(0x2205), true + case "varphi": // GREEK PHI SYMBOL + return rune(0x03d5), true + case "varpi": // GREEK PI SYMBOL + return rune(0x03d6), true + case "varpropto": // PROPORTIONAL TO + return rune(0x221d), true + case "varr": // UP DOWN ARROW + return rune(0x2195), true + case "varrho": // GREEK RHO SYMBOL + return rune(0x03f1), true + case "varsigma": // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "varsubsetneq": // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228a), true + case "varsubsetneqq": // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acb), true + case "varsupsetneq": // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228b), true + case "varsupsetneqq": // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acc), true + case "vartheta": // GREEK THETA SYMBOL + return rune(0x03d1), true + case "vartriangleleft": // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "vartriangleright": // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "vbrtri": // VERTICAL BAR BESIDE RIGHT TRIANGLE + return rune(0x29d0), true + case "vcy": // CYRILLIC SMALL LETTER VE + return rune(0x0432), true + case "vdash": // RIGHT TACK + return rune(0x22a2), true + case "vee": // LOGICAL OR + return rune(0x2228), true + case "veeBar": // LOGICAL OR WITH DOUBLE UNDERBAR + return rune(0x2a63), true + case "veebar": // XOR + return rune(0x22bb), true + case "veeeq": // EQUIANGULAR TO + return rune(0x225a), true + case "vellip": // VERTICAL ELLIPSIS + return rune(0x22ee), true + case "vellip4": // DOTTED FENCE + return rune(0x2999), true + case "vellipv": // TRIPLE COLON OPERATOR + return rune(0x2af6), true + case "verbar": // VERTICAL LINE + return rune(0x7c), true + case "vert": // VERTICAL LINE + return rune(0x7c), true + case "vert3": // TRIPLE VERTICAL BAR BINARY RELATION + return rune(0x2af4), true + case "vfr": // MATHEMATICAL FRAKTUR SMALL V + return rune(0x01d533), true + case "vldash": // LEFT SQUARE BRACKET LOWER CORNER + return rune(0x23a3), true + case "vltri": // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "vnsub": // SUBSET OF with vertical line + return rune(0x2282), true + case "vnsup": // SUPERSET OF with vertical line + return rune(0x2283), true + case "vopf": // MATHEMATICAL DOUBLE-STRUCK SMALL V + return rune(0x01d567), true + case "vprime": // PRIME + return rune(0x2032), true + case "vprop": // PROPORTIONAL TO + return rune(0x221d), true + case "vrtri": // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "vscr": // MATHEMATICAL SCRIPT SMALL V + return rune(0x01d4cb), true + case "vsubnE": // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acb), true + case "vsubne": // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228a), true + case "vsupnE": // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acc), true + case "vsupne": // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228b), true + case "vzigzag": // VERTICAL ZIGZAG LINE + return rune(0x299a), true } case 'w': switch name { - case "wcirc": // LATIN SMALL LETTER W WITH CIRCUMFLEX - return rune(0x0175), true - case "wedbar": // LOGICAL AND WITH UNDERBAR - return rune(0x2a5f), true - case "wedge": // LOGICAL AND - return rune(0x2227), true - case "wedgeq": // ESTIMATES - return rune(0x2259), true - case "weierp": // SCRIPT CAPITAL P - return rune(0x2118), true - case "wfr": // MATHEMATICAL FRAKTUR SMALL W - return rune(0x01d534), true - case "wopf": // MATHEMATICAL DOUBLE-STRUCK SMALL W - return rune(0x01d568), true - case "wp": // SCRIPT CAPITAL P - return rune(0x2118), true - case "wr": // WREATH PRODUCT - return rune(0x2240), true - case "wreath": // WREATH PRODUCT - return rune(0x2240), true - case "wscr": // MATHEMATICAL SCRIPT SMALL W - return rune(0x01d4cc), true + case "wcirc": // LATIN SMALL LETTER W WITH CIRCUMFLEX + return rune(0x0175), true + case "wedbar": // LOGICAL AND WITH UNDERBAR + return rune(0x2a5f), true + case "wedge": // LOGICAL AND + return rune(0x2227), true + case "wedgeq": // ESTIMATES + return rune(0x2259), true + case "weierp": // SCRIPT CAPITAL P + return rune(0x2118), true + case "wfr": // MATHEMATICAL FRAKTUR SMALL W + return rune(0x01d534), true + case "wopf": // MATHEMATICAL DOUBLE-STRUCK SMALL W + return rune(0x01d568), true + case "wp": // SCRIPT CAPITAL P + return rune(0x2118), true + case "wr": // WREATH PRODUCT + return rune(0x2240), true + case "wreath": // WREATH PRODUCT + return rune(0x2240), true + case "wscr": // MATHEMATICAL SCRIPT SMALL W + return rune(0x01d4cc), true } case 'x': switch name { - case "xandand": // TWO LOGICAL AND OPERATOR - return rune(0x2a07), true - case "xbsol": // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT - return rune(0x2571), true - case "xcap": // N-ARY INTERSECTION - return rune(0x22c2), true - case "xcirc": // LARGE CIRCLE - return rune(0x25ef), true - case "xcup": // N-ARY UNION - return rune(0x22c3), true - case "xcupdot": // N-ARY UNION OPERATOR WITH DOT - return rune(0x2a03), true - case "xdtri": // WHITE DOWN-POINTING TRIANGLE - return rune(0x25bd), true - case "xfr": // MATHEMATICAL FRAKTUR SMALL X - return rune(0x01d535), true - case "xgr": // GREEK SMALL LETTER XI - return rune(0x03be), true - case "xhArr": // LONG LEFT RIGHT DOUBLE ARROW - return rune(0x27fa), true - case "xharr": // LONG LEFT RIGHT ARROW - return rune(0x27f7), true - case "xi": // GREEK SMALL LETTER XI - return rune(0x03be), true - case "xlArr": // LONG LEFTWARDS DOUBLE ARROW - return rune(0x27f8), true - case "xlarr": // LONG LEFTWARDS ARROW - return rune(0x27f5), true - case "xmap": // LONG RIGHTWARDS ARROW FROM BAR - return rune(0x27fc), true - case "xnis": // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - return rune(0x22fb), true - case "xodot": // N-ARY CIRCLED DOT OPERATOR - return rune(0x2a00), true - case "xopf": // MATHEMATICAL DOUBLE-STRUCK SMALL X - return rune(0x01d569), true - case "xoplus": // N-ARY CIRCLED PLUS OPERATOR - return rune(0x2a01), true - case "xoror": // TWO LOGICAL OR OPERATOR - return rune(0x2a08), true - case "xotime": // N-ARY CIRCLED TIMES OPERATOR - return rune(0x2a02), true - case "xrArr": // LONG RIGHTWARDS DOUBLE ARROW - return rune(0x27f9), true - case "xrarr": // LONG RIGHTWARDS ARROW - return rune(0x27f6), true - case "xscr": // MATHEMATICAL SCRIPT SMALL X - return rune(0x01d4cd), true - case "xsol": // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - return rune(0x2572), true - case "xsqcap": // N-ARY SQUARE INTERSECTION OPERATOR - return rune(0x2a05), true - case "xsqcup": // N-ARY SQUARE UNION OPERATOR - return rune(0x2a06), true - case "xsqu": // WHITE MEDIUM SQUARE - return rune(0x25fb), true - case "xsquf": // BLACK MEDIUM SQUARE - return rune(0x25fc), true - case "xtimes": // N-ARY TIMES OPERATOR - return rune(0x2a09), true - case "xuplus": // N-ARY UNION OPERATOR WITH PLUS - return rune(0x2a04), true - case "xutri": // WHITE UP-POINTING TRIANGLE - return rune(0x25b3), true - case "xvee": // N-ARY LOGICAL OR - return rune(0x22c1), true - case "xwedge": // N-ARY LOGICAL AND - return rune(0x22c0), true + case "xandand": // TWO LOGICAL AND OPERATOR + return rune(0x2a07), true + case "xbsol": // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + return rune(0x2571), true + case "xcap": // N-ARY INTERSECTION + return rune(0x22c2), true + case "xcirc": // LARGE CIRCLE + return rune(0x25ef), true + case "xcup": // N-ARY UNION + return rune(0x22c3), true + case "xcupdot": // N-ARY UNION OPERATOR WITH DOT + return rune(0x2a03), true + case "xdtri": // WHITE DOWN-POINTING TRIANGLE + return rune(0x25bd), true + case "xfr": // MATHEMATICAL FRAKTUR SMALL X + return rune(0x01d535), true + case "xgr": // GREEK SMALL LETTER XI + return rune(0x03be), true + case "xhArr": // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "xharr": // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "xi": // GREEK SMALL LETTER XI + return rune(0x03be), true + case "xlArr": // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "xlarr": // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "xmap": // LONG RIGHTWARDS ARROW FROM BAR + return rune(0x27fc), true + case "xnis": // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22fb), true + case "xodot": // N-ARY CIRCLED DOT OPERATOR + return rune(0x2a00), true + case "xopf": // MATHEMATICAL DOUBLE-STRUCK SMALL X + return rune(0x01d569), true + case "xoplus": // N-ARY CIRCLED PLUS OPERATOR + return rune(0x2a01), true + case "xoror": // TWO LOGICAL OR OPERATOR + return rune(0x2a08), true + case "xotime": // N-ARY CIRCLED TIMES OPERATOR + return rune(0x2a02), true + case "xrArr": // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "xrarr": // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "xscr": // MATHEMATICAL SCRIPT SMALL X + return rune(0x01d4cd), true + case "xsol": // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + return rune(0x2572), true + case "xsqcap": // N-ARY SQUARE INTERSECTION OPERATOR + return rune(0x2a05), true + case "xsqcup": // N-ARY SQUARE UNION OPERATOR + return rune(0x2a06), true + case "xsqu": // WHITE MEDIUM SQUARE + return rune(0x25fb), true + case "xsquf": // BLACK MEDIUM SQUARE + return rune(0x25fc), true + case "xtimes": // N-ARY TIMES OPERATOR + return rune(0x2a09), true + case "xuplus": // N-ARY UNION OPERATOR WITH PLUS + return rune(0x2a04), true + case "xutri": // WHITE UP-POINTING TRIANGLE + return rune(0x25b3), true + case "xvee": // N-ARY LOGICAL OR + return rune(0x22c1), true + case "xwedge": // N-ARY LOGICAL AND + return rune(0x22c0), true } case 'y': switch name { - case "yacute": // LATIN SMALL LETTER Y WITH ACUTE - return rune(0xfd), true - case "yacy": // CYRILLIC SMALL LETTER YA - return rune(0x044f), true - case "ycirc": // LATIN SMALL LETTER Y WITH CIRCUMFLEX - return rune(0x0177), true - case "ycy": // CYRILLIC SMALL LETTER YERU - return rune(0x044b), true - case "yen": // YEN SIGN - return rune(0xa5), true - case "yfr": // MATHEMATICAL FRAKTUR SMALL Y - return rune(0x01d536), true - case "yicy": // CYRILLIC SMALL LETTER YI - return rune(0x0457), true - case "yopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Y - return rune(0x01d56a), true - case "yscr": // MATHEMATICAL SCRIPT SMALL Y - return rune(0x01d4ce), true - case "yucy": // CYRILLIC SMALL LETTER YU - return rune(0x044e), true - case "yuml": // LATIN SMALL LETTER Y WITH DIAERESIS - return rune(0xff), true + case "yacute": // LATIN SMALL LETTER Y WITH ACUTE + return rune(0xfd), true + case "yacy": // CYRILLIC SMALL LETTER YA + return rune(0x044f), true + case "ycirc": // LATIN SMALL LETTER Y WITH CIRCUMFLEX + return rune(0x0177), true + case "ycy": // CYRILLIC SMALL LETTER YERU + return rune(0x044b), true + case "yen": // YEN SIGN + return rune(0xa5), true + case "yfr": // MATHEMATICAL FRAKTUR SMALL Y + return rune(0x01d536), true + case "yicy": // CYRILLIC SMALL LETTER YI + return rune(0x0457), true + case "yopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Y + return rune(0x01d56a), true + case "yscr": // MATHEMATICAL SCRIPT SMALL Y + return rune(0x01d4ce), true + case "yucy": // CYRILLIC SMALL LETTER YU + return rune(0x044e), true + case "yuml": // LATIN SMALL LETTER Y WITH DIAERESIS + return rune(0xff), true } case 'z': switch name { - case "zacute": // LATIN SMALL LETTER Z WITH ACUTE - return rune(0x017a), true - case "zcaron": // LATIN SMALL LETTER Z WITH CARON - return rune(0x017e), true - case "zcy": // CYRILLIC SMALL LETTER ZE - return rune(0x0437), true - case "zdot": // LATIN SMALL LETTER Z WITH DOT ABOVE - return rune(0x017c), true - case "zeetrf": // BLACK-LETTER CAPITAL Z - return rune(0x2128), true - case "zeta": // GREEK SMALL LETTER ZETA - return rune(0x03b6), true - case "zfr": // MATHEMATICAL FRAKTUR SMALL Z - return rune(0x01d537), true - case "zgr": // GREEK SMALL LETTER ZETA - return rune(0x03b6), true - case "zhcy": // CYRILLIC SMALL LETTER ZHE - return rune(0x0436), true - case "zigrarr": // RIGHTWARDS SQUIGGLE ARROW - return rune(0x21dd), true - case "zopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Z - return rune(0x01d56b), true - case "zscr": // MATHEMATICAL SCRIPT SMALL Z - return rune(0x01d4cf), true - case "zwj": // ZERO WIDTH JOINER - return rune(0x200d), true - case "zwnj": // ZERO WIDTH NON-JOINER - return rune(0x200c), true + case "zacute": // LATIN SMALL LETTER Z WITH ACUTE + return rune(0x017a), true + case "zcaron": // LATIN SMALL LETTER Z WITH CARON + return rune(0x017e), true + case "zcy": // CYRILLIC SMALL LETTER ZE + return rune(0x0437), true + case "zdot": // LATIN SMALL LETTER Z WITH DOT ABOVE + return rune(0x017c), true + case "zeetrf": // BLACK-LETTER CAPITAL Z + return rune(0x2128), true + case "zeta": // GREEK SMALL LETTER ZETA + return rune(0x03b6), true + case "zfr": // MATHEMATICAL FRAKTUR SMALL Z + return rune(0x01d537), true + case "zgr": // GREEK SMALL LETTER ZETA + return rune(0x03b6), true + case "zhcy": // CYRILLIC SMALL LETTER ZHE + return rune(0x0436), true + case "zigrarr": // RIGHTWARDS SQUIGGLE ARROW + return rune(0x21dd), true + case "zopf": // MATHEMATICAL DOUBLE-STRUCK SMALL Z + return rune(0x01d56b), true + case "zscr": // MATHEMATICAL SCRIPT SMALL Z + return rune(0x01d4cf), true + case "zwj": // ZERO WIDTH JOINER + return rune(0x200d), true + case "zwnj": // ZERO WIDTH NON-JOINER + return rune(0x200c), true } } return -1, false diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 2933adf9a..0464c24d1 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -25,7 +25,7 @@ Marshal_Options :: struct { spec: Specification, // Use line breaks & tabs/spaces - pretty: bool, + pretty: bool, // Use spaces for indentation instead of tabs use_spaces: bool, @@ -34,7 +34,7 @@ Marshal_Options :: struct { spaces: int, // Output uint as hex in JSON5 & MJSON - write_uint_as_hex: bool, + write_uint_as_hex: bool, // If spec is MJSON and this is true, then keys will be quoted. // @@ -138,7 +138,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: // allow uints to be printed as hex if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) { switch i in a { - case u8, u16, u32, u64, u128: + case u8, u16, u32, u64, u128: s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) case: @@ -239,7 +239,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Array: opt_write_start(w, opt, '[') or_return for i in 0.. (err: case runtime.Type_Info_Enumerated_Array: opt_write_start(w, opt, '[') or_return for i in 0.. (err: opt_write_start(w, opt, '[') or_return array := cast(^mem.Raw_Dynamic_Array)v.data for i in 0.. (err: opt_write_start(w, opt, '[') or_return slice := cast(^mem.Raw_Slice)v.data for i in 0.. (err: for bucket_index in 0.. (err: slice.sort_by(sorted[:], proc(i, j: Entry) -> bool { return i.key < j.key }) for s, i in sorted { - opt_write_iteration(w, opt, i) or_return + opt_write_iteration(w, opt, i == 0) or_return opt_write_key(w, opt, s.key) or_return marshal_to_writer(w, s.value, opt) or_return } @@ -387,17 +387,17 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Pointer, runtime.Type_Info_Multi_Pointer, runtime.Type_Info_Procedure: - return (^rawptr)(v.data)^ == nil + return (^rawptr)(v.data)^ == nil case runtime.Type_Info_Dynamic_Array: - return (^runtime.Raw_Dynamic_Array)(v.data).len == 0 + return (^runtime.Raw_Dynamic_Array)(v.data).len == 0 case runtime.Type_Info_Slice: - return (^runtime.Raw_Slice)(v.data).len == 0 + return (^runtime.Raw_Slice)(v.data).len == 0 case runtime.Type_Info_Union, runtime.Type_Info_Bit_Set, runtime.Type_Info_Soa_Pointer: return reflect.is_nil(v) case runtime.Type_Info_Map: - return (^runtime.Raw_Map)(v.data).len == 0 + return (^runtime.Raw_Map)(v.data).len == 0 } return false } @@ -405,6 +405,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: marshal_struct_fields :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) { ti := runtime.type_info_base(type_info_of(v.id)) info := ti.variant.(runtime.Type_Info_Struct) + first_iteration := true for name, i in info.names { omitempty := false @@ -424,7 +425,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: continue } - opt_write_iteration(w, opt, i) or_return + opt_write_iteration(w, opt, first_iteration) or_return + first_iteration = false if json_name != "" { opt_write_key(w, opt, json_name) or_return } else { @@ -588,10 +590,10 @@ opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: i } // insert comma separation and write indentations -opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) { +opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, first_iteration: bool) -> (err: io.Error) { switch opt.spec { - case .JSON, .JSON5: - if iteration > 0 { + case .JSON, .JSON5: + if !first_iteration { io.write_byte(w, ',') or_return if opt.pretty { @@ -601,8 +603,8 @@ opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) opt_write_indentation(w, opt) or_return - case .MJSON: - if iteration > 0 { + case .MJSON: + if !first_iteration { // on pretty no commas necessary if opt.pretty { io.write_byte(w, '\n') or_return diff --git a/core/encoding/uuid/LICENSE b/core/encoding/uuid/LICENSE new file mode 100644 index 000000000..e4e21e62d --- /dev/null +++ b/core/encoding/uuid/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, Feoramund + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/core/encoding/uuid/definitions.odin b/core/encoding/uuid/definitions.odin new file mode 100644 index 000000000..fe13ca99a --- /dev/null +++ b/core/encoding/uuid/definitions.odin @@ -0,0 +1,67 @@ +package uuid + +// A RFC 4122 Universally Unique Identifier +Identifier :: distinct [16]u8 + +EXPECTED_LENGTH :: 8 + 4 + 4 + 4 + 12 + 4 + +VERSION_BYTE_INDEX :: 6 +VARIANT_BYTE_INDEX :: 8 + +// The number of 100-nanosecond intervals between 1582-10-15 and 1970-01-01. +HNS_INTERVALS_BETWEEN_GREG_AND_UNIX :: 141427 * 24 * 60 * 60 * 1000 * 1000 * 10 + +VERSION_7_TIME_MASK :: 0xffffffff_ffff0000_00000000_00000000 +VERSION_7_TIME_SHIFT :: 80 +VERSION_7_COUNTER_MASK :: 0x00000000_00000fff_00000000_00000000 +VERSION_7_COUNTER_SHIFT :: 64 + +@(private) +NO_CSPRNG_ERROR :: "The context random generator is not cryptographic. See the documentation for an example of how to set one up." +@(private) +BIG_CLOCK_ERROR :: "The clock sequence can only hold 14 bits of data, therefore no number greater than 16,383 (0x3FFF)." +@(private) +VERSION_7_BIG_COUNTER_ERROR :: "This implementation of the version 7 UUID counter can only hold 12 bits of data, therefore no number greater than 4,095 (0xFFF)." + +Read_Error :: enum { + None, + Invalid_Length, + Invalid_Hexadecimal, + Invalid_Separator, +} + +Variant_Type :: enum { + Unknown, + Reserved_Apollo_NCS, // 0b0xx + RFC_4122, // 0b10x + Reserved_Microsoft_COM, // 0b110 + Reserved_Future, // 0b111 +} + +// Name string is a fully-qualified domain name. +@(rodata) +Namespace_DNS := Identifier { + 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +} + +// Name string is a URL. +@(rodata) +Namespace_URL := Identifier { + 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +} + +// Name string is an ISO OID. +@(rodata) +Namespace_OID := Identifier { + 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +} + +// Name string is an X.500 DN (in DER or a text output format). +@(rodata) +Namespace_X500 := Identifier { + 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +} diff --git a/core/encoding/uuid/doc.odin b/core/encoding/uuid/doc.odin new file mode 100644 index 000000000..6fa375b72 --- /dev/null +++ b/core/encoding/uuid/doc.odin @@ -0,0 +1,46 @@ +/* +package uuid implements Universally Unique Identifiers according to the +standard originally outlined in RFC 4122 with additions from RFC 9562. + +The UUIDs are textually represented and read in the following string format: +`00000000-0000-v000-V000-000000000000` + +`v` is where the version bits reside, and `V` is where the variant bits reside. +The meaning of the other bits is version-dependent. + +Outside of string representations, UUIDs are represented in memory by a 128-bit +structure organized as an array of 16 bytes. + + +Of the UUID versions which may make use of random number generation, a +requirement is placed upon them that the underlying generator be +cryptographically-secure, per RFC 9562's suggestion. + +- Version 1 without a node argument. +- Version 4 in all cases. +- Version 6 without either a clock or node argument. +- Version 7 in all cases. + +Here's an example of how to set up one: + + import "core:crypto" + import "core:encoding/uuid" + + main :: proc() { + my_uuid: uuid.Identifier + + { + // This scope will have a CSPRNG. + context.random_generator = crypto.random_generator() + my_uuid = uuid.generate_v7() + } + + // Back to the default random number generator. + } + + +For more information on the specifications, see here: +- https://www.rfc-editor.org/rfc/rfc4122.html +- https://www.rfc-editor.org/rfc/rfc9562.html +*/ +package uuid diff --git a/core/encoding/uuid/generation.odin b/core/encoding/uuid/generation.odin new file mode 100644 index 000000000..7c9d4b80c --- /dev/null +++ b/core/encoding/uuid/generation.odin @@ -0,0 +1,333 @@ +package uuid + +import "base:runtime" +import "core:crypto/hash" +import "core:math/rand" +import "core:time" + +/* +Generate a version 1 UUID. + +Inputs: +- clock_seq: The clock sequence, a number which must be initialized to a random number once in the lifetime of a system. +- node: An optional 48-bit spatially unique identifier, specified to be the IEEE 802 address of the system. + If one is not provided or available, 48 bits of random state will take its place. +- timestamp: A timestamp from the `core:time` package, or `nil` to use the current time. + +Returns: +- result: The generated UUID. +*/ +generate_v1 :: proc(clock_seq: u16, node: Maybe([6]u8) = nil, timestamp: Maybe(time.Time) = nil) -> (result: Identifier) { + assert(clock_seq <= 0x3FFF, BIG_CLOCK_ERROR) + unix_time_in_hns_intervals := time.to_unix_nanoseconds(timestamp.? or_else time.now()) / 100 + + uuid_timestamp := cast(u64le)(HNS_INTERVALS_BETWEEN_GREG_AND_UNIX + unix_time_in_hns_intervals) + uuid_timestamp_octets := transmute([8]u8)uuid_timestamp + + result[0] = uuid_timestamp_octets[0] + result[1] = uuid_timestamp_octets[1] + result[2] = uuid_timestamp_octets[2] + result[3] = uuid_timestamp_octets[3] + result[4] = uuid_timestamp_octets[4] + result[5] = uuid_timestamp_octets[5] + + result[6] = uuid_timestamp_octets[6] >> 4 + result[7] = uuid_timestamp_octets[6] << 4 | uuid_timestamp_octets[7] + + if realized_node, ok := node.?; ok { + mutable_node := realized_node + runtime.mem_copy_non_overlapping(&result[10], &mutable_node[0], 6) + } else { + assert(.Cryptographic in runtime.random_generator_query_info(context.random_generator), NO_CSPRNG_ERROR) + bytes_generated := rand.read(result[10:]) + assert(bytes_generated == 6, "RNG failed to generate 6 bytes for UUID v1.") + } + + result[VERSION_BYTE_INDEX] |= 0x10 + result[VARIANT_BYTE_INDEX] |= 0x80 + + result[8] |= cast(u8)(clock_seq & 0x3F00 >> 8) + result[9] = cast(u8)clock_seq + + return +} + +/* +Generate a version 4 UUID. + +This UUID will be pseudorandom, save for 6 pre-determined version and variant bits. + +Returns: +- result: The generated UUID. +*/ +generate_v4 :: proc() -> (result: Identifier) { + assert(.Cryptographic in runtime.random_generator_query_info(context.random_generator), NO_CSPRNG_ERROR) + bytes_generated := rand.read(result[:]) + assert(bytes_generated == 16, "RNG failed to generate 16 bytes for UUID v4.") + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x40 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Generate a version 6 UUID. + +Inputs: +- clock_seq: The clock sequence from version 1, now made optional. + If unspecified, it will be replaced with random bits. +- node: An optional 48-bit spatially unique identifier, specified to be the IEEE 802 address of the system. + If one is not provided or available, 48 bits of random state will take its place. +- timestamp: A timestamp from the `core:time` package, or `nil` to use the current time. + +Returns: +- result: The generated UUID. +*/ +generate_v6 :: proc(clock_seq: Maybe(u16) = nil, node: Maybe([6]u8) = nil, timestamp: Maybe(time.Time) = nil) -> (result: Identifier) { + unix_time_in_hns_intervals := time.to_unix_nanoseconds(timestamp.? or_else time.now()) / 100 + + uuid_timestamp := cast(u128be)(HNS_INTERVALS_BETWEEN_GREG_AND_UNIX + unix_time_in_hns_intervals) + + result = transmute(Identifier)( + uuid_timestamp & 0x0FFFFFFF_FFFFF000 << 68 | + uuid_timestamp & 0x00000000_00000FFF << 64 + ) + + if realized_clock_seq, ok := clock_seq.?; ok { + assert(realized_clock_seq <= 0x3FFF, BIG_CLOCK_ERROR) + result[8] |= cast(u8)(realized_clock_seq & 0x3F00 >> 8) + result[9] = cast(u8)realized_clock_seq + } else { + assert(.Cryptographic in runtime.random_generator_query_info(context.random_generator), NO_CSPRNG_ERROR) + temporary: [2]u8 + bytes_generated := rand.read(temporary[:]) + assert(bytes_generated == 2, "RNG failed to generate 2 bytes for UUID v1.") + result[8] |= temporary[0] & 0x3F + result[9] = temporary[1] + } + + if realized_node, ok := node.?; ok { + mutable_node := realized_node + runtime.mem_copy_non_overlapping(&result[10], &mutable_node[0], 6) + } else { + assert(.Cryptographic in runtime.random_generator_query_info(context.random_generator), NO_CSPRNG_ERROR) + bytes_generated := rand.read(result[10:]) + assert(bytes_generated == 6, "RNG failed to generate 6 bytes for UUID v1.") + } + + result[VERSION_BYTE_INDEX] |= 0x60 + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Generate a version 7 UUID. + +This UUID will be pseudorandom, save for 6 pre-determined version and variant +bits and a 48-bit timestamp. + +It is designed with time-based sorting in mind, such as for database usage, as +the highest bits are allocated from the timestamp of when it is created. + +Inputs: +- timestamp: A timestamp from the `core:time` package, or `nil` to use the current time. + +Returns: +- result: The generated UUID. +*/ +generate_v7_basic :: proc(timestamp: Maybe(time.Time) = nil) -> (result: Identifier) { + assert(.Cryptographic in runtime.random_generator_query_info(context.random_generator), NO_CSPRNG_ERROR) + unix_time_in_milliseconds := time.to_unix_nanoseconds(timestamp.? or_else time.now()) / 1e6 + + result = transmute(Identifier)(cast(u128be)unix_time_in_milliseconds << VERSION_7_TIME_SHIFT) + + bytes_generated := rand.read(result[6:]) + assert(bytes_generated == 10, "RNG failed to generate 10 bytes for UUID v7.") + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x70 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Generate a version 7 UUID that has an incremented counter. + +This UUID will be pseudorandom, save for 6 pre-determined version and variant +bits, a 48-bit timestamp, and 12 bits of counter state. + +It is designed with time-based sorting in mind, such as for database usage, as +the highest bits are allocated from the timestamp of when it is created. + +This procedure is preferable if you are generating hundreds or thousands of +UUIDs as a batch within the span of a millisecond. Do note that the counter +only has 12 bits of state, thus `counter` cannot exceed the number 4,095. + +Example: + + import "core:uuid" + + // Create a batch of UUIDs all at once. + batch: [dynamic]uuid.Identifier + + for i: u16 = 0; i < 1000; i += 1 { + my_uuid := uuid.generate_v7_counter(i) + append(&batch, my_uuid) + } + +Inputs: +- counter: A 12-bit value which should be incremented each time a UUID is generated in a batch. +- timestamp: A timestamp from the `core:time` package, or `nil` to use the current time. + +Returns: +- result: The generated UUID. +*/ +generate_v7_with_counter :: proc(counter: u16, timestamp: Maybe(time.Time) = nil) -> (result: Identifier) { + assert(.Cryptographic in runtime.random_generator_query_info(context.random_generator), NO_CSPRNG_ERROR) + assert(counter <= 0x0fff, VERSION_7_BIG_COUNTER_ERROR) + unix_time_in_milliseconds := time.to_unix_nanoseconds(timestamp.? or_else time.now()) / 1e6 + + result = transmute(Identifier)( + cast(u128be)unix_time_in_milliseconds << VERSION_7_TIME_SHIFT | + cast(u128be)counter << VERSION_7_COUNTER_SHIFT + ) + + bytes_generated := rand.read(result[8:]) + assert(bytes_generated == 8, "RNG failed to generate 8 bytes for UUID v7.") + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x70 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +generate_v7 :: proc { + generate_v7_basic, + generate_v7_with_counter, +} + +/* +Generate a version 8 UUID using a specific hashing algorithm. + +This UUID is generated by hashing a name with a namespace. + +Note that all version 8 UUIDs are for experimental or vendor-specific use +cases, per the specification. This use case in particular is for offering a +non-legacy alternative to UUID versions 3 and 5. + +Inputs: +- namespace: An `Identifier` that is used to represent the underlying namespace. + This can be any one of the `Namespace_*` values provided in this package. +- name: The byte slice which will be hashed with the namespace. +- algorithm: A hashing algorithm from `core:crypto/hash`. + +Returns: +- result: The generated UUID. + +Example: + import "core:crypto/hash" + import "core:encoding/uuid" + import "core:fmt" + + main :: proc() { + my_uuid := uuid.generate_v8_hash(uuid.Namespace_DNS, "www.odin-lang.org", .SHA256) + my_uuid_string := uuid.to_string(my_uuid, context.temp_allocator) + fmt.println(my_uuid_string) + } + +Output: + + 3730f688-4bff-8dce-9cbf-74a3960c5703 + +*/ +generate_v8_hash_bytes :: proc( + namespace: Identifier, + name: []byte, + algorithm: hash.Algorithm, +) -> ( + result: Identifier, +) { + // 128 bytes should be enough for the foreseeable future. + digest: [128]byte + + assert(hash.DIGEST_SIZES[algorithm] >= 16, "Per RFC 9562, the hashing algorithm used must generate a digest of 128 bits or larger.") + assert(hash.DIGEST_SIZES[algorithm] < len(digest), "Digest size is too small for this algorithm. The buffer must be increased.") + + hash_context: hash.Context + hash.init(&hash_context, algorithm) + + mutable_namespace := namespace + hash.update(&hash_context, mutable_namespace[:]) + hash.update(&hash_context, name[:]) + hash.final(&hash_context, digest[:]) + + runtime.mem_copy_non_overlapping(&result, &digest, 16) + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x80 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Generate a version 8 UUID using a specific hashing algorithm. + +This UUID is generated by hashing a name with a namespace. + +Note that all version 8 UUIDs are for experimental or vendor-specific use +cases, per the specification. This use case in particular is for offering a +non-legacy alternative to UUID versions 3 and 5. + +Inputs: +- namespace: An `Identifier` that is used to represent the underlying namespace. + This can be any one of the `Namespace_*` values provided in this package. +- name: The string which will be hashed with the namespace. +- algorithm: A hashing algorithm from `core:crypto/hash`. + +Returns: +- result: The generated UUID. + +Example: + import "core:crypto/hash" + import "core:encoding/uuid" + import "core:fmt" + + main :: proc() { + my_uuid := uuid.generate_v8_hash(uuid.Namespace_DNS, "www.odin-lang.org", .SHA256) + my_uuid_string := uuid.to_string(my_uuid, context.temp_allocator) + fmt.println(my_uuid_string) + } + +Output: + + 3730f688-4bff-8dce-9cbf-74a3960c5703 + +*/ +generate_v8_hash_string :: proc( + namespace: Identifier, + name: string, + algorithm: hash.Algorithm, +) -> ( + result: Identifier, +) { + return generate_v8_hash_bytes(namespace, transmute([]byte)name, algorithm) +} + +generate_v8_hash :: proc { + generate_v8_hash_bytes, + generate_v8_hash_string, +} diff --git a/core/encoding/uuid/legacy/legacy.odin b/core/encoding/uuid/legacy/legacy.odin new file mode 100644 index 000000000..d5f3df617 --- /dev/null +++ b/core/encoding/uuid/legacy/legacy.odin @@ -0,0 +1,146 @@ +/* +package uuid/legacy implements versions 3 and 5 of UUID generation, both of +which are using hashing algorithms (MD5 and SHA1, respectively) that are known +these days to no longer be secure. +*/ +package uuid_legacy + +import "base:runtime" +import "core:crypto/legacy/md5" +import "core:crypto/legacy/sha1" +import "core:encoding/uuid" + +Identifier :: uuid.Identifier +VERSION_BYTE_INDEX :: uuid.VERSION_BYTE_INDEX +VARIANT_BYTE_INDEX :: uuid.VARIANT_BYTE_INDEX + + +/* +Generate a version 3 UUID. + +This UUID is generated with a MD5 hash of a name and a namespace. + +Inputs: +- namespace: An `Identifier` that is used to represent the underlying namespace. + This can be any one of the `Namespace_*` values provided in the `uuid` package. +- name: The byte slice which will be hashed with the namespace. + +Returns: +- result: The generated UUID. +*/ +generate_v3_bytes :: proc( + namespace: Identifier, + name: []byte, +) -> ( + result: Identifier, +) { + namespace := namespace + + ctx: md5.Context + md5.init(&ctx) + md5.update(&ctx, namespace[:]) + md5.update(&ctx, name) + md5.final(&ctx, result[:]) + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x30 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Generate a version 3 UUID. + +This UUID is generated with a MD5 hash of a name and a namespace. + +Inputs: +- namespace: An `Identifier` that is used to represent the underlying namespace. + This can be any one of the `Namespace_*` values provided in the `uuid` package. +- name: The string which will be hashed with the namespace. + +Returns: +- result: The generated UUID. +*/ +generate_v3_string :: proc( + namespace: Identifier, + name: string, +) -> ( + result: Identifier, +) { + return generate_v3_bytes(namespace, transmute([]byte)name) +} + +generate_v3 :: proc { + generate_v3_bytes, + generate_v3_string, +} + +/* +Generate a version 5 UUID. + +This UUID is generated with a SHA1 hash of a name and a namespace. + +Inputs: +- namespace: An `Identifier` that is used to represent the underlying namespace. + This can be any one of the `Namespace_*` values provided in the `uuid` package. +- name: The byte slice which will be hashed with the namespace. + +Returns: +- result: The generated UUID. +*/ +generate_v5_bytes :: proc( + namespace: Identifier, + name: []byte, +) -> ( + result: Identifier, +) { + namespace := namespace + digest: [sha1.DIGEST_SIZE]byte + + ctx: sha1.Context + sha1.init(&ctx) + sha1.update(&ctx, namespace[:]) + sha1.update(&ctx, name) + sha1.final(&ctx, digest[:]) + + runtime.mem_copy_non_overlapping(&result, &digest, 16) + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x50 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Generate a version 5 UUID. + +This UUID is generated with a SHA1 hash of a name and a namespace. + +Inputs: +- namespace: An `Identifier` that is used to represent the underlying namespace. + This can be any one of the `Namespace_*` values provided in the `uuid` package. +- name: The string which will be hashed with the namespace. + +Returns: +- result: The generated UUID. +*/ +generate_v5_string :: proc( + namespace: Identifier, + name: string, +) -> ( + result: Identifier, +) { + return generate_v5_bytes(namespace, transmute([]byte)name) +} + +generate_v5 :: proc { + generate_v5_bytes, + generate_v5_string, +} + diff --git a/core/encoding/uuid/reading.odin b/core/encoding/uuid/reading.odin new file mode 100644 index 000000000..c91c82465 --- /dev/null +++ b/core/encoding/uuid/reading.odin @@ -0,0 +1,242 @@ +package uuid + +import "base:runtime" +import "core:time" + +/* +Convert a string to a UUID. + +Inputs: +- str: A string in the 8-4-4-4-12 format. + +Returns: +- id: The converted identifier, or `nil` if there is an error. +- error: A description of the error, or `nil` if successful. +*/ +read :: proc "contextless" (str: string) -> (id: Identifier, error: Read_Error) #no_bounds_check { + // Only exact-length strings are acceptable. + if len(str) != EXPECTED_LENGTH { + return {}, .Invalid_Length + } + + // Check ahead to see if the separators are in the right places. + if str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-' { + return {}, .Invalid_Separator + } + + read_nibble :: proc "contextless" (nibble: u8) -> u8 { + switch nibble { + case '0' ..= '9': + return nibble - '0' + case 'A' ..= 'F': + return nibble - 'A' + 10 + case 'a' ..= 'f': + return nibble - 'a' + 10 + case: + // Return an error value. + return 0xFF + } + } + + index := 0 + octet_index := 0 + + CHUNKS :: [5]int{8, 4, 4, 4, 12} + + for chunk in CHUNKS { + for i := index; i < index + chunk; i += 2 { + high := read_nibble(str[i]) + low := read_nibble(str[i + 1]) + + if high | low > 0xF { + return {}, .Invalid_Hexadecimal + } + + id[octet_index] = low | high << 4 + octet_index += 1 + } + + index += chunk + 1 + } + + return +} + +/* +Get the version of a UUID. + +Inputs: +- id: The identifier. + +Returns: +- number: The version number. +*/ +version :: proc "contextless" (id: Identifier) -> (number: int) #no_bounds_check { + return cast(int)(id[VERSION_BYTE_INDEX] & 0xF0 >> 4) +} + +/* +Get the variant of a UUID. + +Inputs: +- id: The identifier. + +Returns: +- variant: The variant type. +*/ +variant :: proc "contextless" (id: Identifier) -> (variant: Variant_Type) #no_bounds_check { + switch { + case id[VARIANT_BYTE_INDEX] & 0x80 == 0: + return .Reserved_Apollo_NCS + case id[VARIANT_BYTE_INDEX] & 0xC0 == 0x80: + return .RFC_4122 + case id[VARIANT_BYTE_INDEX] & 0xE0 == 0xC0: + return .Reserved_Microsoft_COM + case id[VARIANT_BYTE_INDEX] & 0xF0 == 0xE0: + return .Reserved_Future + case: + return .Unknown + } +} + +/* +Get the clock sequence of a version 1 or version 6 UUID. + +Inputs: +- id: The identifier. + +Returns: +- clock_seq: The 14-bit clock sequence field. +*/ +clock_seq :: proc "contextless" (id: Identifier) -> (clock_seq: u16) { + return cast(u16)id[9] | cast(u16)id[8] & 0x3F << 8 +} + +/* +Get the node of a version 1 or version 6 UUID. + +Inputs: +- id: The identifier. + +Returns: +- node: The 48-bit spatially unique identifier. +*/ +node :: proc "contextless" (id: Identifier) -> (node: [6]u8) { + mutable_id := id + runtime.mem_copy_non_overlapping(&node, &mutable_id[10], 6) + return +} + +/* +Get the raw timestamp of a version 1 UUID. + +Inputs: +- id: The identifier. + +Returns: +- timestamp: The timestamp, in 100-nanosecond intervals since 1582-10-15. +*/ +raw_time_v1 :: proc "contextless" (id: Identifier) -> (timestamp: u64) { + timestamp_octets: [8]u8 + + timestamp_octets[0] = id[0] + timestamp_octets[1] = id[1] + timestamp_octets[2] = id[2] + timestamp_octets[3] = id[3] + timestamp_octets[4] = id[4] + timestamp_octets[5] = id[5] + + timestamp_octets[6] = id[6] << 4 | id[7] >> 4 + timestamp_octets[7] = id[7] & 0xF + + return cast(u64)transmute(u64le)timestamp_octets +} + + +/* +Get the timestamp of a version 1 UUID. + +Inputs: +- id: The identifier. + +Returns: +- timestamp: The timestamp of the UUID. +*/ +time_v1 :: proc "contextless" (id: Identifier) -> (timestamp: time.Time) { + return time.from_nanoseconds(cast(i64)(raw_time_v1(id) - HNS_INTERVALS_BETWEEN_GREG_AND_UNIX) * 100) +} + +/* +Get the raw timestamp of a version 6 UUID. + +Inputs: +- id: The identifier. + +Returns: +- timestamp: The timestamp, in 100-nanosecond intervals since 1582-10-15. +*/ +raw_time_v6 :: proc "contextless" (id: Identifier) -> (timestamp: u64) { + temporary := transmute(u128be)id + + timestamp |= cast(u64)(temporary & 0xFFFFFFFF_FFFF0000_00000000_00000000 >> 68) + timestamp |= cast(u64)(temporary & 0x00000000_00000FFF_00000000_00000000 >> 64) + + return timestamp +} + +/* +Get the timestamp of a version 6 UUID. + +Inputs: +- id: The identifier. + +Returns: +- timestamp: The timestamp, in 100-nanosecond intervals since 1582-10-15. +*/ +time_v6 :: proc "contextless" (id: Identifier) -> (timestamp: time.Time) { + return time.from_nanoseconds(cast(i64)(raw_time_v6(id) - HNS_INTERVALS_BETWEEN_GREG_AND_UNIX) * 100) +} + +/* +Get the raw timestamp of a version 7 UUID. + +Inputs: +- id: The identifier. + +Returns: +- timestamp: The timestamp, in milliseconds since the UNIX epoch. +*/ +raw_time_v7 :: proc "contextless" (id: Identifier) -> (timestamp: u64) { + time_bits := transmute(u128be)id & VERSION_7_TIME_MASK + return cast(u64)(time_bits >> VERSION_7_TIME_SHIFT) +} + +/* +Get the timestamp of a version 7 UUID. + +Inputs: +- id: The identifier. + +Returns: +- timestamp: The timestamp, in milliseconds since the UNIX epoch. +*/ +time_v7 :: proc "contextless" (id: Identifier) -> (timestamp: time.Time) { + return time.from_nanoseconds(cast(i64)raw_time_v7(id) * 1e6) +} + +/* +Get the 12-bit counter value of a version 7 UUID. + +The UUID must have been generated with a counter, otherwise this procedure will +return random bits. + +Inputs: +- id: The identifier. + +Returns: +- counter: The 12-bit counter value. +*/ +counter_v7 :: proc "contextless" (id: Identifier) -> (counter: u16) { + counter_bits := transmute(u128be)id & VERSION_7_COUNTER_MASK + return cast(u16)(counter_bits >> VERSION_7_COUNTER_SHIFT) +} diff --git a/core/encoding/uuid/stamping.odin b/core/encoding/uuid/stamping.odin new file mode 100644 index 000000000..3ca61fe44 --- /dev/null +++ b/core/encoding/uuid/stamping.odin @@ -0,0 +1,89 @@ +package uuid + +import "base:runtime" + +/* +Stamp a 128-bit integer as being a valid version 8 UUID. + +Per the specification, all version 8 UUIDs are either for experimental or +vendor-specific purposes. This procedure allows for converting arbitrary data +into custom UUIDs. + +Inputs: +- integer: Any integer type. + +Returns: +- result: A valid version 8 UUID. +*/ +stamp_v8_int :: proc(#any_int integer: u128) -> (result: Identifier) { + result = transmute(Identifier)cast(u128be)integer + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x80 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Stamp an array of 16 bytes as being a valid version 8 UUID. + +Per the specification, all version 8 UUIDs are either for experimental or +vendor-specific purposes. This procedure allows for converting arbitrary data +into custom UUIDs. + +Inputs: +- array: An array of 16 bytes. + +Returns: +- result: A valid version 8 UUID. +*/ +stamp_v8_array :: proc(array: [16]u8) -> (result: Identifier) { + result = Identifier(array) + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x80 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +/* +Stamp a slice of bytes as being a valid version 8 UUID. + +If the slice is less than 16 bytes long, the data available will be used. +If it is longer than 16 bytes, only the first 16 will be used. + +This procedure does not modify the underlying slice. + +Per the specification, all version 8 UUIDs are either for experimental or +vendor-specific purposes. This procedure allows for converting arbitrary data +into custom UUIDs. + +Inputs: +- slice: A slice of bytes. + +Returns: +- result: A valid version 8 UUID. +*/ +stamp_v8_slice :: proc(slice: []u8) -> (result: Identifier) { + runtime.mem_copy_non_overlapping(&result, &slice[0], min(16, len(slice))) + + result[VERSION_BYTE_INDEX] &= 0x0F + result[VERSION_BYTE_INDEX] |= 0x80 + + result[VARIANT_BYTE_INDEX] &= 0x3F + result[VARIANT_BYTE_INDEX] |= 0x80 + + return +} + +stamp_v8 :: proc { + stamp_v8_int, + stamp_v8_array, + stamp_v8_slice, +} diff --git a/core/encoding/uuid/writing.odin b/core/encoding/uuid/writing.odin new file mode 100644 index 000000000..499cba72b --- /dev/null +++ b/core/encoding/uuid/writing.odin @@ -0,0 +1,131 @@ +package uuid + +import "base:runtime" +import "core:io" +import "core:strconv" +import "core:strings" + +/* +Write a UUID in the 8-4-4-4-12 format. + +This procedure performs error checking with every byte written. + +If you can guarantee beforehand that your stream has enough space to hold the +UUID (32 bytes), then it is better to use `unsafe_write` instead as that will +be faster. + +Inputs: +- w: A writable stream. +- id: The identifier to convert. + +Returns: +- error: An `io` error, if one occurred, otherwise `nil`. +*/ +write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_check { + write_octet :: proc (w: io.Writer, octet: u8) -> io.Error #no_bounds_check { + high_nibble := octet >> 4 + low_nibble := octet & 0xF + + io.write_byte(w, strconv.digits[high_nibble]) or_return + io.write_byte(w, strconv.digits[low_nibble]) or_return + return nil + } + + for index in 0 ..< 4 { write_octet(w, id[index]) or_return } + io.write_byte(w, '-') or_return + for index in 4 ..< 6 { write_octet(w, id[index]) or_return } + io.write_byte(w, '-') or_return + for index in 6 ..< 8 { write_octet(w, id[index]) or_return } + io.write_byte(w, '-') or_return + for index in 8 ..< 10 { write_octet(w, id[index]) or_return } + io.write_byte(w, '-') or_return + for index in 10 ..< 16 { write_octet(w, id[index]) or_return } + + return nil +} + +/* +Write a UUID in the 8-4-4-4-12 format. + +This procedure performs no error checking on the underlying stream. + +Inputs: +- w: A writable stream. +- id: The identifier to convert. +*/ +unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check { + write_octet :: proc (w: io.Writer, octet: u8) #no_bounds_check { + high_nibble := octet >> 4 + low_nibble := octet & 0xF + + io.write_byte(w, strconv.digits[high_nibble]) + io.write_byte(w, strconv.digits[low_nibble]) + } + + for index in 0 ..< 4 { write_octet(w, id[index]) } + io.write_byte(w, '-') + for index in 4 ..< 6 { write_octet(w, id[index]) } + io.write_byte(w, '-') + for index in 6 ..< 8 { write_octet(w, id[index]) } + io.write_byte(w, '-') + for index in 8 ..< 10 { write_octet(w, id[index]) } + io.write_byte(w, '-') + for index in 10 ..< 16 { write_octet(w, id[index]) } +} + +/* +Convert a UUID to a string in the 8-4-4-4-12 format. + +*Allocates Using Provided Allocator* + +Inputs: +- id: The identifier to convert. +- allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: #caller_location) + +Returns: +- str: The allocated and converted string. +- error: An optional allocator error if one occured, `nil` otherwise. +*/ +to_string_allocated :: proc( + id: Identifier, + allocator := context.allocator, + loc := #caller_location, +) -> ( + str: string, + error: runtime.Allocator_Error, +) #optional_allocator_error { + buf := make([]byte, EXPECTED_LENGTH, allocator, loc) or_return + builder := strings.builder_from_bytes(buf[:]) + unsafe_write(strings.to_writer(&builder), id) + return strings.to_string(builder), nil +} + +/* +Convert a UUID to a string in the 8-4-4-4-12 format. + +Inputs: +- id: The identifier to convert. +- buffer: A byte buffer to store the result. Must be at least 32 bytes large. +- loc: The caller location for debugging purposes (default: #caller_location) + +Returns: +- str: The converted string which will be stored in `buffer`. +*/ +to_string_buffer :: proc( + id: Identifier, + buffer: []byte, + loc := #caller_location, +) -> ( + str: string, +) { + assert(len(buffer) >= EXPECTED_LENGTH, "The buffer provided is not at least 32 bytes large.", loc) + builder := strings.builder_from_bytes(buffer) + unsafe_write(strings.to_writer(&builder), id) + return strings.to_string(builder) +} + +to_string :: proc { + to_string_allocated, + to_string_buffer, +} diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index be958baaa..acced262a 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -33,7 +33,7 @@ print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error written += fmt.wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) if len(doc.doctype.rest) > 0 { - fmt.wprintf(writer, "\t%v\n", doc.doctype.rest) + fmt.wprintf(writer, "\t%v\n", doc.doctype.rest) } } @@ -42,10 +42,10 @@ print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error } if len(doc.elements) > 0 { - fmt.wprintln(writer, " --- ") - print_element(writer, doc, 0) - fmt.wprintln(writer, " --- ") - } + fmt.wprintln(writer, " --- ") + print_element(writer, doc, 0) + fmt.wprintln(writer, " --- ") + } return written, .None } diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 2d06038b7..a2bbaf28e 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -126,7 +126,7 @@ error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { t.error_count += 1 } -@(optimization_mode="speed") +@(optimization_mode="favor_size") advance_rune :: proc(t: ^Tokenizer) { #no_bounds_check { /* @@ -170,7 +170,7 @@ peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte { return 0 } -@(optimization_mode="speed") +@(optimization_mode="favor_size") skip_whitespace :: proc(t: ^Tokenizer) { for { switch t.ch { @@ -182,7 +182,7 @@ skip_whitespace :: proc(t: ^Tokenizer) { } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") is_letter :: proc(r: rune) -> bool { if r < utf8.RUNE_SELF { switch r { @@ -296,7 +296,7 @@ skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { return } -@(optimization_mode="speed") +@(optimization_mode="favor_size") scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) { err = .None @@ -414,4 +414,4 @@ scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token { lit = string(t.src[offset : t.offset]) } return Token{kind, lit, pos} -} \ No newline at end of file +} diff --git a/core/flags/LICENSE b/core/flags/LICENSE new file mode 100644 index 000000000..e4e21e62d --- /dev/null +++ b/core/flags/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2024, Feoramund + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/core/flags/constants.odin b/core/flags/constants.odin new file mode 100644 index 000000000..ab3dc9a0a --- /dev/null +++ b/core/flags/constants.odin @@ -0,0 +1,38 @@ +package flags + +import "core:time" + +// Set to true to compile with support for core named types disabled, as a +// fallback in the event your platform does not support one of the types, or +// you have no need for them and want a smaller binary. +NO_CORE_NAMED_TYPES :: #config(ODIN_CORE_FLAGS_NO_CORE_NAMED_TYPES, false) + +// Override support for parsing `time` types. +IMPORTING_TIME :: #config(ODIN_CORE_FLAGS_USE_TIME, time.IS_SUPPORTED) + +// Override support for parsing `net` types. +// TODO: Update this when the BSDs are supported. +IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin) + +TAG_ARGS :: "args" +SUBTAG_NAME :: "name" +SUBTAG_POS :: "pos" +SUBTAG_REQUIRED :: "required" +SUBTAG_HIDDEN :: "hidden" +SUBTAG_VARIADIC :: "variadic" +SUBTAG_FILE :: "file" +SUBTAG_PERMS :: "perms" +SUBTAG_INDISTINCT :: "indistinct" + +TAG_USAGE :: "usage" + +UNDOCUMENTED_FLAG :: "" + +INTERNAL_VARIADIC_FLAG :: "varg" + +RESERVED_HELP_FLAG :: "help" +RESERVED_HELP_FLAG_SHORT :: "h" + +// If there are more than this number of flags in total, only the required and +// positional flags will be shown in the one-line usage summary. +ONE_LINE_FLAG_CUTOFF_COUNT :: 16 diff --git a/core/flags/doc.odin b/core/flags/doc.odin new file mode 100644 index 000000000..c3663c419 --- /dev/null +++ b/core/flags/doc.odin @@ -0,0 +1,181 @@ +/* +package flags implements a command-line argument parser. + +It works by using Odin's run-time type information to determine where and how +to store data on a struct provided by the program. Type conversion is handled +automatically and errors are reported with useful messages. + + +Command-Line Syntax: + +Arguments are treated differently depending on how they're formatted. +The format is similar to the Odin binary's way of handling compiler flags. + +``` +type handling +------------ ------------------------ + depends on struct layout +- set a bool true +- set flag to option +- set flag to option, alternative syntax +-:= set map[key] to value +``` + + +Struct Tags: + +Users of the `core:encoding/json` package may be familiar with using tags to +annotate struct metadata. The same technique is used here to annotate where +arguments should go and which are required. + +Under the `args` tag, there are the following subtags: + +- `name=S`: set `S` as the flag's name. +- `pos=N`: place positional argument `N` into this flag. +- `hidden`: hide this flag from the usage documentation. +- `required`: cause verification to fail if this argument is not set. +- `variadic`: take all remaining arguments when set, UNIX-style only. +- `file`: for `os.Handle` types, file open mode. +- `perms`: for `os.Handle` types, file open permissions. +- `indistinct`: allow the setting of distinct types by their base type. + +`required` may be given a range specifier in the following formats: +``` +min + ( + error: string, + handled: bool, + alloc_error: runtime.Allocator_Error, +) { + if data_type == Fixed_Point1_1 { + handled = true + ptr := cast(^Fixed_Point1_1)data + + // precision := flags.get_subtag(args_tag, "precision") + + if len(unparsed_value) == 3 { + ptr.integer = unparsed_value[0] - '0' + ptr.fractional = unparsed_value[2] - '0' + } else { + error = "Incorrect format. Must be in the form of `i.f`." + } + + // Perform sanity checking here in the type parsing phase. + // + // The validation phase is flag-specific. + if !(0 <= ptr.integer && ptr.integer < 10) || !(0 <= ptr.fractional && ptr.fractional < 10) { + error = "Incorrect format. Must be between `0.0` and `9.9`." + } + } + + return +} + +my_custom_flag_checker :: proc( + model: rawptr, + name: string, + value: any, + args_tag: string, +) -> (error: string) { + if name == "iterations" { + v := value.(int) + if !(1 <= v && v < 5) { + error = "Iterations only supports 1 ..< 5." + } + } + + return +} + +Distinct_Int :: distinct int + +main :: proc() { + Options :: struct { + + file: os.Handle `args:"pos=0,required,file=r" usage:"Input file."`, + output: os.Handle `args:"pos=1,file=cw" usage:"Output file."`, + + hub: net.Host_Or_Endpoint `usage:"Internet address to contact for updates."`, + schedule: datetime.DateTime `usage:"Launch tasks at this time."`, + + opt: Optimization_Level `usage:"Optimization level."`, + todo: [dynamic]string `usage:"Todo items."`, + + accuracy: Fixed_Point1_1 `args:"required" usage:"Lenience in FLOP calculations."`, + iterations: int `usage:"Run this many times."`, + + // Note how the parser will transform this flag's name into `special-int`. + special_int: Distinct_Int `args:"indistinct" usage:"Able to set distinct types."`, + + quat: quaternion256, + + bits: bit_set[0..<8], + + // Many different requirement styles: + + // gadgets: [dynamic]string `args:"required=1" usage:"gadgets"`, + // widgets: [dynamic]string `args:"required=<3" usage:"widgets"`, + // foos: [dynamic]string `args:"required=2<4"`, + // bars: [dynamic]string `args:"required=3<4"`, + // bots: [dynamic]string `args:"required"`, + + // (Maps) Only available in Odin style: + + // assignments: map[string]u8 `args:"name=assign" usage:"Number of jobs per worker."`, + + // (Variadic) Only available in UNIX style: + + // bots: [dynamic]string `args:"variadic=2,required"`, + + verbose: bool `usage:"Show verbose output."`, + debug: bool `args:"hidden" usage:"print debug info"`, + + varg: [dynamic]string `usage:"Any extra arguments go here."`, + } + + opt: Options + style : flags.Parsing_Style = .Odin + + flags.register_type_setter(my_custom_type_setter) + flags.register_flag_checker(my_custom_flag_checker) + flags.parse_or_exit(&opt, os.args, style) + + fmt.printfln("%#v", opt) + + if opt.output != 0 { + os.write_string(opt.output, "Hellope!\n") + } +} diff --git a/core/flags/internal_assignment.odin b/core/flags/internal_assignment.odin new file mode 100644 index 000000000..bb49977eb --- /dev/null +++ b/core/flags/internal_assignment.odin @@ -0,0 +1,262 @@ +//+private +package flags + +import "base:intrinsics" +@require import "base:runtime" +import "core:container/bit_array" +@require import "core:fmt" +@require import "core:mem" +import "core:reflect" +@require import "core:strconv" +@require import "core:strings" + +// Push a positional argument onto a data struct, checking for specified +// positionals first before adding it to a fallback field. +@(optimization_mode="favor_size") +push_positional :: #force_no_inline proc (model: ^$T, parser: ^Parser, arg: string) -> (error: Error) { + if bit_array.get(&parser.filled_pos, parser.filled_pos.max_index) { + // The max index is set, which means we're out of space. + // Add one free bit by setting the index above to false. + bit_array.set(&parser.filled_pos, 1 + parser.filled_pos.max_index, false) + } + + pos: int = --- + { + iter := bit_array.make_iterator(&parser.filled_pos) + ok: bool + pos, ok = bit_array.iterate_by_unset(&iter) + + // This may be an allocator error. + assert(ok, "Unable to find a free spot in the positional bit_array.") + } + + field, index, has_pos_assigned := get_field_by_pos(model, pos) + + if !has_pos_assigned { + when intrinsics.type_has_field(T, INTERNAL_VARIADIC_FLAG) { + // Add it to the fallback array. + field = reflect.struct_field_by_name(T, INTERNAL_VARIADIC_FLAG) + } else { + return Parse_Error { + .Extra_Positional, + fmt.tprintf("Got extra positional argument `%s` with nowhere to store it.", arg), + } + } + } + + ptr := cast(rawptr)(cast(uintptr)model + field.offset) + args_tag, _ := reflect.struct_tag_lookup(field.tag, TAG_ARGS) + field_name := get_field_name(field) + error = parse_and_set_pointer_by_type(ptr, arg, field.type, args_tag) + #partial switch &specific_error in error { + case Parse_Error: + specific_error.message = fmt.tprintf("Unable to set positional #%i (%s) of type %v to `%s`.%s%s", + pos, + field_name, + field.type, + arg, + " " if len(specific_error.message) > 0 else "", + specific_error.message) + case nil: + bit_array.set(&parser.filled_pos, pos) + bit_array.set(&parser.fields_set, index) + } + + return +} + +register_field :: proc(parser: ^Parser, field: reflect.Struct_Field, index: int) { + if pos, ok := get_field_pos(field); ok { + bit_array.set(&parser.filled_pos, pos) + } + + bit_array.set(&parser.fields_set, index) +} + +// Set a `-flag` argument, Odin-style. +@(optimization_mode="favor_size") +set_odin_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (error: Error) { + // We make a special case for help requests. + switch name { + case RESERVED_HELP_FLAG, RESERVED_HELP_FLAG_SHORT: + return Help_Request{} + } + + field, index := get_field_by_name(model, name) or_return + + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Boolean: + ptr := cast(^bool)(cast(uintptr)model + field.offset) + ptr^ = true + case: + return Parse_Error { + .Bad_Value, + fmt.tprintf("Unable to set `%s` of type %v to true.", name, field.type), + } + } + + register_field(parser, field, index) + return +} + +// Set a `-flag` argument, UNIX-style. +@(optimization_mode="favor_size") +set_unix_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (future_args: int, error: Error) { + // We make a special case for help requests. + switch name { + case RESERVED_HELP_FLAG, RESERVED_HELP_FLAG_SHORT: + return 0, Help_Request{} + } + + field, index := get_field_by_name(model, name) or_return + + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Boolean: + ptr := cast(^bool)(cast(uintptr)model + field.offset) + ptr^ = true + case runtime.Type_Info_Dynamic_Array: + future_args = 1 + if tag, ok := reflect.struct_tag_lookup(field.tag, TAG_ARGS); ok { + if length, is_variadic := get_struct_subtag(tag, SUBTAG_VARIADIC); is_variadic { + // Variadic arrays may specify how many arguments they consume at once. + // Otherwise, they take everything that's left. + if value, value_ok := strconv.parse_u64_of_base(length, 10); value_ok { + future_args = cast(int)value + } else { + future_args = max(int) + } + } + } + case: + // `--flag`, waiting on its value. + future_args = 1 + } + + register_field(parser, field, index) + return +} + +// Set a `-flag:option` argument. +@(optimization_mode="favor_size") +set_option :: proc(model: ^$T, parser: ^Parser, name, option: string) -> (error: Error) { + field, index := get_field_by_name(model, name) or_return + + if len(option) == 0 { + return Parse_Error { + .No_Value, + fmt.tprintf("Setting `%s` to an empty value is meaningless.", name), + } + } + + // Guard against incorrect syntax. + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Map: + return Parse_Error { + .No_Value, + fmt.tprintf("Unable to set `%s` of type %v to `%s`. Are you missing an `=`? The correct format is `map:key=value`.", name, field.type, option), + } + } + + ptr := cast(rawptr)(cast(uintptr)model + field.offset) + args_tag := reflect.struct_tag_get(field.tag, TAG_ARGS) + error = parse_and_set_pointer_by_type(ptr, option, field.type, args_tag) + #partial switch &specific_error in error { + case Parse_Error: + specific_error.message = fmt.tprintf("Unable to set `%s` of type %v to `%s`.%s%s", + name, + field.type, + option, + " " if len(specific_error.message) > 0 else "", + specific_error.message) + case nil: + register_field(parser, field, index) + } + + return +} + +// Set a `-map:key=value` argument. +@(optimization_mode="favor_size") +set_key_value :: proc(model: ^$T, parser: ^Parser, name, key, value: string) -> (error: Error) { + field, index := get_field_by_name(model, name) or_return + + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Map: + key := key + key_ptr := cast(rawptr)&key + key_cstr: cstring + if reflect.is_cstring(specific_type_info.key) { + // We clone the key here, because it's liable to be a slice of an + // Odin string, and we need to put a NUL terminator in it. + key_cstr = strings.clone_to_cstring(key) + key_ptr = &key_cstr + } + defer if key_cstr != nil { + delete(key_cstr) + } + + raw_map := (^runtime.Raw_Map)(cast(uintptr)model + field.offset) + + hash := specific_type_info.map_info.key_hasher(key_ptr, runtime.map_seed(raw_map^)) + + backing_alloc := false + elem_backing: []byte + value_ptr: rawptr + + if raw_map.allocator.procedure == nil { + raw_map.allocator = context.allocator + } else { + value_ptr = runtime.__dynamic_map_get(raw_map, + specific_type_info.map_info, + hash, + key_ptr, + ) + } + + if value_ptr == nil { + alloc_error: runtime.Allocator_Error = --- + elem_backing, alloc_error = mem.alloc_bytes(specific_type_info.value.size, specific_type_info.value.align) + if elem_backing == nil { + return Parse_Error { + alloc_error, + "Failed to allocate element backing for map value.", + } + } + + backing_alloc = true + value_ptr = raw_data(elem_backing) + } + + args_tag, _ := reflect.struct_tag_lookup(field.tag, TAG_ARGS) + error = parse_and_set_pointer_by_type(value_ptr, value, specific_type_info.value, args_tag) + #partial switch &specific_error in error { + case Parse_Error: + specific_error.message = fmt.tprintf("Unable to set `%s` of type %v with key=value: `%s`=`%s`.%s%s", + name, + field.type, + key, + value, + " " if len(specific_error.message) > 0 else "", + specific_error.message) + } + + if backing_alloc { + runtime.__dynamic_map_set(raw_map, + specific_type_info.map_info, + hash, + key_ptr, + value_ptr, + ) + + delete(elem_backing) + } + + register_field(parser, field, index) + return + } + + return Parse_Error { + .Bad_Value, + fmt.tprintf("Unable to set `%s` of type %v with key=value: `%s`=`%s`.", name, field.type, key, value), + } +} diff --git a/core/flags/internal_parsing.odin b/core/flags/internal_parsing.odin new file mode 100644 index 000000000..7a769b17c --- /dev/null +++ b/core/flags/internal_parsing.odin @@ -0,0 +1,170 @@ +//+private +package flags + +import "core:container/bit_array" +import "core:strconv" +import "core:strings" + +// Used to group state together. +Parser :: struct { + // `fields_set` tracks which arguments have been set. + // It uses their struct field index. + fields_set: bit_array.Bit_Array, + + // `filled_pos` tracks which arguments have been filled into positional + // spots, much like how `fmt` treats them. + filled_pos: bit_array.Bit_Array, +} + +parse_one_odin_arg :: proc(model: ^$T, parser: ^Parser, arg: string) -> (error: Error) { + arg := arg + + if strings.has_prefix(arg, "-") { + arg = arg[1:] + + flag: string + assignment_rune: rune + find_assignment: for r, i in arg { + switch r { + case ':', '=': + assignment_rune = r + flag = arg[:i] + arg = arg[1 + i:] + break find_assignment + case: + continue find_assignment + } + } + + if assignment_rune == 0 { + if len(arg) == 0 { + return Parse_Error { + .No_Flag, + "No flag was given.", + } + } + + // -flag + set_odin_flag(model, parser, arg) or_return + + } else if assignment_rune == ':' { + // -flag:option -map:key=value + error = set_option(model, parser, flag, arg) + + if error != nil { + // -flag:option did not work, so this may be a -map:key=value set. + find_equals: for r, i in arg { + if r == '=' { + key := arg[:i] + arg = arg[1 + i:] + error = set_key_value(model, parser, flag, key, arg) + break find_equals + } + } + } + + } else { + // -flag=option, alternative syntax + set_option(model, parser, flag, arg) or_return + } + + } else { + // positional + error = push_positional(model, parser, arg) + } + + return +} + +parse_one_unix_arg :: proc(model: ^$T, parser: ^Parser, arg: string) -> ( + future_args: int, + current_flag: string, + error: Error, +) { + arg := arg + + if strings.has_prefix(arg, "-") { + // -flag + arg = arg[1:] + + if strings.has_prefix(arg, "-") { + // Allow `--` to function as `-`. + arg = arg[1:] + + if len(arg) == 0 { + // `--`, and only `--`. + // Everything from now on will be treated as an argument. + future_args = max(int) + current_flag = INTERNAL_VARIADIC_FLAG + return + } + } + + flag: string + find_assignment: for r, i in arg { + if r == '=' { + // --flag=option + flag = arg[:i] + arg = arg[1 + i:] + error = set_option(model, parser, flag, arg) + return + } + } + + // --flag option, potentially + future_args = set_unix_flag(model, parser, arg) or_return + current_flag = arg + + } else { + // positional + error = push_positional(model, parser, arg) + } + + return +} + +// Parse a number of requirements specifier. +// +// Examples: +// +// `min` +// ` (minimum, maximum: int, ok: bool) { + if len(str) == 0 { + return 1, max(int), true + } + + if less_than := strings.index_byte(str, '<'); less_than != -1 { + if len(str) == 1 { + return 0, 0, false + } + + #no_bounds_check left := str[:less_than] + #no_bounds_check right := str[1 + less_than:] + + if left_value, parse_ok := strconv.parse_u64_of_base(left, 10); parse_ok { + minimum = cast(int)left_value + } else if len(left) > 0 { + return 0, 0, false + } + + if right_value, parse_ok := strconv.parse_u64_of_base(right, 10); parse_ok { + maximum = cast(int)right_value + } else if len(right) > 0 { + return 0, 0, false + } else { + maximum = max(int) + } + } else { + if value, parse_ok := strconv.parse_u64_of_base(str, 10); parse_ok { + minimum = cast(int)value + maximum = max(int) + } else { + return 0, 0, false + } + } + + ok = true + return +} diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin new file mode 100644 index 000000000..ac39eaa8b --- /dev/null +++ b/core/flags/internal_rtti.odin @@ -0,0 +1,529 @@ +//+private +package flags + +import "base:intrinsics" +import "base:runtime" +import "core:fmt" +import "core:mem" +import "core:os" +import "core:reflect" +import "core:strconv" +import "core:strings" +@require import "core:time" +@require import "core:time/datetime" +import "core:unicode/utf8" + +@(optimization_mode="favor_size") +parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: ^runtime.Type_Info) -> bool { + bounded_int :: proc(value, min, max: i128) -> (result: i128, ok: bool) { + return value, min <= value && value <= max + } + + bounded_uint :: proc(value, max: u128) -> (result: u128, ok: bool) { + return value, value <= max + } + + // NOTE(Feoramund): This procedure has been written with the goal in mind + // of generating the least amount of assembly, given that this library is + // likely to be called once and forgotten. + // + // I've rewritten the switch tables below in 3 different ways, and the + // current one generates the least amount of code for me on Linux AMD64. + // + // The other two ways were: + // + // - the original implementation: use of parametric polymorphism which led + // to dozens of functions generated, one for each type. + // + // - a `value, ok` assignment statement with the `or_return` done at the + // end of the switch, instead of inline. + // + // This seems to be the smallest way for now. + + #partial switch specific_type_info in type_info.variant { + case runtime.Type_Info_Integer: + if specific_type_info.signed { + value := strconv.parse_i128(str) or_return + switch type_info.id { + case i8: (^i8) (ptr)^ = cast(i8) bounded_int(value, cast(i128)min(i8), cast(i128)max(i8) ) or_return + case i16: (^i16) (ptr)^ = cast(i16) bounded_int(value, cast(i128)min(i16), cast(i128)max(i16) ) or_return + case i32: (^i32) (ptr)^ = cast(i32) bounded_int(value, cast(i128)min(i32), cast(i128)max(i32) ) or_return + case i64: (^i64) (ptr)^ = cast(i64) bounded_int(value, cast(i128)min(i64), cast(i128)max(i64) ) or_return + case i128: (^i128) (ptr)^ = value + + case int: (^int) (ptr)^ = cast(int) bounded_int(value, cast(i128)min(int), cast(i128)max(int) ) or_return + + case i16le: (^i16le) (ptr)^ = cast(i16le) bounded_int(value, cast(i128)min(i16le), cast(i128)max(i16le) ) or_return + case i32le: (^i32le) (ptr)^ = cast(i32le) bounded_int(value, cast(i128)min(i32le), cast(i128)max(i32le) ) or_return + case i64le: (^i64le) (ptr)^ = cast(i64le) bounded_int(value, cast(i128)min(i64le), cast(i128)max(i64le) ) or_return + case i128le: (^i128le)(ptr)^ = cast(i128le) bounded_int(value, cast(i128)min(i128le), cast(i128)max(i128le)) or_return + + case i16be: (^i16be) (ptr)^ = cast(i16be) bounded_int(value, cast(i128)min(i16be), cast(i128)max(i16be) ) or_return + case i32be: (^i32be) (ptr)^ = cast(i32be) bounded_int(value, cast(i128)min(i32be), cast(i128)max(i32be) ) or_return + case i64be: (^i64be) (ptr)^ = cast(i64be) bounded_int(value, cast(i128)min(i64be), cast(i128)max(i64be) ) or_return + case i128be: (^i128be)(ptr)^ = cast(i128be) bounded_int(value, cast(i128)min(i128be), cast(i128)max(i128be)) or_return + } + } else { + value := strconv.parse_u128(str) or_return + switch type_info.id { + case u8: (^u8) (ptr)^ = cast(u8) bounded_uint(value, cast(u128)max(u8) ) or_return + case u16: (^u16) (ptr)^ = cast(u16) bounded_uint(value, cast(u128)max(u16) ) or_return + case u32: (^u32) (ptr)^ = cast(u32) bounded_uint(value, cast(u128)max(u32) ) or_return + case u64: (^u64) (ptr)^ = cast(u64) bounded_uint(value, cast(u128)max(u64) ) or_return + case u128: (^u128) (ptr)^ = value + + case uint: (^uint) (ptr)^ = cast(uint) bounded_uint(value, cast(u128)max(uint) ) or_return + case uintptr: (^uintptr)(ptr)^ = cast(uintptr) bounded_uint(value, cast(u128)max(uintptr)) or_return + + case u16le: (^u16le) (ptr)^ = cast(u16le) bounded_uint(value, cast(u128)max(u16le) ) or_return + case u32le: (^u32le) (ptr)^ = cast(u32le) bounded_uint(value, cast(u128)max(u32le) ) or_return + case u64le: (^u64le) (ptr)^ = cast(u64le) bounded_uint(value, cast(u128)max(u64le) ) or_return + case u128le: (^u128le) (ptr)^ = cast(u128le) bounded_uint(value, cast(u128)max(u128le) ) or_return + + case u16be: (^u16be) (ptr)^ = cast(u16be) bounded_uint(value, cast(u128)max(u16be) ) or_return + case u32be: (^u32be) (ptr)^ = cast(u32be) bounded_uint(value, cast(u128)max(u32be) ) or_return + case u64be: (^u64be) (ptr)^ = cast(u64be) bounded_uint(value, cast(u128)max(u64be) ) or_return + case u128be: (^u128be) (ptr)^ = cast(u128be) bounded_uint(value, cast(u128)max(u128be) ) or_return + } + } + + case runtime.Type_Info_Rune: + if utf8.rune_count_in_string(str) != 1 { + return false + } + + (^rune)(ptr)^ = utf8.rune_at_pos(str, 0) + + case runtime.Type_Info_Float: + value := strconv.parse_f64(str) or_return + switch type_info.id { + case f16: (^f16) (ptr)^ = cast(f16) value + case f32: (^f32) (ptr)^ = cast(f32) value + case f64: (^f64) (ptr)^ = value + + case f16le: (^f16le)(ptr)^ = cast(f16le) value + case f32le: (^f32le)(ptr)^ = cast(f32le) value + case f64le: (^f64le)(ptr)^ = cast(f64le) value + + case f16be: (^f16be)(ptr)^ = cast(f16be) value + case f32be: (^f32be)(ptr)^ = cast(f32be) value + case f64be: (^f64be)(ptr)^ = cast(f64be) value + } + + case runtime.Type_Info_Complex: + value := strconv.parse_complex128(str) or_return + switch type_info.id { + case complex32: (^complex32) (ptr)^ = (complex32)(value) + case complex64: (^complex64) (ptr)^ = (complex64)(value) + case complex128: (^complex128)(ptr)^ = value + } + + case runtime.Type_Info_Quaternion: + value := strconv.parse_quaternion256(str) or_return + switch type_info.id { + case quaternion64: (^quaternion64) (ptr)^ = (quaternion64)(value) + case quaternion128: (^quaternion128)(ptr)^ = (quaternion128)(value) + case quaternion256: (^quaternion256)(ptr)^ = value + } + + case runtime.Type_Info_String: + if specific_type_info.is_cstring { + cstr_ptr := (^cstring)(ptr) + if cstr_ptr != nil { + // Prevent memory leaks from us setting this value multiple times. + delete(cstr_ptr^) + } + cstr_ptr^ = strings.clone_to_cstring(str) + } else { + (^string)(ptr)^ = str + } + + case runtime.Type_Info_Boolean: + value := strconv.parse_bool(str) or_return + switch type_info.id { + case bool: (^bool)(ptr)^ = value + case b8: (^b8) (ptr)^ = b8(value) + case b16: (^b16) (ptr)^ = b16(value) + case b32: (^b32) (ptr)^ = b32(value) + case b64: (^b64) (ptr)^ = b64(value) + } + + case runtime.Type_Info_Bit_Set: + // Parse a string of 1's and 0's, from left to right, + // least significant bit to most significant bit. + value: u128 + + // NOTE: `upper` is inclusive, i.e: `0..=31` + max_bit_index := u128(1 + specific_type_info.upper - specific_type_info.lower) + bit_index := u128(0) + #no_bounds_check for string_index in 0.. (error: Error) { + #partial switch specific_type_info in type_info.variant { + case runtime.Type_Info_Named: + if global_custom_type_setter != nil { + // The program gets to go first. + error_message, handled, alloc_error := global_custom_type_setter(ptr, type_info.id, str, arg_tag) + + if alloc_error != nil { + // There was an allocation error. Bail out. + return Parse_Error { + alloc_error, + "Custom type setter encountered allocation error.", + } + } + + if handled { + // The program handled the type. + + if len(error_message) != 0 { + // However, there was an error. Pass it along. + error = Parse_Error { + .Bad_Value, + error_message, + } + } + + return + } + } + + // Might be a named enum. Need to check here first, since we handle all enums. + if enum_type_info, is_enum := specific_type_info.base.variant.(runtime.Type_Info_Enum); is_enum { + if value, ok := reflect.enum_from_name_any(type_info.id, str); ok { + set_unbounded_integer_by_type(ptr, value, enum_type_info.base.id) + } else { + return Parse_Error { + .Bad_Value, + fmt.tprintf("Invalid value name. Valid names are: %s", enum_type_info.names), + } + } + } else { + parse_and_set_pointer_by_named_type(ptr, str, type_info.id, arg_tag, &error) + + if error != nil { + // So far, it's none of the types that we recognize. + // Check to see if we can set it by base type, if allowed. + if _, is_indistinct := get_struct_subtag(arg_tag, SUBTAG_INDISTINCT); is_indistinct { + return parse_and_set_pointer_by_type(ptr, str, specific_type_info.base, arg_tag) + } + } + } + + case runtime.Type_Info_Dynamic_Array: + ptr := cast(^runtime.Raw_Dynamic_Array)ptr + + // Try to convert the value first. + elem_backing, alloc_error := mem.alloc_bytes(specific_type_info.elem.size, specific_type_info.elem.align) + if alloc_error != nil { + return Parse_Error { + alloc_error, + "Failed to allocate element backing for dynamic array.", + } + } + defer delete(elem_backing) + parse_and_set_pointer_by_type(raw_data(elem_backing), str, specific_type_info.elem, arg_tag) or_return + + if !runtime.__dynamic_array_resize(ptr, specific_type_info.elem.size, specific_type_info.elem.align, ptr.len + 1) { + // NOTE: This is purely an assumption that it's OOM. + // Regardless, the resize failed. + return Parse_Error { + runtime.Allocator_Error.Out_Of_Memory, + "Failed to resize dynamic array.", + } + } + + subptr := rawptr( + uintptr(ptr.data) + + uintptr((ptr.len - 1) * specific_type_info.elem.size)) + mem.copy(subptr, raw_data(elem_backing), len(elem_backing)) + + case runtime.Type_Info_Enum: + // This is a nameless enum. + // The code here is virtually the same as above for named enums. + if value, ok := reflect.enum_from_name_any(type_info.id, str); ok { + set_unbounded_integer_by_type(ptr, value, specific_type_info.base.id) + } else { + return Parse_Error { + .Bad_Value, + fmt.tprintf("Invalid value name. Valid names are: %s", specific_type_info.names), + } + } + + case: + if !parse_and_set_pointer_by_base_type(ptr, str, type_info) { + return Parse_Error { + // The caller will add more details. + .Bad_Value, + "", + } + } + } + + return +} + +get_struct_subtag :: get_subtag + +get_field_name :: proc(field: reflect.Struct_Field) -> string { + if args_tag, ok := reflect.struct_tag_lookup(field.tag, TAG_ARGS); ok { + if name_subtag, name_ok := get_struct_subtag(args_tag, SUBTAG_NAME); name_ok { + return name_subtag + } + } + + name, _ := strings.replace_all(field.name, "_", "-", context.temp_allocator) + return name +} + +get_field_pos :: proc(field: reflect.Struct_Field) -> (int, bool) { + if args_tag, ok := reflect.struct_tag_lookup(field.tag, TAG_ARGS); ok { + if pos_subtag, pos_ok := get_struct_subtag(args_tag, SUBTAG_POS); pos_ok { + if value, parse_ok := strconv.parse_u64_of_base(pos_subtag, 10); parse_ok { + return int(value), true + } + } + } + + return 0, false +} + +// Get a struct field by its field name or `name` subtag. +get_field_by_name :: proc(model: ^$T, name: string) -> (result: reflect.Struct_Field, index: int, error: Error) { + for field, i in reflect.struct_fields_zipped(T) { + if get_field_name(field) == name { + return field, i, nil + } + } + + error = Parse_Error { + .Missing_Flag, + fmt.tprintf("Unable to find any flag named `%s`.", name), + } + return +} + +// Get a struct field by its `pos` subtag. +get_field_by_pos :: proc(model: ^$T, pos: int) -> (result: reflect.Struct_Field, index: int, ok: bool) { + for field, i in reflect.struct_fields_zipped(T) { + args_tag := reflect.struct_tag_lookup(field.tag, TAG_ARGS) or_continue + pos_subtag := get_struct_subtag(args_tag, SUBTAG_POS) or_continue + + value, parse_ok := strconv.parse_u64_of_base(pos_subtag, 10) + if parse_ok && cast(int)value == pos { + return field, i, true + } + } + + return +} diff --git a/core/flags/internal_rtti_nonbsd.odin b/core/flags/internal_rtti_nonbsd.odin new file mode 100644 index 000000000..196c27ab8 --- /dev/null +++ b/core/flags/internal_rtti_nonbsd.odin @@ -0,0 +1,31 @@ +//+private +//+build !freebsd !netbsd !openbsd +package flags + +import "core:net" + +// This proc exists purely as a workaround for import restrictions. +// Returns true if caller should return early. +try_net_parse_workaround :: #force_inline proc ( + data_type: typeid, + str: string, + ptr: rawptr, + out_error: ^Error, +) -> bool { + if data_type == net.Host_Or_Endpoint { + addr, net_error := net.parse_hostname_or_endpoint(str) + if net_error != nil { + // We pass along `net.Error` here. + out_error^ = Parse_Error { + net_error, + "Invalid Host/Endpoint.", + } + return true + } + + (cast(^net.Host_Or_Endpoint)ptr)^ = addr + return true + } + + return false +} diff --git a/core/flags/internal_validation.odin b/core/flags/internal_validation.odin new file mode 100644 index 000000000..b71cf9fe7 --- /dev/null +++ b/core/flags/internal_validation.odin @@ -0,0 +1,244 @@ +//+private +package flags + +@require import "base:runtime" +@require import "core:container/bit_array" +@require import "core:fmt" +@require import "core:mem" +@require import "core:os" +@require import "core:reflect" +@require import "core:strconv" +@require import "core:strings" + +// This proc is used to assert that `T` meets the expectations of the library. +@(optimization_mode="favor_size", disabled=ODIN_DISABLE_ASSERT) +validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_location) { + positionals_assigned_so_far: bit_array.Bit_Array + defer bit_array.destroy(&positionals_assigned_so_far) + + check_fields: for field in reflect.struct_fields_zipped(T) { + if style == .Unix { + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Map: + fmt.panicf("%T.%s is a map type, and these are not supported in UNIX-style parsing mode.", + model_type, field.name, loc = loc) + } + } + + name_is_safe := true + defer { + fmt.assertf(name_is_safe, "%T.%s is using a reserved name.", + model_type, field.name, loc = loc) + } + + switch field.name { + case RESERVED_HELP_FLAG, RESERVED_HELP_FLAG_SHORT: + name_is_safe = false + } + + args_tag, ok := reflect.struct_tag_lookup(field.tag, TAG_ARGS) + if !ok { + // If it has no args tag, then we've checked all we need to. + // Most of this proc is validating that the subtags are sane. + continue + } + + if name, has_name := get_struct_subtag(args_tag, SUBTAG_NAME); has_name { + fmt.assertf(len(name) > 0, "%T.%s has a zero-length `%s`.", + model_type, field.name, SUBTAG_NAME, loc = loc) + + fmt.assertf(strings.index(name, " ") == -1, "%T.%s has a `%s` with spaces in it.", + model_type, field.name, SUBTAG_NAME, loc = loc) + + switch name { + case RESERVED_HELP_FLAG, RESERVED_HELP_FLAG_SHORT: + name_is_safe = false + continue check_fields + case: + name_is_safe = true + } + } + + if pos_str, has_pos := get_struct_subtag(args_tag, SUBTAG_POS); has_pos { + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Map: + fmt.panicf("%T.%s has `%s` defined, and this does not make sense on a map type.", + model_type, field.name, SUBTAG_POS, loc = loc) + } + + pos_value, pos_ok := strconv.parse_u64_of_base(pos_str, 10) + fmt.assertf(pos_ok, "%T.%s has `%s` defined as %q but cannot be parsed a base-10 integer >= 0.", + model_type, field.name, SUBTAG_POS, pos_str, loc = loc) + fmt.assertf(!bit_array.get(&positionals_assigned_so_far, pos_value), "%T.%s has `%s` set to #%i, but that position has already been assigned to another flag.", + model_type, field.name, SUBTAG_POS, pos_value, loc = loc) + bit_array.set(&positionals_assigned_so_far, pos_value) + } + + required_min, required_max: int + if requirement, is_required := get_struct_subtag(args_tag, SUBTAG_REQUIRED); is_required { + fmt.assertf(!reflect.is_boolean(field.type), "%T.%s is a required boolean. This is disallowed.", + model_type, field.name, loc = loc) + + fmt.assertf(field.name != INTERNAL_VARIADIC_FLAG, "%T.%s is defined as required. This is disallowed.", + model_type, field.name, loc = loc) + + if len(requirement) > 0 { + if required_min, required_max, ok = parse_requirements(requirement); ok { + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Dynamic_Array: + fmt.assertf(required_min != required_max, "%T.%s has `%s` defined as %q, but the minimum and maximum are the same. Increase the maximum by 1 for an exact number of arguments: (%i<%i)", + model_type, + field.name, + SUBTAG_REQUIRED, + requirement, + required_min, + 1 + required_max, + loc = loc) + + fmt.assertf(required_min < required_max, "%T.%s has `%s` defined as %q, but the minimum and maximum are swapped.", + model_type, field.name, SUBTAG_REQUIRED, requirement, loc = loc) + + case: + fmt.panicf("%T.%s has `%s` defined as %q, but ranges are only supported on dynamic arrays.", + model_type, field.name, SUBTAG_REQUIRED, requirement, loc = loc) + } + } else { + fmt.panicf("%T.%s has `%s` defined as %q, but it cannot be parsed as a valid range.", + model_type, field.name, SUBTAG_REQUIRED, requirement, loc = loc) + } + } + } + + if length, is_variadic := get_struct_subtag(args_tag, SUBTAG_VARIADIC); is_variadic { + if value, parse_ok := strconv.parse_u64_of_base(length, 10); parse_ok { + fmt.assertf(value > 0, + "%T.%s has `%s` set to %i. It must be greater than zero.", + model_type, field.name, value, SUBTAG_VARIADIC, loc = loc) + fmt.assertf(value != 1, + "%T.%s has `%s` set to 1. This has no effect.", + model_type, field.name, SUBTAG_VARIADIC, loc = loc) + } + + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Dynamic_Array: + fmt.assertf(style != .Odin, + "%T.%s has `%s` defined, but this only makes sense in UNIX-style parsing mode.", + model_type, field.name, SUBTAG_VARIADIC, loc = loc) + case: + fmt.panicf("%T.%s has `%s` defined, but this only makes sense on dynamic arrays.", + model_type, field.name, SUBTAG_VARIADIC, loc = loc) + } + } + + allowed_to_define_file_perms: bool = --- + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Map: + allowed_to_define_file_perms = specific_type_info.value.id == os.Handle + case runtime.Type_Info_Dynamic_Array: + allowed_to_define_file_perms = specific_type_info.elem.id == os.Handle + case: + allowed_to_define_file_perms = field.type.id == os.Handle + } + + if _, has_file := get_struct_subtag(args_tag, SUBTAG_FILE); has_file { + fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `os.Handle` type.", + model_type, field.name, SUBTAG_FILE, loc = loc) + } + + if _, has_perms := get_struct_subtag(args_tag, SUBTAG_PERMS); has_perms { + fmt.assertf(allowed_to_define_file_perms, "%T.%s has `%s` defined, but it is not nor does it contain an `os.Handle` type.", + model_type, field.name, SUBTAG_PERMS, loc = loc) + } + + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Map: + fmt.assertf(reflect.is_string(specific_type_info.key), "%T.%s is defined as a map[%T]. Only string types are currently supported as map keys.", + model_type, + field.name, + specific_type_info.key) + } + } +} + +// Validate that all the required arguments are set and that the set arguments +// are up to the program's expectations. +@(optimization_mode="favor_size") +validate_arguments :: proc(model: ^$T, parser: ^Parser) -> Error { + check_fields: for field, index in reflect.struct_fields_zipped(T) { + was_set := bit_array.get(&parser.fields_set, index) + + field_name := get_field_name(field) + args_tag := reflect.struct_tag_get(field.tag, TAG_ARGS) + requirement, is_required := get_struct_subtag(args_tag, SUBTAG_REQUIRED) + + required_min, required_max: int + has_requirements: bool + if is_required { + required_min, required_max, has_requirements = parse_requirements(requirement) + } + + if has_requirements && required_min == 0 { + // Allow `0 ptr.len || ptr.len >= required_max { + if required_max == max(int) { + return Validation_Error { + fmt.tprintf("The flag `%s` had %i option%s set, but it requires at least %i.", + field_name, + ptr.len, + "" if ptr.len == 1 else "s", + required_min), + } + } else { + return Validation_Error { + fmt.tprintf("The flag `%s` had %i option%s set, but it requires at least %i and at most %i.", + field_name, + ptr.len, + "" if ptr.len == 1 else "s", + required_min, + required_max - 1), + } + } + } + } else if !was_set { + if is_required { + return Validation_Error { + fmt.tprintf("The required flag `%s` was not set.", field_name), + } + } + + // Not set, not required; moving on. + continue + } + + // All default checks have passed. The program gets a look at it now. + + if global_custom_flag_checker != nil { + ptr := cast(rawptr)(cast(uintptr)model + field.offset) + error := global_custom_flag_checker(model, + field.name, + mem.make_any(ptr, field.type.id), + args_tag) + + if len(error) > 0 { + // The program reported an error message. + return Validation_Error { error } + } + } + } + + return nil +} diff --git a/core/flags/parsing.odin b/core/flags/parsing.odin new file mode 100644 index 000000000..2d8ce34eb --- /dev/null +++ b/core/flags/parsing.odin @@ -0,0 +1,101 @@ +package flags + +@require import "core:container/bit_array" +@require import "core:fmt" + +Parsing_Style :: enum { + // Odin-style: `-flag`, `-flag:option`, `-map:key=value` + Odin, + // UNIX-style: `-flag` or `--flag`, `--flag=argument`, `--flag argument repeating-argument` + Unix, +} + +/* +Parse a slice of command-line arguments into an annotated struct. + +*Allocates Using Provided Allocator* + +By default, this proc will only allocate memory outside of its lifetime if it +has to append to a dynamic array, set a map value, or set a cstring. + +The program is expected to free any allocations on `model` as a result of parsing. + +Inputs: +- model: A pointer to an annotated struct with flag definitions. +- args: A slice of strings, usually `os.args[1:]`. +- style: The argument parsing style. +- validate_args: If `true`, will ensure that all required arguments are set if no errors occurred. +- strict: If `true`, will return on first error. Otherwise, parsing continues. +- allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: #caller_location) + +Returns: +- error: A union of errors; parsing, file open, a help request, or validation. +*/ +@(optimization_mode="favor_size") +parse :: proc( + model: ^$T, + args: []string, + style: Parsing_Style = .Odin, + validate_args: bool = true, + strict: bool = true, + allocator := context.allocator, + loc := #caller_location, +) -> (error: Error) { + context.allocator = allocator + validate_structure(model^, style, loc) + + parser: Parser + defer { + bit_array.destroy(&parser.filled_pos) + bit_array.destroy(&parser.fields_set) + } + + switch style { + case .Odin: + for arg in args { + error = parse_one_odin_arg(model, &parser, arg) + if strict && error != nil { + return + } + } + + case .Unix: + // Support for `-flag argument (repeating-argument ...)` + future_args: int + current_flag: string + + for i := 0; i < len(args); i += 1 { + #no_bounds_check arg := args[i] + future_args, current_flag, error = parse_one_unix_arg(model, &parser, arg) + if strict && error != nil { + return + } + + for starting_future_args := future_args; future_args > 0; future_args -= 1 { + i += 1 + if i == len(args) { + if future_args == starting_future_args { + return Parse_Error { + .No_Value, + fmt.tprintf("Expected a value for `%s` but none was given.", current_flag), + } + } + break + } + #no_bounds_check arg = args[i] + + error = set_option(model, &parser, current_flag, arg) + if strict && error != nil { + return + } + } + } + } + + if error == nil && validate_args { + return validate_arguments(model, &parser) + } + + return +} diff --git a/core/flags/rtti.odin b/core/flags/rtti.odin new file mode 100644 index 000000000..ce7a23773 --- /dev/null +++ b/core/flags/rtti.odin @@ -0,0 +1,43 @@ +package flags + +import "base:runtime" + +/* +Handle setting custom data types. + +Inputs: +- data: A raw pointer to the field where the data will go. +- data_type: Type information on the underlying field. +- unparsed_value: The unparsed string that the flag is being set to. +- args_tag: The `args` tag from the struct's field. + +Returns: +- error: An error message, or an empty string if no error occurred. +- handled: A boolean indicating if the setter handles this type. +- alloc_error: If an allocation error occurred, return it here. +*/ +Custom_Type_Setter :: #type proc( + data: rawptr, + data_type: typeid, + unparsed_value: string, + args_tag: string, +) -> ( + error: string, + handled: bool, + alloc_error: runtime.Allocator_Error, +) + +@(private) +global_custom_type_setter: Custom_Type_Setter + +/* +Set the global custom type setter. + +Note that only one can be active at a time. + +Inputs: +- setter: The type setter. Pass `nil` to disable any previously set setter. +*/ +register_type_setter :: proc(setter: Custom_Type_Setter) { + global_custom_type_setter = setter +} diff --git a/core/flags/usage.odin b/core/flags/usage.odin new file mode 100644 index 000000000..c42df7576 --- /dev/null +++ b/core/flags/usage.odin @@ -0,0 +1,293 @@ +package flags + +import "base:runtime" +import "core:fmt" +import "core:io" +import "core:reflect" +import "core:slice" +import "core:strconv" +import "core:strings" + +/* +Write out the documentation for the command-line arguments to a stream. + +Inputs: +- out: The stream to write to. +- data_type: The typeid of the data structure to describe. +- program: The name of the program, usually the first argument to `os.args`. +- style: The argument parsing style, required to show flags in the proper style. +*/ +@(optimization_mode="favor_size") +write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", style: Parsing_Style = .Odin) { + // All flags get their tags parsed so they can be reasoned about later. + Flag :: struct { + name: string, + usage: string, + type_description: string, + full_length: int, + pos: int, + required_min, required_max: int, + is_positional: bool, + is_required: bool, + is_boolean: bool, + is_variadic: bool, + variadic_length: int, + } + + // + // POSITIONAL+REQUIRED, POSITIONAL, REQUIRED, NON_REQUIRED+NON_POSITIONAL, ... + // + sort_flags :: proc(i, j: Flag) -> slice.Ordering { + // `varg` goes to the end. + if i.name == INTERNAL_VARIADIC_FLAG { + return .Greater + } else if j.name == INTERNAL_VARIADIC_FLAG { + return .Less + } + + // Handle positionals. + if i.is_positional { + if j.is_positional { + return slice.cmp(i.pos, j.pos) + } else { + return .Less + } + } else { + if j.is_positional { + return .Greater + } + } + + // Then required flags. + if i.is_required { + if !j.is_required { + return .Less + } + } else if j.is_required { + return .Greater + } + + // Finally, sort by name. + return slice.cmp(i.name, j.name) + } + + describe_array_requirements :: proc(flag: Flag) -> (spec: string) { + if flag.is_required { + if flag.required_min == flag.required_max - 1 { + spec = fmt.tprintf(", exactly %i", flag.required_min) + } else if flag.required_min > 0 && flag.required_max == max(int) { + spec = fmt.tprintf(", at least %i", flag.required_min) + } else if flag.required_min == 0 && flag.required_max > 1 { + spec = fmt.tprintf(", at most %i", flag.required_max - 1) + } else if flag.required_min > 0 && flag.required_max > 1 { + spec = fmt.tprintf(", between %i and %i", flag.required_min, flag.required_max - 1) + } else { + spec = ", required" + } + } + return + } + + builder := strings.builder_make() + defer strings.builder_destroy(&builder) + + flag_prefix, flag_assignment: string = ---, --- + switch style { + case .Odin: flag_prefix = "-"; flag_assignment = ":" + case .Unix: flag_prefix = "--"; flag_assignment = " " + } + + visible_flags: [dynamic]Flag + defer delete(visible_flags) + + longest_flag_length: int + + for field in reflect.struct_fields_zipped(data_type) { + flag: Flag + + if args_tag, ok := reflect.struct_tag_lookup(field.tag, TAG_ARGS); ok { + if _, is_hidden := get_struct_subtag(args_tag, SUBTAG_HIDDEN); is_hidden { + // Hidden flags stay hidden. + continue + } + if pos_str, is_pos := get_struct_subtag(args_tag, SUBTAG_POS); is_pos { + flag.is_positional = true + if pos, parse_ok := strconv.parse_u64_of_base(pos_str, 10); parse_ok { + flag.pos = cast(int)pos + } + } + if requirement, is_required := get_struct_subtag(args_tag, SUBTAG_REQUIRED); is_required { + flag.is_required = true + flag.required_min, flag.required_max, _ = parse_requirements(requirement) + } + if length_str, is_variadic := get_struct_subtag(args_tag, SUBTAG_VARIADIC); is_variadic { + flag.is_variadic = true + if length, parse_ok := strconv.parse_u64_of_base(length_str, 10); parse_ok { + flag.variadic_length = cast(int)length + } + } + } + + flag.name = get_field_name(field) + flag.is_boolean = reflect.is_boolean(field.type) + + if usage, ok := reflect.struct_tag_lookup(field.tag, TAG_USAGE); ok { + flag.usage = usage + } else { + flag.usage = UNDOCUMENTED_FLAG + } + + #partial switch specific_type_info in field.type.variant { + case runtime.Type_Info_Map: + flag.type_description = fmt.tprintf("<%v>=<%v>%s", + specific_type_info.key.id, + specific_type_info.value.id, + ", required" if flag.is_required else "") + + case runtime.Type_Info_Dynamic_Array: + requirement_spec := describe_array_requirements(flag) + + if flag.is_variadic || flag.name == INTERNAL_VARIADIC_FLAG { + if flag.variadic_length == 0 { + flag.type_description = fmt.tprintf("<%v, ...>%s", + specific_type_info.elem.id, + requirement_spec) + } else { + flag.type_description = fmt.tprintf("<%v, %i at once>%s", + specific_type_info.elem.id, + flag.variadic_length, + requirement_spec) + } + } else { + flag.type_description = fmt.tprintf("<%v>%s", specific_type_info.elem.id, + requirement_spec if len(requirement_spec) > 0 else ", multiple") + } + + case: + if flag.is_boolean { + /* + if flag.is_required { + flag.type_description = ", required" + } + */ + } else { + flag.type_description = fmt.tprintf("<%v>%s", + field.type.id, + ", required" if flag.is_required else "") + } + } + + if flag.name == INTERNAL_VARIADIC_FLAG { + flag.full_length = len(flag.type_description) + } else if flag.is_boolean { + flag.full_length = len(flag_prefix) + len(flag.name) + len(flag.type_description) + } else { + flag.full_length = len(flag_prefix) + len(flag.name) + len(flag_assignment) + len(flag.type_description) + } + + longest_flag_length = max(longest_flag_length, flag.full_length) + + append(&visible_flags, flag) + } + + slice.sort_by_cmp(visible_flags[:], sort_flags) + + // All the flags have been figured out now. + + if len(program) > 0 { + keep_it_short := len(visible_flags) >= ONE_LINE_FLAG_CUTOFF_COUNT + + strings.write_string(&builder, "Usage:\n\t") + strings.write_string(&builder, program) + + for flag in visible_flags { + if keep_it_short && !(flag.is_required || flag.is_positional || flag.name == INTERNAL_VARIADIC_FLAG) { + continue + } + + strings.write_byte(&builder, ' ') + + if flag.name == INTERNAL_VARIADIC_FLAG { + strings.write_string(&builder, "...") + continue + } + + if !flag.is_required { strings.write_byte(&builder, '[') } + if !flag.is_positional { strings.write_string(&builder, flag_prefix) } + strings.write_string(&builder, flag.name) + if !flag.is_required { strings.write_byte(&builder, ']') } + } + + strings.write_byte(&builder, '\n') + } + + if len(visible_flags) == 0 { + // No visible flags. An unusual situation, but prevent any extra work. + fmt.wprint(out, strings.to_string(builder)) + return + } + + strings.write_string(&builder, "Flags:\n") + + // Divide the positional/required arguments and the non-required arguments. + divider_index := -1 + for flag, i in visible_flags { + if !flag.is_positional && !flag.is_required { + divider_index = i + break + } + } + if divider_index == 0 { + divider_index = -1 + } + + for flag, i in visible_flags { + if i == divider_index { + SPACING :: 2 // Number of spaces before the '|' from below. + strings.write_byte(&builder, '\t') + spacing := strings.repeat(" ", SPACING + longest_flag_length, context.temp_allocator) + strings.write_string(&builder, spacing) + strings.write_string(&builder, "|\n") + } + + strings.write_byte(&builder, '\t') + + if flag.name == INTERNAL_VARIADIC_FLAG { + strings.write_string(&builder, flag.type_description) + } else { + strings.write_string(&builder, flag_prefix) + strings.write_string(&builder, flag.name) + if !flag.is_boolean { + strings.write_string(&builder, flag_assignment) + } + strings.write_string(&builder, flag.type_description) + } + + if strings.contains_rune(flag.usage, '\n') { + // Multi-line usage documentation. Let's make it look nice. + usage_builder := strings.builder_make(context.temp_allocator) + + strings.write_byte(&usage_builder, '\n') + iter := strings.trim_space(flag.usage) + for line in strings.split_lines_iterator(&iter) { + strings.write_string(&usage_builder, "\t\t") + strings.write_string(&usage_builder, strings.trim_left_space(line)) + strings.write_byte(&usage_builder, '\n') + } + + strings.write_string(&builder, strings.to_string(usage_builder)) + } else { + // Single-line usage documentation. + spacing := strings.repeat(" ", + (longest_flag_length) - flag.full_length, + context.temp_allocator) + + strings.write_string(&builder, spacing) + strings.write_string(&builder, " | ") + strings.write_string(&builder, flag.usage) + strings.write_byte(&builder, '\n') + } + } + + fmt.wprint(out, strings.to_string(builder)) +} diff --git a/core/flags/util.odin b/core/flags/util.odin new file mode 100644 index 000000000..f1bd60e75 --- /dev/null +++ b/core/flags/util.odin @@ -0,0 +1,130 @@ +package flags + +import "core:fmt" +@require import "core:os" +@require import "core:path/filepath" +import "core:strings" + +/* +Parse any arguments into an annotated struct or exit if there was an error. + +*Allocates Using Provided Allocator* + +This is a convenience wrapper over `parse` and `print_errors`. + +Inputs: +- model: A pointer to an annotated struct. +- program_args: A slice of strings, usually `os.args`. +- style: The argument parsing style. +- allocator: (default: context.allocator) +- loc: The caller location for debugging purposes (default: #caller_location) +*/ +@(optimization_mode="favor_size") +parse_or_exit :: proc( + model: ^$T, + program_args: []string, + style: Parsing_Style = .Odin, + allocator := context.allocator, + loc := #caller_location, +) { + assert(len(program_args) > 0, "Program arguments slice is empty.", loc) + + program := filepath.base(program_args[0]) + args: []string + + if len(program_args) > 1 { + args = program_args[1:] + } + + error := parse(model, args, style) + if error != nil { + stderr := os.stream_from_handle(os.stderr) + + if len(args) == 0 { + // No arguments entered, and there was an error; show the usage, + // specifically on STDERR. + write_usage(stderr, T, program, style) + fmt.wprintln(stderr) + } + + print_errors(T, error, program, style) + + _, was_help_request := error.(Help_Request) + os.exit(0 if was_help_request else 1) + } +} +/* +Print out any errors that may have resulted from parsing. + +All error messages print to STDERR, while usage goes to STDOUT, if requested. + +Inputs: +- data_type: The typeid of the data structure to describe, if usage is requested. +- error: The error returned from `parse`. +- style: The argument parsing style, required to show flags in the proper style, when usage is shown. +*/ +@(optimization_mode="favor_size") +print_errors :: proc(data_type: typeid, error: Error, program: string, style: Parsing_Style = .Odin) { + stderr := os.stream_from_handle(os.stderr) + stdout := os.stream_from_handle(os.stdout) + + switch specific_error in error { + case Parse_Error: + fmt.wprintfln(stderr, "[%T.%v] %s", specific_error, specific_error.reason, specific_error.message) + case Open_File_Error: + fmt.wprintfln(stderr, "[%T#%i] Unable to open file with perms 0o%o in mode 0x%x: %s", + specific_error, + specific_error.errno, + specific_error.perms, + specific_error.mode, + specific_error.filename) + case Validation_Error: + fmt.wprintfln(stderr, "[%T] %s", specific_error, specific_error.message) + case Help_Request: + write_usage(stdout, data_type, program, style) + } +} +/* +Get the value for a subtag. + +This is useful if you need to parse through the `args` tag for a struct field +on a custom type setter or custom flag checker. + +Example: + + import "core:flags" + import "core:fmt" + + subtag_example :: proc() { + args_tag := "precision=3,signed" + + precision, has_precision := flags.get_subtag(args_tag, "precision") + signed, is_signed := flags.get_subtag(args_tag, "signed") + + fmt.printfln("precision = %q, %t", precision, has_precision) + fmt.printfln("signed = %q, %t", signed, is_signed) + } + +Output: + + precision = "3", true + signed = "", true + +*/ +get_subtag :: proc(tag, id: string) -> (value: string, ok: bool) { + // This proc was initially private in `internal_rtti.odin`, but given how + // useful it would be to custom type setters and flag checkers, it lives + // here now. + + tag := tag + + for subtag in strings.split_iterator(&tag, ",") { + if equals := strings.index_byte(subtag, '='); equals != -1 && id == subtag[:equals] { + return subtag[1 + equals:], true + } else if id == subtag { + return "", true + } + } + + return +} diff --git a/core/flags/validation.odin b/core/flags/validation.odin new file mode 100644 index 000000000..e370cff48 --- /dev/null +++ b/core/flags/validation.odin @@ -0,0 +1,37 @@ +package flags + +/* +Check a flag after parsing, during the validation stage. + +Inputs: +- model: A raw pointer to the data structure provided to `parse`. +- name: The name of the flag being checked. +- value: An `any` type that contains the value to be checked. +- args_tag: The `args` tag from within the struct. + +Returns: +- error: An error message, or an empty string if no error occurred. +*/ +Custom_Flag_Checker :: #type proc( + model: rawptr, + name: string, + value: any, + args_tag: string, +) -> ( + error: string, +) + +@(private) +global_custom_flag_checker: Custom_Flag_Checker + +/* +Set the global custom flag checker. + +Note that only one can be active at a time. + +Inputs: +- checker: The flag checker. Pass `nil` to disable any previously set checker. +*/ +register_flag_checker :: proc(checker: Custom_Flag_Checker) { + global_custom_flag_checker = checker +} diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 4c65dd01f..234f4afbd 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -92,7 +92,7 @@ _user_formatters: ^map[typeid]User_Formatter // set_user_formatters :: proc(m: ^map[typeid]User_Formatter) { assert(_user_formatters == nil, "set_user_formatters must not be called more than once.") - _user_formatters = m + _user_formatters = m } // Registers a user-defined formatter for a specific typeid // @@ -368,6 +368,25 @@ caprintf :: proc(format: string, args: ..any, newline := false) -> cstring { caprintfln :: proc(format: string, args: ..any) -> cstring { return caprintf(format, ..args, newline=true) } +// Creates a formatted C string +// +// *Allocates Using Context's Temporary Allocator* +// +// Inputs: +// - args: A variadic list of arguments to be formatted. +// - sep: An optional separator string (default is a single space). +// +// Returns: A formatted C string. +// +@(require_results) +ctprint :: proc(args: ..any, sep := " ") -> cstring { + str: strings.Builder + strings.builder_init(&str, context.temp_allocator) + sbprint(&str, ..args, sep=sep) + strings.write_byte(&str, 0) + s := strings.to_string(str) + return cstring(raw_data(s)) +} // Creates a formatted C string // // *Allocates Using Context's Temporary Allocator* @@ -932,10 +951,10 @@ fmt_bad_verb :: proc(fi: ^Info, verb: rune) { io.write_string(fi.writer, "%!", &fi.n) io.write_rune(fi.writer, verb, &fi.n) io.write_byte(fi.writer, '(', &fi.n) - if fi.arg.id != nil { - reflect.write_typeid(fi.writer, fi.arg.id, &fi.n) + if arg := fi.arg; arg != nil { + reflect.write_typeid(fi.writer, arg.id, &fi.n) io.write_byte(fi.writer, '=', &fi.n) - fmt_value(fi, fi.arg, 'v') + fmt_value(fi, arg, 'v') } else { io.write_string(fi.writer, "", &fi.n) } @@ -1053,8 +1072,8 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d } flags: strconv.Int_Flags - if fi.hash && !fi.zero && start == 0 { flags |= {.Prefix} } - if fi.plus { flags |= {.Plus} } + if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } + if fi.plus { flags += {.Plus} } s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags) prev_zero := fi.zero defer fi.zero = prev_zero @@ -1138,8 +1157,8 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i } flags: strconv.Int_Flags - if fi.hash && !fi.zero && start == 0 { flags |= {.Prefix} } - if fi.plus { flags |= {.Plus} } + if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } + if fi.plus { flags += {.Plus} } s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags) if fi.hash && fi.zero && fi.indent == 0 { @@ -1210,10 +1229,10 @@ _fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: st // Add the unit at the end. copy(buf[len(str):], units[off:off+unit_len]) str = string(buf[:len(str)+unit_len]) - - if !fi.plus { - // Strip sign from "+" but not "+Inf". - if str[0] == '+' && str[1] != 'I' { + + if !fi.plus { + // Strip sign from "+" but not "+Inf". + if str[0] == '+' && str[1] != 'I' { str = str[1:] } } @@ -1441,13 +1460,10 @@ fmt_string :: proc(fi: ^Info, s: string, verb: rune) { if !fi.minus { io.write_string(fi.writer, s, &fi.n) } - } - else { + } else { io.write_string(fi.writer, s, &fi.n) } - } - else - { + } else { io.write_string(fi.writer, s, &fi.n) } @@ -1749,7 +1765,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') { if is_enum { enum_name: string - if ti_named, is_named := info.elem.variant.(runtime.Type_Info_Named); is_named { + if ti_named, is_named := info.elem.variant.(runtime.Type_Info_Named); is_named { enum_name = ti_named.name } for ev, evi in e.values { @@ -1973,11 +1989,13 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St // fi.hash = false; fi.indent += 1 - if !is_soa && hash { + is_empty := len(info.names) == 0 + + if !is_soa && hash && !is_empty { io.write_byte(fi.writer, '\n', &fi.n) } defer { - if hash { + if !is_soa && hash && !is_empty { for _ in 0.. 0 { + for _ in 0.. (result: u64) #no_bounds_check { result = seed #no_bounds_check for b in data { @@ -14,7 +14,7 @@ crc64_ecma_182 :: proc "contextless" (data: []byte, seed := u64(0)) -> (result: bit-reversed, with one's complement pre and post processing. Based on Mark Adler's v1.4 implementation in C under the ZLIB license. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") crc64_xz :: proc "contextless" (data: []byte, seed := u64(0)) -> u64 #no_bounds_check { data := data result := ~u64le(seed) @@ -52,7 +52,7 @@ crc64_xz :: proc "contextless" (data: []byte, seed := u64(0)) -> u64 #no_bounds_ /* Generator polynomial: x^64 + x^4 + x^3 + x + 1 */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") crc64_iso_3306 :: proc "contextless" (data: []byte, seed := u64(0)) -> u64 #no_bounds_check { result := seed @@ -738,4 +738,4 @@ crc64_iso_3306_inverse :: proc "contextless" (data: []byte, seed := u64(0)) -> u 0x9fc0, 0x9e70, 0x9ca0, 0x9d10, 0x9480, 0x9530, 0x97e0, 0x9650, 0x9240, 0x93f0, 0x9120, 0x9090, -} \ No newline at end of file +} diff --git a/core/hash/crc32.odin b/core/hash/crc32.odin index 5dde467a7..a7f68207e 100644 --- a/core/hash/crc32.odin +++ b/core/hash/crc32.odin @@ -2,7 +2,7 @@ package hash import "base:intrinsics" -@(optimization_mode="speed") +@(optimization_mode="favor_size") crc32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 #no_bounds_check { crc := ~seed buffer := raw_data(data) diff --git a/core/hash/hash.odin b/core/hash/hash.odin index fb170bfe4..45f524d8a 100644 --- a/core/hash/hash.odin +++ b/core/hash/hash.odin @@ -3,7 +3,7 @@ package hash import "core:mem" import "base:intrinsics" -@(optimization_mode="speed") +@(optimization_mode="favor_size") adler32 :: proc "contextless" (data: []byte, seed := u32(1)) -> u32 #no_bounds_check { ADLER_CONST :: 65521 @@ -46,7 +46,7 @@ adler32 :: proc "contextless" (data: []byte, seed := u32(1)) -> u32 #no_bounds_c return (u32(b) << 16) | u32(a) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") djb2 :: proc "contextless" (data: []byte, seed := u32(5381)) -> u32 { hash: u32 = seed for b in data { @@ -73,7 +73,7 @@ djbx33a :: proc "contextless" (data: []byte, seed := u32(5381)) -> (result: [16] } // If you have a choice, prefer fnv32a -@(optimization_mode="speed") +@(optimization_mode="favor_size") fnv32_no_a :: proc "contextless" (data: []byte, seed := u32(0x811c9dc5)) -> u32 { h: u32 = seed for b in data { @@ -86,7 +86,7 @@ fnv32 :: fnv32_no_a // NOTE(bill): Not a fan of these aliases but seems necessar fnv64 :: fnv64_no_a // NOTE(bill): Not a fan of these aliases but seems necessary // If you have a choice, prefer fnv64a -@(optimization_mode="speed") +@(optimization_mode="favor_size") fnv64_no_a :: proc "contextless" (data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 { h: u64 = seed for b in data { @@ -94,7 +94,7 @@ fnv64_no_a :: proc "contextless" (data: []byte, seed := u64(0xcbf29ce484222325)) } return h } -@(optimization_mode="speed") +@(optimization_mode="favor_size") fnv32a :: proc "contextless" (data: []byte, seed := u32(0x811c9dc5)) -> u32 { h: u32 = seed for b in data { @@ -103,7 +103,7 @@ fnv32a :: proc "contextless" (data: []byte, seed := u32(0x811c9dc5)) -> u32 { return h } -@(optimization_mode="speed") +@(optimization_mode="favor_size") fnv64a :: proc "contextless" (data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 { h: u64 = seed for b in data { @@ -112,7 +112,7 @@ fnv64a :: proc "contextless" (data: []byte, seed := u64(0xcbf29ce484222325)) -> return h } -@(optimization_mode="speed") +@(optimization_mode="favor_size") jenkins :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { hash: u32 = seed for b in data { @@ -126,7 +126,7 @@ jenkins :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { return hash } -@(optimization_mode="speed") +@(optimization_mode="favor_size") murmur32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { c1_32: u32 : 0xcc9e2d51 c2_32: u32 : 0x1b873593 @@ -177,7 +177,7 @@ murmur32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { } // See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L96 -@(optimization_mode="speed") +@(optimization_mode="favor_size") murmur64a :: proc "contextless" (data: []byte, seed := u64(0x9747b28c)) -> u64 { m :: 0xc6a4a7935bd1e995 r :: 47 @@ -218,7 +218,7 @@ murmur64a :: proc "contextless" (data: []byte, seed := u64(0x9747b28c)) -> u64 { } // See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L140 -@(optimization_mode="speed") +@(optimization_mode="favor_size") murmur64b :: proc "contextless" (data: []byte, seed := u64(0x9747b28c)) -> u64 { m :: 0x5bd1e995 r :: 24 @@ -286,7 +286,7 @@ murmur64b :: proc "contextless" (data: []byte, seed := u64(0x9747b28c)) -> u64 { return u64(h1)<<32 | u64(h2) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") sdbm :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { hash: u32 = seed for b in data { diff --git a/core/hash/xxhash/common.odin b/core/hash/xxhash/common.odin index faf88e0d4..bbeb60db3 100644 --- a/core/hash/xxhash/common.odin +++ b/core/hash/xxhash/common.odin @@ -67,17 +67,17 @@ when !XXH_DISABLE_PREFETCH { } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH_rotl32 :: #force_inline proc(x, r: u32) -> (res: u32) { return ((x << r) | (x >> (32 - r))) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH_rotl64 :: #force_inline proc(x, r: u64) -> (res: u64) { return ((x << r) | (x >> (64 - r))) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH32_read32 :: #force_inline proc(buf: []u8, alignment := Alignment.Unaligned) -> (res: u32) { if XXH_FORCE_MEMORY_ACCESS == 2 || alignment == .Aligned { #no_bounds_check b := (^u32le)(&buf[0])^ @@ -89,7 +89,7 @@ XXH32_read32 :: #force_inline proc(buf: []u8, alignment := Alignment.Unaligned) } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_read64 :: #force_inline proc(buf: []u8, alignment := Alignment.Unaligned) -> (res: u64) { if XXH_FORCE_MEMORY_ACCESS == 2 || alignment == .Aligned { #no_bounds_check b := (^u64le)(&buf[0])^ @@ -99,4 +99,4 @@ XXH64_read64 :: #force_inline proc(buf: []u8, alignment := Alignment.Unaligned) mem_copy(&b, raw_data(buf[:]), 8) return u64(b) } -} \ No newline at end of file +} diff --git a/core/hash/xxhash/xxhash_3.odin b/core/hash/xxhash/xxhash_3.odin index 611f4dc9f..9e159260b 100644 --- a/core/hash/xxhash/xxhash_3.odin +++ b/core/hash/xxhash/xxhash_3.odin @@ -111,13 +111,13 @@ XXH128_canonical :: struct { @param lhs, rhs The 64-bit integers to multiply @return The low 64 bits of the product XOR'd by the high 64 bits. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH_mul_64_to_128_fold_64 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_u64) { t := u128(lhs) * u128(rhs) return u64(t & 0xFFFFFFFFFFFFFFFF) ~ u64(t >> 64) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, #any_int shift: uint) -> (res: xxh_u64) { return v ~ (v >> shift) } @@ -125,7 +125,7 @@ XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, #any_int shift: uint) -> (res: /* This is a fast avalanche stage, suitable when input bits are already partially mixed */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_avalanche :: #force_inline proc(h64: xxh_u64) -> (res: xxh_u64) { res = XXH_xorshift_64(h64, 37) res *= 0x165667919E3779F9 @@ -137,7 +137,7 @@ XXH3_avalanche :: #force_inline proc(h64: xxh_u64) -> (res: xxh_u64) { This is a stronger avalanche, inspired by Pelle Evensen's rrmxmx preferable when input has not been previously mixed */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_rrmxmx :: #force_inline proc(h64, length: xxh_u64) -> (res: xxh_u64) { /* this mix is inspired by Pelle Evensen's rrmxmx */ res = h64 @@ -166,7 +166,7 @@ XXH3_rrmxmx :: #force_inline proc(h64, length: xxh_u64) -> (res: xxh_u64) { fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_1to3_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { /* A doubled version of 1to3_64b with different constants. */ length := len(input) @@ -190,7 +190,7 @@ XXH3_len_1to3_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u6 } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_4to8_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { length := len(input) seed := seed @@ -219,7 +219,7 @@ XXH3_len_4to8_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u6 } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_9to16_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { length := len(input) @@ -261,7 +261,7 @@ XXH3_len_9to16_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u /* Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_0to16_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { length := len(input) @@ -279,7 +279,7 @@ XXH3_len_0to16_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u /* A bit slower than XXH3_mix16B, but handles multiply by zero better. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH128_mix32B :: #force_inline proc(acc: xxh_u128, input_1: []u8, input_2: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { acc128 := XXH128_hash_t{ h = acc, @@ -293,7 +293,7 @@ XXH128_mix32B :: #force_inline proc(acc: xxh_u128, input_1: []u8, input_2: []u8, } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_17to128_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { length := len(input) @@ -323,7 +323,7 @@ XXH3_len_17to128_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh unreachable() } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_129to240_128b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u128) { length := len(input) @@ -379,7 +379,7 @@ XXH3_INIT_ACC :: [XXH_ACC_NB]xxh_u64{ XXH_SECRET_MERGEACCS_START :: 11 -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_128b_internal :: #force_inline proc( input: []u8, secret: []u8, @@ -407,7 +407,7 @@ XXH3_hashLong_128b_internal :: #force_inline proc( /* * It's important for performance that XXH3_hashLong is not inlined. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_128b_default :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_internal(input, XXH3_kSecret[:], XXH3_accumulate_512, XXH3_scramble_accumulator) } @@ -415,12 +415,12 @@ XXH3_hashLong_128b_default :: #force_no_inline proc(input: []u8, seed: xxh_u64, /* * It's important for performance that XXH3_hashLong is not inlined. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_128b_withSecret :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_internal(input, secret, XXH3_accumulate_512, XXH3_scramble_accumulator) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_128b_withSeed_internal :: #force_inline proc( input: []u8, seed: xxh_u64, secret: []u8, f_acc512: XXH3_accumulate_512_f, @@ -441,14 +441,14 @@ XXH3_hashLong_128b_withSeed_internal :: #force_inline proc( /* * It's important for performance that XXH3_hashLong is not inlined. */ - @(optimization_mode="speed") + @(optimization_mode="favor_size") XXH3_hashLong_128b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_withSeed_internal(input, seed, secret, XXH3_accumulate_512, XXH3_scramble_accumulator , XXH3_init_custom_secret) } XXH3_hashLong128_f :: #type proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_128bits_internal :: #force_inline proc( input: []u8, seed: xxh_u64, secret: []u8, f_hl128: XXH3_hashLong128_f) -> (res: XXH3_128_hash) { @@ -474,17 +474,17 @@ XXH3_128bits_internal :: #force_inline proc( } /* === Public XXH128 API === */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_128_default :: proc(input: []u8) -> (hash: XXH3_128_hash) { return XXH3_128bits_internal(input, 0, XXH3_kSecret[:], XXH3_hashLong_128b_withSeed) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_128_with_seed :: proc(input: []u8, seed: xxh_u64) -> (hash: XXH3_128_hash) { return XXH3_128bits_internal(input, seed, XXH3_kSecret[:], XXH3_hashLong_128b_withSeed) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_128_with_secret :: proc(input: []u8, secret: []u8) -> (hash: XXH3_128_hash) { return XXH3_128bits_internal(input, 0, secret, XXH3_hashLong_128b_withSecret) } @@ -519,7 +519,7 @@ XXH3_128 :: proc { XXH3_128_default, XXH3_128_with_seed, XXH3_128_with_secret } The XOR mixing hides individual parts of the secret and increases entropy. This adds an extra layer of strength for custom secrets. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_1to3_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u64) { length := u32(len(input)) assert(input != nil) @@ -542,7 +542,7 @@ XXH3_len_1to3_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64 } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_4to8_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u64) { length := u32(len(input)) assert(input != nil) @@ -562,7 +562,7 @@ XXH3_len_4to8_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64 } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_9to16_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u64) { length := u64(len(input)) assert(input != nil) @@ -579,7 +579,7 @@ XXH3_len_9to16_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u6 } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_0to16_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u64) { length := u64(len(input)) assert(input != nil) @@ -621,7 +621,7 @@ XXH3_len_0to16_64b :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u6 by this, although it is always a good idea to use a proper seed if you care about strength. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_mix16B :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u64) { input_lo := XXH64_read64(input[0:]) input_hi := XXH64_read64(input[8:]) @@ -632,7 +632,7 @@ XXH3_mix16B :: #force_inline proc(input: []u8, secret: []u8, seed: xxh_u64) -> ( } /* For mid range keys, XXH3 uses a Mum-hash variant. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_17to128_64b :: proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u64) { assert(len(secret) >= XXH3_SECRET_SIZE_MIN) length := len(input) @@ -665,7 +665,7 @@ XXH3_MIDSIZE_MAX :: 240 XXH3_MIDSIZE_STARTOFFSET :: 3 XXH3_MIDSIZE_LASTOFFSET :: 17 -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_len_129to240_64b :: proc(input: []u8, secret: []u8, seed: xxh_u64) -> (res: xxh_u64) { assert(len(secret) >= XXH3_SECRET_SIZE_MIN) length := len(input) @@ -699,7 +699,7 @@ XXH_SECRET_CONSUME_RATE :: 8 /* nb of secret bytes consumed at each accumulatio XXH_ACC_NB :: (XXH_STRIPE_LEN / size_of(xxh_u64)) XXH_SECRET_LASTACC_START :: 7 /* not aligned on 8, last secret is different from acc & scrambler */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH_writeLE64 :: #force_inline proc(dst: []u8, v64: u64le) { v := v64 mem_copy(raw_data(dst), &v, size_of(v64)) @@ -737,7 +737,7 @@ XXH3_scramble_accumulator : XXH3_scramble_accumulator_f = XXH3_scramble_accumula XXH3_init_custom_secret : XXH3_init_custom_secret_f = XXH3_init_custom_secret_scalar /* scalar variants - universal */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_accumulate_512_scalar :: #force_inline proc(acc: []xxh_u64, input: []u8, secret: []u8) { xacc := acc /* presumed aligned */ xinput := input /* no alignment restriction */ @@ -754,7 +754,7 @@ XXH3_accumulate_512_scalar :: #force_inline proc(acc: []xxh_u64, input: []u8, se } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_scramble_accumulator_scalar :: #force_inline proc(acc: []xxh_u64, secret: []u8) { xacc := acc /* presumed aligned */ xsecret := secret /* no alignment restriction */ @@ -771,7 +771,7 @@ XXH3_scramble_accumulator_scalar :: #force_inline proc(acc: []xxh_u64, secret: [ } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_init_custom_secret_scalar :: #force_inline proc(custom_secret: []u8, seed64: xxh_u64) { #assert((XXH_SECRET_DEFAULT_SIZE & 15) == 0) @@ -791,7 +791,7 @@ XXH_PREFETCH_DIST :: 320 * Loops over XXH3_accumulate_512(). * Assumption: nbStripes will not overflow the secret size */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_accumulate :: #force_inline proc( acc: []xxh_u64, input: []u8, secret: []u8, nbStripes: uint, f_acc512: XXH3_accumulate_512_f) { @@ -804,7 +804,7 @@ XXH3_accumulate :: #force_inline proc( } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_internal_loop :: #force_inline proc(acc: []xxh_u64, input: []u8, secret: []u8, f_acc512: XXH3_accumulate_512_f, f_scramble: XXH3_scramble_accumulator_f) { @@ -833,14 +833,14 @@ XXH3_hashLong_internal_loop :: #force_inline proc(acc: []xxh_u64, input: []u8, s } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_mix2Accs :: #force_inline proc(acc: []xxh_u64, secret: []u8) -> (res: xxh_u64) { return XXH_mul_64_to_128_fold_64( acc[0] ~ XXH64_read64(secret), acc[1] ~ XXH64_read64(secret[8:])) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_mergeAccs :: #force_inline proc(acc: []xxh_u64, secret: []u8, start: xxh_u64) -> (res: xxh_u64) { result64 := start #no_bounds_check for i := 0; i < 4; i += 1 { @@ -849,7 +849,7 @@ XXH3_mergeAccs :: #force_inline proc(acc: []xxh_u64, secret: []u8, start: xxh_u6 return XXH3_avalanche(result64) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_64b_internal :: #force_inline proc(input: []u8, secret: []u8, f_acc512: XXH3_accumulate_512_f, f_scramble: XXH3_scramble_accumulator_f) -> (hash: xxh_u64) { @@ -868,7 +868,7 @@ XXH3_hashLong_64b_internal :: #force_inline proc(input: []u8, secret: []u8, /* It's important for performance that XXH3_hashLong is not inlined. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_64b_withSecret :: #force_no_inline proc(input: []u8, seed64: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_internal(input, secret, XXH3_accumulate_512, XXH3_scramble_accumulator) } @@ -880,7 +880,7 @@ XXH3_hashLong_64b_withSecret :: #force_no_inline proc(input: []u8, seed64: xxh_u This variant enforces that the compiler can detect that, and uses this opportunity to streamline the generated code for better performance. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_64b_default :: #force_no_inline proc(input: []u8, seed64: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_internal(input, XXH3_kSecret[:], XXH3_accumulate_512, XXH3_scramble_accumulator) } @@ -896,26 +896,27 @@ XXH3_hashLong_64b_default :: #force_no_inline proc(input: []u8, seed64: xxh_u64, It's important for performance that XXH3_hashLong is not inlined. Not sure why (uop cache maybe?), but the difference is large and easily measurable. */ -@(optimization_mode="speed") -XXH3_hashLong_64b_withSeed_internal :: #force_no_inline proc(input: []u8, - seed: xxh_u64, - f_acc512: XXH3_accumulate_512_f, - f_scramble: XXH3_scramble_accumulator_f, - f_init_sec: XXH3_init_custom_secret_f) -> (hash: xxh_u64) { +@(optimization_mode="favor_size") +XXH3_hashLong_64b_withSeed_internal :: #force_no_inline proc( + input: []u8, + seed: xxh_u64, + f_acc512: XXH3_accumulate_512_f, + f_scramble: XXH3_scramble_accumulator_f, + f_init_sec: XXH3_init_custom_secret_f, +) -> (hash: xxh_u64) { if seed == 0 { return XXH3_hashLong_64b_internal(input, XXH3_kSecret[:], f_acc512, f_scramble) } - { - secret: [XXH_SECRET_DEFAULT_SIZE]u8 - f_init_sec(secret[:], seed) - return XXH3_hashLong_64b_internal(input, secret[:], f_acc512, f_scramble) - } + + secret: [XXH_SECRET_DEFAULT_SIZE]u8 + f_init_sec(secret[:], seed) + return XXH3_hashLong_64b_internal(input, secret[:], f_acc512, f_scramble) } /* It's important for performance that XXH3_hashLong is not inlined. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_hashLong_64b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_withSeed_internal(input, seed, XXH3_accumulate_512, XXH3_scramble_accumulator, XXH3_init_custom_secret) } @@ -923,7 +924,7 @@ XXH3_hashLong_64b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, XXH3_hashLong64_f :: #type proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: xxh_u64) -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_64bits_internal :: proc(input: []u8, seed: xxh_u64, secret: []u8, f_hashLong: XXH3_hashLong64_f) -> (hash: xxh_u64) { assert(len(secret) >= XXH3_SECRET_SIZE_MIN) /* @@ -943,19 +944,19 @@ XXH3_64bits_internal :: proc(input: []u8, seed: xxh_u64, secret: []u8, f_hashLon } /* === Public entry point === */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_64_default :: proc(input: []u8) -> (hash: xxh_u64) { return XXH3_64bits_internal(input, 0, XXH3_kSecret[:], XXH3_hashLong_64b_default) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_64_with_seed :: proc(input: []u8, seed: xxh_u64) -> (hash: xxh_u64) { return XXH3_64bits_internal(input, seed, XXH3_kSecret[:], XXH3_hashLong_64b_withSeed) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH3_64_with_secret :: proc(input, secret: []u8) -> (hash: xxh_u64) { return XXH3_64bits_internal(input, 0, secret, XXH3_hashLong_64b_withSecret) } -XXH3_64 :: proc { XXH3_64_default, XXH3_64_with_seed, XXH3_64_with_secret } \ No newline at end of file +XXH3_64 :: proc { XXH3_64_default, XXH3_64_with_seed, XXH3_64_with_secret } diff --git a/core/hash/xxhash/xxhash_32.odin b/core/hash/xxhash/xxhash_32.odin index b0dea305e..3ea1c3cf2 100644 --- a/core/hash/xxhash/xxhash_32.odin +++ b/core/hash/xxhash/xxhash_32.odin @@ -40,7 +40,7 @@ XXH_PRIME32_3 :: 0xC2B2AE3D /*!< 0b11000010101100101010111000111101 */ XXH_PRIME32_4 :: 0x27D4EB2F /*!< 0b00100111110101001110101100101111 */ XXH_PRIME32_5 :: 0x165667B1 /*!< 0b00010110010101100110011110110001 */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH32_round :: #force_inline proc(seed, input: XXH32_hash) -> (res: XXH32_hash) { seed := seed @@ -53,7 +53,7 @@ XXH32_round :: #force_inline proc(seed, input: XXH32_hash) -> (res: XXH32_hash) /* Mix all bits */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH32_avalanche :: #force_inline proc(h32: u32) -> (res: u32) { h32 := h32 @@ -65,7 +65,7 @@ XXH32_avalanche :: #force_inline proc(h32: u32) -> (res: u32) { return h32 } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH32_finalize :: #force_inline proc(h32: u32, buf: []u8, alignment: Alignment) -> (res: u32) { process_1 :: #force_inline proc(h32: u32, buf: []u8) -> (h32_res: u32, buf_res: []u8) { #no_bounds_check b := u32(buf[0]) @@ -143,7 +143,7 @@ XXH32_finalize :: #force_inline proc(h32: u32, buf: []u8, alignment: Alignment) unreachable() } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH32_endian_align :: #force_inline proc(input: []u8, seed := XXH32_DEFAULT_SEED, alignment: Alignment) -> (res: XXH32_hash) { buf := input length := len(input) @@ -318,4 +318,4 @@ XXH32_canonical_from_hash :: proc(hash: XXH32_hash) -> (canonical: XXH32_canonic XXH32_hash_from_canonical :: proc(canonical: ^XXH32_canonical) -> (hash: XXH32_hash) { h := (^u32be)(&canonical.digest)^ return XXH32_hash(h) -} \ No newline at end of file +} diff --git a/core/hash/xxhash/xxhash_64.odin b/core/hash/xxhash/xxhash_64.odin index b274da374..3b24f20a1 100644 --- a/core/hash/xxhash/xxhash_64.odin +++ b/core/hash/xxhash/xxhash_64.odin @@ -40,7 +40,7 @@ XXH_PRIME64_3 :: 0x165667B19E3779F9 /*!< 0b0001011001010110011001111011000110011 XXH_PRIME64_4 :: 0x85EBCA77C2B2AE63 /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ XXH_PRIME64_5 :: 0x27D4EB2F165667C5 /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_round :: proc(acc, input: xxh_u64) -> (res: xxh_u64) { acc := acc @@ -50,14 +50,14 @@ XXH64_round :: proc(acc, input: xxh_u64) -> (res: xxh_u64) { return acc } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_mergeRound :: proc(acc, val: xxh_u64) -> (res: xxh_u64) { res = acc ~ XXH64_round(0, val) res = res * XXH_PRIME64_1 + XXH_PRIME64_4 return res } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_avalanche :: proc(h64: xxh_u64) -> (res: xxh_u64) { res = h64 res ~= res >> 33 @@ -68,7 +68,7 @@ XXH64_avalanche :: proc(h64: xxh_u64) -> (res: xxh_u64) { return res } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_finalize :: proc(h64: xxh_u64, buf: []u8, alignment: Alignment) -> (res: xxh_u64) { buf := buf length := len(buf) & 31 @@ -100,7 +100,7 @@ XXH64_finalize :: proc(h64: xxh_u64, buf: []u8, alignment: Alignment) -> (res: x return XXH64_avalanche(res) } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_endian_align :: proc(input: []u8, seed := XXH64_DEFAULT_SEED, alignment := Alignment.Unaligned) -> (res: xxh_u64) { buf := input length := len(buf) @@ -191,7 +191,7 @@ XXH64_reset_state :: proc(state_ptr: ^XXH64_state, seed := XXH64_DEFAULT_SEED) - return .None } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_update :: proc(state: ^XXH64_state, input: []u8) -> (err: Error) { buf := input length := len(buf) @@ -245,7 +245,7 @@ XXH64_update :: proc(state: ^XXH64_state, input: []u8) -> (err: Error) { return .None } -@(optimization_mode="speed") +@(optimization_mode="favor_size") XXH64_digest :: proc(state: ^XXH64_state) -> (res: XXH64_hash) { if state.total_len >= 32 { v1 := state.v1 @@ -292,4 +292,4 @@ XXH64_canonical_from_hash :: proc(hash: XXH64_hash) -> (canonical: XXH64_canonic XXH64_hash_from_canonical :: proc(canonical: ^XXH64_canonical) -> (hash: XXH64_hash) { h := (^u64be)(&canonical.digest)^ return XXH64_hash(h) -} \ No newline at end of file +} diff --git a/core/image/bmp/bmp.odin b/core/image/bmp/bmp.odin index 64fc1d5a8..057c2ffa0 100644 --- a/core/image/bmp/bmp.odin +++ b/core/image/bmp/bmp.odin @@ -71,7 +71,7 @@ save_to_buffer :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{} written := 0 if resize(&output.buf, int(header.size)) != nil { - return .Unable_To_Allocate_Or_Resize + return .Unable_To_Allocate_Or_Resize } header_bytes := transmute([size_of(image.BMP_Header)]u8)header @@ -122,7 +122,7 @@ load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context return img, err } -@(optimization_mode="speed") +@(optimization_mode="favor_size") load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator options := options @@ -131,7 +131,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() if .info in options { - options |= {.return_metadata, .do_not_decompress_image} + options += {.return_metadata, .do_not_decompress_image} options -= {.info} } @@ -735,7 +735,7 @@ destroy :: proc(img: ^Image) { bytes.buffer_destroy(&img.pixels) if v, ok := img.metadata.(^image.BMP_Info); ok { - free(v) + free(v) } free(img) } @@ -743,4 +743,4 @@ destroy :: proc(img: ^Image) { @(init, private) _register :: proc() { image.register(.BMP, load_from_bytes, destroy) -} \ No newline at end of file +} diff --git a/core/image/common.odin b/core/image/common.odin index fed2c1470..2b1f71711 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -1313,55 +1313,55 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo } switch img.depth { - case 8: - switch img.channels { - case 1: // Turn Gray into RGB - out := mem.slice_data_cast([]RGB_Pixel, buf.buf[:]) + case 8: + switch img.channels { + case 1: // Turn Gray into RGB + out := mem.slice_data_cast([]RGB_Pixel, buf.buf[:]) - for p in img.pixels.buf { - out[0] = p // Broadcast gray value into RGB components. - out = out[1:] - } - - case 2: // Turn Gray + Alpha into RGBA - inp := mem.slice_data_cast([]GA_Pixel, img.pixels.buf[:]) - out := mem.slice_data_cast([]RGBA_Pixel, buf.buf[:]) - - for p in inp { - out[0].rgb = p.r // Gray component. - out[0].a = p.g // Alpha component. - } - - case: - unreachable() + for p in img.pixels.buf { + out[0] = p // Broadcast gray value into RGB components. + out = out[1:] } - case 16: - switch img.channels { - case 1: // Turn Gray into RGB - inp := mem.slice_data_cast([]u16, img.pixels.buf[:]) - out := mem.slice_data_cast([]RGB_Pixel_16, buf.buf[:]) + case 2: // Turn Gray + Alpha into RGBA + inp := mem.slice_data_cast([]GA_Pixel, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGBA_Pixel, buf.buf[:]) - for p in inp { - out[0] = p // Broadcast gray value into RGB components. - out = out[1:] - } - - case 2: // Turn Gray + Alpha into RGBA - inp := mem.slice_data_cast([]GA_Pixel_16, img.pixels.buf[:]) - out := mem.slice_data_cast([]RGBA_Pixel_16, buf.buf[:]) - - for p in inp { - out[0].rgb = p.r // Gray component. - out[0].a = p.g // Alpha component. - } - - case: - unreachable() + for p in inp { + out[0].rgb = p.r // Gray component. + out[0].a = p.g // Alpha component. } case: unreachable() + } + + case 16: + switch img.channels { + case 1: // Turn Gray into RGB + inp := mem.slice_data_cast([]u16, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGB_Pixel_16, buf.buf[:]) + + for p in inp { + out[0] = p // Broadcast gray value into RGB components. + out = out[1:] + } + + case 2: // Turn Gray + Alpha into RGBA + inp := mem.slice_data_cast([]GA_Pixel_16, img.pixels.buf[:]) + out := mem.slice_data_cast([]RGBA_Pixel_16, buf.buf[:]) + + for p in inp { + out[0].rgb = p.r // Gray component. + out[0].a = p.g // Alpha component. + } + + case: + unreachable() + } + + case: + unreachable() } @@ -1376,7 +1376,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo /* Helper functions to read and write data from/to a Context, etc. */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_data :: proc(z: $C, $T: typeid) -> (res: T, err: compress.General_Error) { if r, e := compress.read_data(z, T); e != .None { return {}, .Stream_Too_Short @@ -1385,7 +1385,7 @@ read_data :: proc(z: $C, $T: typeid) -> (res: T, err: compress.General_Error) { } } -@(optimization_mode="speed") +@(optimization_mode="favor_size") read_u8 :: proc(z: $C) -> (res: u8, err: compress.General_Error) { if r, e := compress.read_u8(z); e != .None { return {}, .Stream_Too_Short @@ -1405,4 +1405,4 @@ write_bytes :: proc(buf: ^bytes.Buffer, data: []u8) -> (err: compress.General_Er return .Resize_Failed } return nil -} \ No newline at end of file +} diff --git a/core/image/png/png.odin b/core/image/png/png.odin index aa1c5f781..177269722 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -341,7 +341,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a options := options if .info in options { - options |= {.return_metadata, .do_not_decompress_image} + options += {.return_metadata, .do_not_decompress_image} options -= {.info} } @@ -354,7 +354,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } if .do_not_expand_channels in options { - options |= {.do_not_expand_grayscale, .do_not_expand_indexed} + options += {.do_not_expand_grayscale, .do_not_expand_indexed} } if img == nil { @@ -535,28 +535,28 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a ct := transmute(u8)info.header.color_type switch ct { - case 3: // Indexed color - if c.header.length != 1 { - return {}, .BKGD_Invalid_Length - } - col := _plte.entries[c.data[0]] - img.background = [3]u16{ - u16(col[0]) << 8 | u16(col[0]), - u16(col[1]) << 8 | u16(col[1]), - u16(col[2]) << 8 | u16(col[2]), - } - case 0, 4: // Grayscale, with and without Alpha - if c.header.length != 2 { - return {}, .BKGD_Invalid_Length - } - col := u16(mem.slice_data_cast([]u16be, c.data[:])[0]) - img.background = [3]u16{col, col, col} - case 2, 6: // Color, with and without Alpha - if c.header.length != 6 { - return {}, .BKGD_Invalid_Length - } - col := mem.slice_data_cast([]u16be, c.data[:]) - img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])} + case 3: // Indexed color + if c.header.length != 1 { + return {}, .BKGD_Invalid_Length + } + col := _plte.entries[c.data[0]] + img.background = [3]u16{ + u16(col[0]) << 8 | u16(col[0]), + u16(col[1]) << 8 | u16(col[1]), + u16(col[2]) << 8 | u16(col[2]), + } + case 0, 4: // Grayscale, with and without Alpha + if c.header.length != 2 { + return {}, .BKGD_Invalid_Length + } + col := u16(mem.slice_data_cast([]u16be, c.data[:])[0]) + img.background = [3]u16{col, col, col} + case 2, 6: // Color, with and without Alpha + if c.header.length != 6 { + return {}, .BKGD_Invalid_Length + } + col := mem.slice_data_cast([]u16be, c.data[:]) + img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])} } case .tRNS: diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin index 061943f68..5cf252fcc 100644 --- a/core/image/qoi/qoi.odin +++ b/core/image/qoi/qoi.odin @@ -139,15 +139,13 @@ save_to_buffer :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{} } else { // Write RGB literal output.buf[written] = u8(QOI_Opcode_Tag.RGB) - pix_bytes := transmute([4]u8)pix - copy(output.buf[written + 1:], pix_bytes[:3]) + copy(output.buf[written + 1:], pix[:3]) written += 4 } } else { // Write RGBA literal output.buf[written] = u8(QOI_Opcode_Tag.RGBA) - pix_bytes := transmute([4]u8)pix - copy(output.buf[written + 1:], pix_bytes[:]) + copy(output.buf[written + 1:], pix[:]) written += 5 } } @@ -172,13 +170,13 @@ load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context return img, err } -@(optimization_mode="speed") +@(optimization_mode="favor_size") load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { context.allocator = allocator options := options if .info in options { - options |= {.return_metadata, .do_not_decompress_image} + options += {.return_metadata, .do_not_decompress_image} options -= {.info} } @@ -232,7 +230,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8) if resize(&img.pixels.buf, bytes_needed) != nil { - return img, .Unable_To_Allocate_Or_Resize + return img, .Unable_To_Allocate_Or_Resize } /* @@ -343,7 +341,7 @@ destroy :: proc(img: ^Image) { bytes.buffer_destroy(&img.pixels) if v, ok := img.metadata.(^image.QOI_Info); ok { - free(v) + free(v) } free(img) } @@ -375,4 +373,4 @@ qoi_hash :: #force_inline proc(pixel: RGBA_Pixel) -> (index: u8) { @(init, private) _register :: proc() { image.register(.QOI, load_from_bytes, destroy) -} \ No newline at end of file +} diff --git a/core/image/tga/tga.odin b/core/image/tga/tga.odin index 03ef1a386..46e37a0cf 100644 --- a/core/image/tga/tga.odin +++ b/core/image/tga/tga.odin @@ -100,7 +100,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } if .info in options { - options |= {.return_metadata, .do_not_decompress_image} + options += {.return_metadata, .do_not_decompress_image} options -= {.info} } diff --git a/core/io/io.odin b/core/io/io.odin index 961dbe43e..6072aec6d 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -375,10 +375,6 @@ write_at_least :: proc(w: Writer, buf: []byte, min: int) -> (n: int, err: Error) nn, err = write(w, buf[n:]) n += nn } - - if err == nil && n < min { - err = .Short_Write - } return } diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 1969fac49..ee09bb2c7 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -362,11 +362,11 @@ platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) count_lsb :: proc { int_count_lsb, platform_count_lsb, } -int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { +int_random_digit :: proc() -> (res: DIGIT) { when _DIGIT_BITS == 60 { // DIGIT = u64 - return DIGIT(rnd.uint64(r)) & _MASK + return DIGIT(rnd.uint64()) & _MASK } else when _DIGIT_BITS == 28 { // DIGIT = u32 - return DIGIT(rnd.uint32(r)) & _MASK + return DIGIT(rnd.uint32()) & _MASK } else { panic("Unsupported DIGIT size.") } @@ -374,12 +374,12 @@ int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { return 0 // We shouldn't get here. } -int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { +int_random :: proc(dest: ^Int, bits: int, allocator := context.allocator) -> (err: Error) { /* Check that `a` is usable. */ assert_if_nil(dest) - return #force_inline internal_int_random(dest, bits, r, allocator) + return #force_inline internal_int_random(dest, bits, allocator) } random :: proc { int_random, } diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index fa747e46a..c9b331e55 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2178,15 +2178,20 @@ internal_int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator } /* - If not yet iniialized, initialize the `digit` backing with the allocator we were passed. + If not yet initialized, initialize the `digit` backing with the allocator we were passed. */ if cap == 0 { a.digit = make([dynamic]DIGIT, needed, allocator) - } else if cap != needed { + } else if cap < needed { /* `[dynamic]DIGIT` already knows what allocator was used for it, so resize will do the right thing. */ resize(&a.digit, needed) + } else if cap > needed { + /* + Same applies to builtin.shrink here as resize above + */ + builtin.shrink(&a.digit, needed) } /* Let's see if the allocation/resize worked as expected. @@ -2812,11 +2817,11 @@ internal_platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) internal_count_lsb :: proc { internal_int_count_lsb, internal_platform_count_lsb, } -internal_int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { +internal_int_random_digit :: proc() -> (res: DIGIT) { when _DIGIT_BITS == 60 { // DIGIT = u64 - return DIGIT(rnd.uint64(r)) & _MASK + return DIGIT(rnd.uint64()) & _MASK } else when _DIGIT_BITS == 28 { // DIGIT = u32 - return DIGIT(rnd.uint32(r)) & _MASK + return DIGIT(rnd.uint32()) & _MASK } else { panic("Unsupported DIGIT size.") } @@ -2824,7 +2829,7 @@ internal_int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { return 0 // We shouldn't get here. } -internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { +internal_int_random :: proc(dest: ^Int, bits: int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator bits := bits @@ -2841,7 +2846,7 @@ internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator #force_inline internal_grow(dest, digits) or_return for i := 0; i < digits; i += 1 { - dest.digit[i] = int_random_digit(r) & _MASK + dest.digit[i] = int_random_digit() & _MASK } if bits > 0 { dest.digit[digits - 1] &= ((1 << uint(bits)) - 1) diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index 7fc78c7e5..832c75119 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -12,8 +12,6 @@ package math_big -import rnd "core:math/rand" - /* Determines if an Integer is divisible by one of the _PRIME_TABLE primes. Returns true if it is, false if not. @@ -315,7 +313,7 @@ internal_int_prime_miller_rabin :: proc(a, b: ^Int, allocator := context.allocat Assumes `a` not to be `nil` and to have been initialized. */ -internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_rabin_only := USE_MILLER_RABIN_ONLY, r: ^rnd.Rand = nil, allocator := context.allocator) -> (is_prime: bool, err: Error) { +internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_rabin_only := USE_MILLER_RABIN_ONLY, allocator := context.allocator) -> (is_prime: bool, err: Error) { context.allocator = allocator miller_rabin_trials := miller_rabin_trials @@ -461,7 +459,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra for ix := 0; ix < miller_rabin_trials; ix += 1 { // rand() guarantees the first digit to be non-zero - internal_random(b, _DIGIT_TYPE_BITS, r) or_return + internal_random(b, _DIGIT_TYPE_BITS) or_return // Reduce digit before casting because DIGIT might be bigger than // an unsigned int and "mask" on the other side is most probably not. @@ -1183,7 +1181,7 @@ internal_int_prime_next_prime :: proc(a: ^Int, trials: int, bbs_style: bool, all This is possibly the mother of all prime generation functions, muahahahahaha! */ -internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags := Primality_Flags{}, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { +internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags := Primality_Flags{}, allocator := context.allocator) -> (err: Error) { context.allocator = allocator flags := flags trials := trials diff --git a/core/math/big/private.odin b/core/math/big/private.odin index 2ee6cfafa..bb6b9497c 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -787,8 +787,8 @@ _private_int_sqr_comba :: proc(dest, src: ^Int, allocator := context.allocator) /* Karatsuba squaring, computes `dest` = `src` * `src` using three half-size squarings. - See comments of `_private_int_mul_karatsuba` for details. - It is essentially the same algorithm but merely tuned to perform recursive squarings. + See comments of `_private_int_mul_karatsuba` for details. + It is essentially the same algorithm but merely tuned to perform recursive squarings. */ _private_int_sqr_karatsuba :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator @@ -967,7 +967,7 @@ _private_int_div_3 :: proc(quotient, numerator: ^Int, allocator := context.alloc /* b = 2^_DIGIT_BITS / 3 */ - b := _WORD(1) << _WORD(_DIGIT_BITS) / _WORD(3) + b := _WORD(1) << _WORD(_DIGIT_BITS) / _WORD(3) q := &Int{} internal_grow(q, numerator.used) or_return @@ -975,7 +975,7 @@ _private_int_div_3 :: proc(quotient, numerator: ^Int, allocator := context.alloc q.sign = numerator.sign w, t: _WORD - #no_bounds_check for ix := numerator.used; ix >= 0; ix -= 1 { + #no_bounds_check for ix := numerator.used - 1; ix >= 0; ix -= 1 { w = (w << _WORD(_DIGIT_BITS)) | _WORD(numerator.digit[ix]) if w >= 3 { /* @@ -1007,8 +1007,8 @@ _private_int_div_3 :: proc(quotient, numerator: ^Int, allocator := context.alloc */ if quotient != nil { err = clamp(q) - internal_swap(q, quotient) - } + internal_swap(q, quotient) + } internal_destroy(q) return remainder, nil } @@ -1555,24 +1555,24 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. /* If neither `a` or `b` was zero, we need to compute `gcd`. - Get copies of `a` and `b` we can modify. - */ + Get copies of `a` and `b` we can modify. + */ u, v := &Int{}, &Int{} defer internal_destroy(u, v) internal_copy(u, a) or_return internal_copy(v, b) or_return - /* - Must be positive for the remainder of the algorithm. - */ + /* + Must be positive for the remainder of the algorithm. + */ u.sign = .Zero_or_Positive; v.sign = .Zero_or_Positive - /* - B1. Find the common power of two for `u` and `v`. - */ - u_lsb, _ := internal_count_lsb(u) - v_lsb, _ := internal_count_lsb(v) - k := min(u_lsb, v_lsb) + /* + B1. Find the common power of two for `u` and `v`. + */ + u_lsb, _ := internal_count_lsb(u) + v_lsb, _ := internal_count_lsb(v) + k := min(u_lsb, v_lsb) if k > 0 { /* @@ -1615,11 +1615,11 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. internal_shr(v, v, b) or_return } - /* - Multiply by 2**k which we divided out at the beginning. - */ - internal_shl(temp_gcd_res, u, k) or_return - temp_gcd_res.sign = .Zero_or_Positive + /* + Multiply by 2**k which we divided out at the beginning. + */ + internal_shl(temp_gcd_res, u, k) or_return + temp_gcd_res.sign = .Zero_or_Positive /* We've computed `gcd`, either the long way, or because one of the inputs was zero. @@ -1786,8 +1786,8 @@ _private_montgomery_reduce_comba :: proc(x, n: ^Int, rho: DIGIT, allocator := co `a = a + mu * m * b**i` This is computed in place and on the fly. The multiplication - by b**i is handled by offseting which columns the results - are added to. + by b**i is handled by offseting which columns the results + are added to. Note the comba method normally doesn't handle carries in the inner loop In this case we fix the carry from the previous diff --git a/core/math/fixed/fixed.odin b/core/math/fixed/fixed.odin index d55e24175..b23090307 100644 --- a/core/math/fixed/fixed.odin +++ b/core/math/fixed/fixed.odin @@ -41,7 +41,7 @@ init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) { init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) { x.i = fraction x.i &= 1< f64 { diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 37c0447cb..90fe7332c 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -3,7 +3,7 @@ package linalg import "core:math" import "base:builtin" import "base:intrinsics" -import "base:runtime" +@require import "base:runtime" // Generic diff --git a/core/math/noise/internal.odin b/core/math/noise/internal.odin index 5837f9235..bd97bd45c 100644 --- a/core/math/noise/internal.odin +++ b/core/math/noise/internal.odin @@ -637,22 +637,20 @@ _internal_noise_4d_unskewed_base :: proc(seed: i64, coord: Vec4) -> (value: f32) // Next point is the closest vertex on the 4-simplex whose base vertex is the aforementioned vertex. score := 1.0 + ssi * (-1.0 / UNSKEW_4D) // Seems slightly faster than 1.0-xsi-ysi-zsi-wsi - if si.x >= si.x && si.x >= si.z && si.x >= si.w && si.x >= score { + switch { + case si.x >= si.x && si.x >= si.z && si.x >= si.w && si.x >= score: svp.x += PRIME_X si.x -= 1 ssi -= UNSKEW_4D - } - else if si.y > si.x && si.y >= si.z && si.y >= si.w && si.y >= score { + case si.y > si.x && si.y >= si.z && si.y >= si.w && si.y >= score: svp.y += PRIME_Y si.y -= 1 ssi -= UNSKEW_4D - } - else if si.z > si.x && si.z > si.y && si.z >= si.w && si.z >= score { + case si.z > si.x && si.z > si.y && si.z >= si.w && si.z >= score: svp.z += PRIME_Z si.z -= 1 ssi -= UNSKEW_4D - } - else if si.w > si.x && si.w > si.y && si.w > si.z && si.w >= score { + case si.w > si.x && si.w > si.y && si.w > si.z && si.w >= score: svp.w += PRIME_W si.w -= 1 ssi -= UNSKEW_4D @@ -690,7 +688,7 @@ _internal_noise_4d_unskewed_base :: proc(seed: i64, coord: Vec4) -> (value: f32) /* Utility functions */ -@(optimization_mode="speed") +@(optimization_mode="favor_size") grad_2d :: proc(seed: i64, svp: [2]i64, delta: [2]f32) -> (value: f32) { hash := seed ~ svp.x ~ svp.y hash *= HASH_MULTIPLIER @@ -700,7 +698,7 @@ grad_2d :: proc(seed: i64, svp: [2]i64, delta: [2]f32) -> (value: f32) { return GRADIENTS_2D[gi] * delta.x + GRADIENTS_2D[gi | 1] * delta.y } -@(optimization_mode="speed") +@(optimization_mode="favor_size") grad_3d :: proc(seed: i64, rvp: [3]i64, delta: [3]f32) -> (value: f32) { hash := (seed ~ rvp.x) ~ (rvp.y ~ rvp.z) hash *= HASH_MULTIPLIER @@ -710,7 +708,7 @@ grad_3d :: proc(seed: i64, rvp: [3]i64, delta: [3]f32) -> (value: f32) { return GRADIENTS_3D[gi] * delta.x + GRADIENTS_3D[gi | 1] * delta.y + GRADIENTS_3D[gi | 2] * delta.z } -@(optimization_mode="speed") +@(optimization_mode="favor_size") grad_4d :: proc(seed: i64, svp: [4]i64, delta: [4]f32) -> (value: f32) { hash := seed ~ (svp.x ~ svp.y) ~ (svp.z ~ svp.w) hash *= HASH_MULTIPLIER @@ -722,13 +720,13 @@ grad_4d :: proc(seed: i64, svp: [4]i64, delta: [4]f32) -> (value: f32) { grad :: proc {grad_2d, grad_3d, grad_4d} -@(optimization_mode="speed") +@(optimization_mode="favor_size") fast_floor :: proc(x: f64) -> (floored: i64) { xi := i64(x) return x < f64(xi) ? xi - 1 : xi } -@(optimization_mode="speed") +@(optimization_mode="favor_size") fast_round :: proc(x: f64) -> (rounded: i64) { return x < 0 ? i64(x - 0.5) : i64(x + 0.5) -} \ No newline at end of file +} diff --git a/core/math/rand/distributions.odin b/core/math/rand/distributions.odin index 9365e8b76..755e6f86f 100644 --- a/core/math/rand/distributions.odin +++ b/core/math/rand/distributions.odin @@ -8,12 +8,12 @@ float32_uniform :: float32_range // Triangular Distribution // See: http://wikipedia.org/wiki/Triangular_distribution @(require_results) -float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 { +float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), gen := context.random_generator) -> f64 { if hi-lo == 0 { return lo } lo, hi := lo, hi - u := float64(r) + u := float64(gen) c := f64(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1) if u > c { u = 1-u @@ -26,12 +26,12 @@ float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 // Triangular Distribution // See: http://wikipedia.org/wiki/Triangular_distribution @(require_results) -float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 { +float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), gen := context.random_generator) -> f32 { if hi-lo == 0 { return lo } lo, hi := lo, hi - u := float32(r) + u := float32(gen) c := f32(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1) if u > c { u = 1-u @@ -44,25 +44,25 @@ float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 // Normal/Gaussian Distribution @(require_results) -float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { - return norm_float64(r) * stddev + mean +float64_normal :: proc(mean, stddev: f64, gen := context.random_generator) -> f64 { + return norm_float64(gen) * stddev + mean } // Normal/Gaussian Distribution @(require_results) -float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { - return f32(float64_normal(f64(mean), f64(stddev), r)) +float32_normal :: proc(mean, stddev: f32, gen := context.random_generator) -> f32 { + return f32(float64_normal(f64(mean), f64(stddev), gen)) } // Log Normal Distribution @(require_results) -float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { - return math.exp(float64_normal(mean, stddev, r)) +float64_log_normal :: proc(mean, stddev: f64, gen := context.random_generator) -> f64 { + return math.exp(float64_normal(mean, stddev, gen)) } // Log Normal Distribution @(require_results) -float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { - return f32(float64_log_normal(f64(mean), f64(stddev), r)) +float32_log_normal :: proc(mean, stddev: f32, gen := context.random_generator) -> f32 { + return f32(float64_log_normal(f64(mean), f64(stddev), gen)) } @@ -72,8 +72,8 @@ float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { // 0 to positive infinity if lambda > 0 // negative infinity to 0 if lambda <= 0 @(require_results) -float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 { - return - math.ln(1 - float64(r)) / lambda +float64_exponential :: proc(lambda: f64, gen := context.random_generator) -> f64 { + return - math.ln(1 - float64(gen)) / lambda } // Exponential Distribution // `lambda` is 1.0/(desired mean). It should be non-zero. @@ -81,8 +81,8 @@ float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 { // 0 to positive infinity if lambda > 0 // negative infinity to 0 if lambda <= 0 @(require_results) -float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 { - return f32(float64_exponential(f64(lambda), r)) +float32_exponential :: proc(lambda: f32, gen := context.random_generator) -> f32 { + return f32(float64_exponential(f64(lambda), gen)) } @@ -96,7 +96,7 @@ float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 { // // mean is alpha*beta, variance is math.pow(alpha*beta, 2) @(require_results) -float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { +float64_gamma :: proc(alpha, beta: f64, gen := context.random_generator) -> f64 { if alpha <= 0 || beta <= 0 { panic(#procedure + ": alpha and beta must be > 0.0") } @@ -112,11 +112,11 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { bbb := alpha - LOG4 ccc := alpha + ainv for { - u1 := float64(r) + u1 := float64(gen) if !(1e-7 < u1 && u1 < 0.9999999) { continue } - u2 := 1 - float64(r) + u2 := 1 - float64(gen) v := math.ln(u1 / (1 - u1)) / ainv x := alpha * math.exp(v) z := u1 * u1 * u2 @@ -127,12 +127,12 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { } case alpha == 1: // float64_exponential(1/beta) - return -math.ln(1 - float64(r)) * beta + return -math.ln(1 - float64(gen)) * beta case: // ALGORITHM GS of Statistical Computing - Kennedy & Gentle x: f64 for { - u := float64(r) + u := float64(gen) b := (math.e + alpha) / math.e p := b * u if p <= 1 { @@ -140,7 +140,7 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { } else { x = -math.ln((b - p) / alpha) } - u1 := float64(r) + u1 := float64(gen) if p > 1 { if u1 <= math.pow(x, alpha-1) { break @@ -162,8 +162,8 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { // // mean is alpha*beta, variance is math.pow(alpha*beta, 2) @(require_results) -float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_gamma(f64(alpha), f64(beta), r)) +float32_gamma :: proc(alpha, beta: f32, gen := context.random_generator) -> f32 { + return f32(float64_gamma(f64(alpha), f64(beta), gen)) } @@ -173,14 +173,14 @@ float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { // // Return values range between 0 and 1 @(require_results) -float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { +float64_beta :: proc(alpha, beta: f64, gen := context.random_generator) -> f64 { if alpha <= 0 || beta <= 0 { panic(#procedure + ": alpha and beta must be > 0.0") } // Knuth Vol 2 Ed 3 pg 134 "the beta distribution" - y := float64_gamma(alpha, 1.0, r) + y := float64_gamma(alpha, 1.0, gen) if y != 0 { - return y / (y + float64_gamma(beta, 1.0, r)) + return y / (y + float64_gamma(beta, 1.0, gen)) } return 0 } @@ -190,35 +190,35 @@ float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { // // Return values range between 0 and 1 @(require_results) -float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_beta(f64(alpha), f64(beta), r)) +float32_beta :: proc(alpha, beta: f32, gen := context.random_generator) -> f32 { + return f32(float64_beta(f64(alpha), f64(beta), gen)) } // Pareto distribution, `alpha` is the shape parameter. // https://wikipedia.org/wiki/Pareto_distribution @(require_results) -float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 { - return math.pow(1 - float64(r), -1.0 / alpha) +float64_pareto :: proc(alpha: f64, gen := context.random_generator) -> f64 { + return math.pow(1 - float64(gen), -1.0 / alpha) } // Pareto distribution, `alpha` is the shape parameter. // https://wikipedia.org/wiki/Pareto_distribution @(require_results) -float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_pareto(f64(alpha), r)) +float32_pareto :: proc(alpha, beta: f32, gen := context.random_generator) -> f32 { + return f32(float64_pareto(f64(alpha), gen)) } // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. @(require_results) -float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { - u := 1 - float64(r) +float64_weibull :: proc(alpha, beta: f64, gen := context.random_generator) -> f64 { + u := 1 - float64(gen) return alpha * math.pow(-math.ln(u), 1.0/beta) } // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. @(require_results) -float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { - return f32(float64_weibull(f64(alpha), f64(beta), r)) +float32_weibull :: proc(alpha, beta: f32, gen := context.random_generator) -> f32 { + return f32(float64_weibull(f64(alpha), f64(beta), gen)) } @@ -227,23 +227,23 @@ float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { // `kappa` is the concentration parameter which must be >= 0 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi @(require_results) -float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { +float64_von_mises :: proc(mean_angle, kappa: f64, gen := context.random_generator) -> f64 { // Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993. mu := mean_angle if kappa <= 1e-6 { - return math.TAU * float64(r) + return math.TAU * float64(gen) } s := 0.5 / kappa t := s + math.sqrt(1 + s*s) z: f64 for { - u1 := float64(r) + u1 := float64(gen) z = math.cos(math.TAU * 0.5 * u1) d := z / (t + z) - u2 := float64(r) + u2 := float64(gen) if u2 < 1 - d*d || u2 <= (1-d)*math.exp(d) { break } @@ -251,7 +251,7 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { q := 1.0 / t f := (q + z) / (1 + q*z) - u3 := float64(r) + u3 := float64(gen) if u3 > 0.5 { return math.mod(mu + math.acos(f), math.TAU) } else { @@ -263,57 +263,57 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { // `kappa` is the concentration parameter which must be >= 0 // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi @(require_results) -float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 { - return f32(float64_von_mises(f64(mean_angle), f64(kappa), r)) +float32_von_mises :: proc(mean_angle, kappa: f32, gen := context.random_generator) -> f32 { + return f32(float64_von_mises(f64(mean_angle), f64(kappa), gen)) } // Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { +float64_cauchy_lorentz :: proc(x_0, gamma: f64, gen := context.random_generator) -> f64 { assert(gamma > 0) // Calculated from the inverse CDF - return math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0 + return math.tan(math.PI * (float64(gen) - 0.5))*gamma + x_0 } // Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { - return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r)) +float32_cauchy_lorentz :: proc(x_0, gamma: f32, gen := context.random_generator) -> f32 { + return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), gen)) } // Log Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { +float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, gen := context.random_generator) -> f64 { assert(gamma > 0) - return math.exp(math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0) + return math.exp(math.tan(math.PI * (float64(gen) - 0.5))*gamma + x_0) } // Log Cauchy-Lorentz Distribution // `x_0` is the location, `gamma` is the scale where `gamma` > 0 @(require_results) -float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { - return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r)) +float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, gen := context.random_generator) -> f32 { + return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), gen)) } // Laplace Distribution // `b` is the scale where `b` > 0 @(require_results) -float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 { +float64_laplace :: proc(mean, b: f64, gen := context.random_generator) -> f64 { assert(b > 0) - p := float64(r)-0.5 + p := float64(gen)-0.5 return -math.sign(p)*math.ln(1 - 2*abs(p))*b + mean } // Laplace Distribution // `b` is the scale where `b` > 0 @(require_results) -float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 { - return f32(float64_laplace(f64(mean), f64(b), r)) +float32_laplace :: proc(mean, b: f32, gen := context.random_generator) -> f32 { + return f32(float64_laplace(f64(mean), f64(b), gen)) } @@ -321,18 +321,18 @@ float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 { // `eta` is the shape, `b` is the scale // Both `eta` and `b` must be > 0 @(require_results) -float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 { +float64_gompertz :: proc(eta, b: f64, gen := context.random_generator) -> f64 { if eta <= 0 || b <= 0 { panic(#procedure + ": eta and b must be > 0.0") } - p := float64(r) + p := float64(gen) return math.ln(1 - math.ln(1 - p)/eta)/b } // Gompertz Distribution // `eta` is the shape, `b` is the scale // Both `eta` and `b` must be > 0 @(require_results) -float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 { - return f32(float64_gompertz(f64(eta), f64(b), r)) +float32_gompertz :: proc(eta, b: f32, gen := context.random_generator) -> f32 { + return f32(float64_gompertz(f64(eta), f64(b), gen)) } diff --git a/core/math/rand/exp.odin b/core/math/rand/exp.odin index ebc849b2f..4ceb750da 100644 --- a/core/math/rand/exp.odin +++ b/core/math/rand/exp.odin @@ -16,7 +16,7 @@ import "core:math" // https://www.jstatsoft.org/article/view/v005i08 [web page] // @(require_results) -exp_float64 :: proc(r: ^Rand = nil) -> f64 { +exp_float64 :: proc(gen := context.random_generator) -> f64 { re :: 7.69711747013104972 @(static, rodata) @@ -199,16 +199,16 @@ exp_float64 :: proc(r: ^Rand = nil) -> f64 { } for { - j := uint32(r) + j := uint32(gen) i := j & 0xFF x := f64(j) * f64(we[i]) if j < ke[i] { return x } if i == 0 { - return re - math.ln(float64(r)) + return re - math.ln(float64(gen)) } - if fe[i]+f32(float64(r))*(fe[i-1]-fe[i]) < f32(math.exp(-x)) { + if fe[i]+f32(float64(gen))*(fe[i-1]-fe[i]) < f32(math.exp(-x)) { return x } } diff --git a/core/math/rand/normal.odin b/core/math/rand/normal.odin index c8681db80..bc566344c 100644 --- a/core/math/rand/normal.odin +++ b/core/math/rand/normal.odin @@ -18,7 +18,7 @@ import "core:math" // https://www.jstatsoft.org/article/view/v005i08 [web page] // @(require_results) -norm_float64 :: proc(r: ^Rand = nil) -> f64 { +norm_float64 :: proc(gen := context.random_generator) -> f64 { rn :: 3.442619855899 @(static, rodata) @@ -115,15 +115,8 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 { 0.008624485, 0.005548995, 0.0026696292, } - r := r - if r == nil { - // NOTE(bill, 2020-09-07): Do this so that people can - // enforce the global random state if necessary with `nil` - r = &global_rand - } - for { - j := i32(uint32(r)) + j := i32(uint32(gen)) i := j & 0x7f x := f64(j) * f64(wn[i]) if u32(abs(j)) < kn[i] { @@ -133,15 +126,15 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 { if i == 0 { for { - x = -math.ln(float64(r)) * (1.0/ rn) - y := -math.ln(float64(r)) + x = -math.ln(float64(gen)) * (1.0/ rn) + y := -math.ln(float64(gen)) if y+y >= x*x { break } } return j > 0 ? rn + x : -rn - x } - if fn[i]+f32(float64(r))*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) { + if fn[i]+f32(float64(gen))*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) { return x } } diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 664d6abc9..4fdbad01c 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -5,22 +5,26 @@ Package core:math/rand implements various random number generators package rand import "base:intrinsics" -import "core:crypto" +import "base:runtime" import "core:math" import "core:mem" -Rand :: struct { - state: u64, - inc: u64, - is_system: bool, +Generator :: runtime.Random_Generator + +Generator_Query_Info :: runtime.Random_Generator_Query_Info + +Default_Random_State :: runtime.Default_Random_State +default_random_generator :: runtime.default_random_generator + +create :: proc(seed: u64) -> (state: Default_Random_State) { + seed := seed + runtime.default_random_generator(&state) + runtime.default_random_generator_proc(&state, .Reset, ([^]byte)(&seed)[:size_of(seed)]) + return } - -@(private) -global_rand := create(u64(intrinsics.read_cycle_counter())) - /* -Sets the seed used by the global random number generator. +Reset the seed used by the context.random_generator. Inputs: - seed: The seed value @@ -37,139 +41,55 @@ Example: Possible Output: 10 - */ +@(deprecated="Prefer `rand.reset`") set_global_seed :: proc(seed: u64) { - init(&global_rand, seed) + runtime.random_generator_reset_u64(context.random_generator, seed) } /* -Creates a new random number generator. +Reset the seed used by the context.random_generator. Inputs: -- seed: The seed value to create the random number generator with - -Returns: -- res: The created random number generator +- seed: The seed value Example: import "core:math/rand" import "core:fmt" - create_example :: proc() { - my_rand := rand.create(1) - fmt.println(rand.uint64(&my_rand)) + set_global_seed_example :: proc() { + rand.set_global_seed(1) + fmt.println(rand.uint64()) } Possible Output: 10 - */ -@(require_results) -create :: proc(seed: u64) -> (res: Rand) { - r: Rand - init(&r, seed) - return r +reset :: proc(seed: u64, gen := context.random_generator) { + runtime.random_generator_reset_u64(gen, seed) } -/* -Initialises a random number generator. - -Inputs: -- r: The random number generator to initialise -- seed: The seed value to initialise this random number generator - -Example: - import "core:math/rand" - import "core:fmt" - - init_example :: proc() { - my_rand: rand.Rand - rand.init(&my_rand, 1) - fmt.println(rand.uint64(&my_rand)) - } - -Possible Output: - - 10 - -*/ -init :: proc(r: ^Rand, seed: u64) { - r.state = 0 - r.inc = (seed << 1) | 1 - _random_u64(r) - r.state += seed - _random_u64(r) +reset_bytes :: proc(bytes: []byte, gen := context.random_generator) { + runtime.random_generator_reset_bytes(gen, bytes) } -/* -Initialises a random number generator to use the system random number generator. -The system random number generator is platform specific, and not supported -on all targets. - -Inputs: -- r: The random number generator to use the system random number generator - -WARNING: Panics if the system random number generator is not supported. -Support can be determined via the `core:crypto.HAS_RAND_BYTES` constant. - -Example: - import "core:crypto" - import "core:math/rand" - import "core:fmt" - - init_as_system_example :: proc() { - my_rand: rand.Rand - switch crypto.HAS_RAND_BYTES { - case true: - rand.init_as_system(&my_rand) - fmt.println(rand.uint64(&my_rand)) - case false: - fmt.println("system random not supported!") - } - } - -Possible Output: - - 10 - -*/ -init_as_system :: proc(r: ^Rand) { - if !crypto.HAS_RAND_BYTES { - panic(#procedure + " is not supported on this platform yet") - } - r.state = 0 - r.inc = 0 - r.is_system = true +query_info :: proc(gen := context.random_generator) -> Generator_Query_Info { + return runtime.random_generator_query_info(gen) } + @(private) -_random_u64 :: proc(r: ^Rand) -> u64 { - r := r - switch { - case r == nil: - r = &global_rand - case r.is_system: - value: u64 - crypto.rand_bytes((cast([^]u8)&value)[:size_of(u64)]) - return value - } - - old_state := r.state - r.state = old_state * 6364136223846793005 + (r.inc|1) - xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081 - rot := (old_state >> 59) - return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63)) +_random_u64 :: proc(gen := context.random_generator) -> (res: u64) { + ok := runtime.random_generator_read_ptr(gen, &res, size_of(res)) + assert(ok, "uninitialized gen/context.random_generator") + return } /* Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random unsigned 32 bit value @@ -178,11 +98,7 @@ Example: import "core:fmt" uint32_example :: proc() { - // Using the global random number generator fmt.println(rand.uint32()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.uint32(&my_rand)) } Possible Output: @@ -192,14 +108,11 @@ Possible Output: */ @(require_results) -uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return u32(_random_u64(r)) } +uint32 :: proc(gen := context.random_generator) -> (val: u32) { return u32(_random_u64(gen)) } /* Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random unsigned 64 bit value @@ -208,11 +121,7 @@ Example: import "core:fmt" uint64_example :: proc() { - // Using the global random number generator fmt.println(rand.uint64()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.uint64(&my_rand)) } Possible Output: @@ -222,14 +131,11 @@ Possible Output: */ @(require_results) -uint64 :: proc(r: ^Rand = nil) -> (val: u64) { return _random_u64(r) } +uint64 :: proc(gen := context.random_generator) -> (val: u64) { return _random_u64(gen) } /* Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random unsigned 128 bit value @@ -238,11 +144,7 @@ Example: import "core:fmt" uint128_example :: proc() { - // Using the global random number generator fmt.println(rand.uint128()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.uint128(&my_rand)) } Possible Output: @@ -252,9 +154,9 @@ Possible Output: */ @(require_results) -uint128 :: proc(r: ^Rand = nil) -> (val: u128) { - a := u128(_random_u64(r)) - b := u128(_random_u64(r)) +uint128 :: proc(gen := context.random_generator) -> (val: u128) { + a := u128(_random_u64(gen)) + b := u128(_random_u64(gen)) return (a<<64) | b } @@ -262,9 +164,6 @@ uint128 :: proc(r: ^Rand = nil) -> (val: u128) { Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random 31 bit value @@ -273,11 +172,7 @@ Example: import "core:fmt" int31_example :: proc() { - // Using the global random number generator fmt.println(rand.int31()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int31(&my_rand)) } Possible Output: @@ -286,15 +181,12 @@ Possible Output: 389 */ -@(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 1 >> 1) } +@(require_results) int31 :: proc(gen := context.random_generator) -> (val: i32) { return i32(uint32(gen) << 1 >> 1) } /* Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random 63 bit value @@ -303,11 +195,7 @@ Example: import "core:fmt" int63_example :: proc() { - // Using the global random number generator fmt.println(rand.int63()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int63(&my_rand)) } Possible Output: @@ -316,15 +204,12 @@ Possible Output: 389 */ -@(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 1 >> 1) } +@(require_results) int63 :: proc(gen := context.random_generator) -> (val: i64) { return i64(uint64(gen) << 1 >> 1) } /* Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random 127 bit value @@ -333,11 +218,7 @@ Example: import "core:fmt" int127_example :: proc() { - // Using the global random number generator fmt.println(rand.int127()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int127(&my_rand)) } Possible Output: @@ -346,14 +227,13 @@ Possible Output: 389 */ -@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) } +@(require_results) int127 :: proc(gen := context.random_generator) -> (val: i128) { return i128(uint128(gen) << 1 >> 1) } /* Generates a random 31 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used. Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random 31 bit value in the range `[0, n)` @@ -365,11 +245,7 @@ Example: import "core:fmt" int31_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int31_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int31_max(1024, &my_rand)) } Possible Output: @@ -379,17 +255,17 @@ Possible Output: */ @(require_results) -int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) { +int31_max :: proc(n: i32, gen := context.random_generator) -> (val: i32) { if n <= 0 { panic("Invalid argument to int31_max") } if n&(n-1) == 0 { - return int31(r) & (n-1) + return int31(gen) & (n-1) } max := i32((1<<31) - 1 - (1<<31)%u32(n)) - v := int31(r) + v := int31(gen) for v > max { - v = int31(r) + v = int31(gen) } return v % n } @@ -399,7 +275,6 @@ Generates a random 63 bit value in the range `[0, n)` using the provided random Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random 63 bit value in the range `[0, n)` @@ -411,11 +286,7 @@ Example: import "core:fmt" int63_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int63_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int63_max(1024, &my_rand)) } Possible Output: @@ -425,17 +296,17 @@ Possible Output: */ @(require_results) -int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) { +int63_max :: proc(n: i64, gen := context.random_generator) -> (val: i64) { if n <= 0 { panic("Invalid argument to int63_max") } if n&(n-1) == 0 { - return int63(r) & (n-1) + return int63(gen) & (n-1) } max := i64((1<<63) - 1 - (1<<63)%u64(n)) - v := int63(r) + v := int63(gen) for v > max { - v = int63(r) + v = int63(gen) } return v % n } @@ -445,7 +316,6 @@ Generates a random 127 bit value in the range `[0, n)` using the provided random Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random 127 bit value in the range `[0, n)` @@ -457,11 +327,7 @@ Example: import "core:fmt" int127_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int127_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int127_max(1024, &my_rand)) } Possible Output: @@ -471,17 +337,17 @@ Possible Output: */ @(require_results) -int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) { +int127_max :: proc(n: i128, gen := context.random_generator) -> (val: i128) { if n <= 0 { panic("Invalid argument to int127_max") } if n&(n-1) == 0 { - return int127(r) & (n-1) + return int127(gen) & (n-1) } max := i128((1<<127) - 1 - (1<<127)%u128(n)) - v := int127(r) + v := int127(gen) for v > max { - v = int127(r) + v = int127(gen) } return v % n } @@ -491,7 +357,6 @@ Generates a random integer value in the range `[0, n)` using the provided random Inputs: - n: The upper bound of the generated number, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random integer value in the range `[0, n)` @@ -503,11 +368,7 @@ Example: import "core:fmt" int_max_example :: proc() { - // Using the global random number generator fmt.println(rand.int_max(16)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.int_max(1024, &my_rand)) } Possible Output: @@ -517,23 +378,20 @@ Possible Output: */ @(require_results) -int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) { +int_max :: proc(n: int, gen := context.random_generator) -> (val: int) { if n <= 0 { panic("Invalid argument to int_max") } when size_of(int) == 4 { - return int(int31_max(i32(n), r)) + return int(int31_max(i32(n), gen)) } else { - return int(int63_max(i64(n), r)) + return int(int63_max(i64(n), gen)) } } /* Generates a random double floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random double floating point value in the range `[0, 1)` @@ -542,11 +400,7 @@ Example: import "core:fmt" float64_example :: proc() { - // Using the global random number generator fmt.println(rand.float64()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float64(&my_rand)) } Possible Output: @@ -555,14 +409,11 @@ Possible Output: 0.511 */ -@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) } +@(require_results) float64 :: proc(gen := context.random_generator) -> (val: f64) { return f64(int63_max(1<<53, gen)) / (1 << 53) } /* Generates a random single floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used. -Inputs: -- r: The random number generator to use, or nil for the global generator - Returns: - val: A random single floating point value in the range `[0, 1)` @@ -571,11 +422,7 @@ Example: import "core:fmt" float32_example :: proc() { - // Using the global random number generator fmt.println(rand.float32()) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float32(&my_rand)) } Possible Output: @@ -584,7 +431,7 @@ Possible Output: 0.511 */ -@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(int31_max(1<<24, r)) / (1 << 24) } +@(require_results) float32 :: proc(gen := context.random_generator) -> (val: f32) { return f32(int31_max(1<<24, gen)) / (1 << 24) } /* Generates a random double floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used. @@ -594,7 +441,6 @@ WARNING: Panics if `high < low` Inputs: - low: The lower bounds of the value, this value is inclusive - high: The upper bounds of the value, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random double floating point value in the range [low, high) @@ -604,11 +450,7 @@ Example: import "core:fmt" float64_range_example :: proc() { - // Using the global random number generator fmt.println(rand.float64_range(-10, 300)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float64_range(600, 900, &my_rand)) } Possible Output: @@ -617,9 +459,9 @@ Possible Output: 673.130 */ -@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { +@(require_results) float64_range :: proc(low, high: f64, gen := context.random_generator) -> (val: f64) { assert(low <= high, "low must be lower than or equal to high") - val = (high-low)*float64(r) + low + val = (high-low)*float64(gen) + low if val >= high { val = max(low, high * (1 - math.F64_EPSILON)) } @@ -632,7 +474,6 @@ Generates a random single floating point value in the range `[low, high)` using Inputs: - low: The lower bounds of the value, this value is inclusive - high: The upper bounds of the value, this value is exclusive -- r: The random number generator to use, or nil for the global generator Returns: - val: A random single floating point value in the range [low, high) @@ -644,11 +485,7 @@ Example: import "core:fmt" float32_range_example :: proc() { - // Using the global random number generator fmt.println(rand.float32_range(-10, 300)) - // Using local random number generator - my_rand := rand.create(1) - fmt.println(rand.float32_range(600, 900, &my_rand)) } Possible Output: @@ -657,9 +494,9 @@ Possible Output: 673.130 */ -@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { +@(require_results) float32_range :: proc(low, high: f32, gen := context.random_generator) -> (val: f32) { assert(low <= high, "low must be lower than or equal to high") - val = (high-low)*float32(r) + low + val = (high-low)*float32(gen) + low if val >= high { val = max(low, high * (1 - math.F32_EPSILON)) } @@ -672,7 +509,6 @@ Due to floating point precision there is no guarantee if the upper and lower bou Inputs: - p: The byte slice to fill -- r: The random number generator to use, or nil for the global generator Returns: - n: The number of bytes generated @@ -682,7 +518,6 @@ Example: import "core:fmt" read_example :: proc() { - // Using the global random number generator data: [8]byte n := rand.read(data[:]) fmt.println(n) @@ -696,12 +531,12 @@ Possible Output: */ @(require_results) -read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) { +read :: proc(p: []byte, gen := context.random_generator) -> (n: int) { pos := i8(0) val := i64(0) for n = 0; n < len(p); n += 1 { if pos == 0 { - val = int63(r) + val = int63(gen) pos = 7 } p[n] = byte(val) @@ -718,7 +553,6 @@ Creates a slice of `int` filled with random values using the provided random num Inputs: - n: The size of the created slice -- r: The random number generator to use, or nil for the global generator - allocator: (default: context.allocator) Returns: @@ -731,16 +565,10 @@ Example: import "core:fmt" perm_example :: proc() -> (err: mem.Allocator_Error) { - // Using the global random number generator and using the context allocator data := rand.perm(4) or_return fmt.println(data) defer delete(data, context.allocator) - // Using local random number generator and temp allocator - my_rand := rand.create(1) - data_tmp := rand.perm(4, &my_rand, context.temp_allocator) or_return - fmt.println(data_tmp) - return } @@ -751,10 +579,10 @@ Possible Output: */ @(require_results) -perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error { +perm :: proc(n: int, allocator := context.allocator, gen := context.random_generator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error { m := make([]int, n, allocator) or_return for i := 0; i < n; i += 1 { - j := int_max(i+1, r) + j := int_max(i+1, gen) m[i] = m[j] m[j] = i } @@ -766,14 +594,12 @@ Randomizes the ordering of elements for the provided slice. If no generator is p Inputs: - array: The slice to randomize -- r: The random number generator to use, or nil for the global generator Example: import "core:math/rand" import "core:fmt" shuffle_example :: proc() { - // Using the global random number generator data: [4]int = { 1, 2, 3, 4 } fmt.println(data) // the contents are in order rand.shuffle(data[:]) @@ -786,14 +612,14 @@ Possible Output: [2, 4, 3, 1] */ -shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) { +shuffle :: proc(array: $T/[]$E, gen := context.random_generator) { n := i64(len(array)) if n < 2 { return } for i := i64(n - 1); i > 0; i -= 1 { - j := int63_max(i + 1, r) + j := int63_max(i + 1, gen) array[i], array[j] = array[j], array[i] } } @@ -803,7 +629,6 @@ Returns a random element from the provided slice. If no generator is provided th Inputs: - array: The slice to choose an element from -- r: The random number generator to use, or nil for the global generator Returns: - res: A random element from `array` @@ -813,7 +638,6 @@ Example: import "core:fmt" choice_example :: proc() { - // Using the global random number generator data: [4]int = { 1, 2, 3, 4 } fmt.println(rand.choice(data[:])) fmt.println(rand.choice(data[:])) @@ -830,29 +654,29 @@ Possible Output: */ @(require_results) -choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) { +choice :: proc(array: $T/[]$E, gen := context.random_generator) -> (res: E) { n := i64(len(array)) if n < 1 { return E{} } - return array[int63_max(n, r)] + return array[int63_max(n, gen)] } @(require_results) -choice_enum :: proc($T: typeid, r: ^Rand = nil) -> T +choice_enum :: proc($T: typeid, gen := context.random_generator) -> T where intrinsics.type_is_enum(T), size_of(T) <= 8, - len(T) == cap(T) /* Only allow contiguous enum types */ + len(T) == cap(T) /* Only allow contiguous enum types */ \ { when intrinsics.type_is_unsigned(intrinsics.type_core_type(T)) && u64(max(T)) > u64(max(i64)) { - i := uint64(r) % u64(len(T)) + i := uint64(gen) % u64(len(T)) i += u64(min(T)) return T(i) } else { - i := int63_max(i64(len(T)), r) + i := int63_max(i64(len(T)), gen) i += i64(min(T)) return T(i) } diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 1d79e09c1..a5b93ad05 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -748,9 +748,7 @@ dynamic_pool_alloc_bytes :: proc(p: ^Dynamic_Pool, bytes: int) -> ([]byte, Alloc return } - n := bytes - extra := p.alignment - (n % p.alignment) - n += extra + n := align_formula(bytes, p.alignment) if n > p.block_size { return nil, .Invalid_Argument } diff --git a/core/mem/tlsf/tlsf.odin b/core/mem/tlsf/tlsf.odin index 76ecbb4b1..8ec5f52b7 100644 --- a/core/mem/tlsf/tlsf.odin +++ b/core/mem/tlsf/tlsf.odin @@ -97,6 +97,10 @@ init :: proc{init_from_buffer, init_from_allocator} destroy :: proc(control: ^Allocator) { if control == nil { return } + if control.pool.allocator.procedure != nil { + runtime.delete(control.pool.data, control.pool.allocator) + } + // No need to call `pool_remove` or anything, as they're they're embedded in the backing memory. // We do however need to free the `Pool` tracking entities and the backing memory itself. // As `Allocator` is embedded in the first backing slice, the `control` pointer will be @@ -132,8 +136,9 @@ allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, return nil, nil case .Free_All: - clear(control) - return nil, nil + // NOTE: this doesn't work right at the moment, Jeroen has it on his to-do list :) + // clear(control) + return nil, .Mode_Not_Implemented case .Resize: return resize(control, old_memory, uint(old_size), uint(size), uint(alignment)) @@ -144,7 +149,7 @@ allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, case .Query_Features: set := (^runtime.Allocator_Mode_Set)(old_memory) if set != nil { - set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features} + set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, /* .Free_All, */ .Resize, .Resize_Non_Zeroed, .Query_Features} } return nil, nil @@ -153,4 +158,4 @@ allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, } return nil, nil -} \ No newline at end of file +} diff --git a/core/mem/tlsf/tlsf_internal.odin b/core/mem/tlsf/tlsf_internal.odin index 6f33e516c..cac151183 100644 --- a/core/mem/tlsf/tlsf_internal.odin +++ b/core/mem/tlsf/tlsf_internal.odin @@ -214,7 +214,7 @@ block_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) { block_link_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) { next = block_next(block) next.prev_phys_block = block - return + return } block_mark_as_free :: proc(block: ^Block_Header) { @@ -284,7 +284,7 @@ adjust_request_size_with_err :: proc(size, align: uint) -> (adjusted: uint, err: // TLSF utility functions. In most cases these are direct translations of // the documentation in the research paper. -@(optimization_mode="speed", require_results) +@(optimization_mode="favor_size", require_results) mapping_insert :: proc(size: uint) -> (fl, sl: i32) { if size < SMALL_BLOCK_SIZE { // Store small blocks in first list. @@ -297,7 +297,7 @@ mapping_insert :: proc(size: uint) -> (fl, sl: i32) { return } -@(optimization_mode="speed", require_results) +@(optimization_mode="favor_size", require_results) mapping_round :: #force_inline proc(size: uint) -> (rounded: uint) { rounded = size if size >= SMALL_BLOCK_SIZE { @@ -308,7 +308,7 @@ mapping_round :: #force_inline proc(size: uint) -> (rounded: uint) { } // This version rounds up to the next block size (for allocations) -@(optimization_mode="speed", require_results) +@(optimization_mode="favor_size", require_results) mapping_search :: proc(size: uint) -> (fl, sl: i32) { return mapping_insert(mapping_round(size)) } @@ -630,7 +630,7 @@ alloc_bytes_non_zeroed :: proc(control: ^Allocator, size: uint, align: uint) -> @(require_results) alloc_bytes :: proc(control: ^Allocator, size: uint, align: uint) -> (res: []byte, err: runtime.Allocator_Error) { res, err = alloc_bytes_non_zeroed(control, size, align) - if err != nil { + if err == nil { intrinsics.mem_zero(raw_data(res), len(res)) } return @@ -735,4 +735,4 @@ resize_non_zeroed :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: block_trim_used(control, block, adjust) res = ([^]byte)(ptr)[:new_size] return -} \ No newline at end of file +} diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin index 816a8bb84..0b4532baa 100644 --- a/core/mem/virtual/virtual_linux.odin +++ b/core/mem/virtual/virtual_linux.odin @@ -36,9 +36,9 @@ _release :: proc "contextless" (data: rawptr, size: uint) { _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { pflags: linux.Mem_Protection pflags = {} - if .Read in flags { pflags |= {.READ} } - if .Write in flags { pflags |= {.WRITE} } - if .Execute in flags { pflags |= {.EXEC} } + if .Read in flags { pflags += {.READ} } + if .Write in flags { pflags += {.WRITE} } + if .Execute in flags { pflags += {.EXEC} } errno := linux.mprotect(data, size, pflags) return errno == .NONE } diff --git a/core/mem/virtual/virtual_bsd.odin b/core/mem/virtual/virtual_other.odin similarity index 92% rename from core/mem/virtual/virtual_bsd.odin rename to core/mem/virtual/virtual_other.odin index 12e7818ef..96d9683c4 100644 --- a/core/mem/virtual/virtual_bsd.odin +++ b/core/mem/virtual/virtual_other.odin @@ -1,5 +1,7 @@ -//+build freebsd, openbsd, netbsd //+private +//+build !darwin +//+build !linux +//+build !windows package mem_virtual _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { diff --git a/core/net/addr.odin b/core/net/addr.odin index c01724d99..eed3fb3b9 100644 --- a/core/net/addr.odin +++ b/core/net/addr.odin @@ -370,7 +370,7 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address, val |= u16(ipv4[3]) piece_values[7] = u16be(val) } - return transmute(IP6_Address)piece_values, true + return IP6_Address(piece_values), true } /* @@ -522,10 +522,9 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> run := Zero_Run{-1, -1} best := Zero_Run{-1, -1} - addr := transmute([8]u16be)v last := u16be(1) - for val, i in addr { + for val, i in v { /* If we encounter adjacent zeroes, then start a new run if not already in one. Also remember the rightmost index regardless, because it'll be the new @@ -559,7 +558,7 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> last = val } - for val, i in addr { + for val, i in v { if best.start == i || best.end == i { // For the left and right side of the best zero run, print a `:`. fmt.sbprint(&b, ":") diff --git a/core/net/errors_windows.odin b/core/net/errors_windows.odin index 0538c2b82..f63f17f4e 100644 --- a/core/net/errors_windows.odin +++ b/core/net/errors_windows.odin @@ -135,6 +135,7 @@ TCP_Send_Error :: enum c.int { No_Buffer_Space_Available = win.WSAENOBUFS, Network_Subsystem_Failure = win.WSAENETDOWN, Host_Unreachable = win.WSAEHOSTUNREACH, + Would_Block = win.WSAEWOULDBLOCK, // TODO: verify possible, as not mentioned in docs Offline = win.WSAENETUNREACH, diff --git a/core/net/interface_darwin.odin b/core/net/interface_darwin.odin index 59b0e01c5..e2a9a73ca 100644 --- a/core/net/interface_darwin.odin +++ b/core/net/interface_darwin.odin @@ -59,24 +59,21 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] switch int(ifaddr.address.family) { case os.AF_INET, os.AF_INET6: address = _sockaddr_basic_to_endpoint(ifaddr.address).address - case: } } if ifaddr.netmask != nil { switch int(ifaddr.netmask.family) { case os.AF_INET, os.AF_INET6: - netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address) - case: + netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address) } } if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags { switch int(ifaddr.broadcast_or_dest.family) { case os.AF_INET, os.AF_INET6: - broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address - append(&iface.multicast, broadcast) - case: + broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address + append(&iface.multicast, broadcast) } } @@ -91,19 +88,19 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] /* TODO: Refine this based on the type of adapter. */ - state := Link_State{} + state := Link_State{} - if .UP in ifaddr.flags { - state |= {.Up} - } + if .UP in ifaddr.flags { + state += {.Up} + } - /*if .DORMANT in ifaddr.flags { - state |= {.Dormant} - }*/ + /*if .DORMANT in ifaddr.flags { + state |= {.Dormant} + }*/ - if .LOOPBACK in ifaddr.flags { - state |= {.Loopback} - } + if .LOOPBACK in ifaddr.flags { + state += {.Loopback} + } iface.link.state = state } diff --git a/core/net/interface_windows.odin b/core/net/interface_windows.odin index f8bac253a..b9abcff48 100644 --- a/core/net/interface_windows.odin +++ b/core/net/interface_windows.odin @@ -24,42 +24,42 @@ import strings "core:strings" _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { context.allocator = allocator - buf: []u8 - defer delete(buf) + buf: []u8 + defer delete(buf) - buf_size: u32 - res: u32 + buf_size: u32 + res: u32 - gaa: for _ in 1..=MAX_INTERFACE_ENUMERATION_TRIES { - res = sys.get_adapters_addresses( - .Unspecified, // Return both IPv4 and IPv6 adapters. + gaa: for _ in 1..=MAX_INTERFACE_ENUMERATION_TRIES { + res = sys.get_adapters_addresses( + .Unspecified, // Return both IPv4 and IPv6 adapters. sys.GAA_Flags{ .Include_Prefix, // (XP SP1+) Return a list of IP address prefixes on this adapter. When this flag is set, IP address prefixes are returned for both IPv6 and IPv4 addresses. .Include_Gateways, // (Vista+) Return the addresses of default gateways. .Include_Tunnel_Binding_Order, // (Vista+) Return the adapter addresses sorted in tunnel binding order. }, - nil, // Reserved - (^sys.IP_Adapter_Addresses)(raw_data(buf)), - &buf_size, - ) + nil, // Reserved + (^sys.IP_Adapter_Addresses)(raw_data(buf)), + &buf_size, + ) - switch res { - case 111: // ERROR_BUFFER_OVERFLOW: - delete(buf) - buf = make([]u8, buf_size) - case 0: - break gaa - case: - return {}, Platform_Error(res) - } - } + switch res { + case 111: // ERROR_BUFFER_OVERFLOW: + delete(buf) + buf = make([]u8, buf_size) + case 0: + break gaa + case: + return {}, Platform_Error(res) + } + } - if res != 0 { - return {}, .Unable_To_Enumerate_Network_Interfaces - } + if res != 0 { + return {}, .Unable_To_Enumerate_Network_Interfaces + } - _interfaces := make([dynamic]Network_Interface, 0, allocator) - for adapter := (^sys.IP_Adapter_Addresses)(raw_data(buf)); adapter != nil; adapter = adapter.Next { + _interfaces := make([dynamic]Network_Interface, 0, allocator) + for adapter := (^sys.IP_Adapter_Addresses)(raw_data(buf)); adapter != nil; adapter = adapter.Next { friendly_name, err1 := sys.wstring_to_utf8(sys.wstring(adapter.FriendlyName), 256, allocator) if err1 != nil { return {}, Platform_Error(err1) } @@ -71,74 +71,74 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] interface := Network_Interface{ adapter_name = strings.clone(string(adapter.AdapterName)), - friendly_name = friendly_name, - description = description, - dns_suffix = dns_suffix, + friendly_name = friendly_name, + description = description, + dns_suffix = dns_suffix, - mtu = adapter.MTU, + mtu = adapter.MTU, - link = { + link = { transmit_speed = adapter.TransmitLinkSpeed, receive_speed = adapter.ReceiveLinkSpeed, - }, - } + }, + } - if adapter.PhysicalAddressLength > 0 && adapter.PhysicalAddressLength <= len(adapter.PhysicalAddress) { - interface.physical_address = physical_address_to_string(adapter.PhysicalAddress[:adapter.PhysicalAddressLength]) - } + if adapter.PhysicalAddressLength > 0 && adapter.PhysicalAddressLength <= len(adapter.PhysicalAddress) { + interface.physical_address = physical_address_to_string(adapter.PhysicalAddress[:adapter.PhysicalAddressLength]) + } - for u_addr := (^sys.IP_ADAPTER_UNICAST_ADDRESS_LH)(adapter.FirstUnicastAddress); u_addr != nil; u_addr = u_addr.Next { - win_addr := parse_socket_address(u_addr.Address) + for u_addr := (^sys.IP_ADAPTER_UNICAST_ADDRESS_LH)(adapter.FirstUnicastAddress); u_addr != nil; u_addr = u_addr.Next { + win_addr := parse_socket_address(u_addr.Address) - lease := Lease{ - address = win_addr.address, - origin = { - prefix = Prefix_Origin(u_addr.PrefixOrigin), - suffix = Suffix_Origin(u_addr.SuffixOrigin), - }, - lifetime = { - valid = u_addr.ValidLifetime, - preferred = u_addr.PreferredLifetime, - lease = u_addr.LeaseLifetime, - }, - address_duplication = Address_Duplication(u_addr.DadState), - } - append(&interface.unicast, lease) - } + lease := Lease{ + address = win_addr.address, + origin = { + prefix = Prefix_Origin(u_addr.PrefixOrigin), + suffix = Suffix_Origin(u_addr.SuffixOrigin), + }, + lifetime = { + valid = u_addr.ValidLifetime, + preferred = u_addr.PreferredLifetime, + lease = u_addr.LeaseLifetime, + }, + address_duplication = Address_Duplication(u_addr.DadState), + } + append(&interface.unicast, lease) + } - for a_addr := (^sys.IP_ADAPTER_ANYCAST_ADDRESS_XP)(adapter.FirstAnycastAddress); a_addr != nil; a_addr = a_addr.Next { - addr := parse_socket_address(a_addr.Address) - append(&interface.anycast, addr.address) - } + for a_addr := (^sys.IP_ADAPTER_ANYCAST_ADDRESS_XP)(adapter.FirstAnycastAddress); a_addr != nil; a_addr = a_addr.Next { + addr := parse_socket_address(a_addr.Address) + append(&interface.anycast, addr.address) + } - for m_addr := (^sys.IP_ADAPTER_MULTICAST_ADDRESS_XP)(adapter.FirstMulticastAddress); m_addr != nil; m_addr = m_addr.Next { - addr := parse_socket_address(m_addr.Address) - append(&interface.multicast, addr.address) - } + for m_addr := (^sys.IP_ADAPTER_MULTICAST_ADDRESS_XP)(adapter.FirstMulticastAddress); m_addr != nil; m_addr = m_addr.Next { + addr := parse_socket_address(m_addr.Address) + append(&interface.multicast, addr.address) + } - for g_addr := (^sys.IP_ADAPTER_GATEWAY_ADDRESS_LH)(adapter.FirstGatewayAddress); g_addr != nil; g_addr = g_addr.Next { - addr := parse_socket_address(g_addr.Address) - append(&interface.gateways, addr.address) - } + for g_addr := (^sys.IP_ADAPTER_GATEWAY_ADDRESS_LH)(adapter.FirstGatewayAddress); g_addr != nil; g_addr = g_addr.Next { + addr := parse_socket_address(g_addr.Address) + append(&interface.gateways, addr.address) + } interface.dhcp_v4 = parse_socket_address(adapter.Dhcpv4Server).address interface.dhcp_v6 = parse_socket_address(adapter.Dhcpv6Server).address - switch adapter.OperStatus { - case .Up: interface.link.state = {.Up} - case .Down: interface.link.state = {.Down} - case .Testing: interface.link.state = {.Testing} - case .Dormant: interface.link.state = {.Dormant} - case .NotPresent: interface.link.state = {.Not_Present} - case .LowerLayerDown: interface.link.state = {.Lower_Layer_Down} - case .Unknown: fallthrough - case: interface.link.state = {} - } + switch adapter.OperStatus { + case .Up: interface.link.state = {.Up} + case .Down: interface.link.state = {.Down} + case .Testing: interface.link.state = {.Testing} + case .Dormant: interface.link.state = {.Dormant} + case .NotPresent: interface.link.state = {.Not_Present} + case .LowerLayerDown: interface.link.state = {.Lower_Layer_Down} + case .Unknown: fallthrough + case: interface.link.state = {} + } - interface.tunnel_type = Tunnel_Type(adapter.TunnelType) + interface.tunnel_type = Tunnel_Type(adapter.TunnelType) - append(&_interfaces, interface) - } + append(&_interfaces, interface) + } return _interfaces[:], {} } diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index ba86f1005..fc422b3a9 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -274,8 +274,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca .Linger, .Send_Timeout, .Receive_Timeout: - t, ok := value.(time.Duration) - if !ok do panic("set_option() value must be a time.Duration here", loc) + t := value.(time.Duration) or_else panic("set_option() value must be a time.Duration here", loc) micros := i64(time.duration_microseconds(t)) timeval_value.microseconds = int(micros % 1e6) @@ -320,7 +319,7 @@ _set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_E } if should_block { - flags &= ~int(os.O_NONBLOCK) + flags &~= int(os.O_NONBLOCK) } else { flags |= int(os.O_NONBLOCK) } diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index a4d75b92b..a5d553234 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -80,14 +80,14 @@ _unwrap_os_addr :: proc "contextless" (endpoint: Endpoint)->(linux.Sock_Addr_Any ipv4 = { sin_family = .INET, sin_port = u16be(endpoint.port), - sin_addr = transmute([4]u8) endpoint.address.(IP4_Address), + sin_addr = ([4]u8)(endpoint.address.(IP4_Address)), }, } case IP6_Address: return { ipv6 = { sin6_port = u16be(endpoint.port), - sin6_addr = transmute([16]u8) endpoint.address.(IP6_Address), + sin6_addr = transmute([16]u8)endpoint.address.(IP6_Address), sin6_family = .INET6, }, } @@ -377,9 +377,9 @@ _set_blocking :: proc(sock: Any_Socket, should_block: bool) -> (err: Network_Err return Set_Blocking_Error(errno) } if should_block { - flags &= ~{.NONBLOCK} + flags -= {.NONBLOCK} } else { - flags |= {.NONBLOCK} + flags += {.NONBLOCK} } errno = linux.fcntl(os_sock, linux.F_SETFL, flags) if errno != .NONE { diff --git a/core/net/socket_windows.odin b/core/net/socket_windows.odin index 3b9623749..eef0df583 100644 --- a/core/net/socket_windows.odin +++ b/core/net/socket_windows.odin @@ -263,12 +263,15 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca ptr = &bool_value len = size_of(bool_value) case .Linger: - t, ok := value.(time.Duration) - if !ok do panic("set_option() value must be a time.Duration here", loc) + t := value.(time.Duration) or_else panic("set_option() value must be a time.Duration here", loc) num_secs := i64(time.duration_seconds(t)) - if time.Duration(num_secs * 1e9) != t do return .Linger_Only_Supports_Whole_Seconds - if num_secs > i64(max(u16)) do return .Value_Out_Of_Range + if time.Duration(num_secs * 1e9) != t { + return .Linger_Only_Supports_Whole_Seconds + } + if num_secs > i64(max(u16)) { + return .Value_Out_Of_Range + } linger_value.l_onoff = 1 linger_value.l_linger = c.ushort(num_secs) @@ -277,8 +280,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca case .Receive_Timeout, .Send_Timeout: - t, ok := value.(time.Duration) - if !ok do panic("set_option() value must be a time.Duration here", loc) + t := value.(time.Duration) or_else panic("set_option() value must be a time.Duration here", loc) int_value = i32(time.duration_milliseconds(t)) ptr = &int_value diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 229f03d3d..92d00b47c 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -513,6 +513,7 @@ Package_Decl :: struct { Import_Decl :: struct { using node: Decl, docs: ^Comment_Group, + attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily is_using: bool, import_tok: tokenizer.Token, name: tokenizer.Token, diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 6b0aa2888..dec892f84 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -308,7 +308,7 @@ consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Gro end_line = p.curr_tok.pos.line for p.curr_tok.kind == .Comment && p.curr_tok.pos.line <= end_line+n { - comment: tokenizer.Token + comment: tokenizer.Token comment, end_line = consume_comment(p) append(&list, comment) } @@ -689,7 +689,12 @@ parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt { prev_level := p.expr_level p.expr_level = -1 + prev_allow_in_expr := p.allow_in_expr + p.allow_in_expr = true + cond = parse_expr(p, false) + + p.allow_in_expr = prev_allow_in_expr p.expr_level = prev_level if cond == nil { @@ -1103,6 +1108,9 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: case ^ast.Foreign_Import_Decl: if d.docs == nil { d.docs = docs } append(&d.attributes, attribute) + case ^ast.Import_Decl: + if d.docs == nil { d.docs = docs } + append(&d.attributes, attribute) case: error(p, decl.pos, "expected a value or foreign declaration after an attribute") free(attribute) @@ -1307,8 +1315,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { // Unary Expressions .Add, .Sub, .Xor, .Not, .And: - s := parse_simple_stmt(p, {Stmt_Allow_Flag.Label}) - expect_semicolon(p, s) + s := parse_simple_stmt(p, {Stmt_Allow_Flag.Label}) + expect_semicolon(p, s) return s @@ -1845,7 +1853,7 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr { } if p.curr_tok.kind != .Comma || p.curr_tok.kind == .EOF { - break + break } advance_token(p) } @@ -2208,10 +2216,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { case .Integer, .Float, .Imag, .Rune, .String: - tok := advance_token(p) - bl := ast.new(ast.Basic_Lit, tok.pos, end_pos(tok)) - bl.tok = tok - return bl + tok := advance_token(p) + bl := ast.new(ast.Basic_Lit, tok.pos, end_pos(tok)) + bl.tok = tok + return bl case .Open_Brace: if !lhs { @@ -2999,7 +3007,7 @@ parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit { } p.expr_level -= 1 - skip_possible_newline(p) + skip_possible_newline(p) close := expect_closing_brace_of_field_list(p) pos := type.pos if type != nil else open.pos diff --git a/core/os/os.odin b/core/os/os.odin index aa460fe01..51652a52b 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -111,7 +111,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, length: i64 err: Errno if length, err = file_size(fd); err != 0 { - return nil, false + return nil, false } if length <= 0 { @@ -120,7 +120,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, data = make([]byte, int(length), allocator, loc) if data == nil { - return nil, false + return nil, false } bytes_read, read_err := read_full(fd, data) diff --git a/core/os/os2/env_linux.odin b/core/os/os2/env_linux.odin index eb463f22c..99dd00d90 100644 --- a/core/os/os2/env_linux.odin +++ b/core/os/os2/env_linux.odin @@ -2,29 +2,230 @@ package os2 import "base:runtime" +import "base:intrinsics" + +import "core:sync" +import "core:slice" +import "core:strings" + +// TODO: IF NO_CRT: +// Override the libc environment functions' weak linkage to +// allow us to interact with 3rd party code that DOES link +// to libc. Otherwise, our environment can be out of sync. +// ELSE: +// Just use the libc. + +NOT_FOUND :: -1 + +// the environment is a 0 delimited list of = strings +_env: [dynamic]string + +_env_mutex: sync.Mutex + +// We need to be able to figure out if the environment variable +// is contained in the original environment or not. This also +// serves as a flag to determine if we have built _env. +_org_env_begin: uintptr +_org_env_end: uintptr + +// Returns value + index location into _env +// or -1 if not found +_lookup :: proc(key: string) -> (value: string, idx: int) { + sync.mutex_lock(&_env_mutex) + defer sync.mutex_unlock(&_env_mutex) + + for entry, i in _env { + if k, v := _kv_from_entry(entry); k == key { + return v, i + } + } + return "", -1 +} _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { - //TODO + if _org_env_begin == 0 { + _build_env() + } + + if v, idx := _lookup(key); idx != -1 { + found = true + value, _ = clone_string(v, allocator) + } return } -_set_env :: proc(key, value: string) -> bool { - //TODO - return false +_set_env :: proc(key, v_new: string) -> bool { + if _org_env_begin == 0 { + _build_env() + } + + // all key values are stored as "key=value\x00" + kv_size := len(key) + len(v_new) + 2 + if v_curr, idx := _lookup(key); idx != NOT_FOUND { + if v_curr == v_new { + return true + } + sync.mutex_lock(&_env_mutex) + defer sync.mutex_unlock(&_env_mutex) + + unordered_remove(&_env, idx) + + if !_is_in_org_env(v_curr) { + // We allocated this key-value. Possibly resize and + // overwrite the value only. Otherwise, treat as if it + // wasn't in the environment in the first place. + k_addr, v_addr := _kv_addr_from_val(v_curr, key) + if len(v_new) > len(v_curr) { + k_addr = ([^]u8)(heap_resize(k_addr, kv_size)) + if k_addr == nil { + return false + } + v_addr = &k_addr[len(key) + 1] + } + intrinsics.mem_copy_non_overlapping(v_addr, raw_data(v_new), len(v_new)) + v_addr[len(v_new)] = 0 + + append(&_env, string(k_addr[:kv_size])) + return true + } + } + + k_addr := ([^]u8)(heap_alloc(kv_size)) + if k_addr == nil { + return false + } + intrinsics.mem_copy_non_overlapping(k_addr, raw_data(key), len(key)) + k_addr[len(key)] = '=' + + val_slice := k_addr[len(key) + 1:] + intrinsics.mem_copy_non_overlapping(&val_slice[0], raw_data(v_new), len(v_new)) + val_slice[len(v_new)] = 0 + + sync.mutex_lock(&_env_mutex) + append(&_env, string(k_addr[:kv_size - 1])) + sync.mutex_unlock(&_env_mutex) + return true } _unset_env :: proc(key: string) -> bool { - //TODO - return false + if _org_env_begin == 0 { + _build_env() + } + + v: string + i: int + if v, i = _lookup(key); i == -1 { + return false + } + + sync.mutex_lock(&_env_mutex) + unordered_remove(&_env, i) + sync.mutex_unlock(&_env_mutex) + + if _is_in_org_env(v) { + return true + } + + // if we got this far, the envrionment variable + // existed AND was allocated by us. + k_addr, _ := _kv_addr_from_val(v, key) + heap_free(k_addr) + return true } _clear_env :: proc() { - //TODO + sync.mutex_lock(&_env_mutex) + defer sync.mutex_unlock(&_env_mutex) + + for kv in _env { + if !_is_in_org_env(kv) { + heap_free(raw_data(kv)) + } + } + clear(&_env) + + // nothing resides in the original environment either + _org_env_begin = ~uintptr(0) + _org_env_end = ~uintptr(0) } _environ :: proc(allocator: runtime.Allocator) -> []string { - //TODO - return nil + if _org_env_begin == 0 { + _build_env() + } + env := make([]string, len(_env), allocator) + + sync.mutex_lock(&_env_mutex) + defer sync.mutex_unlock(&_env_mutex) + for entry, i in _env { + env[i], _ = clone_string(entry, allocator) + } + return env } +// The entire environment is stored as 0 terminated strings, +// so there is no need to clone/free individual variables +export_cstring_environment :: proc(allocator: runtime.Allocator) -> []cstring { + if _org_env_begin == 0 { + // The environment has not been modified, so we can just + // send the original environment + org_env := _get_original_env() + n: int + for ; org_env[n] != nil; n += 1 {} + return slice.clone(org_env[:n + 1], allocator) + } + // NOTE: already terminated by nil pointer via + 1 + env := make([]cstring, len(_env) + 1, allocator) + + sync.mutex_lock(&_env_mutex) + defer sync.mutex_unlock(&_env_mutex) + for entry, i in _env { + env[i] = cstring(raw_data(entry)) + } + return env +} + +_build_env :: proc() { + sync.mutex_lock(&_env_mutex) + defer sync.mutex_unlock(&_env_mutex) + if _org_env_begin != 0 { + return + } + + _env = make(type_of(_env), heap_allocator()) + cstring_env := _get_original_env() + _org_env_begin = uintptr(rawptr(cstring_env[0])) + for i := 0; cstring_env[i] != nil; i += 1 { + bytes := ([^]u8)(cstring_env[i]) + n := len(cstring_env[i]) + _org_env_end = uintptr(&bytes[n]) + append(&_env, string(bytes[:n])) + } +} + +_get_original_env :: #force_inline proc() -> [^]cstring { + // essentially &argv[argc] which should be a nil pointer! + #no_bounds_check env: [^]cstring = &runtime.args__[len(runtime.args__)] + assert(env[0] == nil) + return &env[1] +} + +_kv_from_entry :: #force_inline proc(entry: string) -> (k, v: string) { + eq_idx := strings.index_byte(entry, '=') + if eq_idx == -1 { + return entry, "" + } + return entry[:eq_idx], entry[eq_idx + 1:] +} + +_kv_addr_from_val :: #force_inline proc(val: string, key: string) -> ([^]u8, [^]u8) { + v_addr := raw_data(val) + k_addr := ([^]u8)(&v_addr[-(len(key) + 1)]) + return k_addr, v_addr +} + +_is_in_org_env :: #force_inline proc(env_data: string) -> bool { + addr := uintptr(raw_data(env_data)) + return addr >= _org_env_begin && addr < _org_env_end +} diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin index 2c570170d..51d8314b4 100644 --- a/core/os/os2/errors.odin +++ b/core/os/os2/errors.odin @@ -99,3 +99,19 @@ error_string :: proc(ferr: Error) -> string { return "unknown error" } + +print_error :: proc(f: ^File, ferr: Error, msg: string) { + TEMP_ALLOCATOR_GUARD() + err_str := error_string(ferr) + + // msg + ": " + err_str + '\n' + length := len(msg) + 2 + len(err_str) + 1 + buf := make([]u8, length, temp_allocator()) + + copy(buf, msg) + buf[len(msg)] = ':' + buf[len(msg) + 1] = ' ' + copy(buf[len(msg) + 2:], err_str) + buf[length - 1] = '\n' + write(f, buf) +} diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index 053256fbd..d7234ce8b 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -1,145 +1,165 @@ //+private package os2 -import "core:sys/unix" +import "core:sys/linux" -EPERM :: 1 -ENOENT :: 2 -ESRCH :: 3 -EINTR :: 4 -EIO :: 5 -ENXIO :: 6 -EBADF :: 9 -EAGAIN :: 11 -ENOMEM :: 12 -EACCES :: 13 -EFAULT :: 14 -EEXIST :: 17 -ENODEV :: 19 -ENOTDIR :: 20 -EISDIR :: 21 -EINVAL :: 22 -ENFILE :: 23 -EMFILE :: 24 -ETXTBSY :: 26 -EFBIG :: 27 -ENOSPC :: 28 -ESPIPE :: 29 -EROFS :: 30 -EPIPE :: 32 -ERANGE :: 34 /* Result too large */ -EDEADLK :: 35 /* Resource deadlock would occur */ -ENAMETOOLONG :: 36 /* File name too long */ -ENOLCK :: 37 /* No record locks available */ -ENOSYS :: 38 /* Invalid system call number */ -ENOTEMPTY :: 39 /* Directory not empty */ -ELOOP :: 40 /* Too many symbolic links encountered */ -EWOULDBLOCK :: EAGAIN /* Operation would block */ -ENOMSG :: 42 /* No message of desired type */ -EIDRM :: 43 /* Identifier removed */ -ECHRNG :: 44 /* Channel number out of range */ -EL2NSYNC :: 45 /* Level 2 not synchronized */ -EL3HLT :: 46 /* Level 3 halted */ -EL3RST :: 47 /* Level 3 reset */ -ELNRNG :: 48 /* Link number out of range */ -EUNATCH :: 49 /* Protocol driver not attached */ -ENOCSI :: 50 /* No CSI structure available */ -EL2HLT :: 51 /* Level 2 halted */ -EBADE :: 52 /* Invalid exchange */ -EBADR :: 53 /* Invalid request descriptor */ -EXFULL :: 54 /* Exchange full */ -ENOANO :: 55 /* No anode */ -EBADRQC :: 56 /* Invalid request code */ -EBADSLT :: 57 /* Invalid slot */ -EDEADLOCK :: EDEADLK -EBFONT :: 59 /* Bad font file format */ -ENOSTR :: 60 /* Device not a stream */ -ENODATA :: 61 /* No data available */ -ETIME :: 62 /* Timer expired */ -ENOSR :: 63 /* Out of streams resources */ -ENONET :: 64 /* Machine is not on the network */ -ENOPKG :: 65 /* Package not installed */ -EREMOTE :: 66 /* Object is remote */ -ENOLINK :: 67 /* Link has been severed */ -EADV :: 68 /* Advertise error */ -ESRMNT :: 69 /* Srmount error */ -ECOMM :: 70 /* Communication error on send */ -EPROTO :: 71 /* Protocol error */ -EMULTIHOP :: 72 /* Multihop attempted */ -EDOTDOT :: 73 /* RFS specific error */ -EBADMSG :: 74 /* Not a data message */ -EOVERFLOW :: 75 /* Value too large for defined data type */ -ENOTUNIQ :: 76 /* Name not unique on network */ -EBADFD :: 77 /* File descriptor in bad state */ -EREMCHG :: 78 /* Remote address changed */ -ELIBACC :: 79 /* Can not access a needed shared library */ -ELIBBAD :: 80 /* Accessing a corrupted shared library */ -ELIBSCN :: 81 /* .lib section in a.out corrupted */ -ELIBMAX :: 82 /* Attempting to link in too many shared libraries */ -ELIBEXEC :: 83 /* Cannot exec a shared library directly */ -EILSEQ :: 84 /* Illegal byte sequence */ -ERESTART :: 85 /* Interrupted system call should be restarted */ -ESTRPIPE :: 86 /* Streams pipe error */ -EUSERS :: 87 /* Too many users */ -ENOTSOCK :: 88 /* Socket operation on non-socket */ -EDESTADDRREQ :: 89 /* Destination address required */ -EMSGSIZE :: 90 /* Message too long */ -EPROTOTYPE :: 91 /* Protocol wrong type for socket */ -ENOPROTOOPT :: 92 /* Protocol not available */ -EPROTONOSUPPORT:: 93 /* Protocol not supported */ -ESOCKTNOSUPPORT:: 94 /* Socket type not supported */ -EOPNOTSUPP :: 95 /* Operation not supported on transport endpoint */ -EPFNOSUPPORT :: 96 /* Protocol family not supported */ -EAFNOSUPPORT :: 97 /* Address family not supported by protocol */ -EADDRINUSE :: 98 /* Address already in use */ -EADDRNOTAVAIL :: 99 /* Cannot assign requested address */ -ENETDOWN :: 100 /* Network is down */ -ENETUNREACH :: 101 /* Network is unreachable */ -ENETRESET :: 102 /* Network dropped connection because of reset */ -ECONNABORTED :: 103 /* Software caused connection abort */ -ECONNRESET :: 104 /* Connection reset by peer */ -ENOBUFS :: 105 /* No buffer space available */ -EISCONN :: 106 /* Transport endpoint is already connected */ -ENOTCONN :: 107 /* Transport endpoint is not connected */ -ESHUTDOWN :: 108 /* Cannot send after transport endpoint shutdown */ -ETOOMANYREFS :: 109 /* Too many references: cannot splice */ -ETIMEDOUT :: 110 /* Connection timed out */ -ECONNREFUSED :: 111 /* Connection refused */ -EHOSTDOWN :: 112 /* Host is down */ -EHOSTUNREACH :: 113 /* No route to host */ -EALREADY :: 114 /* Operation already in progress */ -EINPROGRESS :: 115 /* Operation now in progress */ -ESTALE :: 116 /* Stale file handle */ -EUCLEAN :: 117 /* Structure needs cleaning */ -ENOTNAM :: 118 /* Not a XENIX named type file */ -ENAVAIL :: 119 /* No XENIX semaphores available */ -EISNAM :: 120 /* Is a named type file */ -EREMOTEIO :: 121 /* Remote I/O error */ -EDQUOT :: 122 /* Quota exceeded */ -ENOMEDIUM :: 123 /* No medium found */ -EMEDIUMTYPE :: 124 /* Wrong medium type */ -ECANCELED :: 125 /* Operation Canceled */ -ENOKEY :: 126 /* Required key not available */ -EKEYEXPIRED :: 127 /* Key has expired */ -EKEYREVOKED :: 128 /* Key has been revoked */ -EKEYREJECTED :: 129 /* Key was rejected by service */ -EOWNERDEAD :: 130 /* Owner died */ -ENOTRECOVERABLE:: 131 /* State not recoverable */ -ERFKILL :: 132 /* Operation not possible due to RF-kill */ -EHWPOISON :: 133 /* Memory page has hardware error */ +@(rodata) +_errno_strings : [linux.Errno]string = { + .NONE = "Success", + .EPERM = "Operation not permitted", + .ENOENT = "No such file or directory", + .ESRCH = "No such process", + .EINTR = "Interrupted system call", + .EIO = "Input/output error", + .ENXIO = "No such device or address", + .E2BIG = "Argument list too long", + .ENOEXEC = "Exec format error", + .EBADF = "Bad file descriptor", + .ECHILD = "No child processes", + .EAGAIN = "Resource temporarily unavailable", + .ENOMEM = "Cannot allocate memory", + .EACCES = "Permission denied", + .EFAULT = "Bad address", + .ENOTBLK = "Block device required", + .EBUSY = "Device or resource busy", + .EEXIST = "File exists", + .EXDEV = "Invalid cross-device link", + .ENODEV = "No such device", + .ENOTDIR = "Not a directory", + .EISDIR = "Is a directory", + .EINVAL = "Invalid argument", + .ENFILE = "Too many open files in system", + .EMFILE = "Too many open files", + .ENOTTY = "Inappropriate ioctl for device", + .ETXTBSY = "Text file busy", + .EFBIG = "File too large", + .ENOSPC = "No space left on device", + .ESPIPE = "Illegal seek", + .EROFS = "Read-only file system", + .EMLINK = "Too many links", + .EPIPE = "Broken pipe", + .EDOM = "Numerical argument out of domain", + .ERANGE = "Numerical result out of range", + .EDEADLK = "Resource deadlock avoided", + .ENAMETOOLONG = "File name too long", + .ENOLCK = "No locks available", + .ENOSYS = "Function not implemented", + .ENOTEMPTY = "Directory not empty", + .ELOOP = "Too many levels of symbolic links", + .EUNKNOWN_41 = "Unknown Error (41)", + .ENOMSG = "No message of desired type", + .EIDRM = "Identifier removed", + .ECHRNG = "Channel number out of range", + .EL2NSYNC = "Level 2 not synchronized", + .EL3HLT = "Level 3 halted", + .EL3RST = "Level 3 reset", + .ELNRNG = "Link number out of range", + .EUNATCH = "Protocol driver not attached", + .ENOCSI = "No CSI structure available", + .EL2HLT = "Level 2 halted", + .EBADE = "Invalid exchange", + .EBADR = "Invalid request descriptor", + .EXFULL = "Exchange full", + .ENOANO = "No anode", + .EBADRQC = "Invalid request code", + .EBADSLT = "Invalid slot", + .EUNKNOWN_58 = "Unknown Error (58)", + .EBFONT = "Bad font file format", + .ENOSTR = "Device not a stream", + .ENODATA = "No data available", + .ETIME = "Timer expired", + .ENOSR = "Out of streams resources", + .ENONET = "Machine is not on the network", + .ENOPKG = "Package not installed", + .EREMOTE = "Object is remote", + .ENOLINK = "Link has been severed", + .EADV = "Advertise error", + .ESRMNT = "Srmount error", + .ECOMM = "Communication error on send", + .EPROTO = "Protocol error", + .EMULTIHOP = "Multihop attempted", + .EDOTDOT = "RFS specific error", + .EBADMSG = "Bad message", + .EOVERFLOW = "Value too large for defined data type", + .ENOTUNIQ = "Name not unique on network", + .EBADFD = "File descriptor in bad state", + .EREMCHG = "Remote address changed", + .ELIBACC = "Can not access a needed shared library", + .ELIBBAD = "Accessing a corrupted shared library", + .ELIBSCN = ".lib section in a.out corrupted", + .ELIBMAX = "Attempting to link in too many shared libraries", + .ELIBEXEC = "Cannot exec a shared library directly", + .EILSEQ = "Invalid or incomplete multibyte or wide character", + .ERESTART = "Interrupted system call should be restarted", + .ESTRPIPE = "Streams pipe error", + .EUSERS = "Too many users", + .ENOTSOCK = "Socket operation on non-socket", + .EDESTADDRREQ = "Destination address required", + .EMSGSIZE = "Message too long", + .EPROTOTYPE = "Protocol wrong type for socket", + .ENOPROTOOPT = "Protocol not available", + .EPROTONOSUPPORT = "Protocol not supported", + .ESOCKTNOSUPPORT = "Socket type not supported", + .EOPNOTSUPP = "Operation not supported", + .EPFNOSUPPORT = "Protocol family not supported", + .EAFNOSUPPORT = "Address family not supported by protocol", + .EADDRINUSE = "Address already in use", + .EADDRNOTAVAIL = "Cannot assign requested address", + .ENETDOWN = "Network is down", + .ENETUNREACH = "Network is unreachable", + .ENETRESET = "Network dropped connection on reset", + .ECONNABORTED = "Software caused connection abort", + .ECONNRESET = "Connection reset by peer", + .ENOBUFS = "No buffer space available", + .EISCONN = "Transport endpoint is already connected", + .ENOTCONN = "Transport endpoint is not connected", + .ESHUTDOWN = "Cannot send after transport endpoint shutdown", + .ETOOMANYREFS = "Too many references: cannot splice", + .ETIMEDOUT = "Connection timed out", + .ECONNREFUSED = "Connection refused", + .EHOSTDOWN = "Host is down", + .EHOSTUNREACH = "No route to host", + .EALREADY = "Operation already in progress", + .EINPROGRESS = "Operation now in progress", + .ESTALE = "Stale file handle", + .EUCLEAN = "Structure needs cleaning", + .ENOTNAM = "Not a XENIX named type file", + .ENAVAIL = "No XENIX semaphores available", + .EISNAM = "Is a named type file", + .EREMOTEIO = "Remote I/O error", + .EDQUOT = "Disk quota exceeded", + .ENOMEDIUM = "No medium found", + .EMEDIUMTYPE = "Wrong medium type", + .ECANCELED = "Operation canceled", + .ENOKEY = "Required key not available", + .EKEYEXPIRED = "Key has expired", + .EKEYREVOKED = "Key has been revoked", + .EKEYREJECTED = "Key was rejected by service", + .EOWNERDEAD = "Owner died", + .ENOTRECOVERABLE = "State not recoverable", + .ERFKILL = "Operation not possible due to RF-kill", + .EHWPOISON = "Memory page has hardware error", +} + + +_get_platform_error :: proc(errno: linux.Errno) -> Error { + #partial switch errno { + case .NONE: + return nil + case .EPERM: + return .Permission_Denied + case .EEXIST: + return .Exist + case .ENOENT: + return .Not_Exist + } -_get_platform_error :: proc(res: int) -> Error { - errno := unix.get_errno(res) return Platform_Error(i32(errno)) } -_ok_or_error :: proc(res: int) -> Error { - return res >= 0 ? nil : _get_platform_error(res) -} - _error_string :: proc(errno: i32) -> string { - if errno == 0 { - return "" + if errno >= 0 && errno <= i32(max(linux.Errno)) { + return _errno_strings[linux.Errno(errno)] } - return "Error" + return "Unknown Error" } diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 4f4bd942e..236423163 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -45,13 +45,10 @@ O_TRUNC :: File_Flags{.Trunc} O_SPARSE :: File_Flags{.Sparse} O_CLOEXEC :: File_Flags{.Close_On_Exec} - - stdin: ^File = nil // OS-Specific stdout: ^File = nil // OS-Specific stderr: ^File = nil // OS-Specific - @(require_results) create :: proc(name: string) -> (^File, Error) { return open(name, {.Read, .Write, .Create}, File_Mode(0o777)) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 3843c1105..8e7db9751 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -1,39 +1,64 @@ //+private package os2 -import "base:runtime" import "core:io" import "core:time" -import "core:sys/unix" - -INVALID_HANDLE :: -1 - -_O_RDONLY :: 0o00000000 -_O_WRONLY :: 0o00000001 -_O_RDWR :: 0o00000002 -_O_CREAT :: 0o00000100 -_O_EXCL :: 0o00000200 -_O_NOCTTY :: 0o00000400 -_O_TRUNC :: 0o00001000 -_O_APPEND :: 0o00002000 -_O_NONBLOCK :: 0o00004000 -_O_LARGEFILE :: 0o00100000 -_O_DIRECTORY :: 0o00200000 -_O_NOFOLLOW :: 0o00400000 -_O_SYNC :: 0o04010000 -_O_CLOEXEC :: 0o02000000 -_O_PATH :: 0o10000000 - -_AT_FDCWD :: -100 - -_CSTRING_NAME_HEAP_THRESHOLD :: 512 +import "base:runtime" +import "core:sys/linux" _File :: struct { name: string, - fd: int, + fd: linux.Fd, allocator: runtime.Allocator, } +_stdin : File = { + impl = { + name = "/proc/self/fd/0", + fd = 0, + allocator = _file_allocator(), + }, + stream = { + procedure = _file_stream_proc, + }, +} +_stdout : File = { + impl = { + name = "/proc/self/fd/1", + fd = 1, + allocator = _file_allocator(), + }, + stream = { + procedure = _file_stream_proc, + }, +} +_stderr : File = { + impl = { + name = "/proc/self/fd/2", + fd = 2, + allocator = _file_allocator(), + }, + stream = { + procedure = _file_stream_proc, + }, +} + +@init +_standard_stream_init :: proc() { + // cannot define these manually because cyclic reference + _stdin.stream.data = &_stdin + _stdout.stream.data = &_stdout + _stderr.stream.data = &_stderr + + stdin = &_stdin + stdout = &_stdout + stderr = &_stderr +} + +_file_allocator :: proc() -> runtime.Allocator { + return heap_allocator() +} + _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, err: Error) { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return @@ -41,40 +66,48 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, er // Just default to using O_NOCTTY because needing to open a controlling // terminal would be incredibly rare. This has no effect on files while // allowing us to open serial devices. - flags_i: int = _O_NOCTTY + sys_flags: linux.Open_Flags = {.NOCTTY} switch flags & O_RDONLY|O_WRONLY|O_RDWR { - case O_RDONLY: flags_i = _O_RDONLY - case O_WRONLY: flags_i = _O_WRONLY - case O_RDWR: flags_i = _O_RDWR + case O_RDONLY: + case O_WRONLY: sys_flags += {.WRONLY} + case O_RDWR: sys_flags += {.RDWR} } - if .Append in flags { flags_i |= _O_APPEND } - if .Create in flags { flags_i |= _O_CREAT } - if .Excl in flags { flags_i |= _O_EXCL } - if .Sync in flags { flags_i |= _O_SYNC } - if .Trunc in flags { flags_i |= _O_TRUNC } - if .Close_On_Exec in flags { flags_i |= _O_CLOEXEC } + if .Append in flags { sys_flags += {.APPEND} } + if .Create in flags { sys_flags += {.CREAT} } + if .Excl in flags { sys_flags += {.EXCL} } + if .Sync in flags { sys_flags += {.DSYNC} } + if .Trunc in flags { sys_flags += {.TRUNC} } + if .Close_On_Exec in flags { sys_flags += {.CLOEXEC} } - fd := unix.sys_open(name_cstr, flags_i, uint(perm)) - if fd < 0 { - return nil, _get_platform_error(fd) + fd, errno := linux.open(name_cstr, sys_flags, transmute(linux.Mode)(u32(perm))) + if errno != .NONE { + return nil, _get_platform_error(errno) } return _new_file(uintptr(fd), name), nil } -_new_file :: proc(fd: uintptr, _: string) -> ^File { +_new_file :: proc(fd: uintptr, _: string = "") -> ^File { file := new(File, file_allocator()) - file.impl.fd = int(fd) - file.impl.allocator = file_allocator() - file.impl.name = _get_full_path(file.impl.fd, file.impl.allocator) - file.stream = { - data = file, - procedure = _file_stream_proc, - } + _construct_file(file, fd, "") return file } +_construct_file :: proc(file: ^File, fd: uintptr, _: string = "") { + file^ = { + impl = { + fd = linux.Fd(fd), + allocator = file_allocator(), + name = _get_full_path(file.impl.fd, file.impl.allocator), + }, + stream = { + data = file, + procedure = _file_stream_proc, + }, + } +} + _destroy :: proc(f: ^File) -> Error { if f == nil { return nil @@ -86,12 +119,15 @@ _destroy :: proc(f: ^File) -> Error { _close :: proc(f: ^File) -> Error { - if f != nil { - res := unix.sys_close(f.impl.fd) - _destroy(f) - return _ok_or_error(res) + if f == nil { + return nil } - return nil + errno := linux.close(f.impl.fd) + if errno == .EBADF { // avoid possible double free + return _get_platform_error(errno) + } + _destroy(f) + return _get_platform_error(errno) } _fd :: proc(f: ^File) -> uintptr { @@ -106,106 +142,100 @@ _name :: proc(f: ^File) -> string { } _seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) { - res := unix.sys_lseek(f.impl.fd, offset, int(whence)) - if res < 0 { - return -1, _get_platform_error(int(res)) + n, errno := linux.lseek(f.impl.fd, offset, linux.Seek_Whence(whence)) + if errno != .NONE { + return -1, _get_platform_error(errno) } - return res, nil + return n, nil } _read :: proc(f: ^File, p: []byte) -> (i64, Error) { if len(p) == 0 { return 0, nil } - n := unix.sys_read(f.impl.fd, &p[0], len(p)) - if n < 0 { - return -1, _get_platform_error(n) + n, errno := linux.read(f.impl.fd, p[:]) + if errno != .NONE { + return -1, _get_platform_error(errno) } - return i64(n), nil + return i64(n), n == 0 ? io.Error.EOF : nil } -_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) { +_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (i64, Error) { if offset < 0 { return 0, .Invalid_Offset } - b, offset := p, offset - for len(b) > 0 { - m := unix.sys_pread(f.impl.fd, &b[0], len(b), offset) - if m < 0 { - return -1, _get_platform_error(m) - } - n += i64(m) - b = b[m:] - offset += i64(m) + n, errno := linux.pread(f.impl.fd, p[:], offset) + if errno != .NONE { + return -1, _get_platform_error(errno) } - return + if n == 0 { + return 0, .EOF + } + return i64(n), nil } _write :: proc(f: ^File, p: []byte) -> (i64, Error) { if len(p) == 0 { return 0, nil } - n := unix.sys_write(f.impl.fd, &p[0], uint(len(p))) - if n < 0 { - return -1, _get_platform_error(n) + n, errno := linux.write(f.impl.fd, p[:]) + if errno != .NONE { + return -1, _get_platform_error(errno) } return i64(n), nil } -_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) { +_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (i64, Error) { if offset < 0 { return 0, .Invalid_Offset } - b, offset := p, offset - for len(b) > 0 { - m := unix.sys_pwrite(f.impl.fd, &b[0], len(b), offset) - if m < 0 { - return -1, _get_platform_error(m) - } - n += i64(m) - b = b[m:] - offset += i64(m) + n, errno := linux.pwrite(f.impl.fd, p[:], offset) + if errno != .NONE { + return -1, _get_platform_error(errno) } - return + return i64(n), nil } _file_size :: proc(f: ^File) -> (n: i64, err: Error) { - s: _Stat = --- - res := unix.sys_fstat(f.impl.fd, &s) - if res < 0 { - return -1, _get_platform_error(res) + s: linux.Stat = --- + errno := linux.fstat(f.impl.fd, &s) + if errno != .NONE { + return -1, _get_platform_error(errno) } - return s.size, nil + return i64(s.size), nil } _sync :: proc(f: ^File) -> Error { - return _ok_or_error(unix.sys_fsync(f.impl.fd)) + return _get_platform_error(linux.fsync(f.impl.fd)) } _flush :: proc(f: ^File) -> Error { - return _ok_or_error(unix.sys_fsync(f.impl.fd)) + return _get_platform_error(linux.fsync(f.impl.fd)) } _truncate :: proc(f: ^File, size: i64) -> Error { - return _ok_or_error(unix.sys_ftruncate(f.impl.fd, size)) + return _get_platform_error(linux.ftruncate(f.impl.fd, size)) } _remove :: proc(name: string) -> Error { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - fd := unix.sys_open(name_cstr, int(File_Flags.Read)) - if fd < 0 { - return _get_platform_error(fd) + fd, errno := linux.open(name_cstr, {.NOFOLLOW}) + #partial switch (errno) { + case .ELOOP: /* symlink */ + case .NONE: + defer linux.close(fd) + if _is_dir_fd(fd) { + return _get_platform_error(linux.rmdir(name_cstr)) + } + case: + return _get_platform_error(errno) } - defer unix.sys_close(fd) - if _is_dir_fd(fd) { - return _ok_or_error(unix.sys_rmdir(name_cstr)) - } - return _ok_or_error(unix.sys_unlink(name_cstr)) + return _get_platform_error(linux.unlink(name_cstr)) } _rename :: proc(old_name, new_name: string) -> Error { @@ -213,7 +243,7 @@ _rename :: proc(old_name, new_name: string) -> Error { old_name_cstr := temp_cstring(old_name) or_return new_name_cstr := temp_cstring(new_name) or_return - return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr)) + return _get_platform_error(linux.rename(old_name_cstr, new_name_cstr)) } _link :: proc(old_name, new_name: string) -> Error { @@ -221,148 +251,194 @@ _link :: proc(old_name, new_name: string) -> Error { old_name_cstr := temp_cstring(old_name) or_return new_name_cstr := temp_cstring(new_name) or_return - return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr)) + return _get_platform_error(linux.link(old_name_cstr, new_name_cstr)) } _symlink :: proc(old_name, new_name: string) -> Error { TEMP_ALLOCATOR_GUARD() old_name_cstr := temp_cstring(old_name) or_return new_name_cstr := temp_cstring(new_name) or_return - - return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr)) + return _get_platform_error(linux.symlink(old_name_cstr, new_name_cstr)) } _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (string, Error) { bufsz : uint = 256 buf := make([]byte, bufsz, allocator) for { - rc := unix.sys_readlink(name_cstr, &buf[0], bufsz) - if rc < 0 { - delete(buf) - return "", _get_platform_error(rc) - } else if rc == int(bufsz) { + sz, errno := linux.readlink(name_cstr, buf[:]) + if errno != .NONE { + delete(buf, allocator) + return "", _get_platform_error(errno) + } else if sz == int(bufsz) { bufsz *= 2 - delete(buf) + delete(buf, allocator) buf = make([]byte, bufsz, allocator) } else { - return string(buf[:rc]), nil + return string(buf[:sz]), nil } } } -_read_link :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) { +_read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, e: Error) { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return return _read_link_cstr(name_cstr, allocator) } -_unlink :: proc(name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return - return _ok_or_error(unix.sys_unlink(name_cstr)) -} - _chdir :: proc(name: string) -> Error { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - return _ok_or_error(unix.sys_chdir(name_cstr)) + return _get_platform_error(linux.chdir(name_cstr)) } _fchdir :: proc(f: ^File) -> Error { - return _ok_or_error(unix.sys_fchdir(f.impl.fd)) + return _get_platform_error(linux.fchdir(f.impl.fd)) } _chmod :: proc(name: string, mode: File_Mode) -> Error { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - return _ok_or_error(unix.sys_chmod(name_cstr, uint(mode))) + return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)(u32(mode)))) } _fchmod :: proc(f: ^File, mode: File_Mode) -> Error { - return _ok_or_error(unix.sys_fchmod(f.impl.fd, uint(mode))) + return _get_platform_error(linux.fchmod(f.impl.fd, transmute(linux.Mode)(u32(mode)))) } // NOTE: will throw error without super user priviledges _chown :: proc(name: string, uid, gid: int) -> Error { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - return _ok_or_error(unix.sys_chown(name_cstr, uid, gid)) + return _get_platform_error(linux.chown(name_cstr, linux.Uid(uid), linux.Gid(gid))) } // NOTE: will throw error without super user priviledges _lchown :: proc(name: string, uid, gid: int) -> Error { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid)) + return _get_platform_error(linux.lchown(name_cstr, linux.Uid(uid), linux.Gid(gid))) } // NOTE: will throw error without super user priviledges _fchown :: proc(f: ^File, uid, gid: int) -> Error { - return _ok_or_error(unix.sys_fchown(f.impl.fd, uid, gid)) + return _get_platform_error(linux.fchown(f.impl.fd, linux.Uid(uid), linux.Gid(gid))) } _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - times := [2]Unix_File_Time { - { atime._nsec, 0 }, - { mtime._nsec, 0 }, + times := [2]linux.Time_Spec { + { + uint(atime._nsec) / uint(time.Second), + uint(atime._nsec) % uint(time.Second), + }, + { + uint(mtime._nsec) / uint(time.Second), + uint(mtime._nsec) % uint(time.Second), + }, } - return _ok_or_error(unix.sys_utimensat(_AT_FDCWD, name_cstr, ×, 0)) + return _get_platform_error(linux.utimensat(linux.AT_FDCWD, name_cstr, ×[0], nil)) } _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { - times := [2]Unix_File_Time { - { atime._nsec, 0 }, - { mtime._nsec, 0 }, + times := [2]linux.Time_Spec { + { + uint(atime._nsec) / uint(time.Second), + uint(atime._nsec) % uint(time.Second), + }, + { + uint(mtime._nsec) / uint(time.Second), + uint(mtime._nsec) % uint(time.Second), + }, } - return _ok_or_error(unix.sys_utimensat(f.impl.fd, nil, ×, 0)) + return _get_platform_error(linux.utimensat(f.impl.fd, nil, ×[0], nil)) } _exists :: proc(name: string) -> bool { TEMP_ALLOCATOR_GUARD() name_cstr, _ := temp_cstring(name) - return unix.sys_access(name_cstr, F_OK) == 0 + res, errno := linux.access(name_cstr, linux.F_OK) + return !res && errno == .NONE } _is_file :: proc(name: string) -> bool { TEMP_ALLOCATOR_GUARD() name_cstr, _ := temp_cstring(name) - s: _Stat - res := unix.sys_stat(name_cstr, &s) - if res < 0 { + s: linux.Stat + if linux.stat(name_cstr, &s) != .NONE { return false } - return S_ISREG(s.mode) + return linux.S_ISREG(s.mode) } -_is_file_fd :: proc(fd: int) -> bool { - s: _Stat - res := unix.sys_fstat(fd, &s) - if res < 0 { // error +_is_file_fd :: proc(fd: linux.Fd) -> bool { + s: linux.Stat + if linux.fstat(fd, &s) != .NONE { return false } - return S_ISREG(s.mode) + return linux.S_ISREG(s.mode) } _is_dir :: proc(name: string) -> bool { TEMP_ALLOCATOR_GUARD() name_cstr, _ := temp_cstring(name) - s: _Stat - res := unix.sys_stat(name_cstr, &s) - if res < 0 { + s: linux.Stat + if linux.stat(name_cstr, &s) != .NONE { return false } - return S_ISDIR(s.mode) + return linux.S_ISDIR(s.mode) } -_is_dir_fd :: proc(fd: int) -> bool { - s: _Stat - res := unix.sys_fstat(fd, &s) - if res < 0 { // error +_is_dir_fd :: proc(fd: linux.Fd) -> bool { + s: linux.Stat + if linux.fstat(fd, &s) != .NONE { return false } - return S_ISDIR(s.mode) + return linux.S_ISDIR(s.mode) +} + +/* Certain files in the Linux file system are not actual + * files (e.g. everything in /proc/). Therefore, the + * read_entire_file procs fail to actually read anything + * since these "files" stat to a size of 0. Here, we just + * read until there is nothing left. + */ +_read_entire_pseudo_file :: proc { _read_entire_pseudo_file_string, _read_entire_pseudo_file_cstring } + +_read_entire_pseudo_file_string :: proc(name: string, allocator: runtime.Allocator) -> (b: []u8, e: Error) { + name_cstr := clone_to_cstring(name, allocator) or_return + defer delete(name, allocator) + return _read_entire_pseudo_file_cstring(name_cstr, allocator) +} + +_read_entire_pseudo_file_cstring :: proc(name: cstring, allocator: runtime.Allocator) -> ([]u8, Error) { + fd, errno := linux.open(name, {}) + if errno != .NONE { + return nil, _get_platform_error(errno) + } + defer linux.close(fd) + + BUF_SIZE_STEP :: 128 + contents := make([dynamic]u8, 0, BUF_SIZE_STEP, allocator) + + n: int + i: int + for { + resize(&contents, i + BUF_SIZE_STEP) + n, errno = linux.read(fd, contents[i:i+BUF_SIZE_STEP]) + if errno != .NONE { + delete(contents) + return nil, _get_platform_error(errno) + } + if n < BUF_SIZE_STEP { + break + } + i += BUF_SIZE_STEP + } + + resize(&contents, i + n) + + return contents[:], nil } @(private="package") diff --git a/core/os/os2/heap_linux.odin b/core/os/os2/heap_linux.odin index bb4acba13..11cf5ab41 100644 --- a/core/os/os2/heap_linux.odin +++ b/core/os/os2/heap_linux.odin @@ -1,7 +1,7 @@ //+private package os2 -import "core:sys/unix" +import "core:sys/linux" import "core:sync" import "core:mem" @@ -97,9 +97,8 @@ CURRENTLY_ACTIVE :: (^^Region)(~uintptr(0)) FREE_LIST_ENTRIES_PER_BLOCK :: BLOCK_SIZE / size_of(u16) -MMAP_FLAGS :: unix.MAP_ANONYMOUS | unix.MAP_PRIVATE -MMAP_PROT :: unix.PROT_READ | unix.PROT_WRITE - +MMAP_FLAGS : linux.Map_Flags : {.ANONYMOUS, .PRIVATE} +MMAP_PROT : linux.Mem_Protection : {.READ, .WRITE} @thread_local _local_region: ^Region global_regions: ^Region @@ -324,11 +323,11 @@ heap_free :: proc(memory: rawptr) { // Regions // _new_region :: proc() -> ^Region #no_bounds_check { - res := unix.sys_mmap(nil, uint(SIZE_OF_REGION), MMAP_PROT, MMAP_FLAGS, -1, 0) - if res < 0 { + ptr, errno := linux.mmap(0, uint(SIZE_OF_REGION), MMAP_PROT, MMAP_FLAGS, -1, 0) + if errno != .NONE { return nil } - new_region := (^Region)(uintptr(res)) + new_region := (^Region)(ptr) new_region.hdr.local_addr = CURRENTLY_ACTIVE new_region.hdr.reset_addr = &_local_region @@ -634,8 +633,8 @@ _region_free_list_remove :: proc(region: ^Region, free_idx: u16) #no_bounds_chec // _direct_mmap_alloc :: proc(size: int) -> rawptr { mmap_size := _round_up_to_nearest(size + BLOCK_SIZE, PAGE_SIZE) - new_allocation := unix.sys_mmap(nil, uint(mmap_size), MMAP_PROT, MMAP_FLAGS, -1, 0) - if new_allocation < 0 && new_allocation > -4096 { + new_allocation, errno := linux.mmap(0, uint(mmap_size), MMAP_PROT, MMAP_FLAGS, -1, 0) + if errno != .NONE { return nil } @@ -655,13 +654,8 @@ _direct_mmap_resize :: proc(alloc: ^Allocation_Header, new_size: int) -> rawptr return mem.ptr_offset(alloc, 1) } - new_allocation := unix.sys_mremap( - alloc, - uint(old_mmap_size), - uint(new_mmap_size), - unix.MREMAP_MAYMOVE, - ) - if new_allocation < 0 && new_allocation > -4096 { + new_allocation, errno := linux.mremap(alloc, uint(old_mmap_size), uint(new_mmap_size), {.MAYMOVE}) + if errno != .NONE { return nil } @@ -702,7 +696,7 @@ _direct_mmap_to_region :: proc(alloc: ^Allocation_Header, new_size: int) -> rawp _direct_mmap_free :: proc(alloc: ^Allocation_Header) { requested := int(alloc.requested & REQUESTED_MASK) mmap_size := _round_up_to_nearest(requested + BLOCK_SIZE, PAGE_SIZE) - unix.sys_munmap(alloc, uint(mmap_size)) + linux.munmap(alloc, uint(mmap_size)) } // diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 81176c219..3c08eedee 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -3,104 +3,89 @@ package os2 import "core:strconv" import "base:runtime" -import "core:sys/unix" +import "core:sys/linux" _Path_Separator :: '/' _Path_Separator_String :: "/" _Path_List_Separator :: ':' -_S_IFMT :: 0o170000 // Type of file mask -_S_IFIFO :: 0o010000 // Named pipe (fifo) -_S_IFCHR :: 0o020000 // Character special -_S_IFDIR :: 0o040000 // Directory -_S_IFBLK :: 0o060000 // Block special -_S_IFREG :: 0o100000 // Regular -_S_IFLNK :: 0o120000 // Symbolic link -_S_IFSOCK :: 0o140000 // Socket - -_OPENDIR_FLAGS :: _O_RDONLY|_O_NONBLOCK|_O_DIRECTORY|_O_LARGEFILE|_O_CLOEXEC +_OPENDIR_FLAGS : linux.Open_Flags : {.NONBLOCK, .DIRECTORY, .LARGEFILE, .CLOEXEC} _is_path_separator :: proc(c: byte) -> bool { return c == '/' } _mkdir :: proc(path: string, perm: File_Mode) -> Error { - // NOTE: These modes would require sys_mknod, however, that would require - // additional arguments to this function. + // TODO: These modes would require mknod, however, that would also + // require additional arguments to this function.. if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { return .Invalid_Argument } TEMP_ALLOCATOR_GUARD() path_cstr := temp_cstring(path) or_return - return _ok_or_error(unix.sys_mkdir(path_cstr, uint(perm & 0o777))) + return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)(u32(perm) & 0o777))) } _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { - _mkdirat :: proc(dfd: int, path: []u8, perm: int, has_created: ^bool) -> Error { - if len(path) == 0 { - return _ok_or_error(unix.sys_close(dfd)) - } + mkdirat :: proc(dfd: linux.Fd, path: []u8, perm: int, has_created: ^bool) -> Error { i: int - for /**/; i < len(path) - 1 && path[i] != '/'; i += 1 {} + for ; i < len(path) - 1 && path[i] != '/'; i += 1 {} + if i == 0 { + return _get_platform_error(linux.close(dfd)) + } path[i] = 0 - new_dfd := unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS) - switch new_dfd { - case -ENOENT: - if res := unix.sys_mkdirat(dfd, cstring(&path[0]), uint(perm)); res < 0 { - return _get_platform_error(res) + new_dfd, errno := linux.openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS) + #partial switch errno { + case .ENOENT: + if errno = linux.mkdirat(dfd, cstring(&path[0]), transmute(linux.Mode)(u32(perm))); errno != .NONE { + return _get_platform_error(errno) } has_created^ = true - if new_dfd = unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS); new_dfd < 0 { - return _get_platform_error(new_dfd) + if new_dfd, errno = linux.openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS); errno != .NONE { + return _get_platform_error(errno) } fallthrough - case 0: - if res := unix.sys_close(dfd); res < 0 { - return _get_platform_error(res) + case .NONE: + if errno = linux.close(dfd); errno != .NONE { + return _get_platform_error(errno) } // skip consecutive '/' for i += 1; i < len(path) && path[i] == '/'; i += 1 {} - return _mkdirat(new_dfd, path[i:], perm, has_created) + return mkdirat(new_dfd, path[i:], perm, has_created) case: - return _get_platform_error(new_dfd) + return _get_platform_error(errno) } unreachable() } + // TODO if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { return .Invalid_Argument } TEMP_ALLOCATOR_GUARD() - // need something we can edit, and use to generate cstrings - allocated: bool - path_bytes: []u8 - if len(path) > _CSTRING_NAME_HEAP_THRESHOLD { - allocated = true - path_bytes = make([]u8, len(path) + 1) - } else { - path_bytes = make([]u8, len(path) + 1, temp_allocator()) - } + path_bytes := make([]u8, len(path) + 1, temp_allocator()) - // NULL terminate the byte slice to make it a valid cstring + // zero terminate the byte slice to make it a valid cstring copy(path_bytes, path) path_bytes[len(path)] = 0 - dfd: int + dfd: linux.Fd + errno: linux.Errno if path_bytes[0] == '/' { - dfd = unix.sys_open("/", _OPENDIR_FLAGS) + dfd, errno = linux.open("/", _OPENDIR_FLAGS) path_bytes = path_bytes[1:] } else { - dfd = unix.sys_open(".", _OPENDIR_FLAGS) + dfd, errno = linux.open(".", _OPENDIR_FLAGS) } - if dfd < 0 { - return _get_platform_error(dfd) + if errno != .NONE { + return _get_platform_error(errno) } has_created: bool - _mkdirat(dfd, path_bytes, int(perm & 0o777), &has_created) or_return + mkdirat(dfd, path_bytes, int(perm & 0o777), &has_created) or_return if has_created { return nil } @@ -119,28 +104,28 @@ dirent64 :: struct { _remove_all :: proc(path: string) -> Error { DT_DIR :: 4 - _remove_all_dir :: proc(dfd: int) -> Error { + remove_all_dir :: proc(dfd: linux.Fd) -> Error { n := 64 buf := make([]u8, n) defer delete(buf) loop: for { - getdents_res := unix.sys_getdents64(dfd, &buf[0], n) - switch getdents_res { - case -EINVAL: + buflen, errno := linux.getdents(dfd, buf[:]) + #partial switch errno { + case .EINVAL: delete(buf) n *= 2 buf = make([]u8, n) continue loop - case -4096..<0: - return _get_platform_error(getdents_res) - case 0: - break loop + case .NONE: + if buflen == 0 { break loop } + case: + return _get_platform_error(errno) } d: ^dirent64 - for i := 0; i < getdents_res; i += int(d.d_reclen) { + for i := 0; i < buflen; i += int(d.d_reclen) { d = (^dirent64)(rawptr(&buf[i])) d_name_cstr := cstring(&d.d_name[0]) @@ -156,23 +141,22 @@ _remove_all :: proc(path: string) -> Error { continue } - unlink_res: int - switch d.d_type { case DT_DIR: - new_dfd := unix.sys_openat(dfd, d_name_cstr, _OPENDIR_FLAGS) - if new_dfd < 0 { - return _get_platform_error(new_dfd) + new_dfd: linux.Fd + new_dfd, errno = linux.openat(dfd, d_name_cstr, _OPENDIR_FLAGS) + if errno != .NONE { + return _get_platform_error(errno) } - defer unix.sys_close(new_dfd) - _remove_all_dir(new_dfd) or_return - unlink_res = unix.sys_unlinkat(dfd, d_name_cstr, int(unix.AT_REMOVEDIR)) + defer linux.close(new_dfd) + remove_all_dir(new_dfd) or_return + errno = linux.unlinkat(dfd, d_name_cstr, {.REMOVEDIR}) case: - unlink_res = unix.sys_unlinkat(dfd, d_name_cstr) + errno = linux.unlinkat(dfd, d_name_cstr, nil) } - if unlink_res < 0 { - return _get_platform_error(unlink_res) + if errno != .NONE { + return _get_platform_error(errno) } } } @@ -182,17 +166,19 @@ _remove_all :: proc(path: string) -> Error { TEMP_ALLOCATOR_GUARD() path_cstr := temp_cstring(path) or_return - fd := unix.sys_open(path_cstr, _OPENDIR_FLAGS) - switch fd { - case -ENOTDIR: - return _ok_or_error(unix.sys_unlink(path_cstr)) - case -4096..<0: - return _get_platform_error(fd) + fd, errno := linux.open(path_cstr, _OPENDIR_FLAGS) + #partial switch errno { + case .NONE: + break + case .ENOTDIR: + return _get_platform_error(linux.unlink(path_cstr)) + case: + return _get_platform_error(errno) } - defer unix.sys_close(fd) - _remove_all_dir(fd) or_return - return _ok_or_error(unix.sys_rmdir(path_cstr)) + defer linux.close(fd) + remove_all_dir(fd) or_return + return _get_platform_error(linux.rmdir(path_cstr)) } _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) { @@ -203,13 +189,12 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) { PATH_MAX :: 4096 buf := make([dynamic]u8, PATH_MAX, allocator) for { - #no_bounds_check res := unix.sys_getcwd(&buf[0], uint(len(buf))) - - if res >= 0 { - return string_from_null_terminated_bytes(buf[:]), nil + #no_bounds_check n, errno := linux.getcwd(buf[:]) + if errno == .NONE { + return string(buf[:n-1]), nil } - if res != -ERANGE { - return "", _get_platform_error(res) + if errno != .ERANGE { + return "", _get_platform_error(errno) } resize(&buf, len(buf)+PATH_MAX) } @@ -218,16 +203,16 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) { _setwd :: proc(dir: string) -> Error { dir_cstr := temp_cstring(dir) or_return - return _ok_or_error(unix.sys_chdir(dir_cstr)) + return _get_platform_error(linux.chdir(dir_cstr)) } -_get_full_path :: proc(fd: int, allocator: runtime.Allocator) -> string { +_get_full_path :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> string { PROC_FD_PATH :: "/proc/self/fd/" buf: [32]u8 copy(buf[:], PROC_FD_PATH) - strconv.itoa(buf[len(PROC_FD_PATH):], fd) + strconv.itoa(buf[len(PROC_FD_PATH):], int(fd)) fullpath: string err: Error @@ -236,4 +221,3 @@ _get_full_path :: proc(fd: int, allocator: runtime.Allocator) -> string { } return fullpath } - diff --git a/core/os/os2/pipe_linux.odin b/core/os/os2/pipe_linux.odin index b66ff9663..5d42cca78 100644 --- a/core/os/os2/pipe_linux.odin +++ b/core/os/os2/pipe_linux.odin @@ -1,7 +1,17 @@ //+private package os2 +import "core:sys/linux" + _pipe :: proc() -> (r, w: ^File, err: Error) { - return nil, nil, nil + fds: [2]linux.Fd + errno := linux.pipe2(&fds, {.CLOEXEC}) + if errno != .NONE { + return nil, nil,_get_platform_error(errno) + } + + r = _new_file(uintptr(fds[0])) + w = _new_file(uintptr(fds[1])) + return } diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index dc287cafe..c0b3088b4 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -3,108 +3,32 @@ package os2 import "core:time" import "base:runtime" -import "core:sys/unix" +import "core:sys/linux" import "core:path/filepath" -// File type -S_IFMT :: 0o170000 // Type of file mask -S_IFIFO :: 0o010000 // Named pipe (fifo) -S_IFCHR :: 0o020000 // Character special -S_IFDIR :: 0o040000 // Directory -S_IFBLK :: 0o060000 // Block special -S_IFREG :: 0o100000 // Regular -S_IFLNK :: 0o120000 // Symbolic link -S_IFSOCK :: 0o140000 // Socket - -// File mode -// Read, write, execute/search by owner -S_IRWXU :: 0o0700 // RWX mask for owner -S_IRUSR :: 0o0400 // R for owner -S_IWUSR :: 0o0200 // W for owner -S_IXUSR :: 0o0100 // X for owner - - // Read, write, execute/search by group -S_IRWXG :: 0o0070 // RWX mask for group -S_IRGRP :: 0o0040 // R for group -S_IWGRP :: 0o0020 // W for group -S_IXGRP :: 0o0010 // X for group - - // Read, write, execute/search by others -S_IRWXO :: 0o0007 // RWX mask for other -S_IROTH :: 0o0004 // R for other -S_IWOTH :: 0o0002 // W for other -S_IXOTH :: 0o0001 // X for other - -S_ISUID :: 0o4000 // Set user id on execution -S_ISGID :: 0o2000 // Set group id on execution -S_ISVTX :: 0o1000 // Directory restrcted delete - - -S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK } -S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG } -S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR } -S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR } -S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK } -S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO } -S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK } - -F_OK :: 0 // Test for file existance -X_OK :: 1 // Test for execute permission -W_OK :: 2 // Test for write permission -R_OK :: 4 // Test for read permission - -@private -Unix_File_Time :: struct { - seconds: i64, - nanoseconds: i64, -} - -@private -_Stat :: struct { - device_id: u64, // ID of device containing file - serial: u64, // File serial number - nlink: u64, // Number of hard links - mode: u32, // Mode of the file - uid: u32, // User ID of the file's owner - gid: u32, // Group ID of the file's group - _padding: i32, // 32 bits of padding - rdev: u64, // Device ID, if device - size: i64, // Size of the file, in bytes - block_size: i64, // Optimal bllocksize for I/O - blocks: i64, // Number of 512-byte blocks allocated - - last_access: Unix_File_Time, // Time of last access - modified: Unix_File_Time, // Time of last modification - status_change: Unix_File_Time, // Time of last status change - - _reserve1, - _reserve2, - _reserve3: i64, -} - - _fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) { return _fstat_internal(f.impl.fd, allocator) } -_fstat_internal :: proc(fd: int, allocator: runtime.Allocator) -> (File_Info, Error) { - s: _Stat - result := unix.sys_fstat(fd, &s) - if result < 0 { - return {}, _get_platform_error(result) +_fstat_internal :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (File_Info, Error) { + s: linux.Stat + errno := linux.fstat(fd, &s) + if errno != .NONE { + return {}, _get_platform_error(errno) } // TODO: As of Linux 4.11, the new statx syscall can retrieve creation_time fi := File_Info { fullpath = _get_full_path(fd, allocator), name = "", - size = s.size, + size = i64(s.size), mode = 0, - is_directory = S_ISDIR(s.mode), - modification_time = time.Time {s.modified.seconds}, - access_time = time.Time {s.last_access.seconds}, - creation_time = time.Time{0}, // regular stat does not provide this + is_directory = linux.S_ISDIR(s.mode), + modification_time = time.Time {i64(s.mtime.time_sec) * i64(time.Second) + i64(s.mtime.time_nsec)}, + access_time = time.Time {i64(s.atime.time_sec) * i64(time.Second) + i64(s.atime.time_nsec)}, + creation_time = time.Time{i64(s.ctime.time_sec) * i64(time.Second) + i64(s.ctime.time_nsec)}, // regular stat does not provide this } + fi.creation_time = fi.modification_time fi.name = filepath.base(fi.fullpath) return fi, nil @@ -115,11 +39,11 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - fd := unix.sys_open(name_cstr, _O_RDONLY) - if fd < 0 { - return {}, _get_platform_error(fd) + fd, errno := linux.open(name_cstr, {}) + if errno != .NONE { + return {}, _get_platform_error(errno) } - defer unix.sys_close(fd) + defer linux.close(fd) return _fstat_internal(fd, allocator) } @@ -127,11 +51,11 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW) - if fd < 0 { - return {}, _get_platform_error(fd) + fd, errno := linux.open(name_cstr, {.PATH, .NOFOLLOW}) + if errno != .NONE { + return {}, _get_platform_error(errno) } - defer unix.sys_close(fd) + defer linux.close(fd) return _fstat_internal(fd, allocator) } diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 877a90bf1..e3748cce4 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -477,7 +477,11 @@ foreign libc { @(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr --- @(link_name="free") _unix_free :: proc(ptr: rawptr) --- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr --- + @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- + @(link_name="unsetenv") _unix_unsetenv :: proc(cstring) -> c.int --- + @(link_name="setenv") _unix_setenv :: proc(key: cstring, value: cstring, overwrite: c.int) -> c.int --- + @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- @(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u16) -> c.int --- @@ -555,7 +559,7 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno err := fchmod(handle, cast(u16)mode) if err != 0 { _unix_close(handle) - return INVALID_HANDLE, cast(Errno)err + return INVALID_HANDLE, err } } @@ -883,8 +887,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path_cstr := cast(cstring)path_ptr + path = strings.clone(string(path_cstr)) return path, ERROR_NONE } @@ -896,7 +900,7 @@ access :: proc(path: string, mask: int) -> bool { } flush :: proc(fd: Handle) -> Errno { - return cast(Errno)_unix_fsync(fd) + return cast(Errno)_unix_fsync(fd) } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { @@ -914,6 +918,27 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string) return } +set_env :: proc(key, value: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + key_cstring := strings.clone_to_cstring(key, context.temp_allocator) + value_cstring := strings.clone_to_cstring(value, context.temp_allocator) + res := _unix_setenv(key_cstring, value_cstring, 1) + if res < 0 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + +unset_env :: proc(key: string) -> Errno { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + s := strings.clone_to_cstring(key, context.temp_allocator) + res := _unix_unsetenv(s) + if res < 0 { + return Errno(get_last_error()) + } + return ERROR_NONE +} + get_current_directory :: proc() -> string { page_size := get_page_size() // NOTE(tetra): See note in os_linux.odin/get_current_directory. buf := make([dynamic]u8, page_size) diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 8fe179478..36ada0948 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -648,8 +648,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + + path = strings.clone(string(cstring(path_ptr))) return path, ERROR_NONE } @@ -705,7 +705,9 @@ set_current_directory :: proc(path: string) -> (err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) - if res == -1 do return Errno(get_last_error()) + if res == -1 { + return Errno(get_last_error()) + } return ERROR_NONE } @@ -743,7 +745,9 @@ get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. @static page_size := -1 - if page_size != -1 do return page_size + if page_size != -1 { + return page_size + } page_size = int(_unix_getpagesize()) return page_size diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 545349bc5..ebc1b3600 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -890,8 +890,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path = strings.clone(string(cstring(path_ptr))) return path, ERROR_NONE } diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index c0f237bf5..2bda8abf7 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -658,8 +658,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path = strings.clone(string(cstring(path_ptr))) return path, ERROR_NONE } @@ -715,7 +714,9 @@ set_current_directory :: proc(path: string) -> (err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) - if res == -1 do return Errno(get_last_error()) + if res == -1 { + return Errno(get_last_error()) + } return ERROR_NONE } @@ -756,7 +757,9 @@ get_page_size :: proc() -> int { // NOTE(tetra): The page size never changes, so why do anything complicated // if we don't have to. @static page_size := -1 - if page_size != -1 do return page_size + if page_size != -1 { + return page_size + } page_size = int(_unix_getpagesize()) return page_size diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 182d97979..a3b74a524 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -610,8 +610,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path = strings.clone(string(cstring(path_ptr))) return path, ERROR_NONE } diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 9bfd87322..7b7fb4686 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -6,6 +6,8 @@ import "base:runtime" Handle :: distinct i32 Errno :: distinct i32 +INVALID_HANDLE :: -1 + ERROR_NONE :: Errno(wasi.errno_t.SUCCESS) O_RDONLY :: 0x00000 @@ -24,7 +26,124 @@ O_CLOEXEC :: 0x80000 stdin: Handle = 0 stdout: Handle = 1 stderr: Handle = 2 -current_dir: Handle = 3 + +args := _alloc_command_line_arguments() + +_alloc_command_line_arguments :: proc() -> (args: []string) { + args = make([]string, len(runtime.args__)) + for &arg, i in args { + arg = string(runtime.args__[i]) + } + return +} + +// WASI works with "preopened" directories, the environment retrieves directories +// (for example with `wasmtime --dir=. module.wasm`) and those given directories +// are the only ones accessible by the application. +// +// So in order to facilitate the `os` API (absolute paths etc.) we keep a list +// of the given directories and match them when needed (notably `os.open`). + +@(private) +Preopen :: struct { + fd: wasi.fd_t, + prefix: string, +} +@(private) +preopens: []Preopen + +@(init, private) +init_preopens :: proc() { + + strip_prefixes :: proc(path: string) -> string { + path := path + loop: for len(path) > 0 { + switch { + case path[0] == '/': + path = path[1:] + case len(path) > 2 && path[0] == '.' && path[1] == '/': + path = path[2:] + case len(path) == 1 && path[0] == '.': + path = path[1:] + case: + break loop + } + } + return path + } + + dyn_preopens: [dynamic]Preopen + loop: for fd := wasi.fd_t(3); ; fd += 1 { + desc, err := wasi.fd_prestat_get(fd) + #partial switch err { + case .BADF: break loop + case: panic("fd_prestat_get returned an unexpected error") + case .SUCCESS: + } + + switch desc.tag { + case .DIR: + buf := make([]byte, desc.dir.pr_name_len) or_else panic("could not allocate memory for filesystem preopens") + if err = wasi.fd_prestat_dir_name(fd, buf); err != .SUCCESS { + panic("could not get filesystem preopen dir name") + } + append(&dyn_preopens, Preopen{fd, strip_prefixes(string(buf))}) + } + } + preopens = dyn_preopens[:] +} + +wasi_match_preopen :: proc(path: string) -> (wasi.fd_t, string, bool) { + + prefix_matches :: proc(prefix, path: string) -> bool { + // Empty is valid for any relative path. + if len(prefix) == 0 && len(path) > 0 && path[0] != '/' { + return true + } + + if len(path) < len(prefix) { + return false + } + + if path[:len(prefix)] != prefix { + return false + } + + // Only match on full components. + i := len(prefix) + for i > 0 && prefix[i-1] == '/' { + i -= 1 + } + return path[i] == '/' + } + + path := path + for len(path) > 0 && path[0] == '/' { + path = path[1:] + } + + match: Preopen + #reverse for preopen in preopens { + if (match.fd == 0 || len(preopen.prefix) > len(match.prefix)) && prefix_matches(preopen.prefix, path) { + match = preopen + } + } + + if match.fd == 0 { + return 0, "", false + } + + relative := path[len(match.prefix):] + for len(relative) > 0 && relative[0] == '/' { + relative = relative[1:] + } + + if len(relative) == 0 { + relative = "." + } + + return match.fd, relative, true +} write :: proc(fd: Handle, data: []byte) -> (int, Errno) { iovs := wasi.ciovec_t(data) @@ -75,7 +194,13 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn if mode & O_SYNC == O_SYNC { fdflags += {.SYNC} } - fd, err := wasi.path_open(wasi.fd_t(current_dir),{.SYMLINK_FOLLOW},path,oflags,rights,{},fdflags) + + dir_fd, relative, ok := wasi_match_preopen(path) + if !ok { + return INVALID_HANDLE, Errno(wasi.errno_t.BADF) + } + + fd, err := wasi.path_open(dir_fd, {.SYMLINK_FOLLOW}, relative, oflags, rights, {}, fdflags) return Handle(fd), Errno(err) } close :: proc(fd: Handle) -> Errno { diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index b375e7c66..ecfb0b419 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -178,8 +178,8 @@ WINDOWS_11_BUILD_CUTOFF :: 22_000 get_windows_version_w :: proc() -> win32.OSVERSIONINFOEXW { osvi : win32.OSVERSIONINFOEXW osvi.dwOSVersionInfoSize = size_of(win32.OSVERSIONINFOEXW) - win32.RtlGetVersion(&osvi) - return osvi + win32.RtlGetVersion(&osvi) + return osvi } is_windows_xp :: proc() -> bool { diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin index 59a0f7f1c..c3dfa2bb1 100644 --- a/core/path/filepath/path.odin +++ b/core/path/filepath/path.odin @@ -432,7 +432,7 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> ( then `"."` is returned. */ dir :: proc(path: string, allocator := context.allocator) -> string { - context.allocator = allocator + context.allocator = allocator vol := volume_name(path) i := len(path) - 1 for i >= len(vol) && !is_separator(path[i]) { diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index de7379ecc..332d91c6e 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -1409,7 +1409,7 @@ as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) { #partial switch info in ti.variant { case Type_Info_Pointer: valid = true - value = a.data + value = (^rawptr)(a.data)^ case Type_Info_String: valid = true diff --git a/core/reflect/types.odin b/core/reflect/types.odin index f242dfd5c..04dd8a52d 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -114,7 +114,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { case Type_Info_Struct: y := b.variant.(Type_Info_Struct) or_return - switch { + switch { case len(x.types) != len(y.types), x.is_packed != y.is_packed, x.is_raw_union != y.is_raw_union, @@ -122,7 +122,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { x.soa_kind != y.soa_kind, x.soa_base_type != y.soa_base_type, x.soa_len != y.soa_len: - return false + return false } for _, i in x.types { xn, yn := x.names[i], y.names[i] diff --git a/core/simd/x86/sse2.odin b/core/simd/x86/sse2.odin index fc2fec300..52286cbb8 100644 --- a/core/simd/x86/sse2.odin +++ b/core/simd/x86/sse2.odin @@ -35,7 +35,7 @@ _mm_add_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_add_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.add(transmute(i64x2)a, transmute(i64x2)b) + return simd.add(a, b) } @(require_results, enable_target_feature="sse2") _mm_adds_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { @@ -118,7 +118,7 @@ _mm_sub_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_sub_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.sub(transmute(i64x2)a, transmute(i64x2)b) + return simd.sub(a, b) } @(require_results, enable_target_feature="sse2") _mm_subs_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { @@ -229,7 +229,7 @@ _mm_slli_epi64 :: #force_inline proc "c" (a: __m128i, $IMM8: u32) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_sll_epi64 :: #force_inline proc "c" (a, count: __m128i) -> __m128i { - return transmute(__m128i)psllq(transmute(i64x2)a, transmute(i64x2)count) + return psllq(a, count) } @(require_results, enable_target_feature="sse2") _mm_srai_epi16 :: #force_inline proc "c" (a: __m128i, $IMM8: u32) -> __m128i { @@ -275,7 +275,7 @@ _mm_srli_epi64 :: #force_inline proc "c" (a: __m128i, $IMM8: u32) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_srl_epi64 :: #force_inline proc "c" (a, count: __m128i) -> __m128i { - return transmute(__m128i)psrlq(transmute(i64x2)a, transmute(i64x2)count) + return psrlq(a, count) } @@ -363,7 +363,7 @@ _mm_cvtsi128_si32 :: #force_inline proc "c" (a: __m128i) -> i32 { @(require_results, enable_target_feature="sse2") _mm_set_epi64x :: #force_inline proc "c" (e1, e0: i64) -> __m128i { - return transmute(__m128i)i64x2{e0, e1} + return i64x2{e0, e1} } @(require_results, enable_target_feature="sse2") _mm_set_epi32 :: #force_inline proc "c" (e3, e2, e1, e0: i32) -> __m128i { @@ -453,7 +453,7 @@ _mm_stream_si32 :: #force_inline proc "c" (mem_addr: ^i32, a: i32) { @(require_results, enable_target_feature="sse2") _mm_move_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i { zero := _mm_setzero_si128() - return transmute(__m128i)simd.shuffle(transmute(i64x2)a, transmute(i64x2)zero, 0, 2) + return simd.shuffle(a, zero, 0, 2) } @@ -545,7 +545,7 @@ _mm_unpackhi_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_unpackhi_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.shuffle(transmute(i64x2)a, transmute(i64x2)b, 1, 3) + return simd.shuffle(a, b, 1, 3) } @(require_results, enable_target_feature="sse2") _mm_unpacklo_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { @@ -565,7 +565,7 @@ _mm_unpacklo_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse2") _mm_unpacklo_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.shuffle(transmute(i64x2)a, transmute(i64x2)b, 0, 2) + return simd.shuffle(a, b, 0, 2) } @@ -1023,7 +1023,7 @@ when ODIN_ARCH == .amd64 { } @(require_results, enable_target_feature="sse2") _mm_cvtsi128_si64 :: #force_inline proc "c" (a: __m128i) -> i64 { - return simd.extract(transmute(i64x2)a, 0) + return simd.extract(a, 0) } @(require_results, enable_target_feature="sse2") _mm_cvtsi128_si64x :: #force_inline proc "c" (a: __m128i) -> i64 { diff --git a/core/simd/x86/sse41.odin b/core/simd/x86/sse41.odin index 0b9c5986f..c2c1abc2d 100644 --- a/core/simd/x86/sse41.odin +++ b/core/simd/x86/sse41.odin @@ -106,7 +106,7 @@ _mm_packus_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse4.1") _mm_cmpeq_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)simd.lanes_eq(transmute(i64x2)a, transmute(i64x2)b) + return transmute(__m128i)simd.lanes_eq(a, b) } @(require_results, enable_target_feature="sse4.1") _mm_cvtepi8_epi16 :: #force_inline proc "c" (a: __m128i) -> __m128i { @@ -124,7 +124,7 @@ _mm_cvtepi8_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i { _mm_cvtepi8_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i { x := transmute(i8x16)a y := simd.shuffle(x, x, 0, 1) - return transmute(__m128i)i64x2(y) + return i64x2(y) } @(require_results, enable_target_feature="sse4.1") _mm_cvtepi16_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i { @@ -136,13 +136,13 @@ _mm_cvtepi16_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i { _mm_cvtepi16_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i { x := transmute(i16x8)a y := simd.shuffle(x, x, 0, 1) - return transmute(__m128i)i64x2(y) + return i64x2(y) } @(require_results, enable_target_feature="sse4.1") _mm_cvtepi32_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i { x := transmute(i32x4)a y := simd.shuffle(x, x, 0, 1) - return transmute(__m128i)i64x2(y) + return i64x2(y) } @(require_results, enable_target_feature="sse4.1") _mm_cvtepu8_epi16 :: #force_inline proc "c" (a: __m128i) -> __m128i { @@ -160,7 +160,7 @@ _mm_cvtepu8_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i { _mm_cvtepu8_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i { x := transmute(u8x16)a y := simd.shuffle(x, x, 0, 1) - return transmute(__m128i)i64x2(y) + return i64x2(y) } @(require_results, enable_target_feature="sse4.1") _mm_cvtepu16_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i { @@ -172,13 +172,13 @@ _mm_cvtepu16_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i { _mm_cvtepu16_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i { x := transmute(u16x8)a y := simd.shuffle(x, x, 0, 1) - return transmute(__m128i)i64x2(y) + return i64x2(y) } @(require_results, enable_target_feature="sse4.1") _mm_cvtepu32_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i { x := transmute(u32x4)a y := simd.shuffle(x, x, 0, 1) - return transmute(__m128i)i64x2(y) + return i64x2(y) } @(require_results, enable_target_feature="sse4.1") _mm_dp_pd :: #force_inline proc "c" (a, b: __m128d, $IMM8: u8) -> __m128d { @@ -242,7 +242,7 @@ _mm_minpos_epu16 :: #force_inline proc "c" (a: __m128i) -> __m128i { } @(require_results, enable_target_feature="sse4.1") _mm_mul_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { - return transmute(__m128i)pmuldq(transmute(i32x4)a, transmute(i32x4)b) + return pmuldq(transmute(i32x4)a, transmute(i32x4)b) } @(require_results, enable_target_feature="sse4.1") _mm_mullo_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { @@ -254,15 +254,15 @@ _mm_mpsadbw_epu8 :: #force_inline proc "c" (a, b: __m128i, $IMM8: u8) -> __m128i } @(require_results, enable_target_feature="sse4.1") _mm_testz_si128 :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 { - return ptestz(transmute(i64x2)a, transmute(i64x2)mask) + return ptestz(a, mask) } @(require_results, enable_target_feature="sse4.1") _mm_testc_si128 :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 { - return ptestc(transmute(i64x2)a, transmute(i64x2)mask) + return ptestc(a, mask) } @(require_results, enable_target_feature="sse4.1") _mm_testnzc_si128 :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 { - return ptestnzc(transmute(i64x2)a, transmute(i64x2)mask) + return ptestnzc(a, mask) } @(require_results, enable_target_feature="sse4.1") _mm_test_all_zeros :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 { diff --git a/core/simd/x86/sse42.odin b/core/simd/x86/sse42.odin index 621346342..7a674176b 100644 --- a/core/simd/x86/sse42.odin +++ b/core/simd/x86/sse42.odin @@ -94,7 +94,7 @@ _mm_crc32_u32 :: #force_inline proc "c" (crc: u32, v: u32) -> u32 { } @(require_results, enable_target_feature="sse4.2") _mm_cmpgt_epi64 :: #force_inline proc "c" (a: __m128i, b: __m128i) -> __m128i { - return transmute(__m128i)simd.lanes_gt(transmute(i64x2)a, transmute(i64x2)b) + return transmute(__m128i)simd.lanes_gt(a, b) } when ODIN_ARCH == .amd64 { diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 3cab9189d..043e51aa5 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -156,8 +156,7 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f */ @(require_results) binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) - where intrinsics.type_is_ordered(T) #no_bounds_check -{ + where intrinsics.type_is_ordered(T) #no_bounds_check { return binary_search_by(array, key, cmp_proc(T)) } @@ -180,7 +179,7 @@ binary_search_by :: proc(array: $A/[]$T, key: T, f: proc(T, T) -> Ordering) -> ( } @(require_results) -equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { +equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) #no_bounds_check { if len(a) != len(b) { return false } @@ -495,8 +494,10 @@ unique :: proc(s: $S/[]$T) -> S where intrinsics.type_is_comparable(T) #no_bound } i := 1 for j in 1.. bool) -> S #no_bounds_check { } i := 1 for j in 1.. []intrinsics.type_elem_type(T) @(require_results) enum_slice_to_bitset :: proc(enums: []$E, $T: typeid/bit_set[E]) -> (bits: T) where intrinsics.type_is_enum(E), intrinsics.type_bit_set_elem_type(T) == E { for v in enums { - bits |= {v} + bits += {v} } return } @@ -736,4 +739,4 @@ bitset_to_enum_slice_with_make :: proc(bs: $T, $E: typeid, allocator := context. return bitset_to_enum_slice(buf, bs) } -bitset_to_enum_slice :: proc{bitset_to_enum_slice_with_make, bitset_to_enum_slice_with_buffer} \ No newline at end of file +bitset_to_enum_slice :: proc{bitset_to_enum_slice_with_make, bitset_to_enum_slice_with_buffer} diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 902f1cdc5..dce9f834a 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -932,6 +932,7 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) { nd := 0 nd_mant := 0 decimal_point := 0 + trailing_zeroes_nd := -1 loop: for ; i < len(s); i += 1 { switch c := s[i]; true { case c == '_': @@ -947,9 +948,16 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) { case '0' <= c && c <= '9': saw_digits = true - if c == '0' && nd == 0 { - decimal_point -= 1 - continue loop + if c == '0' { + if nd == 0 { + decimal_point -= 1 + continue loop + } + if trailing_zeroes_nd == -1 { + trailing_zeroes_nd = nd + } + } else { + trailing_zeroes_nd = -1 } nd += 1 if nd_mant < MAX_MANT_DIGITS { @@ -981,6 +989,14 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) { if !saw_dot { decimal_point = nd } + if trailing_zeroes_nd > 0 { + trailing_zeroes_nd = nd_mant - trailing_zeroes_nd + } + for /**/; trailing_zeroes_nd > 0; trailing_zeroes_nd -= 1 { + mantissa /= base + nd_mant -= 1 + nd -= 1 + } if base == 16 { decimal_point *= 4 nd_mant *= 4 diff --git a/core/strings/builder.odin b/core/strings/builder.odin index 11885b689..6bb0b2018 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -24,7 +24,7 @@ Builder :: struct { buf: [dynamic]byte, } /* -Produces a Builder with a default length of 0 and cap of 16 +Produces an empty Builder *Allocates Using Provided Allocator* @@ -39,7 +39,7 @@ builder_make_none :: proc(allocator := context.allocator, loc := #caller_locatio return Builder{buf=make([dynamic]byte, allocator, loc) or_return }, nil } /* -Produces a Builder with a specified length and cap of max(16,len) byte buffer +Produces a Builder with specified length and capacity `len`. *Allocates Using Provided Allocator* @@ -55,7 +55,7 @@ builder_make_len :: proc(len: int, allocator := context.allocator, loc := #calle return Builder{buf=make([dynamic]byte, len, allocator, loc) or_return }, nil } /* -Produces a Builder with a specified length and cap +Produces a Builder with specified length `len` and capacity `cap`. *Allocates Using Provided Allocator* @@ -103,7 +103,7 @@ builder_make :: proc{ builder_make_len_cap, } /* -Initializes a Builder with a length of 0 and cap of 16 +Initializes an empty Builder It replaces the existing `buf` *Allocates Using Provided Allocator* @@ -121,7 +121,7 @@ builder_init_none :: proc(b: ^Builder, allocator := context.allocator, loc := #c return b, nil } /* -Initializes a Builder with a specified length and cap, which is max(len,16) +Initializes a Builder with specified length and capacity `len`. It replaces the existing `buf` *Allocates Using Provided Allocator* @@ -140,7 +140,7 @@ builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator, return b, nil } /* -Initializes a Builder with a specified length and cap +Initializes a Builder with specified length `len` and capacity `cap`. It replaces the existing `buf` Inputs: @@ -286,6 +286,20 @@ to_string :: proc(b: Builder) -> (res: string) { return string(b.buf[:]) } /* +Appends a trailing null byte after the end of the current Builder byte buffer and then casts it to a cstring + +Inputs: +- b: A pointer to builder + +Returns: +- res: A cstring of the Builder's buffer +*/ +to_cstring :: proc(b: ^Builder) -> (res: cstring) { + append(&b.buf, 0) + pop(&b.buf) + return cstring(raw_data(b.buf)) +} +/* Returns the length of the Builder's buffer, in bytes Inputs: @@ -709,11 +723,11 @@ write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: return write_string(b, s) } /* -Writes a f32 value to the Builder and returns the number of characters written +Writes a f64 value to the Builder and returns the number of characters written Inputs: - b: A pointer to the Builder -- f: The f32 value to be appended +- f: The f64 value to be appended - fmt: The format byte - always_signed: Optional boolean flag to always include the sign diff --git a/core/strings/intern.odin b/core/strings/intern.odin index 88eea3c50..4c270980c 100644 --- a/core/strings/intern.odin +++ b/core/strings/intern.odin @@ -37,7 +37,7 @@ Returns: intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator, loc := #caller_location) -> (err: mem.Allocator_Error) { m.allocator = allocator m.entries = make(map[string]^Intern_Entry, 16, map_allocator, loc) or_return - return nil + return nil } /* Frees the map and all its content allocated using the `.allocator`. diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 101ba72a9..e9b50bab0 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -531,6 +531,9 @@ Output: has_prefix :: proc(s, prefix: string) -> (result: bool) { return len(s) >= len(prefix) && s[0:len(prefix)] == prefix } + +starts_with :: has_prefix + /* Determines if a string `s` ends with a given `suffix` @@ -562,6 +565,9 @@ Output: has_suffix :: proc(s, suffix: string) -> (result: bool) { return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix } + +ends_with :: has_suffix + /* Joins a slice of strings `a` with a `sep` string @@ -1001,11 +1007,6 @@ Returns: */ @private _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, ok: bool) { - // stop once the string is empty or nil - if s == nil || len(s^) == 0 { - return - } - if sep == "" { res = s[:] ok = true @@ -2414,9 +2415,6 @@ trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta } // Procedure for `trim_*_proc` variants, which has a string rawptr cast + rune comparison is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) { - if state == nil { - return false - } cutset := (^string)(state)^ for c in cutset { if r == c { @@ -2714,7 +2712,7 @@ Output: */ split_multi_iterate :: proc(it: ^string, substrs: []string) -> (res: string, ok: bool) #no_bounds_check { - if it == nil || len(it) == 0 || len(substrs) <= 0 { + if len(it) == 0 || len(substrs) <= 0 { return } diff --git a/core/sync/chan/chan.odin b/core/sync/chan/chan.odin index f4774e4f8..0c98124de 100644 --- a/core/sync/chan/chan.odin +++ b/core/sync/chan/chan.odin @@ -304,7 +304,7 @@ try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool { if sync.atomic_load(&c.closed) || sync.atomic_load(&c.w_waiting) == 0 { - return false + return false } mem.copy(msg_out, c.unbuffered_data, int(c.msg_size)) @@ -476,10 +476,7 @@ select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: [] return } - r: ^rand.Rand = nil - - - select_idx = rand.int_max(count, r) if count > 0 else 0 + select_idx = rand.int_max(count) if count > 0 else 0 sel := candidates[select_idx] if sel.is_recv { diff --git a/core/sync/futex_netbsd.odin b/core/sync/futex_netbsd.odin index 08f7cd6c9..d12409f32 100644 --- a/core/sync/futex_netbsd.odin +++ b/core/sync/futex_netbsd.odin @@ -30,8 +30,8 @@ get_last_error :: proc "contextless" () -> int { } _futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool { - if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAIT_PRIVATE, uintptr(expected), 0, 0, 0) == -1 { - switch get_last_error() { + if error, ok := intrinsics.syscall_bsd(unix.SYS___futex, uintptr(futex), FUTEX_WAIT_PRIVATE, uintptr(expected), 0, 0, 0); !ok { + switch error { case EINTR, EAGAIN: return true case: @@ -45,11 +45,11 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du if duration <= 0 { return false } - if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAIT_PRIVATE, uintptr(expected), cast(uintptr) &Time_Spec{ + if error, ok := intrinsics.syscall_bsd(unix.SYS___futex, uintptr(futex), FUTEX_WAIT_PRIVATE, uintptr(expected), cast(uintptr) &Time_Spec{ time_sec = cast(uint)(duration / 1e9), time_nsec = cast(uint)(duration % 1e9), - }, 0, 0) == -1 { - switch get_last_error() { + }, 0, 0); !ok { + switch error { case EINTR, EAGAIN: return true case ETIMEDOUT: @@ -62,13 +62,13 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du } _futex_signal :: proc "contextless" (futex: ^Futex) { - if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, 1, 0, 0, 0) == -1 { + if _, ok := intrinsics.syscall_bsd(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); !ok { _panic("futex_wake_single failure") } } _futex_broadcast :: proc "contextless" (futex: ^Futex) { - if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, uintptr(max(i32)), 0, 0, 0) == -1 { + if _, ok := intrinsics.syscall_bsd(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, uintptr(max(i32)), 0, 0, 0); !ok { _panic("_futex_wake_all failure") } } diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin index 1b7cdfe35..2cf25ac11 100644 --- a/core/sync/primitives_atomic.odin +++ b/core/sync/primitives_atomic.odin @@ -169,7 +169,7 @@ atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) { if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) && (state & Atomic_RW_Mutex_State_Is_Writing != 0) { - atomic_sema_post(&rw.sema) + atomic_sema_post(&rw.sema) } } diff --git a/core/sys/darwin/CoreFoundation/CFString.odin b/core/sys/darwin/CoreFoundation/CFString.odin index 4a167c604..6ad3c5bfc 100644 --- a/core/sys/darwin/CoreFoundation/CFString.odin +++ b/core/sys/darwin/CoreFoundation/CFString.odin @@ -192,7 +192,7 @@ StringCopyToOdinString :: proc( max := StringGetMaximumSizeForEncoding(length, StringEncoding(StringBuiltInEncodings.UTF8)) buf, err := make([]byte, max, allocator) - if err != nil do return + if err != nil { return } raw_str := runtime.Raw_String { data = raw_data(buf), diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin index 7159a7c3a..e6103a58a 100644 --- a/core/sys/darwin/Foundation/NSWindow.odin +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -712,3 +712,7 @@ Window_setDelegate :: proc "c" (self: ^Window, delegate: ^WindowDelegate) { Window_backingScaleFactor :: proc "c" (self: ^Window) -> Float { return msgSend(Float, self, "backingScaleFactor") } +@(objc_type=Window, objc_name="setWantsLayer") +Window_setWantsLayer :: proc "c" (self: ^Window, ok: BOOL) { + msgSend(nil, self, "setWantsLayer:", ok) +} diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin index 753f7f058..7fa59bfe0 100644 --- a/core/sys/darwin/xnu_system_call_helpers.odin +++ b/core/sys/darwin/xnu_system_call_helpers.odin @@ -3,6 +3,10 @@ package darwin import "core:c" import "base:runtime" +// IMPORTANT NOTE: direct syscall usage is not allowed by Apple's review process of apps and should +// be entirely avoided in the builtin Odin collections, these are here for users if they don't +// care about the Apple review process. + // this package uses the sys prefix for the proc names to indicate that these aren't native syscalls but directly call such sys_write_string :: proc (fd: c.int, message: string) -> bool { return syscall_write(fd, raw_data(message), cast(u64)len(message)) diff --git a/core/sys/darwin/xnu_system_call_numbers.odin b/core/sys/darwin/xnu_system_call_numbers.odin index 429d18964..00ab75a15 100644 --- a/core/sys/darwin/xnu_system_call_numbers.odin +++ b/core/sys/darwin/xnu_system_call_numbers.odin @@ -1,558 +1,562 @@ package darwin +// IMPORTANT NOTE: direct syscall usage is not allowed by Apple's review process of apps and should +// be entirely avoided in the builtin Odin collections, these are here for users if they don't +// care about the Apple review process. + unix_offset_syscall :: proc "contextless" (number: System_Call_Number) -> uintptr { - return uintptr(number) + uintptr(0x2000000) + return uintptr(number) + uintptr(0x2000000) } System_Call_Number :: enum uintptr { - /* 0 syscall */ - exit = 1, - fork = 2, - read = 3, - write = 4, - open = 5, - close = 6, - wait4 = 7, - /* 8 old creat */ - link = 9, - unlink = 10, - /* 11 old execv */ - chdir = 12, - fchdir = 13, - mknod = 14, - chmod = 15, - chown = 16, - /* 17 old break */ - getfsstat = 18, - /* 19 old lseek */ - getpid = 20, - /* 21 old mount */ - /* 22 old umount */ - setuid = 23, - getuid = 24, - geteuid = 25, - ptrace = 26, - recvmsg = 27, - sendmsg = 28, - recvfrom = 29, - accept = 30, - getpeername = 31, - getsockname = 32, - access = 33, - chflags = 34, - fchflags = 35, - sync = 36, - kill = 37, - /* 38 old stat */ - getppid = 39, - /* 40 old lstat */ - dup = 41, - pipe = 42, - getegid = 43, - /* 44 old profil */ - /* 45 old ktrace */ - sigaction = 46, - getgid = 47, - sigprocmask = 48, - getlogin = 49, - setlogin = 50, - acct = 51, - sigpending = 52, - sigaltstack = 53, - ioctl = 54, - reboot = 55, - revoke = 56, - symlink = 57, - readlink = 58, - execve = 59, - umask = 60, - chroot = 61, - /* 62 old fstat */ - /* 63 used internally and reserved */ - /* getpagesize = 64, invalid */ - msync = 65, - vfork = 66, - /* 67 old vread */ - /* 68 old vwrite */ - /* 69 old sbrk */ - /* 70 old sstk */ - /* 71 old mmap */ - /* 72 old vadvise */ - munmap = 73, - mprotect = 74, - madvise = 75, - /* 76 old vhangup */ - /* 77 old vlimit */ - mincore = 78, - getgroups = 79, - setgroups = 80, - getpgrp = 81, - setpgid = 82, - setitimer = 83, - /* 84 old wait */ - swapon = 85, - getitimer = 86, - /* 87 old gethostname */ - /* 88 old sethostname */ - getdtablesize = 89, - dup2 = 90, - /* 91 old getdopt */ - fcntl = 92, - select = 93, - /* 94 old setdopt */ - fsync = 95, - setpriority = 96, - socket = 97, - connect = 98, - /* 99 old accept */ - getpriority = 100, - /* 101 old send */ - /* 102 old recv */ - /* 103 old sigreturn */ - bind = 104, - setsockopt = 105, - listen = 106, - /* 107 old vtimes */ - /* 108 old sigvec */ - /* 109 old sigblock */ - /* 110 old sigsetmask */ - sigsuspend = 111, - /* 112 old sigstack */ - /* 113 old recvmsg */ - /* 114 old sendmsg */ - /* 115 old vtrace */ - gettimeofday = 116, - getrusage = 117, - getsockopt = 118, - /* 119 old resuba */ - readv = 120, - writev = 121, - settimeofday = 122, - fchown = 123, - fchmod = 124, - /* 125 old recvfrom */ - setreuid = 126, - setregid = 127, - rename = 128, - /* 129 old truncate */ - /* 130 old ftruncate */ - flock = 131, - mkfifo = 132, - sendto = 133, - shutdown = 134, - socketpair = 135, - mkdir = 136, - rmdir = 137, - utimes = 138, - futimes = 139, - adjtime = 140, - /* 141 old getpeername */ - gethostuuid = 142, - /* 143 old sethostid */ - /* 144 old getrlimit */ - /* 145 old setrlimit */ - /* 146 old killpg */ - setsid = 147, - /* 148 old setquota */ - /* 149 old qquota */ - /* 150 old getsockname */ - getpgid = 151, - setprivexec = 152, - pread = 153, - pwrite = 154, - nfssvc = 155, - /* 156 old getdirentries */ - statfs = 157, - fstatfs = 158, - unmount = 159, - /* 160 old async_daemon */ - getfh = 161, - /* 162 old getdomainname */ - /* 163 old setdomainname */ - /* 164 */ - quotactl = 165, - /* 166 old exportfs */ - mount = 167, - /* 168 old ustat */ - csops = 169, - csops_audittoken = 170, - /* 171 old wait3 */ - /* 172 old rpause */ - waitid = 173, - /* 174 old getdents */ - /* 175 old gc_control */ - /* 176 old add_profil */ - kdebug_typefilter = 177, - kdebug_trace_string = 178, - kdebug_trace64 = 179, - kdebug_trace = 180, - setgid = 181, - setegid = 182, - seteuid = 183, - sigreturn = 184, - /* 185 old chud */ - thread_selfcounts = 186, - fdatasync = 187, - stat = 188, - fstat = 189, - lstat = 190, - pathconf = 191, - fpathconf = 192, - /* 193 old getfsstat */ - getrlimit = 194, - setrlimit = 195, - getdirentries = 196, - mmap = 197, - /* 198 old __syscall */ - lseek = 199, - truncate = 200, - ftruncate = 201, - sysctl = 202, - mlock = 203, - munlock = 204, - undelete = 205, - /* 206 old ATsocket */ - /* 207 old ATgetmsg */ - /* 208 old ATputmsg */ - /* 209 old ATsndreq */ - /* 210 old ATsndrsp */ - /* 211 old ATgetreq */ - /* 212 old ATgetrsp */ - /* 213 Reserved for AppleTalk */ - /* 214 */ - /* 215 */ - open_dprotected_np = 216, - fsgetpath_ext = 217, - /* 218 old lstatv */ - /* 219 old fstatv */ - getattrlist = 220, - setattrlist = 221, - getdirentriesattr = 222, - exchangedata = 223, - /* 224 old checkuseraccess or fsgetpath */ - searchfs = 225, - delete = 226, - copyfile = 227, - fgetattrlist = 228, - fsetattrlist = 229, - poll = 230, - /* 231 old watchevent */ - /* 232 old waitevent */ - /* 233 old modwatch */ - getxattr = 234, - fgetxattr = 235, - setxattr = 236, - fsetxattr = 237, - removexattr = 238, - fremovexattr = 239, - listxattr = 240, - flistxattr = 241, - fsctl = 242, - initgroups = 243, - posix_spawn = 244, - ffsctl = 245, - /* 246 */ - nfsclnt = 247, - fhopen = 248, - /* 249 */ - minherit = 250, - semsys = 251, - msgsys = 252, - shmsys = 253, - semctl = 254, - semget = 255, - semop = 256, - /* 257 old semconfig */ - msgctl = 258, - msgget = 259, - msgsnd = 260, - msgrcv = 261, - shmat = 262, - shmctl = 263, - shmdt = 264, - shmget = 265, - shm_open = 266, - shm_unlink = 267, - sem_open = 268, - sem_close = 269, - sem_unlink = 270, - sem_wait = 271, - sem_trywait = 272, - sem_post = 273, - sysctlbyname = 274, - /* 275 old sem_init */ - /* 276 old sem_destroy */ - open_extended = 277, - umask_extended = 278, - stat_extended = 279, - lstat_extended = 280, - fstat_extended = 281, - chmod_extended = 282, - fchmod_extended = 283, - access_extended = 284, - settid = 285, - gettid = 286, - setsgroups = 287, - getsgroups = 288, - setwgroups = 289, - getwgroups = 290, - mkfifo_extended = 291, - mkdir_extended = 292, - identitysvc = 293, - shared_region_check_np = 294, - /* 295 old shared_region_map_np */ - vm_pressure_monitor = 296, - psynch_rw_longrdlock = 297, - psynch_rw_yieldwrlock = 298, - psynch_rw_downgrade = 299, - psynch_rw_upgrade = 300, - psynch_mutexwait = 301, - psynch_mutexdrop = 302, - psynch_cvbroad = 303, - psynch_cvsignal = 304, - psynch_cvwait = 305, - psynch_rw_rdlock = 306, - psynch_rw_wrlock = 307, - psynch_rw_unlock = 308, - psynch_rw_unlock2 = 309, - getsid = 310, - settid_with_pid = 311, - psynch_cvclrprepost = 312, - aio_fsync = 313, - aio_return = 314, - aio_suspend = 315, - aio_cancel = 316, - aio_error = 317, - aio_read = 318, - aio_write = 319, - lio_listio = 320, - /* 321 old __pthread_cond_wait */ - iopolicysys = 322, - process_policy = 323, - mlockall = 324, - munlockall = 325, - /* 326 */ - issetugid = 327, - __pthread_kill = 328, - __pthread_sigmask = 329, - __sigwait = 330, - __disable_threadsignal = 331, - __pthread_markcancel = 332, - __pthread_canceled = 333, - __semwait_signal = 334, - /* 335 old utrace */ - proc_info = 336, - sendfile = 337, - stat64 = 338, - fstat64 = 339, - lstat64 = 340, - stat64_extended = 341, - lstat64_extended = 342, - fstat64_extended = 343, - getdirentries64 = 344, - statfs64 = 345, - fstatfs64 = 346, - getfsstat64 = 347, - __pthread_chdir = 348, - __pthread_fchdir = 349, - audit = 350, - auditon = 351, - /* 352 */ - getauid = 353, - setauid = 354, - /* 355 old getaudit */ - /* 356 old setaudit */ - getaudit_addr = 357, - setaudit_addr = 358, - auditctl = 359, - bsdthread_create = 360, - bsdthread_terminate = 361, - kqueue = 362, - kevent = 363, - lchown = 364, - /* 365 old stack_snapshot */ - bsdthread_register = 366, - workq_open = 367, - workq_kernreturn = 368, - kevent64 = 369, - __old_semwait_signal = 370, - __old_semwait_signal_nocancel = 371, - thread_selfid = 372, - ledger = 373, - kevent_qos = 374, - kevent_id = 375, - /* 376 */ - /* 377 */ - /* 378 */ - /* 379 */ - __mac_execve = 380, - __mac_syscall = 381, - __mac_get_file = 382, - __mac_set_file = 383, - __mac_get_link = 384, - __mac_set_link = 385, - __mac_get_proc = 386, - __mac_set_proc = 387, - __mac_get_fd = 388, - __mac_set_fd = 389, - __mac_get_pid = 390, - /* 391 */ - /* 392 */ - /* 393 */ - pselect = 394, - pselect_nocancel = 395, - read_nocancel = 396, - write_nocancel = 397, - open_nocancel = 398, - close_nocancel = 399, - wait4_nocancel = 400, - recvmsg_nocancel = 401, - sendmsg_nocancel = 402, - recvfrom_nocancel = 403, - accept_nocancel = 404, - msync_nocancel = 405, - fcntl_nocancel = 406, - select_nocancel = 407, - fsync_nocancel = 408, - connect_nocancel = 409, - sigsuspend_nocancel = 410, - readv_nocancel = 411, - writev_nocancel = 412, - sendto_nocancel = 413, - pread_nocancel = 414, - pwrite_nocancel = 415, - waitid_nocancel = 416, - poll_nocancel = 417, - msgsnd_nocancel = 418, - msgrcv_nocancel = 419, - sem_wait_nocancel = 420, - aio_suspend_nocancel = 421, - __sigwait_nocancel = 422, - __semwait_signal_nocancel = 423, - __mac_mount = 424, - __mac_get_mount = 425, - __mac_getfsstat = 426, - fsgetpath = 427, - audit_session_self = 428, - audit_session_join = 429, - fileport_makeport = 430, - fileport_makefd = 431, - audit_session_port = 432, - pid_suspend = 433, - pid_resume = 434, - pid_hibernate = 435, - pid_shutdown_sockets = 436, - /* 437 old shared_region_slide_np */ - shared_region_map_and_slide_np = 438, - kas_info = 439, - memorystatus_control = 440, - guarded_open_np = 441, - guarded_close_np = 442, - guarded_kqueue_np = 443, - change_fdguard_np = 444, - usrctl = 445, - proc_rlimit_control = 446, - connectx = 447, - disconnectx = 448, - peeloff = 449, - socket_delegate = 450, - telemetry = 451, - proc_uuid_policy = 452, - memorystatus_get_level = 453, - system_override = 454, - vfs_purge = 455, - sfi_ctl = 456, - sfi_pidctl = 457, - coalition = 458, - coalition_info = 459, - necp_match_policy = 460, - getattrlistbulk = 461, - clonefileat = 462, - openat = 463, - openat_nocancel = 464, - renameat = 465, - faccessat = 466, - fchmodat = 467, - fchownat = 468, - fstatat = 469, - fstatat64 = 470, - linkat = 471, - unlinkat = 472, - readlinkat = 473, - symlinkat = 474, - mkdirat = 475, - getattrlistat = 476, - proc_trace_log = 477, - bsdthread_ctl = 478, - openbyid_np = 479, - recvmsg_x = 480, - sendmsg_x = 481, - thread_selfusage = 482, - csrctl = 483, - guarded_open_dprotected_np = 484, - guarded_write_np = 485, - guarded_pwrite_np = 486, - guarded_writev_np = 487, - renameatx_np = 488, - mremap_encrypted = 489, - netagent_trigger = 490, - stack_snapshot_with_config = 491, - microstackshot = 492, - grab_pgo_data = 493, - persona = 494, - /* 495 */ - mach_eventlink_signal = 496, - mach_eventlink_wait_until = 497, - mach_eventlink_signal_wait_until = 498, - work_interval_ctl = 499, - getentropy = 500, - necp_open = 501, - necp_client_action = 502, - nexus_open = 503, // for those who are intressted http://newosxbook.com/bonus/vol1ch16.html - nexus_register = 504, - nexus_deregister = 505, - nexus_create = 506, - nexus_destroy = 507, - nexus_get_opt = 508, - nexus_set_opt = 509, - channel_open = 510, - channel_get_info = 511, - channel_sync = 512, - channel_get_opt = 513, - channel_set_opt = 514, - ulock_wait = 515, - ulock_wake = 516, - fclonefileat = 517, - fs_snapshot = 518, - register_uexc_handler = 519, - terminate_with_payload = 520, - abort_with_payload = 521, - necp_session_open = 522, - necp_session_action = 523, - setattrlistat = 524, - net_qos_guideline = 525, - fmount = 526, - ntp_adjtime = 527, - ntp_gettime = 528, - os_fault_with_payload = 529, - kqueue_workloop_ctl = 530, - mach_bridge_remote_time = 531, - coalition_ledger = 532, - log_data = 533, - memorystatus_available_memory = 534, - objc_bp_assist_cfg_np = 535, - shared_region_map_and_slide_2_np = 536, - pivot_root = 537, - task_inspect_for_pid = 538, - task_read_for_pid = 539, - preadv = 540, - pwritev = 541, - preadv_nocancel = 542, - pwritev_nocancel = 543, - ulock_wait2 = 544, - proc_info_extended_id = 545, - tracker_action = 546, - debug_syscall_reject = 547, - MAXSYSCALL = 548, - /* invalid = 63, */ + /* 0 syscall */ + exit = 1, + fork = 2, + read = 3, + write = 4, + open = 5, + close = 6, + wait4 = 7, + /* 8 old creat */ + link = 9, + unlink = 10, + /* 11 old execv */ + chdir = 12, + fchdir = 13, + mknod = 14, + chmod = 15, + chown = 16, + /* 17 old break */ + getfsstat = 18, + /* 19 old lseek */ + getpid = 20, + /* 21 old mount */ + /* 22 old umount */ + setuid = 23, + getuid = 24, + geteuid = 25, + ptrace = 26, + recvmsg = 27, + sendmsg = 28, + recvfrom = 29, + accept = 30, + getpeername = 31, + getsockname = 32, + access = 33, + chflags = 34, + fchflags = 35, + sync = 36, + kill = 37, + /* 38 old stat */ + getppid = 39, + /* 40 old lstat */ + dup = 41, + pipe = 42, + getegid = 43, + /* 44 old profil */ + /* 45 old ktrace */ + sigaction = 46, + getgid = 47, + sigprocmask = 48, + getlogin = 49, + setlogin = 50, + acct = 51, + sigpending = 52, + sigaltstack = 53, + ioctl = 54, + reboot = 55, + revoke = 56, + symlink = 57, + readlink = 58, + execve = 59, + umask = 60, + chroot = 61, + /* 62 old fstat */ + /* 63 used internally and reserved */ + /* getpagesize = 64, invalid */ + msync = 65, + vfork = 66, + /* 67 old vread */ + /* 68 old vwrite */ + /* 69 old sbrk */ + /* 70 old sstk */ + /* 71 old mmap */ + /* 72 old vadvise */ + munmap = 73, + mprotect = 74, + madvise = 75, + /* 76 old vhangup */ + /* 77 old vlimit */ + mincore = 78, + getgroups = 79, + setgroups = 80, + getpgrp = 81, + setpgid = 82, + setitimer = 83, + /* 84 old wait */ + swapon = 85, + getitimer = 86, + /* 87 old gethostname */ + /* 88 old sethostname */ + getdtablesize = 89, + dup2 = 90, + /* 91 old getdopt */ + fcntl = 92, + select = 93, + /* 94 old setdopt */ + fsync = 95, + setpriority = 96, + socket = 97, + connect = 98, + /* 99 old accept */ + getpriority = 100, + /* 101 old send */ + /* 102 old recv */ + /* 103 old sigreturn */ + bind = 104, + setsockopt = 105, + listen = 106, + /* 107 old vtimes */ + /* 108 old sigvec */ + /* 109 old sigblock */ + /* 110 old sigsetmask */ + sigsuspend = 111, + /* 112 old sigstack */ + /* 113 old recvmsg */ + /* 114 old sendmsg */ + /* 115 old vtrace */ + gettimeofday = 116, + getrusage = 117, + getsockopt = 118, + /* 119 old resuba */ + readv = 120, + writev = 121, + settimeofday = 122, + fchown = 123, + fchmod = 124, + /* 125 old recvfrom */ + setreuid = 126, + setregid = 127, + rename = 128, + /* 129 old truncate */ + /* 130 old ftruncate */ + flock = 131, + mkfifo = 132, + sendto = 133, + shutdown = 134, + socketpair = 135, + mkdir = 136, + rmdir = 137, + utimes = 138, + futimes = 139, + adjtime = 140, + /* 141 old getpeername */ + gethostuuid = 142, + /* 143 old sethostid */ + /* 144 old getrlimit */ + /* 145 old setrlimit */ + /* 146 old killpg */ + setsid = 147, + /* 148 old setquota */ + /* 149 old qquota */ + /* 150 old getsockname */ + getpgid = 151, + setprivexec = 152, + pread = 153, + pwrite = 154, + nfssvc = 155, + /* 156 old getdirentries */ + statfs = 157, + fstatfs = 158, + unmount = 159, + /* 160 old async_daemon */ + getfh = 161, + /* 162 old getdomainname */ + /* 163 old setdomainname */ + /* 164 */ + quotactl = 165, + /* 166 old exportfs */ + mount = 167, + /* 168 old ustat */ + csops = 169, + csops_audittoken = 170, + /* 171 old wait3 */ + /* 172 old rpause */ + waitid = 173, + /* 174 old getdents */ + /* 175 old gc_control */ + /* 176 old add_profil */ + kdebug_typefilter = 177, + kdebug_trace_string = 178, + kdebug_trace64 = 179, + kdebug_trace = 180, + setgid = 181, + setegid = 182, + seteuid = 183, + sigreturn = 184, + /* 185 old chud */ + thread_selfcounts = 186, + fdatasync = 187, + stat = 188, + fstat = 189, + lstat = 190, + pathconf = 191, + fpathconf = 192, + /* 193 old getfsstat */ + getrlimit = 194, + setrlimit = 195, + getdirentries = 196, + mmap = 197, + /* 198 old __syscall */ + lseek = 199, + truncate = 200, + ftruncate = 201, + sysctl = 202, + mlock = 203, + munlock = 204, + undelete = 205, + /* 206 old ATsocket */ + /* 207 old ATgetmsg */ + /* 208 old ATputmsg */ + /* 209 old ATsndreq */ + /* 210 old ATsndrsp */ + /* 211 old ATgetreq */ + /* 212 old ATgetrsp */ + /* 213 Reserved for AppleTalk */ + /* 214 */ + /* 215 */ + open_dprotected_np = 216, + fsgetpath_ext = 217, + /* 218 old lstatv */ + /* 219 old fstatv */ + getattrlist = 220, + setattrlist = 221, + getdirentriesattr = 222, + exchangedata = 223, + /* 224 old checkuseraccess or fsgetpath */ + searchfs = 225, + delete = 226, + copyfile = 227, + fgetattrlist = 228, + fsetattrlist = 229, + poll = 230, + /* 231 old watchevent */ + /* 232 old waitevent */ + /* 233 old modwatch */ + getxattr = 234, + fgetxattr = 235, + setxattr = 236, + fsetxattr = 237, + removexattr = 238, + fremovexattr = 239, + listxattr = 240, + flistxattr = 241, + fsctl = 242, + initgroups = 243, + posix_spawn = 244, + ffsctl = 245, + /* 246 */ + nfsclnt = 247, + fhopen = 248, + /* 249 */ + minherit = 250, + semsys = 251, + msgsys = 252, + shmsys = 253, + semctl = 254, + semget = 255, + semop = 256, + /* 257 old semconfig */ + msgctl = 258, + msgget = 259, + msgsnd = 260, + msgrcv = 261, + shmat = 262, + shmctl = 263, + shmdt = 264, + shmget = 265, + shm_open = 266, + shm_unlink = 267, + sem_open = 268, + sem_close = 269, + sem_unlink = 270, + sem_wait = 271, + sem_trywait = 272, + sem_post = 273, + sysctlbyname = 274, + /* 275 old sem_init */ + /* 276 old sem_destroy */ + open_extended = 277, + umask_extended = 278, + stat_extended = 279, + lstat_extended = 280, + fstat_extended = 281, + chmod_extended = 282, + fchmod_extended = 283, + access_extended = 284, + settid = 285, + gettid = 286, + setsgroups = 287, + getsgroups = 288, + setwgroups = 289, + getwgroups = 290, + mkfifo_extended = 291, + mkdir_extended = 292, + identitysvc = 293, + shared_region_check_np = 294, + /* 295 old shared_region_map_np */ + vm_pressure_monitor = 296, + psynch_rw_longrdlock = 297, + psynch_rw_yieldwrlock = 298, + psynch_rw_downgrade = 299, + psynch_rw_upgrade = 300, + psynch_mutexwait = 301, + psynch_mutexdrop = 302, + psynch_cvbroad = 303, + psynch_cvsignal = 304, + psynch_cvwait = 305, + psynch_rw_rdlock = 306, + psynch_rw_wrlock = 307, + psynch_rw_unlock = 308, + psynch_rw_unlock2 = 309, + getsid = 310, + settid_with_pid = 311, + psynch_cvclrprepost = 312, + aio_fsync = 313, + aio_return = 314, + aio_suspend = 315, + aio_cancel = 316, + aio_error = 317, + aio_read = 318, + aio_write = 319, + lio_listio = 320, + /* 321 old __pthread_cond_wait */ + iopolicysys = 322, + process_policy = 323, + mlockall = 324, + munlockall = 325, + /* 326 */ + issetugid = 327, + __pthread_kill = 328, + __pthread_sigmask = 329, + __sigwait = 330, + __disable_threadsignal = 331, + __pthread_markcancel = 332, + __pthread_canceled = 333, + __semwait_signal = 334, + /* 335 old utrace */ + proc_info = 336, + sendfile = 337, + stat64 = 338, + fstat64 = 339, + lstat64 = 340, + stat64_extended = 341, + lstat64_extended = 342, + fstat64_extended = 343, + getdirentries64 = 344, + statfs64 = 345, + fstatfs64 = 346, + getfsstat64 = 347, + __pthread_chdir = 348, + __pthread_fchdir = 349, + audit = 350, + auditon = 351, + /* 352 */ + getauid = 353, + setauid = 354, + /* 355 old getaudit */ + /* 356 old setaudit */ + getaudit_addr = 357, + setaudit_addr = 358, + auditctl = 359, + bsdthread_create = 360, + bsdthread_terminate = 361, + kqueue = 362, + kevent = 363, + lchown = 364, + /* 365 old stack_snapshot */ + bsdthread_register = 366, + workq_open = 367, + workq_kernreturn = 368, + kevent64 = 369, + __old_semwait_signal = 370, + __old_semwait_signal_nocancel = 371, + thread_selfid = 372, + ledger = 373, + kevent_qos = 374, + kevent_id = 375, + /* 376 */ + /* 377 */ + /* 378 */ + /* 379 */ + __mac_execve = 380, + __mac_syscall = 381, + __mac_get_file = 382, + __mac_set_file = 383, + __mac_get_link = 384, + __mac_set_link = 385, + __mac_get_proc = 386, + __mac_set_proc = 387, + __mac_get_fd = 388, + __mac_set_fd = 389, + __mac_get_pid = 390, + /* 391 */ + /* 392 */ + /* 393 */ + pselect = 394, + pselect_nocancel = 395, + read_nocancel = 396, + write_nocancel = 397, + open_nocancel = 398, + close_nocancel = 399, + wait4_nocancel = 400, + recvmsg_nocancel = 401, + sendmsg_nocancel = 402, + recvfrom_nocancel = 403, + accept_nocancel = 404, + msync_nocancel = 405, + fcntl_nocancel = 406, + select_nocancel = 407, + fsync_nocancel = 408, + connect_nocancel = 409, + sigsuspend_nocancel = 410, + readv_nocancel = 411, + writev_nocancel = 412, + sendto_nocancel = 413, + pread_nocancel = 414, + pwrite_nocancel = 415, + waitid_nocancel = 416, + poll_nocancel = 417, + msgsnd_nocancel = 418, + msgrcv_nocancel = 419, + sem_wait_nocancel = 420, + aio_suspend_nocancel = 421, + __sigwait_nocancel = 422, + __semwait_signal_nocancel = 423, + __mac_mount = 424, + __mac_get_mount = 425, + __mac_getfsstat = 426, + fsgetpath = 427, + audit_session_self = 428, + audit_session_join = 429, + fileport_makeport = 430, + fileport_makefd = 431, + audit_session_port = 432, + pid_suspend = 433, + pid_resume = 434, + pid_hibernate = 435, + pid_shutdown_sockets = 436, + /* 437 old shared_region_slide_np */ + shared_region_map_and_slide_np = 438, + kas_info = 439, + memorystatus_control = 440, + guarded_open_np = 441, + guarded_close_np = 442, + guarded_kqueue_np = 443, + change_fdguard_np = 444, + usrctl = 445, + proc_rlimit_control = 446, + connectx = 447, + disconnectx = 448, + peeloff = 449, + socket_delegate = 450, + telemetry = 451, + proc_uuid_policy = 452, + memorystatus_get_level = 453, + system_override = 454, + vfs_purge = 455, + sfi_ctl = 456, + sfi_pidctl = 457, + coalition = 458, + coalition_info = 459, + necp_match_policy = 460, + getattrlistbulk = 461, + clonefileat = 462, + openat = 463, + openat_nocancel = 464, + renameat = 465, + faccessat = 466, + fchmodat = 467, + fchownat = 468, + fstatat = 469, + fstatat64 = 470, + linkat = 471, + unlinkat = 472, + readlinkat = 473, + symlinkat = 474, + mkdirat = 475, + getattrlistat = 476, + proc_trace_log = 477, + bsdthread_ctl = 478, + openbyid_np = 479, + recvmsg_x = 480, + sendmsg_x = 481, + thread_selfusage = 482, + csrctl = 483, + guarded_open_dprotected_np = 484, + guarded_write_np = 485, + guarded_pwrite_np = 486, + guarded_writev_np = 487, + renameatx_np = 488, + mremap_encrypted = 489, + netagent_trigger = 490, + stack_snapshot_with_config = 491, + microstackshot = 492, + grab_pgo_data = 493, + persona = 494, + /* 495 */ + mach_eventlink_signal = 496, + mach_eventlink_wait_until = 497, + mach_eventlink_signal_wait_until = 498, + work_interval_ctl = 499, + getentropy = 500, + necp_open = 501, + necp_client_action = 502, + nexus_open = 503, // for those who are intressted http://newosxbook.com/bonus/vol1ch16.html + nexus_register = 504, + nexus_deregister = 505, + nexus_create = 506, + nexus_destroy = 507, + nexus_get_opt = 508, + nexus_set_opt = 509, + channel_open = 510, + channel_get_info = 511, + channel_sync = 512, + channel_get_opt = 513, + channel_set_opt = 514, + ulock_wait = 515, + ulock_wake = 516, + fclonefileat = 517, + fs_snapshot = 518, + register_uexc_handler = 519, + terminate_with_payload = 520, + abort_with_payload = 521, + necp_session_open = 522, + necp_session_action = 523, + setattrlistat = 524, + net_qos_guideline = 525, + fmount = 526, + ntp_adjtime = 527, + ntp_gettime = 528, + os_fault_with_payload = 529, + kqueue_workloop_ctl = 530, + mach_bridge_remote_time = 531, + coalition_ledger = 532, + log_data = 533, + memorystatus_available_memory = 534, + objc_bp_assist_cfg_np = 535, + shared_region_map_and_slide_2_np = 536, + pivot_root = 537, + task_inspect_for_pid = 538, + task_read_for_pid = 539, + preadv = 540, + pwritev = 541, + preadv_nocancel = 542, + pwritev_nocancel = 543, + ulock_wait2 = 544, + proc_info_extended_id = 545, + tracker_action = 546, + debug_syscall_reject = 547, + MAXSYSCALL = 548, + /* invalid = 63, */ } diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index 7100da4f1..d289ee7c1 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -3,6 +3,10 @@ package darwin import "core:c" import "base:intrinsics" +// IMPORTANT NOTE: direct syscall usage is not allowed by Apple's review process of apps and should +// be entirely avoided in the builtin Odin collections, these are here for users if they don't +// care about the Apple review process. + /* flock */ LOCK_SH :: 1 /* shared lock */ LOCK_EX :: 2 /* exclusive lock */ diff --git a/core/sys/info/cpu_darwin_arm64.odin b/core/sys/info/cpu_darwin_arm64.odin index 336334bc0..ffa60d1cb 100644 --- a/core/sys/info/cpu_darwin_arm64.odin +++ b/core/sys/info/cpu_darwin_arm64.odin @@ -7,7 +7,7 @@ init_cpu_features :: proc "contextless" () { @(static) features: CPU_Features defer cpu_features = features - try_set :: proc "contextless" (name: string, feature: CPU_Feature) -> (ok: bool) { + try_set :: proc "contextless" (name: cstring, feature: CPU_Feature) -> (ok: bool) { support: b32 if ok = unix.sysctlbyname(name, &support); ok && support { features += { feature } diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin index 63af853d0..73d4c15e7 100644 --- a/core/sys/info/cpu_intel.odin +++ b/core/sys/info/cpu_intel.odin @@ -117,7 +117,7 @@ init_cpu_name :: proc "c" () { return } - _buf := transmute(^[0x12]u32)&_cpu_name_buf + _buf := (^[0x12]u32)(&_cpu_name_buf) _buf[ 0], _buf[ 1], _buf[ 2], _buf[ 3] = cpuid(0x8000_0002, 0) _buf[ 4], _buf[ 5], _buf[ 6], _buf[ 7] = cpuid(0x8000_0003, 0) _buf[ 8], _buf[ 9], _buf[10], _buf[11] = cpuid(0x8000_0004, 0) diff --git a/core/sys/info/platform_freebsd.odin b/core/sys/info/platform_freebsd.odin index c1429c4b2..b26fb7875 100644 --- a/core/sys/info/platform_freebsd.odin +++ b/core/sys/info/platform_freebsd.odin @@ -12,7 +12,7 @@ version_string_buf: [1024]u8 init_os_version :: proc () { os_version.platform = .FreeBSD - kernel_version_buf: [129]u8 + kernel_version_buf: [1024]u8 b := strings.builder_from_bytes(version_string_buf[:]) // Retrieve kernel info using `sysctl`, e.g. FreeBSD 13.1-RELEASE-p2 GENERIC diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin index cfae06013..1e9e5bbbd 100644 --- a/core/sys/linux/bits.odin +++ b/core/sys/linux/bits.odin @@ -48,6 +48,7 @@ Errno :: enum i32 { ENOSYS = 38, ENOTEMPTY = 39, ELOOP = 40, + EUNKNOWN_41 = 41, ENOMSG = 42, EIDRM = 43, ECHRNG = 44, @@ -64,6 +65,7 @@ Errno :: enum i32 { ENOANO = 55, EBADRQC = 56, EBADSLT = 57, + EUNKNOWN_58 = 58, EBFONT = 59, ENOSTR = 60, ENODATA = 61, @@ -150,44 +152,66 @@ Errno :: enum i32 { RDONLY flag is not present, because it has the value of 0, i.e. it is the default, unless WRONLY or RDWR is specified. */ -Open_Flags_Bits :: enum { - WRONLY = 0, - RDWR = 1, - CREAT = 6, - EXCL = 7, - NOCTTY = 8, - TRUNC = 9, - APPEND = 10, - NONBLOCK = 11, - DSYNC = 12, - ASYNC = 13, - DIRECT = 14, - LARGEFILE = 15, - DIRECTORY = 16, - NOFOLLOW = 17, - NOATIME = 18, - CLOEXEC = 19, - PATH = 21, -} +when ODIN_ARCH != .arm64 && ODIN_ARCH != .arm32 { + Open_Flags_Bits :: enum { + WRONLY = 0, + RDWR = 1, + CREAT = 6, + EXCL = 7, + NOCTTY = 8, + TRUNC = 9, + APPEND = 10, + NONBLOCK = 11, + DSYNC = 12, + ASYNC = 13, + DIRECT = 14, + LARGEFILE = 15, + DIRECTORY = 16, + NOFOLLOW = 17, + NOATIME = 18, + CLOEXEC = 19, + PATH = 21, + } + // https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19 + #assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1) + #assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2) + #assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100) + #assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200) + #assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400) + #assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000) + #assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000) + #assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000) + #assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000) + #assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000) + #assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000) + #assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000) + #assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000) + #assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000) + #assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000) + #assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000) + #assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000) -// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19 -#assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1) -#assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2) -#assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100) -#assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200) -#assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400) -#assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000) -#assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000) -#assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000) -#assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000) -#assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000) -#assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000) -#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000) -#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000) -#assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000) -#assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000) -#assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000) -#assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000) +} else { + Open_Flags_Bits :: enum { + WRONLY = 0, + RDWR = 1, + CREAT = 6, + EXCL = 7, + NOCTTY = 8, + TRUNC = 9, + APPEND = 10, + NONBLOCK = 11, + DSYNC = 12, + ASYNC = 13, + DIRECTORY = 14, + NOFOLLOW = 15, + DIRECT = 16, + LARGEFILE = 17, + NOATIME = 18, + CLOEXEC = 19, + PATH = 21, + } +} /* Bits for FD_Flags bitset @@ -867,7 +891,7 @@ Wait_Option :: enum { WSTOPPED = 1, WEXITED = 2, WCONTINUED = 3, - WNOWAIT = 24, + WNOWAIT = 24, // // For processes created using clone __WNOTHREAD = 29, __WALL = 30, @@ -946,9 +970,22 @@ Sig_Stack_Flag :: enum i32 { AUTODISARM = 31, } +Sig_Action_Flag :: enum u32 { + NOCLDSTOP = 0, + NOCLDWAIT = 1, + SIGINFO = 2, + UNSUPPORTED = 10, + EXPOSE_TAGBITS = 11, + RESTORER = 26, + ONSTACK = 27, + RESTART = 28, + NODEFER = 30, + RESETHAND = 31, +} + /* Type of socket to create - - For TCP you want to use SOCK_STREAM + - For TCP you want to use SOCK_STREAM - For UDP you want to use SOCK_DGRAM Also see `Protocol` */ @@ -1427,16 +1464,16 @@ Futex_Flags_Bits :: enum { Kind of operation on futex, see FUTEX_WAKE_OP */ Futex_Arg_Op :: enum { - SET = 0, /* uaddr2 = oparg; */ - ADD = 1, /* uaddr2 += oparg; */ - OR = 2, /* uaddr2 |= oparg; */ - ANDN = 3, /* uaddr2 &= ~oparg; */ - XOR = 4, /* uaddr2 ^= oparg; */ - PO2_SET = 0, /* uaddr2 = 1< (Errno) { stat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) { when size_of(int) == 8 { when ODIN_ARCH == .arm64 { - ret := syscall(SYS_fstatat, AT_FDCWD, cast(rawptr) filename, stat) + ret := syscall(SYS_fstatat, AT_FDCWD, cast(rawptr) filename, stat, 0) return Errno(-ret) } else { ret := syscall(SYS_stat, cast(rawptr) filename, stat) @@ -200,10 +200,25 @@ brk :: proc "contextless" (addr: uintptr) -> (Errno) { return Errno(-ret) } +/* + Returns from signal handlers on some archs. +*/ +rt_sigreturn :: proc "c" () -> ! { + intrinsics.syscall(uintptr(SYS_rt_sigreturn)) + unreachable() +} + /* Alter an action taken by a process. */ -rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action, old_sigaction: ^Sig_Action) -> Errno { +rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action($T), old_sigaction: ^Sig_Action) -> Errno { + // NOTE(jason): It appears that the restorer is required for i386 and amd64 + when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 { + sigaction.flags += {.RESTORER} + } + if sigaction != nil && sigaction.restorer == nil && .RESTORER in sigaction.flags { + sigaction.restorer = rt_sigreturn + } ret := syscall(SYS_rt_sigaction, sig, sigaction, old_sigaction, size_of(Sig_Set)) return Errno(-ret) } @@ -1123,7 +1138,7 @@ ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) { ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length)) return Errno(-ret) } else { - ret := syscall(SYS_truncate, fd, compat64_arg_pair(length)) + ret := syscall(SYS_ftruncate, fd, compat64_arg_pair(length)) return Errno(-ret) } } @@ -1231,7 +1246,7 @@ creat :: proc "contextless" (name: cstring, mode: Mode) -> (Fd, Errno) { */ link :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { when ODIN_ARCH == .arm64 { - ret := syscall(SYS_linkat, AT_FDCWD, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath) + ret := syscall(SYS_linkat, AT_FDCWD, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath, 0) return Errno(-ret) } else { ret := syscall(SYS_link, cast(rawptr) target, cast(rawptr) linkpath) @@ -1261,7 +1276,7 @@ unlink :: proc "contextless" (name: cstring) -> (Errno) { */ symlink :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { when ODIN_ARCH == .arm64 { - ret := syscall(SYS_symlinkat, AT_FDCWD, cast(rawptr) target, cast(rawptr) linkpath) + ret := syscall(SYS_symlinkat, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath) return Errno(-ret) } else { ret := syscall(SYS_symlink, cast(rawptr) target, cast(rawptr) linkpath) @@ -1291,7 +1306,7 @@ readlink :: proc "contextless" (name: cstring, buf: []u8) -> (int, Errno) { */ chmod :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) { when ODIN_ARCH == .arm64 { - ret := syscall(SYS_fchmodat, cast(rawptr) name, transmute(u32) mode, 0) + ret := syscall(SYS_fchmodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode) return Errno(-ret) } else { ret := syscall(SYS_chmod, cast(rawptr) name, transmute(u32) mode) @@ -1718,9 +1733,9 @@ getpgrp :: proc "contextless" () -> (Pid, Errno) { Create a session and set the process group ID. Available since Linux 2.0. */ -setsid :: proc "contextless" () -> (Errno) { +setsid :: proc "contextless" () -> (Pid, Errno) { ret := syscall(SYS_setsid) - return Errno(-ret) + return errno_unwrap(ret, Pid) } /* @@ -2226,8 +2241,7 @@ futex_wake :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Type, flags: Fut Returns the total number of waiters that have been woken up plus the number of waiters requeued. */ futex_cmp_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Cmp_Requeue_Type, flags: Futex_Flags, requeue_threshold: u32, - requeue_max: i32, requeue_futex: ^Futex, val: i32) -> (int, Errno) -{ + requeue_max: i32, requeue_futex: ^Futex, val: i32) -> (int, Errno) { futex_flags := cast(u32) op + transmute(u32) flags ret := syscall(SYS_futex, futex, futex_flags, requeue_threshold, requeue_max, requeue_futex, val) return errno_unwrap(ret, int) @@ -2238,8 +2252,7 @@ futex_cmp_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Cmp_Requeue_Ty Returns the total number of waiters that have been woken up. */ futex_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Requeue_Type, flags: Futex_Flags, requeue_threshold: u32, - requeue_max: i32, requeue_futex: ^Futex) -> (int, Errno) -{ + requeue_max: i32, requeue_futex: ^Futex) -> (int, Errno) { futex_flags := cast(u32) op + transmute(u32) flags ret := syscall(SYS_futex, futex, futex_flags, requeue_threshold, requeue_max, requeue_futex) return errno_unwrap(ret, int) @@ -2250,8 +2263,7 @@ futex_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Requeue_Type, flag purpose is to allow implementing conditional values sync primitive, it seems like. */ futex_wake_op :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Op_Type, flags: Futex_Flags, wakeup: i32, - dst_wakeup, dst: ^Futex, futex_op: u32) -> (int, Errno) -{ + dst_wakeup, dst: ^Futex, futex_op: u32) -> (int, Errno) { futex_flags := cast(u32) op + transmute(u32) flags ret := syscall(SYS_futex, futex, futex_flags, wakeup, dst_wakeup, dst, futex_op) return errno_unwrap(ret, int) @@ -2261,8 +2273,7 @@ futex_wake_op :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Op_Type, flag Same as wait, but mask specifies bits that must be equal for the mutex to wake up. */ futex_wait_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wait_Bitset_Type, flags: Futex_Flags, val: u32, - timeout: ^Time_Spec, mask: u32) -> (int, Errno) -{ + timeout: ^Time_Spec, mask: u32) -> (int, Errno) { futex_flags := cast(u32) op + transmute(u32) flags ret := syscall(SYS_futex, futex, futex_flags, val, timeout, 0, mask) return errno_unwrap(ret, int) @@ -2271,8 +2282,7 @@ futex_wait_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wait_Bitset_Ty /* Wake up on bitset. */ -futex_wake_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Bitset_Type, flags: Futex_Flags, n_wakeup: u32, mask: u32) -> (int, Errno) -{ +futex_wake_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Bitset_Type, flags: Futex_Flags, n_wakeup: u32, mask: u32) -> (int, Errno) { futex_flags := cast(u32) op + transmute(u32) flags ret := syscall(SYS_futex, futex, futex_flags, n_wakeup, 0, 0, mask) return errno_unwrap(ret, int) @@ -2280,7 +2290,7 @@ futex_wake_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Bitset_Ty // TODO(flysand): Priority inheritance (PI) futicees -futex :: proc { +futex :: proc{ futex_wait, futex_wake, futex_cmp_requeue, @@ -2476,8 +2486,8 @@ tgkill :: proc "contextless" (tgid, tid: Pid, sig: Signal) -> (Errno) { Wait on process, process group or pid file descriptor. Available since Linux 2.6.10. */ -waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, options: Wait_Options) -> (Errno) { - ret := syscall(SYS_waitid, id_type, id, sig_info, transmute(i32) options) +waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, options: Wait_Options, rusage: ^RUsage) -> (Errno) { + ret := syscall(SYS_waitid, id_type, id, sig_info, transmute(i32) options, rusage) return Errno(-ret) } @@ -2504,7 +2514,7 @@ waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, opt Available since Linux 2.6.16. */ openat :: proc "contextless" (fd: Fd, name: cstring, flags: Open_Flags, mode: Mode = {}) -> (Fd, Errno) { - ret := syscall(SYS_openat, fd, AT_FDCWD, transmute(uintptr) name, transmute(u32) mode) + ret := syscall(SYS_openat, fd, transmute(uintptr) name, transmute(u32) flags, transmute(u32) mode) return errno_unwrap(ret, Fd) } @@ -2583,8 +2593,8 @@ linkat :: proc "contextless" (target_dirfd: Fd, oldpath: cstring, link_dirfd: Fd Create a symbolic link at specified dirfd. Available since Linux 2.6.16. */ -symlinkat :: proc "contextless" (dirfd: Fd, target: cstring, linkpath: cstring) -> (Errno) { - ret := syscall(SYS_symlinkat, dirfd, cast(rawptr) target, cast(rawptr) linkpath) +symlinkat :: proc "contextless" (target: cstring, dirfd: Fd, linkpath: cstring) -> (Errno) { + ret := syscall(SYS_symlinkat, cast(rawptr) target, dirfd, cast(rawptr) linkpath) return Errno(-ret) } @@ -2619,13 +2629,13 @@ faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) -> Wait for events on a file descriptor. Available since Linux 2.6.16. */ -ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (Errno) { +ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) { when size_of(int) == 8 { ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) - return Errno(-ret) + return errno_unwrap(ret, i32) } else { ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) - return Errno(-ret) + return errno_unwrap(ret, i32) } } @@ -2808,8 +2818,8 @@ getrandom :: proc "contextless" (buf: []u8, flags: Get_Random_Flags) -> (int, Er Execute program relative to a directory file descriptor. Available since Linux 3.19. */ -execveat :: proc "contextless" (dirfd: Fd, name: cstring, argv: [^]cstring, envp: [^]cstring) -> (Errno) { - ret := syscall(SYS_execveat, dirfd, cast(rawptr) name, cast(rawptr) argv, cast(rawptr) envp) +execveat :: proc "contextless" (dirfd: Fd, name: cstring, argv: [^]cstring, envp: [^]cstring, flags: FD_Flags = {}) -> (Errno) { + ret := syscall(SYS_execveat, dirfd, cast(rawptr) name, cast(rawptr) argv, cast(rawptr) envp, transmute(i32) flags) return Errno(-ret) } diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 5053e1e1c..e3fe67a9b 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -18,7 +18,7 @@ Gid :: distinct u32 /* Type for Process IDs, Thread IDs, Thread group ID. */ -Pid :: distinct int +Pid :: distinct i32 /* Type for any of: pid, pidfd, pgid. @@ -89,11 +89,11 @@ FD_Flags :: bit_set[FD_Flags_Bits; i32] Represents file's permission and status bits **Example:** When you're passing a value of this type the recommended usage is: - + ``` linux.Mode{.S_IXOTH, .S_IROTH} | linux.S_IRWXU | linux.S_IRWXG ``` - + This would generate a mode that has full permissions for the file's owner and group, and only "read" and "execute" bits for others. @@ -151,9 +151,9 @@ when ODIN_ARCH == .amd64 { size: i64, blksize: uint, blocks: u64, - atim: Time_Spec, - mtim: Time_Spec, - ctim: Time_Spec, + atime: Time_Spec, + mtime: Time_Spec, + ctime: Time_Spec, ino: Inode, } } @@ -495,16 +495,15 @@ Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32] // 1. Odin's bitfields start from 0, whereas signals start from 1 // 2. It's unclear how bitfields act in terms of ABI (are they an array of ints or an array of longs?). // it makes a difference because ARM is big endian. -@private _SIGSET_NWORDS :: (1024 / (8 * size_of(uint))) +@private _SIGSET_NWORDS :: (8 / size_of(uint)) Sig_Set :: [_SIGSET_NWORDS]uint @private SI_MAX_SIZE :: 128 -@private SI_ARCH_PREAMBLE :: 3 * size_of(i32) -@private SI_PAD_SIZE :: (SI_MAX_SIZE - SI_ARCH_PREAMBLE) / size_of(i32) -@private SI_TIMER_PAD_SIZE :: size_of(Uid) - size_of(i32) +@private SI_ARCH_PREAMBLE :: 4 * size_of(i32) +@private SI_PAD_SIZE :: SI_MAX_SIZE - SI_ARCH_PREAMBLE Sig_Handler_Fn :: #type proc "c" (sig: Signal) -Sig_Restore_Fn :: #type proc "c" () +Sig_Restore_Fn :: #type proc "c" () -> ! Sig_Info :: struct #packed { signo: Signal, @@ -518,8 +517,9 @@ Sig_Info :: struct #packed { uid: Uid, /* sender's uid */ }, using _timer: struct { - timerid: i32, /* timer id */ + timerid: i32, /* timer id */ overrun: i32, /* overrun count */ + value: Sig_Val, /* timer value */ }, /* POSIX.1b signals */ using _rt: struct { @@ -528,8 +528,8 @@ Sig_Info :: struct #packed { }, /* SIGCHLD */ using _sigchld: struct { - _pid1: Pid, /* which child */ - _uid1: Uid, /* sender's uid */ + _pid1: Pid, /* which child */ + _uid1: Uid, /* sender's uid */ status: i32, /* exit code */ utime: uint, stime: uint, //clock_t @@ -537,7 +537,24 @@ Sig_Info :: struct #packed { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ using _sigfault: struct { addr: rawptr, /* faulting insn/memory ref. */ - addr_lsb: i16, /* LSB of the reported address */ + using _: struct #raw_union { + trapno: i32, /* Trap number that caused signal */ + addr_lsb: i16, /* LSB of the reported address */ + using _addr_bnd: struct { + _pad2: u64, + lower: rawptr, /* lower bound during fault */ + upper: rawptr, /* upper bound during fault */ + }, + using _addr_pkey: struct { + _pad3: u64, + pkey: u32, /* protection key on PTE that faulted */ + }, + using _perf: struct { + perf_data: u64, + perf_type: u32, + perf_flags: u32, + }, + }, }, /* SIGPOLL */ using _sigpoll: struct { @@ -547,12 +564,43 @@ Sig_Info :: struct #packed { /* SIGSYS */ using _sigsys: struct { call_addr: rawptr, /* calling user insn */ - syscall: i32, /* triggering system call number */ - arch: u32, /* AUDIT_ARCH_* of syscall */ + syscall: i32, /* triggering system call number */ + arch: u32, /* AUDIT_ARCH_* of syscall */ }, }, } +#assert(size_of(Sig_Info) == 128) +when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + #assert(offset_of(Sig_Info, signo) == 0x00) + #assert(offset_of(Sig_Info, errno) == 0x04) + #assert(offset_of(Sig_Info, code) == 0x08) + #assert(offset_of(Sig_Info, pid) == 0x10) + #assert(offset_of(Sig_Info, uid) == 0x14) + #assert(offset_of(Sig_Info, timerid) == 0x10) + #assert(offset_of(Sig_Info, overrun) == 0x14) + #assert(offset_of(Sig_Info, value) == 0x18) + #assert(offset_of(Sig_Info, status) == 0x18) + #assert(offset_of(Sig_Info, utime) == 0x20) + #assert(offset_of(Sig_Info, stime) == 0x28) + #assert(offset_of(Sig_Info, addr) == 0x10) + #assert(offset_of(Sig_Info, addr_lsb) == 0x18) + #assert(offset_of(Sig_Info, trapno) == 0x18) + #assert(offset_of(Sig_Info, lower) == 0x20) + #assert(offset_of(Sig_Info, upper) == 0x28) + #assert(offset_of(Sig_Info, pkey) == 0x20) + #assert(offset_of(Sig_Info, perf_data) == 0x18) + #assert(offset_of(Sig_Info, perf_type) == 0x20) + #assert(offset_of(Sig_Info, perf_flags) == 0x24) + #assert(offset_of(Sig_Info, band) == 0x10) + #assert(offset_of(Sig_Info, fd) == 0x18) + #assert(offset_of(Sig_Info, call_addr) == 0x10) + #assert(offset_of(Sig_Info, syscall) == 0x18) + #assert(offset_of(Sig_Info, arch) == 0x1C) +} else { + // TODO +} + SIGEV_MAX_SIZE :: 64 SIGEV_PAD_SIZE :: ((SIGEV_MAX_SIZE-size_of(i32)*2+size_of(Sig_Val))/size_of(i32)) @@ -583,12 +631,20 @@ Sig_Stack :: struct { size: uintptr, } +Sig_Action_Special :: enum uint { + SIG_DFL = 0, + SIG_IGN = 1, + SIG_ERR = ~uint(0), +} + +Sig_Action_Flags :: bit_set[Sig_Action_Flag; uint] Sig_Action :: struct($T: typeid) { using _u: struct #raw_union { handler: Sig_Handler_Fn, sigaction: #type proc "c" (sig: Signal, si: ^Sig_Info, ctx: ^T), + special: Sig_Action_Special, }, - flags: uint, + flags: Sig_Action_Flags, restorer: Sig_Restore_Fn, mask: Sig_Set, } @@ -733,7 +789,7 @@ RLimit :: struct { /* Structure representing how much of each resource got used. -*/ +*/ RUsage :: struct { utime: Time_Val, stime: Time_Val, @@ -813,7 +869,7 @@ when size_of(int) == 8 || ODIN_ARCH == .i386 { cpid: Pid, lpid: Pid, nattach: uint, - _: [2]uint, + _: [2]uint, } } diff --git a/core/sys/linux/wrappers.odin b/core/sys/linux/wrappers.odin index 13073315d..7a30c3bde 100644 --- a/core/sys/linux/wrappers.odin +++ b/core/sys/linux/wrappers.odin @@ -48,7 +48,7 @@ WCOREDUMP :: #force_inline proc "contextless" (s: u32) -> bool { return 1 << ((cast(uint)(sig) - 1) % (8*size_of(uint))) } @private _sigword :: proc "contextless" (sig: Signal) -> (uint) { - return (cast(uint)sig - 1) / (8*size_of(uint)) + return (cast(uint)sig - 1) / (8*size_of(uint)) } // TODO: sigaddset etc @@ -85,13 +85,13 @@ dirent_iterate_buf :: proc "contextless" (buf: []u8, offs: ^int) -> (d: ^Dirent, /// Obtain the name of dirent as a string /// The lifetime of the string is bound to the lifetime of the provided dirent structure dirent_name :: proc "contextless" (dirent: ^Dirent) -> string #no_bounds_check { - str := transmute([^]u8) &dirent.name + str := ([^]u8)(&dirent.name) // Note(flysand): The string size calculated above applies only to the ideal case // we subtract 1 byte from the string size, because a null terminator is guaranteed // to be present. But! That said, the dirents are aligned to 8 bytes and the padding // between the null terminator and the start of the next struct may be not initialized // which means we also have to scan these garbage bytes. - str_size := (cast(int) dirent.reclen) - 1 - cast(int) offset_of(Dirent, name) + str_size := int(dirent.reclen) - 1 - cast(int)offset_of(Dirent, name) // This skips *only* over the garbage, since if we're not garbage we're at nul terminator, // which skips this loop for str[str_size] != 0 { @@ -115,7 +115,6 @@ futex_op :: proc "contextless" (arg_op: Futex_Arg_Op, cmp_op: Futex_Cmp_Op, op_a /// Helper function for constructing the config for caches perf_cache_config :: #force_inline proc "contextless" (id: Perf_Hardware_Cache_Id, op: Perf_Hardware_Cache_Op_Id, - res: Perf_Hardware_Cache_Result_Id) -> u64 -{ + res: Perf_Hardware_Cache_Result_Id) -> u64 { return u64(id) | (u64(op) << 8) | (u64(res) << 16) } \ No newline at end of file diff --git a/core/sys/unix/sysctl_darwin.odin b/core/sys/unix/sysctl_darwin.odin index 6417961e5..14d3c113a 100644 --- a/core/sys/unix/sysctl_darwin.odin +++ b/core/sys/unix/sysctl_darwin.odin @@ -3,29 +3,60 @@ package unix import "base:intrinsics" -import "core:c" import "core:sys/darwin" _ :: darwin sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) { - result_size := c.size_t(size_of(T)) - res := darwin.syscall_sysctl( - raw_data(mib), len(mib), - val, &result_size, - nil, 0, - ) - return res == 0 + result_size := uint(size_of(T)) + when ODIN_NO_CRT { + res := darwin.syscall_sysctl( + raw_data(mib), len(mib), + val, &result_size, + nil, 0, + ) + return res == 0 + } else { + foreign { + @(link_name="sysctl") _sysctl :: proc( + name: [^]i32, namelen: u32, + oldp: rawptr, oldlenp: ^uint, + newp: rawptr, newlen: uint, + ) -> i32 --- + } + res := _sysctl( + raw_data(mib), u32(len(mib)), + val, &result_size, + nil, 0, + ) + return res == 0 + } } -sysctlbyname :: proc "contextless" (name: string, val: ^$T) -> (ok: bool) { - result_size := c.size_t(size_of(T)) - res := darwin.syscall_sysctlbyname( - name, - val, &result_size, - nil, 0, - ) - return res == 0 +sysctlbyname :: proc "contextless" (name: cstring, val: ^$T) -> (ok: bool) { + result_size := uint(size_of(T)) + when ODIN_NO_CRT { + res := darwin.syscall_sysctlbyname( + string(name), + val, &result_size, + nil, 0, + ) + return res == 0 + } else { + foreign { + @(link_name="sysctlbyname") _sysctlbyname :: proc( + name: cstring, + oldp: rawptr, oldlenp: ^uint, + newp: rawptr, newlen: uint, + ) -> i32 --- + } + res := _sysctlbyname( + name, + val, &result_size, + nil, 0, + ) + return res == 0 + } } // See sysctl.h for darwin for details diff --git a/core/sys/unix/sysctl_freebsd.odin b/core/sys/unix/sysctl_freebsd.odin index d1acbc2a1..35c5db02c 100644 --- a/core/sys/unix/sysctl_freebsd.odin +++ b/core/sys/unix/sysctl_freebsd.odin @@ -5,14 +5,15 @@ import "base:intrinsics" sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { mib := mib - result_size := i64(size_of(T)) + result_size := u64(size_of(T)) - res := intrinsics.syscall(SYS_sysctl, + res: uintptr + res, ok = intrinsics.syscall_bsd(SYS_sysctl, uintptr(raw_data(mib)), uintptr(len(mib)), uintptr(val), uintptr(&result_size), uintptr(0), uintptr(0), ) - return res == 0 + return } // See /usr/include/sys/sysctl.h for details diff --git a/core/sys/wasm/wasi/wasi_api.odin b/core/sys/wasm/wasi/wasi_api.odin index e9ceb4667..22abd8dc4 100644 --- a/core/sys/wasm/wasi/wasi_api.odin +++ b/core/sys/wasm/wasi/wasi_api.odin @@ -962,7 +962,7 @@ prestat_dir_t :: struct { } prestat_t :: struct { - tag: u8, + tag: preopentype_t, using u: struct { dir: prestat_dir_t, }, @@ -1158,7 +1158,7 @@ foreign wasi { /** * A buffer into which to write the preopened directory name. */ - path: string, + path: []byte, ) -> errno_t --- /** * Create a directory. diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 9f6135f4b..c2f97fff9 100755 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -38,20 +38,36 @@ foreign kernel32 { lpNumberOfCharsWritten: LPDWORD, lpReserved: LPVOID) -> BOOL --- + PeekConsoleInputW :: proc(hConsoleInput: HANDLE, + lpBuffer: ^INPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsRead: LPDWORD) -> BOOL --- + + ReadConsoleInputW :: proc(hConsoleInput: HANDLE, + lpBuffer: ^INPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsRead: LPDWORD) -> BOOL --- + + // https://learn.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents + GetNumberOfConsoleInputEvents :: proc(hConsoleInput: HANDLE, lpcNumberOfEvents: LPDWORD) -> BOOL --- + GetConsoleMode :: proc(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL --- SetConsoleMode :: proc(hConsoleHandle: HANDLE, dwMode: DWORD) -> BOOL --- SetConsoleCursorPosition :: proc(hConsoleHandle: HANDLE, - dwCursorPosition: COORD) -> BOOL --- + dwCursorPosition: COORD) -> BOOL --- SetConsoleTextAttribute :: proc(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL --- GetConsoleCP :: proc() -> CODEPAGE --- SetConsoleCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- GetConsoleOutputCP :: proc() -> CODEPAGE --- SetConsoleOutputCP :: proc(wCodePageID: CODEPAGE) -> BOOL --- + FlushConsoleInputBuffer :: proc(hConsoleInput: HANDLE) -> BOOL --- GetFileInformationByHandle :: proc(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) -> BOOL --- + + SetHandleInformation :: proc(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) -> BOOL --- @@ -67,6 +83,7 @@ foreign kernel32 { RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD --- RaiseException :: proc(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! --- + SetUnhandledExceptionFilter :: proc(lpTopLevelExceptionFilter: LPTOP_LEVEL_EXCEPTION_FILTER) -> LPTOP_LEVEL_EXCEPTION_FILTER --- CreateHardLinkW :: proc(lpSymlinkFileName: LPCWSTR, lpTargetFileName: LPCWSTR, @@ -87,6 +104,12 @@ foreign kernel32 { RemoveDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL --- SetFileAttributesW :: proc(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL --- SetLastError :: proc(dwErrCode: DWORD) --- + GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- + SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- + ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL --- + GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- + SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- + GetCommPorts :: proc(lpPortNumbers: PULONG, uPortNumbersCount: ULONG, puPortNumbersFound: PULONG) -> ULONG --- GetCommandLineW :: proc() -> LPCWSTR --- GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- GetCurrentProcess :: proc() -> HANDLE --- @@ -491,6 +514,8 @@ foreign kernel32 { GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL --- RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT --- + + GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL --- } DEBUG_PROCESS :: 0x00000001 @@ -1036,163 +1061,8 @@ foreign kernel32 { HandlerRoutine :: proc "system" (dwCtrlType: DWORD) -> BOOL PHANDLER_ROUTINE :: HandlerRoutine - - - -DCB_Config :: struct { - fParity: bool, - fOutxCtsFlow: bool, - fOutxDsrFlow: bool, - fDtrControl: DTR_Control, - fDsrSensitivity: bool, - fTXContinueOnXoff: bool, - fOutX: bool, - fInX: bool, - fErrorChar: bool, - fNull: bool, - fRtsControl: RTS_Control, - fAbortOnError: bool, - BaudRate: DWORD, - ByteSize: BYTE, - Parity: Parity, - StopBits: Stop_Bits, - XonChar: byte, - XoffChar: byte, - ErrorChar: byte, - EvtChar: byte, -} -DTR_Control :: enum byte { - Disable = 0, - Enable = 1, - Handshake = 2, -} -RTS_Control :: enum byte { - Disable = 0, - Enable = 1, - Handshake = 2, - Toggle = 3, -} -Parity :: enum byte { - None = 0, - Odd = 1, - Even = 2, - Mark = 3, - Space = 4, -} -Stop_Bits :: enum byte { - One = 0, - One_And_A_Half = 1, - Two = 2, -} - -// A helper procedure to set the values of a DCB structure. -init_dcb_with_config :: proc "contextless" (dcb: ^DCB, config: DCB_Config) { - out: u32 - - // NOTE(tetra, 2022-09-21): On both Clang 14 on Windows, and MSVC, the bits in the bitfield - // appear to be defined from LSB to MSB order. - // i.e: `fBinary` (the first bitfield in the C source) is the LSB in the `settings` u32. - - out |= u32(1) << 0 // fBinary must always be true on Windows. - - out |= u32(config.fParity) << 1 - out |= u32(config.fOutxCtsFlow) << 2 - out |= u32(config.fOutxDsrFlow) << 3 - - out |= u32(config.fDtrControl) << 4 - - out |= u32(config.fDsrSensitivity) << 6 - out |= u32(config.fTXContinueOnXoff) << 7 - out |= u32(config.fOutX) << 8 - out |= u32(config.fInX) << 9 - out |= u32(config.fErrorChar) << 10 - out |= u32(config.fNull) << 11 - - out |= u32(config.fRtsControl) << 12 - - out |= u32(config.fAbortOnError) << 14 - - dcb.settings = out - - dcb.BaudRate = config.BaudRate - dcb.ByteSize = config.ByteSize - dcb.Parity = config.Parity - dcb.StopBits = config.StopBits - dcb.XonChar = config.XonChar - dcb.XoffChar = config.XoffChar - dcb.ErrorChar = config.ErrorChar - dcb.EvtChar = config.EvtChar - - dcb.DCBlength = size_of(DCB) -} -get_dcb_config :: proc "contextless" (dcb: DCB) -> (config: DCB_Config) { - config.fParity = bool((dcb.settings >> 1) & 0x01) - config.fOutxCtsFlow = bool((dcb.settings >> 2) & 0x01) - config.fOutxDsrFlow = bool((dcb.settings >> 3) & 0x01) - - config.fDtrControl = DTR_Control((dcb.settings >> 4) & 0x02) - - config.fDsrSensitivity = bool((dcb.settings >> 6) & 0x01) - config.fTXContinueOnXoff = bool((dcb.settings >> 7) & 0x01) - config.fOutX = bool((dcb.settings >> 8) & 0x01) - config.fInX = bool((dcb.settings >> 9) & 0x01) - config.fErrorChar = bool((dcb.settings >> 10) & 0x01) - config.fNull = bool((dcb.settings >> 11) & 0x01) - - config.fRtsControl = RTS_Control((dcb.settings >> 12) & 0x02) - - config.fAbortOnError = bool((dcb.settings >> 14) & 0x01) - - config.BaudRate = dcb.BaudRate - config.ByteSize = dcb.ByteSize - config.Parity = dcb.Parity - config.StopBits = dcb.StopBits - config.XonChar = dcb.XonChar - config.XoffChar = dcb.XoffChar - config.ErrorChar = dcb.ErrorChar - config.EvtChar = dcb.EvtChar - - return -} - -// NOTE(tetra): See get_dcb_config() and init_dcb_with_config() for help with initializing this. -DCB :: struct { - DCBlength: DWORD, // NOTE(tetra): Must be set to size_of(DCB). - BaudRate: DWORD, - settings: u32, // NOTE(tetra): These are bitfields in the C struct. - wReserved: WORD, - XOnLim: WORD, - XOffLim: WORD, - ByteSize: BYTE, - Parity: Parity, - StopBits: Stop_Bits, - XonChar: byte, - XoffChar: byte, - ErrorChar: byte, - EofChar: byte, - EvtChar: byte, - wReserved1: WORD, -} - -@(default_calling_convention="system") -foreign kernel32 { - GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- - SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- -} - -COMMTIMEOUTS :: struct { - ReadIntervalTimeout: DWORD, - ReadTotalTimeoutMultiplier: DWORD, - ReadTotalTimeoutConstant: DWORD, - WriteTotalTimeoutMultiplier: DWORD, - WriteTotalTimeoutConstant: DWORD, -} - -@(default_calling_convention="system") -foreign kernel32 { - GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- - SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL --- -} +// NOTE(Jeroen, 2024-06-13): As Odin now supports bit_fields, we no longer need +// a helper procedure. `init_dcb_with_config` and `get_dcb_config` have been removed. LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID) @@ -1250,6 +1120,30 @@ SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct { DummyUnion: DUMMYUNIONNAME_u, } +SYSTEM_POWER_STATUS :: struct { + ACLineStatus: AC_Line_Status, + BatteryFlag: Battery_Flags, + BatteryLifePercent: BYTE, + SystemStatusFlag: BYTE, + BatteryLifeTime: DWORD, + BatteryFullLifeTime: DWORD, +} + +AC_Line_Status :: enum BYTE { + Offline = 0, + Online = 1, + Unknown = 255, +} + +Battery_Flag :: enum BYTE { + High = 0, + Low = 1, + Critical = 2, + Charging = 3, + No_Battery = 7, +} +Battery_Flags :: bit_set[Battery_Flag; BYTE] + /* Global Memory Flags */ GMEM_FIXED :: 0x0000 GMEM_MOVEABLE :: 0x0002 @@ -1284,3 +1178,5 @@ LOAD_LIBRARY_FLAGS :: enum DWORD { LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000, } + +LPTOP_LEVEL_EXCEPTION_FILTER :: PVECTORED_EXCEPTION_HANDLER diff --git a/core/sys/windows/ole32.odin b/core/sys/windows/ole32.odin index 78b4b7226..8535a6f87 100644 --- a/core/sys/windows/ole32.odin +++ b/core/sys/windows/ole32.odin @@ -7,13 +7,13 @@ foreign import "system:Ole32.lib" /* typedef enum tagCOINIT { - COINIT_APARTMENTTHREADED = 0x2, // Apartment model + COINIT_APARTMENTTHREADED = 0x2, // Apartment model #if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) // DCOM - // These constants are only valid on Windows NT 4.0 - COINIT_MULTITHREADED = COINITBASE_MULTITHREADED, - COINIT_DISABLE_OLE1DDE = 0x4, // Don't use DDE for Ole1 support. - COINIT_SPEED_OVER_MEMORY = 0x8, // Trade memory for speed. + // These constants are only valid on Windows NT 4.0 + COINIT_MULTITHREADED = COINITBASE_MULTITHREADED, + COINIT_DISABLE_OLE1DDE = 0x4, // Don't use DDE for Ole1 support. + COINIT_SPEED_OVER_MEMORY = 0x8, // Trade memory for speed. #endif // DCOM } COINIT; */ @@ -26,9 +26,11 @@ COINIT :: enum DWORD { } IUnknown :: struct { - using Vtbl: ^IUnknownVtbl, + using _iunknown_vtable: ^IUnknown_VTable, } -IUnknownVtbl :: struct { + +IUnknownVtbl :: IUnknown_VTable +IUnknown_VTable :: struct { QueryInterface: proc "system" (This: ^IUnknown, riid: REFIID, ppvObject: ^rawptr) -> HRESULT, AddRef: proc "system" (This: ^IUnknown) -> ULONG, Release: proc "system" (This: ^IUnknown) -> ULONG, diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin index 214a0f501..3d464e847 100644 --- a/core/sys/windows/shell32.odin +++ b/core/sys/windows/shell32.odin @@ -5,7 +5,7 @@ foreign import shell32 "system:Shell32.lib" @(default_calling_convention="system") foreign shell32 { - CommandLineToArgvW :: proc(cmd_list: wstring, num_args: ^c_int) -> ^wstring --- + CommandLineToArgvW :: proc(cmd_list: wstring, num_args: ^c_int) -> [^]wstring --- ShellExecuteW :: proc( hwnd: HWND, lpOperation: LPCWSTR, diff --git a/core/sys/windows/tlhelp.odin b/core/sys/windows/tlhelp.odin new file mode 100644 index 000000000..45d5a3ff9 --- /dev/null +++ b/core/sys/windows/tlhelp.odin @@ -0,0 +1,101 @@ +//+build windows +package sys_windows + +foreign import kernel32 "system:Kernel32.lib" + +@(default_calling_convention="system") +foreign kernel32 { + CreateToolhelp32Snapshot :: proc (dwFlags: DWORD, th32ProcessID: DWORD) -> HANDLE --- + Process32FirstW :: proc (hSnapshot: HANDLE, lppe: LPPROCESSENTRY32W) -> BOOL --- + Process32NextW :: proc (hSnapshot: HANDLE, lppe: LPPROCESSENTRY32W) -> BOOL --- + Thread32First :: proc (hSnapshot: HANDLE, lpte: LPTHREADENTRY32) -> BOOL --- + Thread32Next :: proc (hSnapshot: HANDLE, lpte: LPTHREADENTRY32) -> BOOL --- + Module32FirstW :: proc (hSnapshot: HANDLE, lpme: LPMODULEENTRY32W) -> BOOL --- + Module32NextW :: proc (hSnapshot: HANDLE, lpme: LPMODULEENTRY32W) -> BOOL --- + Heap32ListFirst :: proc (hSnapshot: HANDLE, lphl: LPHEAPLIST32) -> BOOL --- + Heap32ListNext :: proc (hSnapshot: HANDLE, lphl: LPHEAPLIST32) -> BOOL --- + Heap32First :: proc (lphe: LPHEAPENTRY32, th32ProcessID: DWORD, th32HeapID: ULONG_PTR) -> BOOL --- + Heap32Next :: proc (lphe: LPHEAPENTRY32) -> BOOL --- + Toolhelp32ReadProcessMemory :: proc ( + th32ProcessID: DWORD, + lpBaseAddress: LPCVOID, + lpBuffer: LPVOID, + cbRead: SIZE_T, + lpNumberOfBytesRead: ^SIZE_T, + ) -> BOOL --- +} + +MAX_MODULE_NAME32 :: 255 + +TH32CS_INHERIT :: 0x80000000 +TH32CS_SNAPHEAPLIST :: 0x00000001 +TH32CS_SNAPPROCESS :: 0x00000002 +TH32CS_SNAPTHREAD :: 0x00000004 +TH32CS_SNAPMODULE :: 0x00000008 +TH32CS_SNAPMODULE32 :: 0x00000010 +TH32CS_SNAPALL :: TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE + +PROCESSENTRY32W :: struct { + dwSize: DWORD, + cntUsage: DWORD, + th32ProcessID: DWORD, + th32DefaultHeapID: ULONG_PTR, + th32ModuleID: DWORD, + cntThreads: DWORD, + th32ParentProcessID: DWORD, + pcPriClassBase: LONG, + dwFlags: DWORD, + szExeFile: [MAX_PATH]WCHAR, +} + +LPPROCESSENTRY32W :: ^PROCESSENTRY32W + +THREADENTRY32 :: struct { + dwSize: DWORD, + cntUsage: DWORD, + th32ThreadID: DWORD, + th32OwnerProcessID: DWORD, + tpBasePri: LONG, + tpDeltaPri: LONG, + dwFlags: DWORD, +} + +LPTHREADENTRY32 :: ^THREADENTRY32 + +MODULEENTRY32W :: struct { + dwSize: DWORD, + th32ModuleID: DWORD, + th32ProcessID: DWORD, + GlblcntUsage: DWORD, + ProccntUsage: DWORD, + modBaseAddr: ^BYTE, + modBaseSize: DWORD, + hModule: HMODULE, + szModule: [MAX_MODULE_NAME32 + 1]WCHAR, + szExePath: [MAX_PATH]WCHAR, +} + +LPMODULEENTRY32W :: ^MODULEENTRY32W + +HEAPLIST32 :: struct { + dwSize: SIZE_T, + th32ProcessID: DWORD, + th32HeapID: ULONG_PTR, + dwFlags: DWORD, +} + +LPHEAPLIST32 :: ^HEAPLIST32 + +HEAPENTRY32 :: struct { + dwSize: SIZE_T, + hHandle: HANDLE, + dwAddress: ULONG_PTR, + dwBlockSize: SIZE_T, + dwFlags: DWORD, + dwLockCount: DWORD, + dwResvd: DWORD, + th32ProcessID: DWORD, + th32HeapID: ULONG_PTR, +} + +LPHEAPENTRY32 :: ^HEAPENTRY32 diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 35fc68abf..3f207a45b 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -36,6 +36,7 @@ HBITMAP :: distinct HANDLE HPALETTE :: distinct HANDLE HGLOBAL :: distinct HANDLE HHOOK :: distinct HANDLE +HWINEVENTHOOK :: distinct HANDLE HKEY :: distinct HANDLE HDESK :: distinct HANDLE HFONT :: distinct HANDLE @@ -797,6 +798,14 @@ WNDPROC :: #type proc "system" (HWND, UINT, WPARAM, LPARAM) -> LRESULT HOOKPROC :: #type proc "system" (code: c_int, wParam: WPARAM, lParam: LPARAM) -> LRESULT +WINEVENTPROC :: #type proc "system" ( + hWinEventHook: HWINEVENTHOOK, + event: DWORD, + hwnd: HWND, + idObject, idChild: LONG, + idEventThread, dwmsEventTime: DWORD, +) + CWPRETSTRUCT :: struct { lResult: LRESULT, lParam: LPARAM, @@ -2779,6 +2788,22 @@ OSVERSIONINFOEXW :: struct { wReserved: UCHAR, } +LoadLibraryEx_Flag :: enum DWORD { + LOAD_LIBRARY_AS_DATAFILE = 1, // 1 << 1: 0x0002, + LOAD_WITH_ALTERED_SEARCH_PATH = 3, // 1 << 3: 0x0008, + LOAD_IGNORE_CODE_AUTHZ_LEVEL = 4, // 1 << 4: 0x0010, + LOAD_LIBRARY_AS_IMAGE_RESOURCE = 5, // 1 << 5: 0x0020, + LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 6, // 1 << 6: 0x0040, + LOAD_LIBRARY_REQUIRE_SIGNED_TARGET = 7, // 1 << 7: 0x0080, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 8, // 1 << 8: 0x0100, + LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 9, // 1 << 9: 0x0200, + LOAD_LIBRARY_SEARCH_USER_DIRS = 10, // 1 << 10: 0x0400, + LOAD_LIBRARY_SEARCH_SYSTEM32 = 11, // 1 << 11: 0x0800, + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 12, // 1 << 12: 0x1000, + LOAD_LIBRARY_SAFE_CURRENT_DIRS = 13, // 1 << 13: 0x2000, +} +LoadLibraryEx_Flags :: distinct bit_set[LoadLibraryEx_Flag] + // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-quota_limits // Used in LogonUserExW PQUOTA_LIMITS :: struct { @@ -4088,6 +4113,70 @@ CONSOLE_CURSOR_INFO :: struct { PCONSOLE_SCREEN_BUFFER_INFO :: ^CONSOLE_SCREEN_BUFFER_INFO PCONSOLE_CURSOR_INFO :: ^CONSOLE_CURSOR_INFO +Event_Type :: enum WORD { + KEY_EVENT = 0x0001, + MOUSE_EVENT = 0x0002, + WINDOW_BUFFER_SIZE_EVENT = 0x0004, + MENU_EVENT = 0x0008, + FOCUS_EVENT = 0x0010, +} + +INPUT_RECORD :: struct { + EventType: Event_Type, + Event: struct #raw_union { + KeyEvent: KEY_EVENT_RECORD, + MouseEvent: MOUSE_EVENT_RECORD, + WindowBufferSizeEvent: WINDOW_BUFFER_SIZE_RECORD, + MenuEvent: MENU_EVENT_RECORD, + FocusEvent: FOCUS_EVENT_RECORD, + }, +} + +Control_Key_State_Bits :: enum { + RIGHT_ALT_PRESSED, + LEFT_ALT_PRESSED, + RIGHT_CTRL_PRESSED, + LEFT_CTRL_PRESSED, + SHIFT_PRESSED, + NUMLOCK_ON, + SCROLLLOCK_ON, + CAPSLOCK_ON, + ENHANCED_KEY, +} +Control_Key_State :: bit_set[Control_Key_State_Bits; DWORD] + +KEY_EVENT_RECORD :: struct { + bKeyDown: BOOL, + wRepeatCount: WORD, + wVirtualKeyCode: WORD, + wVirtualScanCode: WORD, + uChar: struct #raw_union { + UnicodeChar: WCHAR, + AsciiChar: CHAR, + }, + dwControlKeyState: Control_Key_State, +} + +MOUSE_EVENT_RECORD :: struct { + dwMousePosition: COORD, + dwButtonState: DWORD, + dwControlKeyState: DWORD, + dwEventFlags: DWORD, +} + +WINDOW_BUFFER_SIZE_RECORD :: struct { + dwSize: COORD, +} + +MENU_EVENT_RECORD :: struct { + dwCommandId: UINT, +} + +FOCUS_EVENT_RECORD :: struct { + bSetFocus: BOOL, +} + + // // Networking // @@ -4326,3 +4415,92 @@ SOCKADDR :: struct { ENUMRESNAMEPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lpName: LPWSTR, lParam: LONG_PTR)-> BOOL ENUMRESTYPEPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lParam: LONG_PTR)-> BOOL ENUMRESLANGPROCW :: #type proc (hModule: HMODULE, lpType: LPCWSTR, lpName: LPWSTR, wIDLanguage: LANGID, lParam: LONG_PTR)-> BOOL + +DTR_Control :: enum byte { + Disable = 0, + Enable = 1, + Handshake = 2, +} +RTS_Control :: enum byte { + Disable = 0, + Enable = 1, + Handshake = 2, + Toggle = 3, +} +Parity :: enum byte { + None = 0, + Odd = 1, + Even = 2, + Mark = 3, + Space = 4, +} +Stop_Bits :: enum byte { + One = 0, + One_And_A_Half = 1, + Two = 2, +} + +DCB :: struct { + DCBlength: DWORD, + BaudRate: DWORD, + using _: bit_field DWORD { + fBinary: bool | 1, + fParity: bool | 1, + fOutxCtsFlow: bool | 1, + fOutxDsrFlow: bool | 1, + fDtrControl: DTR_Control | 2, + fDsrSensitivity: bool | 1, + fTXContinueOnXoff: bool | 1, + fOutX: bool | 1, + fInX: bool | 1, + fErrorChar: bool | 1, + fNull: bool | 1, + fRtsControl: RTS_Control | 2, + fAbortOnError: bool | 1, + }, + wReserved: WORD, + XOnLim: WORD, + XOffLim: WORD, + ByteSize: BYTE, + Parity: Parity, + StopBits: Stop_Bits, + XonChar: byte, + XoffChar: byte, + ErrorChar: byte, + EofChar: byte, + EvtChar: byte, + wReserved1: WORD, +} + +COMMTIMEOUTS :: struct { + ReadIntervalTimeout: DWORD, + ReadTotalTimeoutMultiplier: DWORD, + ReadTotalTimeoutConstant: DWORD, + WriteTotalTimeoutMultiplier: DWORD, + WriteTotalTimeoutConstant: DWORD, +} + +Com_Stat_Bits :: enum { + fCtsHold, + fDsrHold, + fRlsdHold, + fXoffHold, + fXoffSent, + fEof, + fTxim, +} +COMSTAT :: struct { + bits: bit_set[Com_Stat_Bits; DWORD], + cbInQue: DWORD, + cbOutQue: DWORD, +} + +Com_Error_Bits :: enum { + RXOVER, + OVERRUN, + RXPARITY, + FRAME, + BREAK, +} +Com_Error :: bit_set[Com_Error_Bits; DWORD] + diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 1463b3906..0ad479dd8 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -17,6 +17,17 @@ foreign user32 { GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: INT) -> INT --- + GetParent :: proc(hWnd: HWND) -> HWND --- + SetWinEventHook :: proc( + eventMin, eventMax: DWORD, + hmodWinEventProc: HMODULE, + pfnWinEvenProc: WINEVENTPROC, + idProcess, idThread: DWORD, + dwFlags: WinEventFlags, + ) -> HWINEVENTHOOK --- + + IsChild :: proc(hWndParent, hWnd: HWND) -> BOOL --- + RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL --- @@ -703,3 +714,12 @@ DISPLAY_DEVICEW :: struct { DeviceKey: [128]WCHAR, } PDISPLAY_DEVICEW :: ^DISPLAY_DEVICEW + +// OUTOFCONTEXT is the zero value, use {} +WinEventFlags :: bit_set[WinEventFlag; DWORD] + +WinEventFlag :: enum DWORD { + SKIPOWNTHREAD = 0, + SKIPOWNPROCESS = 1, + INCONTEXT = 2, +} diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index 3b76de1da..428a37498 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -110,8 +110,8 @@ utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 { return text[:n] } utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> wstring { - if res := utf8_to_utf16(s, allocator); res != nil { - return &res[0] + if res := utf8_to_utf16(s, allocator); len(res) > 0 { + return raw_data(res) } return nil } diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin index f99a90d4f..8882dad71 100644 --- a/core/sys/windows/winerror.odin +++ b/core/sys/windows/winerror.odin @@ -248,7 +248,7 @@ SEVERITY :: enum DWORD { } // Generic test for success on any status value (non-negative numbers indicate success). -SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= S_OK } +SUCCEEDED :: #force_inline proc "contextless" (#any_int result: int) -> bool { return result >= S_OK } // and the inverse FAILED :: #force_inline proc(#any_int result: int) -> bool { return result < S_OK } diff --git a/core/sys/windows/wow64_apiset.odin b/core/sys/windows/wow64_apiset.odin new file mode 100644 index 000000000..28558e9ca --- /dev/null +++ b/core/sys/windows/wow64_apiset.odin @@ -0,0 +1,85 @@ +//+build windows +package sys_windows + +foreign import kernel32 "system:Kernel32.lib" + +@(default_calling_convention="system") +foreign kernel32 { + GetSystemWow64Directory2W :: proc (lpBuffer: LPWSTR, uSize: UINT, ImageFileMachineTyp: WORD) -> UINT --- + GetSystemWow64DirectoryW :: proc (lpBuffer: LPWSTR, uSize: UINT) -> UINT --- + IsWow64GuestMachineSupported :: proc (WowGuestMachine: USHORT, MachineIsSupported: ^BOOL) -> HRESULT --- + IsWow64Process :: proc (hProcess: HANDLE, Wow64Process: PBOOL) -> BOOL --- + IsWow64Process2 :: proc (hProcess: HANDLE, pProcessMachine: ^USHORT, pNativeMachine: ^USHORT) -> BOOL --- + Wow64EnableWow64FsRedirection :: proc (Wow64FsEnableRedirection: BOOLEAN) -> BOOLEAN --- + Wow64DisableWow64FsRedirection :: proc (OldValue: ^PVOID) -> BOOL --- + Wow64RevertWow64FsRedirection :: proc (OlValue: PVOID) -> BOOL --- + Wow64GetThreadContext :: proc (hThread: HANDLE, lpContext: PWOW64_CONTEXT) -> BOOL --- + Wow64SetThreadContext :: proc(hThread: HANDLE, lpContext: ^WOW64_CONTEXT) -> BOOL --- + Wow64SetThreadDefaultGuestMachine :: proc(Machine: USHORT) -> USHORT --- + Wow64SuspendThread :: proc (hThread: HANDLE) -> DWORD --- +} + +WOW64_CONTEXT_i386 :: 0x00010000 + +WOW64_CONTEXT_CONTROL :: (WOW64_CONTEXT_i386 | 0x00000001) +WOW64_CONTEXT_INTEGER :: (WOW64_CONTEXT_i386 | 0x00000002) +WOW64_CONTEXT_SEGMENTS :: (WOW64_CONTEXT_i386 | 0x00000004) + +WOW64_CONTEXT_FLOATING_POINT :: (WOW64_CONTEXT_i386 | 0x00000008) +WOW64_CONTEXT_DEBUG_REGISTERS :: (WOW64_CONTEXT_i386 | 0x00000010) +WOW64_CONTEXT_EXTENDED_REGISTERS :: (WOW64_CONTEXT_i386 | 0x00000020) +WOW64_CONTEXT_FULL :: (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS) +WOW64_CONTEXT_ALL :: ( + WOW64_CONTEXT_CONTROL | + WOW64_CONTEXT_INTEGER | + WOW64_CONTEXT_SEGMENTS | + WOW64_CONTEXT_FLOATING_POINT | + WOW64_CONTEXT_DEBUG_REGISTERS | + WOW64_CONTEXT_EXTENDED_REGISTERS) + +WOW64_SIZE_OF_80387_REGISTERS :: 80 +WOW64_MAXIMUM_SUPPORTED_EXTENSION :: 512 + +WOW64_CONTEXT :: struct { + ContextFlags: DWORD, + Dr0: DWORD, + Dr1: DWORD, + Dr2: DWORD, + Dr3: DWORD, + Dr6: DWORD, + Dr7: DWORD, + FloatSave: WOW64_FLOATING_SAVE_AREA, + SegGs: DWORD, + SegFs: DWORD, + SegEs: DWORD, + SegDs: DWORD, + Edi: DWORD, + Esi: DWORD, + Ebx: DWORD, + Edx: DWORD, + Ecx: DWORD, + Eax: DWORD, + Ebp: DWORD, + Eip: DWORD, + SegCs: DWORD, + EFlags: DWORD, + Esp: DWORD, + SegSs: DWORD, + ExtendedRegisters: [WOW64_MAXIMUM_SUPPORTED_EXTENSION]BYTE, +} + +PWOW64_CONTEXT :: ^WOW64_CONTEXT + +WOW64_FLOATING_SAVE_AREA :: struct { + ControlWord: DWORD, + StatusWord: DWORD, + TagWord: DWORD, + ErrorOffset: DWORD, + ErrorSelector: DWORD, + DataOffset: DWORD, + DataSelector: DWORD, + RegisterArea: [WOW64_SIZE_OF_80387_REGISTERS]BYTE, + Cr0NpxState: DWORD, +} + +PWOW64_FLOATING_SAVE_AREA :: ^WOW64_FLOATING_SAVE_AREA \ No newline at end of file diff --git a/core/testing/logging.odin b/core/testing/logging.odin index 5bbbffeae..f1e75d33c 100644 --- a/core/testing/logging.odin +++ b/core/testing/logging.odin @@ -8,13 +8,22 @@ import "core:strings" import "core:sync/chan" import "core:time" -Default_Test_Logger_Opts :: runtime.Logger_Options { - .Level, - .Terminal_Color, - .Short_File_Path, - .Line, - .Procedure, - .Date, .Time, +when USING_SHORT_LOGS { + Default_Test_Logger_Opts :: runtime.Logger_Options { + .Level, + .Terminal_Color, + .Short_File_Path, + .Line, + } +} else { + Default_Test_Logger_Opts :: runtime.Logger_Options { + .Level, + .Terminal_Color, + .Short_File_Path, + .Line, + .Procedure, + .Date, .Time, + } } Log_Message :: struct { diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 328186c35..fa7c2ffd2 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -9,6 +9,7 @@ import "core:encoding/ansi" import "core:fmt" import "core:io" @require import pkg_log "core:log" +import "core:math/rand" import "core:mem" import "core:os" import "core:slice" @@ -41,6 +42,8 @@ PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) // Set the lowest log level for this test run. LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, "info") +// Show only the most necessary logging information. +USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false) get_log_level :: #force_inline proc() -> runtime.Logger_Level { @@ -48,12 +51,11 @@ get_log_level :: #force_inline proc() -> runtime.Logger_Level { // Always use .Debug in `-debug` mode. return .Debug } else { - when LOG_LEVEL == "debug" { return .Debug } - else when LOG_LEVEL == "info" { return .Info } - else when LOG_LEVEL == "warning" { return .Warning } - else when LOG_LEVEL == "error" { return .Error } - else when LOG_LEVEL == "fatal" { return .Fatal } - else { + when LOG_LEVEL == "debug" { return .Debug } else + when LOG_LEVEL == "info" { return .Info } else + when LOG_LEVEL == "warning" { return .Warning } else + when LOG_LEVEL == "error" { return .Error } else + when LOG_LEVEL == "fatal" { return .Fatal } else { #panic("Unknown `ODIN_TEST_LOG_LEVEL`: \"" + LOG_LEVEL + "\", possible levels are: \"debug\", \"info\", \"warning\", \"error\", or \"fatal\".") } } @@ -104,6 +106,13 @@ run_test_task :: proc(task: thread.Task) { options = Default_Test_Logger_Opts, } + random_generator_state: runtime.Default_Random_State + context.random_generator = { + procedure = runtime.default_random_generator_proc, + data = &random_generator_state, + } + rand.reset(data.t.seed) + free_all(context.temp_allocator) data.it.p(&data.t) @@ -188,8 +197,11 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } } + // `-vet` needs parameters to be shadowed by themselves first as an + // explicit declaration, to allow the next line to work. + internal_tests := internal_tests // Intentional shadow with user-specified tests. - internal_tests := select_internal_tests[:] + internal_tests = select_internal_tests[:] } total_failure_count := 0 @@ -497,6 +509,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { data.it = it data.t.seed = shared_random_seed data.t.error_count = 0 + data.t._fail_now_called = false thread.pool_add_task(&pool, task.allocator, run_test_task, data, run_index) } @@ -604,10 +617,10 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { }) fmt.assertf(alloc_error == nil, "Error appending to log messages: %v", alloc_error) - find_task_data: for &data in task_data_slots { + find_task_data_for_timeout: for &data in task_data_slots { if data.it.pkg == it.pkg && data.it.name == it.name { end_t(&data.t) - break find_task_data + break find_task_data_for_timeout } } } @@ -645,21 +658,36 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { "A signal (%v) was raised to stop test #%i %s.%s, but it was unable to be found.", reason, test_index, it.pkg, it.name) - if test_index not_in failed_test_reason_map { - // We only write a new error message here if there wasn't one - // already, because the message we can provide based only on - // the signal won't be very useful, whereas asserts and panics - // will provide a user-written error message. - failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator) - pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason) - + // The order this is handled in is a little particular. + task_data: ^Task_Data + find_task_data_for_stop_signal: for &data in task_data_slots { + if data.it.pkg == it.pkg && data.it.name == it.name { + task_data = &data + break find_task_data_for_stop_signal + } } - when FANCY_OUTPUT { - bypass_progress_overwrite = true - signals_were_raised = true + fmt.assertf(task_data != nil, "A signal (%v) was raised to stop test #%i %s.%s, but its task data is missing.", + reason, test_index, it.pkg, it.name) + + if !task_data.t._fail_now_called { + if test_index not_in failed_test_reason_map { + // We only write a new error message here if there wasn't one + // already, because the message we can provide based only on + // the signal won't be very useful, whereas asserts and panics + // will provide a user-written error message. + failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator) + pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason) + } + + when FANCY_OUTPUT { + bypass_progress_overwrite = true + signals_were_raised = true + } } + end_t(&task_data.t) + total_failure_count += 1 total_done_count += 1 } diff --git a/core/testing/signal_handler.odin b/core/testing/signal_handler.odin index 891f6bbb6..0b06852ce 100644 --- a/core/testing/signal_handler.odin +++ b/core/testing/signal_handler.odin @@ -9,6 +9,7 @@ Stop_Reason :: enum { Illegal_Instruction, Arithmetic_Error, Segmentation_Fault, + Unhandled_Trap, } test_assertion_failure_proc :: proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index 0ab34776e..d89d84fae 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -19,6 +19,11 @@ import "core:os" @(private="file", thread_local) local_test_index: libc.sig_atomic_t +// Windows does not appear to have a SIGTRAP, so this is defined here, instead +// of in the libc package, just so there's no confusion about it being +// available there. +SIGTRAP :: 5 + @(private="file") stop_runner_callback :: proc "c" (sig: libc.int) { prev := intrinsics.atomic_add(&stop_runner_flag, 1) @@ -110,6 +115,10 @@ _setup_signal_handler :: proc() { // For tests: // Catch asserts and panics. libc.signal(libc.SIGILL, stop_test_callback) + when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Haiku || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Darwin { + // Catch panics on Darwin and unhandled calls to `debug_trap`. + libc.signal(SIGTRAP, stop_test_callback) + } // Catch arithmetic errors. libc.signal(libc.SIGFPE, stop_test_callback) // Catch segmentation faults (illegal memory access). @@ -141,6 +150,7 @@ _should_stop_test :: proc() -> (test_index: int, reason: Stop_Reason, ok: bool) case libc.SIGFPE: reason = .Arithmetic_Error case libc.SIGILL: reason = .Illegal_Instruction case libc.SIGSEGV: reason = .Segmentation_Fault + case SIGTRAP: reason = .Unhandled_Trap } ok = true } diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 92b4d391d..29fe853ef 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -48,7 +48,7 @@ T :: struct { // tests during channel transmission. _log_allocator: runtime.Allocator, - _fail_now: proc() -> !, + _fail_now_called: bool, } @@ -66,15 +66,20 @@ fail :: proc(t: ^T, loc := #caller_location) { pkg_log.error("FAIL", location=loc) } -fail_now :: proc(t: ^T, msg := "", loc := #caller_location) { +// fail_now will cause a test to immediately fail and abort, much in the same +// way a failed assertion or panic call will stop a thread. +// +// It is for when you absolutely need a test to fail without calling any of its +// deferred statements. It will be cleaner than a regular assert or panic, +// as the test runner will know to expect the signal this procedure will raise. +fail_now :: proc(t: ^T, msg := "", loc := #caller_location) -> ! { + t._fail_now_called = true if msg != "" { pkg_log.error("FAIL:", msg, location=loc) } else { pkg_log.error("FAIL", location=loc) } - if t._fail_now != nil { - t._fail_now() - } + runtime.trap() } failed :: proc(t: ^T) -> bool { @@ -94,7 +99,17 @@ logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { // cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete. // Cleanup procedures will be called in LIFO (last added, first called) order. -// Each procedure will use a copy of the context at the time of registering. +// +// Each procedure will use a copy of the context at the time of registering, +// and if the test failed due to a timeout, failed assertion, panic, bounds-checking error, +// memory access violation, or any other signal-based fault, this procedure will +// run with greater privilege in the test runner's main thread. +// +// That means that any cleanup procedure absolutely must not fail in the same way, +// or it will take down the entire test runner with it. This is for when you +// need something to run no matter what, if a test failed. +// +// For almost every usual case, `defer` should be preferable and sufficient. cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) { append(&t.cleanups, Internal_Cleanup{procedure, user_data, context}) } diff --git a/core/text/i18n/doc.odin b/core/text/i18n/doc.odin index 54bf8b80f..d590fd123 100644 --- a/core/text/i18n/doc.odin +++ b/core/text/i18n/doc.odin @@ -1,31 +1,44 @@ /* -The `i18n` package is flexible and easy to use. +The `i18n` package is a flexible and easy to use way to localise applications. -It has one call to get a translation: `get`, which the user can alias into something like `T`. +It has two calls to get a translation: `get()` and `get_n()`, which the user can alias into something like `T` and `Tn` +with statements like: + T :: i18n.get + Tn :: i18n.get_n. -`get`, referred to as `T` here, has a few different signatures. -All of them will return the key if the entry can't be found in the active translation catalog. +`get()` is used for retrieving the translation of sentences which **never** change in form, +like for instance "Connection established" or "All temporary files have been deleted". +Note that the number (singular, dual, plural, whatever else) is not relevant: the sentence is fixed and it will have only one possible translation in any other language. -- `T(key)` returns the translation of `key`. -- `T(key, n)` returns a pluralized translation of `key` according to value `n`. +`get_n()` is used for retrieving the translations of sentences which change according to the number of items referenced. +The various signatures of `get_n()` have one more parameter, `n`, which will receive that number and be used +to select the correct form according to the pluralizer attached to the message catalogue when initially loaded; +for instance, to summarise a rather complex matter, some languages use the singular form when referring to 0 items and some use the (only in their case) plural forms; +also, languages may have more or less quantifier forms than a single singular form and a universal plural form: +for instance, Chinese has just one form for any quantity, while Welsh may have up to 6 different forms for specific different quantities. -- `T(section, key)` returns the translation of `key` in `section`. -- `T(section, key, n)` returns a pluralized translation of `key` in `section` according to value `n`. +Both `get()` and `get_n()`, referred to as `T` and `Tn` here, have several different signatures. +All of them will return the key if the entry can't be found in the active translation catalogue. +By default lookup take place in the global `i18n.ACTIVE` catalogue for ease of use, unless a specific catalogue is supplied. -By default lookup take place in the global `i18n.ACTIVE` catalog for ease of use. -If you want to override which translation to use, for example in a language preview dialog, you can use the following: +- `T(key)` returns the translation of `key`. +- `T(key, catalog)` returns the translation of `key` from explictly supplied catalogue. +- `T(section, key)` returns the translation of `key` in `section`. +- `T(section, key, catalog)` returns the translation of `key` in `section` from explictly supplied catalogue. -- `T(key, n, catalog)` returns the pluralized version of `key` from explictly supplied catalog. -- `T(section, key, n, catalog)` returns the pluralized version of `key` in `section` from explictly supplied catalog. +- `Tn(key, n)` returns the translation of `key` according to number of items `n`. +- `Tn(key, n, catalog)` returns the translation of `key` from explictly supplied catalogue. +- `Tn(section, key, n)` returns the translation of `key` in `section` according to number of items `n`. +- `Tn(section, key, n, catalog)` returns the translation of `key` in `section` according to number of items `n` from explictly supplied catalogue. If a catalog has translation contexts or sections, then omitting it in the above calls looks up in section "". -The default pluralization rule is n != 1, which is to say that passing n == 1 (or not passing n) returns the singular form. -Passing n != 1 returns plural form 1. +The default pluralization rule is `n != 1`, which is to say that passing `n == 1` returns the singular form (in slot 0). +Passing `n != 1` returns the plural form in slot 1 (if any). Should a language not conform to this rule, you can pass a pluralizer procedure to the catalog parser. -This is a procedure that maps an integer to an integer, taking a value and returning which plural slot should be used. +This is a procedure that maps an integer to an integer, taking a quantity and returning which plural slot should be used. You can also assign it to a loaded catalog after parsing, of course. @@ -34,24 +47,21 @@ Example: import "core:fmt" import "core:text/i18n" - T :: i18n.get + T :: i18n.get + Tn :: i18n.get_n mo :: proc() { using fmt err: i18n.Error - /* - Parse MO file and set it as the active translation so we can omit `get`'s "catalog" parameter. - */ + // Parse MO file and set it as the active translation so we can omit `get`'s "catalog" parameter. i18n.ACTIVE, err = i18n.parse_mo(#load("translations/nl_NL.mo")) defer i18n.destroy() if err != .None { return } - /* - These are in the .MO catalog. - */ + // These are in the .MO catalog. println("-----") println(T("")) println("-----") @@ -60,13 +70,11 @@ Example: println(T("Hellope, World!")) println("-----") // We pass 1 into `T` to get the singular format string, then 1 again into printf. - printf(T("There is %d leaf.\n", 1), 1) + printf(Tn("There is %d leaf.\n", 1), 1) // We pass 42 into `T` to get the plural format string, then 42 again into printf. - printf(T("There is %d leaf.\n", 42), 42) + printf(Tn("There is %d leaf.\n", 42), 42) - /* - This isn't in the translation catalog, so the key is passed back untranslated. - */ + // This isn't in the translation catalog, so the key is passed back untranslated. println("-----") println(T("Come visit us on Discord!")) } @@ -76,19 +84,13 @@ Example: err: i18n.Error - /* - Parse QT file and set it as the active translation so we can omit `get`'s "catalog" parameter. - */ + // Parse QT file and set it as the active translation so we can omit `get`'s "catalog" parameter. i18n.ACTIVE, err = i18n.parse_qt(#load("translations/nl_NL-qt-ts.ts")) defer i18n.destroy() - if err != .None { - return - } + if err != .None { return } - /* - These are in the .TS catalog. As you can see they have sections. - */ + // These are in the .TS catalog. As you can see they have sections. println("--- Page section ---") println("Page:Text for translation =", T("Page", "Text for translation")) println("-----") @@ -99,8 +101,8 @@ Example: println("-----") println("--- apple_count section ---") println("apple_count:%d apple(s) =") - println("\t 1 =", T("apple_count", "%d apple(s)", 1)) - println("\t 42 =", T("apple_count", "%d apple(s)", 42)) + println("\t 1 =", Tn("apple_count", "%d apple(s)", 1)) + println("\t 42 =", Tn("apple_count", "%d apple(s)", 42)) } */ package i18n diff --git a/core/text/i18n/i18n.odin b/core/text/i18n/i18n.odin index 64593c4e8..0190ef0f7 100644 --- a/core/text/i18n/i18n.odin +++ b/core/text/i18n/i18n.odin @@ -10,23 +10,13 @@ package i18n */ import "core:strings" -/* - TODO: - - Support for more translation catalog file formats. -*/ - -/* - Currently active catalog. -*/ +// Currently active catalog. ACTIVE: ^Translation // Allow between 1 and 255 plural forms. Default: 10. MAX_PLURALS :: min(max(#config(ODIN_i18N_MAX_PLURAL_FORMS, 10), 1), 255) -/* - The main data structure. This can be generated from various different file formats, as long as we have a parser for them. -*/ - +// The main data structure. This can be generated from various different file formats, as long as we have a parser for them. Section :: map[string][]string Translation :: struct { @@ -37,34 +27,24 @@ Translation :: struct { } Error :: enum { - /* - General return values. - */ + // General return values. None = 0, Empty_Translation_Catalog, Duplicate_Key, - /* - Couldn't find, open or read file. - */ + // Couldn't find, open or read file. File_Error, - /* - File too short. - */ + // File too short. Premature_EOF, - /* - GNU Gettext *.MO file errors. - */ + // GNU Gettext *.MO file errors. MO_File_Invalid_Signature, MO_File_Unsupported_Version, MO_File_Invalid, MO_File_Incorrect_Plural_Count, - /* - Qt Linguist *.TS file errors. - */ + // Qt Linguist *.TS file errors. TS_File_Parse_Error, TS_File_Expected_Context, TS_File_Expected_Context_Name, @@ -85,73 +65,142 @@ DEFAULT_PARSE_OPTIONS :: Parse_Options{ } /* - Several ways to use: - - get(key), which defaults to the singular form and i18n.ACTIVE catalog, or - - get(key, number), which returns the appropriate plural from the active catalog, or - - get(key, number, catalog) to grab text from a specific one. -*/ -get_single_section :: proc(key: string, number := 1, catalog: ^Translation = ACTIVE) -> (value: string) { - /* - A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule. - */ - plural := 1 if number != 1 else 0 + Returns the first translation string for the passed `key`. + It is also aliased with `get()`. - if catalog.pluralize != nil { - plural = catalog.pluralize(number) - } - return get_by_slot(key, plural, catalog) + Two ways to use it: + - get(key), which defaults to the `i18n.ACTIVE` catalogue, or + - get(key, catalog) to grab text from a specific loaded catalogue + + Inputs: + - key: the string to translate + - catalog: the catalogue to use for the translation (defaults to i18n.ACTIVE) + + Returns: the translated string, or the original `key` if no translation was found. +*/ +get_single_section :: proc(key: string, catalog: ^Translation = ACTIVE) -> (value: string) { + return get_by_slot(key, 0, catalog) } /* - Several ways to use: - - get(section, key), which defaults to the singular form and i18n.ACTIVE catalog, or - - get(section, key, number), which returns the appropriate plural from the active catalog, or - - get(section, key, number, catalog) to grab text from a specific one. -*/ -get_by_section :: proc(section, key: string, number := 1, catalog: ^Translation = ACTIVE) -> (value: string) { - /* - A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule. - */ - plural := 1 if number != 1 else 0 + Returns the first translation string for the passed `key` in a specific section or context. + It is also aliases with `get()`. - if catalog.pluralize != nil { - plural = catalog.pluralize(number) - } - return get_by_slot(section, key, plural, catalog) + Two ways to use it: + - get(section, key), which defaults to the `i18n.ACTIVE` catalogue, or + - get(section, key, catalog) to grab text from a specific loaded catalogue + + Inputs: + - section: the catalogue section (sometimes also called 'context') in which to look up the translation + - key: the string to translate + - catalog: the catalogue to use for the translation (defaults to i18n.ACTIVE) + + Returns: the translated string, or the original `key` if no translation was found. +*/ +get_by_section :: proc(section, key: string, catalog: ^Translation = ACTIVE) -> (value: string) { + return get_by_slot(section, key, 0, catalog) } + get :: proc{get_single_section, get_by_section} /* - Several ways to use: - - get_by_slot(key), which defaults to the singular form and i18n.ACTIVE catalog, or - - get_by_slot(key, slot), which returns the requested plural from the active catalog, or - - get_by_slot(key, slot, catalog) to grab text from a specific one. + Returns the translation string for the passed `key` in a specific plural form (if present in the catalogue). + It is also aliased with `get_n()`. + + Two ways to use it: + - get_n(key, quantity), which returns the appropriate plural from the active catalogue, or + - get_n(key, quantity, catalog) to grab text from a specific loaded catalogue + + Inputs: + - key: the string to translate + - quantity: the quantity of item to be used to select the correct plural form + - catalog: the catalogue to use for the translation (defaults to i18n.ACTIVE) + + Returns: the translated string, or the original `key` if no translation was found. +*/ +get_single_section_with_quantity :: proc(key: string, quantity: int, catalog: ^Translation = ACTIVE) -> (value: string) { + /* + A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule. + */ + slot := 1 if quantity != 1 else 0 + + if catalog.pluralize != nil { + slot = catalog.pluralize(quantity) + } + return get_by_slot(key, slot, catalog) +} + +/* + Returns the translation string for the passed `key` in a specific plural form (if present in the catalogue) + in a specific section or context. + It is also aliases with `get_n()`. + + Two ways to use it: + - get(section, key, quantity), which returns the appropriate plural from the active catalogue, or + - get(section, key, quantity, catalog) to grab text from a specific loaded catalogue + + Inputs: + - section: the catalogue section (sometime also called 'context') from which to lookup the translation + - key: the string to translate + - qantity: the quantity of item to be used to select the correct plural form + - catalog: the catalogue to use for the translation (defaults to i18n.ACTIVE) + + Returns: the translated string, or the original `key` if no translation was found +*/ +get_by_section_with_quantity :: proc(section, key: string, quantity: int, catalog: ^Translation = ACTIVE) -> (value: string) { + /* + A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule. + */ + slot := 1 if quantity != 1 else 0 + + if catalog.pluralize != nil { + slot = catalog.pluralize(quantity) + } + return get_by_slot(section, key, slot, catalog) +} +get_n :: proc{get_single_section_with_quantity, get_by_section_with_quantity} + +/* + Two ways to use: + - get_by_slot(key, slot), which returns the requested plural from the active catalogue, or + - get_by_slot(key, slot, catalog) to grab text from a specific loaded catalogue. If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string. + - section: the catalogue section (sometime also called 'context') from which to lookup the translation + + Inputs: + - key: the string to translate. + - slot: the translation slot to choose (slots refer to plural forms specific for each language and their meaning changes from catalogue to catalogue). + - catalog: the catalogue to use for the translation (defaults to i18n.ACTIVE) + + Returns: the translated string, or the original `key` if no translation was found. */ -get_by_slot_single_section :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) { +get_by_slot_single_section :: proc(key: string, slot: int, catalog: ^Translation = ACTIVE) -> (value: string) { return get_by_slot_by_section("", key, slot, catalog) } /* - Several ways to use: - - get_by_slot(key), which defaults to the singular form and i18n.ACTIVE catalog, or + Two ways to use: - get_by_slot(key, slot), which returns the requested plural from the active catalog, or - get_by_slot(key, slot, catalog) to grab text from a specific one. If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string. + + Inputs: + - section: the catalogue section (sometime also called 'context') from which to lookup the translation + - key: the string to translate. + - slot: the translation slot to choose (slots refer to plural forms specific for each language and their meaning changes from catalogue to catalogue). + - catalog: the catalogue to use for the translation (defaults to i18n.ACTIVE) + + Returns: the translated string or the original `key` if no translation was found. */ -get_by_slot_by_section :: proc(section, key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) { +get_by_slot_by_section :: proc(section, key: string, slot: int, catalog: ^Translation = ACTIVE) -> (value: string) { if catalog == nil || section not_in catalog.k_v { - /* - Return the key if the catalog catalog hasn't been initialized yet, or the section is not present. - */ + // Return the key if the catalog catalog hasn't been initialized yet, or the section is not present. return key } - /* - Return the translation from the requested slot if this key is known, else return the key. - */ + // Return the translation from the requested slot if this key is known, else return the key. if translations, ok := catalog.k_v[section][key]; ok { plural := min(max(0, slot), len(catalog.k_v[section][key]) - 1) return translations[plural] @@ -161,7 +210,6 @@ get_by_slot_by_section :: proc(section, key: string, slot := 0, catalog: ^Transl get_by_slot :: proc{get_by_slot_single_section, get_by_slot_by_section} /* - Same for destroy: - destroy(), to clean up the currently active catalog catalog i18n.ACTIVE - destroy(catalog), to clean up a specific catalog. */ diff --git a/core/text/table/doc.odin b/core/text/table/doc.odin index 76886bdea..955ab8d21 100644 --- a/core/text/table/doc.odin +++ b/core/text/table/doc.odin @@ -1,18 +1,27 @@ /* -The package `table` implements ASCII/markdown/HTML/custom rendering of tables. +The package `table` implements plain-text/markdown/HTML/custom rendering of tables. **Custom rendering example:** - tbl := init(&Table{}) - padding(tbl, 0, 1) - row(tbl, "A_LONG_ENUM", "= 54,", "// A comment about A_LONG_ENUM") - row(tbl, "AN_EVEN_LONGER_ENUM", "= 1,", "// A comment about AN_EVEN_LONGER_ENUM") - build(tbl) - for row in 0.. (result: int) { + for r in str { + result += 2 + } + return + } + + table.write_plain_table(stdout, tbl, simple_cjk_width_proc) + +This procedure will output 2 times the number of UTF-8 runes in a string, a +simple heuristic for CJK-only wide text. + +**Unicode Support:** + +This package makes use of the `grapheme_count` procedure from the +`core:unicode/utf8` package. It is a complete, standards-compliant +implementation for counting graphemes and calculating visual width of a Unicode +grapheme cluster in monospace cells. + +Here is a full example of how well-supported Unicode is with this package: + + package main + + import "core:fmt" + import "core:io" + import "core:os" + import "core:text/table" + + scripts :: proc(w: io.Writer) { + t: table.Table + table.init(&t) + table.caption(&t, "Tést Suite") + table.padding(&t, 1, 3) + table.header_of_aligned_values(&t, {{.Left, "Script"}, {.Center, "Sample"}}) + + table.row(&t, "Latin", "At vero eos et accusamus et iusto odio dignissimos ducimus,") + table.row(&t, "Cyrillic", "Ру́сский язы́к — язык восточнославянской группы славянской") + table.row(&t, "Greek", "Η ελληνική γλώσσα ανήκει στην ινδοευρωπαϊκή οικογένεια") + table.row(&t, "Younger Futhark", "ᚴᚢᚱᛘᛦ ᚴᚢᚾᚢᚴᛦ ᚴᛅᚱᚦᛁ ᚴᚢᛒᛚ ᚦᚢᛋᛁ ᛅᚠᛏ ᚦᚢᚱᚢᛁ ᚴᚢᚾᚢ ᛋᛁᚾᛅ ᛏᛅᚾᛘᛅᚱᚴᛅᛦ ᛒᚢᛏ") + table.row(&t, "Chinese hanzi", "官話為汉语的一支,主體分布在中国北部和西南部的大部分地区。") + table.row(&t, "Japanese kana", "いろはにほへとちりぬるをわかよたれそつねならむ") + table.row(&t, "Korean hangul", "한글, 조선글은 한국어의 공식문자로서, 세종이 한국어를") + table.row(&t, "Thai", "ภาษาไทย หรือ ภาษาไทยกลาง เป็นภาษาในกลุ่มภาษาไท ซึ่งเป็นกลุ่มย่อยของตระกูลภาษาขร้า-ไท") + table.row(&t, "Georgian", "ქართული ენა — ქართველურ ენათა ოჯახის ენა. ქართველების მშობლიური ენა,") + table.row(&t, "Armenian", "Իր շուրջ հինգհազարամյա գոյության ընթացքում հայերենը շփվել է տարբեր") + table.row(&t) + table.row_of_aligned_values(&t, {{.Left, "Arabic"}, {.Right, "ٱللُّغَةُ ٱلْعَرَبِيَّة هي أكثر اللغات السامية تحدثًا، وإحدى أكثر"}}) + table.row_of_aligned_values(&t, {{.Left, "Hebrew"}, {.Right, "עִבְרִית היא שפה שמית, ממשפחת השפות האפרו-אסייתיות, הידועה"}}) + table.row(&t) + table.row(&t, "Swedish", "Växjö [ˈvɛkːˌɧøː] är en tätort i södra Smålands inland samt centralort i Växjö kommun") + table.row(&t, "Saxon", "Hwæt! We Gardena in geardagum, þeodcyninga, þrym gefrunon, hu ða æþelingas ellen fremedon.") + table.row(&t) + table.aligned_row_of_values(&t, .Center, "Emoji (Single codepoints)", "\U0001f4ae \U0001F600 \U0001F201 \U0001F21A") + table.row(&t, "Excessive Diacritics", "H̷e̶l̵l̸o̴p̵e̷ ̸w̶o̸r̵l̶d̵!̴") + + table.write_plain_table(w, &t) + fmt.println() + } + + main :: proc() { + stdout := os.stream_from_handle(os.stdout) + + scripts(stdout) + } + +This will print out: + + +----------------------------------------------------------------------------------------------------------------------------+ + | Tést Suite | + +-----------------------------+----------------------------------------------------------------------------------------------+ + | Script | Sample | + +-----------------------------+----------------------------------------------------------------------------------------------+ + | Latin | At vero eos et accusamus et iusto odio dignissimos ducimus, | + | Cyrillic | Ру́сский язы́к — язык восточнославянской группы славянской | + | Greek | Η ελληνική γλώσσα ανήκει στην ινδοευρωπαϊκή οικογένεια | + | Younger Futhark | ᚴᚢᚱᛘᛦ ᚴᚢᚾᚢᚴᛦ ᚴᛅᚱᚦᛁ ᚴᚢᛒᛚ ᚦᚢᛋᛁ ᛅᚠᛏ ᚦᚢᚱᚢᛁ ᚴᚢᚾᚢ ᛋᛁᚾᛅ ᛏᛅᚾᛘᛅᚱᚴᛅᛦ ᛒᚢᛏ | + | Chinese hanzi | 官話為汉语的一支,主體分布在中国北部和西南部的大部分地区。 | + | Japanese kana | いろはにほへとちりぬるをわかよたれそつねならむ | + | Korean hangul | 한글, 조선글은 한국어의 공식문자로서, 세종이 한국어를 | + | Thai | ภาษาไทย หรือ ภาษาไทยกลาง เป็นภาษาในกลุ่มภาษาไท ซึ่งเป็นกลุ่มย่อยของตระกูลภาษาขร้า-ไท | + | Georgian | ქართული ენა — ქართველურ ენათა ოჯახის ენა. ქართველების მშობლიური ენა, | + | Armenian | Իր շուրջ հինգհազարամյա գոյության ընթացքում հայերենը շփվել է տարբեր | + | | | + | Arabic | ٱللُّغَةُ ٱلْعَرَبِيَّة هي أكثر اللغات السامية تحدثًا، وإحدى أكثر | + | Hebrew | עִבְרִית היא שפה שמית, ממשפחת השפות האפרו-אסייתיות, הידועה | + | | | + | Swedish | Växjö [ˈvɛkːˌɧøː] är en tätort i södra Smålands inland samt centralort i Växjö kommun | + | Saxon | Hwæt! We Gardena in geardagum, þeodcyninga, þrym gefrunon, hu ða æþelingas ellen fremedon. | + | | | + | Emoji (Single codepoints) | 💮 😀 🈁 🈚 | + | Excessive Diacritics | H̷e̶l̵l̸o̴p̵e̷ ̸w̶o̸r̵l̶d̵!̴ | + +-----------------------------+----------------------------------------------------------------------------------------------+ + +**Decorated Tables:** + +If you'd prefer to change the borders used by the plain-text table printing, +there is the `write_decorated_table` procedure that allows you to change the +corners and dividers. + +Here is a complete example: + + package main + + import "core:fmt" + import "core:io" + import "core:os" + import "core:text/table" + + box_drawing :: proc(w: io.Writer) { + t: table.Table + table.init(&t) + table.caption(&t, "Box Drawing Example") + table.padding(&t, 2, 2) + table.header_of_aligned_values(&t, {{.Left, "Operating System"}, {.Center, "Year Introduced"}}) + + table.row(&t, "UNIX", "1973") + table.row(&t, "MS-DOS", "1981") + table.row(&t, "Commodore 64 KERNAL", "1982") + table.row(&t, "Mac OS", "1984") + table.row(&t, "Amiga", "1985") + table.row(&t, "Windows 1.0", "1985") + table.row(&t, "Linux", "1991") + table.row(&t, "Windows 3.1", "1992") + + decorations := table.Decorations { + "┌", "┬", "┐", + "├", "┼", "┤", + "└", "┴", "┘", + "│", "─", + } + + table.write_decorated_table(w, &t, decorations) + fmt.println() + } + + main :: proc() { + stdout := os.stream_from_handle(os.stdout) + + box_drawing(stdout) + } + +While the decorations support multi-codepoint Unicode graphemes, do note that +each border character should not be larger than one monospace cell. + */ package text_table diff --git a/core/text/table/table.odin b/core/text/table/table.odin index 5423519d3..27c99b1f1 100644 --- a/core/text/table/table.odin +++ b/core/text/table/table.odin @@ -4,18 +4,22 @@ List of contributors: oskarnp: Initial implementation. + Feoramund: Unicode support. */ package text_table import "core:io" import "core:fmt" +import "core:log" import "core:mem" import "core:mem/virtual" +import "core:unicode/utf8" import "base:runtime" Cell :: struct { text: string, + width: int, alignment: Cell_Alignment, } @@ -25,6 +29,14 @@ Cell_Alignment :: enum { Right, } +Aligned_Value :: struct { + alignment: Cell_Alignment, + value: any, +} + +// Determines the width of a string used in the table for alignment purposes. +Width_Proc :: #type proc(str: string) -> int + Table :: struct { lpad, rpad: int, // Cell padding (left/right) cells: [dynamic]Cell, @@ -34,13 +46,33 @@ Table :: struct { table_allocator: runtime.Allocator, // Used for allocating cells/colw format_allocator: runtime.Allocator, // Used for allocating Cell.text when applicable - dirty: bool, // True if build() needs to be called before rendering - // The following are computed on build() - colw: [dynamic]int, // Width of each column (including padding, excluding borders) + colw: [dynamic]int, // Width of each column (excluding padding and borders) tblw: int, // Width of entire table (including padding, excluding borders) } +Decorations :: struct { + // These are strings, because of multi-codepoint Unicode graphemes. + + // Connecting decorations: + nw, n, ne, + w, x, e, + sw, s, se: string, + + // Straight lines: + vert: string, + horz: string, +} + +ascii_width_proc :: proc(str: string) -> int { + return len(str) +} + +unicode_width_proc :: proc(str: string) -> (width: int) { + _, _, width = #force_inline utf8.grapheme_count(str) + return +} + init :: proc{init_with_allocator, init_with_virtual_arena, init_with_mem_arena} init_with_allocator :: proc(tbl: ^Table, format_allocator := context.temp_allocator, table_allocator := context.allocator) -> ^Table { @@ -65,13 +97,11 @@ destroy :: proc(tbl: ^Table) { caption :: proc(tbl: ^Table, value: string) { tbl.caption = value - tbl.dirty = true } padding :: proc(tbl: ^Table, lpad, rpad: int) { tbl.lpad = lpad tbl.rpad = rpad - tbl.dirty = true } get_cell :: proc(tbl: ^Table, row, col: int, loc := #caller_location) -> ^Cell { @@ -81,43 +111,47 @@ get_cell :: proc(tbl: ^Table, row, col: int, loc := #caller_location) -> ^Cell { return &tbl.cells[row*tbl.nr_cols + col] } -set_cell_value_and_alignment :: proc(tbl: ^Table, row, col: int, value: string, alignment: Cell_Alignment) { - cell := get_cell(tbl, row, col) - cell.text = format(tbl, "%v", value) - cell.alignment = alignment - tbl.dirty = true +@private +to_string :: #force_inline proc(tbl: ^Table, value: any, loc := #caller_location) -> (result: string) { + switch val in value { + case nil: + result = "" + case string: + result = val + case cstring: + result = cast(string)val + case: + result = format(tbl, "%v", val) + if result == "" { + log.error("text/table.format() resulted in empty string (arena out of memory?)", location = loc) + } + } + return } set_cell_value :: proc(tbl: ^Table, row, col: int, value: any, loc := #caller_location) { cell := get_cell(tbl, row, col, loc) - switch val in value { - case nil: - cell.text = "" - case string: - cell.text = string(val) - case cstring: - cell.text = string(val) - case: - cell.text = format(tbl, "%v", val) - if cell.text == "" { - fmt.eprintf("{} text/table: format() resulted in empty string (arena out of memory?)\n", loc) - } - } - tbl.dirty = true + cell.text = to_string(tbl, value, loc) } set_cell_alignment :: proc(tbl: ^Table, row, col: int, alignment: Cell_Alignment, loc := #caller_location) { cell := get_cell(tbl, row, col, loc) cell.alignment = alignment - tbl.dirty = true } -format :: proc(tbl: ^Table, _fmt: string, args: ..any, loc := #caller_location) -> string { +set_cell_value_and_alignment :: proc(tbl: ^Table, row, col: int, value: any, alignment: Cell_Alignment, loc := #caller_location) { + cell := get_cell(tbl, row, col, loc) + cell.text = to_string(tbl, value, loc) + cell.alignment = alignment +} + +format :: proc(tbl: ^Table, _fmt: string, args: ..any) -> string { context.allocator = tbl.format_allocator return fmt.aprintf(_fmt, ..args) } -header :: proc(tbl: ^Table, values: ..any, loc := #caller_location) { +header :: header_of_values +header_of_values :: proc(tbl: ^Table, values: ..any, loc := #caller_location) { if (tbl.has_header_row && tbl.nr_rows != 1) || (!tbl.has_header_row && tbl.nr_rows != 0) { panic("Cannot add headers after rows have been added", loc) } @@ -133,26 +167,108 @@ header :: proc(tbl: ^Table, values: ..any, loc := #caller_location) { set_cell_value(tbl, header_row(tbl), col, val, loc) col += 1 } - - tbl.dirty = true } -row :: proc(tbl: ^Table, values: ..any, loc := #caller_location) { +aligned_header_of_values :: proc(tbl: ^Table, alignment: Cell_Alignment, values: ..any, loc := #caller_location) { + if (tbl.has_header_row && tbl.nr_rows != 1) || (!tbl.has_header_row && tbl.nr_rows != 0) { + panic("Cannot add headers after rows have been added", loc) + } + + if tbl.nr_rows == 0 { + tbl.nr_rows += 1 + tbl.has_header_row = true + } + + col := tbl.nr_cols + tbl.nr_cols += len(values) + for val in values { + set_cell_value_and_alignment(tbl, header_row(tbl), col, val, alignment, loc) + col += 1 + } +} + +header_of_aligned_values :: proc(tbl: ^Table, aligned_values: []Aligned_Value, loc := #caller_location) { + if (tbl.has_header_row && tbl.nr_rows != 1) || (!tbl.has_header_row && tbl.nr_rows != 0) { + panic("Cannot add headers after rows have been added", loc) + } + + if tbl.nr_rows == 0 { + tbl.nr_rows += 1 + tbl.has_header_row = true + } + + col := tbl.nr_cols + tbl.nr_cols += len(aligned_values) + for av in aligned_values { + set_cell_value_and_alignment(tbl, header_row(tbl), col, av.value, av.alignment, loc) + col += 1 + } +} + +row :: row_of_values +row_of_values :: proc(tbl: ^Table, values: ..any, loc := #caller_location) { if tbl.nr_cols == 0 { if len(values) == 0 { - panic("Cannot create row without values unless knowing amount of columns in advance") + panic("Cannot create empty row unless the number of columns is known in advance") } else { tbl.nr_cols = len(values) } } + tbl.nr_rows += 1 + for col in 0.. int { return tbl.nr_rows - 1 } @@ -165,27 +281,24 @@ first_row :: proc(tbl: ^Table) -> int { return header_row(tbl)+1 if tbl.has_header_row else 0 } -build :: proc(tbl: ^Table) { - tbl.dirty = false - +build :: proc(tbl: ^Table, width_proc: Width_Proc) { resize(&tbl.colw, tbl.nr_cols) mem.zero_slice(tbl.colw[:]) for row in 0.. tbl.colw[col] { - tbl.colw[col] = w - } + cell.width = width_proc(cell.text) + tbl.colw[col] = max(tbl.colw[col], cell.width) } } colw_sum := 0 for v in tbl.colw { - colw_sum += v + colw_sum += v + tbl.lpad + tbl.rpad } - tbl.tblw = max(colw_sum, len(tbl.caption) + tbl.lpad + tbl.rpad) + tbl.tblw = max(colw_sum, width_proc(tbl.caption) + tbl.lpad + tbl.rpad) // Resize columns to match total width of table remain := tbl.tblw-colw_sum @@ -198,13 +311,9 @@ build :: proc(tbl: ^Table) { } write_html_table :: proc(w: io.Writer, tbl: ^Table) { - if tbl.dirty { - build(tbl) - } - io.write_string(w, "\n") if tbl.caption != "" { - io.write_string(w, "\n") } @@ -219,45 +328,43 @@ write_html_table :: proc(w: io.Writer, tbl: ^Table) { } if tbl.has_header_row { - io.write_string(w, "\n") - io.write_string(w, " \n") + io.write_string(w, "\t\n") + io.write_string(w, "\t\t\n") for col in 0..") io.write_string(w, cell.text) io.write_string(w, "\n") } - io.write_string(w, " \n") - io.write_string(w, "\n") + io.write_string(w, "\t\t\n") + io.write_string(w, "\t\n") } - io.write_string(w, "\n") + io.write_string(w, "\t\n") for row in 0..\n") + io.write_string(w, "\t\t\n") for col in 0..") io.write_string(w, cell.text) io.write_string(w, "\n") } - io.write_string(w, " \n") + io.write_string(w, "\t\t\n") } - io.write_string(w, " \n") + io.write_string(w, "\t\n") io.write_string(w, "
") + io.write_string(w, "\t") io.write_string(w, tbl.caption) io.write_string(w, "
\n") } -write_ascii_table :: proc(w: io.Writer, tbl: ^Table) { - if tbl.dirty { - build(tbl) - } +write_plain_table :: proc(w: io.Writer, tbl: ^Table, width_proc: Width_Proc = unicode_width_proc) { + build(tbl, width_proc) write_caption_separator :: proc(w: io.Writer, tbl: ^Table) { io.write_byte(w, '+') @@ -271,7 +378,7 @@ write_ascii_table :: proc(w: io.Writer, tbl: ^Table) { if col == 0 { io.write_byte(w, '+') } - write_byte_repeat(w, tbl.colw[col], '-') + write_byte_repeat(w, tbl.colw[col] + tbl.lpad + tbl.rpad, '-') io.write_byte(w, '+') } io.write_byte(w, '\n') @@ -280,8 +387,8 @@ write_ascii_table :: proc(w: io.Writer, tbl: ^Table) { if tbl.caption != "" { write_caption_separator(w, tbl) io.write_byte(w, '|') - write_text_align(w, tbl.tblw - tbl.lpad - tbl.rpad + tbl.nr_cols - 1, - tbl.lpad, tbl.rpad, tbl.caption, .Center) + write_text_align(w, tbl.caption, .Center, + tbl.lpad, tbl.rpad, tbl.tblw + tbl.nr_cols - 1 - width_proc(tbl.caption) - tbl.lpad - tbl.rpad) io.write_byte(w, '|') io.write_byte(w, '\n') } @@ -303,48 +410,123 @@ write_ascii_table :: proc(w: io.Writer, tbl: ^Table) { write_table_separator(w, tbl) } -// Renders table according to GitHub Flavored Markdown (GFM) specification -write_markdown_table :: proc(w: io.Writer, tbl: ^Table) { - // NOTE(oskar): Captions or colspans are not supported by GFM as far as I can tell. - - if tbl.dirty { - build(tbl) +write_decorated_table :: proc(w: io.Writer, tbl: ^Table, decorations: Decorations, width_proc: Width_Proc = unicode_width_proc) { + draw_dividing_row :: proc(w: io.Writer, tbl: ^Table, left, horz, divider, right: string) { + io.write_string(w, left) + for col in 0.. ^Thread { - unimplemented("core:thread procedure not supported on js target") -} - -_start :: proc(t: ^Thread) { - unimplemented("core:thread procedure not supported on js target") -} - -_is_done :: proc(t: ^Thread) -> bool { - unimplemented("core:thread procedure not supported on js target") -} - -_join :: proc(t: ^Thread) { - unimplemented("core:thread procedure not supported on js target") -} - -_join_multiple :: proc(threads: ..^Thread) { - unimplemented("core:thread procedure not supported on js target") -} - -_destroy :: proc(thread: ^Thread) { - unimplemented("core:thread procedure not supported on js target") -} - -_terminate :: proc(using thread : ^Thread, exit_code: int) { - unimplemented("core:thread procedure not supported on js target") -} - -_yield :: proc() { - unimplemented("core:thread procedure not supported on js target") -} - diff --git a/core/thread/thread_other.odin b/core/thread/thread_other.odin new file mode 100644 index 000000000..34bbfda08 --- /dev/null +++ b/core/thread/thread_other.odin @@ -0,0 +1,47 @@ +//+build js, wasi, orca +package thread + +import "base:intrinsics" + +_IS_SUPPORTED :: false + +Thread_Os_Specific :: struct {} + +_thread_priority_map := [Thread_Priority]i32{ + .Normal = 0, + .Low = -2, + .High = +2, +} + +_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread { + unimplemented("core:thread procedure not supported on target") +} + +_start :: proc(t: ^Thread) { + unimplemented("core:thread procedure not supported on target") +} + +_is_done :: proc(t: ^Thread) -> bool { + unimplemented("core:thread procedure not supported on target") +} + +_join :: proc(t: ^Thread) { + unimplemented("core:thread procedure not supported on target") +} + +_join_multiple :: proc(threads: ..^Thread) { + unimplemented("core:thread procedure not supported on target") +} + +_destroy :: proc(thread: ^Thread) { + unimplemented("core:thread procedure not supported on target") +} + +_terminate :: proc(using thread : ^Thread, exit_code: int) { + unimplemented("core:thread procedure not supported on target") +} + +_yield :: proc() { + unimplemented("core:thread procedure not supported on target") +} + diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 5291917da..363f50862 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -6,6 +6,8 @@ import "core:sync" import "core:sys/unix" import "core:time" +_IS_SUPPORTED :: true + CAS :: sync.atomic_compare_exchange_strong // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t. @@ -23,10 +25,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { __unix_thread_entry_proc :: proc "c" (t: rawptr) -> rawptr { t := (^Thread)(t) - when ODIN_OS != .Darwin { - // We need to give the thread a moment to start up before we enable cancellation. - can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) == 0 - } + // We need to give the thread a moment to start up before we enable cancellation. + can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) == 0 sync.lock(&t.mutex) @@ -42,12 +42,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { return nil } - when ODIN_OS != .Darwin { - // Enable thread's cancelability. - if can_set_thread_cancel_state { - unix.pthread_setcanceltype (unix.PTHREAD_CANCEL_ASYNCHRONOUS, nil) - unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) - } + // Enable thread's cancelability. + if can_set_thread_cancel_state { + unix.pthread_setcanceltype (unix.PTHREAD_CANCEL_ASYNCHRONOUS, nil) + unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) } { @@ -169,10 +167,17 @@ _destroy :: proc(t: ^Thread) { } _terminate :: proc(t: ^Thread, exit_code: int) { - // `pthread_cancel` is unreliable on Darwin for unknown reasons. - when ODIN_OS != .Darwin { - unix.pthread_cancel(t.unix_thread) - } + // NOTE(Feoramund): For thread cancellation to succeed on BSDs and + // possibly Darwin systems, the thread must call one of the pthread + // cancelation points at some point after this. + // + // The most obvious one of these is `pthread_cancel`, but there is an + // entire list of functions that act as cancelation points available in the + // pthreads manual page. + // + // This is in contrast to behavior I have seen on Linux where the thread is + // just terminated. + unix.pthread_cancel(t.unix_thread) } _yield :: proc() { diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 314ef5842..8da75a2d9 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -6,6 +6,8 @@ import "base:intrinsics" import "core:sync" import win32 "core:sys/windows" +_IS_SUPPORTED :: true + Thread_Os_Specific :: struct { win32_thread: win32.HANDLE, win32_thread_id: win32.DWORD, diff --git a/core/time/datetime/datetime.odin b/core/time/datetime/datetime.odin index 89fa2ce98..938b4a368 100644 --- a/core/time/datetime/datetime.odin +++ b/core/time/datetime/datetime.odin @@ -48,7 +48,7 @@ ordinal_to_datetime :: proc "contextless" (ordinal: Ordinal) -> (datetime: DateT } day_of_week :: proc "contextless" (ordinal: Ordinal) -> (day: Weekday) { - return Weekday((ordinal - EPOCH) %% 7) + return Weekday((ordinal - EPOCH + 1) %% 7) } subtract_dates :: proc "contextless" (a, b: Date) -> (delta: Delta, err: Error) { diff --git a/core/time/time.odin b/core/time/time.odin index 4575b36f7..4ea5afc70 100644 --- a/core/time/time.odin +++ b/core/time/time.odin @@ -220,6 +220,10 @@ unix :: proc "contextless" (sec: i64, nsec: i64) -> Time { return Time{(sec*1e9 + nsec)} } +from_nanoseconds :: #force_inline proc "contextless" (nsec: i64) -> Time { + return Time{nsec} +} + to_unix_seconds :: time_to_unix time_to_unix :: proc "contextless" (t: Time) -> i64 { return t._nsec/1e9 diff --git a/core/unicode/letter.odin b/core/unicode/letter.odin index 891c90bf3..e6d0261c6 100644 --- a/core/unicode/letter.odin +++ b/core/unicode/letter.odin @@ -5,6 +5,12 @@ REPLACEMENT_CHAR :: '\ufffd' // Represented an invalid code point MAX_ASCII :: '\u007f' // Maximum ASCII value MAX_LATIN1 :: '\u00ff' // Maximum Latin-1 value +ZERO_WIDTH_SPACE :: '\u200B' +ZERO_WIDTH_NON_JOINER :: '\u200C' +ZERO_WIDTH_JOINER :: '\u200D' +WORD_JOINER :: '\u2060' + +@(require_results) binary_search :: proc(c: i32, table: []i32, length, stride: int) -> int { n := length t := 0 @@ -24,6 +30,7 @@ binary_search :: proc(c: i32, table: []i32, length, stride: int) -> int { return -1 } +@(require_results) to_lower :: proc(r: rune) -> rune { c := i32(r) p := binary_search(c, to_lower_ranges[:], len(to_lower_ranges)/3, 3) @@ -36,6 +43,7 @@ to_lower :: proc(r: rune) -> rune { } return rune(c) } +@(require_results) to_upper :: proc(r: rune) -> rune { c := i32(r) p := binary_search(c, to_upper_ranges[:], len(to_upper_ranges)/3, 3) @@ -48,6 +56,7 @@ to_upper :: proc(r: rune) -> rune { } return rune(c) } +@(require_results) to_title :: proc(r: rune) -> rune { c := i32(r) p := binary_search(c, to_upper_singlets[:], len(to_title_singlets)/2, 2) @@ -58,6 +67,7 @@ to_title :: proc(r: rune) -> rune { } +@(require_results) is_lower :: proc(r: rune) -> bool { if r <= MAX_ASCII { return u32(r)-'a' < 26 @@ -74,6 +84,7 @@ is_lower :: proc(r: rune) -> bool { return false } +@(require_results) is_upper :: proc(r: rune) -> bool { if r <= MAX_ASCII { return u32(r)-'A' < 26 @@ -91,6 +102,7 @@ is_upper :: proc(r: rune) -> bool { } is_alpha :: is_letter +@(require_results) is_letter :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pLmask != 0 @@ -111,10 +123,12 @@ is_letter :: proc(r: rune) -> bool { return false } +@(require_results) is_title :: proc(r: rune) -> bool { return is_upper(r) && is_lower(r) } +@(require_results) is_digit :: proc(r: rune) -> bool { if r <= MAX_LATIN1 { return '0' <= r && r <= '9' @@ -124,6 +138,7 @@ is_digit :: proc(r: rune) -> bool { is_white_space :: is_space +@(require_results) is_space :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { switch r { @@ -140,18 +155,20 @@ is_space :: proc(r: rune) -> bool { return false } +@(require_results) is_combining :: proc(r: rune) -> bool { c := i32(r) return c >= 0x0300 && (c <= 0x036f || - (c >= 0x1ab0 && c <= 0x1aff) || - (c >= 0x1dc0 && c <= 0x1dff) || - (c >= 0x20d0 && c <= 0x20ff) || - (c >= 0xfe20 && c <= 0xfe2f)) + (c >= 0x1ab0 && c <= 0x1aff) || + (c >= 0x1dc0 && c <= 0x1dff) || + (c >= 0x20d0 && c <= 0x20ff) || + (c >= 0xfe20 && c <= 0xfe2f)) } +@(require_results) is_graphic :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pg != 0 @@ -159,6 +176,7 @@ is_graphic :: proc(r: rune) -> bool { return false } +@(require_results) is_print :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pp != 0 @@ -166,6 +184,7 @@ is_print :: proc(r: rune) -> bool { return false } +@(require_results) is_control :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pC != 0 @@ -173,6 +192,7 @@ is_control :: proc(r: rune) -> bool { return false } +@(require_results) is_number :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pN != 0 @@ -180,6 +200,7 @@ is_number :: proc(r: rune) -> bool { return false } +@(require_results) is_punct :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pP != 0 @@ -187,9 +208,285 @@ is_punct :: proc(r: rune) -> bool { return false } +@(require_results) is_symbol :: proc(r: rune) -> bool { if u32(r) <= MAX_LATIN1 { return char_properties[u8(r)]&pS != 0 } return false } + +// +// The procedures below are accurate as of Unicode 15.1.0. +// + +// Emoji_Modifier +@(require_results) +is_emoji_modifier :: proc(r: rune) -> bool { + return 0x1F3FB <= r && r <= 0x1F3FF +} + +// Regional_Indicator +@(require_results) +is_regional_indicator :: proc(r: rune) -> bool { + return 0x1F1E6 <= r && r <= 0x1F1FF +} + +// General_Category=Enclosing_Mark +@(require_results) +is_enclosing_mark :: proc(r: rune) -> bool { + switch r { + case 0x0488, + 0x0489, + 0x1ABE, + 0x20DD ..= 0x20E0, + 0x20E2 ..= 0x20E4, + 0xA670 ..= 0xA672: + return true + } + + return false +} + +// Prepended_Concatenation_Mark +@(require_results) +is_prepended_concatenation_mark :: proc(r: rune) -> bool { + switch r { + case 0x00600 ..= 0x00605, + 0x006DD, + 0x0070F, + 0x00890 ..= 0x00891, + 0x008E2, + 0x110BD, + 0x110CD: + return true + case: + return false + } +} + +// General_Category=Spacing_Mark +@(require_results) +is_spacing_mark :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, spacing_mark_ranges[:], len(spacing_mark_ranges)/2, 2) + if p >= 0 && spacing_mark_ranges[p] <= c && c <= spacing_mark_ranges[p+1] { + return true + } + return false +} + +// General_Category=Nonspacing_Mark +@(require_results) +is_nonspacing_mark :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, nonspacing_mark_ranges[:], len(nonspacing_mark_ranges)/2, 2) + if p >= 0 && nonspacing_mark_ranges[p] <= c && c <= nonspacing_mark_ranges[p+1] { + return true + } + return false +} + +// Extended_Pictographic +@(require_results) +is_emoji_extended_pictographic :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, emoji_extended_pictographic_ranges[:], len(emoji_extended_pictographic_ranges)/2, 2) + if p >= 0 && emoji_extended_pictographic_ranges[p] <= c && c <= emoji_extended_pictographic_ranges[p+1] { + return true + } + return false +} + +// Grapheme_Extend +@(require_results) +is_grapheme_extend :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, grapheme_extend_ranges[:], len(grapheme_extend_ranges)/2, 2) + if p >= 0 && grapheme_extend_ranges[p] <= c && c <= grapheme_extend_ranges[p+1] { + return true + } + return false +} + + +// Hangul_Syllable_Type=Leading_Jamo +@(require_results) +is_hangul_syllable_leading :: proc(r: rune) -> bool { + return 0x1100 <= r && r <= 0x115F || 0xA960 <= r && r <= 0xA97C +} + +// Hangul_Syllable_Type=Vowel_Jamo +@(require_results) +is_hangul_syllable_vowel :: proc(r: rune) -> bool { + return 0x1160 <= r && r <= 0x11A7 || 0xD7B0 <= r && r <= 0xD7C6 +} + +// Hangul_Syllable_Type=Trailing_Jamo +@(require_results) +is_hangul_syllable_trailing :: proc(r: rune) -> bool { + return 0x11A8 <= r && r <= 0x11FF || 0xD7CB <= r && r <= 0xD7FB +} + +// Hangul_Syllable_Type=LV_Syllable +@(require_results) +is_hangul_syllable_lv :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, hangul_syllable_lv_singlets[:], len(hangul_syllable_lv_singlets), 1) + if p >= 0 && c == hangul_syllable_lv_singlets[p] { + return true + } + return false +} + +// Hangul_Syllable_Type=LVT_Syllable +@(require_results) +is_hangul_syllable_lvt :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, hangul_syllable_lvt_ranges[:], len(hangul_syllable_lvt_ranges)/2, 2) + if p >= 0 && hangul_syllable_lvt_ranges[p] <= c && c <= hangul_syllable_lvt_ranges[p+1] { + return true + } + return false +} + + +// Indic_Syllabic_Category=Consonant_Preceding_Repha +@(require_results) +is_indic_consonant_preceding_repha :: proc(r: rune) -> bool { + switch r { + case 0x00D4E, + 0x11941, + 0x11D46, + 0x11F02: + return true + case: + return false + } +} + +// Indic_Syllabic_Category=Consonant_Prefixed +@(require_results) +is_indic_consonant_prefixed :: proc(r: rune) -> bool { + switch r { + case 0x111C2 ..= 0x111C3, + 0x1193F, + 0x11A3A, + 0x11A84 ..= 0x11A89: + return true + case: + return false + } +} + +// Indic_Conjunct_Break=Linker +@(require_results) +is_indic_conjunct_break_linker :: proc(r: rune) -> bool { + switch r { + case 0x094D, + 0x09CD, + 0x0ACD, + 0x0B4D, + 0x0C4D, + 0x0D4D: + return true + case: + return false + } +} + +// Indic_Conjunct_Break=Consonant +@(require_results) +is_indic_conjunct_break_consonant :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, indic_conjunct_break_consonant_ranges[:], len(indic_conjunct_break_consonant_ranges)/2, 2) + if p >= 0 && indic_conjunct_break_consonant_ranges[p] <= c && c <= indic_conjunct_break_consonant_ranges[p+1] { + return true + } + return false +} + +// Indic_Conjunct_Break=Extend +@(require_results) +is_indic_conjunct_break_extend :: proc(r: rune) -> bool { + c := i32(r) + p := binary_search(c, indic_conjunct_break_extend_ranges[:], len(indic_conjunct_break_extend_ranges)/2, 2) + if p >= 0 && indic_conjunct_break_extend_ranges[p] <= c && c <= indic_conjunct_break_extend_ranges[p+1] { + return true + } + return false +} + + +/* +For grapheme text segmentation, from Unicode TR 29 Rev 43: + +``` +Indic_Syllabic_Category = Consonant_Preceding_Repha, or +Indic_Syllabic_Category = Consonant_Prefixed, or +Prepended_Concatenation_Mark = Yes +``` +*/ +@(require_results) +is_gcb_prepend_class :: proc(r: rune) -> bool { + return is_indic_consonant_preceding_repha(r) || is_indic_consonant_prefixed(r) || is_prepended_concatenation_mark(r) +} + +/* +For grapheme text segmentation, from Unicode TR 29 Rev 43: + +``` +Grapheme_Extend = Yes, or +Emoji_Modifier = Yes + +This includes: +General_Category = Nonspacing_Mark +General_Category = Enclosing_Mark +U+200C ZERO WIDTH NON-JOINER + +plus a few General_Category = Spacing_Mark needed for canonical equivalence. +``` +*/ +@(require_results) +is_gcb_extend_class :: proc(r: rune) -> bool { + return is_grapheme_extend(r) || is_emoji_modifier(r) +} + +// Return values: +// +// - 2 if East_Asian_Width=F or W, or +// - 0 if non-printable / zero-width, or +// - 1 in all other cases. +// +@(require_results) +normalized_east_asian_width :: proc(r: rune) -> int { + // This is a different interpretation of the BOM which occurs in the middle of text. + ZERO_WIDTH_NO_BREAK_SPACE :: '\uFEFF' + + if is_control(r) { + return 0 + } else if r <= 0x10FF { + // Easy early out for low runes. + return 1 + } + + switch r { + case ZERO_WIDTH_NO_BREAK_SPACE, + ZERO_WIDTH_SPACE, + ZERO_WIDTH_NON_JOINER, + ZERO_WIDTH_JOINER, + WORD_JOINER: + return 0 + } + + c := i32(r) + p := binary_search(c, normalized_east_asian_width_ranges[:], len(normalized_east_asian_width_ranges)/3, 3) + if p >= 0 && normalized_east_asian_width_ranges[p] <= c && c <= normalized_east_asian_width_ranges[p+1] { + return cast(int)normalized_east_asian_width_ranges[p+2] + } + return 1 +} + +// +// End of Unicode 15.1.0 block. +// diff --git a/core/unicode/tables.odin b/core/unicode/tables.odin index dfa5caaa2..c0b3fe434 100644 --- a/core/unicode/tables.odin +++ b/core/unicode/tables.odin @@ -1270,3 +1270,2623 @@ to_title_singlets := [?]i32{ 0x01f1, 501, 0x01f3, 499, } + +// +// The tables below are accurate as of Unicode 15.1.0. +// + +@(rodata) +spacing_mark_ranges := [?]i32 { + 0x0903, 0x0903, + 0x093B, 0x093B, + 0x093E, 0x0940, + 0x0949, 0x094C, + 0x094E, 0x094F, + 0x0982, 0x0983, + 0x09BE, 0x09C0, + 0x09C7, 0x09C8, + 0x09CB, 0x09CC, + 0x09D7, 0x09D7, + 0x0A03, 0x0A03, + 0x0A3E, 0x0A40, + 0x0A83, 0x0A83, + 0x0ABE, 0x0AC0, + 0x0AC9, 0x0AC9, + 0x0ACB, 0x0ACC, + 0x0B02, 0x0B03, + 0x0B3E, 0x0B3E, + 0x0B40, 0x0B40, + 0x0B47, 0x0B48, + 0x0B4B, 0x0B4C, + 0x0B57, 0x0B57, + 0x0BBE, 0x0BBF, + 0x0BC1, 0x0BC2, + 0x0BC6, 0x0BC8, + 0x0BCA, 0x0BCC, + 0x0BD7, 0x0BD7, + 0x0C01, 0x0C03, + 0x0C41, 0x0C44, + 0x0C82, 0x0C83, + 0x0CBE, 0x0CBE, + 0x0CC0, 0x0CC4, + 0x0CC7, 0x0CC8, + 0x0CCA, 0x0CCB, + 0x0CD5, 0x0CD6, + 0x0CF3, 0x0CF3, + 0x0D02, 0x0D03, + 0x0D3E, 0x0D40, + 0x0D46, 0x0D48, + 0x0D4A, 0x0D4C, + 0x0D57, 0x0D57, + 0x0D82, 0x0D83, + 0x0DCF, 0x0DD1, + 0x0DD8, 0x0DDF, + 0x0DF2, 0x0DF3, + 0x0F3E, 0x0F3F, + 0x0F7F, 0x0F7F, + 0x102B, 0x102C, + 0x1031, 0x1031, + 0x1038, 0x1038, + 0x103B, 0x103C, + 0x1056, 0x1057, + 0x1062, 0x1064, + 0x1067, 0x106D, + 0x1083, 0x1084, + 0x1087, 0x108C, + 0x108F, 0x108F, + 0x109A, 0x109C, + 0x1715, 0x1715, + 0x1734, 0x1734, + 0x17B6, 0x17B6, + 0x17BE, 0x17C5, + 0x17C7, 0x17C8, + 0x1923, 0x1926, + 0x1929, 0x192B, + 0x1930, 0x1931, + 0x1933, 0x1938, + 0x1A19, 0x1A1A, + 0x1A55, 0x1A55, + 0x1A57, 0x1A57, + 0x1A61, 0x1A61, + 0x1A63, 0x1A64, + 0x1A6D, 0x1A72, + 0x1B04, 0x1B04, + 0x1B35, 0x1B35, + 0x1B3B, 0x1B3B, + 0x1B3D, 0x1B41, + 0x1B43, 0x1B44, + 0x1B82, 0x1B82, + 0x1BA1, 0x1BA1, + 0x1BA6, 0x1BA7, + 0x1BAA, 0x1BAA, + 0x1BE7, 0x1BE7, + 0x1BEA, 0x1BEC, + 0x1BEE, 0x1BEE, + 0x1BF2, 0x1BF3, + 0x1C24, 0x1C2B, + 0x1C34, 0x1C35, + 0x1CE1, 0x1CE1, + 0x1CF7, 0x1CF7, + 0x302E, 0x302F, + 0xA823, 0xA824, + 0xA827, 0xA827, + 0xA880, 0xA881, + 0xA8B4, 0xA8C3, + 0xA952, 0xA953, + 0xA983, 0xA983, + 0xA9B4, 0xA9B5, + 0xA9BA, 0xA9BB, + 0xA9BE, 0xA9C0, + 0xAA2F, 0xAA30, + 0xAA33, 0xAA34, + 0xAA4D, 0xAA4D, + 0xAA7B, 0xAA7B, + 0xAA7D, 0xAA7D, + 0xAAEB, 0xAAEB, + 0xAAEE, 0xAAEF, + 0xAAF5, 0xAAF5, + 0xABE3, 0xABE4, + 0xABE6, 0xABE7, + 0xABE9, 0xABEA, + 0xABEC, 0xABEC, + 0x11000, 0x11000, + 0x11002, 0x11002, + 0x11082, 0x11082, + 0x110B0, 0x110B2, + 0x110B7, 0x110B8, + 0x1112C, 0x1112C, + 0x11145, 0x11146, + 0x11182, 0x11182, + 0x111B3, 0x111B5, + 0x111BF, 0x111C0, + 0x111CE, 0x111CE, + 0x1122C, 0x1122E, + 0x11232, 0x11233, + 0x11235, 0x11235, + 0x112E0, 0x112E2, + 0x11302, 0x11303, + 0x1133E, 0x1133F, + 0x11341, 0x11344, + 0x11347, 0x11348, + 0x1134B, 0x1134D, + 0x11357, 0x11357, + 0x11362, 0x11363, + 0x11435, 0x11437, + 0x11440, 0x11441, + 0x11445, 0x11445, + 0x114B0, 0x114B2, + 0x114B9, 0x114B9, + 0x114BB, 0x114BE, + 0x114C1, 0x114C1, + 0x115AF, 0x115B1, + 0x115B8, 0x115BB, + 0x115BE, 0x115BE, + 0x11630, 0x11632, + 0x1163B, 0x1163C, + 0x1163E, 0x1163E, + 0x116AC, 0x116AC, + 0x116AE, 0x116AF, + 0x116B6, 0x116B6, + 0x11720, 0x11721, + 0x11726, 0x11726, + 0x1182C, 0x1182E, + 0x11838, 0x11838, + 0x11930, 0x11935, + 0x11937, 0x11938, + 0x1193D, 0x1193D, + 0x11940, 0x11940, + 0x11942, 0x11942, + 0x119D1, 0x119D3, + 0x119DC, 0x119DF, + 0x119E4, 0x119E4, + 0x11A39, 0x11A39, + 0x11A57, 0x11A58, + 0x11A97, 0x11A97, + 0x11C2F, 0x11C2F, + 0x11C3E, 0x11C3E, + 0x11CA9, 0x11CA9, + 0x11CB1, 0x11CB1, + 0x11CB4, 0x11CB4, + 0x11D8A, 0x11D8E, + 0x11D93, 0x11D94, + 0x11D96, 0x11D96, + 0x11EF5, 0x11EF6, + 0x11F03, 0x11F03, + 0x11F34, 0x11F35, + 0x11F3E, 0x11F3F, + 0x11F41, 0x11F41, + 0x16F51, 0x16F87, + 0x16FF0, 0x16FF1, + 0x1D165, 0x1D166, + 0x1D16D, 0x1D172, +} + +@(rodata) +nonspacing_mark_ranges := [?]i32 { + 0x0300, 0x036F, + 0x0483, 0x0487, + 0x0591, 0x05BD, + 0x05BF, 0x05BF, + 0x05C1, 0x05C2, + 0x05C4, 0x05C5, + 0x05C7, 0x05C7, + 0x0610, 0x061A, + 0x064B, 0x065F, + 0x0670, 0x0670, + 0x06D6, 0x06DC, + 0x06DF, 0x06E4, + 0x06E7, 0x06E8, + 0x06EA, 0x06ED, + 0x0711, 0x0711, + 0x0730, 0x074A, + 0x07A6, 0x07B0, + 0x07EB, 0x07F3, + 0x07FD, 0x07FD, + 0x0816, 0x0819, + 0x081B, 0x0823, + 0x0825, 0x0827, + 0x0829, 0x082D, + 0x0859, 0x085B, + 0x0898, 0x089F, + 0x08CA, 0x08E1, + 0x08E3, 0x0902, + 0x093A, 0x093A, + 0x093C, 0x093C, + 0x0941, 0x0948, + 0x094D, 0x094D, + 0x0951, 0x0957, + 0x0962, 0x0963, + 0x0981, 0x0981, + 0x09BC, 0x09BC, + 0x09C1, 0x09C4, + 0x09CD, 0x09CD, + 0x09E2, 0x09E3, + 0x09FE, 0x09FE, + 0x0A01, 0x0A02, + 0x0A3C, 0x0A3C, + 0x0A41, 0x0A42, + 0x0A47, 0x0A48, + 0x0A4B, 0x0A4D, + 0x0A51, 0x0A51, + 0x0A70, 0x0A71, + 0x0A75, 0x0A75, + 0x0A81, 0x0A82, + 0x0ABC, 0x0ABC, + 0x0AC1, 0x0AC5, + 0x0AC7, 0x0AC8, + 0x0ACD, 0x0ACD, + 0x0AE2, 0x0AE3, + 0x0AFA, 0x0AFF, + 0x0B01, 0x0B01, + 0x0B3C, 0x0B3C, + 0x0B3F, 0x0B3F, + 0x0B41, 0x0B44, + 0x0B4D, 0x0B4D, + 0x0B55, 0x0B56, + 0x0B62, 0x0B63, + 0x0B82, 0x0B82, + 0x0BC0, 0x0BC0, + 0x0BCD, 0x0BCD, + 0x0C00, 0x0C00, + 0x0C04, 0x0C04, + 0x0C3C, 0x0C3C, + 0x0C3E, 0x0C40, + 0x0C46, 0x0C48, + 0x0C4A, 0x0C4D, + 0x0C55, 0x0C56, + 0x0C62, 0x0C63, + 0x0C81, 0x0C81, + 0x0CBC, 0x0CBC, + 0x0CBF, 0x0CBF, + 0x0CC6, 0x0CC6, + 0x0CCC, 0x0CCD, + 0x0CE2, 0x0CE3, + 0x0D00, 0x0D01, + 0x0D3B, 0x0D3C, + 0x0D41, 0x0D44, + 0x0D4D, 0x0D4D, + 0x0D62, 0x0D63, + 0x0D81, 0x0D81, + 0x0DCA, 0x0DCA, + 0x0DD2, 0x0DD4, + 0x0DD6, 0x0DD6, + 0x0E31, 0x0E31, + 0x0E34, 0x0E3A, + 0x0E47, 0x0E4E, + 0x0EB1, 0x0EB1, + 0x0EB4, 0x0EBC, + 0x0EC8, 0x0ECE, + 0x0F18, 0x0F19, + 0x0F35, 0x0F35, + 0x0F37, 0x0F37, + 0x0F39, 0x0F39, + 0x0F71, 0x0F7E, + 0x0F80, 0x0F84, + 0x0F86, 0x0F87, + 0x0F8D, 0x0F97, + 0x0F99, 0x0FBC, + 0x0FC6, 0x0FC6, + 0x102D, 0x1030, + 0x1032, 0x1037, + 0x1039, 0x103A, + 0x103D, 0x103E, + 0x1058, 0x1059, + 0x105E, 0x1060, + 0x1071, 0x1074, + 0x1082, 0x1082, + 0x1085, 0x1086, + 0x108D, 0x108D, + 0x109D, 0x109D, + 0x135D, 0x135F, + 0x1712, 0x1714, + 0x1732, 0x1733, + 0x1752, 0x1753, + 0x1772, 0x1773, + 0x17B4, 0x17B5, + 0x17B7, 0x17BD, + 0x17C6, 0x17C6, + 0x17C9, 0x17D3, + 0x17DD, 0x17DD, + 0x180B, 0x180D, + 0x180F, 0x180F, + 0x1885, 0x1886, + 0x18A9, 0x18A9, + 0x1920, 0x1922, + 0x1927, 0x1928, + 0x1932, 0x1932, + 0x1939, 0x193B, + 0x1A17, 0x1A18, + 0x1A1B, 0x1A1B, + 0x1A56, 0x1A56, + 0x1A58, 0x1A5E, + 0x1A60, 0x1A60, + 0x1A62, 0x1A62, + 0x1A65, 0x1A6C, + 0x1A73, 0x1A7C, + 0x1A7F, 0x1A7F, + 0x1AB0, 0x1ABD, + 0x1ABF, 0x1ACE, + 0x1B00, 0x1B03, + 0x1B34, 0x1B34, + 0x1B36, 0x1B3A, + 0x1B3C, 0x1B3C, + 0x1B42, 0x1B42, + 0x1B6B, 0x1B73, + 0x1B80, 0x1B81, + 0x1BA2, 0x1BA5, + 0x1BA8, 0x1BA9, + 0x1BAB, 0x1BAD, + 0x1BE6, 0x1BE6, + 0x1BE8, 0x1BE9, + 0x1BED, 0x1BED, + 0x1BEF, 0x1BF1, + 0x1C2C, 0x1C33, + 0x1C36, 0x1C37, + 0x1CD0, 0x1CD2, + 0x1CD4, 0x1CE0, + 0x1CE2, 0x1CE8, + 0x1CED, 0x1CED, + 0x1CF4, 0x1CF4, + 0x1CF8, 0x1CF9, + 0x1DC0, 0x1DFF, + 0x20D0, 0x20DC, + 0x20E1, 0x20E1, + 0x20E5, 0x20F0, + 0x2CEF, 0x2CF1, + 0x2D7F, 0x2D7F, + 0x2DE0, 0x2DFF, + 0x302A, 0x302D, + 0x3099, 0x309A, + 0xA66F, 0xA66F, + 0xA674, 0xA67D, + 0xA69E, 0xA69F, + 0xA6F0, 0xA6F1, + 0xA802, 0xA802, + 0xA806, 0xA806, + 0xA80B, 0xA80B, + 0xA825, 0xA826, + 0xA82C, 0xA82C, + 0xA8C4, 0xA8C5, + 0xA8E0, 0xA8F1, + 0xA8FF, 0xA8FF, + 0xA926, 0xA92D, + 0xA947, 0xA951, + 0xA980, 0xA982, + 0xA9B3, 0xA9B3, + 0xA9B6, 0xA9B9, + 0xA9BC, 0xA9BD, + 0xA9E5, 0xA9E5, + 0xAA29, 0xAA2E, + 0xAA31, 0xAA32, + 0xAA35, 0xAA36, + 0xAA43, 0xAA43, + 0xAA4C, 0xAA4C, + 0xAA7C, 0xAA7C, + 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, + 0xAAB7, 0xAAB8, + 0xAABE, 0xAABF, + 0xAAC1, 0xAAC1, + 0xAAEC, 0xAAED, + 0xAAF6, 0xAAF6, + 0xABE5, 0xABE5, + 0xABE8, 0xABE8, + 0xABED, 0xABED, + 0xFB1E, 0xFB1E, + 0xFE00, 0xFE0F, + 0xFE20, 0xFE2F, + 0x101FD, 0x101FD, + 0x102E0, 0x102E0, + 0x10376, 0x1037A, + 0x10A01, 0x10A03, + 0x10A05, 0x10A06, + 0x10A0C, 0x10A0F, + 0x10A38, 0x10A3A, + 0x10A3F, 0x10A3F, + 0x10AE5, 0x10AE6, + 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, + 0x10EFD, 0x10EFF, + 0x10F46, 0x10F50, + 0x10F82, 0x10F85, + 0x11001, 0x11001, + 0x11038, 0x11046, + 0x11070, 0x11070, + 0x11073, 0x11074, + 0x1107F, 0x11081, + 0x110B3, 0x110B6, + 0x110B9, 0x110BA, + 0x110C2, 0x110C2, + 0x11100, 0x11102, + 0x11127, 0x1112B, + 0x1112D, 0x11134, + 0x11173, 0x11173, + 0x11180, 0x11181, + 0x111B6, 0x111BE, + 0x111C9, 0x111CC, + 0x111CF, 0x111CF, + 0x1122F, 0x11231, + 0x11234, 0x11234, + 0x11236, 0x11237, + 0x1123E, 0x1123E, + 0x11241, 0x11241, + 0x112DF, 0x112DF, + 0x112E3, 0x112EA, + 0x11300, 0x11301, + 0x1133B, 0x1133C, + 0x11340, 0x11340, + 0x11366, 0x1136C, + 0x11370, 0x11374, + 0x11438, 0x1143F, + 0x11442, 0x11444, + 0x11446, 0x11446, + 0x1145E, 0x1145E, + 0x114B3, 0x114B8, + 0x114BA, 0x114BA, + 0x114BF, 0x114C0, + 0x114C2, 0x114C3, + 0x115B2, 0x115B5, + 0x115BC, 0x115BD, + 0x115BF, 0x115C0, + 0x115DC, 0x115DD, + 0x11633, 0x1163A, + 0x1163D, 0x1163D, + 0x1163F, 0x11640, + 0x116AB, 0x116AB, + 0x116AD, 0x116AD, + 0x116B0, 0x116B5, + 0x116B7, 0x116B7, + 0x1171D, 0x1171F, + 0x11722, 0x11725, + 0x11727, 0x1172B, + 0x1182F, 0x11837, + 0x11839, 0x1183A, + 0x1193B, 0x1193C, + 0x1193E, 0x1193E, + 0x11943, 0x11943, + 0x119D4, 0x119D7, + 0x119DA, 0x119DB, + 0x119E0, 0x119E0, + 0x11A01, 0x11A0A, + 0x11A33, 0x11A38, + 0x11A3B, 0x11A3E, + 0x11A47, 0x11A47, + 0x11A51, 0x11A56, + 0x11A59, 0x11A5B, + 0x11A8A, 0x11A96, + 0x11A98, 0x11A99, + 0x11C30, 0x11C36, + 0x11C38, 0x11C3D, + 0x11C3F, 0x11C3F, + 0x11C92, 0x11CA7, + 0x11CAA, 0x11CB0, + 0x11CB2, 0x11CB3, + 0x11CB5, 0x11CB6, + 0x11D31, 0x11D36, + 0x11D3A, 0x11D3A, + 0x11D3C, 0x11D3D, + 0x11D3F, 0x11D45, + 0x11D47, 0x11D47, + 0x11D90, 0x11D91, + 0x11D95, 0x11D95, + 0x11D97, 0x11D97, + 0x11EF3, 0x11EF4, + 0x11F00, 0x11F01, + 0x11F36, 0x11F3A, + 0x11F40, 0x11F40, + 0x11F42, 0x11F42, + 0x13440, 0x13440, + 0x13447, 0x13455, + 0x16AF0, 0x16AF4, + 0x16B30, 0x16B36, + 0x16F4F, 0x16F4F, + 0x16F8F, 0x16F92, + 0x16FE4, 0x16FE4, + 0x1BC9D, 0x1BC9E, + 0x1CF00, 0x1CF2D, + 0x1CF30, 0x1CF46, + 0x1D167, 0x1D169, + 0x1D17B, 0x1D182, + 0x1D185, 0x1D18B, + 0x1D1AA, 0x1D1AD, + 0x1D242, 0x1D244, + 0x1DA00, 0x1DA36, + 0x1DA3B, 0x1DA6C, + 0x1DA75, 0x1DA75, + 0x1DA84, 0x1DA84, + 0x1DA9B, 0x1DA9F, + 0x1DAA1, 0x1DAAF, + 0x1E000, 0x1E006, + 0x1E008, 0x1E018, + 0x1E01B, 0x1E021, + 0x1E023, 0x1E024, + 0x1E026, 0x1E02A, + 0x1E08F, 0x1E08F, + 0x1E130, 0x1E136, + 0x1E2AE, 0x1E2AE, + 0x1E2EC, 0x1E2EF, + 0x1E4EC, 0x1E4EF, + 0x1E8D0, 0x1E8D6, + 0x1E944, 0x1E94A, + 0xE0100, 0xE01EF, +} + +@(rodata) +emoji_extended_pictographic_ranges := [?]i32 { + 0x00A9, 0x00A9, + 0x00AE, 0x00AE, + 0x203C, 0x203C, + 0x2049, 0x2049, + 0x2122, 0x2122, + 0x2139, 0x2139, + 0x2194, 0x2199, + 0x21A9, 0x21AA, + 0x231A, 0x231B, + 0x2328, 0x2328, + 0x2388, 0x2388, + 0x23CF, 0x23CF, + 0x23E9, 0x23EC, + 0x23ED, 0x23EE, + 0x23EF, 0x23EF, + 0x23F0, 0x23F0, + 0x23F1, 0x23F2, + 0x23F3, 0x23F3, + 0x23F8, 0x23FA, + 0x24C2, 0x24C2, + 0x25AA, 0x25AB, + 0x25B6, 0x25B6, + 0x25C0, 0x25C0, + 0x25FB, 0x25FE, + 0x2600, 0x2601, + 0x2602, 0x2603, + 0x2604, 0x2604, + 0x2605, 0x2605, + 0x2607, 0x260D, + 0x260E, 0x260E, + 0x260F, 0x2610, + 0x2611, 0x2611, + 0x2612, 0x2612, + 0x2614, 0x2615, + 0x2616, 0x2617, + 0x2618, 0x2618, + 0x2619, 0x261C, + 0x261D, 0x261D, + 0x261E, 0x261F, + 0x2620, 0x2620, + 0x2621, 0x2621, + 0x2622, 0x2623, + 0x2624, 0x2625, + 0x2626, 0x2626, + 0x2627, 0x2629, + 0x262A, 0x262A, + 0x262B, 0x262D, + 0x262E, 0x262E, + 0x262F, 0x262F, + 0x2630, 0x2637, + 0x2638, 0x2639, + 0x263A, 0x263A, + 0x263B, 0x263F, + 0x2640, 0x2640, + 0x2641, 0x2641, + 0x2642, 0x2642, + 0x2643, 0x2647, + 0x2648, 0x2653, + 0x2654, 0x265E, + 0x265F, 0x265F, + 0x2660, 0x2660, + 0x2661, 0x2662, + 0x2663, 0x2663, + 0x2664, 0x2664, + 0x2665, 0x2666, + 0x2667, 0x2667, + 0x2668, 0x2668, + 0x2669, 0x267A, + 0x267B, 0x267B, + 0x267C, 0x267D, + 0x267E, 0x267E, + 0x267F, 0x267F, + 0x2680, 0x2685, + 0x2690, 0x2691, + 0x2692, 0x2692, + 0x2693, 0x2693, + 0x2694, 0x2694, + 0x2695, 0x2695, + 0x2696, 0x2697, + 0x2698, 0x2698, + 0x2699, 0x2699, + 0x269A, 0x269A, + 0x269B, 0x269C, + 0x269D, 0x269F, + 0x26A0, 0x26A1, + 0x26A2, 0x26A6, + 0x26A7, 0x26A7, + 0x26A8, 0x26A9, + 0x26AA, 0x26AB, + 0x26AC, 0x26AF, + 0x26B0, 0x26B1, + 0x26B2, 0x26BC, + 0x26BD, 0x26BE, + 0x26BF, 0x26C3, + 0x26C4, 0x26C5, + 0x26C6, 0x26C7, + 0x26C8, 0x26C8, + 0x26C9, 0x26CD, + 0x26CE, 0x26CE, + 0x26CF, 0x26CF, + 0x26D0, 0x26D0, + 0x26D1, 0x26D1, + 0x26D2, 0x26D2, + 0x26D3, 0x26D3, + 0x26D4, 0x26D4, + 0x26D5, 0x26E8, + 0x26E9, 0x26E9, + 0x26EA, 0x26EA, + 0x26EB, 0x26EF, + 0x26F0, 0x26F1, + 0x26F2, 0x26F3, + 0x26F4, 0x26F4, + 0x26F5, 0x26F5, + 0x26F6, 0x26F6, + 0x26F7, 0x26F9, + 0x26FA, 0x26FA, + 0x26FB, 0x26FC, + 0x26FD, 0x26FD, + 0x26FE, 0x2701, + 0x2702, 0x2702, + 0x2703, 0x2704, + 0x2705, 0x2705, + 0x2708, 0x270C, + 0x270D, 0x270D, + 0x270E, 0x270E, + 0x270F, 0x270F, + 0x2710, 0x2711, + 0x2712, 0x2712, + 0x2714, 0x2714, + 0x2716, 0x2716, + 0x271D, 0x271D, + 0x2721, 0x2721, + 0x2728, 0x2728, + 0x2733, 0x2734, + 0x2744, 0x2744, + 0x2747, 0x2747, + 0x274C, 0x274C, + 0x274E, 0x274E, + 0x2753, 0x2755, + 0x2757, 0x2757, + 0x2763, 0x2763, + 0x2764, 0x2764, + 0x2765, 0x2767, + 0x2795, 0x2797, + 0x27A1, 0x27A1, + 0x27B0, 0x27B0, + 0x27BF, 0x27BF, + 0x2934, 0x2935, + 0x2B05, 0x2B07, + 0x2B1B, 0x2B1C, + 0x2B50, 0x2B50, + 0x2B55, 0x2B55, + 0x3030, 0x3030, + 0x303D, 0x303D, + 0x3297, 0x3297, + 0x3299, 0x3299, + 0x1F000, 0x1F003, + 0x1F004, 0x1F004, + 0x1F005, 0x1F0CE, + 0x1F0CF, 0x1F0CF, + 0x1F0D0, 0x1F0FF, + 0x1F10D, 0x1F10F, + 0x1F12F, 0x1F12F, + 0x1F16C, 0x1F16F, + 0x1F170, 0x1F171, + 0x1F17E, 0x1F17F, + 0x1F18E, 0x1F18E, + 0x1F191, 0x1F19A, + 0x1F1AD, 0x1F1E5, + 0x1F201, 0x1F202, + 0x1F203, 0x1F20F, + 0x1F21A, 0x1F21A, + 0x1F22F, 0x1F22F, + 0x1F232, 0x1F23A, + 0x1F23C, 0x1F23F, + 0x1F249, 0x1F24F, + 0x1F250, 0x1F251, + 0x1F252, 0x1F2FF, + 0x1F300, 0x1F30C, + 0x1F30D, 0x1F30E, + 0x1F30F, 0x1F30F, + 0x1F310, 0x1F310, + 0x1F311, 0x1F311, + 0x1F312, 0x1F312, + 0x1F313, 0x1F315, + 0x1F316, 0x1F318, + 0x1F319, 0x1F319, + 0x1F31A, 0x1F31A, + 0x1F31B, 0x1F31B, + 0x1F31C, 0x1F31C, + 0x1F31D, 0x1F31E, + 0x1F31F, 0x1F320, + 0x1F321, 0x1F321, + 0x1F322, 0x1F323, + 0x1F324, 0x1F32C, + 0x1F32D, 0x1F32F, + 0x1F330, 0x1F331, + 0x1F332, 0x1F333, + 0x1F334, 0x1F335, + 0x1F336, 0x1F336, + 0x1F337, 0x1F34A, + 0x1F34B, 0x1F34B, + 0x1F34C, 0x1F34F, + 0x1F350, 0x1F350, + 0x1F351, 0x1F37B, + 0x1F37C, 0x1F37C, + 0x1F37D, 0x1F37D, + 0x1F37E, 0x1F37F, + 0x1F380, 0x1F393, + 0x1F394, 0x1F395, + 0x1F396, 0x1F397, + 0x1F398, 0x1F398, + 0x1F399, 0x1F39B, + 0x1F39C, 0x1F39D, + 0x1F39E, 0x1F39F, + 0x1F3A0, 0x1F3C4, + 0x1F3C5, 0x1F3C5, + 0x1F3C6, 0x1F3C6, + 0x1F3C7, 0x1F3C7, + 0x1F3C8, 0x1F3C8, + 0x1F3C9, 0x1F3C9, + 0x1F3CA, 0x1F3CA, + 0x1F3CB, 0x1F3CE, + 0x1F3CF, 0x1F3D3, + 0x1F3D4, 0x1F3DF, + 0x1F3E0, 0x1F3E3, + 0x1F3E4, 0x1F3E4, + 0x1F3E5, 0x1F3F0, + 0x1F3F1, 0x1F3F2, + 0x1F3F3, 0x1F3F3, + 0x1F3F4, 0x1F3F4, + 0x1F3F5, 0x1F3F5, + 0x1F3F6, 0x1F3F6, + 0x1F3F7, 0x1F3F7, + 0x1F3F8, 0x1F3FA, + 0x1F400, 0x1F407, + 0x1F408, 0x1F408, + 0x1F409, 0x1F40B, + 0x1F40C, 0x1F40E, + 0x1F40F, 0x1F410, + 0x1F411, 0x1F412, + 0x1F413, 0x1F413, + 0x1F414, 0x1F414, + 0x1F415, 0x1F415, + 0x1F416, 0x1F416, + 0x1F417, 0x1F429, + 0x1F42A, 0x1F42A, + 0x1F42B, 0x1F43E, + 0x1F43F, 0x1F43F, + 0x1F440, 0x1F440, + 0x1F441, 0x1F441, + 0x1F442, 0x1F464, + 0x1F465, 0x1F465, + 0x1F466, 0x1F46B, + 0x1F46C, 0x1F46D, + 0x1F46E, 0x1F4AC, + 0x1F4AD, 0x1F4AD, + 0x1F4AE, 0x1F4B5, + 0x1F4B6, 0x1F4B7, + 0x1F4B8, 0x1F4EB, + 0x1F4EC, 0x1F4ED, + 0x1F4EE, 0x1F4EE, + 0x1F4EF, 0x1F4EF, + 0x1F4F0, 0x1F4F4, + 0x1F4F5, 0x1F4F5, + 0x1F4F6, 0x1F4F7, + 0x1F4F8, 0x1F4F8, + 0x1F4F9, 0x1F4FC, + 0x1F4FD, 0x1F4FD, + 0x1F4FE, 0x1F4FE, + 0x1F4FF, 0x1F502, + 0x1F503, 0x1F503, + 0x1F504, 0x1F507, + 0x1F508, 0x1F508, + 0x1F509, 0x1F509, + 0x1F50A, 0x1F514, + 0x1F515, 0x1F515, + 0x1F516, 0x1F52B, + 0x1F52C, 0x1F52D, + 0x1F52E, 0x1F53D, + 0x1F546, 0x1F548, + 0x1F549, 0x1F54A, + 0x1F54B, 0x1F54E, + 0x1F54F, 0x1F54F, + 0x1F550, 0x1F55B, + 0x1F55C, 0x1F567, + 0x1F568, 0x1F56E, + 0x1F56F, 0x1F570, + 0x1F571, 0x1F572, + 0x1F573, 0x1F579, + 0x1F57A, 0x1F57A, + 0x1F57B, 0x1F586, + 0x1F587, 0x1F587, + 0x1F588, 0x1F589, + 0x1F58A, 0x1F58D, + 0x1F58E, 0x1F58F, + 0x1F590, 0x1F590, + 0x1F591, 0x1F594, + 0x1F595, 0x1F596, + 0x1F597, 0x1F5A3, + 0x1F5A4, 0x1F5A4, + 0x1F5A5, 0x1F5A5, + 0x1F5A6, 0x1F5A7, + 0x1F5A8, 0x1F5A8, + 0x1F5A9, 0x1F5B0, + 0x1F5B1, 0x1F5B2, + 0x1F5B3, 0x1F5BB, + 0x1F5BC, 0x1F5BC, + 0x1F5BD, 0x1F5C1, + 0x1F5C2, 0x1F5C4, + 0x1F5C5, 0x1F5D0, + 0x1F5D1, 0x1F5D3, + 0x1F5D4, 0x1F5DB, + 0x1F5DC, 0x1F5DE, + 0x1F5DF, 0x1F5E0, + 0x1F5E1, 0x1F5E1, + 0x1F5E2, 0x1F5E2, + 0x1F5E3, 0x1F5E3, + 0x1F5E4, 0x1F5E7, + 0x1F5E8, 0x1F5E8, + 0x1F5E9, 0x1F5EE, + 0x1F5EF, 0x1F5EF, + 0x1F5F0, 0x1F5F2, + 0x1F5F3, 0x1F5F3, + 0x1F5F4, 0x1F5F9, + 0x1F5FA, 0x1F5FA, + 0x1F5FB, 0x1F5FF, + 0x1F600, 0x1F600, + 0x1F601, 0x1F606, + 0x1F607, 0x1F608, + 0x1F609, 0x1F60D, + 0x1F60E, 0x1F60E, + 0x1F60F, 0x1F60F, + 0x1F610, 0x1F610, + 0x1F611, 0x1F611, + 0x1F612, 0x1F614, + 0x1F615, 0x1F615, + 0x1F616, 0x1F616, + 0x1F617, 0x1F617, + 0x1F618, 0x1F618, + 0x1F619, 0x1F619, + 0x1F61A, 0x1F61A, + 0x1F61B, 0x1F61B, + 0x1F61C, 0x1F61E, + 0x1F61F, 0x1F61F, + 0x1F620, 0x1F625, + 0x1F626, 0x1F627, + 0x1F628, 0x1F62B, + 0x1F62C, 0x1F62C, + 0x1F62D, 0x1F62D, + 0x1F62E, 0x1F62F, + 0x1F630, 0x1F633, + 0x1F634, 0x1F634, + 0x1F635, 0x1F635, + 0x1F636, 0x1F636, + 0x1F637, 0x1F640, + 0x1F641, 0x1F644, + 0x1F645, 0x1F64F, + 0x1F680, 0x1F680, + 0x1F681, 0x1F682, + 0x1F683, 0x1F685, + 0x1F686, 0x1F686, + 0x1F687, 0x1F687, + 0x1F688, 0x1F688, + 0x1F689, 0x1F689, + 0x1F68A, 0x1F68B, + 0x1F68C, 0x1F68C, + 0x1F68D, 0x1F68D, + 0x1F68E, 0x1F68E, + 0x1F68F, 0x1F68F, + 0x1F690, 0x1F690, + 0x1F691, 0x1F693, + 0x1F694, 0x1F694, + 0x1F695, 0x1F695, + 0x1F696, 0x1F696, + 0x1F697, 0x1F697, + 0x1F698, 0x1F698, + 0x1F699, 0x1F69A, + 0x1F69B, 0x1F6A1, + 0x1F6A2, 0x1F6A2, + 0x1F6A3, 0x1F6A3, + 0x1F6A4, 0x1F6A5, + 0x1F6A6, 0x1F6A6, + 0x1F6A7, 0x1F6AD, + 0x1F6AE, 0x1F6B1, + 0x1F6B2, 0x1F6B2, + 0x1F6B3, 0x1F6B5, + 0x1F6B6, 0x1F6B6, + 0x1F6B7, 0x1F6B8, + 0x1F6B9, 0x1F6BE, + 0x1F6BF, 0x1F6BF, + 0x1F6C0, 0x1F6C0, + 0x1F6C1, 0x1F6C5, + 0x1F6C6, 0x1F6CA, + 0x1F6CB, 0x1F6CB, + 0x1F6CC, 0x1F6CC, + 0x1F6CD, 0x1F6CF, + 0x1F6D0, 0x1F6D0, + 0x1F6D1, 0x1F6D2, + 0x1F6D3, 0x1F6D4, + 0x1F6D5, 0x1F6D5, + 0x1F6D6, 0x1F6D7, + 0x1F6D8, 0x1F6DB, + 0x1F6DC, 0x1F6DC, + 0x1F6DD, 0x1F6DF, + 0x1F6E0, 0x1F6E5, + 0x1F6E6, 0x1F6E8, + 0x1F6E9, 0x1F6E9, + 0x1F6EA, 0x1F6EA, + 0x1F6EB, 0x1F6EC, + 0x1F6ED, 0x1F6EF, + 0x1F6F0, 0x1F6F0, + 0x1F6F1, 0x1F6F2, + 0x1F6F3, 0x1F6F3, + 0x1F6F4, 0x1F6F6, + 0x1F6F7, 0x1F6F8, + 0x1F6F9, 0x1F6F9, + 0x1F6FA, 0x1F6FA, + 0x1F6FB, 0x1F6FC, + 0x1F6FD, 0x1F6FF, + 0x1F774, 0x1F77F, + 0x1F7D5, 0x1F7DF, + 0x1F7E0, 0x1F7EB, + 0x1F7EC, 0x1F7EF, + 0x1F7F0, 0x1F7F0, + 0x1F7F1, 0x1F7FF, + 0x1F80C, 0x1F80F, + 0x1F848, 0x1F84F, + 0x1F85A, 0x1F85F, + 0x1F888, 0x1F88F, + 0x1F8AE, 0x1F8FF, + 0x1F90C, 0x1F90C, + 0x1F90D, 0x1F90F, + 0x1F910, 0x1F918, + 0x1F919, 0x1F91E, + 0x1F91F, 0x1F91F, + 0x1F920, 0x1F927, + 0x1F928, 0x1F92F, + 0x1F930, 0x1F930, + 0x1F931, 0x1F932, + 0x1F933, 0x1F93A, + 0x1F93C, 0x1F93E, + 0x1F93F, 0x1F93F, + 0x1F940, 0x1F945, + 0x1F947, 0x1F94B, + 0x1F94C, 0x1F94C, + 0x1F94D, 0x1F94F, + 0x1F950, 0x1F95E, + 0x1F95F, 0x1F96B, + 0x1F96C, 0x1F970, + 0x1F971, 0x1F971, + 0x1F972, 0x1F972, + 0x1F973, 0x1F976, + 0x1F977, 0x1F978, + 0x1F979, 0x1F979, + 0x1F97A, 0x1F97A, + 0x1F97B, 0x1F97B, + 0x1F97C, 0x1F97F, + 0x1F980, 0x1F984, + 0x1F985, 0x1F991, + 0x1F992, 0x1F997, + 0x1F998, 0x1F9A2, + 0x1F9A3, 0x1F9A4, + 0x1F9A5, 0x1F9AA, + 0x1F9AB, 0x1F9AD, + 0x1F9AE, 0x1F9AF, + 0x1F9B0, 0x1F9B9, + 0x1F9BA, 0x1F9BF, + 0x1F9C0, 0x1F9C0, + 0x1F9C1, 0x1F9C2, + 0x1F9C3, 0x1F9CA, + 0x1F9CB, 0x1F9CB, + 0x1F9CC, 0x1F9CC, + 0x1F9CD, 0x1F9CF, + 0x1F9D0, 0x1F9E6, + 0x1F9E7, 0x1F9FF, + 0x1FA00, 0x1FA6F, + 0x1FA70, 0x1FA73, + 0x1FA74, 0x1FA74, + 0x1FA75, 0x1FA77, + 0x1FA78, 0x1FA7A, + 0x1FA7B, 0x1FA7C, + 0x1FA7D, 0x1FA7F, + 0x1FA80, 0x1FA82, + 0x1FA83, 0x1FA86, + 0x1FA87, 0x1FA88, + 0x1FA89, 0x1FA8F, + 0x1FA90, 0x1FA95, + 0x1FA96, 0x1FAA8, + 0x1FAA9, 0x1FAAC, + 0x1FAAD, 0x1FAAF, + 0x1FAB0, 0x1FAB6, + 0x1FAB7, 0x1FABA, + 0x1FABB, 0x1FABD, + 0x1FABE, 0x1FABE, + 0x1FABF, 0x1FABF, + 0x1FAC0, 0x1FAC2, + 0x1FAC3, 0x1FAC5, + 0x1FAC6, 0x1FACD, + 0x1FACE, 0x1FACF, + 0x1FAD0, 0x1FAD6, + 0x1FAD7, 0x1FAD9, + 0x1FADA, 0x1FADB, + 0x1FADC, 0x1FADF, + 0x1FAE0, 0x1FAE7, + 0x1FAE8, 0x1FAE8, + 0x1FAE9, 0x1FAEF, + 0x1FAF0, 0x1FAF6, + 0x1FAF7, 0x1FAF8, + 0x1FAF9, 0x1FAFF, + 0x1FC00, 0x1FFFD, +} + +@(rodata) +grapheme_extend_ranges := [?]i32 { + 0x0300, 0x036F, + 0x0483, 0x0487, + 0x0488, 0x0489, + 0x0591, 0x05BD, + 0x05BF, 0x05BF, + 0x05C1, 0x05C2, + 0x05C4, 0x05C5, + 0x05C7, 0x05C7, + 0x0610, 0x061A, + 0x064B, 0x065F, + 0x0670, 0x0670, + 0x06D6, 0x06DC, + 0x06DF, 0x06E4, + 0x06E7, 0x06E8, + 0x06EA, 0x06ED, + 0x0711, 0x0711, + 0x0730, 0x074A, + 0x07A6, 0x07B0, + 0x07EB, 0x07F3, + 0x07FD, 0x07FD, + 0x0816, 0x0819, + 0x081B, 0x0823, + 0x0825, 0x0827, + 0x0829, 0x082D, + 0x0859, 0x085B, + 0x0898, 0x089F, + 0x08CA, 0x08E1, + 0x08E3, 0x0902, + 0x093A, 0x093A, + 0x093C, 0x093C, + 0x0941, 0x0948, + 0x094D, 0x094D, + 0x0951, 0x0957, + 0x0962, 0x0963, + 0x0981, 0x0981, + 0x09BC, 0x09BC, + 0x09BE, 0x09BE, + 0x09C1, 0x09C4, + 0x09CD, 0x09CD, + 0x09D7, 0x09D7, + 0x09E2, 0x09E3, + 0x09FE, 0x09FE, + 0x0A01, 0x0A02, + 0x0A3C, 0x0A3C, + 0x0A41, 0x0A42, + 0x0A47, 0x0A48, + 0x0A4B, 0x0A4D, + 0x0A51, 0x0A51, + 0x0A70, 0x0A71, + 0x0A75, 0x0A75, + 0x0A81, 0x0A82, + 0x0ABC, 0x0ABC, + 0x0AC1, 0x0AC5, + 0x0AC7, 0x0AC8, + 0x0ACD, 0x0ACD, + 0x0AE2, 0x0AE3, + 0x0AFA, 0x0AFF, + 0x0B01, 0x0B01, + 0x0B3C, 0x0B3C, + 0x0B3E, 0x0B3E, + 0x0B3F, 0x0B3F, + 0x0B41, 0x0B44, + 0x0B4D, 0x0B4D, + 0x0B55, 0x0B56, + 0x0B57, 0x0B57, + 0x0B62, 0x0B63, + 0x0B82, 0x0B82, + 0x0BBE, 0x0BBE, + 0x0BC0, 0x0BC0, + 0x0BCD, 0x0BCD, + 0x0BD7, 0x0BD7, + 0x0C00, 0x0C00, + 0x0C04, 0x0C04, + 0x0C3C, 0x0C3C, + 0x0C3E, 0x0C40, + 0x0C46, 0x0C48, + 0x0C4A, 0x0C4D, + 0x0C55, 0x0C56, + 0x0C62, 0x0C63, + 0x0C81, 0x0C81, + 0x0CBC, 0x0CBC, + 0x0CBF, 0x0CBF, + 0x0CC2, 0x0CC2, + 0x0CC6, 0x0CC6, + 0x0CCC, 0x0CCD, + 0x0CD5, 0x0CD6, + 0x0CE2, 0x0CE3, + 0x0D00, 0x0D01, + 0x0D3B, 0x0D3C, + 0x0D3E, 0x0D3E, + 0x0D41, 0x0D44, + 0x0D4D, 0x0D4D, + 0x0D57, 0x0D57, + 0x0D62, 0x0D63, + 0x0D81, 0x0D81, + 0x0DCA, 0x0DCA, + 0x0DCF, 0x0DCF, + 0x0DD2, 0x0DD4, + 0x0DD6, 0x0DD6, + 0x0DDF, 0x0DDF, + 0x0E31, 0x0E31, + 0x0E34, 0x0E3A, + 0x0E47, 0x0E4E, + 0x0EB1, 0x0EB1, + 0x0EB4, 0x0EBC, + 0x0EC8, 0x0ECE, + 0x0F18, 0x0F19, + 0x0F35, 0x0F35, + 0x0F37, 0x0F37, + 0x0F39, 0x0F39, + 0x0F71, 0x0F7E, + 0x0F80, 0x0F84, + 0x0F86, 0x0F87, + 0x0F8D, 0x0F97, + 0x0F99, 0x0FBC, + 0x0FC6, 0x0FC6, + 0x102D, 0x1030, + 0x1032, 0x1037, + 0x1039, 0x103A, + 0x103D, 0x103E, + 0x1058, 0x1059, + 0x105E, 0x1060, + 0x1071, 0x1074, + 0x1082, 0x1082, + 0x1085, 0x1086, + 0x108D, 0x108D, + 0x109D, 0x109D, + 0x135D, 0x135F, + 0x1712, 0x1714, + 0x1732, 0x1733, + 0x1752, 0x1753, + 0x1772, 0x1773, + 0x17B4, 0x17B5, + 0x17B7, 0x17BD, + 0x17C6, 0x17C6, + 0x17C9, 0x17D3, + 0x17DD, 0x17DD, + 0x180B, 0x180D, + 0x180F, 0x180F, + 0x1885, 0x1886, + 0x18A9, 0x18A9, + 0x1920, 0x1922, + 0x1927, 0x1928, + 0x1932, 0x1932, + 0x1939, 0x193B, + 0x1A17, 0x1A18, + 0x1A1B, 0x1A1B, + 0x1A56, 0x1A56, + 0x1A58, 0x1A5E, + 0x1A60, 0x1A60, + 0x1A62, 0x1A62, + 0x1A65, 0x1A6C, + 0x1A73, 0x1A7C, + 0x1A7F, 0x1A7F, + 0x1AB0, 0x1ABD, + 0x1ABE, 0x1ABE, + 0x1ABF, 0x1ACE, + 0x1B00, 0x1B03, + 0x1B34, 0x1B34, + 0x1B35, 0x1B35, + 0x1B36, 0x1B3A, + 0x1B3C, 0x1B3C, + 0x1B42, 0x1B42, + 0x1B6B, 0x1B73, + 0x1B80, 0x1B81, + 0x1BA2, 0x1BA5, + 0x1BA8, 0x1BA9, + 0x1BAB, 0x1BAD, + 0x1BE6, 0x1BE6, + 0x1BE8, 0x1BE9, + 0x1BED, 0x1BED, + 0x1BEF, 0x1BF1, + 0x1C2C, 0x1C33, + 0x1C36, 0x1C37, + 0x1CD0, 0x1CD2, + 0x1CD4, 0x1CE0, + 0x1CE2, 0x1CE8, + 0x1CED, 0x1CED, + 0x1CF4, 0x1CF4, + 0x1CF8, 0x1CF9, + 0x1DC0, 0x1DFF, + 0x200C, 0x200C, + 0x20D0, 0x20DC, + 0x20DD, 0x20E0, + 0x20E1, 0x20E1, + 0x20E2, 0x20E4, + 0x20E5, 0x20F0, + 0x2CEF, 0x2CF1, + 0x2D7F, 0x2D7F, + 0x2DE0, 0x2DFF, + 0x302A, 0x302D, + 0x302E, 0x302F, + 0x3099, 0x309A, + 0xA66F, 0xA66F, + 0xA670, 0xA672, + 0xA674, 0xA67D, + 0xA69E, 0xA69F, + 0xA6F0, 0xA6F1, + 0xA802, 0xA802, + 0xA806, 0xA806, + 0xA80B, 0xA80B, + 0xA825, 0xA826, + 0xA82C, 0xA82C, + 0xA8C4, 0xA8C5, + 0xA8E0, 0xA8F1, + 0xA8FF, 0xA8FF, + 0xA926, 0xA92D, + 0xA947, 0xA951, + 0xA980, 0xA982, + 0xA9B3, 0xA9B3, + 0xA9B6, 0xA9B9, + 0xA9BC, 0xA9BD, + 0xA9E5, 0xA9E5, + 0xAA29, 0xAA2E, + 0xAA31, 0xAA32, + 0xAA35, 0xAA36, + 0xAA43, 0xAA43, + 0xAA4C, 0xAA4C, + 0xAA7C, 0xAA7C, + 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, + 0xAAB7, 0xAAB8, + 0xAABE, 0xAABF, + 0xAAC1, 0xAAC1, + 0xAAEC, 0xAAED, + 0xAAF6, 0xAAF6, + 0xABE5, 0xABE5, + 0xABE8, 0xABE8, + 0xABED, 0xABED, + 0xFB1E, 0xFB1E, + 0xFE00, 0xFE0F, + 0xFE20, 0xFE2F, + 0xFF9E, 0xFF9F, + 0x101FD, 0x101FD, + 0x102E0, 0x102E0, + 0x10376, 0x1037A, + 0x10A01, 0x10A03, + 0x10A05, 0x10A06, + 0x10A0C, 0x10A0F, + 0x10A38, 0x10A3A, + 0x10A3F, 0x10A3F, + 0x10AE5, 0x10AE6, + 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, + 0x10EFD, 0x10EFF, + 0x10F46, 0x10F50, + 0x10F82, 0x10F85, + 0x11001, 0x11001, + 0x11038, 0x11046, + 0x11070, 0x11070, + 0x11073, 0x11074, + 0x1107F, 0x11081, + 0x110B3, 0x110B6, + 0x110B9, 0x110BA, + 0x110C2, 0x110C2, + 0x11100, 0x11102, + 0x11127, 0x1112B, + 0x1112D, 0x11134, + 0x11173, 0x11173, + 0x11180, 0x11181, + 0x111B6, 0x111BE, + 0x111C9, 0x111CC, + 0x111CF, 0x111CF, + 0x1122F, 0x11231, + 0x11234, 0x11234, + 0x11236, 0x11237, + 0x1123E, 0x1123E, + 0x11241, 0x11241, + 0x112DF, 0x112DF, + 0x112E3, 0x112EA, + 0x11300, 0x11301, + 0x1133B, 0x1133C, + 0x1133E, 0x1133E, + 0x11340, 0x11340, + 0x11357, 0x11357, + 0x11366, 0x1136C, + 0x11370, 0x11374, + 0x11438, 0x1143F, + 0x11442, 0x11444, + 0x11446, 0x11446, + 0x1145E, 0x1145E, + 0x114B0, 0x114B0, + 0x114B3, 0x114B8, + 0x114BA, 0x114BA, + 0x114BD, 0x114BD, + 0x114BF, 0x114C0, + 0x114C2, 0x114C3, + 0x115AF, 0x115AF, + 0x115B2, 0x115B5, + 0x115BC, 0x115BD, + 0x115BF, 0x115C0, + 0x115DC, 0x115DD, + 0x11633, 0x1163A, + 0x1163D, 0x1163D, + 0x1163F, 0x11640, + 0x116AB, 0x116AB, + 0x116AD, 0x116AD, + 0x116B0, 0x116B5, + 0x116B7, 0x116B7, + 0x1171D, 0x1171F, + 0x11722, 0x11725, + 0x11727, 0x1172B, + 0x1182F, 0x11837, + 0x11839, 0x1183A, + 0x11930, 0x11930, + 0x1193B, 0x1193C, + 0x1193E, 0x1193E, + 0x11943, 0x11943, + 0x119D4, 0x119D7, + 0x119DA, 0x119DB, + 0x119E0, 0x119E0, + 0x11A01, 0x11A0A, + 0x11A33, 0x11A38, + 0x11A3B, 0x11A3E, + 0x11A47, 0x11A47, + 0x11A51, 0x11A56, + 0x11A59, 0x11A5B, + 0x11A8A, 0x11A96, + 0x11A98, 0x11A99, + 0x11C30, 0x11C36, + 0x11C38, 0x11C3D, + 0x11C3F, 0x11C3F, + 0x11C92, 0x11CA7, + 0x11CAA, 0x11CB0, + 0x11CB2, 0x11CB3, + 0x11CB5, 0x11CB6, + 0x11D31, 0x11D36, + 0x11D3A, 0x11D3A, + 0x11D3C, 0x11D3D, + 0x11D3F, 0x11D45, + 0x11D47, 0x11D47, + 0x11D90, 0x11D91, + 0x11D95, 0x11D95, + 0x11D97, 0x11D97, + 0x11EF3, 0x11EF4, + 0x11F00, 0x11F01, + 0x11F36, 0x11F3A, + 0x11F40, 0x11F40, + 0x11F42, 0x11F42, + 0x13440, 0x13440, + 0x13447, 0x13455, + 0x16AF0, 0x16AF4, + 0x16B30, 0x16B36, + 0x16F4F, 0x16F4F, + 0x16F8F, 0x16F92, + 0x16FE4, 0x16FE4, + 0x1BC9D, 0x1BC9E, + 0x1CF00, 0x1CF2D, + 0x1CF30, 0x1CF46, + 0x1D165, 0x1D165, + 0x1D167, 0x1D169, + 0x1D16E, 0x1D172, + 0x1D17B, 0x1D182, + 0x1D185, 0x1D18B, + 0x1D1AA, 0x1D1AD, + 0x1D242, 0x1D244, + 0x1DA00, 0x1DA36, + 0x1DA3B, 0x1DA6C, + 0x1DA75, 0x1DA75, + 0x1DA84, 0x1DA84, + 0x1DA9B, 0x1DA9F, + 0x1DAA1, 0x1DAAF, + 0x1E000, 0x1E006, + 0x1E008, 0x1E018, + 0x1E01B, 0x1E021, + 0x1E023, 0x1E024, + 0x1E026, 0x1E02A, + 0x1E08F, 0x1E08F, + 0x1E130, 0x1E136, + 0x1E2AE, 0x1E2AE, + 0x1E2EC, 0x1E2EF, + 0x1E4EC, 0x1E4EF, + 0x1E8D0, 0x1E8D6, + 0x1E944, 0x1E94A, + 0xE0020, 0xE007F, + 0xE0100, 0xE01EF, +} + +@(rodata) +hangul_syllable_lv_singlets := [?]i32 { + 0xAC00, + 0xAC1C, + 0xAC38, + 0xAC54, + 0xAC70, + 0xAC8C, + 0xACA8, + 0xACC4, + 0xACE0, + 0xACFC, + 0xAD18, + 0xAD34, + 0xAD50, + 0xAD6C, + 0xAD88, + 0xADA4, + 0xADC0, + 0xADDC, + 0xADF8, + 0xAE14, + 0xAE30, + 0xAE4C, + 0xAE68, + 0xAE84, + 0xAEA0, + 0xAEBC, + 0xAED8, + 0xAEF4, + 0xAF10, + 0xAF2C, + 0xAF48, + 0xAF64, + 0xAF80, + 0xAF9C, + 0xAFB8, + 0xAFD4, + 0xAFF0, + 0xB00C, + 0xB028, + 0xB044, + 0xB060, + 0xB07C, + 0xB098, + 0xB0B4, + 0xB0D0, + 0xB0EC, + 0xB108, + 0xB124, + 0xB140, + 0xB15C, + 0xB178, + 0xB194, + 0xB1B0, + 0xB1CC, + 0xB1E8, + 0xB204, + 0xB220, + 0xB23C, + 0xB258, + 0xB274, + 0xB290, + 0xB2AC, + 0xB2C8, + 0xB2E4, + 0xB300, + 0xB31C, + 0xB338, + 0xB354, + 0xB370, + 0xB38C, + 0xB3A8, + 0xB3C4, + 0xB3E0, + 0xB3FC, + 0xB418, + 0xB434, + 0xB450, + 0xB46C, + 0xB488, + 0xB4A4, + 0xB4C0, + 0xB4DC, + 0xB4F8, + 0xB514, + 0xB530, + 0xB54C, + 0xB568, + 0xB584, + 0xB5A0, + 0xB5BC, + 0xB5D8, + 0xB5F4, + 0xB610, + 0xB62C, + 0xB648, + 0xB664, + 0xB680, + 0xB69C, + 0xB6B8, + 0xB6D4, + 0xB6F0, + 0xB70C, + 0xB728, + 0xB744, + 0xB760, + 0xB77C, + 0xB798, + 0xB7B4, + 0xB7D0, + 0xB7EC, + 0xB808, + 0xB824, + 0xB840, + 0xB85C, + 0xB878, + 0xB894, + 0xB8B0, + 0xB8CC, + 0xB8E8, + 0xB904, + 0xB920, + 0xB93C, + 0xB958, + 0xB974, + 0xB990, + 0xB9AC, + 0xB9C8, + 0xB9E4, + 0xBA00, + 0xBA1C, + 0xBA38, + 0xBA54, + 0xBA70, + 0xBA8C, + 0xBAA8, + 0xBAC4, + 0xBAE0, + 0xBAFC, + 0xBB18, + 0xBB34, + 0xBB50, + 0xBB6C, + 0xBB88, + 0xBBA4, + 0xBBC0, + 0xBBDC, + 0xBBF8, + 0xBC14, + 0xBC30, + 0xBC4C, + 0xBC68, + 0xBC84, + 0xBCA0, + 0xBCBC, + 0xBCD8, + 0xBCF4, + 0xBD10, + 0xBD2C, + 0xBD48, + 0xBD64, + 0xBD80, + 0xBD9C, + 0xBDB8, + 0xBDD4, + 0xBDF0, + 0xBE0C, + 0xBE28, + 0xBE44, + 0xBE60, + 0xBE7C, + 0xBE98, + 0xBEB4, + 0xBED0, + 0xBEEC, + 0xBF08, + 0xBF24, + 0xBF40, + 0xBF5C, + 0xBF78, + 0xBF94, + 0xBFB0, + 0xBFCC, + 0xBFE8, + 0xC004, + 0xC020, + 0xC03C, + 0xC058, + 0xC074, + 0xC090, + 0xC0AC, + 0xC0C8, + 0xC0E4, + 0xC100, + 0xC11C, + 0xC138, + 0xC154, + 0xC170, + 0xC18C, + 0xC1A8, + 0xC1C4, + 0xC1E0, + 0xC1FC, + 0xC218, + 0xC234, + 0xC250, + 0xC26C, + 0xC288, + 0xC2A4, + 0xC2C0, + 0xC2DC, + 0xC2F8, + 0xC314, + 0xC330, + 0xC34C, + 0xC368, + 0xC384, + 0xC3A0, + 0xC3BC, + 0xC3D8, + 0xC3F4, + 0xC410, + 0xC42C, + 0xC448, + 0xC464, + 0xC480, + 0xC49C, + 0xC4B8, + 0xC4D4, + 0xC4F0, + 0xC50C, + 0xC528, + 0xC544, + 0xC560, + 0xC57C, + 0xC598, + 0xC5B4, + 0xC5D0, + 0xC5EC, + 0xC608, + 0xC624, + 0xC640, + 0xC65C, + 0xC678, + 0xC694, + 0xC6B0, + 0xC6CC, + 0xC6E8, + 0xC704, + 0xC720, + 0xC73C, + 0xC758, + 0xC774, + 0xC790, + 0xC7AC, + 0xC7C8, + 0xC7E4, + 0xC800, + 0xC81C, + 0xC838, + 0xC854, + 0xC870, + 0xC88C, + 0xC8A8, + 0xC8C4, + 0xC8E0, + 0xC8FC, + 0xC918, + 0xC934, + 0xC950, + 0xC96C, + 0xC988, + 0xC9A4, + 0xC9C0, + 0xC9DC, + 0xC9F8, + 0xCA14, + 0xCA30, + 0xCA4C, + 0xCA68, + 0xCA84, + 0xCAA0, + 0xCABC, + 0xCAD8, + 0xCAF4, + 0xCB10, + 0xCB2C, + 0xCB48, + 0xCB64, + 0xCB80, + 0xCB9C, + 0xCBB8, + 0xCBD4, + 0xCBF0, + 0xCC0C, + 0xCC28, + 0xCC44, + 0xCC60, + 0xCC7C, + 0xCC98, + 0xCCB4, + 0xCCD0, + 0xCCEC, + 0xCD08, + 0xCD24, + 0xCD40, + 0xCD5C, + 0xCD78, + 0xCD94, + 0xCDB0, + 0xCDCC, + 0xCDE8, + 0xCE04, + 0xCE20, + 0xCE3C, + 0xCE58, + 0xCE74, + 0xCE90, + 0xCEAC, + 0xCEC8, + 0xCEE4, + 0xCF00, + 0xCF1C, + 0xCF38, + 0xCF54, + 0xCF70, + 0xCF8C, + 0xCFA8, + 0xCFC4, + 0xCFE0, + 0xCFFC, + 0xD018, + 0xD034, + 0xD050, + 0xD06C, + 0xD088, + 0xD0A4, + 0xD0C0, + 0xD0DC, + 0xD0F8, + 0xD114, + 0xD130, + 0xD14C, + 0xD168, + 0xD184, + 0xD1A0, + 0xD1BC, + 0xD1D8, + 0xD1F4, + 0xD210, + 0xD22C, + 0xD248, + 0xD264, + 0xD280, + 0xD29C, + 0xD2B8, + 0xD2D4, + 0xD2F0, + 0xD30C, + 0xD328, + 0xD344, + 0xD360, + 0xD37C, + 0xD398, + 0xD3B4, + 0xD3D0, + 0xD3EC, + 0xD408, + 0xD424, + 0xD440, + 0xD45C, + 0xD478, + 0xD494, + 0xD4B0, + 0xD4CC, + 0xD4E8, + 0xD504, + 0xD520, + 0xD53C, + 0xD558, + 0xD574, + 0xD590, + 0xD5AC, + 0xD5C8, + 0xD5E4, + 0xD600, + 0xD61C, + 0xD638, + 0xD654, + 0xD670, + 0xD68C, + 0xD6A8, + 0xD6C4, + 0xD6E0, + 0xD6FC, + 0xD718, + 0xD734, + 0xD750, + 0xD76C, + 0xD788, +} + +@(rodata) +hangul_syllable_lvt_ranges := [?]i32 { + 0xAC01, 0xAC1B, + 0xAC1D, 0xAC37, + 0xAC39, 0xAC53, + 0xAC55, 0xAC6F, + 0xAC71, 0xAC8B, + 0xAC8D, 0xACA7, + 0xACA9, 0xACC3, + 0xACC5, 0xACDF, + 0xACE1, 0xACFB, + 0xACFD, 0xAD17, + 0xAD19, 0xAD33, + 0xAD35, 0xAD4F, + 0xAD51, 0xAD6B, + 0xAD6D, 0xAD87, + 0xAD89, 0xADA3, + 0xADA5, 0xADBF, + 0xADC1, 0xADDB, + 0xADDD, 0xADF7, + 0xADF9, 0xAE13, + 0xAE15, 0xAE2F, + 0xAE31, 0xAE4B, + 0xAE4D, 0xAE67, + 0xAE69, 0xAE83, + 0xAE85, 0xAE9F, + 0xAEA1, 0xAEBB, + 0xAEBD, 0xAED7, + 0xAED9, 0xAEF3, + 0xAEF5, 0xAF0F, + 0xAF11, 0xAF2B, + 0xAF2D, 0xAF47, + 0xAF49, 0xAF63, + 0xAF65, 0xAF7F, + 0xAF81, 0xAF9B, + 0xAF9D, 0xAFB7, + 0xAFB9, 0xAFD3, + 0xAFD5, 0xAFEF, + 0xAFF1, 0xB00B, + 0xB00D, 0xB027, + 0xB029, 0xB043, + 0xB045, 0xB05F, + 0xB061, 0xB07B, + 0xB07D, 0xB097, + 0xB099, 0xB0B3, + 0xB0B5, 0xB0CF, + 0xB0D1, 0xB0EB, + 0xB0ED, 0xB107, + 0xB109, 0xB123, + 0xB125, 0xB13F, + 0xB141, 0xB15B, + 0xB15D, 0xB177, + 0xB179, 0xB193, + 0xB195, 0xB1AF, + 0xB1B1, 0xB1CB, + 0xB1CD, 0xB1E7, + 0xB1E9, 0xB203, + 0xB205, 0xB21F, + 0xB221, 0xB23B, + 0xB23D, 0xB257, + 0xB259, 0xB273, + 0xB275, 0xB28F, + 0xB291, 0xB2AB, + 0xB2AD, 0xB2C7, + 0xB2C9, 0xB2E3, + 0xB2E5, 0xB2FF, + 0xB301, 0xB31B, + 0xB31D, 0xB337, + 0xB339, 0xB353, + 0xB355, 0xB36F, + 0xB371, 0xB38B, + 0xB38D, 0xB3A7, + 0xB3A9, 0xB3C3, + 0xB3C5, 0xB3DF, + 0xB3E1, 0xB3FB, + 0xB3FD, 0xB417, + 0xB419, 0xB433, + 0xB435, 0xB44F, + 0xB451, 0xB46B, + 0xB46D, 0xB487, + 0xB489, 0xB4A3, + 0xB4A5, 0xB4BF, + 0xB4C1, 0xB4DB, + 0xB4DD, 0xB4F7, + 0xB4F9, 0xB513, + 0xB515, 0xB52F, + 0xB531, 0xB54B, + 0xB54D, 0xB567, + 0xB569, 0xB583, + 0xB585, 0xB59F, + 0xB5A1, 0xB5BB, + 0xB5BD, 0xB5D7, + 0xB5D9, 0xB5F3, + 0xB5F5, 0xB60F, + 0xB611, 0xB62B, + 0xB62D, 0xB647, + 0xB649, 0xB663, + 0xB665, 0xB67F, + 0xB681, 0xB69B, + 0xB69D, 0xB6B7, + 0xB6B9, 0xB6D3, + 0xB6D5, 0xB6EF, + 0xB6F1, 0xB70B, + 0xB70D, 0xB727, + 0xB729, 0xB743, + 0xB745, 0xB75F, + 0xB761, 0xB77B, + 0xB77D, 0xB797, + 0xB799, 0xB7B3, + 0xB7B5, 0xB7CF, + 0xB7D1, 0xB7EB, + 0xB7ED, 0xB807, + 0xB809, 0xB823, + 0xB825, 0xB83F, + 0xB841, 0xB85B, + 0xB85D, 0xB877, + 0xB879, 0xB893, + 0xB895, 0xB8AF, + 0xB8B1, 0xB8CB, + 0xB8CD, 0xB8E7, + 0xB8E9, 0xB903, + 0xB905, 0xB91F, + 0xB921, 0xB93B, + 0xB93D, 0xB957, + 0xB959, 0xB973, + 0xB975, 0xB98F, + 0xB991, 0xB9AB, + 0xB9AD, 0xB9C7, + 0xB9C9, 0xB9E3, + 0xB9E5, 0xB9FF, + 0xBA01, 0xBA1B, + 0xBA1D, 0xBA37, + 0xBA39, 0xBA53, + 0xBA55, 0xBA6F, + 0xBA71, 0xBA8B, + 0xBA8D, 0xBAA7, + 0xBAA9, 0xBAC3, + 0xBAC5, 0xBADF, + 0xBAE1, 0xBAFB, + 0xBAFD, 0xBB17, + 0xBB19, 0xBB33, + 0xBB35, 0xBB4F, + 0xBB51, 0xBB6B, + 0xBB6D, 0xBB87, + 0xBB89, 0xBBA3, + 0xBBA5, 0xBBBF, + 0xBBC1, 0xBBDB, + 0xBBDD, 0xBBF7, + 0xBBF9, 0xBC13, + 0xBC15, 0xBC2F, + 0xBC31, 0xBC4B, + 0xBC4D, 0xBC67, + 0xBC69, 0xBC83, + 0xBC85, 0xBC9F, + 0xBCA1, 0xBCBB, + 0xBCBD, 0xBCD7, + 0xBCD9, 0xBCF3, + 0xBCF5, 0xBD0F, + 0xBD11, 0xBD2B, + 0xBD2D, 0xBD47, + 0xBD49, 0xBD63, + 0xBD65, 0xBD7F, + 0xBD81, 0xBD9B, + 0xBD9D, 0xBDB7, + 0xBDB9, 0xBDD3, + 0xBDD5, 0xBDEF, + 0xBDF1, 0xBE0B, + 0xBE0D, 0xBE27, + 0xBE29, 0xBE43, + 0xBE45, 0xBE5F, + 0xBE61, 0xBE7B, + 0xBE7D, 0xBE97, + 0xBE99, 0xBEB3, + 0xBEB5, 0xBECF, + 0xBED1, 0xBEEB, + 0xBEED, 0xBF07, + 0xBF09, 0xBF23, + 0xBF25, 0xBF3F, + 0xBF41, 0xBF5B, + 0xBF5D, 0xBF77, + 0xBF79, 0xBF93, + 0xBF95, 0xBFAF, + 0xBFB1, 0xBFCB, + 0xBFCD, 0xBFE7, + 0xBFE9, 0xC003, + 0xC005, 0xC01F, + 0xC021, 0xC03B, + 0xC03D, 0xC057, + 0xC059, 0xC073, + 0xC075, 0xC08F, + 0xC091, 0xC0AB, + 0xC0AD, 0xC0C7, + 0xC0C9, 0xC0E3, + 0xC0E5, 0xC0FF, + 0xC101, 0xC11B, + 0xC11D, 0xC137, + 0xC139, 0xC153, + 0xC155, 0xC16F, + 0xC171, 0xC18B, + 0xC18D, 0xC1A7, + 0xC1A9, 0xC1C3, + 0xC1C5, 0xC1DF, + 0xC1E1, 0xC1FB, + 0xC1FD, 0xC217, + 0xC219, 0xC233, + 0xC235, 0xC24F, + 0xC251, 0xC26B, + 0xC26D, 0xC287, + 0xC289, 0xC2A3, + 0xC2A5, 0xC2BF, + 0xC2C1, 0xC2DB, + 0xC2DD, 0xC2F7, + 0xC2F9, 0xC313, + 0xC315, 0xC32F, + 0xC331, 0xC34B, + 0xC34D, 0xC367, + 0xC369, 0xC383, + 0xC385, 0xC39F, + 0xC3A1, 0xC3BB, + 0xC3BD, 0xC3D7, + 0xC3D9, 0xC3F3, + 0xC3F5, 0xC40F, + 0xC411, 0xC42B, + 0xC42D, 0xC447, + 0xC449, 0xC463, + 0xC465, 0xC47F, + 0xC481, 0xC49B, + 0xC49D, 0xC4B7, + 0xC4B9, 0xC4D3, + 0xC4D5, 0xC4EF, + 0xC4F1, 0xC50B, + 0xC50D, 0xC527, + 0xC529, 0xC543, + 0xC545, 0xC55F, + 0xC561, 0xC57B, + 0xC57D, 0xC597, + 0xC599, 0xC5B3, + 0xC5B5, 0xC5CF, + 0xC5D1, 0xC5EB, + 0xC5ED, 0xC607, + 0xC609, 0xC623, + 0xC625, 0xC63F, + 0xC641, 0xC65B, + 0xC65D, 0xC677, + 0xC679, 0xC693, + 0xC695, 0xC6AF, + 0xC6B1, 0xC6CB, + 0xC6CD, 0xC6E7, + 0xC6E9, 0xC703, + 0xC705, 0xC71F, + 0xC721, 0xC73B, + 0xC73D, 0xC757, + 0xC759, 0xC773, + 0xC775, 0xC78F, + 0xC791, 0xC7AB, + 0xC7AD, 0xC7C7, + 0xC7C9, 0xC7E3, + 0xC7E5, 0xC7FF, + 0xC801, 0xC81B, + 0xC81D, 0xC837, + 0xC839, 0xC853, + 0xC855, 0xC86F, + 0xC871, 0xC88B, + 0xC88D, 0xC8A7, + 0xC8A9, 0xC8C3, + 0xC8C5, 0xC8DF, + 0xC8E1, 0xC8FB, + 0xC8FD, 0xC917, + 0xC919, 0xC933, + 0xC935, 0xC94F, + 0xC951, 0xC96B, + 0xC96D, 0xC987, + 0xC989, 0xC9A3, + 0xC9A5, 0xC9BF, + 0xC9C1, 0xC9DB, + 0xC9DD, 0xC9F7, + 0xC9F9, 0xCA13, + 0xCA15, 0xCA2F, + 0xCA31, 0xCA4B, + 0xCA4D, 0xCA67, + 0xCA69, 0xCA83, + 0xCA85, 0xCA9F, + 0xCAA1, 0xCABB, + 0xCABD, 0xCAD7, + 0xCAD9, 0xCAF3, + 0xCAF5, 0xCB0F, + 0xCB11, 0xCB2B, + 0xCB2D, 0xCB47, + 0xCB49, 0xCB63, + 0xCB65, 0xCB7F, + 0xCB81, 0xCB9B, + 0xCB9D, 0xCBB7, + 0xCBB9, 0xCBD3, + 0xCBD5, 0xCBEF, + 0xCBF1, 0xCC0B, + 0xCC0D, 0xCC27, + 0xCC29, 0xCC43, + 0xCC45, 0xCC5F, + 0xCC61, 0xCC7B, + 0xCC7D, 0xCC97, + 0xCC99, 0xCCB3, + 0xCCB5, 0xCCCF, + 0xCCD1, 0xCCEB, + 0xCCED, 0xCD07, + 0xCD09, 0xCD23, + 0xCD25, 0xCD3F, + 0xCD41, 0xCD5B, + 0xCD5D, 0xCD77, + 0xCD79, 0xCD93, + 0xCD95, 0xCDAF, + 0xCDB1, 0xCDCB, + 0xCDCD, 0xCDE7, + 0xCDE9, 0xCE03, + 0xCE05, 0xCE1F, + 0xCE21, 0xCE3B, + 0xCE3D, 0xCE57, + 0xCE59, 0xCE73, + 0xCE75, 0xCE8F, + 0xCE91, 0xCEAB, + 0xCEAD, 0xCEC7, + 0xCEC9, 0xCEE3, + 0xCEE5, 0xCEFF, + 0xCF01, 0xCF1B, + 0xCF1D, 0xCF37, + 0xCF39, 0xCF53, + 0xCF55, 0xCF6F, + 0xCF71, 0xCF8B, + 0xCF8D, 0xCFA7, + 0xCFA9, 0xCFC3, + 0xCFC5, 0xCFDF, + 0xCFE1, 0xCFFB, + 0xCFFD, 0xD017, + 0xD019, 0xD033, + 0xD035, 0xD04F, + 0xD051, 0xD06B, + 0xD06D, 0xD087, + 0xD089, 0xD0A3, + 0xD0A5, 0xD0BF, + 0xD0C1, 0xD0DB, + 0xD0DD, 0xD0F7, + 0xD0F9, 0xD113, + 0xD115, 0xD12F, + 0xD131, 0xD14B, + 0xD14D, 0xD167, + 0xD169, 0xD183, + 0xD185, 0xD19F, + 0xD1A1, 0xD1BB, + 0xD1BD, 0xD1D7, + 0xD1D9, 0xD1F3, + 0xD1F5, 0xD20F, + 0xD211, 0xD22B, + 0xD22D, 0xD247, + 0xD249, 0xD263, + 0xD265, 0xD27F, + 0xD281, 0xD29B, + 0xD29D, 0xD2B7, + 0xD2B9, 0xD2D3, + 0xD2D5, 0xD2EF, + 0xD2F1, 0xD30B, + 0xD30D, 0xD327, + 0xD329, 0xD343, + 0xD345, 0xD35F, + 0xD361, 0xD37B, + 0xD37D, 0xD397, + 0xD399, 0xD3B3, + 0xD3B5, 0xD3CF, + 0xD3D1, 0xD3EB, + 0xD3ED, 0xD407, + 0xD409, 0xD423, + 0xD425, 0xD43F, + 0xD441, 0xD45B, + 0xD45D, 0xD477, + 0xD479, 0xD493, + 0xD495, 0xD4AF, + 0xD4B1, 0xD4CB, + 0xD4CD, 0xD4E7, + 0xD4E9, 0xD503, + 0xD505, 0xD51F, + 0xD521, 0xD53B, + 0xD53D, 0xD557, + 0xD559, 0xD573, + 0xD575, 0xD58F, + 0xD591, 0xD5AB, + 0xD5AD, 0xD5C7, + 0xD5C9, 0xD5E3, + 0xD5E5, 0xD5FF, + 0xD601, 0xD61B, + 0xD61D, 0xD637, + 0xD639, 0xD653, + 0xD655, 0xD66F, + 0xD671, 0xD68B, + 0xD68D, 0xD6A7, + 0xD6A9, 0xD6C3, + 0xD6C5, 0xD6DF, + 0xD6E1, 0xD6FB, + 0xD6FD, 0xD717, + 0xD719, 0xD733, + 0xD735, 0xD74F, + 0xD751, 0xD76B, + 0xD76D, 0xD787, + 0xD789, 0xD7A3, +} + +@(rodata) +indic_conjunct_break_consonant_ranges := [?]i32 { + 0x0915, 0x0939, + 0x0958, 0x095F, + 0x0978, 0x097F, + 0x0995, 0x09A8, + 0x09AA, 0x09B0, + 0x09B2, 0x09B2, + 0x09B6, 0x09B9, + 0x09DC, 0x09DD, + 0x09DF, 0x09DF, + 0x09F0, 0x09F1, + 0x0A95, 0x0AA8, + 0x0AAA, 0x0AB0, + 0x0AB2, 0x0AB3, + 0x0AB5, 0x0AB9, + 0x0AF9, 0x0AF9, + 0x0B15, 0x0B28, + 0x0B2A, 0x0B30, + 0x0B32, 0x0B33, + 0x0B35, 0x0B39, + 0x0B5C, 0x0B5D, + 0x0B5F, 0x0B5F, + 0x0B71, 0x0B71, + 0x0C15, 0x0C28, + 0x0C2A, 0x0C39, + 0x0C58, 0x0C5A, + 0x0D15, 0x0D3A, +} + +@(rodata) +indic_conjunct_break_extend_ranges := [?]i32 { + 0x0300, 0x034E, + 0x0350, 0x036F, + 0x0483, 0x0487, + 0x0591, 0x05BD, + 0x05BF, 0x05BF, + 0x05C1, 0x05C2, + 0x05C4, 0x05C5, + 0x05C7, 0x05C7, + 0x0610, 0x061A, + 0x064B, 0x065F, + 0x0670, 0x0670, + 0x06D6, 0x06DC, + 0x06DF, 0x06E4, + 0x06E7, 0x06E8, + 0x06EA, 0x06ED, + 0x0711, 0x0711, + 0x0730, 0x074A, + 0x07EB, 0x07F3, + 0x07FD, 0x07FD, + 0x0816, 0x0819, + 0x081B, 0x0823, + 0x0825, 0x0827, + 0x0829, 0x082D, + 0x0859, 0x085B, + 0x0898, 0x089F, + 0x08CA, 0x08E1, + 0x08E3, 0x08FF, + 0x093C, 0x093C, + 0x0951, 0x0954, + 0x09BC, 0x09BC, + 0x09FE, 0x09FE, + 0x0A3C, 0x0A3C, + 0x0ABC, 0x0ABC, + 0x0B3C, 0x0B3C, + 0x0C3C, 0x0C3C, + 0x0C55, 0x0C56, + 0x0CBC, 0x0CBC, + 0x0D3B, 0x0D3C, + 0x0E38, 0x0E3A, + 0x0E48, 0x0E4B, + 0x0EB8, 0x0EBA, + 0x0EC8, 0x0ECB, + 0x0F18, 0x0F19, + 0x0F35, 0x0F35, + 0x0F37, 0x0F37, + 0x0F39, 0x0F39, + 0x0F71, 0x0F72, + 0x0F74, 0x0F74, + 0x0F7A, 0x0F7D, + 0x0F80, 0x0F80, + 0x0F82, 0x0F84, + 0x0F86, 0x0F87, + 0x0FC6, 0x0FC6, + 0x1037, 0x1037, + 0x1039, 0x103A, + 0x108D, 0x108D, + 0x135D, 0x135F, + 0x1714, 0x1714, + 0x17D2, 0x17D2, + 0x17DD, 0x17DD, + 0x18A9, 0x18A9, + 0x1939, 0x193B, + 0x1A17, 0x1A18, + 0x1A60, 0x1A60, + 0x1A75, 0x1A7C, + 0x1A7F, 0x1A7F, + 0x1AB0, 0x1ABD, + 0x1ABF, 0x1ACE, + 0x1B34, 0x1B34, + 0x1B6B, 0x1B73, + 0x1BAB, 0x1BAB, + 0x1BE6, 0x1BE6, + 0x1C37, 0x1C37, + 0x1CD0, 0x1CD2, + 0x1CD4, 0x1CE0, + 0x1CE2, 0x1CE8, + 0x1CED, 0x1CED, + 0x1CF4, 0x1CF4, + 0x1CF8, 0x1CF9, + 0x1DC0, 0x1DFF, + 0x200D, 0x200D, + 0x20D0, 0x20DC, + 0x20E1, 0x20E1, + 0x20E5, 0x20F0, + 0x2CEF, 0x2CF1, + 0x2D7F, 0x2D7F, + 0x2DE0, 0x2DFF, + 0x302A, 0x302D, + 0x302E, 0x302F, + 0x3099, 0x309A, + 0xA66F, 0xA66F, + 0xA674, 0xA67D, + 0xA69E, 0xA69F, + 0xA6F0, 0xA6F1, + 0xA82C, 0xA82C, + 0xA8E0, 0xA8F1, + 0xA92B, 0xA92D, + 0xA9B3, 0xA9B3, + 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, + 0xAAB7, 0xAAB8, + 0xAABE, 0xAABF, + 0xAAC1, 0xAAC1, + 0xAAF6, 0xAAF6, + 0xABED, 0xABED, + 0xFB1E, 0xFB1E, + 0xFE20, 0xFE2F, + 0x101FD, 0x101FD, + 0x102E0, 0x102E0, + 0x10376, 0x1037A, + 0x10A0D, 0x10A0D, + 0x10A0F, 0x10A0F, + 0x10A38, 0x10A3A, + 0x10A3F, 0x10A3F, + 0x10AE5, 0x10AE6, + 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, + 0x10EFD, 0x10EFF, + 0x10F46, 0x10F50, + 0x10F82, 0x10F85, + 0x11070, 0x11070, + 0x1107F, 0x1107F, + 0x110BA, 0x110BA, + 0x11100, 0x11102, + 0x11133, 0x11134, + 0x11173, 0x11173, + 0x111CA, 0x111CA, + 0x11236, 0x11236, + 0x112E9, 0x112EA, + 0x1133B, 0x1133C, + 0x11366, 0x1136C, + 0x11370, 0x11374, + 0x11446, 0x11446, + 0x1145E, 0x1145E, + 0x114C3, 0x114C3, + 0x115C0, 0x115C0, + 0x116B7, 0x116B7, + 0x1172B, 0x1172B, + 0x1183A, 0x1183A, + 0x1193E, 0x1193E, + 0x11943, 0x11943, + 0x11A34, 0x11A34, + 0x11A47, 0x11A47, + 0x11A99, 0x11A99, + 0x11D42, 0x11D42, + 0x11D44, 0x11D45, + 0x11D97, 0x11D97, + 0x11F42, 0x11F42, + 0x16AF0, 0x16AF4, + 0x16B30, 0x16B36, + 0x1BC9E, 0x1BC9E, + 0x1D165, 0x1D165, + 0x1D167, 0x1D169, + 0x1D16E, 0x1D172, + 0x1D17B, 0x1D182, + 0x1D185, 0x1D18B, + 0x1D1AA, 0x1D1AD, + 0x1D242, 0x1D244, + 0x1E000, 0x1E006, + 0x1E008, 0x1E018, + 0x1E01B, 0x1E021, + 0x1E023, 0x1E024, + 0x1E026, 0x1E02A, + 0x1E08F, 0x1E08F, + 0x1E130, 0x1E136, + 0x1E2AE, 0x1E2AE, + 0x1E2EC, 0x1E2EF, + 0x1E4EC, 0x1E4EF, + 0x1E8D0, 0x1E8D6, + 0x1E944, 0x1E94A, +} + +// Fullwidth (F) and Wide (W) are counted as 2. +// Everything else is 1. +// +// Derived from: https://unicode.org/Public/15.1.0/ucd/EastAsianWidth.txt +@(rodata) +normalized_east_asian_width_ranges := [?]i32 { + 0x0000, 0x10FF, 1, + 0x1100, 0x115F, 2, + 0x1160, 0x2319, 1, + 0x231A, 0x231B, 2, + 0x231C, 0x2328, 1, + 0x2329, 0x232A, 2, + 0x232B, 0x23E8, 1, + 0x23E9, 0x23EC, 2, + 0x23ED, 0x23EF, 1, + 0x23F0, 0x23F0, 2, + 0x23F1, 0x23F2, 1, + 0x23F3, 0x23F3, 2, + 0x23F4, 0x25FC, 1, + 0x25FD, 0x25FE, 2, + 0x25FF, 0x2613, 1, + 0x2614, 0x2615, 2, + 0x2616, 0x2647, 1, + 0x2648, 0x2653, 2, + 0x2654, 0x267E, 1, + 0x267F, 0x267F, 2, + 0x2680, 0x2692, 1, + 0x2693, 0x2693, 2, + 0x2694, 0x26A0, 1, + 0x26A1, 0x26A1, 2, + 0x26A2, 0x26A9, 1, + 0x26AA, 0x26AB, 2, + 0x26AC, 0x26BC, 1, + 0x26BD, 0x26BE, 2, + 0x26BF, 0x26C3, 1, + 0x26C4, 0x26C5, 2, + 0x26C6, 0x26CD, 1, + 0x26CE, 0x26CE, 2, + 0x26CF, 0x26D3, 1, + 0x26D4, 0x26D4, 2, + 0x26D5, 0x26E9, 1, + 0x26EA, 0x26EA, 2, + 0x26EB, 0x26F1, 1, + 0x26F2, 0x26F3, 2, + 0x26F4, 0x26F4, 1, + 0x26F5, 0x26F5, 2, + 0x26F6, 0x26F9, 1, + 0x26FA, 0x26FA, 2, + 0x26FB, 0x26FC, 1, + 0x26FD, 0x26FD, 2, + 0x26FE, 0x2704, 1, + 0x2705, 0x2705, 2, + 0x2706, 0x2709, 1, + 0x270A, 0x270B, 2, + 0x270C, 0x2727, 1, + 0x2728, 0x2728, 2, + 0x2729, 0x274B, 1, + 0x274C, 0x274C, 2, + 0x274D, 0x274D, 1, + 0x274E, 0x274E, 2, + 0x274F, 0x2752, 1, + 0x2753, 0x2755, 2, + 0x2756, 0x2756, 1, + 0x2757, 0x2757, 2, + 0x2758, 0x2794, 1, + 0x2795, 0x2797, 2, + 0x2798, 0x27AF, 1, + 0x27B0, 0x27B0, 2, + 0x27B1, 0x27BE, 1, + 0x27BF, 0x27BF, 2, + 0x27C0, 0x2B1A, 1, + 0x2B1B, 0x2B1C, 2, + 0x2B1D, 0x2B4F, 1, + 0x2B50, 0x2B50, 2, + 0x2B51, 0x2B54, 1, + 0x2B55, 0x2B55, 2, + 0x2B56, 0x2E5D, 1, + 0x2E80, 0x303E, 2, + 0x303F, 0x303F, 1, + 0x3041, 0x3247, 2, + 0x3248, 0x324F, 1, + 0x3250, 0x4DBF, 2, + 0x4DC0, 0x4DFF, 1, + 0x4E00, 0xA4C6, 2, + 0xA4D0, 0xA95F, 1, + 0xA960, 0xA97C, 2, + 0xA980, 0xABF9, 1, + 0xAC00, 0xD7A3, 2, + 0xD7B0, 0xF8FF, 1, + 0xF900, 0xFAFF, 2, + 0xFB00, 0xFE0F, 1, + 0xFE10, 0xFE19, 2, + 0xFE20, 0xFE2F, 1, + 0xFE30, 0xFE6B, 2, + 0xFE70, 0xFEFF, 1, + 0xFF01, 0xFF60, 2, + 0xFF61, 0xFFDC, 1, + 0xFFE0, 0xFFE6, 2, + 0xFFE8, 0x16F9F, 1, + 0x16FE0, 0x1B2FB, 2, + 0x1BC00, 0x1F003, 1, + 0x1F004, 0x1F004, 2, + 0x1F005, 0x1F0CE, 1, + 0x1F0CF, 0x1F0CF, 2, + 0x1F0D1, 0x1F18D, 1, + 0x1F18E, 0x1F18E, 2, + 0x1F18F, 0x1F190, 1, + 0x1F191, 0x1F19A, 2, + 0x1F19B, 0x1F1FF, 1, + 0x1F200, 0x1F320, 2, + 0x1F321, 0x1F32C, 1, + 0x1F32D, 0x1F335, 2, + 0x1F336, 0x1F336, 1, + 0x1F337, 0x1F37C, 2, + 0x1F37D, 0x1F37D, 1, + 0x1F37E, 0x1F393, 2, + 0x1F394, 0x1F39F, 1, + 0x1F3A0, 0x1F3CA, 2, + 0x1F3CB, 0x1F3CE, 1, + 0x1F3CF, 0x1F3D3, 2, + 0x1F3D4, 0x1F3DF, 1, + 0x1F3E0, 0x1F3F0, 2, + 0x1F3F1, 0x1F3F3, 1, + 0x1F3F4, 0x1F3F4, 2, + 0x1F3F5, 0x1F3F7, 1, + 0x1F3F8, 0x1F43E, 2, + 0x1F43F, 0x1F43F, 1, + 0x1F440, 0x1F440, 2, + 0x1F441, 0x1F441, 1, + 0x1F442, 0x1F4FC, 2, + 0x1F4FD, 0x1F4FE, 1, + 0x1F4FF, 0x1F53D, 2, + 0x1F53E, 0x1F54A, 1, + 0x1F54B, 0x1F54E, 2, + 0x1F54F, 0x1F54F, 1, + 0x1F550, 0x1F567, 2, + 0x1F568, 0x1F579, 1, + 0x1F57A, 0x1F57A, 2, + 0x1F57B, 0x1F594, 1, + 0x1F595, 0x1F596, 2, + 0x1F597, 0x1F5A3, 1, + 0x1F5A4, 0x1F5A4, 2, + 0x1F5A5, 0x1F5FA, 1, + 0x1F5FB, 0x1F64F, 2, + 0x1F650, 0x1F67F, 1, + 0x1F680, 0x1F6C5, 2, + 0x1F6C6, 0x1F6CB, 1, + 0x1F6CC, 0x1F6CC, 2, + 0x1F6CD, 0x1F6CF, 1, + 0x1F6D0, 0x1F6D2, 2, + 0x1F6D3, 0x1F6D4, 1, + 0x1F6D5, 0x1F6DF, 2, + 0x1F6E0, 0x1F6EA, 1, + 0x1F6EB, 0x1F6EC, 2, + 0x1F6F0, 0x1F6F3, 1, + 0x1F6F4, 0x1F6FC, 2, + 0x1F700, 0x1F7D9, 1, + 0x1F7E0, 0x1F7F0, 2, + 0x1F800, 0x1F90B, 1, + 0x1F90C, 0x1F93A, 2, + 0x1F93B, 0x1F93B, 1, + 0x1F93C, 0x1F945, 2, + 0x1F946, 0x1F946, 1, + 0x1F947, 0x1F9FF, 2, + 0x1FA00, 0x1FA6D, 1, + 0x1FA70, 0x1FAF8, 2, + 0x1FB00, 0x1FBF9, 1, + 0x20000, 0x3FFFD, 2, + 0xE0001, 0x10FFFD, 1, +} + +// +// End of Unicode 15.1.0 block. +// diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin index ec8106cbe..16baa1adf 100644 --- a/core/unicode/tools/generate_entity_table.odin +++ b/core/unicode/tools/generate_entity_table.odin @@ -142,7 +142,7 @@ generate_encoding_entity_table :: proc() { /* Generate table. */ - fmt.wprintln(w, "package unicode_entity") + fmt.wprintln(w, "package encoding_unicode_entity") fmt.wprintln(w, "") fmt.wprintln(w, GENERATED) fmt.wprintln(w, "") @@ -195,12 +195,12 @@ named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { e := entity_map[v] - fmt.wprintf(w, "\t\t\tcase \"%v\":", e.name) + fmt.wprintf(w, "\t\tcase \"%v\":", e.name) for i := len(e.name); i < max_name_length; i += 1 { fmt.wprintf(w, " ") } fmt.wprintf(w, " // %v\n", e.description) - fmt.wprintf(w, "\t\t\t\treturn %v, true\n", rune_to_string(e.codepoint)) + fmt.wprintf(w, "\t\t\treturn %v, true\n", rune_to_string(e.codepoint)) should_close = true } diff --git a/core/unicode/utf8/grapheme.odin b/core/unicode/utf8/grapheme.odin new file mode 100644 index 000000000..50d1789ab --- /dev/null +++ b/core/unicode/utf8/grapheme.odin @@ -0,0 +1,411 @@ +package utf8 + +import "core:unicode" + +ZERO_WIDTH_JOINER :: unicode.ZERO_WIDTH_JOINER +is_control :: unicode.is_control +is_hangul_syllable_leading :: unicode.is_hangul_syllable_leading +is_hangul_syllable_vowel :: unicode.is_hangul_syllable_vowel +is_hangul_syllable_trailing :: unicode.is_hangul_syllable_trailing +is_hangul_syllable_lv :: unicode.is_hangul_syllable_lv +is_hangul_syllable_lvt :: unicode.is_hangul_syllable_lvt +is_indic_conjunct_break_extend :: unicode.is_indic_conjunct_break_extend +is_indic_conjunct_break_linker :: unicode.is_indic_conjunct_break_linker +is_indic_conjunct_break_consonant :: unicode.is_indic_conjunct_break_consonant +is_gcb_extend_class :: unicode.is_gcb_extend_class +is_spacing_mark :: unicode.is_spacing_mark +is_gcb_prepend_class :: unicode.is_gcb_prepend_class +is_emoji_extended_pictographic :: unicode.is_emoji_extended_pictographic +is_regional_indicator :: unicode.is_regional_indicator +normalized_east_asian_width :: unicode.normalized_east_asian_width + + +Grapheme :: struct { + byte_index: int, + rune_index: int, + width: int, +} + +/* +Count the individual graphemes in a UTF-8 string. + +Inputs: +- str: The input string. + +Returns: +- graphemes: The number of graphemes in the string. +- runes: The number of runes in the string. +- width: The width of the string in number of monospace cells. +*/ +@(require_results) +grapheme_count :: proc(str: string) -> (graphemes, runes, width: int) { + _, graphemes, runes, width = decode_grapheme_clusters(str, false) + return +} + +/* +Decode the individual graphemes in a UTF-8 string. + +*Allocates Using Provided Allocator* + +Inputs: +- str: The input string. +- track_graphemes: Whether or not to allocate and return `graphemes` with extra data about each grapheme. +- allocator: (default: context.allocator) + +Returns: +- graphemes: Extra data about each grapheme. +- grapheme_count: The number of graphemes in the string. +- rune_count: The number of runes in the string. +- width: The width of the string in number of monospace cells. +*/ +@(require_results) +decode_grapheme_clusters :: proc( + str: string, + track_graphemes := true, + allocator := context.allocator, +) -> ( + graphemes: [dynamic]Grapheme, + grapheme_count: int, + rune_count: int, + width: int, +) { + // The following procedure implements text segmentation by breaking on + // Grapheme Cluster Boundaries[1], using the values[2] and rules[3] from + // the Unicode® Standard Annex #29, entitled: + // + // UNICODE TEXT SEGMENTATION + // + // Version: Unicode 15.1.0 + // Date: 2023-08-16 + // Revision: 43 + // + // This procedure is conformant[4] to UAX29-C1-1, otherwise known as the + // extended, non-legacy ruleset. + // + // Please see the references below for more information. + // + // + // NOTE(Feoramund): This procedure has not been highly optimized. + // A couple opportunities were taken to bypass repeated checking when a + // rune is outside of certain codepoint ranges, but little else has been + // done. Standard switches, conditionals, and binary search are used to + // see if a rune fits into a certain category. + // + // I did find that only one prior rune of state was necessary to build an + // algorithm that successfully passes all 4,835 test cases provided with + // this implementation from the Unicode organization's website. + // + // My initial implementation tracked explicit breaks and counted them once + // the string iteration had terminated. I've found this current + // implementation to be far simpler and need no allocations (unless the + // caller wants position data). + // + // Most rules work backwards instead of forwards which has helped keep this + // simple, despite its length and verbosity. + // + // + // The implementation has been left verbose and in the order described by + // the specification, to enable better readability and future upkeep. + // + // Some possible optimizations might include: + // + // - saving the type of `last_rune` instead of the exact rune. + // - reordering rules. + // - combining tables. + // + // + // [1]: https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries + // [2]: https://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table + // [3]: https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules + // [4]: https://www.unicode.org/reports/tr29/#Conformance + + // Additionally, this procedure now takes into account Standard Annex #11, + // in order to estimate how visually wide the string will appear on a + // monospaced display. This can only ever be a rough guess, as this tends + // to be an implementation detail relating to which fonts are being used, + // how codepoints are interpreted and drawn, if codepoint sequences are + // interpreted correctly, and et cetera. + // + // For example, a program may not properly interpret an emoji modifier + // sequence and print the component glyphs instead of one whole glyph. + // + // See here for more information: https://www.unicode.org/reports/tr11/ + // + // NOTE: There is no explicit mention of what to do with zero-width spaces + // as far as grapheme cluster segmentation goes, therefore this + // implementation may count and return graphemes with a `width` of zero. + // + // Treat them as any other space. + + Grapheme_Cluster_Sequence :: enum { + None, + Indic, + Emoji, + Regional, + } + + context.allocator = allocator + + last_rune: rune + last_rune_breaks_forward: bool + + last_width: int + last_grapheme_count: int + + bypass_next_rune: bool + + regional_indicator_counter: int + + current_sequence: Grapheme_Cluster_Sequence + continue_sequence: bool + + for this_rune, byte_index in str { + defer { + // "Break at the start and end of text, unless the text is empty." + // + // GB1: sot ÷ Any + // GB2: Any ÷ eot + if rune_count == 0 && grapheme_count == 0 { + grapheme_count += 1 + } + + if grapheme_count > last_grapheme_count { + width += normalized_east_asian_width(this_rune) + if track_graphemes { + append(&graphemes, Grapheme{ + byte_index, + rune_count, + width - last_width, + }) + } + last_grapheme_count = grapheme_count + last_width = width + } + + last_rune = this_rune + rune_count += 1 + + if !continue_sequence { + current_sequence = .None + regional_indicator_counter = 0 + } + continue_sequence = false + } + + // "Do not break between a CR and LF. Otherwise, break before and after controls." + // + // GB3: CR × LF + // GB4: (Control | CR | LF) ÷ + // GB5: ÷ (Control | CR | LF) + if this_rune == '\n' && last_rune == '\r' { + last_rune_breaks_forward = false + bypass_next_rune = false + continue + } + + if is_control(this_rune) { + grapheme_count += 1 + last_rune_breaks_forward = true + bypass_next_rune = true + continue + } + + // (This check is for rules that work forwards, instead of backwards.) + if bypass_next_rune { + if last_rune_breaks_forward { + grapheme_count += 1 + last_rune_breaks_forward = false + } + + bypass_next_rune = false + continue + } + + // (Optimization 1: Prevent low runes from proceeding further.) + // + // * 0xA9 and 0xAE are in the Extended_Pictographic range, + // which is checked later in GB11. + if this_rune != 0xA9 && this_rune != 0xAE && this_rune <= 0x2FF { + grapheme_count += 1 + continue + } + + // (Optimization 2: Check if the rune is in the Hangul space before getting specific.) + if 0x1100 <= this_rune && this_rune <= 0xD7FB { + // "Do not break Hangul syllable sequences." + // + // GB6: L × (L | V | LV | LVT) + // GB7: (LV | V) × (V | T) + // GB8: (LVT | T) × T + if is_hangul_syllable_leading(this_rune) || + is_hangul_syllable_lv(this_rune) || + is_hangul_syllable_lvt(this_rune) { + if !is_hangul_syllable_leading(last_rune) { + grapheme_count += 1 + } + continue + } + + if is_hangul_syllable_vowel(this_rune) { + if is_hangul_syllable_leading(last_rune) || + is_hangul_syllable_vowel(last_rune) || + is_hangul_syllable_lv(last_rune) { + continue + } + grapheme_count += 1 + continue + } + + if is_hangul_syllable_trailing(this_rune) { + if is_hangul_syllable_trailing(last_rune) || + is_hangul_syllable_lvt(last_rune) || + is_hangul_syllable_lv(last_rune) || + is_hangul_syllable_vowel(last_rune) { + continue + } + grapheme_count += 1 + continue + } + } + + // "Do not break before extending characters or ZWJ." + // + // GB9: × (Extend | ZWJ) + if this_rune == ZERO_WIDTH_JOINER { + continue_sequence = true + continue + } + + if is_gcb_extend_class(this_rune) { + // (Support for GB9c.) + if current_sequence == .Indic { + if is_indic_conjunct_break_extend(this_rune) && ( + is_indic_conjunct_break_linker(last_rune) || + is_indic_conjunct_break_consonant(last_rune) ) { + continue_sequence = true + continue + } + + if is_indic_conjunct_break_linker(this_rune) && ( + is_indic_conjunct_break_linker(last_rune) || + is_indic_conjunct_break_extend(last_rune) || + is_indic_conjunct_break_consonant(last_rune) ) { + continue_sequence = true + continue + } + + continue + } + + // (Support for GB11.) + if current_sequence == .Emoji && ( + is_gcb_extend_class(last_rune) || + is_emoji_extended_pictographic(last_rune) ) { + continue_sequence = true + } + + continue + } + + // _The GB9a and GB9b rules only apply to extended grapheme clusters:_ + // "Do not break before SpacingMarks, or after Prepend characters." + // + // GB9a: × SpacingMark + // GB9b: Prepend × + if is_spacing_mark(this_rune) { + continue + } + + if is_gcb_prepend_class(this_rune) { + grapheme_count += 1 + bypass_next_rune = true + continue + } + + // _The GB9c rule only applies to extended grapheme clusters:_ + // "Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker." + // + // GB9c: \p{InCB=Consonant} [ \p{InCB=Extend} \p{InCB=Linker} ]* \p{InCB=Linker} [ \p{InCB=Extend} \p{InCB=Linker} ]* × \p{InCB=Consonant} + if is_indic_conjunct_break_consonant(this_rune) { + if current_sequence == .Indic { + if last_rune == ZERO_WIDTH_JOINER || + is_indic_conjunct_break_linker(last_rune) { + continue_sequence = true + } else { + grapheme_count += 1 + } + } else { + grapheme_count += 1 + current_sequence = .Indic + continue_sequence = true + } + continue + } + + if is_indic_conjunct_break_extend(this_rune) { + if current_sequence == .Indic { + if is_indic_conjunct_break_consonant(last_rune) || + is_indic_conjunct_break_linker(last_rune) { + continue_sequence = true + } else { + grapheme_count += 1 + } + } + continue + } + + if is_indic_conjunct_break_linker(this_rune) { + if current_sequence == .Indic { + if is_indic_conjunct_break_extend(last_rune) || + is_indic_conjunct_break_linker(last_rune) { + continue_sequence = true + } else { + grapheme_count += 1 + } + } + continue + } + + // + // (Curiously, there is no GB10.) + // + + // "Do not break within emoji modifier sequences or emoji zwj sequences." + // + // GB11: \p{Extended_Pictographic} Extend* ZWJ × \p{Extended_Pictographic} + if is_emoji_extended_pictographic(this_rune) { + if current_sequence != .Emoji || last_rune != ZERO_WIDTH_JOINER { + grapheme_count += 1 + } + current_sequence = .Emoji + continue_sequence = true + continue + } + + // "Do not break within emoji flag sequences. + // That is, do not break between regional indicator (RI) symbols + // if there is an odd number of RI characters before the break point." + // + // GB12: sot (RI RI)* RI × RI + // GB13: [^RI] (RI RI)* RI × RI + if is_regional_indicator(this_rune) { + if regional_indicator_counter & 1 == 0 { + grapheme_count += 1 + } + + current_sequence = .Regional + continue_sequence = true + regional_indicator_counter += 1 + + continue + } + + // "Otherwise, break everywhere." + // + // GB999: Any ÷ Any + grapheme_count += 1 + } + + return +} diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 6c3972987..976a0f0e5 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -49,25 +49,30 @@ import tuplehash "core:crypto/tuplehash" import x25519 "core:crypto/x25519" import pe "core:debug/pe" +import trace "core:debug/trace" import dynlib "core:dynlib" import net "core:net" +import ansi "core:encoding/ansi" import base32 "core:encoding/base32" import base64 "core:encoding/base64" +import cbor "core:encoding/cbor" import csv "core:encoding/csv" +import endian "core:encoding/endian" import hxa "core:encoding/hxa" import json "core:encoding/json" import varint "core:encoding/varint" import xml "core:encoding/xml" -import endian "core:encoding/endian" -import cbor "core:encoding/cbor" +import uuid "core:encoding/uuid" +import uuid_legacy "core:encoding/uuid/legacy" import fmt "core:fmt" import hash "core:hash" import xxhash "core:hash/xxhash" import image "core:image" +import bmp "core:image/bmp" import netpbm "core:image/netpbm" import png "core:image/png" import qoi "core:image/qoi" @@ -89,6 +94,7 @@ import ease "core:math/ease" import cmplx "core:math/cmplx" import mem "core:mem" +import tlsf "core:mem/tlsf" import virtual "core:mem/virtual" import ast "core:odin/ast" @@ -103,9 +109,12 @@ import os "core:os" import slashpath "core:path/slashpath" import filepath "core:path/filepath" +import relative "core:relative" + import reflect "core:reflect" import runtime "base:runtime" import simd "core:simd" +import x86 "core:simd/x86" import slice "core:slice" import slice_heap "core:slice/heap" import sort "core:sort" @@ -113,14 +122,17 @@ import strconv "core:strconv" import strings "core:strings" import sync "core:sync" import testing "core:testing" -import scanner "core:text/scanner" + +import edit "core:text/edit" import i18n "core:text/i18n" import match "core:text/match" +import scanner "core:text/scanner" import table "core:text/table" -import edit "core:text/edit" + import thread "core:thread" import time "core:time" import datetime "core:time/datetime" +import flags "core:flags" import sysinfo "core:sys/info" @@ -173,8 +185,10 @@ _ :: sm3 _ :: tuplehash _ :: x25519 _ :: pe +_ :: trace _ :: dynlib _ :: net +_ :: ansi _ :: base32 _ :: base64 _ :: csv @@ -188,6 +202,7 @@ _ :: fmt _ :: hash _ :: xxhash _ :: image +_ :: bmp _ :: netpbm _ :: png _ :: qoi @@ -206,6 +221,7 @@ _ :: rand _ :: ease _ :: cmplx _ :: mem +_ :: tlsf _ :: virtual _ :: ast _ :: doc_format @@ -215,9 +231,11 @@ _ :: os _ :: spall _ :: slashpath _ :: filepath +_ :: relative _ :: reflect _ :: runtime _ :: simd +_ :: x86 _ :: slice _ :: slice_heap _ :: sort @@ -233,8 +251,11 @@ _ :: edit _ :: thread _ :: time _ :: datetime +_ :: flags _ :: sysinfo _ :: unicode +_ :: uuid +_ :: uuid_legacy _ :: utf8 _ :: utf8string _ :: utf16 diff --git a/examples/all/all_vendor_windows.odin b/examples/all/all_vendor_windows.odin new file mode 100644 index 000000000..0c72c886c --- /dev/null +++ b/examples/all/all_vendor_windows.odin @@ -0,0 +1,4 @@ +package all + +import wgpu "vendor:wgpu" +_ :: wgpu \ No newline at end of file diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index b3c627808..d31711bad 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1140,6 +1140,7 @@ prefix_table := [?]string{ print_mutex := b64(false) +@(disabled=!thread.IS_SUPPORTED) threading_example :: proc() { fmt.println("\n# threading_example") @@ -2275,7 +2276,7 @@ arbitrary_precision_mathematics :: proc() { } fmt.printf(as) if print_extra_info { - fmt.printf(" (base: %v, bits: %v, digits: %v)", base, cb, a.used) + fmt.printf(" (base: %v, bits: %v, digits: %v)", base, cb, a.used) } if newline { fmt.println() @@ -2550,6 +2551,50 @@ matrix_type :: proc() { // matrix_minor(m) } +bit_field_type :: proc() { + fmt.println("\n# bit_field type") + // A `bit_field` is a record type in Odin that is akin to a bit-packed struct. + // IMPORTNAT NOTE: `bit_field` is NOT equivalent to `bit_set` as it has different sematics and use cases. + + { + // `bit_field` fields are accessed by using a dot: + Foo :: bit_field u16 { // backing type must be an integer or array of integers + x: i32 | 3, // signed integers will be signed extended on use + y: u16 | 2 + 3, // general expressions + z: My_Enum | SOME_CONSTANT, // ability to define the bit-width elsewhere + w: bool | 2 when SOME_CONSTANT > 10 else 1, + } + + v := Foo{} + v.x = 3 // truncates the value to fit into 3 bits + fmt.println(v.x) // accessing will convert `v.x` to an `i32` and do an appropriate sign extension + + + My_Enum :: enum u8 {A, B, C, D} + SOME_CONSTANT :: 7 + } + + { + // A `bit_field` is different from a struct in that you must specify the backing type. + // This backing type must be an integer or a fixed-length array of integers. + // This is useful if there needs to be a specific alignment or access pattern for the record. + + Bar :: bit_field u32 {} + Baz :: bit_field [4]u8 {} + } + + // IMPORTANT NOTES: + // * If _all_ of the fields in a bit_field are 1-bit in size and they are all booleans, + // please consider using a `bit_set` instead. + // * Odin's `bit_field` and C's bit-fields might not be compatible + // * Odin's `bit_field`s have a well defined layout (Least-Significant-Bit) + // * C's bit-fields on `struct`s are undefined and are not portable across targets and compilers + // * A `bit_field`'s field type can only be one of the following: + // * Integer + // * Boolean + // * Enum +} + main :: proc() { /* For More Odin Examples - https://github.com/odin-lang/examples @@ -2595,5 +2640,6 @@ main :: proc() { or_break_and_or_continue_operators() arbitrary_precision_mathematics() matrix_type() + bit_field_type() } } diff --git a/misc/roadmap.md b/misc/roadmap.md deleted file mode 100644 index 83fbbb695..000000000 --- a/misc/roadmap.md +++ /dev/null @@ -1,21 +0,0 @@ -# Odin Roadmap - -Not in any particular order - -* Custom backend to replace LLVM - - Improve SSA design to accommodate for lowering to a "bytecode" - - SSA optimizations - - COFF generation - - linker -* Type safe "macros" -* Documentation generator for "Entities" -* Multiple architecture support -* Inline assembly -* Linking options - - Executable - - Static/Dynamic Library -* Debug information - - pdb format too -* Command line tooling -* Compiler internals: - - Big numbers library diff --git a/src/build_settings.cpp b/src/build_settings.cpp index dc11a5fd2..4d3e20a7a 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -106,468 +106,7 @@ gb_global String target_arch_names[TargetArch_COUNT] = { str_lit("wasm64p32"), }; -// Generated with the featuregen script in `misc/featuregen` -gb_global String target_microarch_list[TargetArch_COUNT] = { - // TargetArch_Invalid: - str_lit(""), - // TargetArch_amd64: - str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), - // TargetArch_i386: - str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), - // TargetArch_arm32: - str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), - // TargetArch_arm64: - str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), - // TargetArch_wasm32: - str_lit("bleeding-edge,generic,mvp"), - // TargetArch_wasm64p32: - str_lit("bleeding-edge,generic,mvp"), -}; - -// Generated with the featuregen script in `misc/featuregen` -gb_global String target_features_list[TargetArch_COUNT] = { - // TargetArch_Invalid: - str_lit(""), - // TargetArch_amd64: - str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), - // TargetArch_i386: - str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), - // TargetArch_arm32: - str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aapcs-frame-chain-leaf,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,atomics-32,avoid-movs-shop,avoid-partial-cpsr,bf16,big-endian-instructions,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a710,cortex-a78,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m7,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), - // TargetArch_arm64: - str_lit("CONTEXTIDREL2,a35,a510,a53,a55,a57,a64fx,a65,a710,a715,a72,a73,a75,a76,a77,a78,a78c,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,am,ampere1,ampere1a,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,b16b16,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,complxnum,cortex-r82,cortex-x1,cortex-x2,cortex-x3,crc,crypto,cssc,custom-cheap-as-move,d128,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,falkor,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,lor,ls64,lse,lse128,lse2,lsl-fast,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversev1,neoversev2,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,outline-atomics,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x30,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-f16f16,sme-f64f64,sme-i16i64,sme2,sme2p1,spe,spe-eef,specres2,specrestrict,ssbs,strict-align,sve,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-postra-scheduler,use-reciprocal-square-root,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vh,wfxt,xs,zcm,zcz,zcz-fp-workaround,zcz-gp"), - // TargetArch_wasm32: - str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), - // TargetArch_wasm64p32: - str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), -}; - -// Generated with the featuregen script in `misc/featuregen` -gb_global int target_microarch_counts[TargetArch_COUNT] = { - // TargetArch_Invalid: - 0, - // TargetArch_amd64: - 120, - // TargetArch_i386: - 120, - // TargetArch_arm32: - 90, - // TargetArch_arm64: - 63, - // TargetArch_wasm32: - 3, - // TargetArch_wasm64p32: - 3, -}; - -// Generated with the featuregen script in `misc/featuregen` -gb_global MicroarchFeatureList microarch_features_list[] = { - // TargetArch_amd64: - { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("amdfam10"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, - { str_lit("athlon"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon-4"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon-fx"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon-mp"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon-tbird"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon-xp"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon64"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon64-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("atom"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("atom_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, - { str_lit("atom_sse4_2_movbe"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("barcelona"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, - { str_lit("bdver1"), str_lit("64bit,64bit-mode,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, - { str_lit("bdver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, - { str_lit("bdver3"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, - { str_lit("bdver4"), str_lit("64bit,64bit-mode,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, - { str_lit("bonnell"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("broadwell"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("btver1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-15bytenop,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, - { str_lit("btver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, - { str_lit("c3"), str_lit("3dnow,64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core2"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("core_2_duo_sse4_1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, - { str_lit("core_2_duo_ssse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("core_2nd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_3rd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_4th_gen_avx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_4th_gen_avx_tsx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_5th_gen_avx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_5th_gen_avx_tsx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_aes_pclmulqdq"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("core_i7_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("corei7"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("corei7-avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("emeraldrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("generic"), str_lit("64bit,64bit-mode,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,sse,sse2,vzeroupper,x87") }, - { str_lit("geode"), str_lit("3dnow,3dnowa,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("graniterapids_d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("haswell"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("i386"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("i486"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("i586"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("i686"), str_lit("64bit-mode,cmov,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("icelake-client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("icelake-server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("icelake_client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("icelake_server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("ivybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("k6"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("k6-2"), str_lit("3dnow,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("k6-3"), str_lit("3dnow,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("k8"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("k8-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, - { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, - { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") }, - { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, - { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("opteron"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("opteron-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, - { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium-mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium3m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium4m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_4_sse3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("pentium_ii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_iii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_iii_no_xmm_regs"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_pro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentiumpro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("prescott"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("raptorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("rocketlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("sandybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("sapphirerapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("sierraforest"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("silvermont"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, - { str_lit("skx"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("skylake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("skylake-avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("skylake_avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("slm"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, - { str_lit("tigerlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("tremont"), str_lit("64bit,64bit-mode,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("westmere"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("winchip-c6"), str_lit("64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("winchip2"), str_lit("3dnow,64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("x86-64"), str_lit("64bit,64bit-mode,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, - { str_lit("x86-64-v2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("x86-64-v3"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, - { str_lit("x86-64-v4"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, - { str_lit("yonah"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("znver1"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("znver2"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("znver3"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("znver4"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - // TargetArch_i386: - { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("amdfam10"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, - { str_lit("athlon"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("athlon-4"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("athlon-fx"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon-mp"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("athlon-tbird"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("athlon-xp"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("athlon64"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("athlon64-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("atom"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("atom_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, - { str_lit("atom_sse4_2_movbe"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("barcelona"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, - { str_lit("bdver1"), str_lit("32bit-mode,64bit,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, - { str_lit("bdver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, - { str_lit("bdver3"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, - { str_lit("bdver4"), str_lit("32bit-mode,64bit,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, - { str_lit("bonnell"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("broadwell"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("btver1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-15bytenop,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, - { str_lit("btver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, - { str_lit("c3"), str_lit("32bit-mode,3dnow,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core2"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("core_2_duo_sse4_1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, - { str_lit("core_2_duo_ssse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, - { str_lit("core_2nd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_3rd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_4th_gen_avx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_4th_gen_avx_tsx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_5th_gen_avx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_5th_gen_avx_tsx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("core_aes_pclmulqdq"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("core_i7_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("corei7"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("corei7-avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("emeraldrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("generic"), str_lit("32bit-mode,64bit,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,vzeroupper,x87") }, - { str_lit("geode"), str_lit("32bit-mode,3dnow,3dnowa,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("graniterapids_d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("haswell"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("i386"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("i486"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("i586"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("i686"), str_lit("32bit-mode,cmov,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("icelake-client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("icelake-server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("icelake_client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("icelake_server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("ivybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("k6"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("k6-2"), str_lit("32bit-mode,3dnow,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("k6-3"), str_lit("32bit-mode,3dnow,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("k8"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("k8-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, - { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, - { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") }, - { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, - { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("opteron"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("opteron-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, - { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium-mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("pentium2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("pentium3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("pentium3m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("pentium4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium4m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_4_sse3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("pentium_ii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("pentium_iii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("pentium_iii_no_xmm_regs"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, - { str_lit("pentium_m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, - { str_lit("pentium_mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("pentium_pro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("pentiumpro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("prescott"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("raptorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("rocketlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("sandybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, - { str_lit("sapphirerapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("sierraforest"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("silvermont"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, - { str_lit("skx"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("skylake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("skylake-avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("skylake_avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("slm"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, - { str_lit("tigerlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("tremont"), str_lit("32bit-mode,64bit,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("westmere"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("winchip-c6"), str_lit("32bit-mode,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("winchip2"), str_lit("32bit-mode,3dnow,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, - { str_lit("x86-64"), str_lit("32bit-mode,64bit,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, - { str_lit("x86-64-v2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, - { str_lit("x86-64-v3"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, - { str_lit("x86-64-v4"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, - { str_lit("yonah"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, - { str_lit("znver1"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("znver2"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("znver3"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - { str_lit("znver4"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, - // TargetArch_arm32: - { str_lit("arm1020e"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm1020t"), str_lit("armv5t,v4t,v5t") }, - { str_lit("arm1022e"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm10e"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm10tdmi"), str_lit("armv5t,v4t,v5t") }, - { str_lit("arm1136j-s"), str_lit("armv6,dsp,v4t,v5t,v5te,v6") }, - { str_lit("arm1136jf-s"), str_lit("armv6,dsp,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,vfp2,vfp2sp") }, - { str_lit("arm1156t2-s"), str_lit("armv6t2,dsp,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m") }, - { str_lit("arm1156t2f-s"), str_lit("armv6t2,dsp,fp64,fpregs,fpregs64,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m,vfp2,vfp2sp") }, - { str_lit("arm1176jz-s"), str_lit("armv6kz,trustzone,v4t,v5t,v5te,v6,v6k") }, - { str_lit("arm1176jzf-s"), str_lit("armv6kz,fp64,fpregs,fpregs64,slowfpvmlx,trustzone,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, - { str_lit("arm710t"), str_lit("armv4t,v4t") }, - { str_lit("arm720t"), str_lit("armv4t,v4t") }, - { str_lit("arm7tdmi"), str_lit("armv4t,v4t") }, - { str_lit("arm7tdmi-s"), str_lit("armv4t,v4t") }, - { str_lit("arm8"), str_lit("armv4") }, - { str_lit("arm810"), str_lit("armv4") }, - { str_lit("arm9"), str_lit("armv4t,v4t") }, - { str_lit("arm920"), str_lit("armv4t,v4t") }, - { str_lit("arm920t"), str_lit("armv4t,v4t") }, - { str_lit("arm922t"), str_lit("armv4t,v4t") }, - { str_lit("arm926ej-s"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm940t"), str_lit("armv4t,v4t") }, - { str_lit("arm946e-s"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm966e-s"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("arm9tdmi"), str_lit("armv4t,v4t") }, - { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, - { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,neon,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, - { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, - { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, - { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, - { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a75"), str_lit("a75,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a76"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a76ae"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,neon,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, - { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, - { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, - { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, - { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, - { str_lit("cortex-m23"), str_lit("8msecext,acquire-release,armv8-m.base,db,hwdiv,mclass,no-branch-predictor,no-movt,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m,v7clrex,v8m") }, - { str_lit("cortex-m3"), str_lit("armv7-m,db,hwdiv,loop-align,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, - { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, - { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, - { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") }, - { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, - { str_lit("cortex-m7"), str_lit("armv7e-m,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, - { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, - { str_lit("cortex-r4"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,hwdiv,perfmon,r4,rclass,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, - { str_lit("cortex-r4f"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,perfmon,r4,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, - { str_lit("cortex-r5"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,perfmon,r5,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, - { str_lit("cortex-r52"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-r7"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,r7,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, - { str_lit("cortex-r8"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, - { str_lit("cortex-x1"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-x1c"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1c,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cyclone"), str_lit("aclass,acquire-release,aes,armv8-a,avoid-movs-shop,avoid-partial-cpsr,crc,crypto,d32,db,disable-postra-scheduler,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,ret-addr-stack,sha2,slowfpvfmx,slowfpvmlx,swift,thumb2,trustzone,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,zcz") }, - { str_lit("ep9312"), str_lit("armv4t,v4t") }, - { str_lit("exynos-m3"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dont-widen-vmovs,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, - { str_lit("exynos-m4"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, - { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, - { str_lit("generic"), str_lit("") }, - { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,neon,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, - { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, - { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") }, - { str_lit("neoverse-n1"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("neoverse-n2"), str_lit("aclass,acquire-release,armv9-a,bf16,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("neoverse-v1"), str_lit("aclass,acquire-release,aes,armv8.4-a,bf16,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("sc000"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, - { str_lit("sc300"), str_lit("armv7-m,db,hwdiv,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, - { str_lit("strongarm"), str_lit("armv4") }, - { str_lit("strongarm110"), str_lit("armv4") }, - { str_lit("strongarm1100"), str_lit("armv4") }, - { str_lit("strongarm1110"), str_lit("armv4") }, - { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, - { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") }, - // TargetArch_arm64: - { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("ampere1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, - { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, - { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-a13"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, - { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, - { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, - { str_lit("apple-latest"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, - { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,crypto,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a34"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, - { str_lit("cortex-a35"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, - { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, - { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,v8a") }, - { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a57"), str_lit("a57,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") }, - { str_lit("cortex-a65"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a65ae"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, - { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, - { str_lit("cortex-a72"), str_lit("a72,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") }, - { str_lit("cortex-a73"), str_lit("a73,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") }, - { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a76ae"), str_lit("CONTEXTIDREL2,a76,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a77"), str_lit("CONTEXTIDREL2,a77,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a78"), str_lit("CONTEXTIDREL2,a78,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-a78c"), str_lit("CONTEXTIDREL2,a78c,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-r82"), str_lit("CONTEXTIDREL2,ccidx,ccpp,complxnum,cortex-r82,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, - { str_lit("cortex-x1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, - { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, - { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, - { str_lit("exynos-m3"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") }, - { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, - { str_lit("exynos-m5"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, - { str_lit("falkor"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,falkor,fp-armv8,neon,perfmon,predictable-select-expensive,rdm,sha2,slow-strqro-store,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, - { str_lit("generic"), str_lit("enable-select-opt,ete,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler") }, - { str_lit("kryo"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,fp-armv8,kryo,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, - { str_lit("neoverse-512tvb"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoverse512tvb,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, - { str_lit("neoverse-e1"), str_lit("CONTEXTIDREL2,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversee1,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("neoverse-n1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversen1,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - { str_lit("neoverse-n2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, - { str_lit("neoverse-v1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoversev1,no-sve-fp-ld1r,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, - { str_lit("neoverse-v2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, - { str_lit("saphira"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,saphira,sel2,sha2,spe,store-pair-suppress,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcz,zcz-gp") }, - { str_lit("thunderx"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderx,use-postra-scheduler,v8a") }, - { str_lit("thunderx2t99"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,crc,crypto,el2vmsa,el3,fp-armv8,lor,lse,neon,pan,predictable-select-expensive,rdm,sha2,store-pair-suppress,thunderx2t99,use-postra-scheduler,v8.1a,v8a,vh") }, - { str_lit("thunderx3t110"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,balance-fp-ops,ccidx,ccpp,complxnum,crc,crypto,el2vmsa,el3,fp-armv8,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,store-pair-suppress,strict-align,thunderx3t110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8a,vh") }, - { str_lit("thunderxt81"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt81,use-postra-scheduler,v8a") }, - { str_lit("thunderxt83"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt83,use-postra-scheduler,v8a") }, - { str_lit("thunderxt88"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt88,use-postra-scheduler,v8a") }, - { str_lit("tsv110"), str_lit("CONTEXTIDREL2,aes,ccpp,complxnum,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fp16fml,fullfp16,fuse-aes,jsconv,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,spe,store-pair-suppress,tsv110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, - // TargetArch_wasm32: - { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,mutable-globals,nontrapping-fptoint,sign-ext,simd128,tail-call") }, - { str_lit("generic"), str_lit("mutable-globals,sign-ext") }, - { str_lit("mvp"), str_lit("") }, - // TargetArch_wasm64p32: - { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,mutable-globals,nontrapping-fptoint,sign-ext,simd128,tail-call") }, - { str_lit("generic"), str_lit("mutable-globals,sign-ext") }, - { str_lit("mvp"), str_lit("") }, -}; +#include "build_settings_microarch.cpp" gb_global String target_endian_names[TargetEndian_COUNT] = { str_lit("little"), @@ -742,10 +281,12 @@ enum VetFlags : u64 { VetFlag_UnusedVariables = 1u<<5, VetFlag_UnusedImports = 1u<<6, VetFlag_Deprecated = 1u<<7, + VetFlag_Cast = 1u<<8, + VetFlag_Tabs = 1u<<9, VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports, - VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt|VetFlag_Deprecated, + VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt|VetFlag_Deprecated|VetFlag_Cast, VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam, }; @@ -769,6 +310,10 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_Semicolon; } else if (name == "deprecated") { return VetFlag_Deprecated; + } else if (name == "cast") { + return VetFlag_Cast; + } else if (name == "tabs") { + return VetFlag_Tabs; } return VetFlag_NONE; } @@ -781,7 +326,17 @@ enum SanitizerFlags : u32 { SanitizerFlag_Thread = 1u<<2, }; +struct BuildCacheData { + u64 crc; + String cache_dir; + // manifests + String files_path; + String args_path; + String env_path; + + bool copy_already_done; +}; // This stores the information for the specify architecture of this build struct BuildContext { @@ -844,6 +399,8 @@ struct BuildContext { bool show_unused; bool show_unused_with_location; bool show_more_timings; + bool show_defineables; + String export_defineables_file; bool show_system_calls; bool keep_temp_files; bool ignore_unknown_attributes; @@ -860,6 +417,8 @@ struct BuildContext { bool keep_object_files; bool disallow_do; + StringSet custom_attributes; + bool strict_style; bool ignore_warnings; @@ -871,11 +430,16 @@ struct BuildContext { bool ignore_lazy; bool ignore_llvm_build; + bool ignore_panic; bool ignore_microsoft_magic; bool linker_map_file; bool use_separate_modules; + bool module_per_file; + bool cached; + BuildCacheData build_cache_data; + bool no_threaded_checker; bool show_debug_messages; @@ -890,6 +454,8 @@ struct BuildContext { bool min_link_libs; + bool print_linker_flags; + RelocMode reloc_mode; bool disable_red_zone; @@ -1310,15 +876,6 @@ gb_internal bool is_arch_x86(void) { return false; } -gb_internal bool allow_check_foreign_filepath(void) { - switch (build_context.metrics.arch) { - case TargetArch_wasm32: - case TargetArch_wasm64p32: - return false; - } - return true; -} - // TODO(bill): OS dependent versions for the BuildContext // join_path // is_dir @@ -1880,6 +1437,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta bc->thread_count = gb_max(bc->affinity.thread_count, 1); } + string_set_init(&bc->custom_attributes); + bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VERSION = ODIN_VERSION; bc->ODIN_ROOT = odin_root_dir(); @@ -2051,10 +1610,12 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta gbString link_flags = gb_string_make(heap_allocator(), " "); // link_flags = gb_string_appendc(link_flags, "--export-all "); // link_flags = gb_string_appendc(link_flags, "--export-table "); - link_flags = gb_string_appendc(link_flags, "--allow-undefined "); // if (bc->metrics.arch == TargetArch_wasm64) { // link_flags = gb_string_appendc(link_flags, "-mwasm64 "); // } + if (bc->metrics.os != TargetOs_orca) { + link_flags = gb_string_appendc(link_flags, "--allow-undefined "); + } if (bc->no_entry_point || bc->metrics.os == TargetOs_orca) { link_flags = gb_string_appendc(link_flags, "--no-entry "); } @@ -2085,7 +1646,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta } } - if (bc->ODIN_DEBUG && !bc->custom_optimization_level) { + if (!bc->custom_optimization_level) { // NOTE(bill): when building with `-debug` but not specifying an optimization level // default to `-o:none` to improve the debug symbol generation by default bc->optimization_level = -1; // -o:none @@ -2244,10 +1805,11 @@ gb_internal bool init_build_paths(String init_filename) { #if defined(GB_SYSTEM_WINDOWS) if (bc->metrics.os == TargetOs_windows) { if (bc->resource_filepath.len > 0) { - bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); - bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); - bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc")); - bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res")); + bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); + if (!string_ends_with(bc->resource_filepath, str_lit(".res"))) { + bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); + bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc")); + } } if (bc->pdb_filepath.len > 0) { diff --git a/src/build_settings_microarch.cpp b/src/build_settings_microarch.cpp new file mode 100644 index 000000000..02b507031 --- /dev/null +++ b/src/build_settings_microarch.cpp @@ -0,0 +1,462 @@ +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_microarch_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), + // TargetArch_i386: + str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), + // TargetArch_arm32: + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + // TargetArch_arm64: + str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + // TargetArch_wasm32: + str_lit("bleeding-edge,generic,mvp"), + // TargetArch_wasm64p32: + str_lit("bleeding-edge,generic,mvp"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_features_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), + // TargetArch_i386: + str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), + // TargetArch_arm32: + str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aapcs-frame-chain-leaf,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,atomics-32,avoid-movs-shop,avoid-partial-cpsr,bf16,big-endian-instructions,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a710,cortex-a78,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m7,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), + // TargetArch_arm64: + str_lit("CONTEXTIDREL2,a35,a510,a53,a55,a57,a64fx,a65,a710,a715,a72,a73,a75,a76,a77,a78,a78c,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,am,ampere1,ampere1a,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,b16b16,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,complxnum,cortex-r82,cortex-x1,cortex-x2,cortex-x3,crc,crypto,cssc,custom-cheap-as-move,d128,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,falkor,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,lor,ls64,lse,lse128,lse2,lsl-fast,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversev1,neoversev2,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,outline-atomics,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x30,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-f16f16,sme-f64f64,sme-i16i64,sme2,sme2p1,spe,spe-eef,specres2,specrestrict,ssbs,strict-align,sve,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-postra-scheduler,use-reciprocal-square-root,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vh,wfxt,xs,zcm,zcz,zcz-fp-workaround,zcz-gp"), + // TargetArch_wasm32: + str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), + // TargetArch_wasm64p32: + str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global int target_microarch_counts[TargetArch_COUNT] = { + // TargetArch_Invalid: + 0, + // TargetArch_amd64: + 120, + // TargetArch_i386: + 120, + // TargetArch_arm32: + 90, + // TargetArch_arm64: + 63, + // TargetArch_wasm32: + 3, + // TargetArch_wasm64p32: + 3, +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global MicroarchFeatureList microarch_features_list[] = { + // TargetArch_amd64: + { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("athlon"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("64bit,64bit-mode,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("64bit,64bit-mode,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-15bytenop,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("3dnow,64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("emeraldrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("64bit,64bit-mode,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,sse,sse2,vzeroupper,x87") }, + { str_lit("geode"), str_lit("3dnow,3dnowa,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i486"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i586"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i686"), str_lit("64bit-mode,cmov,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("3dnow,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("3dnow,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") }, + { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("64bit,64bit-mode,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("3dnow,64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("64bit,64bit-mode,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_i386: + { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("athlon"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("32bit-mode,64bit,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("32bit-mode,64bit,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-15bytenop,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("32bit-mode,3dnow,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("emeraldrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("32bit-mode,64bit,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,vzeroupper,x87") }, + { str_lit("geode"), str_lit("32bit-mode,3dnow,3dnowa,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i486"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i586"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i686"), str_lit("32bit-mode,cmov,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("32bit-mode,3dnow,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("32bit-mode,3dnow,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k8"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") }, + { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("32bit-mode,64bit,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("32bit-mode,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("32bit-mode,3dnow,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("32bit-mode,64bit,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_arm32: + { str_lit("arm1020e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm1020t"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1022e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10tdmi"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1136j-s"), str_lit("armv6,dsp,v4t,v5t,v5te,v6") }, + { str_lit("arm1136jf-s"), str_lit("armv6,dsp,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,vfp2,vfp2sp") }, + { str_lit("arm1156t2-s"), str_lit("armv6t2,dsp,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m") }, + { str_lit("arm1156t2f-s"), str_lit("armv6t2,dsp,fp64,fpregs,fpregs64,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m,vfp2,vfp2sp") }, + { str_lit("arm1176jz-s"), str_lit("armv6kz,trustzone,v4t,v5t,v5te,v6,v6k") }, + { str_lit("arm1176jzf-s"), str_lit("armv6kz,fp64,fpregs,fpregs64,slowfpvmlx,trustzone,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("arm710t"), str_lit("armv4t,v4t") }, + { str_lit("arm720t"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi-s"), str_lit("armv4t,v4t") }, + { str_lit("arm8"), str_lit("armv4") }, + { str_lit("arm810"), str_lit("armv4") }, + { str_lit("arm9"), str_lit("armv4t,v4t") }, + { str_lit("arm920"), str_lit("armv4t,v4t") }, + { str_lit("arm920t"), str_lit("armv4t,v4t") }, + { str_lit("arm922t"), str_lit("armv4t,v4t") }, + { str_lit("arm926ej-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm940t"), str_lit("armv4t,v4t") }, + { str_lit("arm946e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm966e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9tdmi"), str_lit("armv4t,v4t") }, + { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,neon,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, + { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, + { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a75"), str_lit("a75,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76ae"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,neon,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m23"), str_lit("8msecext,acquire-release,armv8-m.base,db,hwdiv,mclass,no-branch-predictor,no-movt,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m,v7clrex,v8m") }, + { str_lit("cortex-m3"), str_lit("armv7-m,db,hwdiv,loop-align,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m7"), str_lit("armv7e-m,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-r4"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,hwdiv,perfmon,r4,rclass,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-r4f"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,perfmon,r4,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r5"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,perfmon,r5,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r52"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r7"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,r7,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r8"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-x1"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-x1c"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1c,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cyclone"), str_lit("aclass,acquire-release,aes,armv8-a,avoid-movs-shop,avoid-partial-cpsr,crc,crypto,d32,db,disable-postra-scheduler,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,ret-addr-stack,sha2,slowfpvfmx,slowfpvmlx,swift,thumb2,trustzone,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,zcz") }, + { str_lit("ep9312"), str_lit("armv4t,v4t") }, + { str_lit("exynos-m3"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dont-widen-vmovs,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m4"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("generic"), str_lit("") }, + { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,neon,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, + { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") }, + { str_lit("neoverse-n1"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-n2"), str_lit("aclass,acquire-release,armv9-a,bf16,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-v1"), str_lit("aclass,acquire-release,aes,armv8.4-a,bf16,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("sc000"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("sc300"), str_lit("armv7-m,db,hwdiv,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("strongarm"), str_lit("armv4") }, + { str_lit("strongarm110"), str_lit("armv4") }, + { str_lit("strongarm1100"), str_lit("armv4") }, + { str_lit("strongarm1110"), str_lit("armv4") }, + { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, + { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") }, + // TargetArch_arm64: + { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("ampere1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a13"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-latest"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,crypto,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a34"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a35"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a57"), str_lit("a57,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a65"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a65ae"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a72"), str_lit("a72,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a73"), str_lit("a73,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76ae"), str_lit("CONTEXTIDREL2,a76,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a77"), str_lit("CONTEXTIDREL2,a77,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78"), str_lit("CONTEXTIDREL2,a78,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78c"), str_lit("CONTEXTIDREL2,a78c,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-r82"), str_lit("CONTEXTIDREL2,ccidx,ccpp,complxnum,cortex-r82,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-x1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("exynos-m3"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") }, + { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("exynos-m5"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("falkor"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,falkor,fp-armv8,neon,perfmon,predictable-select-expensive,rdm,sha2,slow-strqro-store,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("generic"), str_lit("enable-select-opt,ete,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler") }, + { str_lit("kryo"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,fp-armv8,kryo,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("neoverse-512tvb"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoverse512tvb,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-e1"), str_lit("CONTEXTIDREL2,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversee1,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversen1,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-v1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoversev1,no-sve-fp-ld1r,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-v2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("saphira"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,saphira,sel2,sha2,spe,store-pair-suppress,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcz,zcz-gp") }, + { str_lit("thunderx"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderx,use-postra-scheduler,v8a") }, + { str_lit("thunderx2t99"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,crc,crypto,el2vmsa,el3,fp-armv8,lor,lse,neon,pan,predictable-select-expensive,rdm,sha2,store-pair-suppress,thunderx2t99,use-postra-scheduler,v8.1a,v8a,vh") }, + { str_lit("thunderx3t110"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,balance-fp-ops,ccidx,ccpp,complxnum,crc,crypto,el2vmsa,el3,fp-armv8,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,store-pair-suppress,strict-align,thunderx3t110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8a,vh") }, + { str_lit("thunderxt81"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt81,use-postra-scheduler,v8a") }, + { str_lit("thunderxt83"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt83,use-postra-scheduler,v8a") }, + { str_lit("thunderxt88"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt88,use-postra-scheduler,v8a") }, + { str_lit("tsv110"), str_lit("CONTEXTIDREL2,aes,ccpp,complxnum,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fp16fml,fullfp16,fuse-aes,jsconv,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,spe,store-pair-suppress,tsv110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + // TargetArch_wasm32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,mutable-globals,nontrapping-fptoint,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("mutable-globals,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_wasm64p32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,mutable-globals,nontrapping-fptoint,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("mutable-globals,sign-ext") }, + { str_lit("mvp"), str_lit("") }, +}; \ No newline at end of file diff --git a/src/cached.cpp b/src/cached.cpp new file mode 100644 index 000000000..7f213ba21 --- /dev/null +++ b/src/cached.cpp @@ -0,0 +1,461 @@ +gb_internal GB_COMPARE_PROC(string_cmp) { + String const &x = *(String *)a; + String const &y = *(String *)b; + return string_compare(x, y); +} + +gb_internal bool recursively_delete_directory(wchar_t *wpath_c) { +#if defined(GB_SYSTEM_WINDOWS) + auto const is_dots_w = [](wchar_t const *str) -> bool { + if (!str) { + return false; + } + return wcscmp(str, L".") == 0 || wcscmp(str, L"..") == 0; + }; + + TEMPORARY_ALLOCATOR_GUARD(); + + wchar_t dir_path[MAX_PATH] = {}; + wchar_t filename[MAX_PATH] = {}; + wcscpy(dir_path, wpath_c); + wcscat(dir_path, L"\\*"); + + wcscpy(filename, wpath_c); + wcscat(filename, L"\\"); + + + WIN32_FIND_DATAW find_file_data = {}; + HANDLE hfind = FindFirstFileW(dir_path, &find_file_data); + if (hfind == INVALID_HANDLE_VALUE) { + return false; + } + defer (FindClose(hfind)); + + wcscpy(dir_path, filename); + + for (;;) { + if (FindNextFileW(hfind, &find_file_data)) { + if (is_dots_w(find_file_data.cFileName)) { + continue; + } + wcscat(filename, find_file_data.cFileName); + + if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (!recursively_delete_directory(filename)) { + return false; + } + RemoveDirectoryW(filename); + wcscpy(filename, dir_path); + } else { + if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + _wchmod(filename, _S_IWRITE); + } + if (!DeleteFileW(filename)) { + return false; + } + wcscpy(filename, dir_path); + } + } else { + if (GetLastError() == ERROR_NO_MORE_FILES) { + break; + } + return false; + } + } + + + return RemoveDirectoryW(wpath_c); +#else + return false; +#endif +} + +gb_internal bool recursively_delete_directory(String const &path) { +#if defined(GB_SYSTEM_WINDOWS) + String16 wpath = string_to_string16(permanent_allocator(), path); + wchar_t *wpath_c = alloc_wstring(permanent_allocator(), wpath); + return recursively_delete_directory(wpath_c); +#else + return false; +#endif +} + +gb_internal bool try_clear_cache(void) { + return recursively_delete_directory(str_lit(".odin-cache")); +} + + +gb_internal u64 crc64_with_seed(void const *data, isize len, u64 seed) { + isize remaining; + u64 result = ~seed; + u8 const *c = cast(u8 const *)data; + for (remaining = len; remaining--; c++) { + result = (result >> 8) ^ (GB__CRC64_TABLE[(result ^ *c) & 0xff]); + } + return ~result; +} + +gb_internal bool check_if_exists_file_otherwise_create(String const &str) { + char const *str_c = alloc_cstring(permanent_allocator(), str); + if (!gb_file_exists(str_c)) { + gbFile f = {}; + gb_file_create(&f, str_c); + gb_file_close(&f); + return true; + } + return false; +} + + +gb_internal bool check_if_exists_directory_otherwise_create(String const &str) { +#if defined(GB_SYSTEM_WINDOWS) + String16 wstr = string_to_string16(permanent_allocator(), str); + wchar_t *wstr_c = alloc_wstring(permanent_allocator(), wstr); + return CreateDirectoryW(wstr_c, nullptr); +#else + char const *str_c = alloc_cstring(permanent_allocator(), str); + if (!gb_file_exists(str_c)) { + int status = mkdir(str_c, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + return status == 0; + } + return false; +#endif +} +gb_internal bool try_copy_executable_cache_internal(bool to_cache) { + String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); + defer (gb_free(heap_allocator(), exe_name.text)); + + gbString cache_name = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(cache_name)); + + String cache_dir = build_context.build_cache_data.cache_dir; + + cache_name = gb_string_append_length(cache_name, cache_dir.text, cache_dir.len); + cache_name = gb_string_appendc(cache_name, "/"); + + cache_name = gb_string_appendc(cache_name, "cached-exe"); + if (selected_target_metrics) { + cache_name = gb_string_appendc(cache_name, "-"); + cache_name = gb_string_append_length(cache_name, selected_target_metrics->name.text, selected_target_metrics->name.len); + } + if (selected_subtarget) { + String st = subtarget_strings[selected_subtarget]; + cache_name = gb_string_appendc(cache_name, "-"); + cache_name = gb_string_append_length(cache_name, st.text, st.len); + } + cache_name = gb_string_appendc(cache_name, ".bin"); + + if (to_cache) { + return gb_file_copy( + alloc_cstring(temporary_allocator(), exe_name), + cache_name, + false + ); + } else { + return gb_file_copy( + cache_name, + alloc_cstring(temporary_allocator(), exe_name), + false + ); + } +} + + + +gb_internal bool try_copy_executable_to_cache(void) { + debugf("Cache: try_copy_executable_to_cache\n"); + + if (try_copy_executable_cache_internal(true)) { + build_context.build_cache_data.copy_already_done = true; + return true; + } + return false; +} + +gb_internal bool try_copy_executable_from_cache(void) { + debugf("Cache: try_copy_executable_from_cache\n"); + + if (try_copy_executable_cache_internal(false)) { + build_context.build_cache_data.copy_already_done = true; + return true; + } + return false; +} + + +#if !defined(GB_SYSTEM_WINDOWS) +extern char **environ; +#endif + +// returns false if different, true if it is the same +gb_internal bool try_cached_build(Checker *c, Array const &args) { + TEMPORARY_ALLOCATOR_GUARD(); + + Parser *p = c->parser; + + auto files = array_make(heap_allocator()); + for (AstPackage *pkg : p->packages) { + for (AstFile *f : pkg->files) { + array_add(&files, f->fullpath); + } + } + + #if defined(GB_SYSTEM_WINDOWS) + if (build_context.has_resource) { + String res_path = {}; + if (build_context.build_paths[BuildPath_RC].basename == "") { + res_path = path_to_string(permanent_allocator(), build_context.build_paths[BuildPath_RES]); + } else { + res_path = path_to_string(permanent_allocator(), build_context.build_paths[BuildPath_RC]); + } + array_add(&files, res_path); + } + #endif + + for (auto const &entry : c->info.load_file_cache) { + auto *cache = entry.value; + if (!cache || !cache->exists) { + continue; + } + array_add(&files, cache->path); + } + + array_sort(files, string_cmp); + + u64 crc = 0; + for (String const &path : files) { + crc = crc64_with_seed(path.text, path.len, crc); + } + + String base_cache_dir = build_context.build_paths[BuildPath_Output].basename; + base_cache_dir = concatenate_strings(permanent_allocator(), base_cache_dir, str_lit("/.odin-cache")); + (void)check_if_exists_directory_otherwise_create(base_cache_dir); + + gbString crc_str = gb_string_make_reserve(permanent_allocator(), 16); + crc_str = gb_string_append_fmt(crc_str, "%016llx", crc); + String cache_dir = concatenate3_strings(permanent_allocator(), base_cache_dir, str_lit("/"), make_string_c(crc_str)); + String files_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("files.manifest")); + String args_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("args.manifest")); + String env_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("env.manifest")); + + build_context.build_cache_data.cache_dir = cache_dir; + build_context.build_cache_data.files_path = files_path; + build_context.build_cache_data.args_path = args_path; + build_context.build_cache_data.env_path = env_path; + + auto envs = array_make(heap_allocator()); + defer (array_free(&envs)); + { + #if defined(GB_SYSTEM_WINDOWS) + wchar_t *strings = GetEnvironmentStringsW(); + defer (FreeEnvironmentStringsW(strings)); + + wchar_t *curr_string = strings; + while (curr_string && *curr_string) { + String16 wstr = make_string16_c(curr_string); + curr_string += wstr.len+1; + String str = string16_to_string(temporary_allocator(), wstr); + if (string_starts_with(str, str_lit("CURR_DATE_TIME="))) { + continue; + } + array_add(&envs, str); + } + #else + char **curr_env = environ; + while (curr_env && *curr_env) { + String str = make_string_c(*curr_env++); + if (string_starts_with(str, str_lit("PROMPT="))) { + continue; + } + if (string_starts_with(str, str_lit("RPROMPT="))) { + continue; + } + array_add(&envs, str); + } + #endif + } + array_sort(envs, string_cmp); + + if (check_if_exists_directory_otherwise_create(cache_dir)) { + goto write_cache; + } + + if (check_if_exists_file_otherwise_create(files_path)) { + goto write_cache; + } + if (check_if_exists_file_otherwise_create(args_path)) { + goto write_cache; + } + if (check_if_exists_file_otherwise_create(env_path)) { + goto write_cache; + } + + { + // exists already + LoadedFile loaded_file = {}; + + LoadedFileError file_err = load_file_32( + alloc_cstring(temporary_allocator(), files_path), + &loaded_file, + false + ); + if (file_err > LoadedFile_Empty) { + return false; + } + + String data = {cast(u8 *)loaded_file.data, loaded_file.size}; + String_Iterator it = {data, 0}; + + isize file_count = 0; + + for (; it.pos < data.len; file_count++) { + String line = string_split_iterator(&it, '\n'); + if (line.len == 0) { + break; + } + isize sep = string_index_byte(line, ' '); + if (sep < 0) { + goto write_cache; + } + + String timestamp_str = substring(line, 0, sep); + String path_str = substring(line, sep+1, line.len); + + timestamp_str = string_trim_whitespace(timestamp_str); + path_str = string_trim_whitespace(path_str); + + if (file_count >= files.count) { + goto write_cache; + } + if (files[file_count] != path_str) { + goto write_cache; + } + + u64 timestamp = exact_value_to_u64(exact_value_integer_from_string(timestamp_str)); + gbFileTime last_write_time = gb_file_last_write_time(alloc_cstring(temporary_allocator(), path_str)); + if (last_write_time != timestamp) { + goto write_cache; + } + } + + if (file_count != files.count) { + goto write_cache; + } + } + { + LoadedFile loaded_file = {}; + + LoadedFileError file_err = load_file_32( + alloc_cstring(temporary_allocator(), args_path), + &loaded_file, + false + ); + if (file_err > LoadedFile_Empty) { + return false; + } + + String data = {cast(u8 *)loaded_file.data, loaded_file.size}; + String_Iterator it = {data, 0}; + + isize args_count = 0; + + for (; it.pos < data.len; args_count++) { + String line = string_split_iterator(&it, '\n'); + line = string_trim_whitespace(line); + if (line.len == 0) { + break; + } + if (args_count >= args.count) { + goto write_cache; + } + + if (line != args[args_count]) { + goto write_cache; + } + } + } + { + LoadedFile loaded_file = {}; + + LoadedFileError file_err = load_file_32( + alloc_cstring(temporary_allocator(), env_path), + &loaded_file, + false + ); + if (file_err > LoadedFile_Empty) { + return false; + } + + String data = {cast(u8 *)loaded_file.data, loaded_file.size}; + String_Iterator it = {data, 0}; + + isize env_count = 0; + + for (; it.pos < data.len; env_count++) { + String line = string_split_iterator(&it, '\n'); + line = string_trim_whitespace(line); + if (line.len == 0) { + break; + } + if (env_count >= envs.count) { + goto write_cache; + } + + if (line != envs[env_count]) { + goto write_cache; + } + } + } + + return try_copy_executable_from_cache(); + +write_cache:; + { + char const *path_c = alloc_cstring(temporary_allocator(), files_path); + gb_file_remove(path_c); + + debugf("Cache: updating %s\n", path_c); + + gbFile f = {}; + defer (gb_file_close(&f)); + gb_file_open_mode(&f, gbFileMode_Write, path_c); + + for (String const &path : files) { + gbFileTime ft = gb_file_last_write_time(alloc_cstring(temporary_allocator(), path)); + gb_fprintf(&f, "%llu %.*s\n", cast(unsigned long long)ft, LIT(path)); + } + } + { + char const *path_c = alloc_cstring(temporary_allocator(), args_path); + gb_file_remove(path_c); + + debugf("Cache: updating %s\n", path_c); + + gbFile f = {}; + defer (gb_file_close(&f)); + gb_file_open_mode(&f, gbFileMode_Write, path_c); + + for (String const &arg : args) { + String targ = string_trim_whitespace(arg); + gb_fprintf(&f, "%.*s\n", LIT(targ)); + } + } + { + char const *path_c = alloc_cstring(temporary_allocator(), env_path); + gb_file_remove(path_c); + + debugf("Cache: updating %s\n", path_c); + + gbFile f = {}; + defer (gb_file_close(&f)); + gb_file_open_mode(&f, gbFileMode_Write, path_c); + + for (String const &env : envs) { + gb_fprintf(&f, "%.*s\n", LIT(env)); + } + } + + + return false; +} + diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 3aee804df..eec01b497 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1296,6 +1296,9 @@ gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand gb_internal int file_cache_sort_cmp(void const *x, void const *y) { LoadFileCache const *a = *(LoadFileCache const **)(x); LoadFileCache const *b = *(LoadFileCache const **)(y); + if (a == b) { + return 0; + } return string_compare(a->path, b->path); } @@ -1726,11 +1729,13 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o gb_string_free(str); return false; } - error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); - if (c->proc_name != "") { - gbString str = type_to_string(c->curr_proc_sig); - error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); - gb_string_free(str); + if (!build_context.ignore_panic) { + error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } } operand->type = t_invalid; operand->mode = Addressing_NoValue; @@ -1756,9 +1761,21 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->mode = Addressing_Constant; operand->value = exact_value_bool(is_defined); + // If the arg is a selector expression we don't add it, `-define` only allows identifiers. + if (arg->kind == Ast_Ident) { + Defineable defineable = {}; + defineable.docs = nullptr; + defineable.name = arg->Ident.token.string; + defineable.default_value = exact_value_bool(false); + defineable.pos = arg->Ident.token.pos; + + MUTEX_GUARD(&c->info->defineables_mutex); + array_add(&c->info->defineables, defineable); + } + } else if (name == "config") { if (ce->args.count != 2) { - error(call, "'#config' expects 2 argument, got %td", ce->args.count); + error(call, "'#config' expects 2 arguments, got %td", ce->args.count); return false; } Ast *arg = unparen_expr(ce->args[0]); @@ -1793,6 +1810,20 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->value = found->Constant.value; } } + + Defineable defineable = {}; + defineable.docs = nullptr; + defineable.name = name; + defineable.default_value = def.value; + defineable.pos = arg->Ident.token.pos; + + if (c->decl) { + defineable.docs = c->decl->docs; + } + + MUTEX_GUARD(&c->info->defineables_mutex); + array_add(&c->info->defineables, defineable); + } else { error(call, "Unknown directive call: #%.*s", LIT(name)); } @@ -2262,6 +2293,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(o.expr, "Invalid argument to 'type_of'"); return false; } + + if (is_type_untyped(o.type)) { + gbString t = type_to_string(o.type); + error(o.expr, "'type_of' of %s cannot be determined", t); + gb_string_free(t); + return false; + } + // NOTE(bill): Prevent type cycles for procedure declarations if (c->curr_proc_sig == o.type) { gbString s = expr_to_string(o.expr); @@ -5089,15 +5128,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As isize max_arg_count = 32; switch (build_context.metrics.os) { - case TargetOs_windows: - case TargetOs_freestanding: - error(call, "'%.*s' is not supported on this platform (%.*s)", LIT(builtin_name), LIT(target_os_names[build_context.metrics.os])); - break; case TargetOs_darwin: case TargetOs_linux: case TargetOs_essence: - case TargetOs_freebsd: - case TargetOs_openbsd: case TargetOs_haiku: switch (build_context.metrics.arch) { case TargetArch_i386: @@ -5107,6 +5140,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } break; + default: + error(call, "'%.*s' is not supported on this platform (%.*s)", LIT(builtin_name), LIT(target_os_names[build_context.metrics.os])); + break; } if (ce->args.count > max_arg_count) { @@ -5120,6 +5156,55 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return true; } break; + case BuiltinProc_syscall_bsd: + { + convert_to_typed(c, operand, t_uintptr); + if (!is_type_uintptr(operand->type)) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Argument 0 must be of type 'uintptr', got %s", t); + gb_string_free(t); + } + for (isize i = 1; i < ce->args.count; i++) { + Operand x = {}; + check_expr(c, &x, ce->args[i]); + if (x.mode != Addressing_Invalid) { + convert_to_typed(c, &x, t_uintptr); + } + convert_to_typed(c, &x, t_uintptr); + if (!is_type_uintptr(x.type)) { + gbString t = type_to_string(x.type); + error(x.expr, "Argument %td must be of type 'uintptr', got %s", i, t); + gb_string_free(t); + } + } + + isize max_arg_count = 32; + + switch (build_context.metrics.os) { + case TargetOs_freebsd: + case TargetOs_netbsd: + case TargetOs_openbsd: + switch (build_context.metrics.arch) { + case TargetArch_amd64: + case TargetArch_arm64: + max_arg_count = 7; + break; + } + break; + default: + error(call, "'%.*s' is not supported on this platform (%.*s)", LIT(builtin_name), LIT(target_os_names[build_context.metrics.os])); + break; + } + + if (ce->args.count > max_arg_count) { + error(ast_end_token(call), "'%.*s' has a maximum of %td arguments on this platform (%.*s), got %td", LIT(builtin_name), max_arg_count, LIT(target_os_names[build_context.metrics.os]), ce->args.count); + } + + operand->mode = Addressing_Value; + operand->type = make_optional_ok_type(t_uintptr); + return true; + } + break; case BuiltinProc_type_base_type: @@ -5765,6 +5850,31 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->mode = Addressing_Constant; operand->type = t_untyped_integer; break; + case BuiltinProc_type_struct_has_implicit_padding: + operand->value = exact_value_bool(false); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a struct type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_struct(operand->type) && !is_type_soa_struct(operand->type)) { + error(operand->expr, "Expected a struct type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + if (bt->Struct.is_packed) { + operand->value = exact_value_bool(false); + } else if (bt->Struct.fields.count != 0) { + i64 size = type_size_of(bt); + Type *field_type = nullptr; + i64 last_offset = type_offset_of(bt, bt->Struct.fields.count-1, &field_type); + if (last_offset+type_size_of(field_type) < size) { + operand->value = exact_value_bool(true); + } else { + i64 packed_size = type_size_of_struct_pretend_is_packed(bt); + operand->value = exact_value_bool(packed_size < size); + } + } + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; case BuiltinProc_type_proc_parameter_count: operand->value = exact_value_i64(0); diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 02445cbc6..7d81d102d 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -155,6 +155,155 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l } } + +gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { + // NOTE(bill): The original_entity's scope may not be same scope that it was inserted into + // e.g. file entity inserted into its package scope + String original_name = original_entity->token.string; + Scope *found_scope = nullptr; + Entity *found_entity = nullptr; + scope_lookup_parent(original_entity->scope, original_name, &found_scope, &found_entity); + if (found_scope == nullptr) { + return; + } + rw_mutex_lock(&found_scope->mutex); + defer (rw_mutex_unlock(&found_scope->mutex)); + + // IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the + // original entity was still used check checked, but the checking was only + // relying on "constant" data such as the Entity.type and Entity.Constant.value + // + // Therefore two things can be done: the type can be assigned to state that it + // has been "evaluated" and the variant data can be copied across + + string_map_set(&found_scope->elements, original_name, new_entity); + + original_entity->flags |= EntityFlag_Overridden; + original_entity->type = new_entity->type; + original_entity->aliased_of = new_entity; + + Ast *empty_ident = nullptr; + original_entity->identifier.compare_exchange_strong(empty_ident, new_entity->identifier); + + if (original_entity->identifier.load() != nullptr && + original_entity->identifier.load()->kind == Ast_Ident) { + original_entity->identifier.load()->Ident.entity = new_entity; + } + + // IMPORTANT NOTE(bill, 2021-04-10): copy only the variants + // This is most likely NEVER required, but it does not at all hurt to keep + isize offset = cast(u8 *)&original_entity->Dummy.start - cast(u8 *)original_entity; + isize size = gb_size_of(*original_entity) - offset; + gb_memmove(cast(u8 *)original_entity, cast(u8 *)new_entity, size); +} + +gb_internal bool check_override_as_type_due_to_aliasing(CheckerContext *ctx, Entity *e, Entity *entity, Ast *init, Type *named_type) { + if (entity != nullptr && entity->kind == Entity_TypeName) { + // @TypeAliasingProblem + // NOTE(bill, 2022-02-03): This is used to solve the problem caused by type aliases + // being "confused" as constants + // + // A :: B + // C :: proc "c" (^A) + // B :: struct {x: C} + // + // A gets evaluated first, and then checks B. + // B then checks C. + // C then tries to check A which is unresolved but thought to be a constant. + // Therefore within C's check, A errs as "not a type". + // + // This is because a const declaration may or may not be a type and this cannot + // be determined from a syntactical standpoint. + // This check allows the compiler to override the entity to be checked as a type. + // + // There is no problem if B is prefixed with the `#type` helper enforcing at + // both a syntax and semantic level that B must be a type. + // + // A :: #type B + // + // This approach is not fool proof and can fail in case such as: + // + // X :: type_of(x) + // X :: Foo(int).Type + // + // Since even these kind of declarations may cause weird checking cycles. + // For the time being, these are going to be treated as an unfortunate error + // until there is a proper delaying system to try declaration again if they + // have failed. + + e->kind = Entity_TypeName; + check_type_decl(ctx, e, init, named_type); + return true; + } + return false; +} + +gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d); + +gb_internal bool check_try_override_const_decl(CheckerContext *ctx, Entity *e, Entity *entity, Ast *init, Type *named_type) { + if (entity == nullptr) { + retry_proc_lit:; + init = unparen_expr(init); + if (init == nullptr) { + return false; + } + if (init->kind == Ast_TernaryWhenExpr) { + ast_node(we, TernaryWhenExpr, init); + if (we->cond == nullptr) { + return false; + } + if (we->cond->tav.value.kind != ExactValue_Bool) { + return false; + } + init = we->cond->tav.value.value_bool ? we->x : we->y; + goto retry_proc_lit; + } if (init->kind == Ast_ProcLit) { + // NOTE(bill, 2024-07-04): Override as a procedure entity because this could be within a `when` statement + e->kind = Entity_Procedure; + e->type = nullptr; + DeclInfo *d = decl_info_of_entity(e); + d->proc_lit = init; + check_proc_decl(ctx, e, d); + return true; + } + + return false; + } + switch (entity->kind) { + case Entity_TypeName: + if (check_override_as_type_due_to_aliasing(ctx, e, entity, init, named_type)) { + return true; + } + break; + case Entity_Builtin: + if (e->type != nullptr) { + return false; + } + e->kind = Entity_Builtin; + e->Builtin.id = entity->Builtin.id; + e->type = t_invalid; + return true; + } + + if (e->type != nullptr && entity->type != nullptr) { + Operand x = {}; + x.type = entity->type; + x.mode = Addressing_Variable; + if (!check_is_assignable_to(ctx, &x, e->type)) { + return false; + } + } + + // NOTE(bill): Override aliased entity + switch (entity->kind) { + case Entity_ProcGroup: + case Entity_Procedure: + override_entity_in_scope(e, entity); + return true; + } + return false; +} + gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { if (operand->mode == Addressing_Invalid || operand->type == t_invalid || @@ -165,6 +314,13 @@ gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *op return; } + if (operand->mode != Addressing_Constant) { + Entity *entity = entity_of_node(operand->expr); + if (check_try_override_const_decl(ctx, e, entity, operand->expr, nullptr)) { + return; + } + } + if (operand->mode != Addressing_Constant) { gbString str = expr_to_string(operand->expr); error(operand->expr, "'%s' is not a compile-time known constant", str); @@ -373,49 +529,6 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, } -gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { - // NOTE(bill): The original_entity's scope may not be same scope that it was inserted into - // e.g. file entity inserted into its package scope - String original_name = original_entity->token.string; - Scope *found_scope = nullptr; - Entity *found_entity = nullptr; - scope_lookup_parent(original_entity->scope, original_name, &found_scope, &found_entity); - if (found_scope == nullptr) { - return; - } - rw_mutex_lock(&found_scope->mutex); - defer (rw_mutex_unlock(&found_scope->mutex)); - - // IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the - // original entity was still used check checked, but the checking was only - // relying on "constant" data such as the Entity.type and Entity.Constant.value - // - // Therefore two things can be done: the type can be assigned to state that it - // has been "evaluated" and the variant data can be copied across - - string_map_set(&found_scope->elements, original_name, new_entity); - - original_entity->flags |= EntityFlag_Overridden; - original_entity->type = new_entity->type; - original_entity->aliased_of = new_entity; - - Ast *empty_ident = nullptr; - original_entity->identifier.compare_exchange_strong(empty_ident, new_entity->identifier); - - if (original_entity->identifier.load() != nullptr && - original_entity->identifier.load()->kind == Ast_Ident) { - original_entity->identifier.load()->Ident.entity = new_entity; - } - - // IMPORTANT NOTE(bill, 2021-04-10): copy only the variants - // This is most likely NEVER required, but it does not at all hurt to keep - isize offset = cast(u8 *)&original_entity->Dummy.start - cast(u8 *)original_entity; - isize size = gb_size_of(*original_entity) - offset; - gb_memmove(cast(u8 *)original_entity, cast(u8 *)new_entity, size); -} - - - gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Constant); @@ -441,41 +554,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr if (init != nullptr) { Entity *entity = check_entity_from_ident_or_selector(ctx, init, false); - if (entity != nullptr && entity->kind == Entity_TypeName) { - // @TypeAliasingProblem - // NOTE(bill, 2022-02-03): This is used to solve the problem caused by type aliases - // being "confused" as constants - // - // A :: B - // C :: proc "c" (^A) - // B :: struct {x: C} - // - // A gets evaluated first, and then checks B. - // B then checks C. - // C then tries to check A which is unresolved but thought to be a constant. - // Therefore within C's check, A errs as "not a type". - // - // This is because a const declaration may or may not be a type and this cannot - // be determined from a syntactical standpoint. - // This check allows the compiler to override the entity to be checked as a type. - // - // There is no problem if B is prefixed with the `#type` helper enforcing at - // both a syntax and semantic level that B must be a type. - // - // A :: #type B - // - // This approach is not fool proof and can fail in case such as: - // - // X :: type_of(x) - // X :: Foo(int).Type - // - // Since even these kind of declarations may cause weird checking cycles. - // For the time being, these are going to be treated as an unfortunate error - // until there is a proper delaying system to try declaration again if they - // have failed. - - e->kind = Entity_TypeName; - check_type_decl(ctx, e, init, named_type); + if (check_override_as_type_due_to_aliasing(ctx, e, entity, init, named_type)) { return; } entity = nullptr; @@ -709,7 +788,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) } if (ident == nullptr) { - error(e->token, "foreign entiies must declare which library they are from"); + error(e->token, "foreign entities must declare which library they are from"); } else if (ident->kind != Ast_Ident) { error(ident, "foreign library names must be an identifier"); } else { @@ -951,7 +1030,6 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { switch (e->Procedure.optimization_mode) { case ProcedureOptimizationMode_None: - case ProcedureOptimizationMode_Minimal: if (pl->inlining == ProcInlining_inline) { error(e->token, "#force_inline cannot be used in conjunction with the attribute 'optimization_mode' with neither \"none\" nor \"minimal\""); } @@ -1077,7 +1155,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } - if (e->pkg != nullptr && e->token.string == "main") { + if (e->pkg != nullptr && e->token.string == "main" && !build_context.no_entry_point) { if (e->pkg->kind != Package_Runtime) { if (pt->param_count != 0 || pt->result_count != 0) { @@ -1178,9 +1256,12 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (foreign_library->LibraryName.paths.count >= 1) { module_name = foreign_library->LibraryName.paths[0]; } - name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); + + if (!string_ends_with(module_name, str_lit(".o"))) { + name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); + } } - + e->Procedure.is_foreign = true; e->Procedure.link_name = name; @@ -1320,8 +1401,8 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast error(e->token, "A foreign variable declaration cannot have a default value"); } init_entity_foreign_library(ctx, e); - if (is_arch_wasm()) { - error(e->token, "A foreign variable declaration are not allowed for the '%.*s' architecture", LIT(target_arch_names[build_context.metrics.arch])); + if (is_arch_wasm() && e->Variable.foreign_library != nullptr) { + error(e->token, "A foreign variable declaration can not be scoped to a module and must be declared in a 'foreign {' (without a library) block"); } } if (ac.link_name.len > 0) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 359b30276..12acca0cb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -548,13 +548,15 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E final_proc_type->Proc.is_poly_specialized = true; final_proc_type->Proc.is_polymorphic = true; - final_proc_type->Proc.variadic = src->Proc.variadic; - final_proc_type->Proc.require_results = src->Proc.require_results; - final_proc_type->Proc.c_vararg = src->Proc.c_vararg; - final_proc_type->Proc.has_named_results = src->Proc.has_named_results; - final_proc_type->Proc.diverging = src->Proc.diverging; - final_proc_type->Proc.return_by_pointer = src->Proc.return_by_pointer; - final_proc_type->Proc.optional_ok = src->Proc.optional_ok; + final_proc_type->Proc.variadic = src->Proc.variadic; + final_proc_type->Proc.require_results = src->Proc.require_results; + final_proc_type->Proc.c_vararg = src->Proc.c_vararg; + final_proc_type->Proc.has_named_results = src->Proc.has_named_results; + final_proc_type->Proc.diverging = src->Proc.diverging; + final_proc_type->Proc.return_by_pointer = src->Proc.return_by_pointer; + final_proc_type->Proc.optional_ok = src->Proc.optional_ok; + final_proc_type->Proc.enable_target_feature = src->Proc.enable_target_feature; + final_proc_type->Proc.require_target_feature = src->Proc.require_target_feature; for (isize i = 0; i < operands.count; i++) { @@ -587,6 +589,16 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E entity->file = base_entity->file; entity->pkg = base_entity->pkg; entity->flags = 0; + + entity->Procedure.optimization_mode = base_entity->Procedure.optimization_mode; + + if (base_entity->flags & EntityFlag_Cold) { + entity->flags |= EntityFlag_Cold; + } + if (base_entity->flags & EntityFlag_Disabled) { + entity->flags |= EntityFlag_Disabled; + } + d->entity = entity; AstFile *file = nullptr; @@ -1435,6 +1447,16 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T if (!is_polymorphic_type_assignable(c, poly->BitSet.elem, source->BitSet.elem, true, modify_type)) { return false; } + + // For generic types like bit_set[$T] the upper and lower of the poly type will be zeroes since + // it could not figure that stuff out when the poly type was created. + if (poly->BitSet.upper == 0 && modify_type) { + poly->BitSet.upper = source->BitSet.upper; + } + if (poly->BitSet.lower == 0 && modify_type) { + poly->BitSet.lower = source->BitSet.lower; + } + if (poly->BitSet.underlying == nullptr) { if (modify_type) { poly->BitSet.underlying = source->BitSet.underlying; @@ -2606,6 +2628,11 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * if (o->mode == Addressing_Constant) { Type *type = base_type(o->type); if (!is_type_constant_type(o->type)) { + if (is_type_array_like(o->type)) { + o->mode = Addressing_Value; + return; + } + gbString xt = type_to_string(o->type); gbString err_str = expr_to_string(node); error(op, "Invalid type, '%s', for constant unary expression '%s'", xt, err_str); @@ -3305,7 +3332,7 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) } -gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { +gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forbid_identical = false) { if (!is_operand_value(*x)) { error(x->expr, "Only values can be casted"); x->mode = Addressing_Invalid; @@ -3377,27 +3404,37 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { add_package_dependency(c, "runtime", "gnu_f2h_ieee", REQUIRE); } } + // If we check polymorphic procedures, we risk erring on + // identical casts that cannot be foreseen or otherwise + // forbidden, so just skip them. + if (forbid_identical && check_vet_flags(c) & VetFlag_Cast && + (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) { + Type *src_exact = x->type; + Type *dst_exact = type; + + if (src_exact != nullptr && + dst_exact != nullptr && + are_types_identical(src_exact, dst_exact) + ) { + gbString oper_str = expr_to_string(x->expr); + gbString to_type = type_to_string(dst_exact); + error(x->expr, "Unneeded cast of '%s' to identical type '%s'", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); + } + } } x->type = type; } -gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) { +gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t, bool forbid_identical = false) { if (!is_operand_value(*o)) { error(o->expr, "'transmute' can only be applied to values"); o->mode = Addressing_Invalid; return false; } - // if (o->mode == Addressing_Constant) { - // gbString expr_str = expr_to_string(o->expr); - // error(o->expr, "Cannot transmute a constant expression: '%s'", expr_str); - // gb_string_free(expr_str); - // o->mode = Addressing_Invalid; - // o->expr = node; - // return false; - // } - Type *src_t = o->type; Type *dst_t = t; Type *src_bt = base_type(src_t); @@ -3480,6 +3517,36 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type return true; } } + } else { + // If we check polymorphic procedures, we risk erring on + // identical casts that cannot be foreseen or otherwise + // forbidden, so just skip them. + if (forbid_identical && check_vet_flags(c) & VetFlag_Cast && + (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) { + if (are_types_identical(src_t, dst_t)) { + gbString oper_str = expr_to_string(o->expr); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); + } else if (is_type_internally_pointer_like(src_t) && + is_type_internally_pointer_like(dst_t)) { + error(o->expr, "Use of 'transmute' where 'cast' would be preferred since the types are pointer-like"); + } else if (are_types_identical(src_bt, dst_bt)) { + gbString oper_str = expr_to_string(o->expr); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); + } else if (is_type_integer(src_t) && is_type_integer(dst_t) && + types_have_same_internal_endian(src_t, dst_t)) { + gbString oper_type = type_to_string(src_t); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Use of 'transmute' where 'cast' would be preferred since both are integers of the same endianness, from '%s' to '%s'", oper_type, to_type); + gb_string_free(to_type); + gb_string_free(oper_type); + } + } } o->mode = Addressing_Value; @@ -4426,9 +4493,14 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar defer (gb_string_free(type_str)); if (valid_count == 1) { + Type *new_type = t->Union.variants[first_success_index]; + target_type = new_type; + if (is_type_union(new_type)) { + convert_to_typed(c, operand, new_type); + break; + } + operand->type = new_type; operand->mode = Addressing_Value; - operand->type = t->Union.variants[first_success_index]; - target_type = t->Union.variants[first_success_index]; break; } else if (valid_count > 1) { ERROR_BLOCK(); @@ -4908,7 +4980,27 @@ gb_internal bool is_entity_declared_for_selector(Entity *entity, Scope *import_s // NOTE(bill, 2022-02-03): see `check_const_decl` for why it exists reasoning gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node, bool ident_only) { - if (node->kind == Ast_Ident) { + if (node == nullptr) { + return nullptr; + } + /*if (node->kind == Ast_TernaryWhenExpr) { + ast_node(we, TernaryWhenExpr, node); + if (we->cond == nullptr) { + return nullptr; + } + if (we->cond->tav.mode != Addressing_Constant) { + return nullptr; + } + if (we->cond->tav.value.kind != ExactValue_Bool) { + return nullptr; + } + if (we->cond->tav.value.value_bool) { + return check_entity_from_ident_or_selector(c, we->x, ident_only); + } else { + Entity *e = check_entity_from_ident_or_selector(c, we->y, ident_only); + return e; + } + } else */if (node->kind == Ast_Ident) { String name = node->Ident.token.string; return scope_lookup(c->scope, name); } else if (!ident_only) if (node->kind == Ast_SelectorExpr) { @@ -6108,7 +6200,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Type *t = elem; if (is_type_polymorphic(t)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type)); + if (show_error) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type)); + } err = CallArgumentError_AmbiguousPolymorphicVariadic; } @@ -6740,9 +6834,73 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, if (procs.count > 0) { error_line("Did you mean to use one of the following:\n"); } + + // Try to reduce the list further for `$T: typeid` like parameters + bool *possibly_ignore = gb_alloc_array(temporary_allocator(), bool, procs.count); + isize possibly_ignore_set = 0; + + if (true) { + // NOTE(bill): This currently only checks for #soa types + for_array(i, procs) { + Entity *proc = procs[i]; + Type *t = base_type(proc->type); + if (t == nullptr || t->kind != Type_Proc) { + continue; + } + + TypeProc *pt = &t->Proc; + if (pt->param_count == 0) { + continue; + } + + for_array(j, pt->params->Tuple.variables) { + Entity *v = pt->params->Tuple.variables[j]; + if (v->kind != Entity_TypeName) { + continue; + } + + Type *dst_t = base_type(v->type); + while (dst_t->kind == Type_Generic && dst_t->Generic.specialized) { + dst_t = dst_t->Generic.specialized; + } + + if (j >= positional_operands.count) { + continue; + } + Operand const &o = positional_operands[j]; + if (o.mode != Addressing_Type) { + continue; + } + Type *t = base_type(o.type); + if (t->kind == dst_t->kind) { + continue; + } + Type *st = base_type(type_deref(o.type)); + Type *dt = base_type(type_deref(dst_t)); + if (st->kind == dt->kind) { + continue; + } + if (is_type_soa_struct(st)) { + possibly_ignore[i] = true; + possibly_ignore_set += 1; + continue; + } + } + } + } + + if (possibly_ignore_set == procs.count) { + possibly_ignore_set = 0; + } + + isize max_name_length = 0; isize max_type_length = 0; - for (Entity *proc : procs) { + for_array(i, procs) { + if (possibly_ignore_set != 0 && possibly_ignore[i]) { + continue; + } + Entity *proc = procs[i]; Type *t = base_type(proc->type); if (t == t_invalid) continue; String prefix = {}; @@ -6772,7 +6930,11 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } spaces[max_spaces] = 0; - for (Entity *proc : procs) { + for_array(i, procs) { + if (possibly_ignore_set != 0 && possibly_ignore[i]) { + continue; + } + Entity *proc = procs[i]; TokenPos pos = proc->token.pos; Type *t = base_type(proc->type); if (t == t_invalid) continue; @@ -7035,6 +7197,8 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O Array operands = {}; defer (array_free(&operands)); + CallArgumentError err = CallArgumentError_None; + bool named_fields = false; { // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves @@ -7052,6 +7216,11 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O Ast *arg = ce->args[i]; ast_node(fv, FieldValue, arg); + if (fv->value == nullptr) { + error(fv->eq, "Expected a value"); + err = CallArgumentError_InvalidFieldValue; + continue; + } if (fv->field->kind == Ast_Ident) { String name = fv->field->Ident.token.string; isize index = lookup_polymorphic_record_parameter(original_type, name); @@ -7090,7 +7259,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } - CallArgumentError err = CallArgumentError_None; + if (err != 0) { + operand->mode = Addressing_Invalid; + return err; + } TypeTuple *tuple = get_record_polymorphic_params(original_type); isize param_count = tuple->variables.count; @@ -8322,6 +8494,14 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A } o->type = t_untyped_string; o->value = exact_value_string(file); + } else if (name == "directory") { + String file = get_file_path_string(bd->token.pos.file_id); + String path = dir_from_path(file); + if (build_context.obfuscate_source_code_locations) { + path = obfuscate_string(path, "D"); + } + o->type = t_untyped_string; + o->value = exact_value_string(path); } else if (name == "line") { i32 line = bd->token.pos.line; if (build_context.obfuscate_source_code_locations) { @@ -8714,7 +8894,7 @@ gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *no // okay } else { gbString s = type_to_string(right_type); - error(node, "'%.*s' requires a boolean or nil-able type, got %s", s); + error(node, "'%.*s' requires a boolean or nil-able type, got %s", LIT(name), s); gb_string_free(s); } } @@ -8987,12 +9167,16 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * type = nullptr; // [?]Type - if (type_expr->kind == Ast_ArrayType && type_expr->ArrayType.count != nullptr) { + if (type_expr->kind == Ast_ArrayType) { Ast *count = type_expr->ArrayType.count; - if (count->kind == Ast_UnaryExpr && - count->UnaryExpr.op.kind == Token_Question) { - type = alloc_type_array(check_type(c, type_expr->ArrayType.elem), -1); - is_to_be_determined_array_count = true; + if (count != nullptr) { + if (count->kind == Ast_UnaryExpr && + count->UnaryExpr.op.kind == Token_Question) { + type = alloc_type_array(check_type(c, type_expr->ArrayType.elem), -1); + is_to_be_determined_array_count = true; + } + } else { + type = alloc_type_slice(check_type(c, type_expr->ArrayType.elem)); } if (cl->elems.count > 0) { if (type_expr->ArrayType.tag != nullptr) { @@ -9005,8 +9189,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } } - } - if (type_expr->kind == Ast_DynamicArrayType && type_expr->DynamicArrayType.tag != nullptr) { + } else if (type_expr->kind == Ast_DynamicArrayType && type_expr->DynamicArrayType.tag != nullptr) { if (cl->elems.count > 0) { Ast *tag = type_expr->DynamicArrayType.tag; GB_ASSERT(tag->kind == Ast_BasicDirective); @@ -9045,6 +9228,12 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (cl->elems.count == 0) { break; // NOTE(bill): No need to init } + + if (t->Struct.soa_kind != StructSoa_None) { + error(node, "#soa arrays are not supported for compound literals"); + break; + } + if (t->Struct.is_raw_union) { if (cl->elems.count > 0) { // NOTE: unions cannot be constant @@ -9819,7 +10008,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (tav.mode != Addressing_Constant) { continue; } - GB_ASSERT(tav.value.kind == ExactValue_Integer); + if (tav.value.kind != ExactValue_Integer) { + continue; + } i64 v = big_int_to_i64(&tav.value.value_integer); i64 lower = bt->BitSet.lower; u64 index = cast(u64)(v-lower); @@ -10695,10 +10886,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast if (o->mode != Addressing_Invalid) { switch (tc->token.kind) { case Token_transmute: - check_transmute(c, node, o, type); + check_transmute(c, node, o, type, true); break; case Token_cast: - check_cast(c, o, type); + check_cast(c, o, type, true); break; default: error(node, "Invalid AST: Invalid casting expression"); @@ -11344,6 +11535,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(pt, PointerType, node); + if (pt->tag) { + str = write_expr_to_string(str, pt->tag, false); + } str = gb_string_append_rune(str, '^'); str = write_expr_to_string(str, pt->type, shorthand); case_end; @@ -11354,6 +11548,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(at, ArrayType, node); + if (at->tag) { + str = write_expr_to_string(str, at->tag, false); + } str = gb_string_append_rune(str, '['); if (at->count != nullptr && at->count->kind == Ast_UnaryExpr && @@ -11367,6 +11564,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(at, DynamicArrayType, node); + if (at->tag) { + str = write_expr_to_string(str, at->tag, false); + } str = gb_string_appendc(str, "[dynamic]"); str = write_expr_to_string(str, at->elem, shorthand); case_end; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index f2e3b0242..f4d3bd6b8 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1258,6 +1258,20 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags error_line("\tSuggestion: Was '#partial switch' wanted?\n"); } } + + if (build_context.strict_style) { + Token stok = ss->token; + for_array(i, bs->stmts) { + Ast *stmt = bs->stmts[i]; + if (stmt->kind != Ast_CaseClause) { + continue; + } + Token ctok = stmt->CaseClause.token; + if (ctok.pos.column > stok.pos.column) { + error(ctok, "With '-strict-style', 'case' statements must share the same column as the 'switch' token"); + } + } + } } @@ -2017,6 +2031,12 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f gb_string_free(str); init_type = t_invalid; } + if (init_type == t_invalid && entity_count == 1 && (mod_flags & (Stmt_BreakAllowed|Stmt_FallthroughAllowed))) { + Entity *e = entities[0]; + if (e != nullptr && e->token.string == "default") { + warning(e->token, "Did you mean 'case:'?"); + } + } } diff --git a/src/check_type.cpp b/src/check_type.cpp index c56c8a739..dd8559114 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -335,7 +335,7 @@ bool check_constant_parameter_value(Type *type, Ast *expr) { gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params, bool *is_polymorphic_, - Ast *node, Array *poly_operands) { + Array *poly_operands) { Type *polymorphic_params_type = nullptr; GB_ASSERT(is_polymorphic_ != nullptr); @@ -643,13 +643,14 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * context = str_lit("struct #raw_union"); } + struct_type->Struct.node = node; struct_type->Struct.scope = ctx->scope; struct_type->Struct.is_packed = st->is_packed; struct_type->Struct.is_no_copy = st->is_no_copy; struct_type->Struct.polymorphic_params = check_record_polymorphic_params( ctx, st->polymorphic_params, &struct_type->Struct.is_polymorphic, - node, poly_operands + poly_operands ); wait_signal_set(&struct_type->Struct.polymorphic_wait_signal); @@ -696,11 +697,12 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no ast_node(ut, UnionType, node); + union_type->Union.node = node; union_type->Union.scope = ctx->scope; union_type->Union.polymorphic_params = check_record_polymorphic_params( ctx, ut->polymorphic_params, &union_type->Union.is_polymorphic, - node, poly_operands + poly_operands ); wait_signal_set(&union_type->Union.polymorphic_wait_signal); @@ -738,7 +740,7 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no gb_string_free(str); } else { for_array(j, variants) { - if (are_types_identical(t, variants[j])) { + if (union_variant_index_types_equal(t, variants[j])) { ok = false; ERROR_BLOCK(); gbString str = type_to_string(t); @@ -1118,6 +1120,8 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, // NOTE(bill): it doesn't matter, and when it does, // that api is absolutely stupid return Endian_Unknown; + } else if (type_size_of(type) < 2) { + return Endian_Unknown; } else if (is_type_endian_specific(type)) { if (is_type_endian_little(type)) { return Endian_Little; @@ -1761,6 +1765,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (type_expr == nullptr) { param_value = handle_parameter_value(ctx, nullptr, &type, default_value, true); } else { + Ast *original_type_expr = type_expr; if (type_expr->kind == Ast_Ellipsis) { type_expr = type_expr->Ellipsis.expr; is_variadic = true; @@ -1769,6 +1774,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para error(param, "Invalid AST: Invalid variadic parameter with multiple names"); success = false; } + + GB_ASSERT(original_type_expr->kind == Ast_Ellipsis); + type_expr = ast_array_type(type_expr->file(), original_type_expr->Ellipsis.token, nullptr, type_expr); } if (type_expr->kind == Ast_TypeidType) { ast_node(tt, TypeidType, type_expr); @@ -1792,6 +1800,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (operands != nullptr) { ctx->allow_polymorphic_types = true; } + type = check_type(ctx, type_expr); ctx->allow_polymorphic_types = prev; @@ -1824,12 +1833,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } type = t_invalid; } - if (is_type_empty_union(type)) { - gbString str = type_to_string(type); - error(param, "Invalid use of an empty union '%s'", str); - gb_string_free(str); - type = t_invalid; - } + // if (is_type_empty_union(type)) { + // gbString str = type_to_string(type); + // error(param, "Invalid use of an empty union '%s'", str); + // gb_string_free(str); + // type = t_invalid; + // } if (is_type_polymorphic(type)) { switch (param_value.kind) { @@ -2077,6 +2086,14 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para param->Variable.type_expr = type_expr; } } + + if (is_variadic && variadic_index == variables.count) { + param->flags |= EntityFlag_Ellipsis; + if (is_c_vararg) { + param->flags |= EntityFlag_CVarArg; + } + } + if (p->flags&FieldFlag_no_alias) { param->flags |= EntityFlag_NoAlias; } @@ -2111,18 +2128,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (is_variadic) { GB_ASSERT(variadic_index >= 0); - } - - if (is_variadic) { GB_ASSERT(params.count > 0); - // NOTE(bill): Change last variadic parameter to be a slice - // Custom Calling convention for variadic parameters - Entity *end = variables[variadic_index]; - end->type = alloc_type_slice(end->type); - end->flags |= EntityFlag_Ellipsis; - if (is_c_vararg) { - end->flags |= EntityFlag_CVarArg; - } } isize specialization_count = 0; @@ -3331,6 +3337,10 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T gbString s = expr_to_string(pt->type); error(e, "^ is used for pointer types, did you mean '&%s'?", s); gb_string_free(s); + } else if (is_type_pointer(o.type)) { + gbString s = expr_to_string(pt->type); + error(e, "^ is used for pointer types, did you mean a dereference: '%s^'?", s); + gb_string_free(s); } else { // NOTE(bill): call check_type_expr again to get a consistent error message elem = check_type_expr(&c, pt->type, nullptr); diff --git a/src/checker.cpp b/src/checker.cpp index 852fb89bb..8756cce1a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -346,6 +346,7 @@ gb_internal Scope *scope_of_node(Ast *node) { gb_internal void check_open_scope(CheckerContext *c, Ast *node) { node = unparen_expr(node); + GB_ASSERT(node != nullptr); GB_ASSERT(node->kind == Ast_Invalid || is_ast_stmt(node) || is_ast_type(node)); @@ -518,7 +519,7 @@ gb_internal Entity *scope_insert_no_mutex(Scope *s, Entity *entity) { } -GB_COMPARE_PROC(entity_variable_pos_cmp) { +gb_internal GB_COMPARE_PROC(entity_variable_pos_cmp) { Entity *x = *cast(Entity **)a; Entity *y = *cast(Entity **)b; @@ -846,6 +847,10 @@ gb_internal void add_declaration_dependency(CheckerContext *c, Entity *e) { if (e == nullptr) { return; } + if (e->flags & EntityFlag_Disabled) { + // ignore the dependencies if it has been `@(disabled=true)` + return; + } if (c->decl != nullptr) { add_dependency(c->info, c->decl, e); } @@ -1302,6 +1307,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->init_procedures, a, 0, 0); array_init(&i->fini_procedures, a, 0, 0); array_init(&i->required_foreign_imports_through_force, a, 0, 0); + array_init(&i->defineables, a); map_init(&i->objc_msgSend_types); string_map_init(&i->load_file_cache); @@ -1331,6 +1337,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { string_map_destroy(&i->packages); array_free(&i->variable_init_order); array_free(&i->required_foreign_imports_through_force); + array_free(&i->defineables); mpsc_destroy(&i->entity_queue); mpsc_destroy(&i->definition_queue); @@ -1463,6 +1470,7 @@ gb_internal Entity *implicit_entity_of_node(Ast *clause) { } gb_internal Entity *entity_of_node(Ast *expr) { +retry:; expr = unparen_expr(expr); switch (expr->kind) { case_ast_node(ident, Ident, expr); @@ -1483,6 +1491,17 @@ gb_internal Entity *entity_of_node(Ast *expr) { case_ast_node(ce, CallExpr, expr); return ce->entity_procedure_of; case_end; + + case_ast_node(we, TernaryWhenExpr, expr); + if (we->cond == nullptr) { + break; + } + if (we->cond->tav.value.kind != ExactValue_Bool) { + break; + } + expr = we->cond->tav.value.value_bool ? we->x : we->y; + goto retry; + case_end; } return nullptr; } @@ -3491,20 +3510,6 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { error(elem, "Expected a string value for '%.*s'", LIT(name)); } return true; - } else if (name == "warning") { - ExactValue ev = check_decl_attribute_value(c, value); - - if (ev.kind == ExactValue_String) { - String msg = ev.value_string; - if (msg.len == 0) { - error(elem, "Warning message cannot be an empty string"); - } else { - ac->warning_message = msg; - } - } else { - error(elem, "Expected a string value for '%.*s'", LIT(name)); - } - return true; } else if (name == "require_results") { if (value != nullptr) { error(elem, "Expected no value for '%.*s'", LIT(name)); @@ -3539,19 +3544,19 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { String mode = ev.value_string; if (mode == "none") { ac->optimization_mode = ProcedureOptimizationMode_None; + } else if (mode == "favor_size") { + ac->optimization_mode = ProcedureOptimizationMode_FavorSize; } else if (mode == "minimal") { - ac->optimization_mode = ProcedureOptimizationMode_Minimal; + error(elem, "Invalid optimization_mode 'minimal' for '%.*s', mode has been removed due to confusion, but 'none' has the same behaviour", LIT(name)); } else if (mode == "size") { - ac->optimization_mode = ProcedureOptimizationMode_Size; + error(elem, "Invalid optimization_mode 'size' for '%.*s', mode has been removed due to confusion, but 'favor_size' has the same behaviour", LIT(name)); } else if (mode == "speed") { - ac->optimization_mode = ProcedureOptimizationMode_Speed; + error(elem, "Invalid optimization_mode 'speed' for '%.*s', mode has been removed due to confusion, but 'favor_size' has the same behaviour", LIT(name)); } else { ERROR_BLOCK(); error(elem, "Invalid optimization_mode for '%.*s'. Valid modes:", LIT(name)); error_line("\tnone\n"); - error_line("\tminimal\n"); - error_line("\tsize\n"); - error_line("\tspeed\n"); + error_line("\tfavor_size\n"); } } else { error(elem, "Expected a string for '%.*s'", LIT(name)); @@ -3911,10 +3916,11 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array const &at } if (!proc(c, elem, name, value, ac)) { - if (!build_context.ignore_unknown_attributes) { + if (!build_context.ignore_unknown_attributes && + !string_set_exists(&build_context.custom_attributes, name)) { ERROR_BLOCK(); error(elem, "Unknown attribute element name '%.*s'", LIT(name)); - error_line("\tDid you forget to use build flag '-ignore-unknown-attributes'?\n"); + error_line("\tDid you forget to use the build flag '-ignore-unknown-attributes' or '-custom-attribute:%.*s'?\n", LIT(name)); } } } @@ -4110,6 +4116,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { bool is_test = false; bool is_init = false; bool is_fini = false; + bool is_priv = false; for_array(i, vd->attributes) { Ast *attr = vd->attributes[i]; @@ -4154,6 +4161,8 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { } if (!success) { error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + } else { + is_priv = true; } @@ -4175,6 +4184,11 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { } } + if (is_priv && is_test) { + error(decl, "Attribute 'private' is not allowed on a test case"); + return; + } + if (entity_visibility_kind == EntityVisiblity_Public && (c->scope->flags&ScopeFlag_File) && c->scope->file) { @@ -5002,9 +5016,8 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) { String file_str = op.value.value_string; file_str = string_trim_whitespace(file_str); - String fullpath = file_str; - if (allow_check_foreign_filepath()) { + if (!is_arch_wasm() || string_ends_with(file_str, str_lit(".o"))) { String foreign_path = {}; bool ok = determine_path_from_string(nullptr, decl, base_dir, file_str, &foreign_path, /*use error not syntax_error*/true); if (ok) { diff --git a/src/checker.hpp b/src/checker.hpp index 492a64fb6..781737140 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -382,6 +382,17 @@ struct GenTypesData { RecursiveMutex mutex; }; +struct Defineable { + String name; + ExactValue default_value; + TokenPos pos; + CommentGroup *docs; + + // These strings are only computed from previous fields when defineables are being shown or exported. + String default_value_str; + String pos_str; +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -408,6 +419,9 @@ struct CheckerInfo { Array entities; Array required_foreign_imports_through_force; + BlockingMutex defineables_mutex; + Array defineables; + // Below are accessed within procedures RwMutex global_untyped_mutex; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 35acad42f..a90c52e61 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -192,6 +192,7 @@ BuiltinProc__simd_end, // Platform specific intrinsics BuiltinProc_syscall, + BuiltinProc_syscall_bsd, BuiltinProc_x86_cpuid, BuiltinProc_x86_xgetbv, @@ -276,6 +277,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_bit_set_underlying_type, BuiltinProc_type_struct_field_count, + BuiltinProc_type_struct_has_implicit_padding, BuiltinProc_type_proc_parameter_count, BuiltinProc_type_proc_return_count, @@ -512,7 +514,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("syscall"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT("syscall"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT("syscall_bsd"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("x86_cpuid"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("x86_xgetbv"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -591,7 +594,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_bit_set_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_bit_set_underlying_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_struct_has_implicit_padding"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/entity.cpp b/src/entity.cpp index 8f55c1faf..41d84e0f7 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -133,9 +133,7 @@ enum EntityConstantFlags : u32 { enum ProcedureOptimizationMode : u8 { ProcedureOptimizationMode_Default, ProcedureOptimizationMode_None, - ProcedureOptimizationMode_Minimal, - ProcedureOptimizationMode_Size, - ProcedureOptimizationMode_Speed, + ProcedureOptimizationMode_FavorSize, }; @@ -338,6 +336,9 @@ gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Typ entity->token = token; entity->type = type; entity->id = 1 + global_entity_id.fetch_add(1); + if (token.pos.file_id) { + entity->file = thread_safe_get_ast_file_from_id(token.pos.file_id); + } return entity; } diff --git a/src/error.cpp b/src/error.cpp index d0089c952..f95123f15 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -237,6 +237,7 @@ enum TerminalColour { TerminalColour_Blue, TerminalColour_Purple, TerminalColour_Black, + TerminalColour_Grey, }; gb_internal void terminal_set_colours(TerminalStyle style, TerminalColour foreground) { @@ -256,6 +257,7 @@ gb_internal void terminal_set_colours(TerminalStyle style, TerminalColour foregr case TerminalColour_Blue: error_out("\x1b[%s;34m", ss); break; case TerminalColour_Purple: error_out("\x1b[%s;35m", ss); break; case TerminalColour_Black: error_out("\x1b[%s;30m", ss); break; + case TerminalColour_Grey: error_out("\x1b[%s;90m", ss); break; } } } @@ -272,101 +274,234 @@ gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end) { return -1; } - i32 offset = 0; - gbString the_line = get_file_line_as_string(pos, &offset); + i32 error_start_index_bytes = 0; + gbString the_line = get_file_line_as_string(pos, &error_start_index_bytes); defer (gb_string_free(the_line)); - if (the_line != nullptr) { - char const *line_text = the_line; - isize line_len = gb_string_length(the_line); - - // TODO(bill): This assumes ASCII - - enum { - MAX_LINE_LENGTH = 80, - MAX_TAB_WIDTH = 8, - ELLIPSIS_PADDING = 8, // `... ...` - MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING, - }; - - i32 error_length = gb_max(end.offset - pos.offset, 1); - - error_out("\t"); - - terminal_set_colours(TerminalStyle_Bold, TerminalColour_White); - - - i32 squiggle_extra = 0; - - if (line_len > MAX_LINE_LENGTH_PADDED) { - i32 left = MAX_TAB_WIDTH; - i32 diff = gb_max(offset-left, 0); - if (diff > 0) { - line_text += diff; - line_len -= diff; - offset = left + ELLIPSIS_PADDING/2; - } - if (line_len > MAX_LINE_LENGTH_PADDED) { - line_len = MAX_LINE_LENGTH_PADDED; - if (error_length > line_len-left) { - error_length = cast(i32)line_len - left; - squiggle_extra = 1; - } - } - if (diff > 0) { - error_out("... %.*s ...", cast(i32)line_len, line_text); - } else { - error_out("%.*s ...", cast(i32)line_len, line_text); - } - } else { - error_out("%.*s", cast(i32)line_len, line_text); - } - error_out("\n\t"); - - for (i32 rune_width, off = 0; off < offset; off += rune_width) { - i32 rune; - rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); - int w = utf8proc_charwidth(rune); - if (w > 0) { - error_out("%.*s", w, " "); - } - } - - terminal_set_colours(TerminalStyle_Bold, TerminalColour_Green); - - error_out("^"); - if (end.file_id == pos.file_id) { - i32 rune; - - if (end.line > pos.line) { - for (i32 rune, rune_width, off = offset; off < line_len; off += rune_width) { - rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); - int w = utf8proc_charwidth(rune); - if (w > 0) { - error_out("%.*s", w, "~~~~"); - } - } - } else if (end.line == pos.line && end.column > pos.column) { - i32 columns = squiggle_extra; - for (i32 rune, rune_width, off = offset; off < offset + error_length - 1; off += rune_width) { - rune_width = cast(i32)utf8proc_iterate((u8 const *)line_text + off, line_len - off, &rune); - columns += utf8proc_charwidth(rune); - } - for (i32 i = 1; i < columns; i++) { - error_out("~"); - } - if (columns > 0 && squiggle_extra == 0) { - error_out("^"); - } - } - } - + if (the_line == nullptr || gb_string_length(the_line) == 0) { + terminal_set_colours(TerminalStyle_Normal, TerminalColour_Grey); + error_out("\t( empty line )\n"); terminal_reset_colours(); - error_out("\n"); - return offset; + if (the_line == nullptr) { + return -1; + } else { + return cast(isize)error_start_index_bytes; + } } - return -1; + + // These two will be used like an Odin slice later. + char const *line_text = the_line; + i32 line_length_bytes = cast(i32)gb_string_length(the_line); + + ucg_grapheme* graphemes; + i32 line_length_runes = 0; + i32 line_length_graphemes = 0; + i32 line_width = 0; + + int ucg_result = ucg_decode_grapheme_clusters( + permanent_allocator(), (const uint8_t*)line_text, line_length_bytes, + &graphemes, &line_length_runes, &line_length_graphemes, &line_width); + + if (ucg_result < 0) { + // There was a UTF-8 parsing error. + // Insert a dummy grapheme so the start of the invalid rune can be pointed at. + graphemes = (ucg_grapheme*)gb_resize(permanent_allocator(), + graphemes, + sizeof(ucg_grapheme) * (line_length_graphemes), + sizeof(ucg_grapheme) * (1 + line_length_graphemes)); + + ucg_grapheme append = { + error_start_index_bytes, + line_length_runes, + 1, + }; + + graphemes[line_length_graphemes] = append; + } + + // The units below are counted in visual, monospace cells. + enum { + MAX_LINE_LENGTH = 80, + MAX_TAB_WIDTH = 8, + ELLIPSIS_PADDING = 8, // `... ...` + MIN_LEFT_VIEW = 8, + + // A rough estimate of how many characters we'll insert, at most: + MAX_INSERTED_WIDTH = MAX_TAB_WIDTH + ELLIPSIS_PADDING, + + MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH - MAX_INSERTED_WIDTH, + }; + + i32 error_start_index_graphemes = 0; + for (i32 i = 0; i < line_length_graphemes; i += 1) { + if (graphemes[i].byte_index == error_start_index_bytes) { + error_start_index_graphemes = i; + break; + } + } + + if (error_start_index_graphemes == 0 && error_start_index_bytes != 0 && line_length_graphemes != 0) { + // The error index in graphemes was not found, but we did find a valid Unicode string. + // + // This is an edge case where the error is sitting on a newline or the + // end of the line, as that is the only location we could not have checked. + error_start_index_graphemes = line_length_graphemes; + } + + error_out("\t"); + + bool show_right_ellipsis = false; + + i32 squiggle_padding = 0; + i32 window_open_bytes = 0; + i32 window_close_bytes = 0; + if (line_width > MAX_LINE_LENGTH_PADDED) { + // Now that we know the line is over the length limit, we have to + // compose a visual window in which to display the error. + i32 window_size_left = 0; + i32 window_size_right = 0; + i32 window_open_graphemes = 0; + + for (i32 i = error_start_index_graphemes - 1; i > 0; i -= 1) { + window_size_left += graphemes[i].width; + if (window_size_left >= MIN_LEFT_VIEW) { + window_open_graphemes = i; + window_open_bytes = graphemes[i].byte_index; + break; + } + } + + for (i32 i = error_start_index_graphemes; i < line_length_graphemes; i += 1) { + window_size_right += graphemes[i].width; + if (window_size_right >= MAX_LINE_LENGTH_PADDED - MIN_LEFT_VIEW) { + window_close_bytes = graphemes[i].byte_index; + break; + } + } + if (window_close_bytes == 0) { + // The window ends at the end of the line. + window_close_bytes = line_length_bytes; + } + + if (window_size_right < MAX_LINE_LENGTH_PADDED - MIN_LEFT_VIEW) { + // Hit the end of the string early on the right side; expand backwards. + for (i32 i = window_open_graphemes - 1; i > 0; i -= 1) { + window_size_left += graphemes[i].width; + if (window_size_left + window_size_right >= MAX_LINE_LENGTH_PADDED) { + window_open_graphemes = i; + window_open_bytes = graphemes[i].byte_index; + break; + } + } + } + + GB_ASSERT_MSG(window_close_bytes >= window_open_bytes, "Error line truncation window has wrong byte indices. (open, close: %i, %i)", window_open_bytes, window_close_bytes); + + if (window_close_bytes != line_length_bytes) { + show_right_ellipsis = true; + } + + // Close the window, going left. + line_length_bytes = window_close_bytes; + + // Adjust the slice of text. In Odin, this would be: + // `line_text = line_text[window_left_bytes:]` + line_text += window_open_bytes; + line_length_bytes -= window_open_bytes; + GB_ASSERT_MSG(line_length_bytes >= 0, "Bounds-checking error: line_length_bytes"); + + if (window_open_bytes > 0) { + error_out("... "); + squiggle_padding += 4; + } + } else { + // No truncation needed. + window_open_bytes = 0; + window_close_bytes = line_length_bytes; + } + + for (i32 i = error_start_index_graphemes; i > 0; i -= 1) { + if (graphemes[i].byte_index == window_open_bytes) { + break; + } + squiggle_padding += graphemes[i].width; + } + + // Start printing code. + + terminal_set_colours(TerminalStyle_Normal, TerminalColour_White); + error_out("%.*s", line_length_bytes, line_text); + + i32 squiggle_length = 0; + bool trailing_squiggle = false; + + if (end.file_id == pos.file_id) { + // The error has an endpoint. + + if (end.line > pos.line) { + // Error goes to next line. + // Always show the ellipsis in this case + show_right_ellipsis = true; + + for (i32 i = error_start_index_graphemes; i < line_length_graphemes; i += 1) { + squiggle_length += graphemes[i].width; + trailing_squiggle = true; + } + + } else if (end.line == pos.line && end.column > pos.column) { + // Error terminates before line end. + i32 adjusted_end_index = graphemes[error_start_index_graphemes].byte_index + end.column - pos.column; + + for (i32 i = error_start_index_graphemes; i < line_length_graphemes; i += 1) { + if (graphemes[i].byte_index >= adjusted_end_index) { + break; + } else if (graphemes[i].byte_index >= window_close_bytes) { + trailing_squiggle = true; + break; + } + squiggle_length += graphemes[i].width; + } + } + } else { + // The error is at one spot; no range known. + squiggle_length = 1; + } + + if (show_right_ellipsis) { + error_out(" ..."); + } + + error_out("\n\t"); + + for (i32 i = squiggle_padding; i > 0; i -= 1) { + error_out(" "); + } + + terminal_set_colours(TerminalStyle_Bold, TerminalColour_Green); + + if (squiggle_length > 0) { + error_out("^"); + squiggle_length -= 1; + } + for (/**/; squiggle_length > 1; squiggle_length -= 1) { + error_out("~"); + } + if (squiggle_length > 0) { + if (trailing_squiggle) { + error_out("~ ..."); + } else { + error_out("^"); + } + } + + // NOTE(Feoramund): Specifically print a newline, then reset colours, + // instead of the other way around. Otherwise the printing mechanism + // will collapse the newline for reasons currently beyond my ken. + error_out("\n"); + terminal_reset_colours(); + + return squiggle_padding; } gb_internal void error_out_empty(void) { diff --git a/src/linker.cpp b/src/linker.cpp index 25c54a6ab..046e72d0e 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -70,11 +70,37 @@ gb_internal i32 linker_stage(LinkerData *gen) { if (is_arch_wasm()) { timings_start_section(timings, str_lit("wasm-ld")); + gbString lib_str = gb_string_make(heap_allocator(), ""); + gbString extra_orca_flags = gb_string_make(temporary_allocator(), ""); gbString inputs = gb_string_make(temporary_allocator(), ""); inputs = gb_string_append_fmt(inputs, "\"%.*s.o\"", LIT(output_filename)); + + for (Entity *e : gen->foreign_libraries) { + GB_ASSERT(e->kind == Entity_LibraryName); + // NOTE(bill): Add these before the linking values + String extra_linker_flags = string_trim_whitespace(e->LibraryName.extra_linker_flags); + if (extra_linker_flags.len != 0) { + lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(extra_linker_flags)); + } + + for_array(i, e->LibraryName.paths) { + String lib = e->LibraryName.paths[i]; + + if (lib.len == 0) { + continue; + } + + if (!string_ends_with(lib, str_lit(".o"))) { + continue; + } + + inputs = gb_string_append_fmt(inputs, " \"%.*s\"", LIT(lib)); + } + } + if (build_context.metrics.os == TargetOs_orca) { gbString orca_sdk_path = gb_string_make(temporary_allocator(), ""); if (!system_exec_command_line_app_output("orca sdk-path", &orca_sdk_path)) { @@ -93,16 +119,18 @@ gb_internal i32 linker_stage(LinkerData *gen) { #if defined(GB_SYSTEM_WINDOWS) result = system_exec_command_line_app("wasm-ld", - "\"%.*s\\bin\\wasm-ld\" %s -o \"%.*s\" %.*s %.*s %s", + "\"%.*s\\bin\\wasm-ld\" %s -o \"%.*s\" %.*s %.*s %s %s", LIT(build_context.ODIN_ROOT), inputs, LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), + lib_str, extra_orca_flags); #else result = system_exec_command_line_app("wasm-ld", - "wasm-ld %s -o \"%.*s\" %.*s %.*s %s", + "wasm-ld %s -o \"%.*s\" %.*s %.*s %s %s", inputs, LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), + lib_str, extra_orca_flags); #endif return result; @@ -194,7 +222,21 @@ gb_internal i32 linker_stage(LinkerData *gen) { if (has_asm_extension(lib)) { if (!string_set_update(&asm_files, lib)) { String asm_file = lib; - String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj")); + String obj_file = {}; + String temp_dir = temporary_directory(temporary_allocator()); + if (temp_dir.len != 0) { + String filename = filename_without_directory(asm_file); + + gbString str = gb_string_make(heap_allocator(), ""); + str = gb_string_append_length(str, temp_dir.text, temp_dir.len); + str = gb_string_appendc(str, "/"); + str = gb_string_append_length(str, filename.text, filename.len); + str = gb_string_append_fmt(str, "-%p.obj", asm_file.text); + obj_file = make_string_c(str); + } else { + obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj")); + } + String obj_format = str_lit("win64"); #if defined(GB_ARCH_32_BIT) obj_format = str_lit("win32"); @@ -263,26 +305,30 @@ gb_internal i32 linker_stage(LinkerData *gen) { defer (gb_free(heap_allocator(), windows_sdk_bin_path.text)); if (!build_context.use_lld) { // msvc - String res_path = {}; + String res_path = quote_path(heap_allocator(), build_context.build_paths[BuildPath_RES]); + String rc_path = quote_path(heap_allocator(), build_context.build_paths[BuildPath_RC]); defer (gb_free(heap_allocator(), res_path.text)); + defer (gb_free(heap_allocator(), rc_path.text)); + if (build_context.has_resource) { - String temp_res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]); - res_path = concatenate3_strings(heap_allocator(), str_lit("\""), temp_res_path, str_lit("\"")); - gb_free(heap_allocator(), temp_res_path.text); + if (build_context.build_paths[BuildPath_RC].basename == "") { + debugf("Using precompiled resource %.*s\n", LIT(res_path)); + } else { + debugf("Compiling resource %.*s\n", LIT(res_path)); - String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]); - defer (gb_free(heap_allocator(), rc_path.text)); + result = system_exec_command_line_app("msvc-link", + "\"%.*src.exe\" /nologo /fo %.*s %.*s", + LIT(windows_sdk_bin_path), + LIT(res_path), + LIT(rc_path) + ); - result = system_exec_command_line_app("msvc-link", - "\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"", - LIT(windows_sdk_bin_path), - LIT(res_path), - LIT(rc_path) - ); - - if (result) { - return result; + if (result) { + return result; + } } + } else { + res_path = {}; } String linker_name = str_lit("link.exe"); @@ -381,7 +427,22 @@ gb_internal i32 linker_stage(LinkerData *gen) { continue; // already handled } String asm_file = lib; - String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".o")); + String obj_file = {}; + + String temp_dir = temporary_directory(temporary_allocator()); + if (temp_dir.len != 0) { + String filename = filename_without_directory(asm_file); + + gbString str = gb_string_make(heap_allocator(), ""); + str = gb_string_append_length(str, temp_dir.text, temp_dir.len); + str = gb_string_appendc(str, "/"); + str = gb_string_append_length(str, filename.text, filename.len); + str = gb_string_append_fmt(str, "-%p.o", asm_file.text); + obj_file = make_string_c(str); + } else { + obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".o")); + } + String obj_format; #if defined(GB_ARCH_64_BIT) if (is_osx) { @@ -574,9 +635,16 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } - gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument "); + // Link using `clang`, unless overridden by `ODIN_CLANG_PATH` environment variable. + const char* clang_path = gb_get_env("ODIN_CLANG_PATH", permanent_allocator()); + if (clang_path == NULL) { + clang_path = "clang"; + } + + gbString link_command_line = gb_string_make(heap_allocator(), clang_path); defer (gb_string_free(link_command_line)); + link_command_line = gb_string_appendc(link_command_line, " -Wno-unused-command-line-argument "); link_command_line = gb_string_appendc(link_command_line, object_files); link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str); diff --git a/src/llvm-c/Analysis.h b/src/llvm-c/Analysis.h index 270b145a4..6b93b5c3d 100644 --- a/src/llvm-c/Analysis.h +++ b/src/llvm-c/Analysis.h @@ -19,8 +19,8 @@ #ifndef LLVM_C_ANALYSIS_H #define LLVM_C_ANALYSIS_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/BitReader.h b/src/llvm-c/BitReader.h index 088107468..725f3fa84 100644 --- a/src/llvm-c/BitReader.h +++ b/src/llvm-c/BitReader.h @@ -19,8 +19,8 @@ #ifndef LLVM_C_BITREADER_H #define LLVM_C_BITREADER_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/BitWriter.h b/src/llvm-c/BitWriter.h index ea84b6593..ba4a61afc 100644 --- a/src/llvm-c/BitWriter.h +++ b/src/llvm-c/BitWriter.h @@ -19,8 +19,8 @@ #ifndef LLVM_C_BITWRITER_H #define LLVM_C_BITWRITER_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Comdat.h b/src/llvm-c/Comdat.h index 8002bc058..30df20799 100644 --- a/src/llvm-c/Comdat.h +++ b/src/llvm-c/Comdat.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_COMDAT_H #define LLVM_C_COMDAT_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Config/AsmParsers.def b/src/llvm-c/Config/AsmParsers.def index 7aaab6e50..a641f395b 100644 --- a/src/llvm-c/Config/AsmParsers.def +++ b/src/llvm-c/Config/AsmParsers.def @@ -27,18 +27,20 @@ LLVM_ASM_PARSER(AArch64) LLVM_ASM_PARSER(AMDGPU) LLVM_ASM_PARSER(ARM) +LLVM_ASM_PARSER(AVR) LLVM_ASM_PARSER(BPF) LLVM_ASM_PARSER(Hexagon) LLVM_ASM_PARSER(Lanai) +LLVM_ASM_PARSER(LoongArch) LLVM_ASM_PARSER(Mips) LLVM_ASM_PARSER(MSP430) LLVM_ASM_PARSER(PowerPC) LLVM_ASM_PARSER(RISCV) LLVM_ASM_PARSER(Sparc) LLVM_ASM_PARSER(SystemZ) +LLVM_ASM_PARSER(VE) LLVM_ASM_PARSER(WebAssembly) LLVM_ASM_PARSER(X86) -LLVM_ASM_PARSER(AVR) #undef LLVM_ASM_PARSER diff --git a/src/llvm-c/Config/AsmPrinters.def b/src/llvm-c/Config/AsmPrinters.def index 3ecc3644f..c463c3e89 100644 --- a/src/llvm-c/Config/AsmPrinters.def +++ b/src/llvm-c/Config/AsmPrinters.def @@ -27,9 +27,11 @@ LLVM_ASM_PRINTER(AArch64) LLVM_ASM_PRINTER(AMDGPU) LLVM_ASM_PRINTER(ARM) +LLVM_ASM_PRINTER(AVR) LLVM_ASM_PRINTER(BPF) LLVM_ASM_PRINTER(Hexagon) LLVM_ASM_PRINTER(Lanai) +LLVM_ASM_PRINTER(LoongArch) LLVM_ASM_PRINTER(Mips) LLVM_ASM_PRINTER(MSP430) LLVM_ASM_PRINTER(NVPTX) @@ -37,10 +39,10 @@ LLVM_ASM_PRINTER(PowerPC) LLVM_ASM_PRINTER(RISCV) LLVM_ASM_PRINTER(Sparc) LLVM_ASM_PRINTER(SystemZ) +LLVM_ASM_PRINTER(VE) LLVM_ASM_PRINTER(WebAssembly) LLVM_ASM_PRINTER(X86) LLVM_ASM_PRINTER(XCore) -LLVM_ASM_PRINTER(AVR) #undef LLVM_ASM_PRINTER diff --git a/src/llvm-c/Config/Disassemblers.def b/src/llvm-c/Config/Disassemblers.def index 4485af241..dce865414 100644 --- a/src/llvm-c/Config/Disassemblers.def +++ b/src/llvm-c/Config/Disassemblers.def @@ -27,19 +27,21 @@ LLVM_DISASSEMBLER(AArch64) LLVM_DISASSEMBLER(AMDGPU) LLVM_DISASSEMBLER(ARM) +LLVM_DISASSEMBLER(AVR) LLVM_DISASSEMBLER(BPF) LLVM_DISASSEMBLER(Hexagon) LLVM_DISASSEMBLER(Lanai) +LLVM_DISASSEMBLER(LoongArch) LLVM_DISASSEMBLER(Mips) LLVM_DISASSEMBLER(MSP430) LLVM_DISASSEMBLER(PowerPC) LLVM_DISASSEMBLER(RISCV) LLVM_DISASSEMBLER(Sparc) LLVM_DISASSEMBLER(SystemZ) +LLVM_DISASSEMBLER(VE) LLVM_DISASSEMBLER(WebAssembly) LLVM_DISASSEMBLER(X86) LLVM_DISASSEMBLER(XCore) -LLVM_DISASSEMBLER(AVR) #undef LLVM_DISASSEMBLER diff --git a/src/llvm-c/Config/TargetExegesis.def b/src/llvm-c/Config/TargetExegesis.def new file mode 100644 index 000000000..d4d3f99a7 --- /dev/null +++ b/src/llvm-c/Config/TargetExegesis.def @@ -0,0 +1,33 @@ +/*===----- llvm/Config/TargetExegesis.def - LLVM Target Exegesis-*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the target's of llvm-exegesis *| +|* supported by this build of LLVM. Clients of this file should define *| +|* the LLVM_EXEGISIS macro to be a function-like macro with a *| +|* single parameter (the name of the target whose assembly can be *| +|* generated); including this file will then enumerate all of the *| +|* targets with target llvm-exegsis support. *| +|* *| +|* The set of targets supported by LLVM is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_EXEGESIS +# error Please define the macro LLVM_EXEGESIS(TargetName) +#endif + +LLVM_EXEGESIS(AArch64) +LLVM_EXEGESIS(Mips) +LLVM_EXEGESIS(PowerPC) +LLVM_EXEGESIS(X86) + + +#undef LLVM_EXEGESIS diff --git a/src/llvm-c/Config/TargetMCAs.def b/src/llvm-c/Config/TargetMCAs.def new file mode 100644 index 000000000..1aefdbc25 --- /dev/null +++ b/src/llvm-c/Config/TargetMCAs.def @@ -0,0 +1,32 @@ +/*===------ llvm/Config/TargetMCAs.def - LLVM Target MCAs -------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the target MCAs *| +|* supported by this build of LLVM. Clients of this file should define *| +|* the LLVM_TARGETMCA macro to be a function-like macro with a *| +|* single parameter (the name of the target whose assembly can be *| +|* generated); including this file will then enumerate all of the *| +|* targets with target MCAs. *| +|* *| +|* The set of targets supported by LLVM is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_TARGETMCA +# error Please define the macro LLVM_TARGETMCA(TargetName) +#endif + +LLVM_TARGETMCA(AMDGPU) +LLVM_TARGETMCA(RISCV) +LLVM_TARGETMCA(X86) + + +#undef LLVM_TARGETMCA diff --git a/src/llvm-c/Config/Targets.def b/src/llvm-c/Config/Targets.def index 4962add96..250aac5c9 100644 --- a/src/llvm-c/Config/Targets.def +++ b/src/llvm-c/Config/Targets.def @@ -26,9 +26,11 @@ LLVM_TARGET(AArch64) LLVM_TARGET(AMDGPU) LLVM_TARGET(ARM) +LLVM_TARGET(AVR) LLVM_TARGET(BPF) LLVM_TARGET(Hexagon) LLVM_TARGET(Lanai) +LLVM_TARGET(LoongArch) LLVM_TARGET(Mips) LLVM_TARGET(MSP430) LLVM_TARGET(NVPTX) @@ -36,10 +38,10 @@ LLVM_TARGET(PowerPC) LLVM_TARGET(RISCV) LLVM_TARGET(Sparc) LLVM_TARGET(SystemZ) +LLVM_TARGET(VE) LLVM_TARGET(WebAssembly) LLVM_TARGET(X86) LLVM_TARGET(XCore) -LLVM_TARGET(AVR) #undef LLVM_TARGET diff --git a/src/llvm-c/Config/abi-breaking.h b/src/llvm-c/Config/abi-breaking.h index a09cffa7e..c501cc354 100644 --- a/src/llvm-c/Config/abi-breaking.h +++ b/src/llvm-c/Config/abi-breaking.h @@ -1,4 +1,4 @@ -/*===------- llvm-c/Config//abi-breaking.h - llvm configuration -------*- C -*-===*/ +/*===------- llvm/Config/abi-breaking.h - llvm configuration -------*- C -*-===*/ /* */ /* Part of the LLVM Project, under the Apache License v2.0 with LLVM */ /* Exceptions. */ @@ -20,7 +20,7 @@ /* Allow selectively disabling link-time mismatch checking so that header-only ADT content from LLVM can be used without linking libSupport. */ -#if !LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING +#if !defined(LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING) || !LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING // ABI_BREAKING_CHECKS protection: provides link-time failure when clients build // mismatch with LLVM diff --git a/src/llvm-c/Config/llvm-config.h b/src/llvm-c/Config/llvm-config.h index 331d05093..e4edb83c5 100644 --- a/src/llvm-c/Config/llvm-config.h +++ b/src/llvm-c/Config/llvm-config.h @@ -1,4 +1,4 @@ -/*===------- llvm-c/Config//llvm-config.h - llvm configuration -------*- C -*-===*/ +/*===------- llvm/Config/llvm-config.h - llvm configuration -------*- C -*-===*/ /* */ /* Part of the LLVM Project, under the Apache License v2.0 with LLVM */ /* Exceptions. */ @@ -17,10 +17,8 @@ /* Define if LLVM_ENABLE_DUMP is enabled */ /* #undef LLVM_ENABLE_DUMP */ -/* Define if we link Polly to the tools */ -/* #undef LINK_POLLY_INTO_TOOLS */ - /* Target triple LLVM will generate code for by default */ +/* Doesn't use `cmakedefine` because it is allowed to be empty. */ #define LLVM_DEFAULT_TARGET_TRIPLE "x86_64-pc-windows-msvc" /* Define if threads enabled */ @@ -53,6 +51,84 @@ /* LLVM name for the native target MC init function, if available */ #define LLVM_NATIVE_TARGETMC LLVMInitializeX86TargetMC +/* LLVM name for the native target MCA init function, if available */ +/* #undef LLVM_NATIVE_TARGETMCA */ + +/* Define if the AArch64 target is built in */ +#define LLVM_HAS_AARCH64_TARGET 1 + +/* Define if the AMDGPU target is built in */ +#define LLVM_HAS_AMDGPU_TARGET 1 + +/* Define if the ARC target is built in */ +#define LLVM_HAS_ARC_TARGET 0 + +/* Define if the ARM target is built in */ +#define LLVM_HAS_ARM_TARGET 1 + +/* Define if the AVR target is built in */ +#define LLVM_HAS_AVR_TARGET 1 + +/* Define if the BPF target is built in */ +#define LLVM_HAS_BPF_TARGET 1 + +/* Define if the CSKY target is built in */ +#define LLVM_HAS_CSKY_TARGET 0 + +/* Define if the DirectX target is built in */ +#define LLVM_HAS_DIRECTX_TARGET 0 + +/* Define if the Hexagon target is built in */ +#define LLVM_HAS_HEXAGON_TARGET 1 + +/* Define if the Lanai target is built in */ +#define LLVM_HAS_LANAI_TARGET 1 + +/* Define if the LoongArch target is built in */ +#define LLVM_HAS_LOONGARCH_TARGET 1 + +/* Define if the M68k target is built in */ +#define LLVM_HAS_M68K_TARGET 0 + +/* Define if the Mips target is built in */ +#define LLVM_HAS_MIPS_TARGET 1 + +/* Define if the MSP430 target is built in */ +#define LLVM_HAS_MSP430_TARGET 1 + +/* Define if the NVPTX target is built in */ +#define LLVM_HAS_NVPTX_TARGET 1 + +/* Define if the PowerPC target is built in */ +#define LLVM_HAS_POWERPC_TARGET 1 + +/* Define if the RISCV target is built in */ +#define LLVM_HAS_RISCV_TARGET 1 + +/* Define if the Sparc target is built in */ +#define LLVM_HAS_SPARC_TARGET 1 + +/* Define if the SPIRV target is built in */ +#define LLVM_HAS_SPIRV_TARGET 0 + +/* Define if the SystemZ target is built in */ +#define LLVM_HAS_SYSTEMZ_TARGET 1 + +/* Define if the VE target is built in */ +#define LLVM_HAS_VE_TARGET 1 + +/* Define if the WebAssembly target is built in */ +#define LLVM_HAS_WEBASSEMBLY_TARGET 1 + +/* Define if the X86 target is built in */ +#define LLVM_HAS_X86_TARGET 1 + +/* Define if the XCore target is built in */ +#define LLVM_HAS_XCORE_TARGET 1 + +/* Define if the Xtensa target is built in */ +#define LLVM_HAS_XTENSA_TARGET 0 + /* Define if this is Unixish platform */ /* #undef LLVM_ON_UNIX */ @@ -66,20 +142,60 @@ #define LLVM_USE_PERF 0 /* Major version of the LLVM API */ -#define LLVM_VERSION_MAJOR 17 +#define LLVM_VERSION_MAJOR 18 /* Minor version of the LLVM API */ -#define LLVM_VERSION_MINOR 0 +#define LLVM_VERSION_MINOR 1 /* Patch version of the LLVM API */ -#define LLVM_VERSION_PATCH 1 +#define LLVM_VERSION_PATCH 8 /* LLVM version string */ -#define LLVM_VERSION_STRING "17.0.1" +#define LLVM_VERSION_STRING "18.1.8" /* Whether LLVM records statistics for use with GetStatistics(), * PrintStatistics() or PrintStatisticsJSON() */ #define LLVM_FORCE_ENABLE_STATS 0 +/* Define if we have z3 and want to build it */ +/* #undef LLVM_WITH_Z3 */ + +/* Define if we have curl and want to use it */ +/* #undef LLVM_ENABLE_CURL */ + +/* Define if we have cpp-httplib and want to use it */ +/* #undef LLVM_ENABLE_HTTPLIB */ + +/* Define if zlib compression is available */ +#define LLVM_ENABLE_ZLIB 0 + +/* Define if zstd compression is available */ +#define LLVM_ENABLE_ZSTD 0 + +/* Define if LLVM is using tflite */ +/* #undef LLVM_HAVE_TFLITE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYSEXITS_H */ + +/* Define if building libLLVM shared library */ +/* #undef LLVM_BUILD_LLVM_DYLIB */ + +/* Define if building LLVM with BUILD_SHARED_LIBS */ +/* #undef LLVM_BUILD_SHARED_LIBS */ + +/* Define if building LLVM with LLVM_FORCE_USE_OLD_TOOLCHAIN_LIBS */ +/* #undef LLVM_FORCE_USE_OLD_TOOLCHAIN */ + +/* Define if llvm_unreachable should be optimized with undefined behavior + * in non assert builds */ +#define LLVM_UNREACHABLE_OPTIMIZE 1 + +/* Define to 1 if you have the DIA SDK installed, and to 0 if you don't. */ +#define LLVM_ENABLE_DIA_SDK 1 + +/* Define if plugins enabled */ +/* #undef LLVM_ENABLE_PLUGINS */ + #endif diff --git a/src/llvm-c/Core.h b/src/llvm-c/Core.h index fbba8ca42..25b8248fd 100644 --- a/src/llvm-c/Core.h +++ b/src/llvm-c/Core.h @@ -15,11 +15,11 @@ #ifndef LLVM_C_CORE_H #define LLVM_C_CORE_H -#include "llvm-c/Deprecated.h" -#include "llvm-c/ErrorHandling.h" -#include "llvm-c/ExternC.h" +#include "Deprecated.h" +#include "ErrorHandling.h" +#include "ExternC.h" -#include "llvm-c/Types.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN @@ -216,7 +216,6 @@ typedef enum { LLVMColdCallConv = 9, LLVMGHCCallConv = 10, LLVMHiPECallConv = 11, - LLVMWebKitJSCallConv = 12, LLVMAnyRegCallConv = 13, LLVMPreserveMostCallConv = 14, LLVMPreserveAllCallConv = 15, @@ -468,8 +467,45 @@ enum { LLVMAttributeFunctionIndex = -1, }; +/** + * Tail call kind for LLVMSetTailCallKind and LLVMGetTailCallKind. + * + * Note that 'musttail' implies 'tail'. + * + * @see CallInst::TailCallKind + */ +typedef enum { + LLVMTailCallKindNone = 0, + LLVMTailCallKindTail = 1, + LLVMTailCallKindMustTail = 2, + LLVMTailCallKindNoTail = 3, +} LLVMTailCallKind; + typedef unsigned LLVMAttributeIndex; +enum { + LLVMFastMathAllowReassoc = (1 << 0), + LLVMFastMathNoNaNs = (1 << 1), + LLVMFastMathNoInfs = (1 << 2), + LLVMFastMathNoSignedZeros = (1 << 3), + LLVMFastMathAllowReciprocal = (1 << 4), + LLVMFastMathAllowContract = (1 << 5), + LLVMFastMathApproxFunc = (1 << 6), + LLVMFastMathNone = 0, + LLVMFastMathAll = LLVMFastMathAllowReassoc | LLVMFastMathNoNaNs | + LLVMFastMathNoInfs | LLVMFastMathNoSignedZeros | + LLVMFastMathAllowReciprocal | LLVMFastMathAllowContract | + LLVMFastMathApproxFunc, +}; + +/** + * Flags to indicate what fast-math-style optimizations are allowed + * on operations. + * + * See https://llvm.org/docs/LangRef.html#fast-math-flags + */ +typedef unsigned LLVMFastMathFlags; + /** * @} */ @@ -890,12 +926,58 @@ void LLVMAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, size_t Len); * * @see InlineAsm::get() */ -LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, char *AsmString, - size_t AsmStringSize, char *Constraints, +LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, const char *AsmString, + size_t AsmStringSize, const char *Constraints, size_t ConstraintsSize, LLVMBool HasSideEffects, LLVMBool IsAlignStack, LLVMInlineAsmDialect Dialect, LLVMBool CanThrow); +/** + * Get the template string used for an inline assembly snippet + * + */ +const char *LLVMGetInlineAsmAsmString(LLVMValueRef InlineAsmVal, size_t *Len); + +/** + * Get the raw constraint string for an inline assembly snippet + * + */ +const char *LLVMGetInlineAsmConstraintString(LLVMValueRef InlineAsmVal, + size_t *Len); + +/** + * Get the dialect used by the inline asm snippet + * + */ +LLVMInlineAsmDialect LLVMGetInlineAsmDialect(LLVMValueRef InlineAsmVal); + +/** + * Get the function type of the inline assembly snippet. The same type that + * was passed into LLVMGetInlineAsm originally + * + * @see LLVMGetInlineAsm + * + */ +LLVMTypeRef LLVMGetInlineAsmFunctionType(LLVMValueRef InlineAsmVal); + +/** + * Get if the inline asm snippet has side effects + * + */ +LLVMBool LLVMGetInlineAsmHasSideEffects(LLVMValueRef InlineAsmVal); + +/** + * Get if the inline asm snippet needs an aligned stack + * + */ +LLVMBool LLVMGetInlineAsmNeedsAlignedStack(LLVMValueRef InlineAsmVal); + +/** + * Get if the inline asm snippet may unwind the stack + * + */ +LLVMBool LLVMGetInlineAsmCanUnwind(LLVMValueRef InlineAsmVal); + /** * Obtain the context to which this module is associated. * @@ -2216,45 +2298,26 @@ LLVMValueRef LLVMConstNUWSub(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant) LLVMValueRef LLVMConstMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); LLVMValueRef LLVMConstNSWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); LLVMValueRef LLVMConstNUWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); -LLVMValueRef LLVMConstAnd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); -LLVMValueRef LLVMConstOr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); LLVMValueRef LLVMConstXor(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); LLVMValueRef LLVMConstICmp(LLVMIntPredicate Predicate, LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); LLVMValueRef LLVMConstFCmp(LLVMRealPredicate Predicate, LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); LLVMValueRef LLVMConstShl(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); -LLVMValueRef LLVMConstLShr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); -LLVMValueRef LLVMConstAShr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, LLVMValueRef *ConstantIndices, unsigned NumIndices); LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, LLVMValueRef *ConstantIndices, unsigned NumIndices); LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstSExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstZExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstFPTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstFPExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstUIToFP(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstSIToFP(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstFPToUI(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstFPToSI(LLVMValueRef ConstantVal, LLVMTypeRef ToType); LLVMValueRef LLVMConstPtrToInt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); LLVMValueRef LLVMConstIntToPtr(LLVMValueRef ConstantVal, LLVMTypeRef ToType); LLVMValueRef LLVMConstBitCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); LLVMValueRef LLVMConstAddrSpaceCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstZExtOrBitCast(LLVMValueRef ConstantVal, - LLVMTypeRef ToType); -LLVMValueRef LLVMConstSExtOrBitCast(LLVMValueRef ConstantVal, - LLVMTypeRef ToType); LLVMValueRef LLVMConstTruncOrBitCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); LLVMValueRef LLVMConstPointerCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); -LLVMValueRef LLVMConstIntCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType, - LLVMBool isSigned); -LLVMValueRef LLVMConstFPCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); LLVMValueRef LLVMConstExtractElement(LLVMValueRef VectorConstant, LLVMValueRef IndexConstant); LLVMValueRef LLVMConstInsertElement(LLVMValueRef VectorConstant, @@ -2960,6 +3023,74 @@ LLVMValueRef LLVMMDNodeInContext(LLVMContextRef C, LLVMValueRef *Vals, /** Deprecated: Use LLVMMDNodeInContext2 instead. */ LLVMValueRef LLVMMDNode(LLVMValueRef *Vals, unsigned Count); +/** + * @} + */ + +/** + * @defgroup LLVMCCoreOperandBundle Operand Bundles + * + * Functions in this group operate on LLVMOperandBundleRef instances that + * correspond to llvm::OperandBundleDef instances. + * + * @see llvm::OperandBundleDef + * + * @{ + */ + +/** + * Create a new operand bundle. + * + * Every invocation should be paired with LLVMDisposeOperandBundle() or memory + * will be leaked. + * + * @param Tag Tag name of the operand bundle + * @param TagLen Length of Tag + * @param Args Memory address of an array of bundle operands + * @param NumArgs Length of Args + */ +LLVMOperandBundleRef LLVMCreateOperandBundle(const char *Tag, size_t TagLen, + LLVMValueRef *Args, + unsigned NumArgs); + +/** + * Destroy an operand bundle. + * + * This must be called for every created operand bundle or memory will be + * leaked. + */ +void LLVMDisposeOperandBundle(LLVMOperandBundleRef Bundle); + +/** + * Obtain the tag of an operand bundle as a string. + * + * @param Bundle Operand bundle to obtain tag of. + * @param Len Out parameter which holds the length of the returned string. + * @return The tag name of Bundle. + * @see OperandBundleDef::getTag() + */ +const char *LLVMGetOperandBundleTag(LLVMOperandBundleRef Bundle, size_t *Len); + +/** + * Obtain the number of operands for an operand bundle. + * + * @param Bundle Operand bundle to obtain operand count of. + * @return The number of operands. + * @see OperandBundleDef::input_size() + */ +unsigned LLVMGetNumOperandBundleArgs(LLVMOperandBundleRef Bundle); + +/** + * Obtain the operand for an operand bundle at the given index. + * + * @param Bundle Operand bundle to obtain operand of. + * @param Index An operand index, must be less than + * LLVMGetNumOperandBundleArgs(). + * @return The operand. + */ +LLVMValueRef LLVMGetOperandBundleArgAtIndex(LLVMOperandBundleRef Bundle, + unsigned Index); + /** * @} */ @@ -3411,6 +3542,24 @@ LLVMTypeRef LLVMGetCalledFunctionType(LLVMValueRef C); */ LLVMValueRef LLVMGetCalledValue(LLVMValueRef Instr); +/** + * Obtain the number of operand bundles attached to this instruction. + * + * This only works on llvm::CallInst and llvm::InvokeInst instructions. + * + * @see llvm::CallBase::getNumOperandBundles() + */ +unsigned LLVMGetNumOperandBundles(LLVMValueRef C); + +/** + * Obtain the operand bundle attached to this instruction at the given index. + * Use LLVMDisposeOperandBundle to free the operand bundle. + * + * This only works on llvm::CallInst and llvm::InvokeInst instructions. + */ +LLVMOperandBundleRef LLVMGetOperandBundleAtIndex(LLVMValueRef C, + unsigned Index); + /** * Obtain whether a call instruction is a tail call. * @@ -3429,6 +3578,20 @@ LLVMBool LLVMIsTailCall(LLVMValueRef CallInst); */ void LLVMSetTailCall(LLVMValueRef CallInst, LLVMBool IsTailCall); +/** + * Obtain a tail call kind of the call instruction. + * + * @see llvm::CallInst::setTailCallKind() + */ +LLVMTailCallKind LLVMGetTailCallKind(LLVMValueRef CallInst); + +/** + * Set the call kind of the call instruction. + * + * @see llvm::CallInst::getTailCallKind() + */ +void LLVMSetTailCallKind(LLVMValueRef CallInst, LLVMTailCallKind kind); + /** * Return the normal destination basic block. * @@ -3761,6 +3924,10 @@ LLVMValueRef LLVMBuildInvoke2(LLVMBuilderRef, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, const char *Name); +LLVMValueRef LLVMBuildInvokeWithOperandBundles( + LLVMBuilderRef, LLVMTypeRef Ty, LLVMValueRef Fn, LLVMValueRef *Args, + unsigned NumArgs, LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, + LLVMOperandBundleRef *Bundles, unsigned NumBundles, const char *Name); LLVMValueRef LLVMBuildUnreachable(LLVMBuilderRef); /* Exception Handling */ @@ -3920,6 +4087,55 @@ void LLVMSetNSW(LLVMValueRef ArithInst, LLVMBool HasNSW); LLVMBool LLVMGetExact(LLVMValueRef DivOrShrInst); void LLVMSetExact(LLVMValueRef DivOrShrInst, LLVMBool IsExact); +/** + * Gets if the instruction has the non-negative flag set. + * Only valid for zext instructions. + */ +LLVMBool LLVMGetNNeg(LLVMValueRef NonNegInst); +/** + * Sets the non-negative flag for the instruction. + * Only valid for zext instructions. + */ +void LLVMSetNNeg(LLVMValueRef NonNegInst, LLVMBool IsNonNeg); + +/** + * Get the flags for which fast-math-style optimizations are allowed for this + * value. + * + * Only valid on floating point instructions. + * @see LLVMCanValueUseFastMathFlags + */ +LLVMFastMathFlags LLVMGetFastMathFlags(LLVMValueRef FPMathInst); + +/** + * Sets the flags for which fast-math-style optimizations are allowed for this + * value. + * + * Only valid on floating point instructions. + * @see LLVMCanValueUseFastMathFlags + */ +void LLVMSetFastMathFlags(LLVMValueRef FPMathInst, LLVMFastMathFlags FMF); + +/** + * Check if a given value can potentially have fast math flags. + * + * Will return true for floating point arithmetic instructions, and for select, + * phi, and call instructions whose type is a floating point type, or a vector + * or array thereof. See https://llvm.org/docs/LangRef.html#fast-math-flags + */ +LLVMBool LLVMCanValueUseFastMathFlags(LLVMValueRef Inst); + +/** + * Gets whether the instruction has the disjoint flag set. + * Only valid for or instructions. + */ +LLVMBool LLVMGetIsDisjoint(LLVMValueRef Inst); +/** + * Sets the disjoint flag for the instruction. + * Only valid for or instructions. + */ +void LLVMSetIsDisjoint(LLVMValueRef Inst, LLVMBool IsDisjoint); + /* Memory */ LLVMValueRef LLVMBuildMalloc(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name); LLVMValueRef LLVMBuildArrayMalloc(LLVMBuilderRef, LLVMTypeRef Ty, @@ -4045,6 +4261,11 @@ LLVMValueRef LLVMBuildPhi(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name); LLVMValueRef LLVMBuildCall2(LLVMBuilderRef, LLVMTypeRef, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, const char *Name); +LLVMValueRef +LLVMBuildCallWithOperandBundles(LLVMBuilderRef, LLVMTypeRef, LLVMValueRef Fn, + LLVMValueRef *Args, unsigned NumArgs, + LLVMOperandBundleRef *Bundles, + unsigned NumBundles, const char *Name); LLVMValueRef LLVMBuildSelect(LLVMBuilderRef, LLVMValueRef If, LLVMValueRef Then, LLVMValueRef Else, const char *Name); diff --git a/src/llvm-c/DebugInfo.h b/src/llvm-c/DebugInfo.h index 592429470..93bd9e2ad 100644 --- a/src/llvm-c/DebugInfo.h +++ b/src/llvm-c/DebugInfo.h @@ -16,8 +16,8 @@ #ifndef LLVM_C_DEBUGINFO_H #define LLVM_C_DEBUGINFO_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Disassembler.h b/src/llvm-c/Disassembler.h index b1cb35da6..e6642f4ed 100644 --- a/src/llvm-c/Disassembler.h +++ b/src/llvm-c/Disassembler.h @@ -15,8 +15,8 @@ #ifndef LLVM_C_DISASSEMBLER_H #define LLVM_C_DISASSEMBLER_H -#include "llvm-c/DisassemblerTypes.h" -#include "llvm-c/ExternC.h" +#include "DisassemblerTypes.h" +#include "ExternC.h" /** * @defgroup LLVMCDisassembler Disassembler diff --git a/src/llvm-c/DisassemblerTypes.h b/src/llvm-c/DisassemblerTypes.h index 6999a350e..6b7ad6104 100644 --- a/src/llvm-c/DisassemblerTypes.h +++ b/src/llvm-c/DisassemblerTypes.h @@ -10,7 +10,7 @@ #ifndef LLVM_C_DISASSEMBLERTYPES_H #define LLVM_C_DISASSEMBLERTYPES_H -#include "llvm-c/DataTypes.h" +#include "DataTypes.h" #ifdef __cplusplus #include #else diff --git a/src/llvm-c/Error.h b/src/llvm-c/Error.h index c3baaf651..00746c701 100644 --- a/src/llvm-c/Error.h +++ b/src/llvm-c/Error.h @@ -14,7 +14,7 @@ #ifndef LLVM_C_ERROR_H #define LLVM_C_ERROR_H -#include "llvm-c/ExternC.h" +#include "ExternC.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/ErrorHandling.h b/src/llvm-c/ErrorHandling.h index d9b9f2275..7f9b50a95 100644 --- a/src/llvm-c/ErrorHandling.h +++ b/src/llvm-c/ErrorHandling.h @@ -14,7 +14,7 @@ #ifndef LLVM_C_ERRORHANDLING_H #define LLVM_C_ERRORHANDLING_H -#include "llvm-c/ExternC.h" +#include "ExternC.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/ExecutionEngine.h b/src/llvm-c/ExecutionEngine.h index c5fc9bdb4..8e72faefd 100644 --- a/src/llvm-c/ExecutionEngine.h +++ b/src/llvm-c/ExecutionEngine.h @@ -19,10 +19,10 @@ #ifndef LLVM_C_EXECUTIONENGINE_H #define LLVM_C_EXECUTIONENGINE_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Target.h" -#include "llvm-c/TargetMachine.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Target.h" +#include "TargetMachine.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/IRReader.h b/src/llvm-c/IRReader.h index 905b84fa5..ec1110c7a 100644 --- a/src/llvm-c/IRReader.h +++ b/src/llvm-c/IRReader.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_IRREADER_H #define LLVM_C_IRREADER_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/LLJIT.h b/src/llvm-c/LLJIT.h index a06133aac..ee207e10e 100644 --- a/src/llvm-c/LLJIT.h +++ b/src/llvm-c/LLJIT.h @@ -1,4 +1,4 @@ -/*===----------- llvm-c/LLJIT.h - OrcV2 LLJIT C bindings --------*- C++ -*-===*\ +/*===----------- llvm-c/LLJIT.h - OrcV2 LLJIT C bindings ----------*- C -*-===*\ |* *| |* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| |* Exceptions. *| @@ -24,10 +24,10 @@ #ifndef LLVM_C_LLJIT_H #define LLVM_C_LLJIT_H -#include "llvm-c/Error.h" -#include "llvm-c/Orc.h" -#include "llvm-c/TargetMachine.h" -#include "llvm-c/Types.h" +#include "Error.h" +#include "Orc.h" +#include "TargetMachine.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/LLJITUtils.h b/src/llvm-c/LLJITUtils.h new file mode 100644 index 000000000..57ffedff8 --- /dev/null +++ b/src/llvm-c/LLJITUtils.h @@ -0,0 +1,52 @@ +/*===------- llvm-c/LLJITUtils.h - Advanced LLJIT features --------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface for extra utilities to be used with *| +|* the LLJIT class from the llvm-c/LLJIT.h header. It requires to following *| +|* link libraries in addition to libLLVMOrcJIT.a: *| +|* - libLLVMOrcDebugging.a *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +|* Note: This interface is experimental. It is *NOT* stable, and may be *| +|* changed without warning. Only C API usage documentation is *| +|* provided. See the C++ documentation for all higher level ORC API *| +|* details. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_LLJITUTILS_H +#define LLVM_C_LLJITUTILS_H + +#include "LLJIT.h" + +LLVM_C_EXTERN_C_BEGIN + +/** + * @defgroup LLVMCExecutionEngineLLJITUtils LLJIT Utilities + * @ingroup LLVMCExecutionEngineLLJIT + * + * @{ + */ + +/** + * Install the plugin that submits debug objects to the executor. Executors must + * expose the llvm_orc_registerJITLoaderGDBWrapper symbol. + */ +LLVMErrorRef LLVMOrcLLJITEnableDebugSupport(LLVMOrcLLJITRef J); + +/** + * @} + */ + +LLVM_C_EXTERN_C_END + +#endif /* LLVM_C_LLJITUTILS_H */ diff --git a/src/llvm-c/Linker.h b/src/llvm-c/Linker.h index acff5d5e2..463a2cff9 100644 --- a/src/llvm-c/Linker.h +++ b/src/llvm-c/Linker.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_LINKER_H #define LLVM_C_LINKER_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Object.h b/src/llvm-c/Object.h index f871d5230..1948c3c34 100644 --- a/src/llvm-c/Object.h +++ b/src/llvm-c/Object.h @@ -19,9 +19,9 @@ #ifndef LLVM_C_OBJECT_H #define LLVM_C_OBJECT_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" -#include "llvm-c/Config//llvm-config.h" +#include "ExternC.h" +#include "Types.h" +#include "Config/llvm-config.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Orc.h b/src/llvm-c/Orc.h index 0dcfb0686..ecd110b4d 100644 --- a/src/llvm-c/Orc.h +++ b/src/llvm-c/Orc.h @@ -27,9 +27,9 @@ #ifndef LLVM_C_ORC_H #define LLVM_C_ORC_H -#include "llvm-c/Error.h" -#include "llvm-c/TargetMachine.h" -#include "llvm-c/Types.h" +#include "Error.h" +#include "TargetMachine.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN @@ -346,7 +346,7 @@ typedef struct LLVMOrcOpaqueLookupState *LLVMOrcLookupStateRef; * into. * * The JDLookupFlags argument can be inspected to determine whether the original - * lookup included non-exported symobls. + * lookup included non-exported symbols. * * Finally, the LookupSet argument contains the set of symbols that could not * be found in JD already (the set of generation candidates). @@ -508,7 +508,7 @@ void LLVMOrcSymbolStringPoolClearDeadEntries(LLVMOrcSymbolStringPoolRef SSP); * Intern a string in the ExecutionSession's SymbolStringPool and return a * reference to it. This increments the ref-count of the pool entry, and the * returned value should be released once the client is done with it by - * calling LLVMOrReleaseSymbolStringPoolEntry. + * calling LLVMOrcReleaseSymbolStringPoolEntry. * * Since strings are uniqued within the SymbolStringPool * LLVMOrcSymbolStringPoolEntryRefs can be compared by value to test string @@ -796,7 +796,7 @@ void LLVMOrcDisposeSymbols(LLVMOrcSymbolStringPoolEntryRef *Symbols); * method returns an error then clients should log it and call * LLVMOrcMaterializationResponsibilityFailMaterialization. If no dependencies * have been registered for the symbols covered by this - * MaterializationResponsibiility then this method is guaranteed to return + * MaterializationResponsibility then this method is guaranteed to return * LLVMErrorSuccess. */ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyResolved( @@ -813,7 +813,7 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyResolved( * method returns an error then clients should log it and call * LLVMOrcMaterializationResponsibilityFailMaterialization. * If no dependencies have been registered for the symbols covered by this - * MaterializationResponsibiility then this method is guaranteed to return + * MaterializationResponsibility then this method is guaranteed to return * LLVMErrorSuccess. */ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyEmitted( @@ -839,7 +839,7 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityDefineMaterializing( /** * Notify all not-yet-emitted covered by this MaterializationResponsibility * instance that an error has occurred. - * This will remove all symbols covered by this MaterializationResponsibilty + * This will remove all symbols covered by this MaterializationResponsibility * from the target JITDylib, and send an error to any queries waiting on * these symbols. */ diff --git a/src/llvm-c/OrcEE.h b/src/llvm-c/OrcEE.h index d451187aa..aef24c7aa 100644 --- a/src/llvm-c/OrcEE.h +++ b/src/llvm-c/OrcEE.h @@ -24,11 +24,11 @@ #ifndef LLVM_C_ORCEE_H #define LLVM_C_ORCEE_H -#include "llvm-c/Error.h" -#include "llvm-c/ExecutionEngine.h" -#include "llvm-c/Orc.h" -#include "llvm-c/TargetMachine.h" -#include "llvm-c/Types.h" +#include "Error.h" +#include "ExecutionEngine.h" +#include "Orc.h" +#include "TargetMachine.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Remarks.h b/src/llvm-c/Remarks.h index ffe647a65..548a4041a 100644 --- a/src/llvm-c/Remarks.h +++ b/src/llvm-c/Remarks.h @@ -15,8 +15,8 @@ #ifndef LLVM_C_REMARKS_H #define LLVM_C_REMARKS_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Types.h" #ifdef __cplusplus #include #else diff --git a/src/llvm-c/Support.h b/src/llvm-c/Support.h index 17657861b..31a75354c 100644 --- a/src/llvm-c/Support.h +++ b/src/llvm-c/Support.h @@ -14,9 +14,9 @@ #ifndef LLVM_C_SUPPORT_H #define LLVM_C_SUPPORT_H -#include "llvm-c/DataTypes.h" -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" +#include "DataTypes.h" +#include "ExternC.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Target.h b/src/llvm-c/Target.h index 2bc3d1ae7..4d03741c4 100644 --- a/src/llvm-c/Target.h +++ b/src/llvm-c/Target.h @@ -19,9 +19,9 @@ #ifndef LLVM_C_TARGET_H #define LLVM_C_TARGET_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Types.h" -#include "llvm-c/Config//llvm-config.h" +#include "ExternC.h" +#include "Types.h" +#include "Config/llvm-config.h" LLVM_C_EXTERN_C_BEGIN @@ -40,34 +40,34 @@ typedef struct LLVMOpaqueTargetLibraryInfotData *LLVMTargetLibraryInfoRef; /* Declare all of the target-initialization functions that are available. */ #define LLVM_TARGET(TargetName) \ void LLVMInitialize##TargetName##TargetInfo(void); -#include "llvm-c/Config//Targets.def" +#include "Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ #define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##Target(void); -#include "llvm-c/Config//Targets.def" +#include "Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ #define LLVM_TARGET(TargetName) \ void LLVMInitialize##TargetName##TargetMC(void); -#include "llvm-c/Config//Targets.def" +#include "Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ /* Declare all of the available assembly printer initialization functions. */ #define LLVM_ASM_PRINTER(TargetName) \ void LLVMInitialize##TargetName##AsmPrinter(void); -#include "llvm-c/Config//AsmPrinters.def" +#include "Config/AsmPrinters.def" #undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */ /* Declare all of the available assembly parser initialization functions. */ #define LLVM_ASM_PARSER(TargetName) \ void LLVMInitialize##TargetName##AsmParser(void); -#include "llvm-c/Config//AsmParsers.def" +#include "Config/AsmParsers.def" #undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */ /* Declare all of the available disassembler initialization functions. */ #define LLVM_DISASSEMBLER(TargetName) \ void LLVMInitialize##TargetName##Disassembler(void); -#include "llvm-c/Config//Disassemblers.def" +#include "Config/Disassemblers.def" #undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */ /** LLVMInitializeAllTargetInfos - The main program should call this function if @@ -75,7 +75,7 @@ typedef struct LLVMOpaqueTargetLibraryInfotData *LLVMTargetLibraryInfoRef; support. */ static inline void LLVMInitializeAllTargetInfos(void) { #define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetInfo(); -#include "llvm-c/Config//Targets.def" +#include "Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ } @@ -84,7 +84,7 @@ static inline void LLVMInitializeAllTargetInfos(void) { support. */ static inline void LLVMInitializeAllTargets(void) { #define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##Target(); -#include "llvm-c/Config//Targets.def" +#include "Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ } @@ -93,7 +93,7 @@ static inline void LLVMInitializeAllTargets(void) { support. */ static inline void LLVMInitializeAllTargetMCs(void) { #define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetMC(); -#include "llvm-c/Config//Targets.def" +#include "Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ } @@ -102,7 +102,7 @@ static inline void LLVMInitializeAllTargetMCs(void) { available via the TargetRegistry. */ static inline void LLVMInitializeAllAsmPrinters(void) { #define LLVM_ASM_PRINTER(TargetName) LLVMInitialize##TargetName##AsmPrinter(); -#include "llvm-c/Config//AsmPrinters.def" +#include "Config/AsmPrinters.def" #undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */ } @@ -111,7 +111,7 @@ static inline void LLVMInitializeAllAsmPrinters(void) { available via the TargetRegistry. */ static inline void LLVMInitializeAllAsmParsers(void) { #define LLVM_ASM_PARSER(TargetName) LLVMInitialize##TargetName##AsmParser(); -#include "llvm-c/Config//AsmParsers.def" +#include "Config/AsmParsers.def" #undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */ } @@ -121,7 +121,7 @@ static inline void LLVMInitializeAllAsmParsers(void) { static inline void LLVMInitializeAllDisassemblers(void) { #define LLVM_DISASSEMBLER(TargetName) \ LLVMInitialize##TargetName##Disassembler(); -#include "llvm-c/Config//Disassemblers.def" +#include "Config/Disassemblers.def" #undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */ } diff --git a/src/llvm-c/TargetMachine.h b/src/llvm-c/TargetMachine.h index bfbe1421a..aa628e216 100644 --- a/src/llvm-c/TargetMachine.h +++ b/src/llvm-c/TargetMachine.h @@ -19,9 +19,9 @@ #ifndef LLVM_C_TARGETMACHINE_H #define LLVM_C_TARGETMACHINE_H -#include "llvm-c/ExternC.h" -#include "llvm-c/Target.h" -#include "llvm-c/Types.h" +#include "ExternC.h" +#include "Target.h" +#include "Types.h" LLVM_C_EXTERN_C_BEGIN @@ -31,6 +31,7 @@ LLVM_C_EXTERN_C_BEGIN * @{ */ +typedef struct LLVMOpaqueTargetMachineOptions *LLVMTargetMachineOptionsRef; typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; typedef struct LLVMTarget *LLVMTargetRef; @@ -66,6 +67,12 @@ typedef enum { LLVMObjectFile } LLVMCodeGenFileType; +typedef enum { + LLVMGlobalISelAbortEnable, + LLVMGlobalISelAbortDisable, + LLVMGlobalISelAbortDisableWithDiag, +} LLVMGlobalISelAbortMode; + /** Returns the first llvm::Target in the registered targets list. */ LLVMTargetRef LLVMGetFirstTarget(void); /** Returns the next llvm::Target given a previous one (or null if there's none) */ @@ -98,6 +105,55 @@ LLVMBool LLVMTargetHasTargetMachine(LLVMTargetRef T); LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T); /*===-- Target Machine ----------------------------------------------------===*/ +/** + * Create a new set of options for an llvm::TargetMachine. + * + * The returned option structure must be released with + * LLVMDisposeTargetMachineOptions() after the call to + * LLVMCreateTargetMachineWithOptions(). + */ +LLVMTargetMachineOptionsRef LLVMCreateTargetMachineOptions(void); + +/** + * Dispose of an LLVMTargetMachineOptionsRef instance. + */ +void LLVMDisposeTargetMachineOptions(LLVMTargetMachineOptionsRef Options); + +void LLVMTargetMachineOptionsSetCPU(LLVMTargetMachineOptionsRef Options, + const char *CPU); + +/** + * Set the list of features for the target machine. + * + * \param Features a comma-separated list of features. + */ +void LLVMTargetMachineOptionsSetFeatures(LLVMTargetMachineOptionsRef Options, + const char *Features); + +void LLVMTargetMachineOptionsSetABI(LLVMTargetMachineOptionsRef Options, + const char *ABI); + +void LLVMTargetMachineOptionsSetCodeGenOptLevel( + LLVMTargetMachineOptionsRef Options, LLVMCodeGenOptLevel Level); + +void LLVMTargetMachineOptionsSetRelocMode(LLVMTargetMachineOptionsRef Options, + LLVMRelocMode Reloc); + +void LLVMTargetMachineOptionsSetCodeModel(LLVMTargetMachineOptionsRef Options, + LLVMCodeModel CodeModel); + +/** + * Create a new llvm::TargetMachine. + * + * \param T the target to create a machine for. + * \param Triple a triple describing the target machine. + * \param Options additional configuration (see + * LLVMCreateTargetMachineOptions()). + */ +LLVMTargetMachineRef +LLVMCreateTargetMachineWithOptions(LLVMTargetRef T, const char *Triple, + LLVMTargetMachineOptionsRef Options); + /** Creates a new llvm::TargetMachine. See llvm::Target::createTargetMachine */ LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple, const char *CPU, const char *Features, @@ -132,6 +188,21 @@ LLVMTargetDataRef LLVMCreateTargetDataLayout(LLVMTargetMachineRef T); void LLVMSetTargetMachineAsmVerbosity(LLVMTargetMachineRef T, LLVMBool VerboseAsm); +/** Enable fast-path instruction selection. */ +void LLVMSetTargetMachineFastISel(LLVMTargetMachineRef T, LLVMBool Enable); + +/** Enable global instruction selection. */ +void LLVMSetTargetMachineGlobalISel(LLVMTargetMachineRef T, LLVMBool Enable); + +/** Set abort behaviour when global instruction selection fails to lower/select + * an instruction. */ +void LLVMSetTargetMachineGlobalISelAbort(LLVMTargetMachineRef T, + LLVMGlobalISelAbortMode Mode); + +/** Enable the MachineOutliner pass. */ +void LLVMSetTargetMachineMachineOutliner(LLVMTargetMachineRef T, + LLVMBool Enable); + /** Emits an asm or object file for the given module to the filename. This wraps several c++ only classes (among them a file stream). Returns any error in ErrorMessage. Use LLVMDisposeMessage to dispose the message. */ diff --git a/src/llvm-c/Transforms/PassBuilder.h b/src/llvm-c/Transforms/PassBuilder.h index d0466dd7f..8ad2a9982 100644 --- a/src/llvm-c/Transforms/PassBuilder.h +++ b/src/llvm-c/Transforms/PassBuilder.h @@ -14,9 +14,9 @@ #ifndef LLVM_C_TRANSFORMS_PASSBUILDER_H #define LLVM_C_TRANSFORMS_PASSBUILDER_H -#include "llvm-c/Error.h" -#include "llvm-c/TargetMachine.h" -#include "llvm-c/Types.h" +#include "../Error.h" +#include "../TargetMachine.h" +#include "../Types.h" /** * @defgroup LLVMCCoreNewPM New Pass Manager diff --git a/src/llvm-c/Types.h b/src/llvm-c/Types.h index 4e9967372..77aa7c9b4 100644 --- a/src/llvm-c/Types.h +++ b/src/llvm-c/Types.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_TYPES_H #define LLVM_C_TYPES_H -#include "llvm-c/DataTypes.h" -#include "llvm-c/ExternC.h" +#include "DataTypes.h" +#include "ExternC.h" LLVM_C_EXTERN_C_BEGIN @@ -132,6 +132,11 @@ typedef struct LLVMOpaquePassManager *LLVMPassManagerRef; * @see llvm::Use */ typedef struct LLVMOpaqueUse *LLVMUseRef; +/** + * @see llvm::OperandBundleDef + */ +typedef struct LLVMOpaqueOperandBundle *LLVMOperandBundleRef; + /** * Used to represent an attributes. * diff --git a/src/llvm-c/lto.h b/src/llvm-c/lto.h index 5ceb02224..89f76c695 100644 --- a/src/llvm-c/lto.h +++ b/src/llvm-c/lto.h @@ -16,7 +16,7 @@ #ifndef LLVM_C_LTO_H #define LLVM_C_LTO_H -#include "llvm-c/ExternC.h" +#include "ExternC.h" #ifdef __cplusplus #include diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 1f7a39447..b2e485d01 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1239,9 +1239,9 @@ namespace lbAbiWasm { gb_internal LB_ABI_INFO(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; + ft->calling_convention = calling_convention; ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention, original_type); ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); - ft->calling_convention = calling_convention; return ft; } @@ -1378,14 +1378,14 @@ namespace lbAbiWasm { } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) { if (type_can_be_direct(return_type, ft->calling_convention)) { return lb_arg_type_direct(return_type); - } - - i64 sz = lb_sizeof(return_type); - switch (sz) { - case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr); - case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr); - case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); - case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); + } else if (ft->calling_convention != ProcCC_CDecl) { + i64 sz = lb_sizeof(return_type); + switch (sz) { + case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr); + case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr); + case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); + case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); + } } LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO(); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 04c4ce244..52661dfa7 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1321,6 +1321,24 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) { return 0; } +gb_internal GB_COMPARE_PROC(llvm_global_entity_cmp) { + Entity *x = *cast(Entity **)a; + Entity *y = *cast(Entity **)b; + if (x == y) { + return 0; + } + if (x->kind != y->kind) { + return cast(i32)(x->kind - y->kind); + } + + i32 cmp = 0; + cmp = token_pos_cmp(x->token.pos, y->token.pos); + if (!cmp) { + return cmp; + } + return cmp; +} + gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info, bool do_threading) { auto *min_dep_set = &info->minimum_dependency_set; @@ -1377,6 +1395,12 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker } } + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + array_sort(m->global_types_to_create, llvm_global_entity_cmp); + array_sort(m->global_procedures_to_create, llvm_global_entity_cmp); + } + if (do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; @@ -1462,10 +1486,6 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { lb_populate_function_pass_manager(m, m->function_pass_managers[lbFunctionPassManager_default], false, build_context.optimization_level); lb_populate_function_pass_manager(m, m->function_pass_managers[lbFunctionPassManager_default_without_memcpy], true, build_context.optimization_level); lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_none], -1); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_minimal], 0); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_size], 1); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_speed], 2); - lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_aggressive], 3); for (i32 i = 0; i < lbFunctionPassManager_COUNT; i++) { LLVMFinalizeFunctionPassManager(m->function_pass_managers[i]); @@ -1489,15 +1509,12 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { if (p->entity && p->entity->kind == Entity_Procedure) { switch (p->entity->Procedure.optimization_mode) { case ProcedureOptimizationMode_None: - case ProcedureOptimizationMode_Minimal: - pass_manager_kind = lbFunctionPassManager_minimal; + pass_manager_kind = lbFunctionPassManager_none; + GB_ASSERT(lb_proc_has_attribute(p->module, p->value, "optnone")); + GB_ASSERT(lb_proc_has_attribute(p->module, p->value, "noinline")); break; - case ProcedureOptimizationMode_Size: - pass_manager_kind = lbFunctionPassManager_size; - lb_add_attribute_to_proc(p->module, p->value, "optsize"); - break; - case ProcedureOptimizationMode_Speed: - pass_manager_kind = lbFunctionPassManager_speed; + case ProcedureOptimizationMode_FavorSize: + GB_ASSERT(lb_proc_has_attribute(p->module, p->value, "optsize")); break; } } @@ -2532,20 +2549,37 @@ gb_internal String lb_filepath_ll_for_module(lbModule *m) { return path; } + gb_internal String lb_filepath_obj_for_module(lbModule *m) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); + String basename = build_context.build_paths[BuildPath_Output].basename; + String name = build_context.build_paths[BuildPath_Output].name; + + bool use_temporary_directory = false; + if (USE_SEPARATE_MODULES && build_context.build_mode == BuildMode_Executable) { + // NOTE(bill): use a temporary directory + String dir = temporary_directory(permanent_allocator()); + if (dir.len != 0) { + basename = dir; + use_temporary_directory = true; + } + } + + gbString path = gb_string_make_length(heap_allocator(), basename.text, basename.len); + path = gb_string_appendc(path, "/"); + path = gb_string_append_length(path, name.text, name.len); if (m->file) { char buf[32] = {}; isize n = gb_snprintf(buf, gb_size_of(buf), "-%u", m->file->id); String suffix = make_string((u8 *)buf, n-1); - path = concatenate_strings(permanent_allocator(), path, suffix); + path = gb_string_append_length(path, suffix.text, suffix.len); } else if (m->pkg) { - path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); + path = gb_string_appendc(path, "-"); + path = gb_string_append_length(path, m->pkg->name.text, m->pkg->name.len); + } + + if (use_temporary_directory) { + path = gb_string_append_fmt(path, "-%p", m); } String ext = {}; @@ -2583,7 +2617,10 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { } } - return concatenate_strings(permanent_allocator(), path, ext); + path = gb_string_append_length(path, ext.text, ext.len); + + return make_string(cast(u8 *)path, gb_string_length(path)); + } @@ -2642,7 +2679,6 @@ gb_internal bool lb_llvm_object_generation(lbGenerator *gen, bool do_threading) String filepath_ll = lb_filepath_ll_for_module(m); String filepath_obj = lb_filepath_obj_for_module(m); - // gb_printf_err("%.*s\n", LIT(filepath_obj)); array_add(&gen->output_object_paths, filepath_obj); array_add(&gen->output_temp_paths, filepath_ll); @@ -3217,8 +3253,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass); LLVMSetExternallyInitialized(g.value, true); lb_add_foreign_library_path(m, e->Variable.foreign_library); - - lb_set_wasm_import_attributes(g.value, e, name); } else { LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type))); } @@ -3396,7 +3430,20 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Add Foreign Library Paths"); lb_add_foreign_library_paths(gen); - TIME_SECTION("LLVM Object Generation"); + + //////////////////////////////////////////// + for (auto const &entry: gen->modules) { + lbModule *m = entry.value; + if (!lb_is_module_empty(m)) { + gen->used_module_count += 1; + } + } + + gbString label_object_generation = gb_string_make(heap_allocator(), "LLVM Object Generation"); + if (gen->used_module_count > 1) { + label_object_generation = gb_string_append_fmt(label_object_generation, " (%td used modules)", gen->used_module_count); + } + TIME_SECTION_WITH_LEN(label_object_generation, gb_string_length(label_object_generation)); if (build_context.ignore_llvm_build) { gb_printf_err("LLVM object generation has been ignored!\n"); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 447e93d42..005358734 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -134,11 +134,6 @@ enum lbFunctionPassManagerKind { lbFunctionPassManager_default, lbFunctionPassManager_default_without_memcpy, lbFunctionPassManager_none, - lbFunctionPassManager_minimal, - lbFunctionPassManager_size, - lbFunctionPassManager_speed, - lbFunctionPassManager_aggressive, - lbFunctionPassManager_COUNT }; @@ -218,6 +213,8 @@ struct lbGenerator : LinkerData { std::atomic global_array_index; std::atomic global_generated_index; + isize used_module_count; + lbProcedure *startup_runtime; lbProcedure *cleanup_runtime; lbProcedure *objc_names; diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 3ed8d72d9..9cc0552de 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -94,9 +94,6 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { LLVMTypeKind kind = LLVMGetTypeKind(dst); switch (kind) { case LLVMPointerTypeKind: - if (LB_USE_NEW_PASS_SYSTEM) { - return val; - } return LLVMConstPointerCast(val, dst); case LLVMStructTypeKind: // GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst)); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index a23f8cfbe..bcacc0537 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1127,12 +1127,21 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV switch (op) { case Token_Add: - real = lb_emit_arith(p, Token_Add, a, c, ft); - imag = lb_emit_arith(p, Token_Add, b, d, ft); - break; case Token_Sub: - real = lb_emit_arith(p, Token_Sub, a, c, ft); - imag = lb_emit_arith(p, Token_Sub, b, d, ft); + if (type_size_of(ft) == 2) { + a = lb_emit_conv(p, a, t_f32); + b = lb_emit_conv(p, b, t_f32); + c = lb_emit_conv(p, c, t_f32); + d = lb_emit_conv(p, d, t_f32); + real = lb_emit_arith(p, op, a, c, t_f32); + imag = lb_emit_arith(p, op, b, d, t_f32); + + real = lb_emit_conv(p, real, ft); + imag = lb_emit_conv(p, imag, ft); + } else { + real = lb_emit_arith(p, op, a, c, ft); + imag = lb_emit_arith(p, op, b, d, ft); + } break; case Token_Mul: { lbValue x = lb_emit_arith(p, Token_Mul, a, c, ft); @@ -1156,6 +1165,11 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV Type *ft = base_complex_elem_type(type); if (op == Token_Add || op == Token_Sub) { + Type *immediate_type = ft; + if (type_size_of(ft) == 2) { + immediate_type = t_f32; + } + lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later lbValue x0 = lb_emit_struct_ev(p, lhs, 0); lbValue x1 = lb_emit_struct_ev(p, lhs, 1); @@ -1167,15 +1181,39 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV lbValue y2 = lb_emit_struct_ev(p, rhs, 2); lbValue y3 = lb_emit_struct_ev(p, rhs, 3); - lbValue z0 = lb_emit_arith(p, op, x0, y0, ft); - lbValue z1 = lb_emit_arith(p, op, x1, y1, ft); - lbValue z2 = lb_emit_arith(p, op, x2, y2, ft); - lbValue z3 = lb_emit_arith(p, op, x3, y3, ft); + if (immediate_type != ft) { + x0 = lb_emit_conv(p, x0, immediate_type); + x1 = lb_emit_conv(p, x1, immediate_type); + x2 = lb_emit_conv(p, x2, immediate_type); + x3 = lb_emit_conv(p, x3, immediate_type); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), z0); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), z1); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 2), z2); - lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 3), z3); + y0 = lb_emit_conv(p, y0, immediate_type); + y1 = lb_emit_conv(p, y1, immediate_type); + y2 = lb_emit_conv(p, y2, immediate_type); + y3 = lb_emit_conv(p, y3, immediate_type); + } + + lbValue z0 = lb_emit_arith(p, op, x0, y0, immediate_type); + lbValue z1 = lb_emit_arith(p, op, x1, y1, immediate_type); + lbValue z2 = lb_emit_arith(p, op, x2, y2, immediate_type); + lbValue z3 = lb_emit_arith(p, op, x3, y3, immediate_type); + + lbValue d0 = lb_emit_struct_ep(p, res.addr, 0); + lbValue d1 = lb_emit_struct_ep(p, res.addr, 1); + lbValue d2 = lb_emit_struct_ep(p, res.addr, 2); + lbValue d3 = lb_emit_struct_ep(p, res.addr, 3); + + if (immediate_type != ft) { + d0 = lb_emit_conv(p, d0, ft); + d1 = lb_emit_conv(p, d1, ft); + d2 = lb_emit_conv(p, d2, ft); + d3 = lb_emit_conv(p, d3, ft); + } + + lb_emit_store(p, d0, z0); + lb_emit_store(p, d1, z1); + lb_emit_store(p, d2, z2); + lb_emit_store(p, d3, z3); return lb_addr_load(p, res); } else if (op == Token_Mul) { @@ -2044,13 +2082,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } if (is_type_union(dst)) { - for (Type *vt : dst->Union.variants) { - if (are_types_identical(vt, src_type)) { - lbAddr parent = lb_add_local_generated(p, t, true); - lb_emit_store_union_variant(p, parent.addr, value, vt); - return lb_addr_load(p, parent); - } - } if (dst->Union.variants.count == 1) { Type *vt = dst->Union.variants[0]; if (internal_check_is_assignable_to(src_type, vt)) { @@ -2060,6 +2091,50 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return lb_addr_load(p, parent); } } + for (Type *vt : dst->Union.variants) { + if (are_types_identical(src_type, vt)) { + lbAddr parent = lb_add_local_generated(p, t, true); + lb_emit_store_union_variant(p, parent.addr, value, vt); + return lb_addr_load(p, parent); + } + } + ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, dst->Union.variants.count); + isize valid_count = 0; + isize first_success_index = -1; + for_array(i, dst->Union.variants) { + Type *vt = dst->Union.variants[i]; + i64 score = 0; + if (internal_check_is_assignable_to(src_type, vt)) { + valids[valid_count].index = i; + valids[valid_count].score = score; + valid_count += 1; + if (first_success_index < 0) { + first_success_index = i; + } + } + } + if (valid_count > 1) { + gb_sort_array(valids, valid_count, valid_index_and_score_cmp); + i64 best_score = valids[0].score; + for (isize i = 1; i < valid_count; i++) { + auto v = valids[i]; + if (best_score > v.score) { + valid_count = i; + break; + } + best_score = v.score; + } + first_success_index = valids[0].index; + } + + if (valid_count == 1) { + Type *vt = dst->Union.variants[first_success_index]; + value = lb_emit_conv(p, value, vt); + lbAddr parent = lb_add_local_generated(p, t, true); + lb_emit_store_union_variant(p, parent.addr, value, vt); + return lb_addr_load(p, parent); + } + } // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's @@ -3283,13 +3358,8 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { Type *type = type_of_expr(expr); GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); - if (tv.value.kind != ExactValue_Invalid) { - // NOTE(bill): The commented out code below is just for debug purposes only - // if (is_type_untyped(type)) { - // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr); - // GB_PANIC("%s\n", type_to_string(tv.type)); - // } + if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Short on constant values return lb_const_value(p->module, type, tv.value); } else if (tv.mode == Addressing_Type) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 03d0f8b32..f5595b70e 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -118,15 +118,17 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { map_init(&gen->anonymous_proc_lits, 1024); if (USE_SEPARATE_MODULES) { + bool module_per_file = build_context.module_per_file && build_context.optimization_level <= 0; for (auto const &entry : gen->info->packages) { AstPackage *pkg = entry.value; - #if 1 auto m = gb_alloc_item(permanent_allocator(), lbModule); m->pkg = pkg; m->gen = gen; map_set(&gen->modules, cast(void *)pkg, m); lb_init_module(m, c); - #else + if (!module_per_file) { + continue; + } // NOTE(bill): Probably per file is not a good idea, so leave this for later for (AstFile *file : pkg->files) { auto m = gb_alloc_item(permanent_allocator(), lbModule); @@ -136,7 +138,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { map_set(&gen->modules, cast(void *)file, m); lb_init_module(m, c); } - #endif } } @@ -144,7 +145,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { map_set(&gen->modules, cast(void *)1, &gen->default_module); lb_init_module(&gen->default_module, c); - for (auto const &entry : gen->modules) { lbModule *m = entry.value; LLVMContextRef ctx = LLVMGetModuleContext(m->mod); @@ -1011,7 +1011,7 @@ gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { return; } - Type *a = type_deref(ptr.type); + Type *a = type_deref(ptr.type, true); if (LLVMIsNull(value.value)) { LLVMTypeRef src_t = llvm_addr_type(p->module, ptr); if (is_type_proc(a)) { @@ -1109,9 +1109,13 @@ gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue value) { Type *t = type_deref(value.type); LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, ""); - u64 is_packed = lb_get_metadata_custom_u64(p->module, value.value, ODIN_METADATA_IS_PACKED); - if (is_packed != 0) { - LLVMSetAlignment(v, 1); + // If it is not an instruction it isn't a GEP, so we don't need to track alignment in the metadata, + // which is not possible anyway (only LLVM instructions can have metadata). + if (LLVMIsAInstruction(value.value)) { + u64 is_packed = lb_get_metadata_custom_u64(p->module, value.value, ODIN_METADATA_IS_PACKED); + if (is_packed != 0) { + LLVMSetAlignment(v, 1); + } } return lbValue{v, t}; @@ -1159,11 +1163,12 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { r = lb_addr_load(p, dst); r.value = LLVMBuildShl(p->builder, r.value, shift_amount, ""); } else if ((addr.bitfield.bit_offset % 8) == 0) { + do_mask = 8*dst_byte_size != addr.bitfield.bit_size; + lbValue copy_size = byte_size; lbValue src_offset = lb_emit_conv(p, src, t_u8_ptr); src_offset = lb_emit_ptr_offset(p, src_offset, byte_offset); - if (addr.bitfield.bit_offset + dst_byte_size <= total_bitfield_bit_size) { - do_mask = true; + if (addr.bitfield.bit_offset + 8*dst_byte_size <= total_bitfield_bit_size) { copy_size = lb_const_int(p->module, t_uintptr, dst_byte_size); } lb_mem_copy_non_overlapping(p, dst.addr, src_offset, copy_size, false); @@ -2519,6 +2524,12 @@ gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, cha gb_internal void lb_add_attribute_to_proc(lbModule *m, LLVMValueRef proc_value, char const *name, u64 value=0) { LLVMAddAttributeAtIndex(proc_value, LLVMAttributeIndex_FunctionIndex, lb_create_enum_attribute(m->ctx, name, value)); } + +gb_internal bool lb_proc_has_attribute(lbModule *m, LLVMValueRef proc_value, char const *name) { + LLVMAttributeRef ref = LLVMGetEnumAttributeAtIndex(proc_value, LLVMAttributeIndex_FunctionIndex, LLVMGetEnumAttributeKindForName(name, gb_strlen(name))); + return ref != nullptr; +} + gb_internal void lb_add_attribute_to_proc_with_string(lbModule *m, LLVMValueRef proc_value, String const &name, String const &value) { LLVMAttributeRef attr = lb_create_string_attribute(m->ctx, name, value); LLVMAddAttributeAtIndex(proc_value, LLVMAttributeIndex_FunctionIndex, attr); diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 6a6d2f802..e6ccc9a57 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -398,16 +398,20 @@ gb_internal LLVMValueRef lb_run_instrumentation_pass_insert_call(lbProcedure *p, LLVMValueRef args[3] = {}; args[0] = p->value; - LLVMValueRef returnaddress_args[1] = {}; + if (is_arch_wasm()) { + args[1] = LLVMConstPointerNull(lb_type(m, t_rawptr)); + } else { + LLVMValueRef returnaddress_args[1] = {}; - returnaddress_args[0] = LLVMConstInt(LLVMInt32TypeInContext(m->ctx), 0, false); + returnaddress_args[0] = LLVMConstInt(LLVMInt32TypeInContext(m->ctx), 0, false); - char const *instrinsic_name = "llvm.returnaddress"; - unsigned id = LLVMLookupIntrinsicID(instrinsic_name, gb_strlen(instrinsic_name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", instrinsic_name); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, nullptr, 0); - LLVMTypeRef call_type = LLVMIntrinsicGetType(m->ctx, id, nullptr, 0); - args[1] = LLVMBuildCall2(dummy_builder, call_type, ip, returnaddress_args, gb_count_of(returnaddress_args), ""); + char const *instrinsic_name = "llvm.returnaddress"; + unsigned id = LLVMLookupIntrinsicID(instrinsic_name, gb_strlen(instrinsic_name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s", instrinsic_name); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, nullptr, 0); + LLVMTypeRef call_type = LLVMIntrinsicGetType(m->ctx, id, nullptr, 0); + args[1] = LLVMBuildCall2(dummy_builder, call_type, ip, returnaddress_args, gb_count_of(returnaddress_args), ""); + } Token name = {}; if (p->entity) { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 87f75fb1d..610c34de2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -163,16 +163,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i switch (entity->Procedure.optimization_mode) { case ProcedureOptimizationMode_None: - break; - case ProcedureOptimizationMode_Minimal: lb_add_attribute_to_proc(m, p->value, "optnone"); lb_add_attribute_to_proc(m, p->value, "noinline"); break; - case ProcedureOptimizationMode_Size: - lb_add_attribute_to_proc(m, p->value, "optsize"); - break; - case ProcedureOptimizationMode_Speed: - // TODO(bill): handle this correctly + case ProcedureOptimizationMode_FavorSize: lb_add_attribute_to_proc(m, p->value, "optsize"); break; } @@ -233,7 +227,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i if (p->is_foreign) { - lb_set_wasm_import_attributes(p->value, entity, p->name); + lb_set_wasm_procedure_import_attributes(p->value, entity, p->name); } @@ -2747,26 +2741,10 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu { GB_ASSERT(arg_count <= 7); - // FreeBSD additionally clobbers r8, r9, r10, but they - // can also be used to pass in arguments, so this needs - // to be handled in two parts. - bool clobber_arg_regs[7] = { - false, false, false, false, false, false, false - }; - if (build_context.metrics.os == TargetOs_freebsd) { - clobber_arg_regs[4] = true; // r10 - clobber_arg_regs[5] = true; // r8 - clobber_arg_regs[6] = true; // r9 - } - char asm_string[] = "syscall"; gbString constraints = gb_string_make(heap_allocator(), "={rax}"); for (unsigned i = 0; i < arg_count; i++) { - if (!clobber_arg_regs[i]) { - constraints = gb_string_appendc(constraints, ",{"); - } else { - constraints = gb_string_appendc(constraints, ",+{"); - } + constraints = gb_string_appendc(constraints, ",{"); static char const *regs[] = { "rax", "rdi", @@ -2790,36 +2768,9 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu // Some but not all system calls will additionally // clobber memory. // - // As a fix for CVE-2019-5595, FreeBSD started - // clobbering R8, R9, and R10, instead of restoring - // them. Additionally unlike Linux, instead of - // returning negative errno, positive errno is - // returned and CF is set. - // // TODO: // * Figure out what Darwin does. - // * Add some extra handling to propagate CF back - // up to the caller on FreeBSD systems so that - // the caller knows that the return value is - // positive errno. constraints = gb_string_appendc(constraints, ",~{rcx},~{r11},~{memory}"); - if (build_context.metrics.os == TargetOs_freebsd) { - // Second half of dealing with FreeBSD's system - // call semantics. Explicitly clobber the registers - // that were not used to pass in arguments, and - // then clobber RFLAGS. - if (arg_count < 5) { - constraints = gb_string_appendc(constraints, ",~{r10}"); - } - if (arg_count < 6) { - constraints = gb_string_appendc(constraints, ",~{r8}"); - } - if (arg_count < 7) { - constraints = gb_string_appendc(constraints, ",~{r9}"); - } - constraints = gb_string_appendc(constraints, ",~{cc}"); - } - inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; @@ -2927,6 +2878,139 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu res.type = t_uintptr; return res; } + case BuiltinProc_syscall_bsd: + { + // This is a BSD-style syscall where errors are indicated by a high + // Carry Flag and a positive return value, allowing the kernel to + // return any value that fits into a machine word. + // + // This is unlike Linux, where errors are indicated by a negative + // return value, limiting what can be expressed in one result. + unsigned arg_count = cast(unsigned)ce->args.count; + LLVMValueRef *args = gb_alloc_array(permanent_allocator(), LLVMValueRef, arg_count); + for_array(i, ce->args) { + lbValue arg = lb_build_expr(p, ce->args[i]); + arg = lb_emit_conv(p, arg, t_uintptr); + args[i] = arg.value; + } + + LLVMTypeRef llvm_uintptr = lb_type(p->module, t_uintptr); + LLVMTypeRef *llvm_arg_types = gb_alloc_array(permanent_allocator(), LLVMTypeRef, arg_count); + for (unsigned i = 0; i < arg_count; i++) { + llvm_arg_types[i] = llvm_uintptr; + } + + LLVMTypeRef *results = gb_alloc_array(permanent_allocator(), LLVMTypeRef, 2); + results[0] = lb_type(p->module, t_uintptr); + results[1] = lb_type(p->module, t_bool); + LLVMTypeRef llvm_results = LLVMStructTypeInContext(p->module->ctx, results, 2, false); + + LLVMTypeRef func_type = LLVMFunctionType(llvm_results, llvm_arg_types, arg_count, false); + + LLVMValueRef inline_asm = nullptr; + + switch (build_context.metrics.arch) { + case TargetArch_amd64: + { + GB_ASSERT(arg_count <= 7); + + char asm_string[] = "syscall; setnb %cl"; + + // Using CL as an output; RCX doesn't need to get clobbered later. + gbString constraints = gb_string_make(heap_allocator(), "={rax},={cl}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "rax", + "rdi", + "rsi", + "rdx", + "r10", + "r8", + "r9", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + // NOTE(Feoramund): If you're experiencing instability + // regarding syscalls during optimized builds, it is + // possible that the ABI has changed for your platform, + // or I've missed a register clobber. + // + // Documentation on this topic is sparse, but I was able to + // determine what registers were being clobbered by adding + // dummy values to them, setting a breakpoint after the + // syscall, and checking the state of the registers afterwards. + // + // Be advised that manually stepping through a debugger may + // cause the kernel to not return via sysret, which will + // preserve register state that normally would've been + // otherwise clobbered. + // + // It is also possible that some syscalls clobber different registers. + + if (build_context.metrics.os == TargetOs_freebsd) { + // As a fix for CVE-2019-5595, FreeBSD started + // clobbering R8, R9, and R10, instead of restoring + // them. + // + // More info here: + // + // https://www.freebsd.org/security/advisories/FreeBSD-SA-19:01.syscall.asc + // https://github.com/freebsd/freebsd-src/blob/098dbd7ff7f3da9dda03802cdb2d8755f816eada/sys/amd64/amd64/exception.S#L605 + // https://stackoverflow.com/q/66878250 + constraints = gb_string_appendc(constraints, ",~{r8},~{r9},~{r10}"); + } + + // Both FreeBSD and NetBSD might clobber RDX. + // + // For NetBSD, it was clobbered during a call to sysctl. + // + // For FreeBSD, it's listed as "return value 2" in their + // AMD64 assembly, so there's no guarantee that it will persist. + constraints = gb_string_appendc(constraints, ",~{rdx},~{r11},~{cc},~{memory}"); + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } + break; + case TargetArch_arm64: + { + GB_ASSERT(arg_count <= 7); + + char asm_string[] = "svc #0; cset x8, cc"; + gbString constraints = gb_string_make(heap_allocator(), "={x0},={x8}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "x8", + "x0", + "x1", + "x2", + "x3", + "x4", + "x5", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + // FreeBSD clobbered x1 on a call to sysctl. + constraints = gb_string_appendc(constraints, ",~{x1},~{cc},~{memory}"); + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } + break; + default: + GB_PANIC("Unsupported platform"); + } + + lbValue res = {}; + res.value = LLVMBuildCall2(p->builder, func_type, inline_asm, args, arg_count, ""); + res.type = make_optional_ok_type(t_uintptr, true); + + return res; + } case BuiltinProc_objc_send: return lb_handle_objc_send(p, expr); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9f28e45e0..70b695627 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1579,7 +1579,8 @@ gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValu lb_addr_store(p, x, value); } else { if (!is_default_case) { - GB_ASSERT_MSG(are_types_identical(e->type, type_deref(value.type)), "%s %s", type_to_string(e->type), type_to_string(value.type)); + Type *clause_type = e->type; + GB_ASSERT_MSG(are_types_identical(type_deref(clause_type), type_deref(value.type)), "%s %s", type_to_string(clause_type), type_to_string(value.type)); } lb_add_entity(p->module, e, value); } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 94153e233..1165476be 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -2018,7 +2018,7 @@ gb_internal LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const } -gb_internal void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String import_name) { +gb_internal void lb_set_wasm_procedure_import_attributes(LLVMValueRef value, Entity *entity, String import_name) { if (!is_arch_wasm()) { return; } @@ -2029,7 +2029,11 @@ gb_internal void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entit GB_ASSERT(foreign_library->LibraryName.paths.count == 1); module_name = foreign_library->LibraryName.paths[0]; - + + if (string_ends_with(module_name, str_lit(".o"))) { + return; + } + if (string_starts_with(import_name, module_name)) { import_name = substring(import_name, module_name.len+WASM_MODULE_NAME_SEPARATOR.len, import_name.len); } diff --git a/src/main.cpp b/src/main.cpp index 70def5802..e6a0aecf0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,6 +61,7 @@ gb_global Timings global_timings = {0}; #include "llvm-c/Types.h" #else #include +#include #endif #include "parser.hpp" @@ -70,6 +71,8 @@ gb_global Timings global_timings = {0}; #include "checker.cpp" #include "docs.cpp" +#include "cached.cpp" + #include "linker.cpp" #if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND) @@ -94,16 +97,38 @@ gb_global Timings global_timings = {0}; #include "bug_report.cpp" // NOTE(bill): 'name' is used in debugging and profiling modes -gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { +gb_internal i32 system_exec_command_line_app_internal(bool exit_on_err, char const *name, char const *fmt, va_list va) { isize const cmd_cap = 64<<20; // 64 MiB should be more than enough char *cmd_line = gb_alloc_array(gb_heap_allocator(), char, cmd_cap); isize cmd_len = 0; - va_list va; i32 exit_code = 0; - va_start(va, fmt); cmd_len = gb_snprintf_va(cmd_line, cmd_cap-1, fmt, va); - va_end(va); + + if (build_context.print_linker_flags) { + // NOTE(bill): remove the first argument (the executable) from the executable list + // and then print it for the "linker flags" + while (*cmd_line && gb_char_is_space(*cmd_line)) { + cmd_line++; + } + if (*cmd_line == '\"') for (cmd_line++; *cmd_line; cmd_line++) { + if (*cmd_line == '\\') { + cmd_line++; + if (*cmd_line == '\"') { + cmd_line++; + } + } else if (*cmd_line == '\"') { + cmd_line++; + break; + } + } + while (*cmd_line && gb_char_is_space(*cmd_line)) { + cmd_line++; + } + + fprintf(stdout, "%s\n", cmd_line); + return exit_code; + } #if defined(GB_SYSTEM_WINDOWS) STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)}; @@ -143,18 +168,36 @@ gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, gb_printf_err("%s\n\n", cmd_line); } exit_code = system(cmd_line); + if (exit_on_err && WIFSIGNALED(exit_code)) { + raise(WTERMSIG(exit_code)); + } if (WIFEXITED(exit_code)) { exit_code = WEXITSTATUS(exit_code); } #endif - if (exit_code) { + if (exit_on_err && exit_code) { exit(exit_code); } return exit_code; } +gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + i32 exit_code = system_exec_command_line_app_internal(/* exit_on_err= */ false, name, fmt, va); + va_end(va); + return exit_code; +} + +gb_internal void system_must_exec_command_line_app(char const *name, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + system_exec_command_line_app_internal(/* exit_on_err= */ true, name, fmt, va); + va_end(va); +} + #if defined(GB_SYSTEM_WINDOWS) #define popen _popen #define pclose _pclose @@ -288,6 +331,9 @@ enum BuildFlagKind { BuildFlag_NoThreadedChecker, BuildFlag_ShowDebugMessages, + BuildFlag_ShowDefineables, + BuildFlag_ExportDefineables, + BuildFlag_Vet, BuildFlag_VetShadowing, BuildFlag_VetUnused, @@ -297,7 +343,10 @@ enum BuildFlagKind { BuildFlag_VetUsingParam, BuildFlag_VetStyle, BuildFlag_VetSemicolon, + BuildFlag_VetCast, + BuildFlag_VetTabs, + BuildFlag_CustomAttribute, BuildFlag_IgnoreUnknownAttributes, BuildFlag_ExtraLinkerFlags, BuildFlag_ExtraAssemblerFlags, @@ -337,9 +386,14 @@ enum BuildFlagKind { BuildFlag_MinLinkLibs, + BuildFlag_PrintLinkerFlags, + // internal use only BuildFlag_InternalIgnoreLazy, BuildFlag_InternalIgnoreLLVMBuild, + BuildFlag_InternalIgnorePanic, + BuildFlag_InternalModulePerFile, + BuildFlag_InternalCached, BuildFlag_Tilde, @@ -483,6 +537,9 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_ShowDefineables, str_lit("show-defineables"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ExportDefineables, str_lit("export-defineables"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnusedVariables, str_lit("vet-unused-variables"), BuildFlagParam_None, Command__does_check); @@ -492,7 +549,10 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetStyle, str_lit("vet-style"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetCast, str_lit("vet-cast"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetTabs, str_lit("vet-tabs"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_CustomAttribute, str_lit("custom-attribute"), BuildFlagParam_String, Command__does_check, true); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); @@ -531,8 +591,13 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_MinLinkLibs, str_lit("min-link-libs"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_PrintLinkerFlags, str_lit("print-linker-flags"), BuildFlagParam_None, Command_build); + add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalIgnorePanic, str_lit("internal-ignore-panic"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalModulePerFile, str_lit("internal-module-per-file"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); @@ -798,8 +863,7 @@ gb_internal bool parse_build_flags(Array args) { gb_printf_err("\tjson\n"); bad_flags = true; } - - break; + break; } case BuildFlag_ExportDependenciesFile: { GB_ASSERT(value.kind == ExactValue_String); @@ -814,6 +878,24 @@ gb_internal bool parse_build_flags(Array args) { break; } + case BuildFlag_ShowDefineables: { + GB_ASSERT(value.kind == ExactValue_Invalid); + build_context.show_defineables = true; + break; + } + case BuildFlag_ExportDefineables: { + GB_ASSERT(value.kind == ExactValue_String); + + String export_path = string_trim_whitespace(value.value_string); + if (is_build_flag_path_valid(export_path)) { + build_context.export_defineables_file = path_to_full_path(heap_allocator(), export_path); + } else { + gb_printf_err("Invalid -export-defineables path, got %.*s\n", LIT(export_path)); + bad_flags = true; + } + + break; + } case BuildFlag_ShowSystemCalls: { GB_ASSERT(value.kind == ExactValue_Invalid); build_context.show_system_calls = true; @@ -1058,6 +1140,9 @@ gb_internal bool parse_build_flags(Array args) { build_context.build_mode = BuildMode_Assembly; } else if (str == "llvm" || str == "llvm-ir") { build_context.build_mode = BuildMode_LLVM_IR; + } else if (str == "test") { + build_context.build_mode = BuildMode_Executable; + build_context.command_kind = Command_test; } else { gb_printf_err("Unknown build mode '%.*s'\n", LIT(str)); gb_printf_err("Valid build modes:\n"); @@ -1067,6 +1152,7 @@ gb_internal bool parse_build_flags(Array args) { gb_printf_err("\texe\n"); gb_printf_err("\tasm, assembly, assembler\n"); gb_printf_err("\tllvm, llvm-ir\n"); + gb_printf_err("\ttest\n"); bad_flags = true; break; } @@ -1122,6 +1208,31 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; + case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; + case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; + + case BuildFlag_CustomAttribute: + { + GB_ASSERT(value.kind == ExactValue_String); + String val = value.value_string; + String_Iterator it = {val, 0}; + for (;;) { + String attr = string_split_iterator(&it, ','); + if (attr.len == 0) { + break; + } + + attr = string_trim_whitespace(attr); + if (!string_is_valid_identifier(attr)) { + gb_printf_err("-custom-attribute '%.*s' must be a valid identifier\n", LIT(attr)); + bad_flags = true; + continue; + } + + string_set_add(&build_context.custom_attributes, attr); + } + } + break; case BuildFlag_IgnoreUnknownAttributes: build_context.ignore_unknown_attributes = true; @@ -1290,12 +1401,27 @@ gb_internal bool parse_build_flags(Array args) { build_context.min_link_libs = true; break; + case BuildFlag_PrintLinkerFlags: + build_context.print_linker_flags = true; + break; + case BuildFlag_InternalIgnoreLazy: build_context.ignore_lazy = true; break; case BuildFlag_InternalIgnoreLLVMBuild: build_context.ignore_llvm_build = true; break; + case BuildFlag_InternalIgnorePanic: + build_context.ignore_panic = true; + break; + case BuildFlag_InternalModulePerFile: + build_context.module_per_file = true; + break; + case BuildFlag_InternalCached: + build_context.cached = true; + build_context.use_separate_modules = true; + break; + case BuildFlag_Tilde: build_context.tilde_backend = true; break; @@ -1326,8 +1452,9 @@ gb_internal bool parse_build_flags(Array args) { String path = value.value_string; path = string_trim_whitespace(path); if (is_build_flag_path_valid(path)) { - if(!string_ends_with(path, str_lit(".rc"))) { - gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path)); + bool is_resource = string_ends_with(path, str_lit(".rc")) || string_ends_with(path, str_lit(".res")); + if(!is_resource) { + gb_printf_err("Invalid -resource path %.*s, missing .rc or .res file\n", LIT(path)); bad_flags = true; break; } else if (!gb_file_exists((const char *)path.text)) { @@ -1455,6 +1582,16 @@ gb_internal bool parse_build_flags(Array args) { gb_printf_err("`-export-timings:` requires `-show-timings` or `-show-more-timings` to be present\n"); bad_flags = true; } + + + if (build_context.export_dependencies_format != DependenciesExportUnspecified && build_context.print_linker_flags) { + gb_printf_err("-export-dependencies cannot be used with -print-linker-flags\n"); + bad_flags = true; + } else if (build_context.show_timings && build_context.print_linker_flags) { + gb_printf_err("-show-timings/-show-more-timings cannot be used with -print-linker-flags\n"); + bad_flags = true; + } + return !bad_flags; } @@ -1553,6 +1690,115 @@ gb_internal void timings_export_all(Timings *t, Checker *c, bool timings_are_fin gb_printf("Done.\n"); } +gb_internal void check_defines(BuildContext *bc, Checker *c) { + for (auto const &entry : bc->defined_values) { + String name = make_string_c(entry.key); + ExactValue value = entry.value; + GB_ASSERT(value.kind != ExactValue_Invalid); + + bool found = false; + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + if (def->name == name) { + found = true; + break; + } + } + + if (!found) { + ERROR_BLOCK(); + warning(nullptr, "given -define:%.*s is unused in the project", LIT(name)); + error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n"); + } + } +} + +gb_internal void temp_alloc_defineable_strings(Checker *c) { + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + def->default_value_str = make_string_c(write_exact_value_to_string(gb_string_make(temporary_allocator(), ""), def->default_value)); + def->pos_str = make_string_c(token_pos_to_string(def->pos)); + } +} + +gb_internal GB_COMPARE_PROC(defineables_cmp) { + Defineable *x = (Defineable *)a; + Defineable *y = (Defineable *)b; + + int cmp = 0; + + String x_file = get_file_path_string(x->pos.file_id); + String y_file = get_file_path_string(y->pos.file_id); + cmp = string_compare(x_file, y_file); + if (cmp) { + return cmp; + } + + return i32_cmp(x->pos.offset, y->pos.offset); +} + +gb_internal void sort_defineables(Checker *c) { + gb_sort_array(c->info.defineables.data, c->info.defineables.count, defineables_cmp); +} + +gb_internal void export_defineables(Checker *c, String path) { + gbFile f = {}; + gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, (char *)path.text); + if (err != gbFileError_None) { + gb_printf_err("Failed to export defineables to: %.*s\n", LIT(path)); + gb_exit(1); + return; + } else { + gb_printf("Exporting defineables to '%.*s'...\n", LIT(path)); + } + defer (gb_file_close(&f)); + + gbString docs = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(docs)); + + gb_fprintf(&f, "Defineable,Default Value,Docs,Location\n"); + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + + gb_string_clear(docs); + if (def->docs) { + docs = gb_string_appendc(docs, "\""); + for (Token const &token : def->docs->list) { + for (isize i = 0; i < token.string.len; i++) { + u8 c = token.string.text[i]; + if (c == '"') { + docs = gb_string_appendc(docs, "\"\""); + } else { + docs = gb_string_append_length(docs, &c, 1); + } + } + } + docs = gb_string_appendc(docs, "\""); + } + + gb_fprintf(&f,"%.*s,%.*s,%s,%.*s\n", LIT(def->name), LIT(def->default_value_str), docs, LIT(def->pos_str)); + } +} + +gb_internal void show_defineables(Checker *c) { + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + if (has_ansi_terminal_colours()) { + gb_printf("\x1b[0;90m"); + } + printf("%.*s\n", LIT(def->pos_str)); + if (def->docs) { + for (Token const &token : def->docs->list) { + gb_printf("%.*s\n", LIT(token.string)); + } + } + if (has_ansi_terminal_colours()) { + gb_printf("\x1b[0m"); + } + gb_printf("%.*s :: %.*s\n\n", LIT(def->name), LIT(def->default_value_str)); + } +} + gb_internal void show_timings(Checker *c, Timings *t) { Parser *p = c->parser; isize lines = p->total_line_count; @@ -1681,7 +1927,13 @@ gb_internal void show_timings(Checker *c, Timings *t) { } } -gb_internal void export_dependencies(Parser *p) { +gb_internal GB_COMPARE_PROC(file_path_cmp) { + AstFile *x = *(AstFile **)a; + AstFile *y = *(AstFile **)b; + return string_compare(x->fullpath, y->fullpath); +} + +gb_internal void export_dependencies(Checker *c) { GB_ASSERT(build_context.export_dependencies_format != DependenciesExportUnspecified); if (build_context.export_dependencies_file.len <= 0) { @@ -1690,6 +1942,8 @@ gb_internal void export_dependencies(Parser *p) { return; } + Parser *p = c->parser; + gbFile f = {}; char * fileName = (char *)build_context.export_dependencies_file.text; gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, fileName); @@ -1700,6 +1954,26 @@ gb_internal void export_dependencies(Parser *p) { } defer (gb_file_close(&f)); + + auto files = array_make(heap_allocator()); + for (AstPackage *pkg : p->packages) { + for (AstFile *f : pkg->files) { + array_add(&files, f); + } + } + array_sort(files, file_path_cmp); + + + auto load_files = array_make(heap_allocator()); + for (auto const &entry : c->info.load_file_cache) { + auto *cache = entry.value; + if (!cache || !cache->exists) { + continue; + } + array_add(&load_files, cache); + } + array_sort(files, file_cache_sort_cmp); + if (build_context.export_dependencies_format == DependenciesExportMake) { String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); defer (gb_free(heap_allocator(), exe_name.text)); @@ -1708,26 +1982,25 @@ gb_internal void export_dependencies(Parser *p) { isize current_line_length = exe_name.len + 1; - for(AstPackage *pkg : p->packages) { - for(AstFile *file : pkg->files) { - /* Arbitrary line break value. Maybe make this better? */ - if (current_line_length >= 80-2) { - gb_file_write(&f, " \\\n ", 4); - current_line_length = 1; - } + for_array(i, files) { + AstFile *file = files[i]; + /* Arbitrary line break value. Maybe make this better? */ + if (current_line_length >= 80-2) { + gb_file_write(&f, " \\\n ", 4); + current_line_length = 1; + } - gb_file_write(&f, " ", 1); - current_line_length++; + gb_file_write(&f, " ", 1); + current_line_length++; - for (isize k = 0; k < file->fullpath.len; k++) { - char part = file->fullpath.text[k]; - if (part == ' ') { - gb_file_write(&f, "\\", 1); - current_line_length++; - } - gb_file_write(&f, &part, 1); + for (isize k = 0; k < file->fullpath.len; k++) { + char part = file->fullpath.text[k]; + if (part == ' ') { + gb_file_write(&f, "\\", 1); current_line_length++; } + gb_file_write(&f, &part, 1); + current_line_length++; } } @@ -1737,14 +2010,30 @@ gb_internal void export_dependencies(Parser *p) { gb_fprintf(&f, "\t\"source_files\": [\n"); - for(AstPackage *pkg : p->packages) { - for(AstFile *file : pkg->files) { - gb_fprintf(&f, "\t\t\"%.*s\",\n", LIT(file->fullpath)); + for_array(i, files) { + AstFile *file = files[i]; + gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath)); + if (i+1 == files.count) { + gb_fprintf(&f, ","); } + gb_fprintf(&f, "\n"); } gb_fprintf(&f, "\t],\n"); + gb_fprintf(&f, "\t\"load_files\": [\n"); + + for_array(i, load_files) { + LoadFileCache *cache = load_files[i]; + gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path)); + if (i+1 == load_files.count) { + gb_fprintf(&f, ","); + } + gb_fprintf(&f, "\n"); + } + + gb_fprintf(&f, "\t]\n"); + gb_fprintf(&f, "}\n"); } } @@ -1875,7 +2164,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { if (LB_USE_NEW_PASS_SYSTEM) { print_usage_line(3, "-o:aggressive"); } - print_usage_line(2, "The default is -o:minimal."); + print_usage_line(2, "The default is -o:none."); print_usage_line(0, ""); } @@ -1955,6 +2244,15 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Usage in code:"); print_usage_line(3, "#config(SPAM, default_value)"); print_usage_line(0, ""); + + print_usage_line(1, "-show-defineables"); + print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project."); + print_usage_line(0, ""); + + print_usage_line(1, "-export-defineables:"); + print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path."); + print_usage_line(2, "Example: -export-defineables:defineables.csv"); + print_usage_line(0, ""); } if (build) { @@ -1966,7 +2264,6 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library."); print_usage_line(3, "-build-mode:lib Builds as a statically linked library."); print_usage_line(3, "-build-mode:static Builds as a statically linked library."); - print_usage_line(3, "-build-mode:lib Builds as an static library."); print_usage_line(3, "-build-mode:obj Builds as an object file."); print_usage_line(3, "-build-mode:object Builds as an object file."); print_usage_line(3, "-build-mode:assembly Builds as an assembly file."); @@ -2072,9 +2369,26 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-vet-semicolon"); print_usage_line(2, "Errs on unneeded semicolons."); print_usage_line(0, ""); + + print_usage_line(1, "-vet-cast"); + print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`."); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-tabs"); + print_usage_line(2, "Errs when the use of tabs has not been used for indentation."); + print_usage_line(0, ""); } if (check) { + print_usage_line(1, "-custom-attribute:"); + print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown."); + print_usage_line(2, "This can be used with metaprogramming tools."); + print_usage_line(2, "Examples:"); + print_usage_line(3, "-custom-attribute:my_tag"); + print_usage_line(3, "-custom-attribute:my_tag,the_other_thing"); + print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing"); + print_usage_line(0, ""); + print_usage_line(1, "-ignore-unknown-attributes"); print_usage_line(2, "Ignores unknown attributes."); print_usage_line(2, "This can be used with metaprogramming tools."); @@ -2147,6 +2461,12 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); } + if (build) { + print_usage_line(1, "-print-linker-flags"); + print_usage_line(2, "Prints the all of the flags/arguments that will be passed to the linker."); + print_usage_line(0, ""); + } + if (check) { print_usage_line(1, "-disallow-do"); print_usage_line(2, "Disallows the 'do' keyword in the project."); @@ -2157,9 +2477,13 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-strict-style"); + print_usage_line(2, "This enforces parts of same style as the Odin compiler, prefer '-vet-style -vet-semicolon' if you do not want to match it exactly."); + print_usage_line(2, ""); print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons."); print_usage_line(2, "Errs on missing trailing commas followed by a newline."); print_usage_line(2, "Errs on deprecated syntax."); + print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS)."); + print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token."); print_usage_line(0, ""); print_usage_line(1, "-ignore-warnings"); @@ -2229,6 +2553,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "[Windows only]"); print_usage_line(2, "Defines the resource file for the executable."); print_usage_line(2, "Example: -resource:path/to/file.rc"); + print_usage_line(2, "or: -resource:path/to/file.res for a precompiled one."); print_usage_line(0, ""); print_usage_line(1, "-pdb-name:"); @@ -2734,6 +3059,8 @@ int main(int arg_count, char const **arg_ptr) { } else if (command == "root") { gb_printf("%.*s", LIT(odin_root_dir())); return 0; + } else if (command == "clear-cache") { + return try_clear_cache() ? 0 : 1; } else { String argv1 = {}; if (args.count > 1) { @@ -2934,7 +3261,8 @@ int main(int arg_count, char const **arg_ptr) { // TODO(jeroen): Remove the `init_filename` param. // Let's put that on `build_context.build_paths[0]` instead. if (parse_packages(parser, init_filename) != ParseFile_None) { - return 1; + GB_ASSERT_MSG(any_errors(), "parse_packages failed but no error was reported."); + // We depend on the next conditional block to return 1, after printing errors. } if (any_errors()) { @@ -2945,13 +3273,21 @@ int main(int arg_count, char const **arg_ptr) { print_all_errors(); } - MAIN_TIME_SECTION("type check"); checker->parser = parser; init_checker(checker); - defer (destroy_checker(checker)); + defer (destroy_checker(checker)); // this is here because of a `goto` + if (build_context.cached && parser->total_seen_load_directive_count.load() == 0) { + MAIN_TIME_SECTION("check cached build (pre-semantic check)"); + if (try_cached_build(checker, args)) { + goto end_of_code_gen; + } + } + + MAIN_TIME_SECTION("type check"); check_parsed_files(checker); + check_defines(&build_context, checker); if (any_errors()) { print_all_errors(); return 1; @@ -2960,6 +3296,19 @@ int main(int arg_count, char const **arg_ptr) { print_all_errors(); } + if (build_context.show_defineables || build_context.export_defineables_file != "") { + TEMPORARY_ALLOCATOR_GUARD(); + temp_alloc_defineable_strings(checker); + sort_defineables(checker); + + if (build_context.show_defineables) { + show_defineables(checker); + } + + if (build_context.export_defineables_file != "") { + export_defineables(checker, build_context.export_defineables_file); + } + } if (build_context.command_kind == Command_strip_semicolon) { return strip_semicolons(parser); @@ -2989,6 +3338,13 @@ int main(int arg_count, char const **arg_ptr) { return 0; } + if (build_context.cached) { + MAIN_TIME_SECTION("check cached build"); + if (try_cached_build(checker, args)) { + goto end_of_code_gen; + } + } + #if ALLOW_TILDE if (build_context.tilde_backend) { LinkerData linker_data = {}; @@ -3008,7 +3364,7 @@ int main(int arg_count, char const **arg_ptr) { } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { - export_dependencies(parser); + export_dependencies(checker); } return result; } @@ -3017,11 +3373,16 @@ int main(int arg_count, char const **arg_ptr) { } else #endif { - MAIN_TIME_SECTION("LLVM API Code Gen"); lbGenerator *gen = gb_alloc_item(permanent_allocator(), lbGenerator); if (!lb_init_generator(gen, checker)) { return 1; } + + gbString label_code_gen = gb_string_make(heap_allocator(), "LLVM API Code Gen"); + if (gen->modules.count > 1) { + label_code_gen = gb_string_append_fmt(label_code_gen, " ( %4td modules )", gen->modules.count); + } + MAIN_TIME_SECTION_WITH_LEN(label_code_gen, gb_string_length(label_code_gen)); if (lb_generate_code(gen)) { switch (build_context.build_mode) { case BuildMode_Executable: @@ -3034,7 +3395,7 @@ int main(int arg_count, char const **arg_ptr) { } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { - export_dependencies(parser); + export_dependencies(checker); } return result; } @@ -3045,19 +3406,27 @@ int main(int arg_count, char const **arg_ptr) { remove_temp_files(gen); } +end_of_code_gen:; + if (build_context.show_timings) { show_timings(checker, &global_timings); } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { - export_dependencies(parser); + export_dependencies(checker); + } + + + if (!build_context.build_cache_data.copy_already_done && + build_context.cached) { + try_copy_executable_to_cache(); } if (run_output) { String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); defer (gb_free(heap_allocator(), exe_name.text)); - return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); + system_must_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); } return 0; } diff --git a/src/parser.cpp b/src/parser.cpp index 0cd96f5b5..9ce3d563d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -35,22 +35,48 @@ gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) if (file == nullptr) { return nullptr; } - isize offset = pos.offset; - u8 *start = file->tokenizer.start; u8 *end = file->tokenizer.end; if (start == end) { return nullptr; } + + isize offset = pos.offset; + if (pos.line != 0 && offset == 0) { + for (i32 i = 1; i < pos.line; i++) { + while (start+offset < end) { + u8 c = start[offset++]; + if (c == '\n') { + break; + } + } + } + for (i32 i = 1; i < pos.column; i++) { + u8 *ptr = start+offset; + u8 c = *ptr; + if (c & 0x80) { + offset += utf8_decode(ptr, end-ptr, nullptr); + } else { + offset++; + } + } + } + + isize len = end-start; if (len < offset) { return nullptr; } - u8 *pos_offset = start+offset; u8 *line_start = pos_offset; u8 *line_end = pos_offset; + + if (offset > 0 && *line_start == '\n') { + // Prevent an error token that starts at the boundary of a line that + // leads to an empty line from advancing off its line. + line_start -= 1; + } while (line_start >= start) { if (*line_start == '\n') { line_start += 1; @@ -58,6 +84,11 @@ gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) } line_start -= 1; } + if (line_start == start - 1) { + // Prevent an error on the first line from stepping behind the boundary + // of the text. + line_start += 1; + } while (line_end < end) { if (*line_end == '\n') { @@ -70,6 +101,7 @@ gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) if (offset_) *offset_ = cast(i32)(pos_offset - the_line.text); + return gb_string_make_length(heap_allocator(), the_line.text, the_line.len); } @@ -718,7 +750,17 @@ gb_internal ExactValue exact_value_from_token(AstFile *f, Token const &token) { } ExactValue value = exact_value_from_basic_literal(token.kind, s); if (value.kind == ExactValue_Invalid) { - syntax_error(token, "Invalid token literal"); + switch (token.kind) { + case Token_Integer: + syntax_error(token, "Invalid integer literal"); + break; + case Token_Float: + syntax_error(token, "Invalid float literal"); + break; + default: + syntax_error(token, "Invalid token literal"); + break; + } } return value; } @@ -745,6 +787,9 @@ gb_internal Ast *ast_basic_directive(AstFile *f, Token token, Token name) { Ast *result = alloc_ast_node(f, Ast_BasicDirective); result->BasicDirective.token = token; result->BasicDirective.name = name; + if (string_starts_with(name.string, str_lit("load"))) { + f->seen_load_directive_count++; + } return result; } @@ -1455,7 +1500,7 @@ gb_internal bool skip_possible_newline(AstFile *f) { return false; } -gb_internal bool skip_possible_newline_for_literal(AstFile *f) { +gb_internal bool skip_possible_newline_for_literal(AstFile *f, bool ignore_strict_style=false) { Token curr = f->curr_token; if (token_is_newline(curr)) { Token next = peek_token(f); @@ -1463,6 +1508,10 @@ gb_internal bool skip_possible_newline_for_literal(AstFile *f) { switch (next.kind) { case Token_OpenBrace: case Token_else: + if (build_context.strict_style && !ignore_strict_style) { + syntax_error(next, "With '-strict-style' the attached brace style (1TBS) is enforced"); + } + /*fallthrough*/ case Token_where: advance_token(f); return true; @@ -2486,7 +2535,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { return type; } - skip_possible_newline_for_literal(f); + skip_possible_newline_for_literal(f, where_token.kind == Token_where); if (allow_token(f, Token_Uninit)) { if (where_token.kind != Token_Invalid) { @@ -3089,7 +3138,7 @@ gb_internal Ast *parse_call_expr(AstFile *f, Ast *operand) { Ast *call = ast_call_expr(f, operand, args, open_paren, close_paren, ellipsis); Ast *o = unparen_expr(operand); - if (o->kind == Ast_SelectorExpr && o->SelectorExpr.token.kind == Token_ArrowRight) { + if (o && o->kind == Ast_SelectorExpr && o->SelectorExpr.token.kind == Token_ArrowRight) { return ast_selector_call_expr(f, o->SelectorExpr.token, o, call); } @@ -4468,6 +4517,9 @@ gb_internal bool parse_control_statement_semicolon_separator(AstFile *f) { } + + + gb_internal Ast *parse_if_stmt(AstFile *f) { if (f->curr_proc == nullptr) { syntax_error(f->curr_token, "You cannot use an if statement in the file scope"); @@ -4510,7 +4562,11 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { body = parse_block_stmt(f, false); } - skip_possible_newline_for_literal(f); + bool ignore_strict_style = false; + if (token.pos.line == ast_end_token(body).pos.line) { + ignore_strict_style = true; + } + skip_possible_newline_for_literal(f, ignore_strict_style); if (f->curr_token.kind == Token_else) { Token else_token = expect_token(f, Token_else); switch (f->curr_token.kind) { @@ -4542,9 +4598,12 @@ gb_internal Ast *parse_when_stmt(AstFile *f) { isize prev_level = f->expr_level; f->expr_level = -1; + bool prev_allow_in_expr = f->allow_in_expr; + f->allow_in_expr = true; cond = parse_expr(f, false); + f->allow_in_expr = prev_allow_in_expr; f->expr_level = prev_level; if (cond == nullptr) { @@ -4559,7 +4618,11 @@ gb_internal Ast *parse_when_stmt(AstFile *f) { body = parse_block_stmt(f, true); } - skip_possible_newline_for_literal(f); + bool ignore_strict_style = false; + if (token.pos.line == ast_end_token(body).pos.line) { + ignore_strict_style = true; + } + skip_possible_newline_for_literal(f, ignore_strict_style); if (f->curr_token.kind == Token_else) { Token else_token = expect_token(f, Token_else); switch (f->curr_token.kind) { @@ -5194,6 +5257,38 @@ gb_internal Ast *parse_stmt(AstFile *f) { } else if (tag == "include") { syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?"); s = ast_bad_stmt(f, token, f->curr_token); + } else if (tag == "define") { + s = ast_bad_stmt(f, token, f->curr_token); + + if (name.pos.line == f->curr_token.pos.line) { + bool call_like = false; + Ast *macro_expr = nullptr; + Token ident = f->curr_token; + if (allow_token(f, Token_Ident) && + name.pos.line == f->curr_token.pos.line) { + if (f->curr_token.kind == Token_OpenParen && f->curr_token.pos.column == ident.pos.column+ident.string.len) { + call_like = true; + (void)parse_call_expr(f, nullptr); + } + + if (name.pos.line == f->curr_token.pos.line && f->curr_token.kind != Token_Semicolon) { + macro_expr = parse_expr(f, false); + } + } + + ERROR_BLOCK(); + syntax_error(ident, "#define is not a valid declaration, Odin does not have a C-like preprocessor."); + if (macro_expr == nullptr || call_like) { + error_line("\tNote: Odin does not support macros\n"); + } else { + gbString s = expr_to_string(macro_expr); + error_line("\tSuggestion: Did you mean '%.*s :: %s'?\n", LIT(ident.string), s); + gb_string_free(s); + } + } else { + syntax_error(token, "#define is not a valid declaration, Odin does not have a C-like preprocessor."); + } + } else { syntax_error(token, "Unknown tag directive used: '%.*s'", LIT(tag)); s = ast_bad_stmt(f, token, f->curr_token); @@ -5245,12 +5340,53 @@ gb_internal Ast *parse_stmt(AstFile *f) { return ast_bad_stmt(f, token, f->curr_token); } + + +gb_internal u64 check_vet_flags(AstFile *file) { + if (file && file->vet_flags_set) { + return file->vet_flags; + } + return build_context.vet_flags; +} + + +gb_internal void parse_enforce_tabs(AstFile *f) { + Token prev = f->prev_token; + Token curr = f->curr_token; + if (prev.pos.line < curr.pos.line) { + u8 *start = f->tokenizer.start+prev.pos.offset; + u8 *end = f->tokenizer.start+curr.pos.offset; + u8 *it = end; + while (it > start) { + if (*it == '\n') { + it++; + break; + } + it--; + } + + isize len = end-it; + for (isize i = 0; i < len; i++) { + if (it[i] == ' ') { + syntax_error(curr, "With '-vet-tabs', tabs must be used for indentation"); + break; + } + } + } +} + gb_internal Array parse_stmt_list(AstFile *f) { auto list = array_make(ast_allocator(f)); while (f->curr_token.kind != Token_case && f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { + + // Checks to see if tabs have been used for indentation + if (check_vet_flags(f) & VetFlag_Tabs) { + parse_enforce_tabs(f); + } + Ast *stmt = parse_stmt(f); if (stmt && stmt->kind != Ast_EmptyStmt) { array_add(&list, stmt); @@ -5407,6 +5543,7 @@ gb_internal WORKER_TASK_PROC(parser_worker_proc) { gb_internal void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) { ImportedFile f = {pkg, fi, pos, p->file_to_process_count++}; + f.pos.file_id = cast(i32)(f.index+1); auto wd = gb_alloc_item(permanent_allocator(), ParserWorkerData); wd->parser = p; wd->imported_file = f; @@ -5443,6 +5580,7 @@ gb_internal WORKER_TASK_PROC(foreign_file_worker_proc) { gb_internal void parser_add_foreign_file_to_process(Parser *p, AstPackage *pkg, AstForeignFileKind kind, FileInfo fi, TokenPos pos) { // TODO(bill): Use a better allocator ImportedFile f = {pkg, fi, pos, p->file_to_process_count++}; + f.pos.file_id = cast(i32)(f.index+1); auto wd = gb_alloc_item(permanent_allocator(), ForeignFileWorkerData); wd->parser = p; wd->imported_file = f; @@ -5721,7 +5859,6 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node return false; } - if (collection_name.len > 0) { // NOTE(bill): `base:runtime` == `core:runtime` if (collection_name == "core") { @@ -5876,7 +6013,7 @@ gb_internal void parse_setup_file_decls(Parser *p, AstFile *f, String const &bas Token fp_token = fp->BasicLit.token; String file_str = string_trim_whitespace(string_value_from_token(f, fp_token)); String fullpath = file_str; - if (allow_check_foreign_filepath()) { + if (!is_arch_wasm() || string_ends_with(fullpath, str_lit(".o"))) { String foreign_path = {}; bool ok = determine_path_from_string(&p->file_decl_mutex, node, base_dir, file_str, &foreign_path); if (!ok) { @@ -6240,8 +6377,6 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } else if (lc == "+lazy") { if (build_context.ignore_lazy) { // Ignore - } else if (f->flags & AstFile_IsTest) { - // Ignore } else if (f->pkg->kind == Package_Init && build_context.command_kind == Command_doc) { // Ignore } else { @@ -6359,11 +6494,6 @@ gb_internal ParseFileError process_imported_file(Parser *p, ImportedFile importe if (build_context.command_kind == Command_test) { String name = file->fullpath; name = remove_extension_from_path(name); - - String test_suffix = str_lit("_test"); - if (string_ends_with(name, test_suffix) && name != test_suffix) { - file->flags |= AstFile_IsTest; - } } @@ -6481,6 +6611,13 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) { } } } + + for (AstPackage *pkg : p->packages) { + for (AstFile *file : pkg->files) { + p->total_seen_load_directive_count += file->seen_load_directive_count; + } + } + return ParseFile_None; } diff --git a/src/parser.hpp b/src/parser.hpp index 02f2af28d..86b3393af 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -74,7 +74,6 @@ enum AstFileFlag : u32 { AstFile_IsPrivatePkg = 1<<0, AstFile_IsPrivateFile = 1<<1, - AstFile_IsTest = 1<<3, AstFile_IsLazy = 1<<4, AstFile_NoInstrumentation = 1<<5, @@ -141,6 +140,8 @@ struct AstFile { // This is effectively a queue but does not require any multi-threading capabilities Array delayed_decls_queues[AstDelayQueue_COUNT]; + std::atomic seen_load_directive_count; + #define PARSER_MAX_FIX_COUNT 6 isize fix_count; TokenPos fix_prev_pos; @@ -211,6 +212,8 @@ struct Parser { std::atomic total_token_count; std::atomic total_line_count; + std::atomic total_seen_load_directive_count; + // TODO(bill): What should this mutex be per? // * Parser // * Package diff --git a/src/path.cpp b/src/path.cpp index 26ccb7cbf..2c08ddd98 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -152,6 +152,13 @@ gb_internal String path_to_string(gbAllocator a, Path path) { return res; } +gb_internal String quote_path(gbAllocator a, Path path) { + String temp = path_to_string(a, path); + String quoted = concatenate3_strings(a, str_lit("\""), temp, str_lit("\"")); + gb_free(a, temp.text); + return quoted; +} + // NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`. gb_internal String path_to_full_path(gbAllocator a, Path path) { String temp = path_to_string(heap_allocator(), path); diff --git a/src/string.cpp b/src/string.cpp index 86eddeddd..3c7d96934 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -88,6 +88,13 @@ gb_internal char *alloc_cstring(gbAllocator a, String s) { return c_str; } +gb_internal wchar_t *alloc_wstring(gbAllocator a, String16 s) { + wchar_t *c_str = gb_alloc_array(a, wchar_t, s.len+1); + gb_memmove(c_str, s.text, s.len*2); + c_str[s.len] = '\0'; + return c_str; +} + gb_internal gb_inline bool str_eq_ignore_case(String const &a, String const &b) { if (a.len == b.len) { @@ -329,22 +336,22 @@ gb_internal bool string_contains_char(String const &s, u8 c) { } gb_internal bool string_contains_string(String const &haystack, String const &needle) { - if (needle.len == 0) return true; - if (needle.len > haystack.len) return false; + if (needle.len == 0) return true; + if (needle.len > haystack.len) return false; - for (isize i = 0; i <= haystack.len - needle.len; i++) { - bool found = true; - for (isize j = 0; j < needle.len; j++) { - if (haystack[i + j] != needle[j]) { - found = false; - break; - } - } - if (found) { - return true; - } - } - return false; + for (isize i = 0; i <= haystack.len - needle.len; i++) { + bool found = true; + for (isize j = 0; j < needle.len; j++) { + if (haystack[i + j] != needle[j]) { + found = false; + break; + } + } + if (found) { + return true; + } + } + return false; } gb_internal String filename_from_path(String s) { @@ -543,6 +550,40 @@ gb_internal String string16_to_string(gbAllocator a, String16 s) { +gb_internal String temporary_directory(gbAllocator allocator) { +#if defined(GB_SYSTEM_WINDOWS) + DWORD n = GetTempPathW(0, nullptr); + if (n == 0) { + return String{0}; + } + DWORD len = gb_max(MAX_PATH, n); + wchar_t *b = gb_alloc_array(heap_allocator(), wchar_t, len+1); + defer (gb_free(heap_allocator(), b)); + n = GetTempPathW(len, b); + if (n == 3 && b[1] == ':' && b[2] == '\\') { + + } else if (n > 0 && b[n-1] == '\\') { + n -= 1; + } + b[n] = 0; + String16 s = make_string16(b, n); + return string16_to_string(allocator, s); +#else + char const *tmp_env = gb_get_env("TMPDIR", allocator); + if (tmp_env) { + return make_string_c(tmp_env); + } + +#if defined(P_tmpdir) + String tmp_macro = make_string_c(P_tmpdir); + if (tmp_macro.len != 0) { + return copy_string(allocator, tmp_macro); + } +#endif + + return copy_string(allocator, str_lit("/tmp")); +#endif +} diff --git a/src/tilde.cpp b/src/tilde.cpp index 4fc7d1c9b..f6fed0f9a 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -363,7 +363,6 @@ gb_internal bool cg_global_variables_create(cgModule *m, Array if (is_foreign) { linkage = TB_LINKAGE_PUBLIC; // lb_add_foreign_library_path(m, e->Variable.foreign_library); - // lb_set_wasm_import_attributes(g.value, e, name); } else if (is_export) { linkage = TB_LINKAGE_PUBLIC; } diff --git a/src/timings.cpp b/src/timings.cpp index 712e804cb..3f8402b36 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -146,9 +146,10 @@ gb_internal f64 time_stamp_as_us(TimeStamp const &ts, u64 freq) { return 1000000.0*time_stamp_as_s(ts, freq); } -#define MAIN_TIME_SECTION(str) do { debugf("[Section] %s\n", str); timings_start_section(&global_timings, str_lit(str)); } while (0) -#define TIME_SECTION(str) do { debugf("[Section] %s\n", str); if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0) -#define TIME_SECTION_WITH_LEN(str, len) do { debugf("[Section] %s\n", str); if (build_context.show_more_timings) timings_start_section(&global_timings, make_string((u8 *)str, len)); } while (0) +#define MAIN_TIME_SECTION(str) do { debugf("[Section] %s\n", str); timings_start_section(&global_timings, str_lit(str)); } while (0) +#define MAIN_TIME_SECTION_WITH_LEN(str, len) do { debugf("[Section] %s\n", str); timings_start_section(&global_timings, make_string((u8 *)str, len)); } while (0) +#define TIME_SECTION(str) do { debugf("[Section] %s\n", str); if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0) +#define TIME_SECTION_WITH_LEN(str, len) do { debugf("[Section] %s\n", str); if (build_context.show_more_timings) timings_start_section(&global_timings, make_string((u8 *)str, len)); } while (0) enum TimingUnit { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index f7751d840..4425bee29 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -432,7 +432,10 @@ gb_internal gb_inline i32 digit_value(Rune r) { return 16; // NOTE(bill): Larger than highest possible } -gb_internal gb_inline void scan_mantissa(Tokenizer *t, i32 base) { +gb_internal gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool force_base) { + if (!force_base) { + base = 16; // always check for any possible letter + } while (digit_value(t->curr_rune) < base || t->curr_rune == '_') { advance_to_next_rune(t); } @@ -457,7 +460,7 @@ gb_internal void scan_number_to_token(Tokenizer *t, Token *token, bool seen_deci token->string.len += 1; token->pos.column -= 1; token->kind = Token_Float; - scan_mantissa(t, 10); + scan_mantissa(t, 10, true); goto exponent; } @@ -467,44 +470,50 @@ gb_internal void scan_number_to_token(Tokenizer *t, Token *token, bool seen_deci switch (t->curr_rune) { case 'b': // Binary advance_to_next_rune(t); - scan_mantissa(t, 2); + scan_mantissa(t, 2, false); if (t->curr - prev <= 2) { + tokenizer_err(t, "Invalid binary integer"); token->kind = Token_Invalid; } goto end; case 'o': // Octal advance_to_next_rune(t); - scan_mantissa(t, 8); + scan_mantissa(t, 8, false); if (t->curr - prev <= 2) { + tokenizer_err(t, "Invalid octal integer"); token->kind = Token_Invalid; } goto end; case 'd': // Decimal advance_to_next_rune(t); - scan_mantissa(t, 10); + scan_mantissa(t, 10, false); if (t->curr - prev <= 2) { + tokenizer_err(t, "Invalid explicitly decimal integer"); token->kind = Token_Invalid; } goto end; case 'z': // Dozenal advance_to_next_rune(t); - scan_mantissa(t, 12); + scan_mantissa(t, 12, false); if (t->curr - prev <= 2) { + tokenizer_err(t, "Invalid dozenal integer"); token->kind = Token_Invalid; } goto end; case 'x': // Hexadecimal advance_to_next_rune(t); - scan_mantissa(t, 16); + scan_mantissa(t, 16, false); if (t->curr - prev <= 2) { + tokenizer_err(t, "Invalid hexadecimal integer"); token->kind = Token_Invalid; } goto end; case 'h': // Hexadecimal Float token->kind = Token_Float; advance_to_next_rune(t); - scan_mantissa(t, 16); + scan_mantissa(t, 16, false); if (t->curr - prev <= 2) { + tokenizer_err(t, "Invalid hexadecimal float"); token->kind = Token_Invalid; } else { u8 *start = prev+2; @@ -527,12 +536,12 @@ gb_internal void scan_number_to_token(Tokenizer *t, Token *token, bool seen_deci } goto end; default: - scan_mantissa(t, 10); + scan_mantissa(t, 10, true); goto fraction; } } - scan_mantissa(t, 10); + scan_mantissa(t, 10, true); fraction: @@ -544,7 +553,7 @@ fraction: advance_to_next_rune(t); token->kind = Token_Float; - scan_mantissa(t, 10); + scan_mantissa(t, 10, true); } exponent: @@ -554,7 +563,7 @@ exponent: if (t->curr_rune == '-' || t->curr_rune == '+') { advance_to_next_rune(t); } - scan_mantissa(t, 10); + scan_mantissa(t, 10, false); } switch (t->curr_rune) { @@ -777,7 +786,6 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) { case '`': // Raw String Literal case '"': // String Literal { - bool has_carriage_return = false; i32 success; Rune quote = curr_rune; token->kind = Token_String; @@ -807,9 +815,6 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) { if (r == quote) { break; } - if (r == '\r') { - has_carriage_return = true; - } } } token->string.len = t->curr - token->string.text; diff --git a/src/types.cpp b/src/types.cpp index 97e8267a3..c3a5fb539 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2366,6 +2366,7 @@ gb_internal bool type_has_nil(Type *t) { return false; } + gb_internal bool elem_type_can_be_constant(Type *t) { t = base_type(t); if (t == t_invalid) { @@ -3224,7 +3225,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name } } if (type->kind == Type_Struct) { - wait_signal_until_available(&type->Struct.fields_wait_signal); + // wait_signal_until_available(&type->Struct.fields_wait_signal); isize field_count = type->Struct.fields.count; if (field_count != 0) for_array(i, type->Struct.fields) { Entity *f = type->Struct.fields[i]; @@ -3254,7 +3255,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name } if (type->kind == Type_Struct) { - wait_signal_until_available(&type->Struct.fields_wait_signal); + // wait_signal_until_available(&type->Struct.fields_wait_signal); Scope *s = type->Struct.scope; if (s != nullptr) { Entity *found = scope_lookup_current(s, field_name); diff --git a/src/ucg/ucg.c b/src/ucg/ucg.c new file mode 100644 index 000000000..c3e270e1a --- /dev/null +++ b/src/ucg/ucg.c @@ -0,0 +1,686 @@ +/* + * SPDX-FileCopyrightText: (c) 2024 Feoramund + * SPDX-License-Identifier: BSD-3-Clause + */ + + +// +// NOTE(Feoramund): This is my UCG library, adapted for use within the Odin compiler. +// Most of the comments have been let alone and may not strictly apply anymore. +// +// 1. The UCG allocator interface was replaced by gbAllocator. +// 2. The UCG UTF-8 decoder was replaced with the one already in the compiler. +// 3. Non-essential code was stripped. +// 4. Some types were changed for compatibility. +// + + +/* This is the data that is allocated when an allocator is passed to + * ucg_decode_grapheme_clusters. */ +typedef struct { + i32 byte_index; + i32 rune_index; + i32 width; +} ucg_grapheme; + + +/* #include "ucg.h" */ +#include "ucg_tables.h" + +#define UCG_TABLE_LEN(t) (sizeof(t) / sizeof(int32_t)) + +#define ZERO_WIDTH_SPACE 0x200B +#define ZERO_WIDTH_NON_JOINER 0x200C +#define ZERO_WIDTH_JOINER 0x200D +#define WORD_JOINER 0x2060 + +int ucg_binary_search(int32_t value, const int32_t* table, int length, int stride) { + GB_ASSERT(table != NULL); + GB_ASSERT(length > 0); + GB_ASSERT(stride > 0); + + int n = length; + int t = 0; + for (/**/; n > 1; /**/) { + int m = n / 2; + int p = t + m * stride; + if (value >= table[p]) { + t = p; + n = n - m; + } else { + n = m; + } + } + if (n != 0 && value >= table[t]) { + return t; + } + return -1; +} + +// +// The procedures below are accurate as of Unicode 15.1.0. +// + +bool ucg_is_control(int32_t r) { + if (r <= 0x1F || (0x7F <= r && r <= 0x9F)) { + return true; + } + return false; +} + +// Emoji_Modifier +bool ucg_is_emoji_modifier(int32_t r) { + return 0x1F3FB <= r && r <= 0x1F3FF; +} + +// Regional_Indicator +bool ucg_is_regional_indicator(int32_t r) { + return 0x1F1E6 <= r && r <= 0x1F1FF; +} + +// General_Category=Enclosing_Mark +bool ucg_is_enclosing_mark(int32_t r) { + switch (r) { + case 0x0488: + case 0x0489: + case 0x1ABE: + return true; + } + + if (0x20DD <= r && r <= 0x20E0) { return true; } + if (0x20E2 <= r && r <= 0x20E4) { return true; } + if (0xA670 <= r && r <= 0xA672) { return true; } + + return false; +} + +// Prepended_Concatenation_Mark +bool ucg_is_prepended_concatenation_mark(int32_t r) { + switch (r) { + case 0x006DD: + case 0x0070F: + case 0x008E2: + case 0x110BD: + case 0x110CD: + return true; + } + + if (0x00600 <= r && r <= 0x00605) { return true; } + if (0x00890 <= r && r <= 0x00891) { return true; } + + return false; +} + +// General_Category=Spacing_Mark +bool ucg_is_spacing_mark(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_spacing_mark_ranges, UCG_TABLE_LEN(ucg_spacing_mark_ranges)/2, 2); + if (p >= 0 && ucg_spacing_mark_ranges[p] <= r && r <= ucg_spacing_mark_ranges[p+1]) { + return true; + } + return false; +} + +// General_Category=Nonspacing_Mark +bool ucg_is_nonspacing_mark(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_nonspacing_mark_ranges, UCG_TABLE_LEN(ucg_nonspacing_mark_ranges)/2, 2); + if (p >= 0 && ucg_nonspacing_mark_ranges[p] <= r && r <= ucg_nonspacing_mark_ranges[p+1]) { + return true; + } + return false; +} + +// Extended_Pictographic +bool ucg_is_emoji_extended_pictographic(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_emoji_extended_pictographic_ranges, UCG_TABLE_LEN(ucg_emoji_extended_pictographic_ranges)/2, 2); + if (p >= 0 && ucg_emoji_extended_pictographic_ranges[p] <= r && r <= ucg_emoji_extended_pictographic_ranges[p+1]) { + return true; + } + return false; +} + +// Grapheme_Extend +bool ucg_is_grapheme_extend(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_grapheme_extend_ranges, UCG_TABLE_LEN(ucg_grapheme_extend_ranges)/2, 2); + if (p >= 0 && ucg_grapheme_extend_ranges[p] <= r && r <= ucg_grapheme_extend_ranges[p+1]) { + return true; + } + return false; +} + + +// Hangul_Syllable_Type=Leading_Jamo +bool ucg_is_hangul_syllable_leading(int32_t r) { + return (0x1100 <= r && r <= 0x115F) || (0xA960 <= r && r <= 0xA97C); +} + +// Hangul_Syllable_Type=Vowel_Jamo +bool ucg_is_hangul_syllable_vowel(int32_t r) { + return (0x1160 <= r && r <= 0x11A7) || (0xD7B0 <= r && r <= 0xD7C6); +} + +// Hangul_Syllable_Type=Trailing_Jamo +bool ucg_is_hangul_syllable_trailing(int32_t r) { + return (0x11A8 <= r && r <= 0x11FF) || (0xD7CB <= r && r <= 0xD7FB); +} + +// Hangul_Syllable_Type=LV_Syllable +bool ucg_is_hangul_syllable_lv(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_hangul_syllable_lv_singlets, UCG_TABLE_LEN(ucg_hangul_syllable_lv_singlets), 1); + if (p >= 0 && r == ucg_hangul_syllable_lv_singlets[p]) { + return true; + } + return false; +} + +// Hangul_Syllable_Type=LVT_Syllable +bool ucg_is_hangul_syllable_lvt(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_hangul_syllable_lvt_ranges, UCG_TABLE_LEN(ucg_hangul_syllable_lvt_ranges)/2, 2); + if (p >= 0 && ucg_hangul_syllable_lvt_ranges[p] <= r && r <= ucg_hangul_syllable_lvt_ranges[p+1]) { + return true; + } + return false; +} + + +// Indic_Syllabic_Category=Consonant_Preceding_Repha +bool ucg_is_indic_consonant_preceding_repha(int32_t r) { + switch (r) { + case 0x00D4E: + case 0x11941: + case 0x11D46: + case 0x11F02: + return true; + } + return false; +} + +// Indic_Syllabic_Category=Consonant_Prefixed +bool ucg_is_indic_consonant_prefixed(int32_t r) { + switch (r) { + case 0x1193F: + case 0x11A3A: + return true; + } + + if (0x111C2 <= r && r <= 0x111C3) { return true; } + if (0x11A84 <= r && r <= 0x11A89) { return true; } + + return false; +} + +// Indic_Conjunct_Break=Linker +bool ucg_is_indic_conjunct_break_linker(int32_t r) { + switch (r) { + case 0x094D: + case 0x09CD: + case 0x0ACD: + case 0x0B4D: + case 0x0C4D: + case 0x0D4D: + return true; + } + return false; +} + +// Indic_Conjunct_Break=Consonant +bool ucg_is_indic_conjunct_break_consonant(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_indic_conjunct_break_consonant_ranges, UCG_TABLE_LEN(ucg_indic_conjunct_break_consonant_ranges)/2, 2); + if (p >= 0 && ucg_indic_conjunct_break_consonant_ranges[p] <= r && r <= ucg_indic_conjunct_break_consonant_ranges[p+1]) { + return true; + } + return false; +} + +// Indic_Conjunct_Break=Extend +bool ucg_is_indic_conjunct_break_extend(int32_t r) { + intptr_t p = ucg_binary_search(r, ucg_indic_conjunct_break_extend_ranges, UCG_TABLE_LEN(ucg_indic_conjunct_break_extend_ranges)/2, 2); + if (p >= 0 && ucg_indic_conjunct_break_extend_ranges[p] <= r && r <= ucg_indic_conjunct_break_extend_ranges[p+1]) { + return true; + } + return false; +} + + +/* +``` +Indic_Syllabic_Category = Consonant_Preceding_Repha, or +Indic_Syllabic_Category = Consonant_Prefixed, or +Prepended_Concatenation_Mark = Yes +``` +*/ +bool ucg_is_gcb_prepend_class(int32_t r) { + return ucg_is_indic_consonant_preceding_repha(r) || ucg_is_indic_consonant_prefixed(r) || ucg_is_prepended_concatenation_mark(r); +} + +/* +``` +Grapheme_Extend = Yes, or +Emoji_Modifier = Yes + +This includes: +General_Category = Nonspacing_Mark +General_Category = Enclosing_Mark +U+200C ZERO WIDTH NON-JOINER + +plus a few General_Category = Spacing_Mark needed for canonical equivalence. +``` +*/ +bool ucg_is_gcb_extend_class(int32_t r) { + return ucg_is_grapheme_extend(r) || ucg_is_emoji_modifier(r); +} + +// Return values: +// +// - 2 if East_Asian_Width=F or W, or +// - 0 if non-printable / zero-width, or +// - 1 in all other cases. +// +int ucg_normalized_east_asian_width(int32_t r) { + if (ucg_is_control(r)) { + return 0; + } else if (r <= 0x10FF) { + // Easy early out for low runes. + return 1; + } + + switch (r) { + // This is a different interpretation of the BOM which occurs in the middle of text. + case 0xFEFF: /* ZERO_WIDTH_NO_BREAK_SPACE */ + case ZERO_WIDTH_SPACE: + case ZERO_WIDTH_NON_JOINER: + case ZERO_WIDTH_JOINER: + case WORD_JOINER: + return 0; + } + + intptr_t p = ucg_binary_search(r, ucg_normalized_east_asian_width_ranges, UCG_TABLE_LEN(ucg_normalized_east_asian_width_ranges)/3, 3); + if (p >= 0 && ucg_normalized_east_asian_width_ranges[p] <= r && r <= ucg_normalized_east_asian_width_ranges[p+1]) { + return (int)ucg_normalized_east_asian_width_ranges[p+2]; + } + return 1; +} + +// +// End of Unicode 15.1.0 block. +// + +enum grapheme_cluster_sequence { + None, + Indic, + Emoji, + Regional, +}; + +typedef struct { + ucg_grapheme* graphemes; + i32 rune_count; + i32 grapheme_count; + i32 width; + + int32_t last_rune; + bool last_rune_breaks_forward; + + i32 last_width; + i32 last_grapheme_count; + + bool bypass_next_rune; + + int regional_indicator_counter; + + enum grapheme_cluster_sequence current_sequence; + bool continue_sequence; +} ucg_decoder_state; + + +void _ucg_decode_grapheme_clusters_deferred_step( + gbAllocator allocator, + ucg_decoder_state* state, + i32 byte_index, + int32_t this_rune +) { + // "Break at the start and end of text, unless the text is empty." + // + // GB1: sot ÷ Any + // GB2: Any ÷ eot + if (state->rune_count == 0 && state->grapheme_count == 0) { + state->grapheme_count += 1; + } + + if (state->grapheme_count > state->last_grapheme_count) { + state->width += ucg_normalized_east_asian_width(this_rune); + + /* if (allocator != NULL) { */ + state->graphemes = (ucg_grapheme*)gb_resize(allocator, + state->graphemes, + sizeof(ucg_grapheme) * (state->grapheme_count), + sizeof(ucg_grapheme) * (1 + state->grapheme_count)); + + ucg_grapheme append = { + byte_index, + state->rune_count, + state->width - state->last_width, + }; + + state->graphemes[state->grapheme_count - 1] = append; + /* } */ + + state->last_grapheme_count = state->grapheme_count; + state->last_width = state->width; + } + + state->last_rune = this_rune; + state->rune_count += 1; + + if (!state->continue_sequence) { + state->current_sequence = None; + state->regional_indicator_counter = 0; + } + state->continue_sequence = false; +} + +int ucg_decode_grapheme_clusters( + gbAllocator allocator, + const uint8_t* str, + int str_len, + + ucg_grapheme** out_graphemes, + i32* out_rune_count, + i32* out_grapheme_count, + i32* out_width +) { + // The following procedure implements text segmentation by breaking on + // Grapheme Cluster Boundaries[1], using the values[2] and rules[3] from + // the Unicode® Standard Annex #29, entitled: + // + // UNICODE TEXT SEGMENTATION + // + // Version: Unicode 15.1.0 + // Date: 2023-08-16 + // Revision: 43 + // + // This procedure is conformant[4] to UAX29-C1-1, otherwise known as the + // extended, non-legacy ruleset. + // + // Please see the references for more information. + // + // + // [1]: https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries + // [2]: https://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table + // [3]: https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules + // [4]: https://www.unicode.org/reports/tr29/#Conformance + + // Additionally, this procedure takes into account Standard Annex #11, + // in order to estimate how visually wide the string will appear on a + // monospaced display. This can only ever be a rough guess, as this tends + // to be an implementation detail relating to which fonts are being used, + // how codepoints are interpreted and drawn, if codepoint sequences are + // interpreted correctly, and et cetera. + // + // For example, a program may not properly interpret an emoji modifier + // sequence and print the component glyphs instead of one whole glyph. + // + // See here for more information: https://www.unicode.org/reports/tr11/ + // + // NOTE: There is no explicit mention of what to do with zero-width spaces + // as far as grapheme cluster segmentation goes, therefore this + // implementation may count and return graphemes with a `width` of zero. + // + // Treat them as any other space. + + ucg_decoder_state state = {0}; + +#define UCG_DEFERRED_DECODE_STEP() (_ucg_decode_grapheme_clusters_deferred_step(allocator, &state, byte_index, this_rune)) + + for (i32 byte_index = 0, bytes_advanced = 0; byte_index < str_len; byte_index += bytes_advanced) { + int32_t this_rune = GB_RUNE_INVALID; + bytes_advanced = (i32)(utf8_decode(str+byte_index, str_len-byte_index, &this_rune)); + if (this_rune == GB_RUNE_INVALID || bytes_advanced == 0) { + // There was a Unicode parsing error; bail out. + if (out_graphemes != NULL) { *out_graphemes = state.graphemes; } + if (out_rune_count != NULL) { *out_rune_count = state.rune_count; } + if (out_grapheme_count != NULL) { *out_grapheme_count = state.grapheme_count; } + if (out_width != NULL) { *out_width = state.width; } + + // Return an error code. + return -1; + } + + // "Do not break between a CR and LF. Otherwise, break before and after controls." + // + // GB3: CR × LF + // GB4: (Control | CR | LF) ÷ + // GB5: ÷ (Control | CR | LF) + if (this_rune == '\n' && state.last_rune == '\r') { + state.last_rune_breaks_forward = false; + state.bypass_next_rune = false; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_control(this_rune)) { + state.grapheme_count += 1; + state.last_rune_breaks_forward = true; + state.bypass_next_rune = true; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // (This check is for rules that work forwards, instead of backwards.) + if (state.bypass_next_rune) { + if (state.last_rune_breaks_forward) { + state.grapheme_count += 1; + state.last_rune_breaks_forward = false; + } + + state.bypass_next_rune = false; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // (Optimization 1: Prevent low runes from proceeding further.) + // + // * 0xA9 and 0xAE are in the Extended_Pictographic range, + // which is checked later in GB11. + if (this_rune != 0xA9 && this_rune != 0xAE && this_rune <= 0x2FF) { + state.grapheme_count += 1; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // (Optimization 2: Check if the rune is in the Hangul space before getting specific.) + if (0x1100 <= this_rune && this_rune <= 0xD7FB) { + // "Do not break Hangul syllable sequences." + // + // GB6: L × (L | V | LV | LVT) + // GB7: (LV | V) × (V | T) + // GB8: (LVT | T) × T + if (ucg_is_hangul_syllable_leading(this_rune) || + ucg_is_hangul_syllable_lv(this_rune) || + ucg_is_hangul_syllable_lvt(this_rune)) + { + if (!ucg_is_hangul_syllable_leading(state.last_rune)) { + state.grapheme_count += 1; + } + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_hangul_syllable_vowel(this_rune)) { + if (ucg_is_hangul_syllable_leading(state.last_rune) || + ucg_is_hangul_syllable_vowel(state.last_rune) || + ucg_is_hangul_syllable_lv(state.last_rune)) + { + UCG_DEFERRED_DECODE_STEP(); continue; + } + state.grapheme_count += 1; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_hangul_syllable_trailing(this_rune)) { + if (ucg_is_hangul_syllable_trailing(state.last_rune) || + ucg_is_hangul_syllable_lvt(state.last_rune) || + ucg_is_hangul_syllable_lv(state.last_rune) || + ucg_is_hangul_syllable_vowel(state.last_rune)) + { + UCG_DEFERRED_DECODE_STEP(); continue; + } + state.grapheme_count += 1; + UCG_DEFERRED_DECODE_STEP(); continue; + } + } + + // "Do not break before extending characters or ZWJ." + // + // GB9: × (Extend | ZWJ) + if (this_rune == ZERO_WIDTH_JOINER) { + state.continue_sequence = true; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_gcb_extend_class(this_rune)) { + // (Support for GB9c.) + if (state.current_sequence == Indic) { + if (ucg_is_indic_conjunct_break_extend(this_rune) && ( + ucg_is_indic_conjunct_break_linker(state.last_rune) || + ucg_is_indic_conjunct_break_consonant(state.last_rune) )) + { + state.continue_sequence = true; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_indic_conjunct_break_linker(this_rune) && ( + ucg_is_indic_conjunct_break_linker(state.last_rune) || + ucg_is_indic_conjunct_break_extend(state.last_rune) || + ucg_is_indic_conjunct_break_consonant(state.last_rune) )) + { + state.continue_sequence = true; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // (Support for GB11.) + if (state.current_sequence == Emoji && ( + ucg_is_gcb_extend_class(state.last_rune) || + ucg_is_emoji_extended_pictographic(state.last_rune) )) + { + state.continue_sequence = true; + } + + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // _The GB9a and GB9b rules only apply to extended grapheme clusters:_ + // "Do not break before SpacingMarks, or after Prepend characters." + // + // GB9a: × SpacingMark + // GB9b: Prepend × + if (ucg_is_spacing_mark(this_rune)) { + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_gcb_prepend_class(this_rune)) { + state.grapheme_count += 1; + state.bypass_next_rune = true; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // _The GB9c rule only applies to extended grapheme clusters:_ + // "Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker." + // + // GB9c: \p{InCB=Consonant} [ \p{InCB=Extend} \p{InCB=Linker} ]* \p{InCB=Linker} [ \p{InCB=Extend} \p{InCB=Linker} ]* × \p{InCB=Consonant} + if (ucg_is_indic_conjunct_break_consonant(this_rune)) { + if (state.current_sequence == Indic) { + if (state.last_rune == ZERO_WIDTH_JOINER || + ucg_is_indic_conjunct_break_linker(state.last_rune)) + { + state.continue_sequence = true; + } else { + state.grapheme_count += 1; + } + } else { + state.grapheme_count += 1; + state.current_sequence = Indic; + state.continue_sequence = true; + } + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_indic_conjunct_break_extend(this_rune)) { + if (state.current_sequence == Indic) { + if (ucg_is_indic_conjunct_break_consonant(state.last_rune) || + ucg_is_indic_conjunct_break_linker(state.last_rune)) + { + state.continue_sequence = true; + } else { + state.grapheme_count += 1; + } + } + UCG_DEFERRED_DECODE_STEP(); continue; + } + + if (ucg_is_indic_conjunct_break_linker(this_rune)) { + if (state.current_sequence == Indic) { + if (ucg_is_indic_conjunct_break_extend(state.last_rune) || + ucg_is_indic_conjunct_break_linker(state.last_rune)) + { + state.continue_sequence = true; + } else { + state.grapheme_count += 1; + } + } + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // + // (Curiously, there is no GB10.) + // + + // "Do not break within emoji modifier sequences or emoji zwj sequences." + // + // GB11: \p{Extended_Pictographic} Extend* ZWJ × \p{Extended_Pictographic} + if (ucg_is_emoji_extended_pictographic(this_rune)) { + if (state.current_sequence != Emoji || state.last_rune != ZERO_WIDTH_JOINER) { + state.grapheme_count += 1; + } + state.current_sequence = Emoji; + state.continue_sequence = true; + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // "Do not break within emoji flag sequences. + // That is, do not break between regional indicator (RI) symbols + // if there is an odd number of RI characters before the break point." + // + // GB12: sot (RI RI)* RI × RI + // GB13: [^RI] (RI RI)* RI × RI + if (ucg_is_regional_indicator(this_rune)) { + if ((state.regional_indicator_counter & 1) == 0) { + state.grapheme_count += 1; + } + + state.current_sequence = Regional; + state.continue_sequence = true; + state.regional_indicator_counter += 1; + + UCG_DEFERRED_DECODE_STEP(); continue; + } + + // "Otherwise, break everywhere." + // + // GB999: Any ÷ Any + state.grapheme_count += 1; + UCG_DEFERRED_DECODE_STEP(); + } + +#undef UCG_DEFERRED_DECODE_STEP + + if (out_graphemes != NULL) { *out_graphemes = state.graphemes; } + if (out_rune_count != NULL) { *out_rune_count = state.rune_count; } + if (out_grapheme_count != NULL) { *out_grapheme_count = state.grapheme_count; } + if (out_width != NULL) { *out_width = state.width; } + + return 0; +} + +#undef UCG_TABLE_LEN +#undef ZERO_WIDTH_SPACE +#undef ZERO_WIDTH_NON_JOINER +#undef ZERO_WIDTH_JOINER +#undef WORD_JOINER diff --git a/src/ucg/ucg_tables.h b/src/ucg/ucg_tables.h new file mode 100644 index 000000000..a33f9f898 --- /dev/null +++ b/src/ucg/ucg_tables.h @@ -0,0 +1,2629 @@ +/* + * SPDX-FileCopyrightText: (c) 2024 Feoramund + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _UCG_TABLES_INCLUDED +#define _UCG_TABLES_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// +// The tables below are accurate as of Unicode 15.1.0. +// + +static const int32_t ucg_spacing_mark_ranges[] = { + 0x0903, 0x0903, + 0x093B, 0x093B, + 0x093E, 0x0940, + 0x0949, 0x094C, + 0x094E, 0x094F, + 0x0982, 0x0983, + 0x09BE, 0x09C0, + 0x09C7, 0x09C8, + 0x09CB, 0x09CC, + 0x09D7, 0x09D7, + 0x0A03, 0x0A03, + 0x0A3E, 0x0A40, + 0x0A83, 0x0A83, + 0x0ABE, 0x0AC0, + 0x0AC9, 0x0AC9, + 0x0ACB, 0x0ACC, + 0x0B02, 0x0B03, + 0x0B3E, 0x0B3E, + 0x0B40, 0x0B40, + 0x0B47, 0x0B48, + 0x0B4B, 0x0B4C, + 0x0B57, 0x0B57, + 0x0BBE, 0x0BBF, + 0x0BC1, 0x0BC2, + 0x0BC6, 0x0BC8, + 0x0BCA, 0x0BCC, + 0x0BD7, 0x0BD7, + 0x0C01, 0x0C03, + 0x0C41, 0x0C44, + 0x0C82, 0x0C83, + 0x0CBE, 0x0CBE, + 0x0CC0, 0x0CC4, + 0x0CC7, 0x0CC8, + 0x0CCA, 0x0CCB, + 0x0CD5, 0x0CD6, + 0x0CF3, 0x0CF3, + 0x0D02, 0x0D03, + 0x0D3E, 0x0D40, + 0x0D46, 0x0D48, + 0x0D4A, 0x0D4C, + 0x0D57, 0x0D57, + 0x0D82, 0x0D83, + 0x0DCF, 0x0DD1, + 0x0DD8, 0x0DDF, + 0x0DF2, 0x0DF3, + 0x0F3E, 0x0F3F, + 0x0F7F, 0x0F7F, + 0x102B, 0x102C, + 0x1031, 0x1031, + 0x1038, 0x1038, + 0x103B, 0x103C, + 0x1056, 0x1057, + 0x1062, 0x1064, + 0x1067, 0x106D, + 0x1083, 0x1084, + 0x1087, 0x108C, + 0x108F, 0x108F, + 0x109A, 0x109C, + 0x1715, 0x1715, + 0x1734, 0x1734, + 0x17B6, 0x17B6, + 0x17BE, 0x17C5, + 0x17C7, 0x17C8, + 0x1923, 0x1926, + 0x1929, 0x192B, + 0x1930, 0x1931, + 0x1933, 0x1938, + 0x1A19, 0x1A1A, + 0x1A55, 0x1A55, + 0x1A57, 0x1A57, + 0x1A61, 0x1A61, + 0x1A63, 0x1A64, + 0x1A6D, 0x1A72, + 0x1B04, 0x1B04, + 0x1B35, 0x1B35, + 0x1B3B, 0x1B3B, + 0x1B3D, 0x1B41, + 0x1B43, 0x1B44, + 0x1B82, 0x1B82, + 0x1BA1, 0x1BA1, + 0x1BA6, 0x1BA7, + 0x1BAA, 0x1BAA, + 0x1BE7, 0x1BE7, + 0x1BEA, 0x1BEC, + 0x1BEE, 0x1BEE, + 0x1BF2, 0x1BF3, + 0x1C24, 0x1C2B, + 0x1C34, 0x1C35, + 0x1CE1, 0x1CE1, + 0x1CF7, 0x1CF7, + 0x302E, 0x302F, + 0xA823, 0xA824, + 0xA827, 0xA827, + 0xA880, 0xA881, + 0xA8B4, 0xA8C3, + 0xA952, 0xA953, + 0xA983, 0xA983, + 0xA9B4, 0xA9B5, + 0xA9BA, 0xA9BB, + 0xA9BE, 0xA9C0, + 0xAA2F, 0xAA30, + 0xAA33, 0xAA34, + 0xAA4D, 0xAA4D, + 0xAA7B, 0xAA7B, + 0xAA7D, 0xAA7D, + 0xAAEB, 0xAAEB, + 0xAAEE, 0xAAEF, + 0xAAF5, 0xAAF5, + 0xABE3, 0xABE4, + 0xABE6, 0xABE7, + 0xABE9, 0xABEA, + 0xABEC, 0xABEC, + 0x11000, 0x11000, + 0x11002, 0x11002, + 0x11082, 0x11082, + 0x110B0, 0x110B2, + 0x110B7, 0x110B8, + 0x1112C, 0x1112C, + 0x11145, 0x11146, + 0x11182, 0x11182, + 0x111B3, 0x111B5, + 0x111BF, 0x111C0, + 0x111CE, 0x111CE, + 0x1122C, 0x1122E, + 0x11232, 0x11233, + 0x11235, 0x11235, + 0x112E0, 0x112E2, + 0x11302, 0x11303, + 0x1133E, 0x1133F, + 0x11341, 0x11344, + 0x11347, 0x11348, + 0x1134B, 0x1134D, + 0x11357, 0x11357, + 0x11362, 0x11363, + 0x11435, 0x11437, + 0x11440, 0x11441, + 0x11445, 0x11445, + 0x114B0, 0x114B2, + 0x114B9, 0x114B9, + 0x114BB, 0x114BE, + 0x114C1, 0x114C1, + 0x115AF, 0x115B1, + 0x115B8, 0x115BB, + 0x115BE, 0x115BE, + 0x11630, 0x11632, + 0x1163B, 0x1163C, + 0x1163E, 0x1163E, + 0x116AC, 0x116AC, + 0x116AE, 0x116AF, + 0x116B6, 0x116B6, + 0x11720, 0x11721, + 0x11726, 0x11726, + 0x1182C, 0x1182E, + 0x11838, 0x11838, + 0x11930, 0x11935, + 0x11937, 0x11938, + 0x1193D, 0x1193D, + 0x11940, 0x11940, + 0x11942, 0x11942, + 0x119D1, 0x119D3, + 0x119DC, 0x119DF, + 0x119E4, 0x119E4, + 0x11A39, 0x11A39, + 0x11A57, 0x11A58, + 0x11A97, 0x11A97, + 0x11C2F, 0x11C2F, + 0x11C3E, 0x11C3E, + 0x11CA9, 0x11CA9, + 0x11CB1, 0x11CB1, + 0x11CB4, 0x11CB4, + 0x11D8A, 0x11D8E, + 0x11D93, 0x11D94, + 0x11D96, 0x11D96, + 0x11EF5, 0x11EF6, + 0x11F03, 0x11F03, + 0x11F34, 0x11F35, + 0x11F3E, 0x11F3F, + 0x11F41, 0x11F41, + 0x16F51, 0x16F87, + 0x16FF0, 0x16FF1, + 0x1D165, 0x1D166, + 0x1D16D, 0x1D172, +}; + +static const int32_t ucg_nonspacing_mark_ranges[] = { + 0x0300, 0x036F, + 0x0483, 0x0487, + 0x0591, 0x05BD, + 0x05BF, 0x05BF, + 0x05C1, 0x05C2, + 0x05C4, 0x05C5, + 0x05C7, 0x05C7, + 0x0610, 0x061A, + 0x064B, 0x065F, + 0x0670, 0x0670, + 0x06D6, 0x06DC, + 0x06DF, 0x06E4, + 0x06E7, 0x06E8, + 0x06EA, 0x06ED, + 0x0711, 0x0711, + 0x0730, 0x074A, + 0x07A6, 0x07B0, + 0x07EB, 0x07F3, + 0x07FD, 0x07FD, + 0x0816, 0x0819, + 0x081B, 0x0823, + 0x0825, 0x0827, + 0x0829, 0x082D, + 0x0859, 0x085B, + 0x0898, 0x089F, + 0x08CA, 0x08E1, + 0x08E3, 0x0902, + 0x093A, 0x093A, + 0x093C, 0x093C, + 0x0941, 0x0948, + 0x094D, 0x094D, + 0x0951, 0x0957, + 0x0962, 0x0963, + 0x0981, 0x0981, + 0x09BC, 0x09BC, + 0x09C1, 0x09C4, + 0x09CD, 0x09CD, + 0x09E2, 0x09E3, + 0x09FE, 0x09FE, + 0x0A01, 0x0A02, + 0x0A3C, 0x0A3C, + 0x0A41, 0x0A42, + 0x0A47, 0x0A48, + 0x0A4B, 0x0A4D, + 0x0A51, 0x0A51, + 0x0A70, 0x0A71, + 0x0A75, 0x0A75, + 0x0A81, 0x0A82, + 0x0ABC, 0x0ABC, + 0x0AC1, 0x0AC5, + 0x0AC7, 0x0AC8, + 0x0ACD, 0x0ACD, + 0x0AE2, 0x0AE3, + 0x0AFA, 0x0AFF, + 0x0B01, 0x0B01, + 0x0B3C, 0x0B3C, + 0x0B3F, 0x0B3F, + 0x0B41, 0x0B44, + 0x0B4D, 0x0B4D, + 0x0B55, 0x0B56, + 0x0B62, 0x0B63, + 0x0B82, 0x0B82, + 0x0BC0, 0x0BC0, + 0x0BCD, 0x0BCD, + 0x0C00, 0x0C00, + 0x0C04, 0x0C04, + 0x0C3C, 0x0C3C, + 0x0C3E, 0x0C40, + 0x0C46, 0x0C48, + 0x0C4A, 0x0C4D, + 0x0C55, 0x0C56, + 0x0C62, 0x0C63, + 0x0C81, 0x0C81, + 0x0CBC, 0x0CBC, + 0x0CBF, 0x0CBF, + 0x0CC6, 0x0CC6, + 0x0CCC, 0x0CCD, + 0x0CE2, 0x0CE3, + 0x0D00, 0x0D01, + 0x0D3B, 0x0D3C, + 0x0D41, 0x0D44, + 0x0D4D, 0x0D4D, + 0x0D62, 0x0D63, + 0x0D81, 0x0D81, + 0x0DCA, 0x0DCA, + 0x0DD2, 0x0DD4, + 0x0DD6, 0x0DD6, + 0x0E31, 0x0E31, + 0x0E34, 0x0E3A, + 0x0E47, 0x0E4E, + 0x0EB1, 0x0EB1, + 0x0EB4, 0x0EBC, + 0x0EC8, 0x0ECE, + 0x0F18, 0x0F19, + 0x0F35, 0x0F35, + 0x0F37, 0x0F37, + 0x0F39, 0x0F39, + 0x0F71, 0x0F7E, + 0x0F80, 0x0F84, + 0x0F86, 0x0F87, + 0x0F8D, 0x0F97, + 0x0F99, 0x0FBC, + 0x0FC6, 0x0FC6, + 0x102D, 0x1030, + 0x1032, 0x1037, + 0x1039, 0x103A, + 0x103D, 0x103E, + 0x1058, 0x1059, + 0x105E, 0x1060, + 0x1071, 0x1074, + 0x1082, 0x1082, + 0x1085, 0x1086, + 0x108D, 0x108D, + 0x109D, 0x109D, + 0x135D, 0x135F, + 0x1712, 0x1714, + 0x1732, 0x1733, + 0x1752, 0x1753, + 0x1772, 0x1773, + 0x17B4, 0x17B5, + 0x17B7, 0x17BD, + 0x17C6, 0x17C6, + 0x17C9, 0x17D3, + 0x17DD, 0x17DD, + 0x180B, 0x180D, + 0x180F, 0x180F, + 0x1885, 0x1886, + 0x18A9, 0x18A9, + 0x1920, 0x1922, + 0x1927, 0x1928, + 0x1932, 0x1932, + 0x1939, 0x193B, + 0x1A17, 0x1A18, + 0x1A1B, 0x1A1B, + 0x1A56, 0x1A56, + 0x1A58, 0x1A5E, + 0x1A60, 0x1A60, + 0x1A62, 0x1A62, + 0x1A65, 0x1A6C, + 0x1A73, 0x1A7C, + 0x1A7F, 0x1A7F, + 0x1AB0, 0x1ABD, + 0x1ABF, 0x1ACE, + 0x1B00, 0x1B03, + 0x1B34, 0x1B34, + 0x1B36, 0x1B3A, + 0x1B3C, 0x1B3C, + 0x1B42, 0x1B42, + 0x1B6B, 0x1B73, + 0x1B80, 0x1B81, + 0x1BA2, 0x1BA5, + 0x1BA8, 0x1BA9, + 0x1BAB, 0x1BAD, + 0x1BE6, 0x1BE6, + 0x1BE8, 0x1BE9, + 0x1BED, 0x1BED, + 0x1BEF, 0x1BF1, + 0x1C2C, 0x1C33, + 0x1C36, 0x1C37, + 0x1CD0, 0x1CD2, + 0x1CD4, 0x1CE0, + 0x1CE2, 0x1CE8, + 0x1CED, 0x1CED, + 0x1CF4, 0x1CF4, + 0x1CF8, 0x1CF9, + 0x1DC0, 0x1DFF, + 0x20D0, 0x20DC, + 0x20E1, 0x20E1, + 0x20E5, 0x20F0, + 0x2CEF, 0x2CF1, + 0x2D7F, 0x2D7F, + 0x2DE0, 0x2DFF, + 0x302A, 0x302D, + 0x3099, 0x309A, + 0xA66F, 0xA66F, + 0xA674, 0xA67D, + 0xA69E, 0xA69F, + 0xA6F0, 0xA6F1, + 0xA802, 0xA802, + 0xA806, 0xA806, + 0xA80B, 0xA80B, + 0xA825, 0xA826, + 0xA82C, 0xA82C, + 0xA8C4, 0xA8C5, + 0xA8E0, 0xA8F1, + 0xA8FF, 0xA8FF, + 0xA926, 0xA92D, + 0xA947, 0xA951, + 0xA980, 0xA982, + 0xA9B3, 0xA9B3, + 0xA9B6, 0xA9B9, + 0xA9BC, 0xA9BD, + 0xA9E5, 0xA9E5, + 0xAA29, 0xAA2E, + 0xAA31, 0xAA32, + 0xAA35, 0xAA36, + 0xAA43, 0xAA43, + 0xAA4C, 0xAA4C, + 0xAA7C, 0xAA7C, + 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, + 0xAAB7, 0xAAB8, + 0xAABE, 0xAABF, + 0xAAC1, 0xAAC1, + 0xAAEC, 0xAAED, + 0xAAF6, 0xAAF6, + 0xABE5, 0xABE5, + 0xABE8, 0xABE8, + 0xABED, 0xABED, + 0xFB1E, 0xFB1E, + 0xFE00, 0xFE0F, + 0xFE20, 0xFE2F, + 0x101FD, 0x101FD, + 0x102E0, 0x102E0, + 0x10376, 0x1037A, + 0x10A01, 0x10A03, + 0x10A05, 0x10A06, + 0x10A0C, 0x10A0F, + 0x10A38, 0x10A3A, + 0x10A3F, 0x10A3F, + 0x10AE5, 0x10AE6, + 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, + 0x10EFD, 0x10EFF, + 0x10F46, 0x10F50, + 0x10F82, 0x10F85, + 0x11001, 0x11001, + 0x11038, 0x11046, + 0x11070, 0x11070, + 0x11073, 0x11074, + 0x1107F, 0x11081, + 0x110B3, 0x110B6, + 0x110B9, 0x110BA, + 0x110C2, 0x110C2, + 0x11100, 0x11102, + 0x11127, 0x1112B, + 0x1112D, 0x11134, + 0x11173, 0x11173, + 0x11180, 0x11181, + 0x111B6, 0x111BE, + 0x111C9, 0x111CC, + 0x111CF, 0x111CF, + 0x1122F, 0x11231, + 0x11234, 0x11234, + 0x11236, 0x11237, + 0x1123E, 0x1123E, + 0x11241, 0x11241, + 0x112DF, 0x112DF, + 0x112E3, 0x112EA, + 0x11300, 0x11301, + 0x1133B, 0x1133C, + 0x11340, 0x11340, + 0x11366, 0x1136C, + 0x11370, 0x11374, + 0x11438, 0x1143F, + 0x11442, 0x11444, + 0x11446, 0x11446, + 0x1145E, 0x1145E, + 0x114B3, 0x114B8, + 0x114BA, 0x114BA, + 0x114BF, 0x114C0, + 0x114C2, 0x114C3, + 0x115B2, 0x115B5, + 0x115BC, 0x115BD, + 0x115BF, 0x115C0, + 0x115DC, 0x115DD, + 0x11633, 0x1163A, + 0x1163D, 0x1163D, + 0x1163F, 0x11640, + 0x116AB, 0x116AB, + 0x116AD, 0x116AD, + 0x116B0, 0x116B5, + 0x116B7, 0x116B7, + 0x1171D, 0x1171F, + 0x11722, 0x11725, + 0x11727, 0x1172B, + 0x1182F, 0x11837, + 0x11839, 0x1183A, + 0x1193B, 0x1193C, + 0x1193E, 0x1193E, + 0x11943, 0x11943, + 0x119D4, 0x119D7, + 0x119DA, 0x119DB, + 0x119E0, 0x119E0, + 0x11A01, 0x11A0A, + 0x11A33, 0x11A38, + 0x11A3B, 0x11A3E, + 0x11A47, 0x11A47, + 0x11A51, 0x11A56, + 0x11A59, 0x11A5B, + 0x11A8A, 0x11A96, + 0x11A98, 0x11A99, + 0x11C30, 0x11C36, + 0x11C38, 0x11C3D, + 0x11C3F, 0x11C3F, + 0x11C92, 0x11CA7, + 0x11CAA, 0x11CB0, + 0x11CB2, 0x11CB3, + 0x11CB5, 0x11CB6, + 0x11D31, 0x11D36, + 0x11D3A, 0x11D3A, + 0x11D3C, 0x11D3D, + 0x11D3F, 0x11D45, + 0x11D47, 0x11D47, + 0x11D90, 0x11D91, + 0x11D95, 0x11D95, + 0x11D97, 0x11D97, + 0x11EF3, 0x11EF4, + 0x11F00, 0x11F01, + 0x11F36, 0x11F3A, + 0x11F40, 0x11F40, + 0x11F42, 0x11F42, + 0x13440, 0x13440, + 0x13447, 0x13455, + 0x16AF0, 0x16AF4, + 0x16B30, 0x16B36, + 0x16F4F, 0x16F4F, + 0x16F8F, 0x16F92, + 0x16FE4, 0x16FE4, + 0x1BC9D, 0x1BC9E, + 0x1CF00, 0x1CF2D, + 0x1CF30, 0x1CF46, + 0x1D167, 0x1D169, + 0x1D17B, 0x1D182, + 0x1D185, 0x1D18B, + 0x1D1AA, 0x1D1AD, + 0x1D242, 0x1D244, + 0x1DA00, 0x1DA36, + 0x1DA3B, 0x1DA6C, + 0x1DA75, 0x1DA75, + 0x1DA84, 0x1DA84, + 0x1DA9B, 0x1DA9F, + 0x1DAA1, 0x1DAAF, + 0x1E000, 0x1E006, + 0x1E008, 0x1E018, + 0x1E01B, 0x1E021, + 0x1E023, 0x1E024, + 0x1E026, 0x1E02A, + 0x1E08F, 0x1E08F, + 0x1E130, 0x1E136, + 0x1E2AE, 0x1E2AE, + 0x1E2EC, 0x1E2EF, + 0x1E4EC, 0x1E4EF, + 0x1E8D0, 0x1E8D6, + 0x1E944, 0x1E94A, + 0xE0100, 0xE01EF, +}; + +static const int32_t ucg_emoji_extended_pictographic_ranges[] = { + 0x00A9, 0x00A9, + 0x00AE, 0x00AE, + 0x203C, 0x203C, + 0x2049, 0x2049, + 0x2122, 0x2122, + 0x2139, 0x2139, + 0x2194, 0x2199, + 0x21A9, 0x21AA, + 0x231A, 0x231B, + 0x2328, 0x2328, + 0x2388, 0x2388, + 0x23CF, 0x23CF, + 0x23E9, 0x23EC, + 0x23ED, 0x23EE, + 0x23EF, 0x23EF, + 0x23F0, 0x23F0, + 0x23F1, 0x23F2, + 0x23F3, 0x23F3, + 0x23F8, 0x23FA, + 0x24C2, 0x24C2, + 0x25AA, 0x25AB, + 0x25B6, 0x25B6, + 0x25C0, 0x25C0, + 0x25FB, 0x25FE, + 0x2600, 0x2601, + 0x2602, 0x2603, + 0x2604, 0x2604, + 0x2605, 0x2605, + 0x2607, 0x260D, + 0x260E, 0x260E, + 0x260F, 0x2610, + 0x2611, 0x2611, + 0x2612, 0x2612, + 0x2614, 0x2615, + 0x2616, 0x2617, + 0x2618, 0x2618, + 0x2619, 0x261C, + 0x261D, 0x261D, + 0x261E, 0x261F, + 0x2620, 0x2620, + 0x2621, 0x2621, + 0x2622, 0x2623, + 0x2624, 0x2625, + 0x2626, 0x2626, + 0x2627, 0x2629, + 0x262A, 0x262A, + 0x262B, 0x262D, + 0x262E, 0x262E, + 0x262F, 0x262F, + 0x2630, 0x2637, + 0x2638, 0x2639, + 0x263A, 0x263A, + 0x263B, 0x263F, + 0x2640, 0x2640, + 0x2641, 0x2641, + 0x2642, 0x2642, + 0x2643, 0x2647, + 0x2648, 0x2653, + 0x2654, 0x265E, + 0x265F, 0x265F, + 0x2660, 0x2660, + 0x2661, 0x2662, + 0x2663, 0x2663, + 0x2664, 0x2664, + 0x2665, 0x2666, + 0x2667, 0x2667, + 0x2668, 0x2668, + 0x2669, 0x267A, + 0x267B, 0x267B, + 0x267C, 0x267D, + 0x267E, 0x267E, + 0x267F, 0x267F, + 0x2680, 0x2685, + 0x2690, 0x2691, + 0x2692, 0x2692, + 0x2693, 0x2693, + 0x2694, 0x2694, + 0x2695, 0x2695, + 0x2696, 0x2697, + 0x2698, 0x2698, + 0x2699, 0x2699, + 0x269A, 0x269A, + 0x269B, 0x269C, + 0x269D, 0x269F, + 0x26A0, 0x26A1, + 0x26A2, 0x26A6, + 0x26A7, 0x26A7, + 0x26A8, 0x26A9, + 0x26AA, 0x26AB, + 0x26AC, 0x26AF, + 0x26B0, 0x26B1, + 0x26B2, 0x26BC, + 0x26BD, 0x26BE, + 0x26BF, 0x26C3, + 0x26C4, 0x26C5, + 0x26C6, 0x26C7, + 0x26C8, 0x26C8, + 0x26C9, 0x26CD, + 0x26CE, 0x26CE, + 0x26CF, 0x26CF, + 0x26D0, 0x26D0, + 0x26D1, 0x26D1, + 0x26D2, 0x26D2, + 0x26D3, 0x26D3, + 0x26D4, 0x26D4, + 0x26D5, 0x26E8, + 0x26E9, 0x26E9, + 0x26EA, 0x26EA, + 0x26EB, 0x26EF, + 0x26F0, 0x26F1, + 0x26F2, 0x26F3, + 0x26F4, 0x26F4, + 0x26F5, 0x26F5, + 0x26F6, 0x26F6, + 0x26F7, 0x26F9, + 0x26FA, 0x26FA, + 0x26FB, 0x26FC, + 0x26FD, 0x26FD, + 0x26FE, 0x2701, + 0x2702, 0x2702, + 0x2703, 0x2704, + 0x2705, 0x2705, + 0x2708, 0x270C, + 0x270D, 0x270D, + 0x270E, 0x270E, + 0x270F, 0x270F, + 0x2710, 0x2711, + 0x2712, 0x2712, + 0x2714, 0x2714, + 0x2716, 0x2716, + 0x271D, 0x271D, + 0x2721, 0x2721, + 0x2728, 0x2728, + 0x2733, 0x2734, + 0x2744, 0x2744, + 0x2747, 0x2747, + 0x274C, 0x274C, + 0x274E, 0x274E, + 0x2753, 0x2755, + 0x2757, 0x2757, + 0x2763, 0x2763, + 0x2764, 0x2764, + 0x2765, 0x2767, + 0x2795, 0x2797, + 0x27A1, 0x27A1, + 0x27B0, 0x27B0, + 0x27BF, 0x27BF, + 0x2934, 0x2935, + 0x2B05, 0x2B07, + 0x2B1B, 0x2B1C, + 0x2B50, 0x2B50, + 0x2B55, 0x2B55, + 0x3030, 0x3030, + 0x303D, 0x303D, + 0x3297, 0x3297, + 0x3299, 0x3299, + 0x1F000, 0x1F003, + 0x1F004, 0x1F004, + 0x1F005, 0x1F0CE, + 0x1F0CF, 0x1F0CF, + 0x1F0D0, 0x1F0FF, + 0x1F10D, 0x1F10F, + 0x1F12F, 0x1F12F, + 0x1F16C, 0x1F16F, + 0x1F170, 0x1F171, + 0x1F17E, 0x1F17F, + 0x1F18E, 0x1F18E, + 0x1F191, 0x1F19A, + 0x1F1AD, 0x1F1E5, + 0x1F201, 0x1F202, + 0x1F203, 0x1F20F, + 0x1F21A, 0x1F21A, + 0x1F22F, 0x1F22F, + 0x1F232, 0x1F23A, + 0x1F23C, 0x1F23F, + 0x1F249, 0x1F24F, + 0x1F250, 0x1F251, + 0x1F252, 0x1F2FF, + 0x1F300, 0x1F30C, + 0x1F30D, 0x1F30E, + 0x1F30F, 0x1F30F, + 0x1F310, 0x1F310, + 0x1F311, 0x1F311, + 0x1F312, 0x1F312, + 0x1F313, 0x1F315, + 0x1F316, 0x1F318, + 0x1F319, 0x1F319, + 0x1F31A, 0x1F31A, + 0x1F31B, 0x1F31B, + 0x1F31C, 0x1F31C, + 0x1F31D, 0x1F31E, + 0x1F31F, 0x1F320, + 0x1F321, 0x1F321, + 0x1F322, 0x1F323, + 0x1F324, 0x1F32C, + 0x1F32D, 0x1F32F, + 0x1F330, 0x1F331, + 0x1F332, 0x1F333, + 0x1F334, 0x1F335, + 0x1F336, 0x1F336, + 0x1F337, 0x1F34A, + 0x1F34B, 0x1F34B, + 0x1F34C, 0x1F34F, + 0x1F350, 0x1F350, + 0x1F351, 0x1F37B, + 0x1F37C, 0x1F37C, + 0x1F37D, 0x1F37D, + 0x1F37E, 0x1F37F, + 0x1F380, 0x1F393, + 0x1F394, 0x1F395, + 0x1F396, 0x1F397, + 0x1F398, 0x1F398, + 0x1F399, 0x1F39B, + 0x1F39C, 0x1F39D, + 0x1F39E, 0x1F39F, + 0x1F3A0, 0x1F3C4, + 0x1F3C5, 0x1F3C5, + 0x1F3C6, 0x1F3C6, + 0x1F3C7, 0x1F3C7, + 0x1F3C8, 0x1F3C8, + 0x1F3C9, 0x1F3C9, + 0x1F3CA, 0x1F3CA, + 0x1F3CB, 0x1F3CE, + 0x1F3CF, 0x1F3D3, + 0x1F3D4, 0x1F3DF, + 0x1F3E0, 0x1F3E3, + 0x1F3E4, 0x1F3E4, + 0x1F3E5, 0x1F3F0, + 0x1F3F1, 0x1F3F2, + 0x1F3F3, 0x1F3F3, + 0x1F3F4, 0x1F3F4, + 0x1F3F5, 0x1F3F5, + 0x1F3F6, 0x1F3F6, + 0x1F3F7, 0x1F3F7, + 0x1F3F8, 0x1F3FA, + 0x1F400, 0x1F407, + 0x1F408, 0x1F408, + 0x1F409, 0x1F40B, + 0x1F40C, 0x1F40E, + 0x1F40F, 0x1F410, + 0x1F411, 0x1F412, + 0x1F413, 0x1F413, + 0x1F414, 0x1F414, + 0x1F415, 0x1F415, + 0x1F416, 0x1F416, + 0x1F417, 0x1F429, + 0x1F42A, 0x1F42A, + 0x1F42B, 0x1F43E, + 0x1F43F, 0x1F43F, + 0x1F440, 0x1F440, + 0x1F441, 0x1F441, + 0x1F442, 0x1F464, + 0x1F465, 0x1F465, + 0x1F466, 0x1F46B, + 0x1F46C, 0x1F46D, + 0x1F46E, 0x1F4AC, + 0x1F4AD, 0x1F4AD, + 0x1F4AE, 0x1F4B5, + 0x1F4B6, 0x1F4B7, + 0x1F4B8, 0x1F4EB, + 0x1F4EC, 0x1F4ED, + 0x1F4EE, 0x1F4EE, + 0x1F4EF, 0x1F4EF, + 0x1F4F0, 0x1F4F4, + 0x1F4F5, 0x1F4F5, + 0x1F4F6, 0x1F4F7, + 0x1F4F8, 0x1F4F8, + 0x1F4F9, 0x1F4FC, + 0x1F4FD, 0x1F4FD, + 0x1F4FE, 0x1F4FE, + 0x1F4FF, 0x1F502, + 0x1F503, 0x1F503, + 0x1F504, 0x1F507, + 0x1F508, 0x1F508, + 0x1F509, 0x1F509, + 0x1F50A, 0x1F514, + 0x1F515, 0x1F515, + 0x1F516, 0x1F52B, + 0x1F52C, 0x1F52D, + 0x1F52E, 0x1F53D, + 0x1F546, 0x1F548, + 0x1F549, 0x1F54A, + 0x1F54B, 0x1F54E, + 0x1F54F, 0x1F54F, + 0x1F550, 0x1F55B, + 0x1F55C, 0x1F567, + 0x1F568, 0x1F56E, + 0x1F56F, 0x1F570, + 0x1F571, 0x1F572, + 0x1F573, 0x1F579, + 0x1F57A, 0x1F57A, + 0x1F57B, 0x1F586, + 0x1F587, 0x1F587, + 0x1F588, 0x1F589, + 0x1F58A, 0x1F58D, + 0x1F58E, 0x1F58F, + 0x1F590, 0x1F590, + 0x1F591, 0x1F594, + 0x1F595, 0x1F596, + 0x1F597, 0x1F5A3, + 0x1F5A4, 0x1F5A4, + 0x1F5A5, 0x1F5A5, + 0x1F5A6, 0x1F5A7, + 0x1F5A8, 0x1F5A8, + 0x1F5A9, 0x1F5B0, + 0x1F5B1, 0x1F5B2, + 0x1F5B3, 0x1F5BB, + 0x1F5BC, 0x1F5BC, + 0x1F5BD, 0x1F5C1, + 0x1F5C2, 0x1F5C4, + 0x1F5C5, 0x1F5D0, + 0x1F5D1, 0x1F5D3, + 0x1F5D4, 0x1F5DB, + 0x1F5DC, 0x1F5DE, + 0x1F5DF, 0x1F5E0, + 0x1F5E1, 0x1F5E1, + 0x1F5E2, 0x1F5E2, + 0x1F5E3, 0x1F5E3, + 0x1F5E4, 0x1F5E7, + 0x1F5E8, 0x1F5E8, + 0x1F5E9, 0x1F5EE, + 0x1F5EF, 0x1F5EF, + 0x1F5F0, 0x1F5F2, + 0x1F5F3, 0x1F5F3, + 0x1F5F4, 0x1F5F9, + 0x1F5FA, 0x1F5FA, + 0x1F5FB, 0x1F5FF, + 0x1F600, 0x1F600, + 0x1F601, 0x1F606, + 0x1F607, 0x1F608, + 0x1F609, 0x1F60D, + 0x1F60E, 0x1F60E, + 0x1F60F, 0x1F60F, + 0x1F610, 0x1F610, + 0x1F611, 0x1F611, + 0x1F612, 0x1F614, + 0x1F615, 0x1F615, + 0x1F616, 0x1F616, + 0x1F617, 0x1F617, + 0x1F618, 0x1F618, + 0x1F619, 0x1F619, + 0x1F61A, 0x1F61A, + 0x1F61B, 0x1F61B, + 0x1F61C, 0x1F61E, + 0x1F61F, 0x1F61F, + 0x1F620, 0x1F625, + 0x1F626, 0x1F627, + 0x1F628, 0x1F62B, + 0x1F62C, 0x1F62C, + 0x1F62D, 0x1F62D, + 0x1F62E, 0x1F62F, + 0x1F630, 0x1F633, + 0x1F634, 0x1F634, + 0x1F635, 0x1F635, + 0x1F636, 0x1F636, + 0x1F637, 0x1F640, + 0x1F641, 0x1F644, + 0x1F645, 0x1F64F, + 0x1F680, 0x1F680, + 0x1F681, 0x1F682, + 0x1F683, 0x1F685, + 0x1F686, 0x1F686, + 0x1F687, 0x1F687, + 0x1F688, 0x1F688, + 0x1F689, 0x1F689, + 0x1F68A, 0x1F68B, + 0x1F68C, 0x1F68C, + 0x1F68D, 0x1F68D, + 0x1F68E, 0x1F68E, + 0x1F68F, 0x1F68F, + 0x1F690, 0x1F690, + 0x1F691, 0x1F693, + 0x1F694, 0x1F694, + 0x1F695, 0x1F695, + 0x1F696, 0x1F696, + 0x1F697, 0x1F697, + 0x1F698, 0x1F698, + 0x1F699, 0x1F69A, + 0x1F69B, 0x1F6A1, + 0x1F6A2, 0x1F6A2, + 0x1F6A3, 0x1F6A3, + 0x1F6A4, 0x1F6A5, + 0x1F6A6, 0x1F6A6, + 0x1F6A7, 0x1F6AD, + 0x1F6AE, 0x1F6B1, + 0x1F6B2, 0x1F6B2, + 0x1F6B3, 0x1F6B5, + 0x1F6B6, 0x1F6B6, + 0x1F6B7, 0x1F6B8, + 0x1F6B9, 0x1F6BE, + 0x1F6BF, 0x1F6BF, + 0x1F6C0, 0x1F6C0, + 0x1F6C1, 0x1F6C5, + 0x1F6C6, 0x1F6CA, + 0x1F6CB, 0x1F6CB, + 0x1F6CC, 0x1F6CC, + 0x1F6CD, 0x1F6CF, + 0x1F6D0, 0x1F6D0, + 0x1F6D1, 0x1F6D2, + 0x1F6D3, 0x1F6D4, + 0x1F6D5, 0x1F6D5, + 0x1F6D6, 0x1F6D7, + 0x1F6D8, 0x1F6DB, + 0x1F6DC, 0x1F6DC, + 0x1F6DD, 0x1F6DF, + 0x1F6E0, 0x1F6E5, + 0x1F6E6, 0x1F6E8, + 0x1F6E9, 0x1F6E9, + 0x1F6EA, 0x1F6EA, + 0x1F6EB, 0x1F6EC, + 0x1F6ED, 0x1F6EF, + 0x1F6F0, 0x1F6F0, + 0x1F6F1, 0x1F6F2, + 0x1F6F3, 0x1F6F3, + 0x1F6F4, 0x1F6F6, + 0x1F6F7, 0x1F6F8, + 0x1F6F9, 0x1F6F9, + 0x1F6FA, 0x1F6FA, + 0x1F6FB, 0x1F6FC, + 0x1F6FD, 0x1F6FF, + 0x1F774, 0x1F77F, + 0x1F7D5, 0x1F7DF, + 0x1F7E0, 0x1F7EB, + 0x1F7EC, 0x1F7EF, + 0x1F7F0, 0x1F7F0, + 0x1F7F1, 0x1F7FF, + 0x1F80C, 0x1F80F, + 0x1F848, 0x1F84F, + 0x1F85A, 0x1F85F, + 0x1F888, 0x1F88F, + 0x1F8AE, 0x1F8FF, + 0x1F90C, 0x1F90C, + 0x1F90D, 0x1F90F, + 0x1F910, 0x1F918, + 0x1F919, 0x1F91E, + 0x1F91F, 0x1F91F, + 0x1F920, 0x1F927, + 0x1F928, 0x1F92F, + 0x1F930, 0x1F930, + 0x1F931, 0x1F932, + 0x1F933, 0x1F93A, + 0x1F93C, 0x1F93E, + 0x1F93F, 0x1F93F, + 0x1F940, 0x1F945, + 0x1F947, 0x1F94B, + 0x1F94C, 0x1F94C, + 0x1F94D, 0x1F94F, + 0x1F950, 0x1F95E, + 0x1F95F, 0x1F96B, + 0x1F96C, 0x1F970, + 0x1F971, 0x1F971, + 0x1F972, 0x1F972, + 0x1F973, 0x1F976, + 0x1F977, 0x1F978, + 0x1F979, 0x1F979, + 0x1F97A, 0x1F97A, + 0x1F97B, 0x1F97B, + 0x1F97C, 0x1F97F, + 0x1F980, 0x1F984, + 0x1F985, 0x1F991, + 0x1F992, 0x1F997, + 0x1F998, 0x1F9A2, + 0x1F9A3, 0x1F9A4, + 0x1F9A5, 0x1F9AA, + 0x1F9AB, 0x1F9AD, + 0x1F9AE, 0x1F9AF, + 0x1F9B0, 0x1F9B9, + 0x1F9BA, 0x1F9BF, + 0x1F9C0, 0x1F9C0, + 0x1F9C1, 0x1F9C2, + 0x1F9C3, 0x1F9CA, + 0x1F9CB, 0x1F9CB, + 0x1F9CC, 0x1F9CC, + 0x1F9CD, 0x1F9CF, + 0x1F9D0, 0x1F9E6, + 0x1F9E7, 0x1F9FF, + 0x1FA00, 0x1FA6F, + 0x1FA70, 0x1FA73, + 0x1FA74, 0x1FA74, + 0x1FA75, 0x1FA77, + 0x1FA78, 0x1FA7A, + 0x1FA7B, 0x1FA7C, + 0x1FA7D, 0x1FA7F, + 0x1FA80, 0x1FA82, + 0x1FA83, 0x1FA86, + 0x1FA87, 0x1FA88, + 0x1FA89, 0x1FA8F, + 0x1FA90, 0x1FA95, + 0x1FA96, 0x1FAA8, + 0x1FAA9, 0x1FAAC, + 0x1FAAD, 0x1FAAF, + 0x1FAB0, 0x1FAB6, + 0x1FAB7, 0x1FABA, + 0x1FABB, 0x1FABD, + 0x1FABE, 0x1FABE, + 0x1FABF, 0x1FABF, + 0x1FAC0, 0x1FAC2, + 0x1FAC3, 0x1FAC5, + 0x1FAC6, 0x1FACD, + 0x1FACE, 0x1FACF, + 0x1FAD0, 0x1FAD6, + 0x1FAD7, 0x1FAD9, + 0x1FADA, 0x1FADB, + 0x1FADC, 0x1FADF, + 0x1FAE0, 0x1FAE7, + 0x1FAE8, 0x1FAE8, + 0x1FAE9, 0x1FAEF, + 0x1FAF0, 0x1FAF6, + 0x1FAF7, 0x1FAF8, + 0x1FAF9, 0x1FAFF, + 0x1FC00, 0x1FFFD, +}; + +static const int32_t ucg_grapheme_extend_ranges[] = { + 0x0300, 0x036F, + 0x0483, 0x0487, + 0x0488, 0x0489, + 0x0591, 0x05BD, + 0x05BF, 0x05BF, + 0x05C1, 0x05C2, + 0x05C4, 0x05C5, + 0x05C7, 0x05C7, + 0x0610, 0x061A, + 0x064B, 0x065F, + 0x0670, 0x0670, + 0x06D6, 0x06DC, + 0x06DF, 0x06E4, + 0x06E7, 0x06E8, + 0x06EA, 0x06ED, + 0x0711, 0x0711, + 0x0730, 0x074A, + 0x07A6, 0x07B0, + 0x07EB, 0x07F3, + 0x07FD, 0x07FD, + 0x0816, 0x0819, + 0x081B, 0x0823, + 0x0825, 0x0827, + 0x0829, 0x082D, + 0x0859, 0x085B, + 0x0898, 0x089F, + 0x08CA, 0x08E1, + 0x08E3, 0x0902, + 0x093A, 0x093A, + 0x093C, 0x093C, + 0x0941, 0x0948, + 0x094D, 0x094D, + 0x0951, 0x0957, + 0x0962, 0x0963, + 0x0981, 0x0981, + 0x09BC, 0x09BC, + 0x09BE, 0x09BE, + 0x09C1, 0x09C4, + 0x09CD, 0x09CD, + 0x09D7, 0x09D7, + 0x09E2, 0x09E3, + 0x09FE, 0x09FE, + 0x0A01, 0x0A02, + 0x0A3C, 0x0A3C, + 0x0A41, 0x0A42, + 0x0A47, 0x0A48, + 0x0A4B, 0x0A4D, + 0x0A51, 0x0A51, + 0x0A70, 0x0A71, + 0x0A75, 0x0A75, + 0x0A81, 0x0A82, + 0x0ABC, 0x0ABC, + 0x0AC1, 0x0AC5, + 0x0AC7, 0x0AC8, + 0x0ACD, 0x0ACD, + 0x0AE2, 0x0AE3, + 0x0AFA, 0x0AFF, + 0x0B01, 0x0B01, + 0x0B3C, 0x0B3C, + 0x0B3E, 0x0B3E, + 0x0B3F, 0x0B3F, + 0x0B41, 0x0B44, + 0x0B4D, 0x0B4D, + 0x0B55, 0x0B56, + 0x0B57, 0x0B57, + 0x0B62, 0x0B63, + 0x0B82, 0x0B82, + 0x0BBE, 0x0BBE, + 0x0BC0, 0x0BC0, + 0x0BCD, 0x0BCD, + 0x0BD7, 0x0BD7, + 0x0C00, 0x0C00, + 0x0C04, 0x0C04, + 0x0C3C, 0x0C3C, + 0x0C3E, 0x0C40, + 0x0C46, 0x0C48, + 0x0C4A, 0x0C4D, + 0x0C55, 0x0C56, + 0x0C62, 0x0C63, + 0x0C81, 0x0C81, + 0x0CBC, 0x0CBC, + 0x0CBF, 0x0CBF, + 0x0CC2, 0x0CC2, + 0x0CC6, 0x0CC6, + 0x0CCC, 0x0CCD, + 0x0CD5, 0x0CD6, + 0x0CE2, 0x0CE3, + 0x0D00, 0x0D01, + 0x0D3B, 0x0D3C, + 0x0D3E, 0x0D3E, + 0x0D41, 0x0D44, + 0x0D4D, 0x0D4D, + 0x0D57, 0x0D57, + 0x0D62, 0x0D63, + 0x0D81, 0x0D81, + 0x0DCA, 0x0DCA, + 0x0DCF, 0x0DCF, + 0x0DD2, 0x0DD4, + 0x0DD6, 0x0DD6, + 0x0DDF, 0x0DDF, + 0x0E31, 0x0E31, + 0x0E34, 0x0E3A, + 0x0E47, 0x0E4E, + 0x0EB1, 0x0EB1, + 0x0EB4, 0x0EBC, + 0x0EC8, 0x0ECE, + 0x0F18, 0x0F19, + 0x0F35, 0x0F35, + 0x0F37, 0x0F37, + 0x0F39, 0x0F39, + 0x0F71, 0x0F7E, + 0x0F80, 0x0F84, + 0x0F86, 0x0F87, + 0x0F8D, 0x0F97, + 0x0F99, 0x0FBC, + 0x0FC6, 0x0FC6, + 0x102D, 0x1030, + 0x1032, 0x1037, + 0x1039, 0x103A, + 0x103D, 0x103E, + 0x1058, 0x1059, + 0x105E, 0x1060, + 0x1071, 0x1074, + 0x1082, 0x1082, + 0x1085, 0x1086, + 0x108D, 0x108D, + 0x109D, 0x109D, + 0x135D, 0x135F, + 0x1712, 0x1714, + 0x1732, 0x1733, + 0x1752, 0x1753, + 0x1772, 0x1773, + 0x17B4, 0x17B5, + 0x17B7, 0x17BD, + 0x17C6, 0x17C6, + 0x17C9, 0x17D3, + 0x17DD, 0x17DD, + 0x180B, 0x180D, + 0x180F, 0x180F, + 0x1885, 0x1886, + 0x18A9, 0x18A9, + 0x1920, 0x1922, + 0x1927, 0x1928, + 0x1932, 0x1932, + 0x1939, 0x193B, + 0x1A17, 0x1A18, + 0x1A1B, 0x1A1B, + 0x1A56, 0x1A56, + 0x1A58, 0x1A5E, + 0x1A60, 0x1A60, + 0x1A62, 0x1A62, + 0x1A65, 0x1A6C, + 0x1A73, 0x1A7C, + 0x1A7F, 0x1A7F, + 0x1AB0, 0x1ABD, + 0x1ABE, 0x1ABE, + 0x1ABF, 0x1ACE, + 0x1B00, 0x1B03, + 0x1B34, 0x1B34, + 0x1B35, 0x1B35, + 0x1B36, 0x1B3A, + 0x1B3C, 0x1B3C, + 0x1B42, 0x1B42, + 0x1B6B, 0x1B73, + 0x1B80, 0x1B81, + 0x1BA2, 0x1BA5, + 0x1BA8, 0x1BA9, + 0x1BAB, 0x1BAD, + 0x1BE6, 0x1BE6, + 0x1BE8, 0x1BE9, + 0x1BED, 0x1BED, + 0x1BEF, 0x1BF1, + 0x1C2C, 0x1C33, + 0x1C36, 0x1C37, + 0x1CD0, 0x1CD2, + 0x1CD4, 0x1CE0, + 0x1CE2, 0x1CE8, + 0x1CED, 0x1CED, + 0x1CF4, 0x1CF4, + 0x1CF8, 0x1CF9, + 0x1DC0, 0x1DFF, + 0x200C, 0x200C, + 0x20D0, 0x20DC, + 0x20DD, 0x20E0, + 0x20E1, 0x20E1, + 0x20E2, 0x20E4, + 0x20E5, 0x20F0, + 0x2CEF, 0x2CF1, + 0x2D7F, 0x2D7F, + 0x2DE0, 0x2DFF, + 0x302A, 0x302D, + 0x302E, 0x302F, + 0x3099, 0x309A, + 0xA66F, 0xA66F, + 0xA670, 0xA672, + 0xA674, 0xA67D, + 0xA69E, 0xA69F, + 0xA6F0, 0xA6F1, + 0xA802, 0xA802, + 0xA806, 0xA806, + 0xA80B, 0xA80B, + 0xA825, 0xA826, + 0xA82C, 0xA82C, + 0xA8C4, 0xA8C5, + 0xA8E0, 0xA8F1, + 0xA8FF, 0xA8FF, + 0xA926, 0xA92D, + 0xA947, 0xA951, + 0xA980, 0xA982, + 0xA9B3, 0xA9B3, + 0xA9B6, 0xA9B9, + 0xA9BC, 0xA9BD, + 0xA9E5, 0xA9E5, + 0xAA29, 0xAA2E, + 0xAA31, 0xAA32, + 0xAA35, 0xAA36, + 0xAA43, 0xAA43, + 0xAA4C, 0xAA4C, + 0xAA7C, 0xAA7C, + 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, + 0xAAB7, 0xAAB8, + 0xAABE, 0xAABF, + 0xAAC1, 0xAAC1, + 0xAAEC, 0xAAED, + 0xAAF6, 0xAAF6, + 0xABE5, 0xABE5, + 0xABE8, 0xABE8, + 0xABED, 0xABED, + 0xFB1E, 0xFB1E, + 0xFE00, 0xFE0F, + 0xFE20, 0xFE2F, + 0xFF9E, 0xFF9F, + 0x101FD, 0x101FD, + 0x102E0, 0x102E0, + 0x10376, 0x1037A, + 0x10A01, 0x10A03, + 0x10A05, 0x10A06, + 0x10A0C, 0x10A0F, + 0x10A38, 0x10A3A, + 0x10A3F, 0x10A3F, + 0x10AE5, 0x10AE6, + 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, + 0x10EFD, 0x10EFF, + 0x10F46, 0x10F50, + 0x10F82, 0x10F85, + 0x11001, 0x11001, + 0x11038, 0x11046, + 0x11070, 0x11070, + 0x11073, 0x11074, + 0x1107F, 0x11081, + 0x110B3, 0x110B6, + 0x110B9, 0x110BA, + 0x110C2, 0x110C2, + 0x11100, 0x11102, + 0x11127, 0x1112B, + 0x1112D, 0x11134, + 0x11173, 0x11173, + 0x11180, 0x11181, + 0x111B6, 0x111BE, + 0x111C9, 0x111CC, + 0x111CF, 0x111CF, + 0x1122F, 0x11231, + 0x11234, 0x11234, + 0x11236, 0x11237, + 0x1123E, 0x1123E, + 0x11241, 0x11241, + 0x112DF, 0x112DF, + 0x112E3, 0x112EA, + 0x11300, 0x11301, + 0x1133B, 0x1133C, + 0x1133E, 0x1133E, + 0x11340, 0x11340, + 0x11357, 0x11357, + 0x11366, 0x1136C, + 0x11370, 0x11374, + 0x11438, 0x1143F, + 0x11442, 0x11444, + 0x11446, 0x11446, + 0x1145E, 0x1145E, + 0x114B0, 0x114B0, + 0x114B3, 0x114B8, + 0x114BA, 0x114BA, + 0x114BD, 0x114BD, + 0x114BF, 0x114C0, + 0x114C2, 0x114C3, + 0x115AF, 0x115AF, + 0x115B2, 0x115B5, + 0x115BC, 0x115BD, + 0x115BF, 0x115C0, + 0x115DC, 0x115DD, + 0x11633, 0x1163A, + 0x1163D, 0x1163D, + 0x1163F, 0x11640, + 0x116AB, 0x116AB, + 0x116AD, 0x116AD, + 0x116B0, 0x116B5, + 0x116B7, 0x116B7, + 0x1171D, 0x1171F, + 0x11722, 0x11725, + 0x11727, 0x1172B, + 0x1182F, 0x11837, + 0x11839, 0x1183A, + 0x11930, 0x11930, + 0x1193B, 0x1193C, + 0x1193E, 0x1193E, + 0x11943, 0x11943, + 0x119D4, 0x119D7, + 0x119DA, 0x119DB, + 0x119E0, 0x119E0, + 0x11A01, 0x11A0A, + 0x11A33, 0x11A38, + 0x11A3B, 0x11A3E, + 0x11A47, 0x11A47, + 0x11A51, 0x11A56, + 0x11A59, 0x11A5B, + 0x11A8A, 0x11A96, + 0x11A98, 0x11A99, + 0x11C30, 0x11C36, + 0x11C38, 0x11C3D, + 0x11C3F, 0x11C3F, + 0x11C92, 0x11CA7, + 0x11CAA, 0x11CB0, + 0x11CB2, 0x11CB3, + 0x11CB5, 0x11CB6, + 0x11D31, 0x11D36, + 0x11D3A, 0x11D3A, + 0x11D3C, 0x11D3D, + 0x11D3F, 0x11D45, + 0x11D47, 0x11D47, + 0x11D90, 0x11D91, + 0x11D95, 0x11D95, + 0x11D97, 0x11D97, + 0x11EF3, 0x11EF4, + 0x11F00, 0x11F01, + 0x11F36, 0x11F3A, + 0x11F40, 0x11F40, + 0x11F42, 0x11F42, + 0x13440, 0x13440, + 0x13447, 0x13455, + 0x16AF0, 0x16AF4, + 0x16B30, 0x16B36, + 0x16F4F, 0x16F4F, + 0x16F8F, 0x16F92, + 0x16FE4, 0x16FE4, + 0x1BC9D, 0x1BC9E, + 0x1CF00, 0x1CF2D, + 0x1CF30, 0x1CF46, + 0x1D165, 0x1D165, + 0x1D167, 0x1D169, + 0x1D16E, 0x1D172, + 0x1D17B, 0x1D182, + 0x1D185, 0x1D18B, + 0x1D1AA, 0x1D1AD, + 0x1D242, 0x1D244, + 0x1DA00, 0x1DA36, + 0x1DA3B, 0x1DA6C, + 0x1DA75, 0x1DA75, + 0x1DA84, 0x1DA84, + 0x1DA9B, 0x1DA9F, + 0x1DAA1, 0x1DAAF, + 0x1E000, 0x1E006, + 0x1E008, 0x1E018, + 0x1E01B, 0x1E021, + 0x1E023, 0x1E024, + 0x1E026, 0x1E02A, + 0x1E08F, 0x1E08F, + 0x1E130, 0x1E136, + 0x1E2AE, 0x1E2AE, + 0x1E2EC, 0x1E2EF, + 0x1E4EC, 0x1E4EF, + 0x1E8D0, 0x1E8D6, + 0x1E944, 0x1E94A, + 0xE0020, 0xE007F, + 0xE0100, 0xE01EF, +}; + +static const int32_t ucg_hangul_syllable_lv_singlets[] = { + 0xAC00, + 0xAC1C, + 0xAC38, + 0xAC54, + 0xAC70, + 0xAC8C, + 0xACA8, + 0xACC4, + 0xACE0, + 0xACFC, + 0xAD18, + 0xAD34, + 0xAD50, + 0xAD6C, + 0xAD88, + 0xADA4, + 0xADC0, + 0xADDC, + 0xADF8, + 0xAE14, + 0xAE30, + 0xAE4C, + 0xAE68, + 0xAE84, + 0xAEA0, + 0xAEBC, + 0xAED8, + 0xAEF4, + 0xAF10, + 0xAF2C, + 0xAF48, + 0xAF64, + 0xAF80, + 0xAF9C, + 0xAFB8, + 0xAFD4, + 0xAFF0, + 0xB00C, + 0xB028, + 0xB044, + 0xB060, + 0xB07C, + 0xB098, + 0xB0B4, + 0xB0D0, + 0xB0EC, + 0xB108, + 0xB124, + 0xB140, + 0xB15C, + 0xB178, + 0xB194, + 0xB1B0, + 0xB1CC, + 0xB1E8, + 0xB204, + 0xB220, + 0xB23C, + 0xB258, + 0xB274, + 0xB290, + 0xB2AC, + 0xB2C8, + 0xB2E4, + 0xB300, + 0xB31C, + 0xB338, + 0xB354, + 0xB370, + 0xB38C, + 0xB3A8, + 0xB3C4, + 0xB3E0, + 0xB3FC, + 0xB418, + 0xB434, + 0xB450, + 0xB46C, + 0xB488, + 0xB4A4, + 0xB4C0, + 0xB4DC, + 0xB4F8, + 0xB514, + 0xB530, + 0xB54C, + 0xB568, + 0xB584, + 0xB5A0, + 0xB5BC, + 0xB5D8, + 0xB5F4, + 0xB610, + 0xB62C, + 0xB648, + 0xB664, + 0xB680, + 0xB69C, + 0xB6B8, + 0xB6D4, + 0xB6F0, + 0xB70C, + 0xB728, + 0xB744, + 0xB760, + 0xB77C, + 0xB798, + 0xB7B4, + 0xB7D0, + 0xB7EC, + 0xB808, + 0xB824, + 0xB840, + 0xB85C, + 0xB878, + 0xB894, + 0xB8B0, + 0xB8CC, + 0xB8E8, + 0xB904, + 0xB920, + 0xB93C, + 0xB958, + 0xB974, + 0xB990, + 0xB9AC, + 0xB9C8, + 0xB9E4, + 0xBA00, + 0xBA1C, + 0xBA38, + 0xBA54, + 0xBA70, + 0xBA8C, + 0xBAA8, + 0xBAC4, + 0xBAE0, + 0xBAFC, + 0xBB18, + 0xBB34, + 0xBB50, + 0xBB6C, + 0xBB88, + 0xBBA4, + 0xBBC0, + 0xBBDC, + 0xBBF8, + 0xBC14, + 0xBC30, + 0xBC4C, + 0xBC68, + 0xBC84, + 0xBCA0, + 0xBCBC, + 0xBCD8, + 0xBCF4, + 0xBD10, + 0xBD2C, + 0xBD48, + 0xBD64, + 0xBD80, + 0xBD9C, + 0xBDB8, + 0xBDD4, + 0xBDF0, + 0xBE0C, + 0xBE28, + 0xBE44, + 0xBE60, + 0xBE7C, + 0xBE98, + 0xBEB4, + 0xBED0, + 0xBEEC, + 0xBF08, + 0xBF24, + 0xBF40, + 0xBF5C, + 0xBF78, + 0xBF94, + 0xBFB0, + 0xBFCC, + 0xBFE8, + 0xC004, + 0xC020, + 0xC03C, + 0xC058, + 0xC074, + 0xC090, + 0xC0AC, + 0xC0C8, + 0xC0E4, + 0xC100, + 0xC11C, + 0xC138, + 0xC154, + 0xC170, + 0xC18C, + 0xC1A8, + 0xC1C4, + 0xC1E0, + 0xC1FC, + 0xC218, + 0xC234, + 0xC250, + 0xC26C, + 0xC288, + 0xC2A4, + 0xC2C0, + 0xC2DC, + 0xC2F8, + 0xC314, + 0xC330, + 0xC34C, + 0xC368, + 0xC384, + 0xC3A0, + 0xC3BC, + 0xC3D8, + 0xC3F4, + 0xC410, + 0xC42C, + 0xC448, + 0xC464, + 0xC480, + 0xC49C, + 0xC4B8, + 0xC4D4, + 0xC4F0, + 0xC50C, + 0xC528, + 0xC544, + 0xC560, + 0xC57C, + 0xC598, + 0xC5B4, + 0xC5D0, + 0xC5EC, + 0xC608, + 0xC624, + 0xC640, + 0xC65C, + 0xC678, + 0xC694, + 0xC6B0, + 0xC6CC, + 0xC6E8, + 0xC704, + 0xC720, + 0xC73C, + 0xC758, + 0xC774, + 0xC790, + 0xC7AC, + 0xC7C8, + 0xC7E4, + 0xC800, + 0xC81C, + 0xC838, + 0xC854, + 0xC870, + 0xC88C, + 0xC8A8, + 0xC8C4, + 0xC8E0, + 0xC8FC, + 0xC918, + 0xC934, + 0xC950, + 0xC96C, + 0xC988, + 0xC9A4, + 0xC9C0, + 0xC9DC, + 0xC9F8, + 0xCA14, + 0xCA30, + 0xCA4C, + 0xCA68, + 0xCA84, + 0xCAA0, + 0xCABC, + 0xCAD8, + 0xCAF4, + 0xCB10, + 0xCB2C, + 0xCB48, + 0xCB64, + 0xCB80, + 0xCB9C, + 0xCBB8, + 0xCBD4, + 0xCBF0, + 0xCC0C, + 0xCC28, + 0xCC44, + 0xCC60, + 0xCC7C, + 0xCC98, + 0xCCB4, + 0xCCD0, + 0xCCEC, + 0xCD08, + 0xCD24, + 0xCD40, + 0xCD5C, + 0xCD78, + 0xCD94, + 0xCDB0, + 0xCDCC, + 0xCDE8, + 0xCE04, + 0xCE20, + 0xCE3C, + 0xCE58, + 0xCE74, + 0xCE90, + 0xCEAC, + 0xCEC8, + 0xCEE4, + 0xCF00, + 0xCF1C, + 0xCF38, + 0xCF54, + 0xCF70, + 0xCF8C, + 0xCFA8, + 0xCFC4, + 0xCFE0, + 0xCFFC, + 0xD018, + 0xD034, + 0xD050, + 0xD06C, + 0xD088, + 0xD0A4, + 0xD0C0, + 0xD0DC, + 0xD0F8, + 0xD114, + 0xD130, + 0xD14C, + 0xD168, + 0xD184, + 0xD1A0, + 0xD1BC, + 0xD1D8, + 0xD1F4, + 0xD210, + 0xD22C, + 0xD248, + 0xD264, + 0xD280, + 0xD29C, + 0xD2B8, + 0xD2D4, + 0xD2F0, + 0xD30C, + 0xD328, + 0xD344, + 0xD360, + 0xD37C, + 0xD398, + 0xD3B4, + 0xD3D0, + 0xD3EC, + 0xD408, + 0xD424, + 0xD440, + 0xD45C, + 0xD478, + 0xD494, + 0xD4B0, + 0xD4CC, + 0xD4E8, + 0xD504, + 0xD520, + 0xD53C, + 0xD558, + 0xD574, + 0xD590, + 0xD5AC, + 0xD5C8, + 0xD5E4, + 0xD600, + 0xD61C, + 0xD638, + 0xD654, + 0xD670, + 0xD68C, + 0xD6A8, + 0xD6C4, + 0xD6E0, + 0xD6FC, + 0xD718, + 0xD734, + 0xD750, + 0xD76C, + 0xD788, +}; + +static const int32_t ucg_hangul_syllable_lvt_ranges[] = { + 0xAC01, 0xAC1B, + 0xAC1D, 0xAC37, + 0xAC39, 0xAC53, + 0xAC55, 0xAC6F, + 0xAC71, 0xAC8B, + 0xAC8D, 0xACA7, + 0xACA9, 0xACC3, + 0xACC5, 0xACDF, + 0xACE1, 0xACFB, + 0xACFD, 0xAD17, + 0xAD19, 0xAD33, + 0xAD35, 0xAD4F, + 0xAD51, 0xAD6B, + 0xAD6D, 0xAD87, + 0xAD89, 0xADA3, + 0xADA5, 0xADBF, + 0xADC1, 0xADDB, + 0xADDD, 0xADF7, + 0xADF9, 0xAE13, + 0xAE15, 0xAE2F, + 0xAE31, 0xAE4B, + 0xAE4D, 0xAE67, + 0xAE69, 0xAE83, + 0xAE85, 0xAE9F, + 0xAEA1, 0xAEBB, + 0xAEBD, 0xAED7, + 0xAED9, 0xAEF3, + 0xAEF5, 0xAF0F, + 0xAF11, 0xAF2B, + 0xAF2D, 0xAF47, + 0xAF49, 0xAF63, + 0xAF65, 0xAF7F, + 0xAF81, 0xAF9B, + 0xAF9D, 0xAFB7, + 0xAFB9, 0xAFD3, + 0xAFD5, 0xAFEF, + 0xAFF1, 0xB00B, + 0xB00D, 0xB027, + 0xB029, 0xB043, + 0xB045, 0xB05F, + 0xB061, 0xB07B, + 0xB07D, 0xB097, + 0xB099, 0xB0B3, + 0xB0B5, 0xB0CF, + 0xB0D1, 0xB0EB, + 0xB0ED, 0xB107, + 0xB109, 0xB123, + 0xB125, 0xB13F, + 0xB141, 0xB15B, + 0xB15D, 0xB177, + 0xB179, 0xB193, + 0xB195, 0xB1AF, + 0xB1B1, 0xB1CB, + 0xB1CD, 0xB1E7, + 0xB1E9, 0xB203, + 0xB205, 0xB21F, + 0xB221, 0xB23B, + 0xB23D, 0xB257, + 0xB259, 0xB273, + 0xB275, 0xB28F, + 0xB291, 0xB2AB, + 0xB2AD, 0xB2C7, + 0xB2C9, 0xB2E3, + 0xB2E5, 0xB2FF, + 0xB301, 0xB31B, + 0xB31D, 0xB337, + 0xB339, 0xB353, + 0xB355, 0xB36F, + 0xB371, 0xB38B, + 0xB38D, 0xB3A7, + 0xB3A9, 0xB3C3, + 0xB3C5, 0xB3DF, + 0xB3E1, 0xB3FB, + 0xB3FD, 0xB417, + 0xB419, 0xB433, + 0xB435, 0xB44F, + 0xB451, 0xB46B, + 0xB46D, 0xB487, + 0xB489, 0xB4A3, + 0xB4A5, 0xB4BF, + 0xB4C1, 0xB4DB, + 0xB4DD, 0xB4F7, + 0xB4F9, 0xB513, + 0xB515, 0xB52F, + 0xB531, 0xB54B, + 0xB54D, 0xB567, + 0xB569, 0xB583, + 0xB585, 0xB59F, + 0xB5A1, 0xB5BB, + 0xB5BD, 0xB5D7, + 0xB5D9, 0xB5F3, + 0xB5F5, 0xB60F, + 0xB611, 0xB62B, + 0xB62D, 0xB647, + 0xB649, 0xB663, + 0xB665, 0xB67F, + 0xB681, 0xB69B, + 0xB69D, 0xB6B7, + 0xB6B9, 0xB6D3, + 0xB6D5, 0xB6EF, + 0xB6F1, 0xB70B, + 0xB70D, 0xB727, + 0xB729, 0xB743, + 0xB745, 0xB75F, + 0xB761, 0xB77B, + 0xB77D, 0xB797, + 0xB799, 0xB7B3, + 0xB7B5, 0xB7CF, + 0xB7D1, 0xB7EB, + 0xB7ED, 0xB807, + 0xB809, 0xB823, + 0xB825, 0xB83F, + 0xB841, 0xB85B, + 0xB85D, 0xB877, + 0xB879, 0xB893, + 0xB895, 0xB8AF, + 0xB8B1, 0xB8CB, + 0xB8CD, 0xB8E7, + 0xB8E9, 0xB903, + 0xB905, 0xB91F, + 0xB921, 0xB93B, + 0xB93D, 0xB957, + 0xB959, 0xB973, + 0xB975, 0xB98F, + 0xB991, 0xB9AB, + 0xB9AD, 0xB9C7, + 0xB9C9, 0xB9E3, + 0xB9E5, 0xB9FF, + 0xBA01, 0xBA1B, + 0xBA1D, 0xBA37, + 0xBA39, 0xBA53, + 0xBA55, 0xBA6F, + 0xBA71, 0xBA8B, + 0xBA8D, 0xBAA7, + 0xBAA9, 0xBAC3, + 0xBAC5, 0xBADF, + 0xBAE1, 0xBAFB, + 0xBAFD, 0xBB17, + 0xBB19, 0xBB33, + 0xBB35, 0xBB4F, + 0xBB51, 0xBB6B, + 0xBB6D, 0xBB87, + 0xBB89, 0xBBA3, + 0xBBA5, 0xBBBF, + 0xBBC1, 0xBBDB, + 0xBBDD, 0xBBF7, + 0xBBF9, 0xBC13, + 0xBC15, 0xBC2F, + 0xBC31, 0xBC4B, + 0xBC4D, 0xBC67, + 0xBC69, 0xBC83, + 0xBC85, 0xBC9F, + 0xBCA1, 0xBCBB, + 0xBCBD, 0xBCD7, + 0xBCD9, 0xBCF3, + 0xBCF5, 0xBD0F, + 0xBD11, 0xBD2B, + 0xBD2D, 0xBD47, + 0xBD49, 0xBD63, + 0xBD65, 0xBD7F, + 0xBD81, 0xBD9B, + 0xBD9D, 0xBDB7, + 0xBDB9, 0xBDD3, + 0xBDD5, 0xBDEF, + 0xBDF1, 0xBE0B, + 0xBE0D, 0xBE27, + 0xBE29, 0xBE43, + 0xBE45, 0xBE5F, + 0xBE61, 0xBE7B, + 0xBE7D, 0xBE97, + 0xBE99, 0xBEB3, + 0xBEB5, 0xBECF, + 0xBED1, 0xBEEB, + 0xBEED, 0xBF07, + 0xBF09, 0xBF23, + 0xBF25, 0xBF3F, + 0xBF41, 0xBF5B, + 0xBF5D, 0xBF77, + 0xBF79, 0xBF93, + 0xBF95, 0xBFAF, + 0xBFB1, 0xBFCB, + 0xBFCD, 0xBFE7, + 0xBFE9, 0xC003, + 0xC005, 0xC01F, + 0xC021, 0xC03B, + 0xC03D, 0xC057, + 0xC059, 0xC073, + 0xC075, 0xC08F, + 0xC091, 0xC0AB, + 0xC0AD, 0xC0C7, + 0xC0C9, 0xC0E3, + 0xC0E5, 0xC0FF, + 0xC101, 0xC11B, + 0xC11D, 0xC137, + 0xC139, 0xC153, + 0xC155, 0xC16F, + 0xC171, 0xC18B, + 0xC18D, 0xC1A7, + 0xC1A9, 0xC1C3, + 0xC1C5, 0xC1DF, + 0xC1E1, 0xC1FB, + 0xC1FD, 0xC217, + 0xC219, 0xC233, + 0xC235, 0xC24F, + 0xC251, 0xC26B, + 0xC26D, 0xC287, + 0xC289, 0xC2A3, + 0xC2A5, 0xC2BF, + 0xC2C1, 0xC2DB, + 0xC2DD, 0xC2F7, + 0xC2F9, 0xC313, + 0xC315, 0xC32F, + 0xC331, 0xC34B, + 0xC34D, 0xC367, + 0xC369, 0xC383, + 0xC385, 0xC39F, + 0xC3A1, 0xC3BB, + 0xC3BD, 0xC3D7, + 0xC3D9, 0xC3F3, + 0xC3F5, 0xC40F, + 0xC411, 0xC42B, + 0xC42D, 0xC447, + 0xC449, 0xC463, + 0xC465, 0xC47F, + 0xC481, 0xC49B, + 0xC49D, 0xC4B7, + 0xC4B9, 0xC4D3, + 0xC4D5, 0xC4EF, + 0xC4F1, 0xC50B, + 0xC50D, 0xC527, + 0xC529, 0xC543, + 0xC545, 0xC55F, + 0xC561, 0xC57B, + 0xC57D, 0xC597, + 0xC599, 0xC5B3, + 0xC5B5, 0xC5CF, + 0xC5D1, 0xC5EB, + 0xC5ED, 0xC607, + 0xC609, 0xC623, + 0xC625, 0xC63F, + 0xC641, 0xC65B, + 0xC65D, 0xC677, + 0xC679, 0xC693, + 0xC695, 0xC6AF, + 0xC6B1, 0xC6CB, + 0xC6CD, 0xC6E7, + 0xC6E9, 0xC703, + 0xC705, 0xC71F, + 0xC721, 0xC73B, + 0xC73D, 0xC757, + 0xC759, 0xC773, + 0xC775, 0xC78F, + 0xC791, 0xC7AB, + 0xC7AD, 0xC7C7, + 0xC7C9, 0xC7E3, + 0xC7E5, 0xC7FF, + 0xC801, 0xC81B, + 0xC81D, 0xC837, + 0xC839, 0xC853, + 0xC855, 0xC86F, + 0xC871, 0xC88B, + 0xC88D, 0xC8A7, + 0xC8A9, 0xC8C3, + 0xC8C5, 0xC8DF, + 0xC8E1, 0xC8FB, + 0xC8FD, 0xC917, + 0xC919, 0xC933, + 0xC935, 0xC94F, + 0xC951, 0xC96B, + 0xC96D, 0xC987, + 0xC989, 0xC9A3, + 0xC9A5, 0xC9BF, + 0xC9C1, 0xC9DB, + 0xC9DD, 0xC9F7, + 0xC9F9, 0xCA13, + 0xCA15, 0xCA2F, + 0xCA31, 0xCA4B, + 0xCA4D, 0xCA67, + 0xCA69, 0xCA83, + 0xCA85, 0xCA9F, + 0xCAA1, 0xCABB, + 0xCABD, 0xCAD7, + 0xCAD9, 0xCAF3, + 0xCAF5, 0xCB0F, + 0xCB11, 0xCB2B, + 0xCB2D, 0xCB47, + 0xCB49, 0xCB63, + 0xCB65, 0xCB7F, + 0xCB81, 0xCB9B, + 0xCB9D, 0xCBB7, + 0xCBB9, 0xCBD3, + 0xCBD5, 0xCBEF, + 0xCBF1, 0xCC0B, + 0xCC0D, 0xCC27, + 0xCC29, 0xCC43, + 0xCC45, 0xCC5F, + 0xCC61, 0xCC7B, + 0xCC7D, 0xCC97, + 0xCC99, 0xCCB3, + 0xCCB5, 0xCCCF, + 0xCCD1, 0xCCEB, + 0xCCED, 0xCD07, + 0xCD09, 0xCD23, + 0xCD25, 0xCD3F, + 0xCD41, 0xCD5B, + 0xCD5D, 0xCD77, + 0xCD79, 0xCD93, + 0xCD95, 0xCDAF, + 0xCDB1, 0xCDCB, + 0xCDCD, 0xCDE7, + 0xCDE9, 0xCE03, + 0xCE05, 0xCE1F, + 0xCE21, 0xCE3B, + 0xCE3D, 0xCE57, + 0xCE59, 0xCE73, + 0xCE75, 0xCE8F, + 0xCE91, 0xCEAB, + 0xCEAD, 0xCEC7, + 0xCEC9, 0xCEE3, + 0xCEE5, 0xCEFF, + 0xCF01, 0xCF1B, + 0xCF1D, 0xCF37, + 0xCF39, 0xCF53, + 0xCF55, 0xCF6F, + 0xCF71, 0xCF8B, + 0xCF8D, 0xCFA7, + 0xCFA9, 0xCFC3, + 0xCFC5, 0xCFDF, + 0xCFE1, 0xCFFB, + 0xCFFD, 0xD017, + 0xD019, 0xD033, + 0xD035, 0xD04F, + 0xD051, 0xD06B, + 0xD06D, 0xD087, + 0xD089, 0xD0A3, + 0xD0A5, 0xD0BF, + 0xD0C1, 0xD0DB, + 0xD0DD, 0xD0F7, + 0xD0F9, 0xD113, + 0xD115, 0xD12F, + 0xD131, 0xD14B, + 0xD14D, 0xD167, + 0xD169, 0xD183, + 0xD185, 0xD19F, + 0xD1A1, 0xD1BB, + 0xD1BD, 0xD1D7, + 0xD1D9, 0xD1F3, + 0xD1F5, 0xD20F, + 0xD211, 0xD22B, + 0xD22D, 0xD247, + 0xD249, 0xD263, + 0xD265, 0xD27F, + 0xD281, 0xD29B, + 0xD29D, 0xD2B7, + 0xD2B9, 0xD2D3, + 0xD2D5, 0xD2EF, + 0xD2F1, 0xD30B, + 0xD30D, 0xD327, + 0xD329, 0xD343, + 0xD345, 0xD35F, + 0xD361, 0xD37B, + 0xD37D, 0xD397, + 0xD399, 0xD3B3, + 0xD3B5, 0xD3CF, + 0xD3D1, 0xD3EB, + 0xD3ED, 0xD407, + 0xD409, 0xD423, + 0xD425, 0xD43F, + 0xD441, 0xD45B, + 0xD45D, 0xD477, + 0xD479, 0xD493, + 0xD495, 0xD4AF, + 0xD4B1, 0xD4CB, + 0xD4CD, 0xD4E7, + 0xD4E9, 0xD503, + 0xD505, 0xD51F, + 0xD521, 0xD53B, + 0xD53D, 0xD557, + 0xD559, 0xD573, + 0xD575, 0xD58F, + 0xD591, 0xD5AB, + 0xD5AD, 0xD5C7, + 0xD5C9, 0xD5E3, + 0xD5E5, 0xD5FF, + 0xD601, 0xD61B, + 0xD61D, 0xD637, + 0xD639, 0xD653, + 0xD655, 0xD66F, + 0xD671, 0xD68B, + 0xD68D, 0xD6A7, + 0xD6A9, 0xD6C3, + 0xD6C5, 0xD6DF, + 0xD6E1, 0xD6FB, + 0xD6FD, 0xD717, + 0xD719, 0xD733, + 0xD735, 0xD74F, + 0xD751, 0xD76B, + 0xD76D, 0xD787, + 0xD789, 0xD7A3, +}; + +static const int32_t ucg_indic_conjunct_break_consonant_ranges[] = { + 0x0915, 0x0939, + 0x0958, 0x095F, + 0x0978, 0x097F, + 0x0995, 0x09A8, + 0x09AA, 0x09B0, + 0x09B2, 0x09B2, + 0x09B6, 0x09B9, + 0x09DC, 0x09DD, + 0x09DF, 0x09DF, + 0x09F0, 0x09F1, + 0x0A95, 0x0AA8, + 0x0AAA, 0x0AB0, + 0x0AB2, 0x0AB3, + 0x0AB5, 0x0AB9, + 0x0AF9, 0x0AF9, + 0x0B15, 0x0B28, + 0x0B2A, 0x0B30, + 0x0B32, 0x0B33, + 0x0B35, 0x0B39, + 0x0B5C, 0x0B5D, + 0x0B5F, 0x0B5F, + 0x0B71, 0x0B71, + 0x0C15, 0x0C28, + 0x0C2A, 0x0C39, + 0x0C58, 0x0C5A, + 0x0D15, 0x0D3A, +}; + +static const int32_t ucg_indic_conjunct_break_extend_ranges[] = { + 0x0300, 0x034E, + 0x0350, 0x036F, + 0x0483, 0x0487, + 0x0591, 0x05BD, + 0x05BF, 0x05BF, + 0x05C1, 0x05C2, + 0x05C4, 0x05C5, + 0x05C7, 0x05C7, + 0x0610, 0x061A, + 0x064B, 0x065F, + 0x0670, 0x0670, + 0x06D6, 0x06DC, + 0x06DF, 0x06E4, + 0x06E7, 0x06E8, + 0x06EA, 0x06ED, + 0x0711, 0x0711, + 0x0730, 0x074A, + 0x07EB, 0x07F3, + 0x07FD, 0x07FD, + 0x0816, 0x0819, + 0x081B, 0x0823, + 0x0825, 0x0827, + 0x0829, 0x082D, + 0x0859, 0x085B, + 0x0898, 0x089F, + 0x08CA, 0x08E1, + 0x08E3, 0x08FF, + 0x093C, 0x093C, + 0x0951, 0x0954, + 0x09BC, 0x09BC, + 0x09FE, 0x09FE, + 0x0A3C, 0x0A3C, + 0x0ABC, 0x0ABC, + 0x0B3C, 0x0B3C, + 0x0C3C, 0x0C3C, + 0x0C55, 0x0C56, + 0x0CBC, 0x0CBC, + 0x0D3B, 0x0D3C, + 0x0E38, 0x0E3A, + 0x0E48, 0x0E4B, + 0x0EB8, 0x0EBA, + 0x0EC8, 0x0ECB, + 0x0F18, 0x0F19, + 0x0F35, 0x0F35, + 0x0F37, 0x0F37, + 0x0F39, 0x0F39, + 0x0F71, 0x0F72, + 0x0F74, 0x0F74, + 0x0F7A, 0x0F7D, + 0x0F80, 0x0F80, + 0x0F82, 0x0F84, + 0x0F86, 0x0F87, + 0x0FC6, 0x0FC6, + 0x1037, 0x1037, + 0x1039, 0x103A, + 0x108D, 0x108D, + 0x135D, 0x135F, + 0x1714, 0x1714, + 0x17D2, 0x17D2, + 0x17DD, 0x17DD, + 0x18A9, 0x18A9, + 0x1939, 0x193B, + 0x1A17, 0x1A18, + 0x1A60, 0x1A60, + 0x1A75, 0x1A7C, + 0x1A7F, 0x1A7F, + 0x1AB0, 0x1ABD, + 0x1ABF, 0x1ACE, + 0x1B34, 0x1B34, + 0x1B6B, 0x1B73, + 0x1BAB, 0x1BAB, + 0x1BE6, 0x1BE6, + 0x1C37, 0x1C37, + 0x1CD0, 0x1CD2, + 0x1CD4, 0x1CE0, + 0x1CE2, 0x1CE8, + 0x1CED, 0x1CED, + 0x1CF4, 0x1CF4, + 0x1CF8, 0x1CF9, + 0x1DC0, 0x1DFF, + 0x200D, 0x200D, + 0x20D0, 0x20DC, + 0x20E1, 0x20E1, + 0x20E5, 0x20F0, + 0x2CEF, 0x2CF1, + 0x2D7F, 0x2D7F, + 0x2DE0, 0x2DFF, + 0x302A, 0x302D, + 0x302E, 0x302F, + 0x3099, 0x309A, + 0xA66F, 0xA66F, + 0xA674, 0xA67D, + 0xA69E, 0xA69F, + 0xA6F0, 0xA6F1, + 0xA82C, 0xA82C, + 0xA8E0, 0xA8F1, + 0xA92B, 0xA92D, + 0xA9B3, 0xA9B3, + 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, + 0xAAB7, 0xAAB8, + 0xAABE, 0xAABF, + 0xAAC1, 0xAAC1, + 0xAAF6, 0xAAF6, + 0xABED, 0xABED, + 0xFB1E, 0xFB1E, + 0xFE20, 0xFE2F, + 0x101FD, 0x101FD, + 0x102E0, 0x102E0, + 0x10376, 0x1037A, + 0x10A0D, 0x10A0D, + 0x10A0F, 0x10A0F, + 0x10A38, 0x10A3A, + 0x10A3F, 0x10A3F, + 0x10AE5, 0x10AE6, + 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, + 0x10EFD, 0x10EFF, + 0x10F46, 0x10F50, + 0x10F82, 0x10F85, + 0x11070, 0x11070, + 0x1107F, 0x1107F, + 0x110BA, 0x110BA, + 0x11100, 0x11102, + 0x11133, 0x11134, + 0x11173, 0x11173, + 0x111CA, 0x111CA, + 0x11236, 0x11236, + 0x112E9, 0x112EA, + 0x1133B, 0x1133C, + 0x11366, 0x1136C, + 0x11370, 0x11374, + 0x11446, 0x11446, + 0x1145E, 0x1145E, + 0x114C3, 0x114C3, + 0x115C0, 0x115C0, + 0x116B7, 0x116B7, + 0x1172B, 0x1172B, + 0x1183A, 0x1183A, + 0x1193E, 0x1193E, + 0x11943, 0x11943, + 0x11A34, 0x11A34, + 0x11A47, 0x11A47, + 0x11A99, 0x11A99, + 0x11D42, 0x11D42, + 0x11D44, 0x11D45, + 0x11D97, 0x11D97, + 0x11F42, 0x11F42, + 0x16AF0, 0x16AF4, + 0x16B30, 0x16B36, + 0x1BC9E, 0x1BC9E, + 0x1D165, 0x1D165, + 0x1D167, 0x1D169, + 0x1D16E, 0x1D172, + 0x1D17B, 0x1D182, + 0x1D185, 0x1D18B, + 0x1D1AA, 0x1D1AD, + 0x1D242, 0x1D244, + 0x1E000, 0x1E006, + 0x1E008, 0x1E018, + 0x1E01B, 0x1E021, + 0x1E023, 0x1E024, + 0x1E026, 0x1E02A, + 0x1E08F, 0x1E08F, + 0x1E130, 0x1E136, + 0x1E2AE, 0x1E2AE, + 0x1E2EC, 0x1E2EF, + 0x1E4EC, 0x1E4EF, + 0x1E8D0, 0x1E8D6, + 0x1E944, 0x1E94A, +}; + +// Fullwidth (F) and Wide (W) are counted as 2. +// Everything else is 1. +// +// Derived from: https://unicode.org/Public/15.1.0/ucd/EastAsianWidth.txt +static const int32_t ucg_normalized_east_asian_width_ranges[] = { + 0x0000, 0x10FF, 1, + 0x1100, 0x115F, 2, + 0x1160, 0x2319, 1, + 0x231A, 0x231B, 2, + 0x231C, 0x2328, 1, + 0x2329, 0x232A, 2, + 0x232B, 0x23E8, 1, + 0x23E9, 0x23EC, 2, + 0x23ED, 0x23EF, 1, + 0x23F0, 0x23F0, 2, + 0x23F1, 0x23F2, 1, + 0x23F3, 0x23F3, 2, + 0x23F4, 0x25FC, 1, + 0x25FD, 0x25FE, 2, + 0x25FF, 0x2613, 1, + 0x2614, 0x2615, 2, + 0x2616, 0x2647, 1, + 0x2648, 0x2653, 2, + 0x2654, 0x267E, 1, + 0x267F, 0x267F, 2, + 0x2680, 0x2692, 1, + 0x2693, 0x2693, 2, + 0x2694, 0x26A0, 1, + 0x26A1, 0x26A1, 2, + 0x26A2, 0x26A9, 1, + 0x26AA, 0x26AB, 2, + 0x26AC, 0x26BC, 1, + 0x26BD, 0x26BE, 2, + 0x26BF, 0x26C3, 1, + 0x26C4, 0x26C5, 2, + 0x26C6, 0x26CD, 1, + 0x26CE, 0x26CE, 2, + 0x26CF, 0x26D3, 1, + 0x26D4, 0x26D4, 2, + 0x26D5, 0x26E9, 1, + 0x26EA, 0x26EA, 2, + 0x26EB, 0x26F1, 1, + 0x26F2, 0x26F3, 2, + 0x26F4, 0x26F4, 1, + 0x26F5, 0x26F5, 2, + 0x26F6, 0x26F9, 1, + 0x26FA, 0x26FA, 2, + 0x26FB, 0x26FC, 1, + 0x26FD, 0x26FD, 2, + 0x26FE, 0x2704, 1, + 0x2705, 0x2705, 2, + 0x2706, 0x2709, 1, + 0x270A, 0x270B, 2, + 0x270C, 0x2727, 1, + 0x2728, 0x2728, 2, + 0x2729, 0x274B, 1, + 0x274C, 0x274C, 2, + 0x274D, 0x274D, 1, + 0x274E, 0x274E, 2, + 0x274F, 0x2752, 1, + 0x2753, 0x2755, 2, + 0x2756, 0x2756, 1, + 0x2757, 0x2757, 2, + 0x2758, 0x2794, 1, + 0x2795, 0x2797, 2, + 0x2798, 0x27AF, 1, + 0x27B0, 0x27B0, 2, + 0x27B1, 0x27BE, 1, + 0x27BF, 0x27BF, 2, + 0x27C0, 0x2B1A, 1, + 0x2B1B, 0x2B1C, 2, + 0x2B1D, 0x2B4F, 1, + 0x2B50, 0x2B50, 2, + 0x2B51, 0x2B54, 1, + 0x2B55, 0x2B55, 2, + 0x2B56, 0x2E5D, 1, + 0x2E80, 0x303E, 2, + 0x303F, 0x303F, 1, + 0x3041, 0x3247, 2, + 0x3248, 0x324F, 1, + 0x3250, 0x4DBF, 2, + 0x4DC0, 0x4DFF, 1, + 0x4E00, 0xA4C6, 2, + 0xA4D0, 0xA95F, 1, + 0xA960, 0xA97C, 2, + 0xA980, 0xABF9, 1, + 0xAC00, 0xD7A3, 2, + 0xD7B0, 0xF8FF, 1, + 0xF900, 0xFAFF, 2, + 0xFB00, 0xFE0F, 1, + 0xFE10, 0xFE19, 2, + 0xFE20, 0xFE2F, 1, + 0xFE30, 0xFE6B, 2, + 0xFE70, 0xFEFF, 1, + 0xFF01, 0xFF60, 2, + 0xFF61, 0xFFDC, 1, + 0xFFE0, 0xFFE6, 2, + 0xFFE8, 0x16F9F, 1, + 0x16FE0, 0x1B2FB, 2, + 0x1BC00, 0x1F003, 1, + 0x1F004, 0x1F004, 2, + 0x1F005, 0x1F0CE, 1, + 0x1F0CF, 0x1F0CF, 2, + 0x1F0D1, 0x1F18D, 1, + 0x1F18E, 0x1F18E, 2, + 0x1F18F, 0x1F190, 1, + 0x1F191, 0x1F19A, 2, + 0x1F19B, 0x1F1FF, 1, + 0x1F200, 0x1F320, 2, + 0x1F321, 0x1F32C, 1, + 0x1F32D, 0x1F335, 2, + 0x1F336, 0x1F336, 1, + 0x1F337, 0x1F37C, 2, + 0x1F37D, 0x1F37D, 1, + 0x1F37E, 0x1F393, 2, + 0x1F394, 0x1F39F, 1, + 0x1F3A0, 0x1F3CA, 2, + 0x1F3CB, 0x1F3CE, 1, + 0x1F3CF, 0x1F3D3, 2, + 0x1F3D4, 0x1F3DF, 1, + 0x1F3E0, 0x1F3F0, 2, + 0x1F3F1, 0x1F3F3, 1, + 0x1F3F4, 0x1F3F4, 2, + 0x1F3F5, 0x1F3F7, 1, + 0x1F3F8, 0x1F43E, 2, + 0x1F43F, 0x1F43F, 1, + 0x1F440, 0x1F440, 2, + 0x1F441, 0x1F441, 1, + 0x1F442, 0x1F4FC, 2, + 0x1F4FD, 0x1F4FE, 1, + 0x1F4FF, 0x1F53D, 2, + 0x1F53E, 0x1F54A, 1, + 0x1F54B, 0x1F54E, 2, + 0x1F54F, 0x1F54F, 1, + 0x1F550, 0x1F567, 2, + 0x1F568, 0x1F579, 1, + 0x1F57A, 0x1F57A, 2, + 0x1F57B, 0x1F594, 1, + 0x1F595, 0x1F596, 2, + 0x1F597, 0x1F5A3, 1, + 0x1F5A4, 0x1F5A4, 2, + 0x1F5A5, 0x1F5FA, 1, + 0x1F5FB, 0x1F64F, 2, + 0x1F650, 0x1F67F, 1, + 0x1F680, 0x1F6C5, 2, + 0x1F6C6, 0x1F6CB, 1, + 0x1F6CC, 0x1F6CC, 2, + 0x1F6CD, 0x1F6CF, 1, + 0x1F6D0, 0x1F6D2, 2, + 0x1F6D3, 0x1F6D4, 1, + 0x1F6D5, 0x1F6DF, 2, + 0x1F6E0, 0x1F6EA, 1, + 0x1F6EB, 0x1F6EC, 2, + 0x1F6F0, 0x1F6F3, 1, + 0x1F6F4, 0x1F6FC, 2, + 0x1F700, 0x1F7D9, 1, + 0x1F7E0, 0x1F7F0, 2, + 0x1F800, 0x1F90B, 1, + 0x1F90C, 0x1F93A, 2, + 0x1F93B, 0x1F93B, 1, + 0x1F93C, 0x1F945, 2, + 0x1F946, 0x1F946, 1, + 0x1F947, 0x1F9FF, 2, + 0x1FA00, 0x1FA6D, 1, + 0x1FA70, 0x1FAF8, 2, + 0x1FB00, 0x1FBF9, 1, + 0x20000, 0x3FFFD, 2, + 0xE0001, 0x10FFFD, 1, +}; + +// +// End of Unicode 15.1.0 block. +// + +#ifdef __cplusplus +} +#endif + +#endif /* _UCG_TABLES_INCLUDED */ diff --git a/src/unicode.cpp b/src/unicode.cpp index c244a323c..665d5b182 100644 --- a/src/unicode.cpp +++ b/src/unicode.cpp @@ -162,3 +162,8 @@ end: if (codepoint_out) *codepoint_out = codepoint; return width; } + +// NOTE(Feoramund): It's down here because I made UCG use the utf8_decode above to avoid duplicating code. +extern "C" { +#include "ucg/ucg.c" +} diff --git a/tests/core/container/test_core_avl.odin b/tests/core/container/test_core_avl.odin index 99dbba8b2..0e2d0d94a 100644 --- a/tests/core/container/test_core_avl.odin +++ b/tests/core/container/test_core_avl.odin @@ -20,15 +20,12 @@ test_avl :: proc(t: ^testing.T) { iter := avl.iterator(&tree, avl.Direction.Forward) testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") - r: rand.Rand - rand.init(&r, t.seed) - // Test insertion. NR_INSERTS :: 32 + 1 // Ensure at least 1 collision. inserted_map := make(map[int]^avl.Node(int)) defer delete(inserted_map) for i := 0; i < NR_INSERTS; i += 1 { - v := int(rand.uint32(&r) & 0x1f) + v := int(rand.uint32() & 0x1f) existing_node, in_map := inserted_map[v] n, ok, _ := avl.find_or_insert(&tree, v) @@ -78,7 +75,7 @@ test_avl :: proc(t: ^testing.T) { testing.expect(t, visited == nrEntries, "iterator/backward: visited") // Test removal. - rand.shuffle(inserted_values[:], &r) + rand.shuffle(inserted_values[:]) for v, i in inserted_values { node := avl.find(&tree, v) testing.expect(t, node != nil, "remove: find (pre)") diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin index 8def8edb6..b686ef6dd 100644 --- a/tests/core/container/test_core_rbtree.odin +++ b/tests/core/container/test_core_rbtree.odin @@ -14,9 +14,6 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { defer mem.tracking_allocator_destroy(&track) context.allocator = mem.tracking_allocator(&track) - r: rand.Rand - rand.init(&r, t.seed) - log.infof("Testing Red-Black Tree($Key=%v,$Value=%v) using random seed %v.", type_info_of(Key), type_info_of(Value), t.seed) tree: rb.Tree(Key, Value) rb.init(&tree) @@ -35,9 +32,9 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { max_key := min(Key) for i := 0; i < NR_INSERTS; i += 1 { - k := Key(rand.uint32(&r)) & 0x1f + k := Key(rand.uint32()) & 0x1f min_key = min(min_key, k); max_key = max(max_key, k) - v := Value(rand.uint32(&r)) + v := Value(rand.uint32()) existing_node, in_map := inserted_map[k] n, inserted, _ := rb.find_or_insert(&tree, k, v) @@ -92,7 +89,7 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { testing.expect(t, visited == entry_count, "iterator/backward: visited") // Test removal (and on_remove callback) - rand.shuffle(inserted_keys[:], &r) + rand.shuffle(inserted_keys[:]) callback_count := entry_count tree.user_data = &callback_count tree.on_remove = proc(key: Key, value: Value, user_data: rawptr) { diff --git a/tests/core/encoding/hxa/test_core_hxa.odin b/tests/core/encoding/hxa/test_core_hxa.odin index 31d40c8b3..a8f3e94f6 100644 --- a/tests/core/encoding/hxa/test_core_hxa.odin +++ b/tests/core/encoding/hxa/test_core_hxa.odin @@ -134,14 +134,11 @@ test_write :: proc(t: ^testing.T) { testing.expectf(t, read_err == read_e, fmt.tprintf("read_err %v != %v", read_err, read_e)) defer hxa.file_destroy(file) - testing.expectf(t, file.magic_number == 0x417848, fmt.tprintf("file.magic_number %v != %v", - file.magic_number, 0x417848)) + testing.expectf(t, file.magic_number == 0x417848, fmt.tprintf("file.magic_number %v != %v", file.magic_number, 0x417848)) testing.expectf(t, file.version == 3, fmt.tprintf("file.version %v != %v", file.version, 3)) - testing.expectf(t, file.internal_node_count == 1, fmt.tprintf("file.internal_node_count %v != %v", - file.internal_node_count, 1)) + testing.expectf(t, file.internal_node_count == 1, fmt.tprintf("file.internal_node_count %v != %v", file.internal_node_count, 1)) - testing.expectf(t, len(file.nodes) == len(w_file.nodes), fmt.tprintf("len(file.nodes) %v != %v", - len(file.nodes), len(w_file.nodes))) + testing.expectf(t, len(file.nodes) == len(w_file.nodes), fmt.tprintf("len(file.nodes) %v != %v", len(file.nodes), len(w_file.nodes))) m := &file.nodes[0].meta_data w_m := &w_file.nodes[0].meta_data @@ -150,20 +147,16 @@ test_write :: proc(t: ^testing.T) { m_v, m_v_ok := m[0].value.([]f64le) testing.expectf(t, m_v_ok, fmt.tprintf("m_v_ok %v != %v", m_v_ok, true)) - testing.expectf(t, len(m_v) == len(n1_m1_value), fmt.tprintf("%v != len(m_v) %v", - len(m_v), len(n1_m1_value))) + testing.expectf(t, len(m_v) == len(n1_m1_value), fmt.tprintf("%v != len(m_v) %v", len(m_v), len(n1_m1_value))) for i := 0; i < len(m_v); i += 1 { - testing.expectf(t, m_v[i] == n1_m1_value[i], fmt.tprintf("m_v[%d] %v != %v", - i, m_v[i], n1_m1_value[i])) + testing.expectf(t, m_v[i] == n1_m1_value[i], fmt.tprintf("m_v[%d] %v != %v", i, m_v[i], n1_m1_value[i])) } v, v_ok := file.nodes[0].content.(hxa.Node_Image) testing.expectf(t, v_ok, fmt.tprintf("v_ok %v != %v", v_ok, true)) testing.expectf(t, v.type == n1_content.type, fmt.tprintf("v.type %v != %v", v.type, n1_content.type)) - testing.expectf(t, len(v.resolution) == 3, fmt.tprintf("len(v.resolution) %v != %v", - len(v.resolution), 3)) - testing.expectf(t, len(v.image_stack) == len(n1_content.image_stack), fmt.tprintf("len(v.image_stack) %v != %v", - len(v.image_stack), len(n1_content.image_stack))) + testing.expectf(t, len(v.resolution) == 3, fmt.tprintf("len(v.resolution) %v != %v", len(v.resolution), 3)) + testing.expectf(t, len(v.image_stack) == len(n1_content.image_stack), fmt.tprintf("len(v.image_stack) %v != %v", len(v.image_stack), len(n1_content.image_stack))) for i := 0; i < len(v.image_stack); i += 1 { testing.expectf(t, v.image_stack[i].name == n1_content.image_stack[i].name, fmt.tprintf("v.image_stack[%d].name %v != %v", @@ -182,8 +175,7 @@ test_write :: proc(t: ^testing.T) { testing.expectf(t, l_ok, fmt.tprintf("l_ok %v != %v", l_ok, true)) testing.expectf(t, len(l) == len(n1_t), fmt.tprintf("len(l) %v != %v", len(l), len(n1_t))) for j := 0; j < len(l); j += 1 { - testing.expectf(t, l[j] == n1_t[j], fmt.tprintf("l[%d] %v (%h) != %v (%h)", - j, l[j], l[j], n1_t[j], n1_t[j])) + testing.expectf(t, l[j] == n1_t[j], fmt.tprintf("l[%d] %v (%h) != %v (%h)", j, l[j], l[j], n1_t[j], n1_t[j])) } case []f64le: l, l_ok := v.image_stack[i].data.([]f64le) diff --git a/tests/core/encoding/uuid/test_core_uuid.odin b/tests/core/encoding/uuid/test_core_uuid.odin new file mode 100644 index 000000000..619534a7f --- /dev/null +++ b/tests/core/encoding/uuid/test_core_uuid.odin @@ -0,0 +1,439 @@ +package test_core_uuid + +import "core:crypto" +import "core:encoding/uuid" +import uuid_legacy "core:encoding/uuid/legacy" +import "core:log" +import "core:slice" +import "core:testing" +import "core:time" + +@(test) +test_version_and_variant :: proc(t: ^testing.T) { + context.random_generator = crypto.random_generator() + + v1 := uuid.generate_v1(0) + v3 := uuid_legacy.generate_v3(uuid.Namespace_DNS, "") + v4 := uuid.generate_v4() + v5 := uuid_legacy.generate_v5(uuid.Namespace_DNS, "") + v6 := uuid.generate_v6() + v7 := uuid.generate_v7() + + _v8_array: [16]u8 = 0xff + v8_int := uuid.stamp_v8(max(u128)) + v8_array := uuid.stamp_v8(_v8_array) + v8_slice := uuid.stamp_v8(_v8_array[:]) + + v8_hash := uuid.generate_v8_hash(uuid.Namespace_DNS, "", .SHA512) + + testing.expect_value(t, uuid.version(v1), 1) + testing.expect_value(t, uuid.variant(v1), uuid.Variant_Type.RFC_4122) + testing.expect_value(t, uuid.version(v3), 3) + testing.expect_value(t, uuid.variant(v3), uuid.Variant_Type.RFC_4122) + testing.expect_value(t, uuid.version(v4), 4) + testing.expect_value(t, uuid.variant(v4), uuid.Variant_Type.RFC_4122) + testing.expect_value(t, uuid.version(v5), 5) + testing.expect_value(t, uuid.variant(v5), uuid.Variant_Type.RFC_4122) + testing.expect_value(t, uuid.version(v6), 6) + testing.expect_value(t, uuid.variant(v6), uuid.Variant_Type.RFC_4122) + testing.expect_value(t, uuid.version(v7), 7) + testing.expect_value(t, uuid.variant(v7), uuid.Variant_Type.RFC_4122) + + testing.expect_value(t, uuid.version(v8_int), 8) + testing.expect_value(t, uuid.variant(v8_int), uuid.Variant_Type.RFC_4122) + testing.expect_value(t, uuid.version(v8_array), 8) + testing.expect_value(t, uuid.variant(v8_array), uuid.Variant_Type.RFC_4122) + testing.expect_value(t, uuid.version(v8_slice), 8) + testing.expect_value(t, uuid.variant(v8_slice), uuid.Variant_Type.RFC_4122) + + testing.expect_value(t, uuid.version(v8_hash), 8) + testing.expect_value(t, uuid.variant(v8_hash), uuid.Variant_Type.RFC_4122) +} + +@(test) +test_timestamps :: proc(t: ^testing.T) { + // This test makes sure that timestamps are recoverable and have not been + // overwritten by neighboring bits, taking into account precision loss. + context.random_generator = crypto.random_generator() + + N :: max(i64) + + max_time := time.Time { N } + + mac: [6]byte + v1 := uuid.generate_v1(0, mac, max_time) + v6 := uuid.generate_v6(0, mac, max_time) + v7 := uuid.generate_v7(max_time) + // The counter version keeps its time in the same place as the basic version, + // this is just for the sake of completeness. + v7_counter := uuid.generate_v7(0, max_time) + + v1_time := uuid.time_v1(v1) + v6_time := uuid.time_v6(v6) + v7_time := uuid.time_v7(v7) + v7_counter_time := uuid.time_v7(v7_counter) + + // I hope the compiler doesn't ever optimize this out. + max_time_hns_resolution := time.Time { N / 100 * 100 } + max_time_ms_resolution := time.Time { N / 1e6 * 1e6 } + + testing.expectf(t, + time.diff(max_time_hns_resolution, v1_time) == 0, + "v1 UUID timestamp is invalid, expected %x, got %x", + max_time_hns_resolution, v1_time) + + testing.expectf(t, + time.diff(max_time_hns_resolution, v6_time) == 0, + "v6 UUID timestamp is invalid, expected %x, got %x", + max_time_hns_resolution, v6_time) + + testing.expectf(t, + time.diff(max_time_ms_resolution, v7_time) == 0, + "v7 UUID timestamp is invalid, expected %x, got %x", + max_time_ms_resolution, v7_time) + + testing.expectf(t, + time.diff(max_time_ms_resolution, v7_counter_time) == 0, + "v7 UUID (with counter) timestamp is invalid, expected %x, got %x", + max_time_ms_resolution, v7_counter_time) +} + +@(test) +test_v8_hash_implementation :: proc(t: ^testing.T) { + // This example and its results are derived from RFC 9562. + // https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv8-value-n + + id := uuid.generate_v8_hash(uuid.Namespace_DNS, "www.example.com", .SHA256) + id_str := uuid.to_string(id) + defer delete(id_str) + testing.expect_value(t, id_str, "5c146b14-3c52-8afd-938a-375d0df1fbf6") +} + +@(test) +test_legacy_namespaced_uuids :: proc(t: ^testing.T) { + TEST_NAME :: "0123456789ABCDEF0123456789ABCDEF" + + Expected_Result :: struct { + namespace: uuid.Identifier, + v3, v5: string, + } + + Expected_Results := [?]Expected_Result { + { uuid.Namespace_DNS, "80147f37-36db-3b82-b78f-810c3c6504ba", "18394c41-13a2-593f-abf2-a63e163c2860" }, + { uuid.Namespace_URL, "8136789b-8e16-3fbd-800b-1587e2f22521", "07337422-eb77-5fd3-99af-c7f59e641e13" }, + { uuid.Namespace_OID, "adbb95bc-ea50-3226-9a75-20c34a6030f8", "24db9b0f-70b8-53c4-a301-f695ce17276d" }, + { uuid.Namespace_X500, "a8965ad1-0e54-3d65-b933-8b7cca8e8313", "3012bf2d-fac4-5187-9825-493e6636b936" }, + } + + for exp in Expected_Results { + v3 := uuid_legacy.generate_v3(exp.namespace, TEST_NAME) + v5 := uuid_legacy.generate_v5(exp.namespace, TEST_NAME) + + v3_str := uuid.to_string(v3) + defer delete(v3_str) + + v5_str := uuid.to_string(v5) + defer delete(v5_str) + + testing.expect_value(t, v3_str, exp.v3) + testing.expect_value(t, v5_str, exp.v5) + } +} + +@(test) +test_v1 :: proc(t: ^testing.T) { + context.random_generator = crypto.random_generator() + + point_a := time.unix(1, 0) + point_b := time.unix(3, 0) + point_c := time.unix(5, 0) + + CLOCK :: 0x3A1A + mac := [6]u8{0xFF, 0x10, 0xAA, 0x55, 0x01, 0xFF} + + v1_a := uuid.generate_v1(CLOCK, mac, point_a) + v1_b := uuid.generate_v1(CLOCK, mac, point_b) + v1_c := uuid.generate_v1(CLOCK, mac, point_c) + + testing.expect_value(t, uuid.clock_seq(v1_a), CLOCK) + + extracted_mac := uuid.node(v1_a) + for i in 0 ..< len(mac) { + testing.expect(t, mac[i] == extracted_mac[i]) + } + + time_a := uuid.time_v1(v1_a) + time_b := uuid.time_v1(v1_b) + time_c := uuid.time_v1(v1_c) + + log.debugf("A: %02x, %v", v1_a, time_a) + log.debugf("B: %02x, %v", v1_b, time_b) + log.debugf("C: %02x, %v", v1_c, time_c) + + testing.expect(t, time.diff(time_a, time_b) > 0, "The time on the later-generated v1 UUID is earlier than its successor.") + testing.expect(t, time.diff(time_b, time_c) > 0, "The time on the later-generated v1 UUID is earlier than its successor.") + testing.expect(t, time.diff(time_a, time_c) > 0, "The time on the later-generated v1 UUID is earlier than its successor.") +} + +@(test) +test_v6 :: proc(t: ^testing.T) { + context.random_generator = crypto.random_generator() + + point_a := time.unix(1, 0) + point_b := time.unix(3, 0) + point_c := time.unix(5, 0) + + CLOCK :: 0x3A1A + mac := [6]u8{0xFF, 0x10, 0xAA, 0x55, 0x01, 0xFF} + + v6_a := uuid.generate_v6(CLOCK, mac, point_a) + v6_b := uuid.generate_v6(CLOCK, mac, point_b) + v6_c := uuid.generate_v6(CLOCK, mac, point_c) + + testing.expect_value(t, uuid.clock_seq(v6_a), CLOCK) + + extracted_mac := uuid.node(v6_a) + for i in 0 ..< len(mac) { + testing.expect(t, mac[i] == extracted_mac[i]) + } + + time_a := uuid.time_v6(v6_a) + time_b := uuid.time_v6(v6_b) + time_c := uuid.time_v6(v6_c) + + log.debugf("A: %02x, %v", v6_a, time_a) + log.debugf("B: %02x, %v", v6_b, time_b) + log.debugf("C: %02x, %v", v6_c, time_c) + + testing.expect(t, time.diff(time_a, time_b) > 0, "The time on the later-generated v6 UUID is earlier than its successor.") + testing.expect(t, time.diff(time_b, time_c) > 0, "The time on the later-generated v6 UUID is earlier than its successor.") + testing.expect(t, time.diff(time_a, time_c) > 0, "The time on the later-generated v6 UUID is earlier than its successor.") +} + +@(test) +test_v7 :: proc(t: ^testing.T) { + context.random_generator = crypto.random_generator() + + point_a := time.unix(1, 0) + point_b := time.unix(3, 0) + point_c := time.unix(5, 0) + + v7_a := uuid.generate_v7(point_a) + v7_b := uuid.generate_v7(point_b) + v7_c := uuid.generate_v7(point_c) + + time_a := uuid.time_v7(v7_a) + time_b := uuid.time_v7(v7_b) + time_c := uuid.time_v7(v7_c) + + log.debugf("A: %02x, %v", v7_a, time_a) + log.debugf("B: %02x, %v", v7_b, time_b) + log.debugf("C: %02x, %v", v7_c, time_c) + + testing.expect(t, time.diff(time_a, time_b) > 0, "The time on the later-generated v7 UUID is earlier than its successor.") + testing.expect(t, time.diff(time_b, time_c) > 0, "The time on the later-generated v7 UUID is earlier than its successor.") + testing.expect(t, time.diff(time_a, time_c) > 0, "The time on the later-generated v7 UUID is earlier than its successor.") + + v7_with_counter := uuid.generate_v7(0x555) + log.debugf("D: %02x", v7_with_counter) + testing.expect_value(t, uuid.counter_v7(v7_with_counter), 0x555) +} + +@(test) +test_sorting_v1 :: proc(t: ^testing.T) { + // This test is to make sure that the v1 UUIDs do _not_ sort. + // They are incapable of sorting properly by the nature their time bit ordering. + // + // Something is very strange if they do sort correctly. + point_a := time.unix(1, 0) + point_b := time.unix(3, 0) + point_c := time.unix(5, 0) + point_d := time.unix(7, 0) + point_e := time.unix(11, 0) + + mac: [6]byte + v1_a := uuid.generate_v1(0, mac, point_a) + v1_b := uuid.generate_v1(0, mac, point_b) + v1_c := uuid.generate_v1(0, mac, point_c) + v1_d := uuid.generate_v1(0, mac, point_d) + v1_e := uuid.generate_v1(0, mac, point_e) + + sort_test := [5]u128be { + transmute(u128be)v1_e, + transmute(u128be)v1_a, + transmute(u128be)v1_d, + transmute(u128be)v1_b, + transmute(u128be)v1_c, + } + + log.debugf("Before: %x", sort_test) + slice.sort(sort_test[:]) + log.debugf("After: %x", sort_test) + + ERROR :: "v1 UUIDs are sorting by time, despite this not being possible." + + testing.expect(t, sort_test[0] != transmute(u128be)v1_a, ERROR) + testing.expect(t, sort_test[1] != transmute(u128be)v1_b, ERROR) + testing.expect(t, sort_test[2] != transmute(u128be)v1_c, ERROR) + testing.expect(t, sort_test[3] != transmute(u128be)v1_d, ERROR) + testing.expect(t, sort_test[4] != transmute(u128be)v1_e, ERROR) +} + +@(test) +test_sorting_v6 :: proc(t: ^testing.T) { + context.random_generator = crypto.random_generator() + + point_a := time.unix(1, 0) + point_b := time.unix(3, 0) + point_c := time.unix(5, 0) + point_d := time.unix(7, 0) + point_e := time.unix(11, 0) + + mac: [6]byte + v6_a := uuid.generate_v6(0, mac, point_a) + v6_b := uuid.generate_v6(0, mac, point_b) + v6_c := uuid.generate_v6(0, mac, point_c) + v6_d := uuid.generate_v6(0, mac, point_d) + v6_e := uuid.generate_v6(0, mac, point_e) + + sort_test := [5]u128be { + transmute(u128be)v6_e, + transmute(u128be)v6_a, + transmute(u128be)v6_d, + transmute(u128be)v6_b, + transmute(u128be)v6_c, + } + + log.debugf("Before: %x", sort_test) + slice.sort(sort_test[:]) + log.debugf("After: %x", sort_test) + + ERROR :: "v6 UUIDs are failing to sort properly." + + testing.expect(t, sort_test[0] < sort_test[1], ERROR) + testing.expect(t, sort_test[1] < sort_test[2], ERROR) + testing.expect(t, sort_test[2] < sort_test[3], ERROR) + testing.expect(t, sort_test[3] < sort_test[4], ERROR) + + testing.expect(t, sort_test[0] == transmute(u128be)v6_a, ERROR) + testing.expect(t, sort_test[1] == transmute(u128be)v6_b, ERROR) + testing.expect(t, sort_test[2] == transmute(u128be)v6_c, ERROR) + testing.expect(t, sort_test[3] == transmute(u128be)v6_d, ERROR) + testing.expect(t, sort_test[4] == transmute(u128be)v6_e, ERROR) +} + +@(test) +test_sorting_v7 :: proc(t: ^testing.T) { + context.random_generator = crypto.random_generator() + + point_a := time.unix(1, 0) + point_b := time.unix(3, 0) + point_c := time.unix(5, 0) + point_d := time.unix(7, 0) + point_e := time.unix(11, 0) + + v7_a := uuid.generate_v7(point_a) + v7_b := uuid.generate_v7(point_b) + v7_c := uuid.generate_v7(point_c) + v7_d := uuid.generate_v7(point_d) + v7_e := uuid.generate_v7(point_e) + + sort_test := [5]u128be { + transmute(u128be)v7_e, + transmute(u128be)v7_a, + transmute(u128be)v7_d, + transmute(u128be)v7_b, + transmute(u128be)v7_c, + } + + log.debugf("Before: %x", sort_test) + slice.sort(sort_test[:]) + log.debugf("After: %x", sort_test) + + ERROR :: "v7 UUIDs are failing to sort properly." + + testing.expect(t, sort_test[0] < sort_test[1], ERROR) + testing.expect(t, sort_test[1] < sort_test[2], ERROR) + testing.expect(t, sort_test[2] < sort_test[3], ERROR) + testing.expect(t, sort_test[3] < sort_test[4], ERROR) + + testing.expect(t, sort_test[0] == transmute(u128be)v7_a, ERROR) + testing.expect(t, sort_test[1] == transmute(u128be)v7_b, ERROR) + testing.expect(t, sort_test[2] == transmute(u128be)v7_c, ERROR) + testing.expect(t, sort_test[3] == transmute(u128be)v7_d, ERROR) + testing.expect(t, sort_test[4] == transmute(u128be)v7_e, ERROR) +} + +@(test) +test_writing :: proc(t: ^testing.T) { + id: uuid.Identifier + + for &b, i in id { + b = u8(i) + } + + buf: [uuid.EXPECTED_LENGTH]u8 + + s_alloc := uuid.to_string(id) + defer delete(s_alloc) + + s_buf := uuid.to_string(id, buf[:]) + + testing.expect_value(t, s_alloc, "00010203-0405-0607-0809-0a0b0c0d0e0f") + testing.expect_value(t, s_buf, "00010203-0405-0607-0809-0a0b0c0d0e0f") +} + +@(test) +test_reading :: proc(t: ^testing.T) { + id, err := uuid.read("00010203-0405-0607-0809-0a0b0c0d0e0f") + testing.expect_value(t, err, nil) + + for b, i in id { + testing.expect_value(t, b, u8(i)) + } +} + +@(test) +test_reading_errors :: proc(t: ^testing.T) { + { + BAD_STRING :: "|.......@....@....@....@............" + _, err := uuid.read(BAD_STRING) + testing.expect_value(t, err, uuid.Read_Error.Invalid_Separator) + } + + { + BAD_STRING :: "|.......-....-....-....-............" + _, err := uuid.read(BAD_STRING) + testing.expect_value(t, err, uuid.Read_Error.Invalid_Hexadecimal) + } + + { + BAD_STRING :: ".......-....-....-....-............" + _, err := uuid.read(BAD_STRING) + testing.expect_value(t, err, uuid.Read_Error.Invalid_Length) + } + + { + BAD_STRING :: "|.......-....-....-....-............|" + _, err := uuid.read(BAD_STRING) + testing.expect_value(t, err, uuid.Read_Error.Invalid_Length) + } + + { + BAD_STRING :: "00000000-0000-0000-0000-0000000000001" + _, err := uuid.read(BAD_STRING) + testing.expect_value(t, err, uuid.Read_Error.Invalid_Length) + } + + { + BAD_STRING :: "00000000000000000000000000000000" + _, err := uuid.read(BAD_STRING) + testing.expect_value(t, err, uuid.Read_Error.Invalid_Length) + } + + { + OK_STRING :: "00000000-0000-0000-0000-000000000000" + _, err := uuid.read(OK_STRING) + testing.expect_value(t, err, nil) + } +} diff --git a/tests/core/flags/test_core_flags.odin b/tests/core/flags/test_core_flags.odin new file mode 100644 index 000000000..e32c6832c --- /dev/null +++ b/tests/core/flags/test_core_flags.odin @@ -0,0 +1,1393 @@ +package test_core_flags + +import "base:runtime" +import "core:bytes" +import "core:flags" +import "core:fmt" +@require import "core:log" +import "core:math" +@require import "core:net" +import "core:os" +import "core:strings" +import "core:testing" +import "core:time/datetime" + +@(test) +test_no_args :: proc(t: ^testing.T) { + S :: struct { + a: string, + } + s: S + args: []string + result := flags.parse(&s, args) + testing.expect_value(t, result, nil) +} + +@(test) +test_two_flags :: proc(t: ^testing.T) { + S :: struct { + i: string, + o: string, + } + s: S + args := [?]string { "-i:hellope", "-o:world" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.i, "hellope") + testing.expect_value(t, s.o, "world") +} + +@(test) +test_extra_arg :: proc(t: ^testing.T) { + S :: struct { + a: string, + } + s: S + args := [?]string { "-a:hellope", "world" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Extra_Positional) + } +} + +@(test) +test_assignment_oddities :: proc(t: ^testing.T) { + S :: struct { + s: string, + } + s: S + + { + args := [?]string { "-s:=" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.s, "=") + } + + { + args := [?]string { "-s=:" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.s, ":") + } + + { + args := [?]string { "-" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.No_Flag) + } + } +} + +@(test) +test_string_into_int :: proc(t: ^testing.T) { + S :: struct { + n: int, + } + s: S + args := [?]string { "-n:hellope" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value) + } +} + +@(test) +test_string_into_bool :: proc(t: ^testing.T) { + S :: struct { + b: bool, + } + s: S + args := [?]string { "-b:hellope" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value) + } +} + +@(test) +test_all_bools :: proc(t: ^testing.T) { + S :: struct { + a: bool, + b: b8, + c: b16, + d: b32, + e: b64, + } + s: S + s.a = true + s.c = true + args := [?]string { "-a:false", "-b:true", "-c:0", "-d", "-e:1" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, false) + testing.expect_value(t, s.b, true) + testing.expect_value(t, s.c, false) + testing.expect_value(t, s.d, true) + testing.expect_value(t, s.e, true) +} + +@(test) +test_all_ints :: proc(t: ^testing.T) { + S :: struct { + a: u8, + b: i8, + c: u16, + d: i16, + e: u32, + f: i32, + g: u64, + i: i64, + j: u128, + k: i128, + } + + s: S + args := [?]string { + fmt.tprintf("-a:%i", max(u8)), + fmt.tprintf("-b:%i", min(i8)), + fmt.tprintf("-c:%i", max(u16)), + fmt.tprintf("-d:%i", min(i16)), + fmt.tprintf("-e:%i", max(u32)), + fmt.tprintf("-f:%i", min(i32)), + fmt.tprintf("-g:%i", max(u64)), + fmt.tprintf("-i:%i", min(i64)), + fmt.tprintf("-j:%i", max(u128)), + fmt.tprintf("-k:%i", min(i128)), + } + + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, max(u8)) + testing.expect_value(t, s.b, min(i8)) + testing.expect_value(t, s.c, max(u16)) + testing.expect_value(t, s.d, min(i16)) + testing.expect_value(t, s.e, max(u32)) + testing.expect_value(t, s.f, min(i32)) + testing.expect_value(t, s.g, max(u64)) + testing.expect_value(t, s.i, min(i64)) + testing.expect_value(t, s.j, max(u128)) + testing.expect_value(t, s.k, min(i128)) +} + +@(test) +test_all_floats :: proc(t: ^testing.T) { + S :: struct { + a: f16, + b: f32, + c: f64, + d: f64, + e: f64, + } + s: S + args := [?]string { "-a:100", "-b:3.14", "-c:-123.456", "-d:nan", "-e:inf" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, 100) + testing.expect_value(t, s.b, 3.14) + testing.expect_value(t, s.c, -123.456) + testing.expectf(t, math.is_nan(s.d), "expected NaN, got %v", s.d) + testing.expectf(t, math.is_inf(s.e, +1), "expected +Inf, got %v", s.e) +} + +@(test) +test_all_enums :: proc(t: ^testing.T) { + E :: enum { A, B } + S :: struct { + nameless: enum { C, D }, + named: E, + } + s: S + args := [?]string { "-nameless:D", "-named:B" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, cast(int)s.nameless, 1) + testing.expect_value(t, s.named, E.B) +} + +@(test) +test_all_complex :: proc(t: ^testing.T) { + S :: struct { + a: complex32, + b: complex64, + c: complex128, + } + s: S + args := [?]string { "-a:1+0i", "-b:3+7i", "-c:NaNNaNi" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, real(s.a), 1) + testing.expect_value(t, imag(s.a), 0) + testing.expect_value(t, real(s.b), 3) + testing.expect_value(t, imag(s.b), 7) + testing.expectf(t, math.is_nan(real(s.c)), "expected NaN, got %v", real(s.c)) + testing.expectf(t, math.is_nan(imag(s.c)), "expected NaN, got %v", imag(s.c)) +} + +@(test) +test_all_quaternion :: proc(t: ^testing.T) { + S :: struct { + a: quaternion64, + b: quaternion128, + c: quaternion256, + } + s: S + args := [?]string { "-a:1+0i+1j+0k", "-b:3+7i+5j-3k", "-c:NaNNaNi+Infj-Infk" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + + raw_a := (cast(^runtime.Raw_Quaternion64)&s.a) + raw_b := (cast(^runtime.Raw_Quaternion128)&s.b) + raw_c := (cast(^runtime.Raw_Quaternion256)&s.c) + + testing.expect_value(t, raw_a.real, 1) + testing.expect_value(t, raw_a.imag, 0) + testing.expect_value(t, raw_a.jmag, 1) + testing.expect_value(t, raw_a.kmag, 0) + + testing.expect_value(t, raw_b.real, 3) + testing.expect_value(t, raw_b.imag, 7) + testing.expect_value(t, raw_b.jmag, 5) + testing.expect_value(t, raw_b.kmag, -3) + + testing.expectf(t, math.is_nan(raw_c.real), "expected NaN, got %v", raw_c.real) + testing.expectf(t, math.is_nan(raw_c.imag), "expected NaN, got %v", raw_c.imag) + testing.expectf(t, math.is_inf(raw_c.jmag, +1), "expected +Inf, got %v", raw_c.jmag) + testing.expectf(t, math.is_inf(raw_c.kmag, -1), "expected -Inf, got %v", raw_c.kmag) +} + +@(test) +test_all_bit_sets :: proc(t: ^testing.T) { + E :: enum { + Option_A, + Option_B, + } + S :: struct { + a: bit_set[0..<8], + b: bit_set[0..<16; u16], + c: bit_set[16..<18; rune], + d: bit_set[0..<1; i8], + e: bit_set[0..<128], + f: bit_set[-32..<32], + g: bit_set[E], + i: bit_set[E; u8], + } + s: S + { + args := [?]string { + "-a:10101", + "-b:0000_0000_0000_0001", + "-c:11", + "-d:___1", + "-e:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "-f:1", + "-g:01", + "-i:1", + } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, bit_set[0..<8]{0, 2, 4}) + testing.expect_value(t, s.b, bit_set[0..<16; u16]{15}) + testing.expect_value(t, s.c, bit_set[16..<18; rune]{16, 17}) + testing.expect_value(t, s.d, bit_set[0..<1; i8]{0}) + testing.expect_value(t, s.e, bit_set[0..<128]{127}) + testing.expect_value(t, s.f, bit_set[-32..<32]{-32}) + testing.expect_value(t, s.g, bit_set[E]{E.Option_B}) + testing.expect_value(t, s.i, bit_set[E; u8]{E.Option_A}) + } + { + args := [?]string { "-d:11" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value) + } + } +} + +@(test) +test_all_strings :: proc(t: ^testing.T) { + S :: struct { + a, b, c: string, + d: cstring, + } + s: S + args := [?]string { "-a:hi", "-b:hellope", "-c:spaced out", "-d:cstr", "-d:cstr-overwrite" } + result := flags.parse(&s, args[:]) + defer delete(s.d) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, "hi") + testing.expect_value(t, s.b, "hellope") + testing.expect_value(t, s.c, "spaced out") + testing.expect_value(t, s.d, "cstr-overwrite") +} + +@(test) +test_runes :: proc(t: ^testing.T) { + S :: struct { + a, b, c: rune, + } + s: S + args := [?]string { "-a:a", "-b:ツ", "-c:\U0010FFFF" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, 'a') + testing.expect_value(t, s.b, 'ツ') + testing.expect_value(t, s.c, '\U0010FFFF') +} + +@(test) +test_no_value :: proc(t: ^testing.T) { + S :: struct { + a: rune, + } + s: S + + { + args := [?]string { "-a:" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.No_Value) + } + } + + { + args := [?]string { "-a=" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.No_Value) + } + } +} + +@(test) +test_overflow :: proc(t: ^testing.T) { + S :: struct { + a: u8, + } + s: S + args := [?]string { "-a:256" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value) + } +} + +@(test) +test_underflow :: proc(t: ^testing.T) { + S :: struct { + a: i8, + } + s: S + args := [?]string { "-a:-129" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value) + } +} + +@(test) +test_arrays :: proc(t: ^testing.T) { + S :: struct { + a: [dynamic]string, + b: [dynamic]int, + } + s: S + args := [?]string { "-a:abc", "-b:1", "-a:foo", "-b:3" } + result := flags.parse(&s, args[:]) + defer { + delete(s.a) + delete(s.b) + } + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.a), 2) + testing.expect_value(t, len(s.b), 2) + + if len(s.a) < 2 || len(s.b) < 2 { + return + } + + testing.expect_value(t, s.a[0], "abc") + testing.expect_value(t, s.a[1], "foo") + testing.expect_value(t, s.b[0], 1) + testing.expect_value(t, s.b[1], 3) +} + +@(test) +test_varargs :: proc(t: ^testing.T) { + S :: struct { + varg: [dynamic]string, + } + s: S + args := [?]string { "abc", "foo", "bar" } + result := flags.parse(&s, args[:]) + defer delete(s.varg) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.varg), 3) + + if len(s.varg) < 3 { + return + } + + testing.expect_value(t, s.varg[0], "abc") + testing.expect_value(t, s.varg[1], "foo") + testing.expect_value(t, s.varg[2], "bar") +} + +@(test) +test_mixed_varargs :: proc(t: ^testing.T) { + S :: struct { + input: string `args:"pos=0"`, + varg: [dynamic]string, + } + s: S + args := [?]string { "abc", "foo", "bar" } + result := flags.parse(&s, args[:]) + defer delete(s.varg) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.varg), 2) + + if len(s.varg) < 2 { + return + } + + testing.expect_value(t, s.input, "abc") + testing.expect_value(t, s.varg[0], "foo") + testing.expect_value(t, s.varg[1], "bar") +} + +@(test) +test_maps :: proc(t: ^testing.T) { + S :: struct { + a: map[string]string, + b: map[string]int, + } + s: S + args := [?]string { "-a:abc=foo", "-b:bar=42" } + result := flags.parse(&s, args[:]) + defer { + delete(s.a) + delete(s.b) + } + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.a), 1) + testing.expect_value(t, len(s.b), 1) + + if len(s.a) < 1 || len(s.b) < 1 { + return + } + + abc, has_abc := s.a["abc"] + bar, has_bar := s.b["bar"] + + testing.expect(t, has_abc, "expected map to have `abc` key set") + testing.expect(t, has_bar, "expected map to have `bar` key set") + testing.expect_value(t, abc, "foo") + testing.expect_value(t, bar, 42) +} + +@(test) +test_invalid_map_syntax :: proc(t: ^testing.T) { + S :: struct { + a: map[string]string, + } + s: S + args := [?]string { "-a:foo:42" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.No_Value) + } +} + +@(test) +test_underline_name_to_dash :: proc(t: ^testing.T) { + S :: struct { + a_b: int, + } + s: S + args := [?]string { "-a-b:3" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a_b, 3) +} + +@(test) +test_tags_pos :: proc(t: ^testing.T) { + S :: struct { + b: int `args:"pos=1"`, + a: int `args:"pos=0"`, + } + s: S + args := [?]string { "42", "99" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, 42) + testing.expect_value(t, s.b, 99) +} + +@(test) +test_tags_name :: proc(t: ^testing.T) { + S :: struct { + a: int `args:"name=alice"`, + b: int `args:"name=bill"`, + } + s: S + args := [?]string { "-alice:1", "-bill:2" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, 1) + testing.expect_value(t, s.b, 2) +} + +@(test) +test_tags_required :: proc(t: ^testing.T) { + S :: struct { + a: int, + b: int `args:"required"`, + } + s: S + args := [?]string { "-a:1" } + result := flags.parse(&s, args[:]) + _, ok := result.(flags.Validation_Error) + testing.expectf(t, ok, "unexpected result: %v", result) +} + +@(test) +test_tags_required_pos :: proc(t: ^testing.T) { + S :: struct { + a: int `args:"pos=0,required"`, + b: int `args:"pos=1"`, + } + s: S + args := [?]string { "-b:5" } + result := flags.parse(&s, args[:]) + _, ok := result.(flags.Validation_Error) + testing.expectf(t, ok, "unexpected result: %v", result) +} + +@(test) +test_tags_required_limit_min :: proc(t: ^testing.T) { + S :: struct { + n: [dynamic]int `args:"required=3"`, + } + + { + s: S + args := [?]string { "-n:1" } + result := flags.parse(&s, args[:]) + defer delete(s.n) + _, ok := result.(flags.Validation_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + } + + { + s: S + args := [?]string { "-n:3", "-n:5", "-n:7" } + result := flags.parse(&s, args[:]) + defer delete(s.n) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.n), 3) + + if len(s.n) == 3 { + testing.expect_value(t, s.n[0], 3) + testing.expect_value(t, s.n[1], 5) + testing.expect_value(t, s.n[2], 7) + } + } +} + +@(test) +test_tags_required_limit_min_max :: proc(t: ^testing.T) { + S :: struct { + n: [dynamic]int `args:"required=2<4"`, + } + + { + s: S + args := [?]string { "-n:1" } + result := flags.parse(&s, args[:]) + defer delete(s.n) + _, ok := result.(flags.Validation_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + } + + { + s: S + args := [?]string { "-n:1", "-n:2", "-n:3", "-n:4" } + result := flags.parse(&s, args[:]) + defer delete(s.n) + _, ok := result.(flags.Validation_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + } + + { + s: S + args := [?]string { "-n:3", "-n:5", "-n:7" } + result := flags.parse(&s, args[:]) + defer delete(s.n) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.n), 3) + + if len(s.n) == 3 { + testing.expect_value(t, s.n[0], 3) + testing.expect_value(t, s.n[1], 5) + testing.expect_value(t, s.n[2], 7) + } + } +} + +@(test) +test_tags_required_limit_max :: proc(t: ^testing.T) { + S :: struct { + n: [dynamic]int `args:"required=<4"`, + } + + { + s: S + args: []string + result := flags.parse(&s, args) + testing.expect_value(t, result, nil) + } + + { + s: S + args := [?]string { "-n:1", "-n:2", "-n:3", "-n:4" } + result := flags.parse(&s, args[:]) + defer delete(s.n) + _, ok := result.(flags.Validation_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + } + + { + s: S + args := [?]string { "-n:3", "-n:5", "-n:7" } + result := flags.parse(&s, args[:]) + defer delete(s.n) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.n), 3) + + if len(s.n) == 3 { + testing.expect_value(t, s.n[0], 3) + testing.expect_value(t, s.n[1], 5) + testing.expect_value(t, s.n[2], 7) + } + } +} + +@(test) +test_tags_pos_out_of_order :: proc(t: ^testing.T) { + S :: struct { + a: int `args:"pos=2"`, + varg: [dynamic]int, + } + s: S + args := [?]string { "1", "2", "3", "4" } + result := flags.parse(&s, args[:]) + defer delete(s.varg) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.varg), 3) + + if len(s.varg) < 3 { + return + } + + testing.expect_value(t, s.a, 3) + testing.expect_value(t, s.varg[0], 1) + testing.expect_value(t, s.varg[1], 2) + testing.expect_value(t, s.varg[2], 4) +} + +@(test) +test_missing_flag :: proc(t: ^testing.T) { + S :: struct { + a: int, + } + s: S + args := [?]string { "-b" } + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Missing_Flag) + } +} + +@(test) +test_alt_syntax :: proc(t: ^testing.T) { + S :: struct { + a: int, + } + s: S + args := [?]string { "-a=3" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, 3) +} + +@(test) +test_strict_returns_first_error :: proc(t: ^testing.T) { + S :: struct { + b: int, + c: int, + } + s: S + args := [?]string { "-a=3", "-b=3" } + result := flags.parse(&s, args[:], strict=true) + err, ok := result.(flags.Parse_Error) + testing.expect_value(t, s.b, 0) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Missing_Flag) + } +} + +@(test) +test_non_strict_returns_last_error :: proc(t: ^testing.T) { + S :: struct { + a: int, + b: int, + } + s: S + args := [?]string { "-a=foo", "-b=2", "-c=3" } + result := flags.parse(&s, args[:], strict=false) + err, ok := result.(flags.Parse_Error) + testing.expect_value(t, s.b, 2) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Missing_Flag) + } +} + +@(test) +test_map_overwrite :: proc(t: ^testing.T) { + S :: struct { + m: map[string]int, + } + s: S + args := [?]string { "-m:foo=3", "-m:foo=5" } + result := flags.parse(&s, args[:]) + defer delete(s.m) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.m), 1) + foo, has_foo := s.m["foo"] + testing.expect(t, has_foo, "expected map to have `foo` key set") + testing.expect_value(t, foo, 5) +} + +@(test) +test_maps_of_arrays :: proc(t: ^testing.T) { + // Why you would ever want to do this, I don't know, but it's possible! + S :: struct { + m: map[string][dynamic]int, + } + s: S + args := [?]string { "-m:foo=1", "-m:foo=2", "-m:bar=3" } + result := flags.parse(&s, args[:]) + defer { + for _, v in s.m { + delete(v) + } + delete(s.m) + } + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.m), 2) + + if len(s.m) != 2 { + return + } + + foo, has_foo := s.m["foo"] + bar, has_bar := s.m["bar"] + + testing.expect_value(t, has_foo, true) + testing.expect_value(t, has_bar, true) + + if has_foo { + testing.expect_value(t, len(foo), 2) + if len(foo) == 2 { + testing.expect_value(t, foo[0], 1) + testing.expect_value(t, foo[1], 2) + } + } + + if has_bar { + testing.expect_value(t, len(bar), 1) + if len(bar) == 1 { + testing.expect_value(t, bar[0], 3) + } + } +} + +@(test) +test_builtin_help_flag :: proc(t: ^testing.T) { + S :: struct {} + s: S + + args_short := [?]string { "-h" } + args_normal := [?]string { "-help" } + + result := flags.parse(&s, args_short[:]) + _, ok := result.(flags.Help_Request) + testing.expectf(t, ok, "unexpected result: %v", result) + + result = flags.parse(&s, args_normal[:]) + _, ok = result.(flags.Help_Request) + testing.expectf(t, ok, "unexpected result: %v", result) +} + +// This test makes sure that if a positional argument is specified, it won't be +// overwritten by an unspecified positional, which should follow the principle +// of least surprise for the user. +@(test) +test_pos_nonoverlap :: proc(t: ^testing.T) { + S :: struct { + a: int `args:"pos=0"`, + b: int `args:"pos=1"`, + } + s: S + + args := [?]string { "-a:3", "5" } + + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, 3) + testing.expect_value(t, s.b, 5) +} + +// This test ensures the underlying `bit_array` container handles many +// arguments in a sane manner. +@(test) +test_pos_many_args :: proc(t: ^testing.T) { + S :: struct { + varg: [dynamic]int, + a: int `args:"pos=0,required"`, + b: int `args:"pos=64,required"`, + c: int `args:"pos=66,required"`, + d: int `args:"pos=129,required"`, + } + s: S + + args: [dynamic]string + defer delete(s.varg) + + for i in 0 ..< 130 { append(&args, fmt.aprintf("%i", 1 + i)) } + defer { + for a in args { + delete(a) + } + delete(args) + } + + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + + testing.expect_value(t, s.a, 1) + for i in 1 ..< 63 { testing.expect_value(t, s.varg[i], 2 + i) } + testing.expect_value(t, s.b, 65) + testing.expect_value(t, s.varg[63], 66) + testing.expect_value(t, s.c, 67) + testing.expect_value(t, s.varg[64], 68) + testing.expect_value(t, s.varg[65], 69) + testing.expect_value(t, s.varg[66], 70) + for i in 67 ..< 126 { testing.expect_value(t, s.varg[i], 4 + i) } + testing.expect_value(t, s.d, 130) +} + +@(test) +test_unix :: proc(t: ^testing.T) { + S :: struct { + a: string, + } + s: S + + { + args := [?]string { "--a", "hellope" } + + result := flags.parse(&s, args[:], .Unix) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, "hellope") + } + + { + args := [?]string { "-a", "hellope", "--a", "world" } + + result := flags.parse(&s, args[:], .Unix) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, "world") + } + + { + args := [?]string { "-a=hellope" } + + result := flags.parse(&s, args[:], .Unix) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, "hellope") + } +} + +@(test) +test_unix_variadic :: proc(t: ^testing.T) { + S :: struct { + a: [dynamic]int `args:"variadic"`, + } + s: S + + args := [?]string { "--a", "7", "32", "11" } + + result := flags.parse(&s, args[:], .Unix) + defer delete(s.a) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.a), 3) + + if len(s.a) < 3 { + return + } + + testing.expect_value(t, s.a[0], 7) + testing.expect_value(t, s.a[1], 32) + testing.expect_value(t, s.a[2], 11) +} + +@(test) +test_unix_variadic_limited :: proc(t: ^testing.T) { + S :: struct { + a: [dynamic]int `args:"variadic=2"`, + b: int, + } + s: S + + args := [?]string { "-a", "11", "101", "-b", "3" } + + result := flags.parse(&s, args[:], .Unix) + defer delete(s.a) + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.a), 2) + + if len(s.a) < 2 { + return + } + + testing.expect_value(t, s.a[0], 11) + testing.expect_value(t, s.a[1], 101) + testing.expect_value(t, s.b, 3) +} + +@(test) +test_unix_positional :: proc(t: ^testing.T) { + S :: struct { + a: int `args:"pos=1"`, + b: int `args:"pos=0"`, + } + s: S + + args := [?]string { "-b", "17", "11" } + + result := flags.parse(&s, args[:], .Unix) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a, 11) + testing.expect_value(t, s.b, 17) +} + +@(test) +test_unix_positional_with_variadic :: proc(t: ^testing.T) { + S :: struct { + varg: [dynamic]int, + v: [dynamic]int `args:"variadic"`, + } + s: S + + args := [?]string { "35", "-v", "17", "11" } + + result := flags.parse(&s, args[:], .Unix) + defer { + delete(s.varg) + delete(s.v) + } + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.varg), 1) + testing.expect_value(t, len(s.v), 2) +} + +@(test) +test_unix_double_dash_variadic :: proc(t: ^testing.T) { + S :: struct { + varg: [dynamic]string, + i: int, + } + s: S + + args := [?]string { "-i", "3", "--", "hellope", "-i", "5" } + + result := flags.parse(&s, args[:], .Unix) + defer { + delete(s.varg) + } + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.varg), 3) + testing.expect_value(t, s.i, 3) + + if len(s.varg) != 3 { + return + } + + testing.expect_value(t, s.varg[0], "hellope") + testing.expect_value(t, s.varg[1], "-i") + testing.expect_value(t, s.varg[2], "5") +} + +@(test) +test_unix_no_value :: proc(t: ^testing.T) { + S :: struct { + i: int, + } + s: S + + args := [?]string { "--i" } + + result := flags.parse(&s, args[:], .Unix) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.No_Value) + } +} + +// This test ensures there are no bad frees with cstrings. +@(test) +test_if_dynamic_cstrings_get_freed :: proc(t: ^testing.T) { + S :: struct { + varg: [dynamic]cstring, + } + s: S + + args := [?]string { "Hellope", "world!" } + result := flags.parse(&s, args[:]) + defer { + for v in s.varg { + delete(v) + } + delete(s.varg) + } + testing.expect_value(t, result, nil) +} + +// This test ensures there are no double allocations with cstrings. +@(test) +test_if_map_cstrings_get_freed :: proc(t: ^testing.T) { + S :: struct { + m: map[cstring]cstring, + } + s: S + + args := [?]string { "-m:hellope=world", "-m:hellope=bar", "-m:hellope=foo" } + result := flags.parse(&s, args[:]) + defer { + for _, v in s.m { + delete(v) + } + delete(s.m) + } + testing.expect_value(t, result, nil) + testing.expect_value(t, s.m["hellope"], "foo") +} + +@(test) +test_os_handle :: proc(t: ^testing.T) { + defer if !testing.failed(t) { + // Delete the file now that we're done. + // + // This is not done all the time, just in case the file is useful to debugging. + testing.expect_value(t, os.remove(TEMPORARY_FILENAME), os.ERROR_NONE) + } + + TEMPORARY_FILENAME :: "test_core_flags_write_test_output_data" + + test_data := "Hellope!" + + W :: struct { + outf: os.Handle `args:"file=cw"`, + } + w: W + + args := [?]string { fmt.tprintf("-outf:%s", TEMPORARY_FILENAME) } + result := flags.parse(&w, args[:]) + testing.expect_value(t, result, nil) + if result != nil { + return + } + defer os.close(w.outf) + os.write_string(w.outf, test_data) + + R :: struct { + inf: os.Handle `args:"file=r"`, + } + r: R + + args = [?]string { fmt.tprintf("-inf:%s", TEMPORARY_FILENAME) } + result = flags.parse(&r, args[:]) + testing.expect_value(t, result, nil) + if result != nil { + return + } + defer os.close(r.inf) + data, read_ok := os.read_entire_file_from_handle(r.inf, context.temp_allocator) + testing.expect_value(t, read_ok, true) + file_contents_equal := 0 == bytes.compare(transmute([]u8)test_data, data) + testing.expectf(t, file_contents_equal, "expected file contents to be the same, got %v", data) +} + +@(test) +test_distinct_types :: proc(t: ^testing.T) { + I :: distinct int + S :: struct { + base_i: I `args:"indistinct"`, + unmodified_i: I, + } + s: S + + { + args := [?]string {"-base-i:1"} + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + } + + { + args := [?]string {"-unmodified-i:1"} + result := flags.parse(&s, args[:]) + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Unsupported_Type) + } + } +} + +@(test) +test_datetime :: proc(t: ^testing.T) { + when flags.IMPORTING_TIME { + W :: struct { + t: datetime.DateTime, + } + w: W + + args := [?]string { "-t:2024-06-04T12:34:56Z" } + result := flags.parse(&w, args[:]) + testing.expect_value(t, result, nil) + if result != nil { + return + } + testing.expect_value(t, w.t.date.year, 2024) + testing.expect_value(t, w.t.date.month, 6) + testing.expect_value(t, w.t.date.day, 4) + } else { + log.info("Skipping test due to lack of platform support.") + } +} + +@(test) +test_net :: proc(t: ^testing.T) { + when flags.IMPORTING_NET { + W :: struct { + addr: net.Host_Or_Endpoint, + } + w: W + + args := [?]string { "-addr:odin-lang.org:80" } + result := flags.parse(&w, args[:]) + testing.expect_value(t, result, nil) + if result != nil { + return + } + host, is_host := w.addr.(net.Host) + testing.expectf(t, is_host, "expected type of `addr` to be `net.Host`, was %v", w.addr) + testing.expect_value(t, host.hostname, "odin-lang.org") + testing.expect_value(t, host.port, 80) + } else { + log.info("Skipping test due to lack of platform support.") + } +} + +@(test) +test_custom_type_setter :: proc(t: ^testing.T) { + Custom_Bool :: distinct bool + Custom_Data :: struct { + a: int, + } + + S :: struct { + a: Custom_Data, + b: Custom_Bool `args:"indistinct"`, + } + s: S + + // NOTE: Mind that this setter is global state, and the test runner is multi-threaded. + // It should be fine so long as all type setter tests are in this one test proc. + flags.register_type_setter(proc (data: rawptr, data_type: typeid, _, _: string) -> (string, bool, runtime.Allocator_Error) { + if data_type == Custom_Data { + (cast(^Custom_Data)data).a = 32 + return "", true, nil + } + return "", false, nil + }) + defer flags.register_type_setter(nil) + args := [?]string { "-a:hellope", "-b:true" } + result := flags.parse(&s, args[:]) + testing.expect_value(t, result, nil) + testing.expect_value(t, s.a.a, 32) + testing.expect_value(t, s.b, true) +} + +// This test is sensitive to many of the underlying mechanisms of the library, +// so if something isn't working, it'll probably show up here first, but it may +// not be immediately obvious as to what's wrong. +// +// It makes for a good early warning system. +@(test) +test_usage_write_odin :: proc(t: ^testing.T) { + Expected_Output :: `Usage: + varg required-number [number] [name] -bars -bots -foos -gadgets -widgets [-array] [-count] [-greek] [-map-type] [-verbose] ... +Flags: + -required-number:, required | some number + -number: | some other number + -name: + Multi-line documentation + gets formatted + very nicely. + -bars:, exactly 3 | + -bots:, at least 1 | + -foos:, between 2 and 3 | + -gadgets:, at least 1 | + -widgets:, at most 2 | + | + -array:, multiple | + -count: | + -greek: | + -map-type:= | + -verbose | + | +` + + Custom_Enum :: enum { + Alpha, + Omega, + } + + S :: struct { + required_number: int `args:"pos=0,required" usage:"some number"`, + number: int `args:"pos=1" usage:"some other number"`, + name: string `args:"pos=2" usage:" + Multi-line documentation + gets formatted +very nicely. + +"`, + + c: u8 `args:"name=count"`, + greek: Custom_Enum, + + array: [dynamic]rune, + map_type: map[cstring]byte, + + gadgets: [dynamic]string `args:"required=1"`, + widgets: [dynamic]string `args:"required=<3"`, + foos: [dynamic]string `args:"required=2<4"`, + bars: [dynamic]string `args:"required=3<4"`, + bots: [dynamic]string `args:"required"`, + + debug: bool `args:"hidden" usage:"print debug info"`, + verbose: bool, + + varg: [dynamic]string, + } + + builder := strings.builder_make() + defer strings.builder_destroy(&builder) + writer := strings.to_stream(&builder) + flags.write_usage(writer, S, "varg", .Odin) + testing.expect_value(t, strings.to_string(builder), Expected_Output) +} + +@(test) +test_usage_write_unix :: proc(t: ^testing.T) { + Expected_Output :: `Usage: + varg required-number [number] [name] --bars --bots --foos --gadgets --variadic-flag --widgets [--array] [--count] [--greek] [--verbose] ... +Flags: + --required-number , required | some number + --number | some other number + --name + Multi-line documentation + gets formatted + very nicely. + --bars , exactly 3 | + --bots , at least 1 | + --foos , between 2 and 3 | + --gadgets , at least 1 | + --variadic-flag , at least 2 | + --widgets , at most 2 | + | + --array , multiple | + --count | + --greek | + --verbose | + | +` + + Custom_Enum :: enum { + Alpha, + Omega, + } + + S :: struct { + required_number: int `args:"pos=0,required" usage:"some number"`, + number: int `args:"pos=1" usage:"some other number"`, + name: string `args:"pos=2" usage:" + Multi-line documentation + gets formatted +very nicely. + +"`, + + c: u8 `args:"name=count"`, + greek: Custom_Enum, + + array: [dynamic]rune, + variadic_flag: [dynamic]int `args:"variadic,required=2"`, + + gadgets: [dynamic]string `args:"required=1"`, + widgets: [dynamic]string `args:"required=<3"`, + foos: [dynamic]string `args:"required=2<4"`, + bars: [dynamic]string `args:"required=3<4"`, + bots: [dynamic]string `args:"required"`, + + debug: bool `args:"hidden" usage:"print debug info"`, + verbose: bool, + + varg: [dynamic]string, + } + + builder := strings.builder_make() + defer strings.builder_destroy(&builder) + writer := strings.to_stream(&builder) + flags.write_usage(writer, S, "varg", .Unix) + testing.expect_value(t, strings.to_string(builder), Expected_Output) +} diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index c332383e7..c3f0bee91 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -53,9 +53,9 @@ test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) { testing.expect(t, xxh3_128_err == nil, "Problem initializing XXH3_128 state") // XXH3_128_update - random_seed := rand.create(t.seed) + rand.reset(t.seed) for len(b) > 0 { - update_size := min(len(b), rand.int_max(8192, &random_seed)) + update_size := min(len(b), rand.int_max(8192)) if update_size > 4096 { update_size %= 73 } diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index 54b715a4f..ad199d775 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -5,7 +5,7 @@ set TEST_ARGS=-fast-tests set TEST_ARGS=-no-random set TEST_ARGS= set OUT_NAME=math_big_test_library.dll -set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style -define:ODIN_TEST_FANCY=false +set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style echo --- echo Running core:math/big tests echo --- diff --git a/tests/core/math/fixed/test_core_math_fixed.odin b/tests/core/math/fixed/test_core_math_fixed.odin new file mode 100644 index 000000000..4fcd63422 --- /dev/null +++ b/tests/core/math/fixed/test_core_math_fixed.odin @@ -0,0 +1,51 @@ +package test_core_math_fixed + +import "core:math/fixed" +import "core:testing" + +@test +test_fixed_4_4_unsigned :: proc(t: ^testing.T) { + I_SHIFT :: 4 + F_MASK :: 15 + F_ULP :: 0.0625 + Fixed :: fixed.Fixed(u8, 4) + + for c in 0..<256 { + raw := u8(c) + fv := transmute(Fixed)raw + + i := raw >> I_SHIFT + f := raw & F_MASK + expected := f64(i) + F_ULP * f64(f) + + testing.expectf(t, fixed.to_f64(fv) == expected, "Expected Fixed(u8, 4)(%v) to equal %.5f, got %.5f", raw, expected, fixed.to_f64(fv)) + } +} + +@test +test_fixed_4_4_signed :: proc(t: ^testing.T) { + I_SHIFT :: 4 + F_MASK :: 15 + F_ULP :: 0.0625 + Fixed :: fixed.Fixed(i8, 4) + + for c in 0..<256 { + raw := i8(c) + fv := transmute(Fixed)raw + + f := raw & F_MASK + expected: f64 + if c < 128 { + i := raw >> I_SHIFT + expected = f64(i) + F_ULP * f64(f) + } else if c == 128 { + expected = 8.0 + + } else if c > 128 { + i := i8(-8) + i += (raw & 0b0111_0000) >> I_SHIFT + expected = f64(i) + F_ULP * f64(f) + } + testing.expectf(t, fixed.to_f64(fv) == expected, "Expected Fixed(i8, 4)(%v, %v) to equal %.5f, got %.5f", c, raw, expected, fixed.to_f64(fv)) + } +} \ No newline at end of file diff --git a/tests/core/math/rand/test_core_math_rand.odin b/tests/core/math/rand/test_core_math_rand.odin new file mode 100644 index 000000000..392d3d241 --- /dev/null +++ b/tests/core/math/rand/test_core_math_rand.odin @@ -0,0 +1,35 @@ +package test_core_math_rand + +import "core:math/rand" +import "core:testing" + +@test +test_default_rand_determinism :: proc(t: ^testing.T) { + rand.reset(13) + first_value := rand.int127() + rand.reset(13) + second_value := rand.int127() + + testing.expect(t, first_value == second_value, "Context default random number generator is non-deterministic.") +} + +@test +test_default_rand_determinism_user_set :: proc(t: ^testing.T) { + rng_state_1 := rand.create(13) + rng_state_2 := rand.create(13) + + rng_1 := rand.default_random_generator(&rng_state_1) + rng_2 := rand.default_random_generator(&rng_state_2) + + first_value, second_value: i128 + { + context.random_generator = rng_1 + first_value = rand.int127() + } + { + context.random_generator = rng_2 + second_value = rand.int127() + } + + testing.expect(t, first_value == second_value, "User-set default random number generator is non-deterministic.") +} diff --git a/tests/core/mem/test_mem_dynamic_pool.odin b/tests/core/mem/test_mem_dynamic_pool.odin new file mode 100644 index 000000000..80c973c68 --- /dev/null +++ b/tests/core/mem/test_mem_dynamic_pool.odin @@ -0,0 +1,80 @@ +package test_core_mem + +import "core:testing" +import "core:mem" + + +expect_pool_allocation :: proc(t: ^testing.T, expected_used_bytes, num_bytes, alignment: int) { + pool: mem.Dynamic_Pool + mem.dynamic_pool_init(pool = &pool, alignment = alignment) + pool_allocator := mem.dynamic_pool_allocator(&pool) + + element, err := mem.alloc(num_bytes, alignment, pool_allocator) + testing.expect(t, err == .None) + testing.expect(t, element != nil) + + expected_bytes_left := pool.block_size - expected_used_bytes + testing.expectf(t, pool.bytes_left == expected_bytes_left, + ` + Allocated data with size %v bytes, expected %v bytes left, got %v bytes left, off by %v bytes. + Pool: + block_size = %v + out_band_size = %v + alignment = %v + unused_blocks = %v + used_blocks = %v + out_band_allocations = %v + current_block = %v + current_pos = %v + bytes_left = %v + `, + num_bytes, expected_bytes_left, pool.bytes_left, expected_bytes_left - pool.bytes_left, + pool.block_size, + pool.out_band_size, + pool.alignment, + pool.unused_blocks, + pool.used_blocks, + pool.out_band_allocations, + pool.current_block, + pool.current_pos, + pool.bytes_left, + ) + + mem.dynamic_pool_destroy(&pool) + testing.expect(t, pool.used_blocks == nil) +} + +expect_pool_allocation_out_of_band :: proc(t: ^testing.T, num_bytes, out_band_size: int) { + testing.expect(t, num_bytes >= out_band_size, "Sanity check failed, your test call is flawed! Make sure that num_bytes >= out_band_size!") + + pool: mem.Dynamic_Pool + mem.dynamic_pool_init(pool = &pool, out_band_size = out_band_size) + pool_allocator := mem.dynamic_pool_allocator(&pool) + + element, err := mem.alloc(num_bytes, allocator = pool_allocator) + testing.expect(t, err == .None) + testing.expect(t, element != nil) + testing.expectf(t, pool.out_band_allocations != nil, + "Allocated data with size %v bytes, which is >= out_of_band_size and it should be in pool.out_band_allocations, but isn't!", + ) + + mem.dynamic_pool_destroy(&pool) + testing.expect(t, pool.out_band_allocations == nil) +} + +@(test) +test_dynamic_pool_alloc_aligned :: proc(t: ^testing.T) { + expect_pool_allocation(t, expected_used_bytes = 16, num_bytes = 16, alignment=8) +} + +@(test) +test_dynamic_pool_alloc_unaligned :: proc(t: ^testing.T) { + expect_pool_allocation(t, expected_used_bytes = 8, num_bytes=1, alignment=8) + expect_pool_allocation(t, expected_used_bytes = 16, num_bytes=9, alignment=8) +} + +@(test) +test_dynamic_pool_alloc_out_of_band :: proc(t: ^testing.T) { + expect_pool_allocation_out_of_band(t, num_bytes = 128, out_band_size = 128) + expect_pool_allocation_out_of_band(t, num_bytes = 129, out_band_size = 128) +} \ No newline at end of file diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin index f806463e9..a8f41082a 100644 --- a/tests/core/net/test_core_net.odin +++ b/tests/core/net/test_core_net.odin @@ -18,6 +18,7 @@ import "core:sync" import "core:time" import "core:thread" import "core:fmt" +import "core:log" @test address_parsing_test :: proc(t: ^testing.T) { @@ -216,6 +217,8 @@ IP_Address_Parsing_Test_Vectors :: []IP_Address_Parsing_Test_Vector{ ENDPOINT_TWO_SERVERS := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9991} ENDPOINT_CLOSED_PORT := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9992} ENDPOINT_SERVER_SENDS := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9993} +ENDPOINT_UDP_ECHO := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9994} +ENDPOINT_NONBLOCK := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9995} @(test) two_servers_binding_same_endpoint :: proc(t: ^testing.T) { @@ -256,7 +259,7 @@ client_sends_server_data :: proc(t: ^testing.T) { } tcp_client :: proc(thread_data: rawptr) { - r := transmute(^Thread_Data)thread_data + r := cast(^Thread_Data)thread_data defer sync.wait_group_done(r.wg) @@ -271,7 +274,7 @@ client_sends_server_data :: proc(t: ^testing.T) { } tcp_server :: proc(thread_data: rawptr) { - r := transmute(^Thread_Data)thread_data + r := cast(^Thread_Data)thread_data defer sync.wait_group_done(r.wg) @@ -516,6 +519,102 @@ join_url_test :: proc(t: ^testing.T) { } } +@test +test_udp_echo :: proc(t: ^testing.T) { + server, make_server_err := net.make_unbound_udp_socket(.IP4) + if !testing.expect_value(t, make_server_err, nil) { + return + } + defer net.close(server) + + bind_server_err := net.bind(server, ENDPOINT_UDP_ECHO) + if !testing.expect_value(t, bind_server_err, nil) { + return + } + + client, make_client_err := net.make_unbound_udp_socket(.IP4) + if !testing.expect_value(t, make_client_err, nil) { + return + } + defer net.close(client) + + msg := "Hellope world!" + buf: [64]u8 + + bytes_written, send_err := net.send_udp(client, transmute([]u8)msg[:], ENDPOINT_UDP_ECHO) + if !testing.expect_value(t, send_err, nil) { + return + } + if !testing.expect_value(t, bytes_written, len(msg)) { + return + } + + bytes_read, _, read_err := net.recv_udp(server, buf[:]) + if !testing.expect_value(t, read_err, nil) { + return + } + if !testing.expect_value(t, bytes_read, len(msg)) { + return + } + + testing.expect_value(t, msg, transmute(string)buf[:bytes_read]) +} + +@test +test_dns_resolve :: proc(t: ^testing.T) { + // NOTE: This test depends on external factors, so if it fails, an IP + // address may have changed or become unavailable. + + // The net API returns only one address per protocol version, and DNS + // records can store many, so we'll have to check all possibilities. + ep4, ep6, resolve_err := net.resolve("dns.quad9.net") + if !testing.expect_value(t, resolve_err, nil) { + return + } + + ip4, ip4_ok := ep4.address.(net.IP4_Address) + if !testing.expect(t, ip4_ok, "Unable to resolve IP4") { + return + } + + valid_ip4_a := net.IP4_Address{ 9, 9, 9, 9} + valid_ip4_b := net.IP4_Address{149, 112, 112, 112} + if ip4 != valid_ip4_a && ip4 != valid_ip4_b { + log.errorf("DNS resolved to invalid IP4: %v, expected %v or %v", ip4, valid_ip4_a, valid_ip4_b) + } + + ip6, ip6_ok := ep6.address.(net.IP6_Address) + if !testing.expect(t, ip6_ok, "Unable to resolve IP6") { + return + } + + valid_ip6_a := net.IP6_Address{0x2620, 0xfe, 0, 0, 0, 0, 0, 9} + valid_ip6_b := net.IP6_Address{0x2620, 0xfe, 0, 0, 0, 0, 0, 0xfe} + if ip6 != valid_ip6_a && ip6 != valid_ip6_b { + log.errorf("DNS resolved to invalid IP6: %v, expected %v or %v", ip6, valid_ip6_a, valid_ip6_b) + } +} + +@test +test_nonblocking_option :: proc(t: ^testing.T) { + server, listen_err := net.listen_tcp(ENDPOINT_NONBLOCK) + if !testing.expect_value(t, listen_err, nil) { + return + } + defer net.close(server) + + testing.set_fail_timeout(t, 2 * time.Second) + + // If the nonblocking option isn't set correctly in the operating system, + // this should block until the timeout hits. + net.set_blocking(server, false) + + _, _, accept_err := net.accept_tcp(server) + if !testing.expect_value(t, accept_err, net.Accept_Error.Would_Block) { + return + } +} + @(private) address_to_binstr :: proc(address: net.Address) -> (binstr: string) { switch t in address { diff --git a/tests/core/normal.odin b/tests/core/normal.odin index 7620d7d6e..065090be3 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -17,13 +17,16 @@ download_assets :: proc() { @(require) import "encoding/hex" @(require) import "encoding/hxa" @(require) import "encoding/json" +@(require) import "encoding/uuid" @(require) import "encoding/varint" @(require) import "encoding/xml" +@(require) import "flags" @(require) import "fmt" @(require) import "math" @(require) import "math/big" @(require) import "math/linalg/glsl" @(require) import "math/noise" +@(require) import "math/rand" @(require) import "mem" @(require) import "net" @(require) import "odin" @@ -37,3 +40,4 @@ download_assets :: proc() { @(require) import "text/match" @(require) import "thread" @(require) import "time" +@(require) import "unicode" diff --git a/tests/core/path/filepath/test_core_filepath.odin b/tests/core/path/filepath/test_core_filepath.odin index 94b9329bb..f0137f69b 100644 --- a/tests/core/path/filepath/test_core_filepath.odin +++ b/tests/core/path/filepath/test_core_filepath.odin @@ -35,12 +35,10 @@ test_split_list_windows :: proc(t: ^testing.T) { assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) r := filepath.split_list(d.v) defer delete_split(r) - testing.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", - i, #procedure, d.v, len(r), len(d.e))) + testing.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", i, #procedure, d.v, len(r), len(d.e))) if len(r) == len(d.e) { for _, j in r { - testing.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", - i, #procedure, d.v, r[j], j, d.e[j])) + testing.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", i, #procedure, d.v, r[j], j, d.e[j])) } } } diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 23de1b482..3e249055b 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -3,6 +3,7 @@ package test_core_slice import "core:slice" import "core:testing" import "core:math/rand" +import "core:log" @test test_sort_with_indices :: proc(t: ^testing.T) { @@ -10,7 +11,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { test_sizes :: []int{7, 13, 347, 1031, 10111, 100003} for test_size in test_sizes { - r := rand.create(t.seed) + rand.reset(t.seed) vals := make([]u64, test_size) r_idx := make([]int, test_size) // Reverse index @@ -21,7 +22,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { // Set up test values for _, i in vals { - vals[i] = rand.uint64(&r) + vals[i] = rand.uint64() } // Sort @@ -29,7 +30,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { defer delete(f_idx) // Verify sorted test values - rand.init(&r, t.seed) + rand.reset(t.seed) for v, i in f_idx { r_idx[v] = i @@ -45,7 +46,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { } } - idx_pass := vals[r_idx[i]] == rand.uint64(&r) + idx_pass := vals[r_idx[i]] == rand.uint64() testing.expect(t, idx_pass, "Expected index to have been sorted") if !idx_pass { break @@ -61,7 +62,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { test_sizes :: []int{7, 13, 347, 1031, 10111, 100003} for test_size in test_sizes { - r := rand.create(t.seed) + rand.reset(t.seed) vals := make([]u64, test_size) r_idx := make([]int, test_size) // Reverse index @@ -72,7 +73,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { // Set up test values for _, i in vals { - vals[i] = rand.uint64(&r) + vals[i] = rand.uint64() } // Sort @@ -80,7 +81,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { defer delete(f_idx) // Verify sorted test values - rand.init(&r, t.seed) + rand.reset(t.seed) { indices := make([]int, test_size) @@ -200,12 +201,12 @@ test_permutation_iterator :: proc(t: ^testing.T) { permutations_counted: int for slice.permute(&iter) { n := 0 - for item, index in s { + for item in s { n *= 10 n += item } if n in seen { - testing.fail_now(t, "Permutation iterator made a duplicate permutation.") + log.error("Permutation iterator made a duplicate permutation.") return } seen[n] = true @@ -215,3 +216,63 @@ test_permutation_iterator :: proc(t: ^testing.T) { testing.expect_value(t, len(seen), FAC_5) testing.expect_value(t, permutations_counted, FAC_5) } + +// Test inputs from #3276 and #3769 +UNIQUE_TEST_VECTORS :: [][2][]int{ + {{2,2,2}, {2}}, + {{1,1,1,2,2,3,3,3,3}, {1,2,3}}, + {{1,2,4,4,5}, {1,2,4,5}}, +} + +@test +test_unique :: proc(t: ^testing.T) { + for v in UNIQUE_TEST_VECTORS { + assorted := v[0] + expected := v[1] + + uniq := slice.unique(assorted) + testing.expectf(t, slice.equal(uniq, expected), "Expected slice.uniq(%v) == %v, got %v", v[0], v[1], uniq) + } + + for v in UNIQUE_TEST_VECTORS { + assorted := v[0] + expected := v[1] + + uniq := slice.unique_proc(assorted, proc(a, b: int) -> bool { + return a == b + }) + testing.expectf(t, slice.equal(uniq, expected), "Expected slice.unique_proc(%v, ...) == %v, got %v", v[0], v[1], uniq) + } + + r := rand.create(t.seed) + context.random_generator = rand.default_random_generator(&r) + + // 10_000 random tests + for _ in 0..<10_000 { + assorted: [dynamic]i64 + expected: [dynamic]i64 + + // Prime with 1 value + old := rand.int63() + append(&assorted, old) + append(&expected, old) + + // Add 99 additional random values + for _ in 1..<100 { + new := rand.int63() + append(&assorted, new) + if old != new { + append(&expected, new) + } + old = new + } + + original := slice.clone(assorted[:]) + uniq := slice.unique(assorted[:]) + testing.expectf(t, slice.equal(uniq, expected[:]), "Expected slice.uniq(%v) == %v, got %v", original, expected, uniq) + + delete(assorted) + delete(original) + delete(expected) + } +} \ No newline at end of file diff --git a/tests/core/text/i18n/test_core_text_i18n.odin b/tests/core/text/i18n/test_core_text_i18n.odin index f6cffc318..4c70bd8b9 100644 --- a/tests/core/text/i18n/test_core_text_i18n.odin +++ b/tests/core/text/i18n/test_core_text_i18n.odin @@ -5,6 +5,7 @@ import "core:testing" import "core:text/i18n" T :: i18n.get +Tn :: i18n.get_n Test :: struct { section: string, @@ -47,7 +48,8 @@ test_custom_pluralizer :: proc(t: ^testing.T) { {"", "Message1/plural", "This is message 1", 1}, {"", "Message1/plural", "This is message 1 - plural A", 1_000_000}, {"", "Message1/plural", "This is message 1 - plural B", 42}, - // This isn't in the catalog, so should ruturn the key. + + // This isn't in the catalog, so should return the key. {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, }, }) @@ -61,11 +63,11 @@ test_mixed_context :: proc(t: ^testing.T) { plural = nil, tests = { // These are in the catalog. - {"", "Message1", "This is message 1 without Context", 1}, - {"Context", "Message1", "This is message 1 with Context", 1}, + {"", "Message1", "This is message 1 without Context",-1}, + {"Context", "Message1", "This is message 1 with Context", -1}, // This isn't in the catalog, so should ruturn the key. - {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, + {"", "Come visit us on Discord!", "Come visit us on Discord!", -1}, }, }) } @@ -90,15 +92,15 @@ test_nl_mo :: proc(t: ^testing.T) { plural = nil, // Default pluralizer tests = { // These are in the catalog. - {"", "There are 69,105 leaves here.", "Er zijn hier 69.105 bladeren.", 1}, - {"", "Hellope, World!", "Hallo, Wereld!", 1}, + {"", "There are 69,105 leaves here.", "Er zijn hier 69.105 bladeren.", -1}, + {"", "Hellope, World!", "Hallo, Wereld!", -1}, {"", "There is %d leaf.\n", "Er is %d blad.\n", 1}, {"", "There are %d leaves.\n", "Er is %d blad.\n", 1}, {"", "There is %d leaf.\n", "Er zijn %d bladeren.\n", 42}, {"", "There are %d leaves.\n", "Er zijn %d bladeren.\n", 42}, // This isn't in the catalog, so should ruturn the key. - {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, + {"", "Come visit us on Discord!", "Come visit us on Discord!", -1}, }, }) } @@ -111,15 +113,15 @@ test_qt_linguist :: proc(t: ^testing.T) { plural = nil, // Default pluralizer tests = { // These are in the catalog. - {"Page", "Text for translation", "Tekst om te vertalen", 1}, - {"Page", "Also text to translate", "Ook tekst om te vertalen", 1}, - {"installscript", "99 bottles of beer on the wall", "99 flessen bier op de muur", 1}, + {"Page", "Text for translation", "Tekst om te vertalen", -1}, + {"Page", "Also text to translate", "Ook tekst om te vertalen", -1}, + {"installscript", "99 bottles of beer on the wall", "99 flessen bier op de muur", -1}, {"apple_count", "%d apple(s)", "%d appel", 1}, {"apple_count", "%d apple(s)", "%d appels", 42}, // These aren't in the catalog, so should ruturn the key. - {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, - {"Fake_Section", "Come visit us on Discord!", "Come visit us on Discord!", 1}, + {"", "Come visit us on Discord!", "Come visit us on Discord!", -1}, + {"Fake_Section", "Come visit us on Discord!", "Come visit us on Discord!", -1}, }, }) } @@ -133,16 +135,16 @@ test_qt_linguist_merge_sections :: proc(t: ^testing.T) { options = {merge_sections = true}, tests = { // All of them are now in section "", lookup with original section should return the key. - {"", "Text for translation", "Tekst om te vertalen", 1}, - {"", "Also text to translate", "Ook tekst om te vertalen", 1}, - {"", "99 bottles of beer on the wall", "99 flessen bier op de muur", 1}, + {"", "Text for translation", "Tekst om te vertalen", -1}, + {"", "Also text to translate", "Ook tekst om te vertalen", -1}, + {"", "99 bottles of beer on the wall", "99 flessen bier op de muur", -1}, {"", "%d apple(s)", "%d appel", 1}, {"", "%d apple(s)", "%d appels", 42}, // All of them are now in section "", lookup with original section should return the key. - {"Page", "Text for translation", "Text for translation", 1}, - {"Page", "Also text to translate", "Also text to translate", 1}, - {"installscript", "99 bottles of beer on the wall", "99 bottles of beer on the wall", 1}, + {"Page", "Text for translation", "Text for translation", -1}, + {"Page", "Also text to translate", "Also text to translate", -1}, + {"installscript", "99 bottles of beer on the wall", "99 bottles of beer on the wall", -1}, {"apple_count", "%d apple(s)", "%d apple(s)", 1}, {"apple_count", "%d apple(s)", "%d apple(s)", 42}, }, @@ -175,7 +177,7 @@ test :: proc(t: ^testing.T, suite: Test_Suite, loc := #caller_location) { if err == .None { for test in suite.tests { - val := T(test.section, test.key, test.n, cat) + val := test.n > -1 ? Tn(test.section, test.key, test.n, cat): T(test.section, test.key, cat) testing.expectf(t, val == test.val, "Expected key `%v` from section `%v`'s form for value `%v` to equal `%v`, got `%v`", test.key, test.section, test.n, test.val, val, loc=loc) } } diff --git a/tests/core/unicode/test_core_unicode.odin b/tests/core/unicode/test_core_unicode.odin new file mode 100644 index 000000000..a1f6ac934 --- /dev/null +++ b/tests/core/unicode/test_core_unicode.odin @@ -0,0 +1,135 @@ +package test_core_unicode + +import "core:log" +import "core:testing" +import "core:unicode/utf8" + +Test_Case :: struct { + str: string, + expected_clusters: int, +} + +run_test_cases :: proc(t: ^testing.T, test_cases: []Test_Case, loc := #caller_location) { + failed := 0 + for c, i in test_cases { + log.debugf("(#% 4i) %q ...", i, c.str) + result, _, _ := utf8.grapheme_count(c.str) + if !testing.expectf(t, result == c.expected_clusters, + "(#% 4i) graphemes: %i != %i, %q %s", i, result, c.expected_clusters, c.str, c.str, + loc = loc) + { + failed += 1 + } + } + + log.logf(.Error if failed > 0 else .Info, "% 4i/% 4i test cases failed.", failed, len(test_cases), location = loc) +} + +@test +test_official_gcb_cases :: proc(t: ^testing.T) { + run_test_cases(t, official_grapheme_break_test_cases) +} + +@test +test_official_emoji_cases :: proc(t: ^testing.T) { + run_test_cases(t, official_emoji_test_cases) +} + +@test +test_grapheme_byte_index_segmentation :: proc(t: ^testing.T) { + SAMPLE_1 :: "\U0001F600" + SAMPLE_2 :: "\U0001F3F4\U000E0067\U000E0062\U000E0065\U000E006E\U000E0067\U000E007F" + SAMPLE_3 :: "\U0001F468\U0001F3FB\u200D\U0001F9B0" + + str := SAMPLE_1 + SAMPLE_2 + SAMPLE_3 + SAMPLE_2 + SAMPLE_1 + + graphemes, _, _, _ := utf8.decode_grapheme_clusters(str) + defer delete(graphemes) + + defer if testing.failed(t) { + log.infof("%#v\n%q\n%v", graphemes, str, transmute([]u8)str) + } + if !testing.expect_value(t, len(graphemes), 5) { + return + } + + testing.expect_value(t, graphemes[0].rune_index, 0) + testing.expect_value(t, graphemes[1].rune_index, 1) + testing.expect_value(t, graphemes[2].rune_index, 8) + testing.expect_value(t, graphemes[3].rune_index, 12) + testing.expect_value(t, graphemes[4].rune_index, 19) + + grapheme_1 := str[graphemes[0].byte_index:graphemes[1].byte_index] + grapheme_2 := str[graphemes[1].byte_index:graphemes[2].byte_index] + grapheme_3 := str[graphemes[2].byte_index:graphemes[3].byte_index] + grapheme_4 := str[graphemes[3].byte_index:graphemes[4].byte_index] + grapheme_5 := str[graphemes[4].byte_index:] + + testing.expectf(t, grapheme_1 == SAMPLE_1, "expected %q, got %q", SAMPLE_1, grapheme_1) + testing.expectf(t, grapheme_2 == SAMPLE_2, "expected %q, got %q", SAMPLE_2, grapheme_2) + testing.expectf(t, grapheme_3 == SAMPLE_3, "expected %q, got %q", SAMPLE_3, grapheme_3) + testing.expectf(t, grapheme_4 == SAMPLE_2, "expected %q, got %q", SAMPLE_2, grapheme_2) + testing.expectf(t, grapheme_5 == SAMPLE_1, "expected %q, got %q", SAMPLE_1, grapheme_1) +} + +@test +test_width :: proc(t: ^testing.T) { + { + str := "He\u200dllo" + graphemes, _, width := utf8.grapheme_count(str) + testing.expect_value(t, graphemes, 5) + testing.expect_value(t, width, 5) + } + + { + // Note that a zero-width space is still considered a grapheme as far + // as the specification is concerned. + str := "He\u200bllo" + graphemes, _, width := utf8.grapheme_count(str) + testing.expect_value(t, graphemes, 6) + testing.expect_value(t, width, 5) + } + + { + str := "\U0001F926\U0001F3FC\u200D\u2642" + graphemes, _, width := utf8.grapheme_count(str) + testing.expect_value(t, graphemes, 1) + testing.expect_value(t, width, 2) + } + + { + str := "H̷e̶l̵l̸o̴p̵e̷ ̸w̶o̸r̵l̶d̵!̴" + graphemes, _, width := utf8.grapheme_count(str) + testing.expect_value(t, graphemes, 14) + testing.expect_value(t, width, 14) + } + + { + str := "aカ.ヒフ" + graphemes, grapheme_count, _, width := utf8.decode_grapheme_clusters(str) + defer delete(graphemes) + testing.expect_value(t, grapheme_count, 5) + testing.expect_value(t, width, 8) + if grapheme_count == 5 { + testing.expect_value(t, graphemes[0].width, 1) + testing.expect_value(t, graphemes[1].width, 2) + testing.expect_value(t, graphemes[2].width, 1) + testing.expect_value(t, graphemes[3].width, 2) + testing.expect_value(t, graphemes[4].width, 2) + } + } + + { + str := "いろはにほへ" + graphemes, _, width := utf8.grapheme_count(str) + testing.expect_value(t, graphemes, 6) + testing.expect_value(t, width, 12) + } + + { + str := "舍利弗,是諸法空相,不生不滅,不垢不淨,不增不減。" + graphemes, _, width := utf8.grapheme_count(str) + testing.expect_value(t, graphemes, 25) + testing.expect_value(t, width, 50) + } +} diff --git a/tests/core/unicode/test_core_unicode_data.odin b/tests/core/unicode/test_core_unicode_data.odin new file mode 100644 index 000000000..594af3c65 --- /dev/null +++ b/tests/core/unicode/test_core_unicode_data.odin @@ -0,0 +1,4912 @@ +package test_core_unicode + +// This file contains test data licensed under the Unicode Consortium that has +// been converted to a format that will work within Odin. +// +// The Unicode license to which said test data is under is included verbatim +// within this file, along with the names of the files from which the test data +// has been converted. + +/* +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2024 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. +*/ + + +// https://unicode.org/Public/15.1.0/ucd/auxiliary/GraphemeBreakTest.txt +// +// GraphemeBreakTest-15.1.0.txt +// Date: 2023-08-07, 15:52:55 GMT +// © 2023 Unicode®, Inc. +// Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +// For terms of use, see https://www.unicode.org/terms_of_use.html +@(rodata) +official_grapheme_break_test_cases := []Test_Case { +{"\u0020\u0020", 2}, +{"\u0020\u0308\u0020", 2}, +{"\u0020\u000D", 2}, +{"\u0020\u0308\u000D", 2}, +{"\u0020\u000A", 2}, +{"\u0020\u0308\u000A", 2}, +{"\u0020\u0001", 2}, +{"\u0020\u0308\u0001", 2}, +{"\u0020\u034F", 1}, +{"\u0020\u0308\u034F", 1}, +{"\u0020\U0001F1E6", 2}, +{"\u0020\u0308\U0001F1E6", 2}, +{"\u0020\u0600", 2}, +{"\u0020\u0308\u0600", 2}, +{"\u0020\u0A03", 1}, +{"\u0020\u0308\u0A03", 1}, +{"\u0020\u1100", 2}, +{"\u0020\u0308\u1100", 2}, +{"\u0020\u1160", 2}, +{"\u0020\u0308\u1160", 2}, +{"\u0020\u11A8", 2}, +{"\u0020\u0308\u11A8", 2}, +{"\u0020\uAC00", 2}, +{"\u0020\u0308\uAC00", 2}, +{"\u0020\uAC01", 2}, +{"\u0020\u0308\uAC01", 2}, +{"\u0020\u0900", 1}, +{"\u0020\u0308\u0900", 1}, +{"\u0020\u0903", 1}, +{"\u0020\u0308\u0903", 1}, +{"\u0020\u0904", 2}, +{"\u0020\u0308\u0904", 2}, +{"\u0020\u0D4E", 2}, +{"\u0020\u0308\u0D4E", 2}, +{"\u0020\u0915", 2}, +{"\u0020\u0308\u0915", 2}, +{"\u0020\u231A", 2}, +{"\u0020\u0308\u231A", 2}, +{"\u0020\u0300", 1}, +{"\u0020\u0308\u0300", 1}, +{"\u0020\u093C", 1}, +{"\u0020\u0308\u093C", 1}, +{"\u0020\u094D", 1}, +{"\u0020\u0308\u094D", 1}, +{"\u0020\u200D", 1}, +{"\u0020\u0308\u200D", 1}, +{"\u0020\u0378", 2}, +{"\u0020\u0308\u0378", 2}, +{"\u000D\u0020", 2}, +{"\u000D\u0308\u0020", 3}, +{"\u000D\u000D", 2}, +{"\u000D\u0308\u000D", 3}, +{"\u000D\u000A", 1}, +{"\u000D\u0308\u000A", 3}, +{"\u000D\u0001", 2}, +{"\u000D\u0308\u0001", 3}, +{"\u000D\u034F", 2}, +{"\u000D\u0308\u034F", 2}, +{"\u000D\U0001F1E6", 2}, +{"\u000D\u0308\U0001F1E6", 3}, +{"\u000D\u0600", 2}, +{"\u000D\u0308\u0600", 3}, +{"\u000D\u0A03", 2}, +{"\u000D\u0308\u0A03", 2}, +{"\u000D\u1100", 2}, +{"\u000D\u0308\u1100", 3}, +{"\u000D\u1160", 2}, +{"\u000D\u0308\u1160", 3}, +{"\u000D\u11A8", 2}, +{"\u000D\u0308\u11A8", 3}, +{"\u000D\uAC00", 2}, +{"\u000D\u0308\uAC00", 3}, +{"\u000D\uAC01", 2}, +{"\u000D\u0308\uAC01", 3}, +{"\u000D\u0900", 2}, +{"\u000D\u0308\u0900", 2}, +{"\u000D\u0903", 2}, +{"\u000D\u0308\u0903", 2}, +{"\u000D\u0904", 2}, +{"\u000D\u0308\u0904", 3}, +{"\u000D\u0D4E", 2}, +{"\u000D\u0308\u0D4E", 3}, +{"\u000D\u0915", 2}, +{"\u000D\u0308\u0915", 3}, +{"\u000D\u231A", 2}, +{"\u000D\u0308\u231A", 3}, +{"\u000D\u0300", 2}, +{"\u000D\u0308\u0300", 2}, +{"\u000D\u093C", 2}, +{"\u000D\u0308\u093C", 2}, +{"\u000D\u094D", 2}, +{"\u000D\u0308\u094D", 2}, +{"\u000D\u200D", 2}, +{"\u000D\u0308\u200D", 2}, +{"\u000D\u0378", 2}, +{"\u000D\u0308\u0378", 3}, +{"\u000A\u0020", 2}, +{"\u000A\u0308\u0020", 3}, +{"\u000A\u000D", 2}, +{"\u000A\u0308\u000D", 3}, +{"\u000A\u000A", 2}, +{"\u000A\u0308\u000A", 3}, +{"\u000A\u0001", 2}, +{"\u000A\u0308\u0001", 3}, +{"\u000A\u034F", 2}, +{"\u000A\u0308\u034F", 2}, +{"\u000A\U0001F1E6", 2}, +{"\u000A\u0308\U0001F1E6", 3}, +{"\u000A\u0600", 2}, +{"\u000A\u0308\u0600", 3}, +{"\u000A\u0A03", 2}, +{"\u000A\u0308\u0A03", 2}, +{"\u000A\u1100", 2}, +{"\u000A\u0308\u1100", 3}, +{"\u000A\u1160", 2}, +{"\u000A\u0308\u1160", 3}, +{"\u000A\u11A8", 2}, +{"\u000A\u0308\u11A8", 3}, +{"\u000A\uAC00", 2}, +{"\u000A\u0308\uAC00", 3}, +{"\u000A\uAC01", 2}, +{"\u000A\u0308\uAC01", 3}, +{"\u000A\u0900", 2}, +{"\u000A\u0308\u0900", 2}, +{"\u000A\u0903", 2}, +{"\u000A\u0308\u0903", 2}, +{"\u000A\u0904", 2}, +{"\u000A\u0308\u0904", 3}, +{"\u000A\u0D4E", 2}, +{"\u000A\u0308\u0D4E", 3}, +{"\u000A\u0915", 2}, +{"\u000A\u0308\u0915", 3}, +{"\u000A\u231A", 2}, +{"\u000A\u0308\u231A", 3}, +{"\u000A\u0300", 2}, +{"\u000A\u0308\u0300", 2}, +{"\u000A\u093C", 2}, +{"\u000A\u0308\u093C", 2}, +{"\u000A\u094D", 2}, +{"\u000A\u0308\u094D", 2}, +{"\u000A\u200D", 2}, +{"\u000A\u0308\u200D", 2}, +{"\u000A\u0378", 2}, +{"\u000A\u0308\u0378", 3}, +{"\u0001\u0020", 2}, +{"\u0001\u0308\u0020", 3}, +{"\u0001\u000D", 2}, +{"\u0001\u0308\u000D", 3}, +{"\u0001\u000A", 2}, +{"\u0001\u0308\u000A", 3}, +{"\u0001\u0001", 2}, +{"\u0001\u0308\u0001", 3}, +{"\u0001\u034F", 2}, +{"\u0001\u0308\u034F", 2}, +{"\u0001\U0001F1E6", 2}, +{"\u0001\u0308\U0001F1E6", 3}, +{"\u0001\u0600", 2}, +{"\u0001\u0308\u0600", 3}, +{"\u0001\u0A03", 2}, +{"\u0001\u0308\u0A03", 2}, +{"\u0001\u1100", 2}, +{"\u0001\u0308\u1100", 3}, +{"\u0001\u1160", 2}, +{"\u0001\u0308\u1160", 3}, +{"\u0001\u11A8", 2}, +{"\u0001\u0308\u11A8", 3}, +{"\u0001\uAC00", 2}, +{"\u0001\u0308\uAC00", 3}, +{"\u0001\uAC01", 2}, +{"\u0001\u0308\uAC01", 3}, +{"\u0001\u0900", 2}, +{"\u0001\u0308\u0900", 2}, +{"\u0001\u0903", 2}, +{"\u0001\u0308\u0903", 2}, +{"\u0001\u0904", 2}, +{"\u0001\u0308\u0904", 3}, +{"\u0001\u0D4E", 2}, +{"\u0001\u0308\u0D4E", 3}, +{"\u0001\u0915", 2}, +{"\u0001\u0308\u0915", 3}, +{"\u0001\u231A", 2}, +{"\u0001\u0308\u231A", 3}, +{"\u0001\u0300", 2}, +{"\u0001\u0308\u0300", 2}, +{"\u0001\u093C", 2}, +{"\u0001\u0308\u093C", 2}, +{"\u0001\u094D", 2}, +{"\u0001\u0308\u094D", 2}, +{"\u0001\u200D", 2}, +{"\u0001\u0308\u200D", 2}, +{"\u0001\u0378", 2}, +{"\u0001\u0308\u0378", 3}, +{"\u034F\u0020", 2}, +{"\u034F\u0308\u0020", 2}, +{"\u034F\u000D", 2}, +{"\u034F\u0308\u000D", 2}, +{"\u034F\u000A", 2}, +{"\u034F\u0308\u000A", 2}, +{"\u034F\u0001", 2}, +{"\u034F\u0308\u0001", 2}, +{"\u034F\u034F", 1}, +{"\u034F\u0308\u034F", 1}, +{"\u034F\U0001F1E6", 2}, +{"\u034F\u0308\U0001F1E6", 2}, +{"\u034F\u0600", 2}, +{"\u034F\u0308\u0600", 2}, +{"\u034F\u0A03", 1}, +{"\u034F\u0308\u0A03", 1}, +{"\u034F\u1100", 2}, +{"\u034F\u0308\u1100", 2}, +{"\u034F\u1160", 2}, +{"\u034F\u0308\u1160", 2}, +{"\u034F\u11A8", 2}, +{"\u034F\u0308\u11A8", 2}, +{"\u034F\uAC00", 2}, +{"\u034F\u0308\uAC00", 2}, +{"\u034F\uAC01", 2}, +{"\u034F\u0308\uAC01", 2}, +{"\u034F\u0900", 1}, +{"\u034F\u0308\u0900", 1}, +{"\u034F\u0903", 1}, +{"\u034F\u0308\u0903", 1}, +{"\u034F\u0904", 2}, +{"\u034F\u0308\u0904", 2}, +{"\u034F\u0D4E", 2}, +{"\u034F\u0308\u0D4E", 2}, +{"\u034F\u0915", 2}, +{"\u034F\u0308\u0915", 2}, +{"\u034F\u231A", 2}, +{"\u034F\u0308\u231A", 2}, +{"\u034F\u0300", 1}, +{"\u034F\u0308\u0300", 1}, +{"\u034F\u093C", 1}, +{"\u034F\u0308\u093C", 1}, +{"\u034F\u094D", 1}, +{"\u034F\u0308\u094D", 1}, +{"\u034F\u200D", 1}, +{"\u034F\u0308\u200D", 1}, +{"\u034F\u0378", 2}, +{"\u034F\u0308\u0378", 2}, +{"\U0001F1E6\u0020", 2}, +{"\U0001F1E6\u0308\u0020", 2}, +{"\U0001F1E6\u000D", 2}, +{"\U0001F1E6\u0308\u000D", 2}, +{"\U0001F1E6\u000A", 2}, +{"\U0001F1E6\u0308\u000A", 2}, +{"\U0001F1E6\u0001", 2}, +{"\U0001F1E6\u0308\u0001", 2}, +{"\U0001F1E6\u034F", 1}, +{"\U0001F1E6\u0308\u034F", 1}, +{"\U0001F1E6\U0001F1E6", 1}, +{"\U0001F1E6\u0308\U0001F1E6", 2}, +{"\U0001F1E6\u0600", 2}, +{"\U0001F1E6\u0308\u0600", 2}, +{"\U0001F1E6\u0A03", 1}, +{"\U0001F1E6\u0308\u0A03", 1}, +{"\U0001F1E6\u1100", 2}, +{"\U0001F1E6\u0308\u1100", 2}, +{"\U0001F1E6\u1160", 2}, +{"\U0001F1E6\u0308\u1160", 2}, +{"\U0001F1E6\u11A8", 2}, +{"\U0001F1E6\u0308\u11A8", 2}, +{"\U0001F1E6\uAC00", 2}, +{"\U0001F1E6\u0308\uAC00", 2}, +{"\U0001F1E6\uAC01", 2}, +{"\U0001F1E6\u0308\uAC01", 2}, +{"\U0001F1E6\u0900", 1}, +{"\U0001F1E6\u0308\u0900", 1}, +{"\U0001F1E6\u0903", 1}, +{"\U0001F1E6\u0308\u0903", 1}, +{"\U0001F1E6\u0904", 2}, +{"\U0001F1E6\u0308\u0904", 2}, +{"\U0001F1E6\u0D4E", 2}, +{"\U0001F1E6\u0308\u0D4E", 2}, +{"\U0001F1E6\u0915", 2}, +{"\U0001F1E6\u0308\u0915", 2}, +{"\U0001F1E6\u231A", 2}, +{"\U0001F1E6\u0308\u231A", 2}, +{"\U0001F1E6\u0300", 1}, +{"\U0001F1E6\u0308\u0300", 1}, +{"\U0001F1E6\u093C", 1}, +{"\U0001F1E6\u0308\u093C", 1}, +{"\U0001F1E6\u094D", 1}, +{"\U0001F1E6\u0308\u094D", 1}, +{"\U0001F1E6\u200D", 1}, +{"\U0001F1E6\u0308\u200D", 1}, +{"\U0001F1E6\u0378", 2}, +{"\U0001F1E6\u0308\u0378", 2}, +{"\u0600\u0020", 1}, +{"\u0600\u0308\u0020", 2}, +{"\u0600\u000D", 2}, +{"\u0600\u0308\u000D", 2}, +{"\u0600\u000A", 2}, +{"\u0600\u0308\u000A", 2}, +{"\u0600\u0001", 2}, +{"\u0600\u0308\u0001", 2}, +{"\u0600\u034F", 1}, +{"\u0600\u0308\u034F", 1}, +{"\u0600\U0001F1E6", 1}, +{"\u0600\u0308\U0001F1E6", 2}, +{"\u0600\u0600", 1}, +{"\u0600\u0308\u0600", 2}, +{"\u0600\u0A03", 1}, +{"\u0600\u0308\u0A03", 1}, +{"\u0600\u1100", 1}, +{"\u0600\u0308\u1100", 2}, +{"\u0600\u1160", 1}, +{"\u0600\u0308\u1160", 2}, +{"\u0600\u11A8", 1}, +{"\u0600\u0308\u11A8", 2}, +{"\u0600\uAC00", 1}, +{"\u0600\u0308\uAC00", 2}, +{"\u0600\uAC01", 1}, +{"\u0600\u0308\uAC01", 2}, +{"\u0600\u0900", 1}, +{"\u0600\u0308\u0900", 1}, +{"\u0600\u0903", 1}, +{"\u0600\u0308\u0903", 1}, +{"\u0600\u0904", 1}, +{"\u0600\u0308\u0904", 2}, +{"\u0600\u0D4E", 1}, +{"\u0600\u0308\u0D4E", 2}, +{"\u0600\u0915", 1}, +{"\u0600\u0308\u0915", 2}, +{"\u0600\u231A", 1}, +{"\u0600\u0308\u231A", 2}, +{"\u0600\u0300", 1}, +{"\u0600\u0308\u0300", 1}, +{"\u0600\u093C", 1}, +{"\u0600\u0308\u093C", 1}, +{"\u0600\u094D", 1}, +{"\u0600\u0308\u094D", 1}, +{"\u0600\u200D", 1}, +{"\u0600\u0308\u200D", 1}, +{"\u0600\u0378", 1}, +{"\u0600\u0308\u0378", 2}, +{"\u0A03\u0020", 2}, +{"\u0A03\u0308\u0020", 2}, +{"\u0A03\u000D", 2}, +{"\u0A03\u0308\u000D", 2}, +{"\u0A03\u000A", 2}, +{"\u0A03\u0308\u000A", 2}, +{"\u0A03\u0001", 2}, +{"\u0A03\u0308\u0001", 2}, +{"\u0A03\u034F", 1}, +{"\u0A03\u0308\u034F", 1}, +{"\u0A03\U0001F1E6", 2}, +{"\u0A03\u0308\U0001F1E6", 2}, +{"\u0A03\u0600", 2}, +{"\u0A03\u0308\u0600", 2}, +{"\u0A03\u0A03", 1}, +{"\u0A03\u0308\u0A03", 1}, +{"\u0A03\u1100", 2}, +{"\u0A03\u0308\u1100", 2}, +{"\u0A03\u1160", 2}, +{"\u0A03\u0308\u1160", 2}, +{"\u0A03\u11A8", 2}, +{"\u0A03\u0308\u11A8", 2}, +{"\u0A03\uAC00", 2}, +{"\u0A03\u0308\uAC00", 2}, +{"\u0A03\uAC01", 2}, +{"\u0A03\u0308\uAC01", 2}, +{"\u0A03\u0900", 1}, +{"\u0A03\u0308\u0900", 1}, +{"\u0A03\u0903", 1}, +{"\u0A03\u0308\u0903", 1}, +{"\u0A03\u0904", 2}, +{"\u0A03\u0308\u0904", 2}, +{"\u0A03\u0D4E", 2}, +{"\u0A03\u0308\u0D4E", 2}, +{"\u0A03\u0915", 2}, +{"\u0A03\u0308\u0915", 2}, +{"\u0A03\u231A", 2}, +{"\u0A03\u0308\u231A", 2}, +{"\u0A03\u0300", 1}, +{"\u0A03\u0308\u0300", 1}, +{"\u0A03\u093C", 1}, +{"\u0A03\u0308\u093C", 1}, +{"\u0A03\u094D", 1}, +{"\u0A03\u0308\u094D", 1}, +{"\u0A03\u200D", 1}, +{"\u0A03\u0308\u200D", 1}, +{"\u0A03\u0378", 2}, +{"\u0A03\u0308\u0378", 2}, +{"\u1100\u0020", 2}, +{"\u1100\u0308\u0020", 2}, +{"\u1100\u000D", 2}, +{"\u1100\u0308\u000D", 2}, +{"\u1100\u000A", 2}, +{"\u1100\u0308\u000A", 2}, +{"\u1100\u0001", 2}, +{"\u1100\u0308\u0001", 2}, +{"\u1100\u034F", 1}, +{"\u1100\u0308\u034F", 1}, +{"\u1100\U0001F1E6", 2}, +{"\u1100\u0308\U0001F1E6", 2}, +{"\u1100\u0600", 2}, +{"\u1100\u0308\u0600", 2}, +{"\u1100\u0A03", 1}, +{"\u1100\u0308\u0A03", 1}, +{"\u1100\u1100", 1}, +{"\u1100\u0308\u1100", 2}, +{"\u1100\u1160", 1}, +{"\u1100\u0308\u1160", 2}, +{"\u1100\u11A8", 2}, +{"\u1100\u0308\u11A8", 2}, +{"\u1100\uAC00", 1}, +{"\u1100\u0308\uAC00", 2}, +{"\u1100\uAC01", 1}, +{"\u1100\u0308\uAC01", 2}, +{"\u1100\u0900", 1}, +{"\u1100\u0308\u0900", 1}, +{"\u1100\u0903", 1}, +{"\u1100\u0308\u0903", 1}, +{"\u1100\u0904", 2}, +{"\u1100\u0308\u0904", 2}, +{"\u1100\u0D4E", 2}, +{"\u1100\u0308\u0D4E", 2}, +{"\u1100\u0915", 2}, +{"\u1100\u0308\u0915", 2}, +{"\u1100\u231A", 2}, +{"\u1100\u0308\u231A", 2}, +{"\u1100\u0300", 1}, +{"\u1100\u0308\u0300", 1}, +{"\u1100\u093C", 1}, +{"\u1100\u0308\u093C", 1}, +{"\u1100\u094D", 1}, +{"\u1100\u0308\u094D", 1}, +{"\u1100\u200D", 1}, +{"\u1100\u0308\u200D", 1}, +{"\u1100\u0378", 2}, +{"\u1100\u0308\u0378", 2}, +{"\u1160\u0020", 2}, +{"\u1160\u0308\u0020", 2}, +{"\u1160\u000D", 2}, +{"\u1160\u0308\u000D", 2}, +{"\u1160\u000A", 2}, +{"\u1160\u0308\u000A", 2}, +{"\u1160\u0001", 2}, +{"\u1160\u0308\u0001", 2}, +{"\u1160\u034F", 1}, +{"\u1160\u0308\u034F", 1}, +{"\u1160\U0001F1E6", 2}, +{"\u1160\u0308\U0001F1E6", 2}, +{"\u1160\u0600", 2}, +{"\u1160\u0308\u0600", 2}, +{"\u1160\u0A03", 1}, +{"\u1160\u0308\u0A03", 1}, +{"\u1160\u1100", 2}, +{"\u1160\u0308\u1100", 2}, +{"\u1160\u1160", 1}, +{"\u1160\u0308\u1160", 2}, +{"\u1160\u11A8", 1}, +{"\u1160\u0308\u11A8", 2}, +{"\u1160\uAC00", 2}, +{"\u1160\u0308\uAC00", 2}, +{"\u1160\uAC01", 2}, +{"\u1160\u0308\uAC01", 2}, +{"\u1160\u0900", 1}, +{"\u1160\u0308\u0900", 1}, +{"\u1160\u0903", 1}, +{"\u1160\u0308\u0903", 1}, +{"\u1160\u0904", 2}, +{"\u1160\u0308\u0904", 2}, +{"\u1160\u0D4E", 2}, +{"\u1160\u0308\u0D4E", 2}, +{"\u1160\u0915", 2}, +{"\u1160\u0308\u0915", 2}, +{"\u1160\u231A", 2}, +{"\u1160\u0308\u231A", 2}, +{"\u1160\u0300", 1}, +{"\u1160\u0308\u0300", 1}, +{"\u1160\u093C", 1}, +{"\u1160\u0308\u093C", 1}, +{"\u1160\u094D", 1}, +{"\u1160\u0308\u094D", 1}, +{"\u1160\u200D", 1}, +{"\u1160\u0308\u200D", 1}, +{"\u1160\u0378", 2}, +{"\u1160\u0308\u0378", 2}, +{"\u11A8\u0020", 2}, +{"\u11A8\u0308\u0020", 2}, +{"\u11A8\u000D", 2}, +{"\u11A8\u0308\u000D", 2}, +{"\u11A8\u000A", 2}, +{"\u11A8\u0308\u000A", 2}, +{"\u11A8\u0001", 2}, +{"\u11A8\u0308\u0001", 2}, +{"\u11A8\u034F", 1}, +{"\u11A8\u0308\u034F", 1}, +{"\u11A8\U0001F1E6", 2}, +{"\u11A8\u0308\U0001F1E6", 2}, +{"\u11A8\u0600", 2}, +{"\u11A8\u0308\u0600", 2}, +{"\u11A8\u0A03", 1}, +{"\u11A8\u0308\u0A03", 1}, +{"\u11A8\u1100", 2}, +{"\u11A8\u0308\u1100", 2}, +{"\u11A8\u1160", 2}, +{"\u11A8\u0308\u1160", 2}, +{"\u11A8\u11A8", 1}, +{"\u11A8\u0308\u11A8", 2}, +{"\u11A8\uAC00", 2}, +{"\u11A8\u0308\uAC00", 2}, +{"\u11A8\uAC01", 2}, +{"\u11A8\u0308\uAC01", 2}, +{"\u11A8\u0900", 1}, +{"\u11A8\u0308\u0900", 1}, +{"\u11A8\u0903", 1}, +{"\u11A8\u0308\u0903", 1}, +{"\u11A8\u0904", 2}, +{"\u11A8\u0308\u0904", 2}, +{"\u11A8\u0D4E", 2}, +{"\u11A8\u0308\u0D4E", 2}, +{"\u11A8\u0915", 2}, +{"\u11A8\u0308\u0915", 2}, +{"\u11A8\u231A", 2}, +{"\u11A8\u0308\u231A", 2}, +{"\u11A8\u0300", 1}, +{"\u11A8\u0308\u0300", 1}, +{"\u11A8\u093C", 1}, +{"\u11A8\u0308\u093C", 1}, +{"\u11A8\u094D", 1}, +{"\u11A8\u0308\u094D", 1}, +{"\u11A8\u200D", 1}, +{"\u11A8\u0308\u200D", 1}, +{"\u11A8\u0378", 2}, +{"\u11A8\u0308\u0378", 2}, +{"\uAC00\u0020", 2}, +{"\uAC00\u0308\u0020", 2}, +{"\uAC00\u000D", 2}, +{"\uAC00\u0308\u000D", 2}, +{"\uAC00\u000A", 2}, +{"\uAC00\u0308\u000A", 2}, +{"\uAC00\u0001", 2}, +{"\uAC00\u0308\u0001", 2}, +{"\uAC00\u034F", 1}, +{"\uAC00\u0308\u034F", 1}, +{"\uAC00\U0001F1E6", 2}, +{"\uAC00\u0308\U0001F1E6", 2}, +{"\uAC00\u0600", 2}, +{"\uAC00\u0308\u0600", 2}, +{"\uAC00\u0A03", 1}, +{"\uAC00\u0308\u0A03", 1}, +{"\uAC00\u1100", 2}, +{"\uAC00\u0308\u1100", 2}, +{"\uAC00\u1160", 1}, +{"\uAC00\u0308\u1160", 2}, +{"\uAC00\u11A8", 1}, +{"\uAC00\u0308\u11A8", 2}, +{"\uAC00\uAC00", 2}, +{"\uAC00\u0308\uAC00", 2}, +{"\uAC00\uAC01", 2}, +{"\uAC00\u0308\uAC01", 2}, +{"\uAC00\u0900", 1}, +{"\uAC00\u0308\u0900", 1}, +{"\uAC00\u0903", 1}, +{"\uAC00\u0308\u0903", 1}, +{"\uAC00\u0904", 2}, +{"\uAC00\u0308\u0904", 2}, +{"\uAC00\u0D4E", 2}, +{"\uAC00\u0308\u0D4E", 2}, +{"\uAC00\u0915", 2}, +{"\uAC00\u0308\u0915", 2}, +{"\uAC00\u231A", 2}, +{"\uAC00\u0308\u231A", 2}, +{"\uAC00\u0300", 1}, +{"\uAC00\u0308\u0300", 1}, +{"\uAC00\u093C", 1}, +{"\uAC00\u0308\u093C", 1}, +{"\uAC00\u094D", 1}, +{"\uAC00\u0308\u094D", 1}, +{"\uAC00\u200D", 1}, +{"\uAC00\u0308\u200D", 1}, +{"\uAC00\u0378", 2}, +{"\uAC00\u0308\u0378", 2}, +{"\uAC01\u0020", 2}, +{"\uAC01\u0308\u0020", 2}, +{"\uAC01\u000D", 2}, +{"\uAC01\u0308\u000D", 2}, +{"\uAC01\u000A", 2}, +{"\uAC01\u0308\u000A", 2}, +{"\uAC01\u0001", 2}, +{"\uAC01\u0308\u0001", 2}, +{"\uAC01\u034F", 1}, +{"\uAC01\u0308\u034F", 1}, +{"\uAC01\U0001F1E6", 2}, +{"\uAC01\u0308\U0001F1E6", 2}, +{"\uAC01\u0600", 2}, +{"\uAC01\u0308\u0600", 2}, +{"\uAC01\u0A03", 1}, +{"\uAC01\u0308\u0A03", 1}, +{"\uAC01\u1100", 2}, +{"\uAC01\u0308\u1100", 2}, +{"\uAC01\u1160", 2}, +{"\uAC01\u0308\u1160", 2}, +{"\uAC01\u11A8", 1}, +{"\uAC01\u0308\u11A8", 2}, +{"\uAC01\uAC00", 2}, +{"\uAC01\u0308\uAC00", 2}, +{"\uAC01\uAC01", 2}, +{"\uAC01\u0308\uAC01", 2}, +{"\uAC01\u0900", 1}, +{"\uAC01\u0308\u0900", 1}, +{"\uAC01\u0903", 1}, +{"\uAC01\u0308\u0903", 1}, +{"\uAC01\u0904", 2}, +{"\uAC01\u0308\u0904", 2}, +{"\uAC01\u0D4E", 2}, +{"\uAC01\u0308\u0D4E", 2}, +{"\uAC01\u0915", 2}, +{"\uAC01\u0308\u0915", 2}, +{"\uAC01\u231A", 2}, +{"\uAC01\u0308\u231A", 2}, +{"\uAC01\u0300", 1}, +{"\uAC01\u0308\u0300", 1}, +{"\uAC01\u093C", 1}, +{"\uAC01\u0308\u093C", 1}, +{"\uAC01\u094D", 1}, +{"\uAC01\u0308\u094D", 1}, +{"\uAC01\u200D", 1}, +{"\uAC01\u0308\u200D", 1}, +{"\uAC01\u0378", 2}, +{"\uAC01\u0308\u0378", 2}, +{"\u0900\u0020", 2}, +{"\u0900\u0308\u0020", 2}, +{"\u0900\u000D", 2}, +{"\u0900\u0308\u000D", 2}, +{"\u0900\u000A", 2}, +{"\u0900\u0308\u000A", 2}, +{"\u0900\u0001", 2}, +{"\u0900\u0308\u0001", 2}, +{"\u0900\u034F", 1}, +{"\u0900\u0308\u034F", 1}, +{"\u0900\U0001F1E6", 2}, +{"\u0900\u0308\U0001F1E6", 2}, +{"\u0900\u0600", 2}, +{"\u0900\u0308\u0600", 2}, +{"\u0900\u0A03", 1}, +{"\u0900\u0308\u0A03", 1}, +{"\u0900\u1100", 2}, +{"\u0900\u0308\u1100", 2}, +{"\u0900\u1160", 2}, +{"\u0900\u0308\u1160", 2}, +{"\u0900\u11A8", 2}, +{"\u0900\u0308\u11A8", 2}, +{"\u0900\uAC00", 2}, +{"\u0900\u0308\uAC00", 2}, +{"\u0900\uAC01", 2}, +{"\u0900\u0308\uAC01", 2}, +{"\u0900\u0900", 1}, +{"\u0900\u0308\u0900", 1}, +{"\u0900\u0903", 1}, +{"\u0900\u0308\u0903", 1}, +{"\u0900\u0904", 2}, +{"\u0900\u0308\u0904", 2}, +{"\u0900\u0D4E", 2}, +{"\u0900\u0308\u0D4E", 2}, +{"\u0900\u0915", 2}, +{"\u0900\u0308\u0915", 2}, +{"\u0900\u231A", 2}, +{"\u0900\u0308\u231A", 2}, +{"\u0900\u0300", 1}, +{"\u0900\u0308\u0300", 1}, +{"\u0900\u093C", 1}, +{"\u0900\u0308\u093C", 1}, +{"\u0900\u094D", 1}, +{"\u0900\u0308\u094D", 1}, +{"\u0900\u200D", 1}, +{"\u0900\u0308\u200D", 1}, +{"\u0900\u0378", 2}, +{"\u0900\u0308\u0378", 2}, +{"\u0903\u0020", 2}, +{"\u0903\u0308\u0020", 2}, +{"\u0903\u000D", 2}, +{"\u0903\u0308\u000D", 2}, +{"\u0903\u000A", 2}, +{"\u0903\u0308\u000A", 2}, +{"\u0903\u0001", 2}, +{"\u0903\u0308\u0001", 2}, +{"\u0903\u034F", 1}, +{"\u0903\u0308\u034F", 1}, +{"\u0903\U0001F1E6", 2}, +{"\u0903\u0308\U0001F1E6", 2}, +{"\u0903\u0600", 2}, +{"\u0903\u0308\u0600", 2}, +{"\u0903\u0A03", 1}, +{"\u0903\u0308\u0A03", 1}, +{"\u0903\u1100", 2}, +{"\u0903\u0308\u1100", 2}, +{"\u0903\u1160", 2}, +{"\u0903\u0308\u1160", 2}, +{"\u0903\u11A8", 2}, +{"\u0903\u0308\u11A8", 2}, +{"\u0903\uAC00", 2}, +{"\u0903\u0308\uAC00", 2}, +{"\u0903\uAC01", 2}, +{"\u0903\u0308\uAC01", 2}, +{"\u0903\u0900", 1}, +{"\u0903\u0308\u0900", 1}, +{"\u0903\u0903", 1}, +{"\u0903\u0308\u0903", 1}, +{"\u0903\u0904", 2}, +{"\u0903\u0308\u0904", 2}, +{"\u0903\u0D4E", 2}, +{"\u0903\u0308\u0D4E", 2}, +{"\u0903\u0915", 2}, +{"\u0903\u0308\u0915", 2}, +{"\u0903\u231A", 2}, +{"\u0903\u0308\u231A", 2}, +{"\u0903\u0300", 1}, +{"\u0903\u0308\u0300", 1}, +{"\u0903\u093C", 1}, +{"\u0903\u0308\u093C", 1}, +{"\u0903\u094D", 1}, +{"\u0903\u0308\u094D", 1}, +{"\u0903\u200D", 1}, +{"\u0903\u0308\u200D", 1}, +{"\u0903\u0378", 2}, +{"\u0903\u0308\u0378", 2}, +{"\u0904\u0020", 2}, +{"\u0904\u0308\u0020", 2}, +{"\u0904\u000D", 2}, +{"\u0904\u0308\u000D", 2}, +{"\u0904\u000A", 2}, +{"\u0904\u0308\u000A", 2}, +{"\u0904\u0001", 2}, +{"\u0904\u0308\u0001", 2}, +{"\u0904\u034F", 1}, +{"\u0904\u0308\u034F", 1}, +{"\u0904\U0001F1E6", 2}, +{"\u0904\u0308\U0001F1E6", 2}, +{"\u0904\u0600", 2}, +{"\u0904\u0308\u0600", 2}, +{"\u0904\u0A03", 1}, +{"\u0904\u0308\u0A03", 1}, +{"\u0904\u1100", 2}, +{"\u0904\u0308\u1100", 2}, +{"\u0904\u1160", 2}, +{"\u0904\u0308\u1160", 2}, +{"\u0904\u11A8", 2}, +{"\u0904\u0308\u11A8", 2}, +{"\u0904\uAC00", 2}, +{"\u0904\u0308\uAC00", 2}, +{"\u0904\uAC01", 2}, +{"\u0904\u0308\uAC01", 2}, +{"\u0904\u0900", 1}, +{"\u0904\u0308\u0900", 1}, +{"\u0904\u0903", 1}, +{"\u0904\u0308\u0903", 1}, +{"\u0904\u0904", 2}, +{"\u0904\u0308\u0904", 2}, +{"\u0904\u0D4E", 2}, +{"\u0904\u0308\u0D4E", 2}, +{"\u0904\u0915", 2}, +{"\u0904\u0308\u0915", 2}, +{"\u0904\u231A", 2}, +{"\u0904\u0308\u231A", 2}, +{"\u0904\u0300", 1}, +{"\u0904\u0308\u0300", 1}, +{"\u0904\u093C", 1}, +{"\u0904\u0308\u093C", 1}, +{"\u0904\u094D", 1}, +{"\u0904\u0308\u094D", 1}, +{"\u0904\u200D", 1}, +{"\u0904\u0308\u200D", 1}, +{"\u0904\u0378", 2}, +{"\u0904\u0308\u0378", 2}, +{"\u0D4E\u0020", 1}, +{"\u0D4E\u0308\u0020", 2}, +{"\u0D4E\u000D", 2}, +{"\u0D4E\u0308\u000D", 2}, +{"\u0D4E\u000A", 2}, +{"\u0D4E\u0308\u000A", 2}, +{"\u0D4E\u0001", 2}, +{"\u0D4E\u0308\u0001", 2}, +{"\u0D4E\u034F", 1}, +{"\u0D4E\u0308\u034F", 1}, +{"\u0D4E\U0001F1E6", 1}, +{"\u0D4E\u0308\U0001F1E6", 2}, +{"\u0D4E\u0600", 1}, +{"\u0D4E\u0308\u0600", 2}, +{"\u0D4E\u0A03", 1}, +{"\u0D4E\u0308\u0A03", 1}, +{"\u0D4E\u1100", 1}, +{"\u0D4E\u0308\u1100", 2}, +{"\u0D4E\u1160", 1}, +{"\u0D4E\u0308\u1160", 2}, +{"\u0D4E\u11A8", 1}, +{"\u0D4E\u0308\u11A8", 2}, +{"\u0D4E\uAC00", 1}, +{"\u0D4E\u0308\uAC00", 2}, +{"\u0D4E\uAC01", 1}, +{"\u0D4E\u0308\uAC01", 2}, +{"\u0D4E\u0900", 1}, +{"\u0D4E\u0308\u0900", 1}, +{"\u0D4E\u0903", 1}, +{"\u0D4E\u0308\u0903", 1}, +{"\u0D4E\u0904", 1}, +{"\u0D4E\u0308\u0904", 2}, +{"\u0D4E\u0D4E", 1}, +{"\u0D4E\u0308\u0D4E", 2}, +{"\u0D4E\u0915", 1}, +{"\u0D4E\u0308\u0915", 2}, +{"\u0D4E\u231A", 1}, +{"\u0D4E\u0308\u231A", 2}, +{"\u0D4E\u0300", 1}, +{"\u0D4E\u0308\u0300", 1}, +{"\u0D4E\u093C", 1}, +{"\u0D4E\u0308\u093C", 1}, +{"\u0D4E\u094D", 1}, +{"\u0D4E\u0308\u094D", 1}, +{"\u0D4E\u200D", 1}, +{"\u0D4E\u0308\u200D", 1}, +{"\u0D4E\u0378", 1}, +{"\u0D4E\u0308\u0378", 2}, +{"\u0915\u0020", 2}, +{"\u0915\u0308\u0020", 2}, +{"\u0915\u000D", 2}, +{"\u0915\u0308\u000D", 2}, +{"\u0915\u000A", 2}, +{"\u0915\u0308\u000A", 2}, +{"\u0915\u0001", 2}, +{"\u0915\u0308\u0001", 2}, +{"\u0915\u034F", 1}, +{"\u0915\u0308\u034F", 1}, +{"\u0915\U0001F1E6", 2}, +{"\u0915\u0308\U0001F1E6", 2}, +{"\u0915\u0600", 2}, +{"\u0915\u0308\u0600", 2}, +{"\u0915\u0A03", 1}, +{"\u0915\u0308\u0A03", 1}, +{"\u0915\u1100", 2}, +{"\u0915\u0308\u1100", 2}, +{"\u0915\u1160", 2}, +{"\u0915\u0308\u1160", 2}, +{"\u0915\u11A8", 2}, +{"\u0915\u0308\u11A8", 2}, +{"\u0915\uAC00", 2}, +{"\u0915\u0308\uAC00", 2}, +{"\u0915\uAC01", 2}, +{"\u0915\u0308\uAC01", 2}, +{"\u0915\u0900", 1}, +{"\u0915\u0308\u0900", 1}, +{"\u0915\u0903", 1}, +{"\u0915\u0308\u0903", 1}, +{"\u0915\u0904", 2}, +{"\u0915\u0308\u0904", 2}, +{"\u0915\u0D4E", 2}, +{"\u0915\u0308\u0D4E", 2}, +{"\u0915\u0915", 2}, +{"\u0915\u0308\u0915", 2}, +{"\u0915\u231A", 2}, +{"\u0915\u0308\u231A", 2}, +{"\u0915\u0300", 1}, +{"\u0915\u0308\u0300", 1}, +{"\u0915\u093C", 1}, +{"\u0915\u0308\u093C", 1}, +{"\u0915\u094D", 1}, +{"\u0915\u0308\u094D", 1}, +{"\u0915\u200D", 1}, +{"\u0915\u0308\u200D", 1}, +{"\u0915\u0378", 2}, +{"\u0915\u0308\u0378", 2}, +{"\u231A\u0020", 2}, +{"\u231A\u0308\u0020", 2}, +{"\u231A\u000D", 2}, +{"\u231A\u0308\u000D", 2}, +{"\u231A\u000A", 2}, +{"\u231A\u0308\u000A", 2}, +{"\u231A\u0001", 2}, +{"\u231A\u0308\u0001", 2}, +{"\u231A\u034F", 1}, +{"\u231A\u0308\u034F", 1}, +{"\u231A\U0001F1E6", 2}, +{"\u231A\u0308\U0001F1E6", 2}, +{"\u231A\u0600", 2}, +{"\u231A\u0308\u0600", 2}, +{"\u231A\u0A03", 1}, +{"\u231A\u0308\u0A03", 1}, +{"\u231A\u1100", 2}, +{"\u231A\u0308\u1100", 2}, +{"\u231A\u1160", 2}, +{"\u231A\u0308\u1160", 2}, +{"\u231A\u11A8", 2}, +{"\u231A\u0308\u11A8", 2}, +{"\u231A\uAC00", 2}, +{"\u231A\u0308\uAC00", 2}, +{"\u231A\uAC01", 2}, +{"\u231A\u0308\uAC01", 2}, +{"\u231A\u0900", 1}, +{"\u231A\u0308\u0900", 1}, +{"\u231A\u0903", 1}, +{"\u231A\u0308\u0903", 1}, +{"\u231A\u0904", 2}, +{"\u231A\u0308\u0904", 2}, +{"\u231A\u0D4E", 2}, +{"\u231A\u0308\u0D4E", 2}, +{"\u231A\u0915", 2}, +{"\u231A\u0308\u0915", 2}, +{"\u231A\u231A", 2}, +{"\u231A\u0308\u231A", 2}, +{"\u231A\u0300", 1}, +{"\u231A\u0308\u0300", 1}, +{"\u231A\u093C", 1}, +{"\u231A\u0308\u093C", 1}, +{"\u231A\u094D", 1}, +{"\u231A\u0308\u094D", 1}, +{"\u231A\u200D", 1}, +{"\u231A\u0308\u200D", 1}, +{"\u231A\u0378", 2}, +{"\u231A\u0308\u0378", 2}, +{"\u0300\u0020", 2}, +{"\u0300\u0308\u0020", 2}, +{"\u0300\u000D", 2}, +{"\u0300\u0308\u000D", 2}, +{"\u0300\u000A", 2}, +{"\u0300\u0308\u000A", 2}, +{"\u0300\u0001", 2}, +{"\u0300\u0308\u0001", 2}, +{"\u0300\u034F", 1}, +{"\u0300\u0308\u034F", 1}, +{"\u0300\U0001F1E6", 2}, +{"\u0300\u0308\U0001F1E6", 2}, +{"\u0300\u0600", 2}, +{"\u0300\u0308\u0600", 2}, +{"\u0300\u0A03", 1}, +{"\u0300\u0308\u0A03", 1}, +{"\u0300\u1100", 2}, +{"\u0300\u0308\u1100", 2}, +{"\u0300\u1160", 2}, +{"\u0300\u0308\u1160", 2}, +{"\u0300\u11A8", 2}, +{"\u0300\u0308\u11A8", 2}, +{"\u0300\uAC00", 2}, +{"\u0300\u0308\uAC00", 2}, +{"\u0300\uAC01", 2}, +{"\u0300\u0308\uAC01", 2}, +{"\u0300\u0900", 1}, +{"\u0300\u0308\u0900", 1}, +{"\u0300\u0903", 1}, +{"\u0300\u0308\u0903", 1}, +{"\u0300\u0904", 2}, +{"\u0300\u0308\u0904", 2}, +{"\u0300\u0D4E", 2}, +{"\u0300\u0308\u0D4E", 2}, +{"\u0300\u0915", 2}, +{"\u0300\u0308\u0915", 2}, +{"\u0300\u231A", 2}, +{"\u0300\u0308\u231A", 2}, +{"\u0300\u0300", 1}, +{"\u0300\u0308\u0300", 1}, +{"\u0300\u093C", 1}, +{"\u0300\u0308\u093C", 1}, +{"\u0300\u094D", 1}, +{"\u0300\u0308\u094D", 1}, +{"\u0300\u200D", 1}, +{"\u0300\u0308\u200D", 1}, +{"\u0300\u0378", 2}, +{"\u0300\u0308\u0378", 2}, +{"\u093C\u0020", 2}, +{"\u093C\u0308\u0020", 2}, +{"\u093C\u000D", 2}, +{"\u093C\u0308\u000D", 2}, +{"\u093C\u000A", 2}, +{"\u093C\u0308\u000A", 2}, +{"\u093C\u0001", 2}, +{"\u093C\u0308\u0001", 2}, +{"\u093C\u034F", 1}, +{"\u093C\u0308\u034F", 1}, +{"\u093C\U0001F1E6", 2}, +{"\u093C\u0308\U0001F1E6", 2}, +{"\u093C\u0600", 2}, +{"\u093C\u0308\u0600", 2}, +{"\u093C\u0A03", 1}, +{"\u093C\u0308\u0A03", 1}, +{"\u093C\u1100", 2}, +{"\u093C\u0308\u1100", 2}, +{"\u093C\u1160", 2}, +{"\u093C\u0308\u1160", 2}, +{"\u093C\u11A8", 2}, +{"\u093C\u0308\u11A8", 2}, +{"\u093C\uAC00", 2}, +{"\u093C\u0308\uAC00", 2}, +{"\u093C\uAC01", 2}, +{"\u093C\u0308\uAC01", 2}, +{"\u093C\u0900", 1}, +{"\u093C\u0308\u0900", 1}, +{"\u093C\u0903", 1}, +{"\u093C\u0308\u0903", 1}, +{"\u093C\u0904", 2}, +{"\u093C\u0308\u0904", 2}, +{"\u093C\u0D4E", 2}, +{"\u093C\u0308\u0D4E", 2}, +{"\u093C\u0915", 2}, +{"\u093C\u0308\u0915", 2}, +{"\u093C\u231A", 2}, +{"\u093C\u0308\u231A", 2}, +{"\u093C\u0300", 1}, +{"\u093C\u0308\u0300", 1}, +{"\u093C\u093C", 1}, +{"\u093C\u0308\u093C", 1}, +{"\u093C\u094D", 1}, +{"\u093C\u0308\u094D", 1}, +{"\u093C\u200D", 1}, +{"\u093C\u0308\u200D", 1}, +{"\u093C\u0378", 2}, +{"\u093C\u0308\u0378", 2}, +{"\u094D\u0020", 2}, +{"\u094D\u0308\u0020", 2}, +{"\u094D\u000D", 2}, +{"\u094D\u0308\u000D", 2}, +{"\u094D\u000A", 2}, +{"\u094D\u0308\u000A", 2}, +{"\u094D\u0001", 2}, +{"\u094D\u0308\u0001", 2}, +{"\u094D\u034F", 1}, +{"\u094D\u0308\u034F", 1}, +{"\u094D\U0001F1E6", 2}, +{"\u094D\u0308\U0001F1E6", 2}, +{"\u094D\u0600", 2}, +{"\u094D\u0308\u0600", 2}, +{"\u094D\u0A03", 1}, +{"\u094D\u0308\u0A03", 1}, +{"\u094D\u1100", 2}, +{"\u094D\u0308\u1100", 2}, +{"\u094D\u1160", 2}, +{"\u094D\u0308\u1160", 2}, +{"\u094D\u11A8", 2}, +{"\u094D\u0308\u11A8", 2}, +{"\u094D\uAC00", 2}, +{"\u094D\u0308\uAC00", 2}, +{"\u094D\uAC01", 2}, +{"\u094D\u0308\uAC01", 2}, +{"\u094D\u0900", 1}, +{"\u094D\u0308\u0900", 1}, +{"\u094D\u0903", 1}, +{"\u094D\u0308\u0903", 1}, +{"\u094D\u0904", 2}, +{"\u094D\u0308\u0904", 2}, +{"\u094D\u0D4E", 2}, +{"\u094D\u0308\u0D4E", 2}, +{"\u094D\u0915", 2}, +{"\u094D\u0308\u0915", 2}, +{"\u094D\u231A", 2}, +{"\u094D\u0308\u231A", 2}, +{"\u094D\u0300", 1}, +{"\u094D\u0308\u0300", 1}, +{"\u094D\u093C", 1}, +{"\u094D\u0308\u093C", 1}, +{"\u094D\u094D", 1}, +{"\u094D\u0308\u094D", 1}, +{"\u094D\u200D", 1}, +{"\u094D\u0308\u200D", 1}, +{"\u094D\u0378", 2}, +{"\u094D\u0308\u0378", 2}, +{"\u200D\u0020", 2}, +{"\u200D\u0308\u0020", 2}, +{"\u200D\u000D", 2}, +{"\u200D\u0308\u000D", 2}, +{"\u200D\u000A", 2}, +{"\u200D\u0308\u000A", 2}, +{"\u200D\u0001", 2}, +{"\u200D\u0308\u0001", 2}, +{"\u200D\u034F", 1}, +{"\u200D\u0308\u034F", 1}, +{"\u200D\U0001F1E6", 2}, +{"\u200D\u0308\U0001F1E6", 2}, +{"\u200D\u0600", 2}, +{"\u200D\u0308\u0600", 2}, +{"\u200D\u0A03", 1}, +{"\u200D\u0308\u0A03", 1}, +{"\u200D\u1100", 2}, +{"\u200D\u0308\u1100", 2}, +{"\u200D\u1160", 2}, +{"\u200D\u0308\u1160", 2}, +{"\u200D\u11A8", 2}, +{"\u200D\u0308\u11A8", 2}, +{"\u200D\uAC00", 2}, +{"\u200D\u0308\uAC00", 2}, +{"\u200D\uAC01", 2}, +{"\u200D\u0308\uAC01", 2}, +{"\u200D\u0900", 1}, +{"\u200D\u0308\u0900", 1}, +{"\u200D\u0903", 1}, +{"\u200D\u0308\u0903", 1}, +{"\u200D\u0904", 2}, +{"\u200D\u0308\u0904", 2}, +{"\u200D\u0D4E", 2}, +{"\u200D\u0308\u0D4E", 2}, +{"\u200D\u0915", 2}, +{"\u200D\u0308\u0915", 2}, +{"\u200D\u231A", 2}, +{"\u200D\u0308\u231A", 2}, +{"\u200D\u0300", 1}, +{"\u200D\u0308\u0300", 1}, +{"\u200D\u093C", 1}, +{"\u200D\u0308\u093C", 1}, +{"\u200D\u094D", 1}, +{"\u200D\u0308\u094D", 1}, +{"\u200D\u200D", 1}, +{"\u200D\u0308\u200D", 1}, +{"\u200D\u0378", 2}, +{"\u200D\u0308\u0378", 2}, +{"\u0378\u0020", 2}, +{"\u0378\u0308\u0020", 2}, +{"\u0378\u000D", 2}, +{"\u0378\u0308\u000D", 2}, +{"\u0378\u000A", 2}, +{"\u0378\u0308\u000A", 2}, +{"\u0378\u0001", 2}, +{"\u0378\u0308\u0001", 2}, +{"\u0378\u034F", 1}, +{"\u0378\u0308\u034F", 1}, +{"\u0378\U0001F1E6", 2}, +{"\u0378\u0308\U0001F1E6", 2}, +{"\u0378\u0600", 2}, +{"\u0378\u0308\u0600", 2}, +{"\u0378\u0A03", 1}, +{"\u0378\u0308\u0A03", 1}, +{"\u0378\u1100", 2}, +{"\u0378\u0308\u1100", 2}, +{"\u0378\u1160", 2}, +{"\u0378\u0308\u1160", 2}, +{"\u0378\u11A8", 2}, +{"\u0378\u0308\u11A8", 2}, +{"\u0378\uAC00", 2}, +{"\u0378\u0308\uAC00", 2}, +{"\u0378\uAC01", 2}, +{"\u0378\u0308\uAC01", 2}, +{"\u0378\u0900", 1}, +{"\u0378\u0308\u0900", 1}, +{"\u0378\u0903", 1}, +{"\u0378\u0308\u0903", 1}, +{"\u0378\u0904", 2}, +{"\u0378\u0308\u0904", 2}, +{"\u0378\u0D4E", 2}, +{"\u0378\u0308\u0D4E", 2}, +{"\u0378\u0915", 2}, +{"\u0378\u0308\u0915", 2}, +{"\u0378\u231A", 2}, +{"\u0378\u0308\u231A", 2}, +{"\u0378\u0300", 1}, +{"\u0378\u0308\u0300", 1}, +{"\u0378\u093C", 1}, +{"\u0378\u0308\u093C", 1}, +{"\u0378\u094D", 1}, +{"\u0378\u0308\u094D", 1}, +{"\u0378\u200D", 1}, +{"\u0378\u0308\u200D", 1}, +{"\u0378\u0378", 2}, +{"\u0378\u0308\u0378", 2}, +{"\u000D\u000A\u0061\u000A\u0308", 4}, +{"\u0061\u0308", 1}, +{"\u0020\u200D\u0646", 2}, +{"\u0646\u200D\u0020", 2}, +{"\u1100\u1100", 1}, +{"\uAC00\u11A8\u1100", 2}, +{"\uAC01\u11A8\u1100", 2}, +{"\U0001F1E6\U0001F1E7\U0001F1E8\u0062", 3}, +{"\u0061\U0001F1E6\U0001F1E7\U0001F1E8\u0062", 4}, +{"\u0061\U0001F1E6\U0001F1E7\u200D\U0001F1E8\u0062", 4}, +{"\u0061\U0001F1E6\u200D\U0001F1E7\U0001F1E8\u0062", 4}, +{"\u0061\U0001F1E6\U0001F1E7\U0001F1E8\U0001F1E9\u0062", 4}, +{"\u0061\u200D", 1}, +{"\u0061\u0308\u0062", 2}, +{"\u0061\u0903\u0062", 2}, +{"\u0061\u0600\u0062", 2}, +{"\U0001F476\U0001F3FF\U0001F476", 2}, +{"\u0061\U0001F3FF\U0001F476", 2}, +{"\u0061\U0001F3FF\U0001F476\u200D\U0001F6D1", 2}, +{"\U0001F476\U0001F3FF\u0308\u200D\U0001F476\U0001F3FF", 1}, +{"\U0001F6D1\u200D\U0001F6D1", 1}, +{"\u0061\u200D\U0001F6D1", 2}, +{"\u2701\u200D\u2701", 1}, +{"\u0061\u200D\u2701", 2}, +{"\u0915\u0924", 2}, +{"\u0915\u094D\u0924", 1}, +{"\u0915\u094D\u094D\u0924", 1}, +{"\u0915\u094D\u200D\u0924", 1}, +{"\u0915\u093C\u200D\u094D\u0924", 1}, +{"\u0915\u093C\u094D\u200D\u0924", 1}, +{"\u0915\u094D\u0924\u094D\u092F", 1}, +{"\u0915\u094D\u0061", 2}, +{"\u0061\u094D\u0924", 2}, +{"\u003F\u094D\u0924", 2}, +{"\u0915\u094D\u094D\u0924", 1}, +} + +// (Note that the test cases below only include the multi-codepoint cases +// listed in the file, as these were the only relevant ones for counting +// grapheme cluster boundaries.) +// +// https://unicode.org/Public/emoji/15.1/emoji-test.txt +// +// emoji-test.txt +// Date: 2023-06-05, 21:39:54 GMT +// © 2023 Unicode®, Inc. +// Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +// For terms of use, see https://www.unicode.org/terms_of_use.html +@(rodata) +official_emoji_test_cases := []Test_Case { +{"\u263A\uFE0F", 1}, +{"\U0001F636\u200D\U0001F32B\uFE0F", 1}, +{"\U0001F636\u200D\U0001F32B", 1}, +{"\U0001F62E\u200D\U0001F4A8", 1}, +{"\U0001F642\u200D\u2194\uFE0F", 1}, +{"\U0001F642\u200D\u2194", 1}, +{"\U0001F642\u200D\u2195\uFE0F", 1}, +{"\U0001F642\u200D\u2195", 1}, +{"\U0001F635\u200D\U0001F4AB", 1}, +{"\u2639\uFE0F", 1}, +{"\u2620\uFE0F", 1}, +{"\u2763\uFE0F", 1}, +{"\u2764\uFE0F\u200D\U0001F525", 1}, +{"\u2764\u200D\U0001F525", 1}, +{"\u2764\uFE0F\u200D\U0001FA79", 1}, +{"\u2764\u200D\U0001FA79", 1}, +{"\u2764\uFE0F", 1}, +{"\U0001F573\uFE0F", 1}, +{"\U0001F441\uFE0F\u200D\U0001F5E8\uFE0F", 1}, +{"\U0001F441\u200D\U0001F5E8\uFE0F", 1}, +{"\U0001F441\uFE0F\u200D\U0001F5E8", 1}, +{"\U0001F441\u200D\U0001F5E8", 1}, +{"\U0001F5E8\uFE0F", 1}, +{"\U0001F5EF\uFE0F", 1}, +{"\U0001F44B\U0001F3FB", 1}, +{"\U0001F44B\U0001F3FC", 1}, +{"\U0001F44B\U0001F3FD", 1}, +{"\U0001F44B\U0001F3FE", 1}, +{"\U0001F44B\U0001F3FF", 1}, +{"\U0001F91A\U0001F3FB", 1}, +{"\U0001F91A\U0001F3FC", 1}, +{"\U0001F91A\U0001F3FD", 1}, +{"\U0001F91A\U0001F3FE", 1}, +{"\U0001F91A\U0001F3FF", 1}, +{"\U0001F590\uFE0F", 1}, +{"\U0001F590\U0001F3FB", 1}, +{"\U0001F590\U0001F3FC", 1}, +{"\U0001F590\U0001F3FD", 1}, +{"\U0001F590\U0001F3FE", 1}, +{"\U0001F590\U0001F3FF", 1}, +{"\u270B\U0001F3FB", 1}, +{"\u270B\U0001F3FC", 1}, +{"\u270B\U0001F3FD", 1}, +{"\u270B\U0001F3FE", 1}, +{"\u270B\U0001F3FF", 1}, +{"\U0001F596\U0001F3FB", 1}, +{"\U0001F596\U0001F3FC", 1}, +{"\U0001F596\U0001F3FD", 1}, +{"\U0001F596\U0001F3FE", 1}, +{"\U0001F596\U0001F3FF", 1}, +{"\U0001FAF1\U0001F3FB", 1}, +{"\U0001FAF1\U0001F3FC", 1}, +{"\U0001FAF1\U0001F3FD", 1}, +{"\U0001FAF1\U0001F3FE", 1}, +{"\U0001FAF1\U0001F3FF", 1}, +{"\U0001FAF2\U0001F3FB", 1}, +{"\U0001FAF2\U0001F3FC", 1}, +{"\U0001FAF2\U0001F3FD", 1}, +{"\U0001FAF2\U0001F3FE", 1}, +{"\U0001FAF2\U0001F3FF", 1}, +{"\U0001FAF3\U0001F3FB", 1}, +{"\U0001FAF3\U0001F3FC", 1}, +{"\U0001FAF3\U0001F3FD", 1}, +{"\U0001FAF3\U0001F3FE", 1}, +{"\U0001FAF3\U0001F3FF", 1}, +{"\U0001FAF4\U0001F3FB", 1}, +{"\U0001FAF4\U0001F3FC", 1}, +{"\U0001FAF4\U0001F3FD", 1}, +{"\U0001FAF4\U0001F3FE", 1}, +{"\U0001FAF4\U0001F3FF", 1}, +{"\U0001FAF7\U0001F3FB", 1}, +{"\U0001FAF7\U0001F3FC", 1}, +{"\U0001FAF7\U0001F3FD", 1}, +{"\U0001FAF7\U0001F3FE", 1}, +{"\U0001FAF7\U0001F3FF", 1}, +{"\U0001FAF8\U0001F3FB", 1}, +{"\U0001FAF8\U0001F3FC", 1}, +{"\U0001FAF8\U0001F3FD", 1}, +{"\U0001FAF8\U0001F3FE", 1}, +{"\U0001FAF8\U0001F3FF", 1}, +{"\U0001F44C\U0001F3FB", 1}, +{"\U0001F44C\U0001F3FC", 1}, +{"\U0001F44C\U0001F3FD", 1}, +{"\U0001F44C\U0001F3FE", 1}, +{"\U0001F44C\U0001F3FF", 1}, +{"\U0001F90C\U0001F3FB", 1}, +{"\U0001F90C\U0001F3FC", 1}, +{"\U0001F90C\U0001F3FD", 1}, +{"\U0001F90C\U0001F3FE", 1}, +{"\U0001F90C\U0001F3FF", 1}, +{"\U0001F90F\U0001F3FB", 1}, +{"\U0001F90F\U0001F3FC", 1}, +{"\U0001F90F\U0001F3FD", 1}, +{"\U0001F90F\U0001F3FE", 1}, +{"\U0001F90F\U0001F3FF", 1}, +{"\u270C\uFE0F", 1}, +{"\u270C\U0001F3FB", 1}, +{"\u270C\U0001F3FC", 1}, +{"\u270C\U0001F3FD", 1}, +{"\u270C\U0001F3FE", 1}, +{"\u270C\U0001F3FF", 1}, +{"\U0001F91E\U0001F3FB", 1}, +{"\U0001F91E\U0001F3FC", 1}, +{"\U0001F91E\U0001F3FD", 1}, +{"\U0001F91E\U0001F3FE", 1}, +{"\U0001F91E\U0001F3FF", 1}, +{"\U0001FAF0\U0001F3FB", 1}, +{"\U0001FAF0\U0001F3FC", 1}, +{"\U0001FAF0\U0001F3FD", 1}, +{"\U0001FAF0\U0001F3FE", 1}, +{"\U0001FAF0\U0001F3FF", 1}, +{"\U0001F91F\U0001F3FB", 1}, +{"\U0001F91F\U0001F3FC", 1}, +{"\U0001F91F\U0001F3FD", 1}, +{"\U0001F91F\U0001F3FE", 1}, +{"\U0001F91F\U0001F3FF", 1}, +{"\U0001F918\U0001F3FB", 1}, +{"\U0001F918\U0001F3FC", 1}, +{"\U0001F918\U0001F3FD", 1}, +{"\U0001F918\U0001F3FE", 1}, +{"\U0001F918\U0001F3FF", 1}, +{"\U0001F919\U0001F3FB", 1}, +{"\U0001F919\U0001F3FC", 1}, +{"\U0001F919\U0001F3FD", 1}, +{"\U0001F919\U0001F3FE", 1}, +{"\U0001F919\U0001F3FF", 1}, +{"\U0001F448\U0001F3FB", 1}, +{"\U0001F448\U0001F3FC", 1}, +{"\U0001F448\U0001F3FD", 1}, +{"\U0001F448\U0001F3FE", 1}, +{"\U0001F448\U0001F3FF", 1}, +{"\U0001F449\U0001F3FB", 1}, +{"\U0001F449\U0001F3FC", 1}, +{"\U0001F449\U0001F3FD", 1}, +{"\U0001F449\U0001F3FE", 1}, +{"\U0001F449\U0001F3FF", 1}, +{"\U0001F446\U0001F3FB", 1}, +{"\U0001F446\U0001F3FC", 1}, +{"\U0001F446\U0001F3FD", 1}, +{"\U0001F446\U0001F3FE", 1}, +{"\U0001F446\U0001F3FF", 1}, +{"\U0001F595\U0001F3FB", 1}, +{"\U0001F595\U0001F3FC", 1}, +{"\U0001F595\U0001F3FD", 1}, +{"\U0001F595\U0001F3FE", 1}, +{"\U0001F595\U0001F3FF", 1}, +{"\U0001F447\U0001F3FB", 1}, +{"\U0001F447\U0001F3FC", 1}, +{"\U0001F447\U0001F3FD", 1}, +{"\U0001F447\U0001F3FE", 1}, +{"\U0001F447\U0001F3FF", 1}, +{"\u261D\uFE0F", 1}, +{"\u261D\U0001F3FB", 1}, +{"\u261D\U0001F3FC", 1}, +{"\u261D\U0001F3FD", 1}, +{"\u261D\U0001F3FE", 1}, +{"\u261D\U0001F3FF", 1}, +{"\U0001FAF5\U0001F3FB", 1}, +{"\U0001FAF5\U0001F3FC", 1}, +{"\U0001FAF5\U0001F3FD", 1}, +{"\U0001FAF5\U0001F3FE", 1}, +{"\U0001FAF5\U0001F3FF", 1}, +{"\U0001F44D\U0001F3FB", 1}, +{"\U0001F44D\U0001F3FC", 1}, +{"\U0001F44D\U0001F3FD", 1}, +{"\U0001F44D\U0001F3FE", 1}, +{"\U0001F44D\U0001F3FF", 1}, +{"\U0001F44E\U0001F3FB", 1}, +{"\U0001F44E\U0001F3FC", 1}, +{"\U0001F44E\U0001F3FD", 1}, +{"\U0001F44E\U0001F3FE", 1}, +{"\U0001F44E\U0001F3FF", 1}, +{"\u270A\U0001F3FB", 1}, +{"\u270A\U0001F3FC", 1}, +{"\u270A\U0001F3FD", 1}, +{"\u270A\U0001F3FE", 1}, +{"\u270A\U0001F3FF", 1}, +{"\U0001F44A\U0001F3FB", 1}, +{"\U0001F44A\U0001F3FC", 1}, +{"\U0001F44A\U0001F3FD", 1}, +{"\U0001F44A\U0001F3FE", 1}, +{"\U0001F44A\U0001F3FF", 1}, +{"\U0001F91B\U0001F3FB", 1}, +{"\U0001F91B\U0001F3FC", 1}, +{"\U0001F91B\U0001F3FD", 1}, +{"\U0001F91B\U0001F3FE", 1}, +{"\U0001F91B\U0001F3FF", 1}, +{"\U0001F91C\U0001F3FB", 1}, +{"\U0001F91C\U0001F3FC", 1}, +{"\U0001F91C\U0001F3FD", 1}, +{"\U0001F91C\U0001F3FE", 1}, +{"\U0001F91C\U0001F3FF", 1}, +{"\U0001F44F\U0001F3FB", 1}, +{"\U0001F44F\U0001F3FC", 1}, +{"\U0001F44F\U0001F3FD", 1}, +{"\U0001F44F\U0001F3FE", 1}, +{"\U0001F44F\U0001F3FF", 1}, +{"\U0001F64C\U0001F3FB", 1}, +{"\U0001F64C\U0001F3FC", 1}, +{"\U0001F64C\U0001F3FD", 1}, +{"\U0001F64C\U0001F3FE", 1}, +{"\U0001F64C\U0001F3FF", 1}, +{"\U0001FAF6\U0001F3FB", 1}, +{"\U0001FAF6\U0001F3FC", 1}, +{"\U0001FAF6\U0001F3FD", 1}, +{"\U0001FAF6\U0001F3FE", 1}, +{"\U0001FAF6\U0001F3FF", 1}, +{"\U0001F450\U0001F3FB", 1}, +{"\U0001F450\U0001F3FC", 1}, +{"\U0001F450\U0001F3FD", 1}, +{"\U0001F450\U0001F3FE", 1}, +{"\U0001F450\U0001F3FF", 1}, +{"\U0001F932\U0001F3FB", 1}, +{"\U0001F932\U0001F3FC", 1}, +{"\U0001F932\U0001F3FD", 1}, +{"\U0001F932\U0001F3FE", 1}, +{"\U0001F932\U0001F3FF", 1}, +{"\U0001F91D\U0001F3FB", 1}, +{"\U0001F91D\U0001F3FC", 1}, +{"\U0001F91D\U0001F3FD", 1}, +{"\U0001F91D\U0001F3FE", 1}, +{"\U0001F91D\U0001F3FF", 1}, +{"\U0001FAF1\U0001F3FB\u200D\U0001FAF2\U0001F3FC", 1}, +{"\U0001FAF1\U0001F3FB\u200D\U0001FAF2\U0001F3FD", 1}, +{"\U0001FAF1\U0001F3FB\u200D\U0001FAF2\U0001F3FE", 1}, +{"\U0001FAF1\U0001F3FB\u200D\U0001FAF2\U0001F3FF", 1}, +{"\U0001FAF1\U0001F3FC\u200D\U0001FAF2\U0001F3FB", 1}, +{"\U0001FAF1\U0001F3FC\u200D\U0001FAF2\U0001F3FD", 1}, +{"\U0001FAF1\U0001F3FC\u200D\U0001FAF2\U0001F3FE", 1}, +{"\U0001FAF1\U0001F3FC\u200D\U0001FAF2\U0001F3FF", 1}, +{"\U0001FAF1\U0001F3FD\u200D\U0001FAF2\U0001F3FB", 1}, +{"\U0001FAF1\U0001F3FD\u200D\U0001FAF2\U0001F3FC", 1}, +{"\U0001FAF1\U0001F3FD\u200D\U0001FAF2\U0001F3FE", 1}, +{"\U0001FAF1\U0001F3FD\u200D\U0001FAF2\U0001F3FF", 1}, +{"\U0001FAF1\U0001F3FE\u200D\U0001FAF2\U0001F3FB", 1}, +{"\U0001FAF1\U0001F3FE\u200D\U0001FAF2\U0001F3FC", 1}, +{"\U0001FAF1\U0001F3FE\u200D\U0001FAF2\U0001F3FD", 1}, +{"\U0001FAF1\U0001F3FE\u200D\U0001FAF2\U0001F3FF", 1}, +{"\U0001FAF1\U0001F3FF\u200D\U0001FAF2\U0001F3FB", 1}, +{"\U0001FAF1\U0001F3FF\u200D\U0001FAF2\U0001F3FC", 1}, +{"\U0001FAF1\U0001F3FF\u200D\U0001FAF2\U0001F3FD", 1}, +{"\U0001FAF1\U0001F3FF\u200D\U0001FAF2\U0001F3FE", 1}, +{"\U0001F64F\U0001F3FB", 1}, +{"\U0001F64F\U0001F3FC", 1}, +{"\U0001F64F\U0001F3FD", 1}, +{"\U0001F64F\U0001F3FE", 1}, +{"\U0001F64F\U0001F3FF", 1}, +{"\u270D\uFE0F", 1}, +{"\u270D\U0001F3FB", 1}, +{"\u270D\U0001F3FC", 1}, +{"\u270D\U0001F3FD", 1}, +{"\u270D\U0001F3FE", 1}, +{"\u270D\U0001F3FF", 1}, +{"\U0001F485\U0001F3FB", 1}, +{"\U0001F485\U0001F3FC", 1}, +{"\U0001F485\U0001F3FD", 1}, +{"\U0001F485\U0001F3FE", 1}, +{"\U0001F485\U0001F3FF", 1}, +{"\U0001F933\U0001F3FB", 1}, +{"\U0001F933\U0001F3FC", 1}, +{"\U0001F933\U0001F3FD", 1}, +{"\U0001F933\U0001F3FE", 1}, +{"\U0001F933\U0001F3FF", 1}, +{"\U0001F4AA\U0001F3FB", 1}, +{"\U0001F4AA\U0001F3FC", 1}, +{"\U0001F4AA\U0001F3FD", 1}, +{"\U0001F4AA\U0001F3FE", 1}, +{"\U0001F4AA\U0001F3FF", 1}, +{"\U0001F9B5\U0001F3FB", 1}, +{"\U0001F9B5\U0001F3FC", 1}, +{"\U0001F9B5\U0001F3FD", 1}, +{"\U0001F9B5\U0001F3FE", 1}, +{"\U0001F9B5\U0001F3FF", 1}, +{"\U0001F9B6\U0001F3FB", 1}, +{"\U0001F9B6\U0001F3FC", 1}, +{"\U0001F9B6\U0001F3FD", 1}, +{"\U0001F9B6\U0001F3FE", 1}, +{"\U0001F9B6\U0001F3FF", 1}, +{"\U0001F442\U0001F3FB", 1}, +{"\U0001F442\U0001F3FC", 1}, +{"\U0001F442\U0001F3FD", 1}, +{"\U0001F442\U0001F3FE", 1}, +{"\U0001F442\U0001F3FF", 1}, +{"\U0001F9BB\U0001F3FB", 1}, +{"\U0001F9BB\U0001F3FC", 1}, +{"\U0001F9BB\U0001F3FD", 1}, +{"\U0001F9BB\U0001F3FE", 1}, +{"\U0001F9BB\U0001F3FF", 1}, +{"\U0001F443\U0001F3FB", 1}, +{"\U0001F443\U0001F3FC", 1}, +{"\U0001F443\U0001F3FD", 1}, +{"\U0001F443\U0001F3FE", 1}, +{"\U0001F443\U0001F3FF", 1}, +{"\U0001F441\uFE0F", 1}, +{"\U0001F476\U0001F3FB", 1}, +{"\U0001F476\U0001F3FC", 1}, +{"\U0001F476\U0001F3FD", 1}, +{"\U0001F476\U0001F3FE", 1}, +{"\U0001F476\U0001F3FF", 1}, +{"\U0001F9D2\U0001F3FB", 1}, +{"\U0001F9D2\U0001F3FC", 1}, +{"\U0001F9D2\U0001F3FD", 1}, +{"\U0001F9D2\U0001F3FE", 1}, +{"\U0001F9D2\U0001F3FF", 1}, +{"\U0001F466\U0001F3FB", 1}, +{"\U0001F466\U0001F3FC", 1}, +{"\U0001F466\U0001F3FD", 1}, +{"\U0001F466\U0001F3FE", 1}, +{"\U0001F466\U0001F3FF", 1}, +{"\U0001F467\U0001F3FB", 1}, +{"\U0001F467\U0001F3FC", 1}, +{"\U0001F467\U0001F3FD", 1}, +{"\U0001F467\U0001F3FE", 1}, +{"\U0001F467\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FF", 1}, +{"\U0001F471\U0001F3FB", 1}, +{"\U0001F471\U0001F3FC", 1}, +{"\U0001F471\U0001F3FD", 1}, +{"\U0001F471\U0001F3FE", 1}, +{"\U0001F471\U0001F3FF", 1}, +{"\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FF", 1}, +{"\U0001F9D4\U0001F3FB", 1}, +{"\U0001F9D4\U0001F3FC", 1}, +{"\U0001F9D4\U0001F3FD", 1}, +{"\U0001F9D4\U0001F3FE", 1}, +{"\U0001F9D4\U0001F3FF", 1}, +{"\U0001F9D4\u200D\u2642\uFE0F", 1}, +{"\U0001F9D4\u200D\u2642", 1}, +{"\U0001F9D4\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9D4\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9D4\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9D4\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9D4\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9D4\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9D4\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9D4\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9D4\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9D4\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9D4\u200D\u2640\uFE0F", 1}, +{"\U0001F9D4\u200D\u2640", 1}, +{"\U0001F9D4\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9D4\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9D4\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9D4\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9D4\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9D4\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9D4\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9D4\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9D4\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9D4\U0001F3FF\u200D\u2640", 1}, +{"\U0001F468\u200D\U0001F9B0", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9B0", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9B0", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9B0", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9B0", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9B0", 1}, +{"\U0001F468\u200D\U0001F9B1", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9B1", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9B1", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9B1", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9B1", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9B1", 1}, +{"\U0001F468\u200D\U0001F9B3", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9B3", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9B3", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9B3", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9B3", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9B3", 1}, +{"\U0001F468\u200D\U0001F9B2", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9B2", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9B2", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9B2", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9B2", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9B2", 1}, +{"\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF", 1}, +{"\U0001F469\u200D\U0001F9B0", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9B0", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9B0", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9B0", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9B0", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9B0", 1}, +{"\U0001F9D1\u200D\U0001F9B0", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9B0", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9B0", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9B0", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9B0", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9B0", 1}, +{"\U0001F469\u200D\U0001F9B1", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9B1", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9B1", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9B1", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9B1", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9B1", 1}, +{"\U0001F9D1\u200D\U0001F9B1", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9B1", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9B1", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9B1", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9B1", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9B1", 1}, +{"\U0001F469\u200D\U0001F9B3", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9B3", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9B3", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9B3", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9B3", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9B3", 1}, +{"\U0001F9D1\u200D\U0001F9B3", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9B3", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9B3", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9B3", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9B3", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9B3", 1}, +{"\U0001F469\u200D\U0001F9B2", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9B2", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9B2", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9B2", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9B2", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9B2", 1}, +{"\U0001F9D1\u200D\U0001F9B2", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9B2", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9B2", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9B2", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9B2", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9B2", 1}, +{"\U0001F471\u200D\u2640\uFE0F", 1}, +{"\U0001F471\u200D\u2640", 1}, +{"\U0001F471\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F471\U0001F3FB\u200D\u2640", 1}, +{"\U0001F471\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F471\U0001F3FC\u200D\u2640", 1}, +{"\U0001F471\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F471\U0001F3FD\u200D\u2640", 1}, +{"\U0001F471\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F471\U0001F3FE\u200D\u2640", 1}, +{"\U0001F471\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F471\U0001F3FF\u200D\u2640", 1}, +{"\U0001F471\u200D\u2642\uFE0F", 1}, +{"\U0001F471\u200D\u2642", 1}, +{"\U0001F471\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F471\U0001F3FB\u200D\u2642", 1}, +{"\U0001F471\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F471\U0001F3FC\u200D\u2642", 1}, +{"\U0001F471\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F471\U0001F3FD\u200D\u2642", 1}, +{"\U0001F471\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F471\U0001F3FE\u200D\u2642", 1}, +{"\U0001F471\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F471\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9D3\U0001F3FB", 1}, +{"\U0001F9D3\U0001F3FC", 1}, +{"\U0001F9D3\U0001F3FD", 1}, +{"\U0001F9D3\U0001F3FE", 1}, +{"\U0001F9D3\U0001F3FF", 1}, +{"\U0001F474\U0001F3FB", 1}, +{"\U0001F474\U0001F3FC", 1}, +{"\U0001F474\U0001F3FD", 1}, +{"\U0001F474\U0001F3FE", 1}, +{"\U0001F474\U0001F3FF", 1}, +{"\U0001F475\U0001F3FB", 1}, +{"\U0001F475\U0001F3FC", 1}, +{"\U0001F475\U0001F3FD", 1}, +{"\U0001F475\U0001F3FE", 1}, +{"\U0001F475\U0001F3FF", 1}, +{"\U0001F64D\U0001F3FB", 1}, +{"\U0001F64D\U0001F3FC", 1}, +{"\U0001F64D\U0001F3FD", 1}, +{"\U0001F64D\U0001F3FE", 1}, +{"\U0001F64D\U0001F3FF", 1}, +{"\U0001F64D\u200D\u2642\uFE0F", 1}, +{"\U0001F64D\u200D\u2642", 1}, +{"\U0001F64D\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F64D\U0001F3FB\u200D\u2642", 1}, +{"\U0001F64D\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F64D\U0001F3FC\u200D\u2642", 1}, +{"\U0001F64D\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F64D\U0001F3FD\u200D\u2642", 1}, +{"\U0001F64D\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F64D\U0001F3FE\u200D\u2642", 1}, +{"\U0001F64D\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F64D\U0001F3FF\u200D\u2642", 1}, +{"\U0001F64D\u200D\u2640\uFE0F", 1}, +{"\U0001F64D\u200D\u2640", 1}, +{"\U0001F64D\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F64D\U0001F3FB\u200D\u2640", 1}, +{"\U0001F64D\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F64D\U0001F3FC\u200D\u2640", 1}, +{"\U0001F64D\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F64D\U0001F3FD\u200D\u2640", 1}, +{"\U0001F64D\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F64D\U0001F3FE\u200D\u2640", 1}, +{"\U0001F64D\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F64D\U0001F3FF\u200D\u2640", 1}, +{"\U0001F64E\U0001F3FB", 1}, +{"\U0001F64E\U0001F3FC", 1}, +{"\U0001F64E\U0001F3FD", 1}, +{"\U0001F64E\U0001F3FE", 1}, +{"\U0001F64E\U0001F3FF", 1}, +{"\U0001F64E\u200D\u2642\uFE0F", 1}, +{"\U0001F64E\u200D\u2642", 1}, +{"\U0001F64E\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F64E\U0001F3FB\u200D\u2642", 1}, +{"\U0001F64E\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F64E\U0001F3FC\u200D\u2642", 1}, +{"\U0001F64E\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F64E\U0001F3FD\u200D\u2642", 1}, +{"\U0001F64E\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F64E\U0001F3FE\u200D\u2642", 1}, +{"\U0001F64E\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F64E\U0001F3FF\u200D\u2642", 1}, +{"\U0001F64E\u200D\u2640\uFE0F", 1}, +{"\U0001F64E\u200D\u2640", 1}, +{"\U0001F64E\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F64E\U0001F3FB\u200D\u2640", 1}, +{"\U0001F64E\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F64E\U0001F3FC\u200D\u2640", 1}, +{"\U0001F64E\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F64E\U0001F3FD\u200D\u2640", 1}, +{"\U0001F64E\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F64E\U0001F3FE\u200D\u2640", 1}, +{"\U0001F64E\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F64E\U0001F3FF\u200D\u2640", 1}, +{"\U0001F645\U0001F3FB", 1}, +{"\U0001F645\U0001F3FC", 1}, +{"\U0001F645\U0001F3FD", 1}, +{"\U0001F645\U0001F3FE", 1}, +{"\U0001F645\U0001F3FF", 1}, +{"\U0001F645\u200D\u2642\uFE0F", 1}, +{"\U0001F645\u200D\u2642", 1}, +{"\U0001F645\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F645\U0001F3FB\u200D\u2642", 1}, +{"\U0001F645\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F645\U0001F3FC\u200D\u2642", 1}, +{"\U0001F645\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F645\U0001F3FD\u200D\u2642", 1}, +{"\U0001F645\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F645\U0001F3FE\u200D\u2642", 1}, +{"\U0001F645\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F645\U0001F3FF\u200D\u2642", 1}, +{"\U0001F645\u200D\u2640\uFE0F", 1}, +{"\U0001F645\u200D\u2640", 1}, +{"\U0001F645\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F645\U0001F3FB\u200D\u2640", 1}, +{"\U0001F645\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F645\U0001F3FC\u200D\u2640", 1}, +{"\U0001F645\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F645\U0001F3FD\u200D\u2640", 1}, +{"\U0001F645\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F645\U0001F3FE\u200D\u2640", 1}, +{"\U0001F645\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F645\U0001F3FF\u200D\u2640", 1}, +{"\U0001F646\U0001F3FB", 1}, +{"\U0001F646\U0001F3FC", 1}, +{"\U0001F646\U0001F3FD", 1}, +{"\U0001F646\U0001F3FE", 1}, +{"\U0001F646\U0001F3FF", 1}, +{"\U0001F646\u200D\u2642\uFE0F", 1}, +{"\U0001F646\u200D\u2642", 1}, +{"\U0001F646\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F646\U0001F3FB\u200D\u2642", 1}, +{"\U0001F646\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F646\U0001F3FC\u200D\u2642", 1}, +{"\U0001F646\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F646\U0001F3FD\u200D\u2642", 1}, +{"\U0001F646\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F646\U0001F3FE\u200D\u2642", 1}, +{"\U0001F646\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F646\U0001F3FF\u200D\u2642", 1}, +{"\U0001F646\u200D\u2640\uFE0F", 1}, +{"\U0001F646\u200D\u2640", 1}, +{"\U0001F646\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F646\U0001F3FB\u200D\u2640", 1}, +{"\U0001F646\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F646\U0001F3FC\u200D\u2640", 1}, +{"\U0001F646\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F646\U0001F3FD\u200D\u2640", 1}, +{"\U0001F646\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F646\U0001F3FE\u200D\u2640", 1}, +{"\U0001F646\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F646\U0001F3FF\u200D\u2640", 1}, +{"\U0001F481\U0001F3FB", 1}, +{"\U0001F481\U0001F3FC", 1}, +{"\U0001F481\U0001F3FD", 1}, +{"\U0001F481\U0001F3FE", 1}, +{"\U0001F481\U0001F3FF", 1}, +{"\U0001F481\u200D\u2642\uFE0F", 1}, +{"\U0001F481\u200D\u2642", 1}, +{"\U0001F481\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F481\U0001F3FB\u200D\u2642", 1}, +{"\U0001F481\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F481\U0001F3FC\u200D\u2642", 1}, +{"\U0001F481\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F481\U0001F3FD\u200D\u2642", 1}, +{"\U0001F481\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F481\U0001F3FE\u200D\u2642", 1}, +{"\U0001F481\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F481\U0001F3FF\u200D\u2642", 1}, +{"\U0001F481\u200D\u2640\uFE0F", 1}, +{"\U0001F481\u200D\u2640", 1}, +{"\U0001F481\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F481\U0001F3FB\u200D\u2640", 1}, +{"\U0001F481\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F481\U0001F3FC\u200D\u2640", 1}, +{"\U0001F481\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F481\U0001F3FD\u200D\u2640", 1}, +{"\U0001F481\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F481\U0001F3FE\u200D\u2640", 1}, +{"\U0001F481\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F481\U0001F3FF\u200D\u2640", 1}, +{"\U0001F64B\U0001F3FB", 1}, +{"\U0001F64B\U0001F3FC", 1}, +{"\U0001F64B\U0001F3FD", 1}, +{"\U0001F64B\U0001F3FE", 1}, +{"\U0001F64B\U0001F3FF", 1}, +{"\U0001F64B\u200D\u2642\uFE0F", 1}, +{"\U0001F64B\u200D\u2642", 1}, +{"\U0001F64B\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F64B\U0001F3FB\u200D\u2642", 1}, +{"\U0001F64B\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F64B\U0001F3FC\u200D\u2642", 1}, +{"\U0001F64B\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F64B\U0001F3FD\u200D\u2642", 1}, +{"\U0001F64B\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F64B\U0001F3FE\u200D\u2642", 1}, +{"\U0001F64B\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F64B\U0001F3FF\u200D\u2642", 1}, +{"\U0001F64B\u200D\u2640\uFE0F", 1}, +{"\U0001F64B\u200D\u2640", 1}, +{"\U0001F64B\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F64B\U0001F3FB\u200D\u2640", 1}, +{"\U0001F64B\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F64B\U0001F3FC\u200D\u2640", 1}, +{"\U0001F64B\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F64B\U0001F3FD\u200D\u2640", 1}, +{"\U0001F64B\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F64B\U0001F3FE\u200D\u2640", 1}, +{"\U0001F64B\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F64B\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9CF\U0001F3FB", 1}, +{"\U0001F9CF\U0001F3FC", 1}, +{"\U0001F9CF\U0001F3FD", 1}, +{"\U0001F9CF\U0001F3FE", 1}, +{"\U0001F9CF\U0001F3FF", 1}, +{"\U0001F9CF\u200D\u2642\uFE0F", 1}, +{"\U0001F9CF\u200D\u2642", 1}, +{"\U0001F9CF\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9CF\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9CF\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9CF\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9CF\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9CF\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9CF\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9CF\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9CF\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9CF\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9CF\u200D\u2640\uFE0F", 1}, +{"\U0001F9CF\u200D\u2640", 1}, +{"\U0001F9CF\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9CF\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9CF\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9CF\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9CF\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9CF\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9CF\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9CF\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9CF\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9CF\U0001F3FF\u200D\u2640", 1}, +{"\U0001F647\U0001F3FB", 1}, +{"\U0001F647\U0001F3FC", 1}, +{"\U0001F647\U0001F3FD", 1}, +{"\U0001F647\U0001F3FE", 1}, +{"\U0001F647\U0001F3FF", 1}, +{"\U0001F647\u200D\u2642\uFE0F", 1}, +{"\U0001F647\u200D\u2642", 1}, +{"\U0001F647\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F647\U0001F3FB\u200D\u2642", 1}, +{"\U0001F647\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F647\U0001F3FC\u200D\u2642", 1}, +{"\U0001F647\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F647\U0001F3FD\u200D\u2642", 1}, +{"\U0001F647\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F647\U0001F3FE\u200D\u2642", 1}, +{"\U0001F647\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F647\U0001F3FF\u200D\u2642", 1}, +{"\U0001F647\u200D\u2640\uFE0F", 1}, +{"\U0001F647\u200D\u2640", 1}, +{"\U0001F647\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F647\U0001F3FB\u200D\u2640", 1}, +{"\U0001F647\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F647\U0001F3FC\u200D\u2640", 1}, +{"\U0001F647\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F647\U0001F3FD\u200D\u2640", 1}, +{"\U0001F647\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F647\U0001F3FE\u200D\u2640", 1}, +{"\U0001F647\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F647\U0001F3FF\u200D\u2640", 1}, +{"\U0001F926\U0001F3FB", 1}, +{"\U0001F926\U0001F3FC", 1}, +{"\U0001F926\U0001F3FD", 1}, +{"\U0001F926\U0001F3FE", 1}, +{"\U0001F926\U0001F3FF", 1}, +{"\U0001F926\u200D\u2642\uFE0F", 1}, +{"\U0001F926\u200D\u2642", 1}, +{"\U0001F926\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F926\U0001F3FB\u200D\u2642", 1}, +{"\U0001F926\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F926\U0001F3FC\u200D\u2642", 1}, +{"\U0001F926\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F926\U0001F3FD\u200D\u2642", 1}, +{"\U0001F926\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F926\U0001F3FE\u200D\u2642", 1}, +{"\U0001F926\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F926\U0001F3FF\u200D\u2642", 1}, +{"\U0001F926\u200D\u2640\uFE0F", 1}, +{"\U0001F926\u200D\u2640", 1}, +{"\U0001F926\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F926\U0001F3FB\u200D\u2640", 1}, +{"\U0001F926\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F926\U0001F3FC\u200D\u2640", 1}, +{"\U0001F926\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F926\U0001F3FD\u200D\u2640", 1}, +{"\U0001F926\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F926\U0001F3FE\u200D\u2640", 1}, +{"\U0001F926\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F926\U0001F3FF\u200D\u2640", 1}, +{"\U0001F937\U0001F3FB", 1}, +{"\U0001F937\U0001F3FC", 1}, +{"\U0001F937\U0001F3FD", 1}, +{"\U0001F937\U0001F3FE", 1}, +{"\U0001F937\U0001F3FF", 1}, +{"\U0001F937\u200D\u2642\uFE0F", 1}, +{"\U0001F937\u200D\u2642", 1}, +{"\U0001F937\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F937\U0001F3FB\u200D\u2642", 1}, +{"\U0001F937\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F937\U0001F3FC\u200D\u2642", 1}, +{"\U0001F937\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F937\U0001F3FD\u200D\u2642", 1}, +{"\U0001F937\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F937\U0001F3FE\u200D\u2642", 1}, +{"\U0001F937\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F937\U0001F3FF\u200D\u2642", 1}, +{"\U0001F937\u200D\u2640\uFE0F", 1}, +{"\U0001F937\u200D\u2640", 1}, +{"\U0001F937\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F937\U0001F3FB\u200D\u2640", 1}, +{"\U0001F937\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F937\U0001F3FC\u200D\u2640", 1}, +{"\U0001F937\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F937\U0001F3FD\u200D\u2640", 1}, +{"\U0001F937\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F937\U0001F3FE\u200D\u2640", 1}, +{"\U0001F937\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F937\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9D1\u200D\u2695\uFE0F", 1}, +{"\U0001F9D1\u200D\u2695", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2695\uFE0F", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2695", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2695\uFE0F", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2695", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2695\uFE0F", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2695", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2695\uFE0F", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2695", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2695\uFE0F", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2695", 1}, +{"\U0001F468\u200D\u2695\uFE0F", 1}, +{"\U0001F468\u200D\u2695", 1}, +{"\U0001F468\U0001F3FB\u200D\u2695\uFE0F", 1}, +{"\U0001F468\U0001F3FB\u200D\u2695", 1}, +{"\U0001F468\U0001F3FC\u200D\u2695\uFE0F", 1}, +{"\U0001F468\U0001F3FC\u200D\u2695", 1}, +{"\U0001F468\U0001F3FD\u200D\u2695\uFE0F", 1}, +{"\U0001F468\U0001F3FD\u200D\u2695", 1}, +{"\U0001F468\U0001F3FE\u200D\u2695\uFE0F", 1}, +{"\U0001F468\U0001F3FE\u200D\u2695", 1}, +{"\U0001F468\U0001F3FF\u200D\u2695\uFE0F", 1}, +{"\U0001F468\U0001F3FF\u200D\u2695", 1}, +{"\U0001F469\u200D\u2695\uFE0F", 1}, +{"\U0001F469\u200D\u2695", 1}, +{"\U0001F469\U0001F3FB\u200D\u2695\uFE0F", 1}, +{"\U0001F469\U0001F3FB\u200D\u2695", 1}, +{"\U0001F469\U0001F3FC\u200D\u2695\uFE0F", 1}, +{"\U0001F469\U0001F3FC\u200D\u2695", 1}, +{"\U0001F469\U0001F3FD\u200D\u2695\uFE0F", 1}, +{"\U0001F469\U0001F3FD\u200D\u2695", 1}, +{"\U0001F469\U0001F3FE\u200D\u2695\uFE0F", 1}, +{"\U0001F469\U0001F3FE\u200D\u2695", 1}, +{"\U0001F469\U0001F3FF\u200D\u2695\uFE0F", 1}, +{"\U0001F469\U0001F3FF\u200D\u2695", 1}, +{"\U0001F9D1\u200D\U0001F393", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F393", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F393", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F393", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F393", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F393", 1}, +{"\U0001F468\u200D\U0001F393", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F393", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F393", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F393", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F393", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F393", 1}, +{"\U0001F469\u200D\U0001F393", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F393", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F393", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F393", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F393", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F393", 1}, +{"\U0001F9D1\u200D\U0001F3EB", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F3EB", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F3EB", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F3EB", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F3EB", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F3EB", 1}, +{"\U0001F468\u200D\U0001F3EB", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F3EB", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F3EB", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F3EB", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F3EB", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F3EB", 1}, +{"\U0001F469\u200D\U0001F3EB", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F3EB", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F3EB", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F3EB", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F3EB", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F3EB", 1}, +{"\U0001F9D1\u200D\u2696\uFE0F", 1}, +{"\U0001F9D1\u200D\u2696", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2696\uFE0F", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2696", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2696\uFE0F", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2696", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2696\uFE0F", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2696", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2696\uFE0F", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2696", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2696\uFE0F", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2696", 1}, +{"\U0001F468\u200D\u2696\uFE0F", 1}, +{"\U0001F468\u200D\u2696", 1}, +{"\U0001F468\U0001F3FB\u200D\u2696\uFE0F", 1}, +{"\U0001F468\U0001F3FB\u200D\u2696", 1}, +{"\U0001F468\U0001F3FC\u200D\u2696\uFE0F", 1}, +{"\U0001F468\U0001F3FC\u200D\u2696", 1}, +{"\U0001F468\U0001F3FD\u200D\u2696\uFE0F", 1}, +{"\U0001F468\U0001F3FD\u200D\u2696", 1}, +{"\U0001F468\U0001F3FE\u200D\u2696\uFE0F", 1}, +{"\U0001F468\U0001F3FE\u200D\u2696", 1}, +{"\U0001F468\U0001F3FF\u200D\u2696\uFE0F", 1}, +{"\U0001F468\U0001F3FF\u200D\u2696", 1}, +{"\U0001F469\u200D\u2696\uFE0F", 1}, +{"\U0001F469\u200D\u2696", 1}, +{"\U0001F469\U0001F3FB\u200D\u2696\uFE0F", 1}, +{"\U0001F469\U0001F3FB\u200D\u2696", 1}, +{"\U0001F469\U0001F3FC\u200D\u2696\uFE0F", 1}, +{"\U0001F469\U0001F3FC\u200D\u2696", 1}, +{"\U0001F469\U0001F3FD\u200D\u2696\uFE0F", 1}, +{"\U0001F469\U0001F3FD\u200D\u2696", 1}, +{"\U0001F469\U0001F3FE\u200D\u2696\uFE0F", 1}, +{"\U0001F469\U0001F3FE\u200D\u2696", 1}, +{"\U0001F469\U0001F3FF\u200D\u2696\uFE0F", 1}, +{"\U0001F469\U0001F3FF\u200D\u2696", 1}, +{"\U0001F9D1\u200D\U0001F33E", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F33E", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F33E", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F33E", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F33E", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F33E", 1}, +{"\U0001F468\u200D\U0001F33E", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F33E", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F33E", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F33E", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F33E", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F33E", 1}, +{"\U0001F469\u200D\U0001F33E", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F33E", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F33E", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F33E", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F33E", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F33E", 1}, +{"\U0001F9D1\u200D\U0001F373", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F373", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F373", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F373", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F373", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F373", 1}, +{"\U0001F468\u200D\U0001F373", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F373", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F373", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F373", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F373", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F373", 1}, +{"\U0001F469\u200D\U0001F373", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F373", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F373", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F373", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F373", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F373", 1}, +{"\U0001F9D1\u200D\U0001F527", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F527", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F527", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F527", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F527", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F527", 1}, +{"\U0001F468\u200D\U0001F527", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F527", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F527", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F527", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F527", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F527", 1}, +{"\U0001F469\u200D\U0001F527", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F527", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F527", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F527", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F527", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F527", 1}, +{"\U0001F9D1\u200D\U0001F3ED", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F3ED", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F3ED", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F3ED", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F3ED", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F3ED", 1}, +{"\U0001F468\u200D\U0001F3ED", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F3ED", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F3ED", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F3ED", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F3ED", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F3ED", 1}, +{"\U0001F469\u200D\U0001F3ED", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F3ED", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F3ED", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F3ED", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F3ED", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F3ED", 1}, +{"\U0001F9D1\u200D\U0001F4BC", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F4BC", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F4BC", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F4BC", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F4BC", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F4BC", 1}, +{"\U0001F468\u200D\U0001F4BC", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F4BC", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F4BC", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F4BC", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F4BC", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F4BC", 1}, +{"\U0001F469\u200D\U0001F4BC", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F4BC", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F4BC", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F4BC", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F4BC", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F4BC", 1}, +{"\U0001F9D1\u200D\U0001F52C", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F52C", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F52C", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F52C", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F52C", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F52C", 1}, +{"\U0001F468\u200D\U0001F52C", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F52C", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F52C", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F52C", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F52C", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F52C", 1}, +{"\U0001F469\u200D\U0001F52C", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F52C", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F52C", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F52C", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F52C", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F52C", 1}, +{"\U0001F9D1\u200D\U0001F4BB", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F4BB", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F4BB", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F4BB", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F4BB", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F4BB", 1}, +{"\U0001F468\u200D\U0001F4BB", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F4BB", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F4BB", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F4BB", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F4BB", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F4BB", 1}, +{"\U0001F469\u200D\U0001F4BB", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F4BB", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F4BB", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F4BB", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F4BB", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F4BB", 1}, +{"\U0001F9D1\u200D\U0001F3A4", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F3A4", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F3A4", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F3A4", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F3A4", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F3A4", 1}, +{"\U0001F468\u200D\U0001F3A4", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F3A4", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F3A4", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F3A4", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F3A4", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F3A4", 1}, +{"\U0001F469\u200D\U0001F3A4", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F3A4", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F3A4", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F3A4", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F3A4", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F3A4", 1}, +{"\U0001F9D1\u200D\U0001F3A8", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F3A8", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F3A8", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F3A8", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F3A8", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F3A8", 1}, +{"\U0001F468\u200D\U0001F3A8", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F3A8", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F3A8", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F3A8", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F3A8", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F3A8", 1}, +{"\U0001F469\u200D\U0001F3A8", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F3A8", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F3A8", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F3A8", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F3A8", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F3A8", 1}, +{"\U0001F9D1\u200D\u2708\uFE0F", 1}, +{"\U0001F9D1\u200D\u2708", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2708\uFE0F", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2708", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2708\uFE0F", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2708", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2708\uFE0F", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2708", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2708\uFE0F", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2708", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2708\uFE0F", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2708", 1}, +{"\U0001F468\u200D\u2708\uFE0F", 1}, +{"\U0001F468\u200D\u2708", 1}, +{"\U0001F468\U0001F3FB\u200D\u2708\uFE0F", 1}, +{"\U0001F468\U0001F3FB\u200D\u2708", 1}, +{"\U0001F468\U0001F3FC\u200D\u2708\uFE0F", 1}, +{"\U0001F468\U0001F3FC\u200D\u2708", 1}, +{"\U0001F468\U0001F3FD\u200D\u2708\uFE0F", 1}, +{"\U0001F468\U0001F3FD\u200D\u2708", 1}, +{"\U0001F468\U0001F3FE\u200D\u2708\uFE0F", 1}, +{"\U0001F468\U0001F3FE\u200D\u2708", 1}, +{"\U0001F468\U0001F3FF\u200D\u2708\uFE0F", 1}, +{"\U0001F468\U0001F3FF\u200D\u2708", 1}, +{"\U0001F469\u200D\u2708\uFE0F", 1}, +{"\U0001F469\u200D\u2708", 1}, +{"\U0001F469\U0001F3FB\u200D\u2708\uFE0F", 1}, +{"\U0001F469\U0001F3FB\u200D\u2708", 1}, +{"\U0001F469\U0001F3FC\u200D\u2708\uFE0F", 1}, +{"\U0001F469\U0001F3FC\u200D\u2708", 1}, +{"\U0001F469\U0001F3FD\u200D\u2708\uFE0F", 1}, +{"\U0001F469\U0001F3FD\u200D\u2708", 1}, +{"\U0001F469\U0001F3FE\u200D\u2708\uFE0F", 1}, +{"\U0001F469\U0001F3FE\u200D\u2708", 1}, +{"\U0001F469\U0001F3FF\u200D\u2708\uFE0F", 1}, +{"\U0001F469\U0001F3FF\u200D\u2708", 1}, +{"\U0001F9D1\u200D\U0001F680", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F680", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F680", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F680", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F680", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F680", 1}, +{"\U0001F468\u200D\U0001F680", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F680", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F680", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F680", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F680", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F680", 1}, +{"\U0001F469\u200D\U0001F680", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F680", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F680", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F680", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F680", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F680", 1}, +{"\U0001F9D1\u200D\U0001F692", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F692", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F692", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F692", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F692", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F692", 1}, +{"\U0001F468\u200D\U0001F692", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F692", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F692", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F692", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F692", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F692", 1}, +{"\U0001F469\u200D\U0001F692", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F692", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F692", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F692", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F692", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F692", 1}, +{"\U0001F46E\U0001F3FB", 1}, +{"\U0001F46E\U0001F3FC", 1}, +{"\U0001F46E\U0001F3FD", 1}, +{"\U0001F46E\U0001F3FE", 1}, +{"\U0001F46E\U0001F3FF", 1}, +{"\U0001F46E\u200D\u2642\uFE0F", 1}, +{"\U0001F46E\u200D\u2642", 1}, +{"\U0001F46E\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F46E\U0001F3FB\u200D\u2642", 1}, +{"\U0001F46E\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F46E\U0001F3FC\u200D\u2642", 1}, +{"\U0001F46E\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F46E\U0001F3FD\u200D\u2642", 1}, +{"\U0001F46E\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F46E\U0001F3FE\u200D\u2642", 1}, +{"\U0001F46E\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F46E\U0001F3FF\u200D\u2642", 1}, +{"\U0001F46E\u200D\u2640\uFE0F", 1}, +{"\U0001F46E\u200D\u2640", 1}, +{"\U0001F46E\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F46E\U0001F3FB\u200D\u2640", 1}, +{"\U0001F46E\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F46E\U0001F3FC\u200D\u2640", 1}, +{"\U0001F46E\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F46E\U0001F3FD\u200D\u2640", 1}, +{"\U0001F46E\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F46E\U0001F3FE\u200D\u2640", 1}, +{"\U0001F46E\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F46E\U0001F3FF\u200D\u2640", 1}, +{"\U0001F575\uFE0F", 1}, +{"\U0001F575\U0001F3FB", 1}, +{"\U0001F575\U0001F3FC", 1}, +{"\U0001F575\U0001F3FD", 1}, +{"\U0001F575\U0001F3FE", 1}, +{"\U0001F575\U0001F3FF", 1}, +{"\U0001F575\uFE0F\u200D\u2642\uFE0F", 1}, +{"\U0001F575\u200D\u2642\uFE0F", 1}, +{"\U0001F575\uFE0F\u200D\u2642", 1}, +{"\U0001F575\u200D\u2642", 1}, +{"\U0001F575\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F575\U0001F3FB\u200D\u2642", 1}, +{"\U0001F575\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F575\U0001F3FC\u200D\u2642", 1}, +{"\U0001F575\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F575\U0001F3FD\u200D\u2642", 1}, +{"\U0001F575\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F575\U0001F3FE\u200D\u2642", 1}, +{"\U0001F575\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F575\U0001F3FF\u200D\u2642", 1}, +{"\U0001F575\uFE0F\u200D\u2640\uFE0F", 1}, +{"\U0001F575\u200D\u2640\uFE0F", 1}, +{"\U0001F575\uFE0F\u200D\u2640", 1}, +{"\U0001F575\u200D\u2640", 1}, +{"\U0001F575\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F575\U0001F3FB\u200D\u2640", 1}, +{"\U0001F575\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F575\U0001F3FC\u200D\u2640", 1}, +{"\U0001F575\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F575\U0001F3FD\u200D\u2640", 1}, +{"\U0001F575\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F575\U0001F3FE\u200D\u2640", 1}, +{"\U0001F575\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F575\U0001F3FF\u200D\u2640", 1}, +{"\U0001F482\U0001F3FB", 1}, +{"\U0001F482\U0001F3FC", 1}, +{"\U0001F482\U0001F3FD", 1}, +{"\U0001F482\U0001F3FE", 1}, +{"\U0001F482\U0001F3FF", 1}, +{"\U0001F482\u200D\u2642\uFE0F", 1}, +{"\U0001F482\u200D\u2642", 1}, +{"\U0001F482\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F482\U0001F3FB\u200D\u2642", 1}, +{"\U0001F482\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F482\U0001F3FC\u200D\u2642", 1}, +{"\U0001F482\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F482\U0001F3FD\u200D\u2642", 1}, +{"\U0001F482\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F482\U0001F3FE\u200D\u2642", 1}, +{"\U0001F482\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F482\U0001F3FF\u200D\u2642", 1}, +{"\U0001F482\u200D\u2640\uFE0F", 1}, +{"\U0001F482\u200D\u2640", 1}, +{"\U0001F482\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F482\U0001F3FB\u200D\u2640", 1}, +{"\U0001F482\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F482\U0001F3FC\u200D\u2640", 1}, +{"\U0001F482\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F482\U0001F3FD\u200D\u2640", 1}, +{"\U0001F482\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F482\U0001F3FE\u200D\u2640", 1}, +{"\U0001F482\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F482\U0001F3FF\u200D\u2640", 1}, +{"\U0001F977\U0001F3FB", 1}, +{"\U0001F977\U0001F3FC", 1}, +{"\U0001F977\U0001F3FD", 1}, +{"\U0001F977\U0001F3FE", 1}, +{"\U0001F977\U0001F3FF", 1}, +{"\U0001F477\U0001F3FB", 1}, +{"\U0001F477\U0001F3FC", 1}, +{"\U0001F477\U0001F3FD", 1}, +{"\U0001F477\U0001F3FE", 1}, +{"\U0001F477\U0001F3FF", 1}, +{"\U0001F477\u200D\u2642\uFE0F", 1}, +{"\U0001F477\u200D\u2642", 1}, +{"\U0001F477\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F477\U0001F3FB\u200D\u2642", 1}, +{"\U0001F477\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F477\U0001F3FC\u200D\u2642", 1}, +{"\U0001F477\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F477\U0001F3FD\u200D\u2642", 1}, +{"\U0001F477\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F477\U0001F3FE\u200D\u2642", 1}, +{"\U0001F477\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F477\U0001F3FF\u200D\u2642", 1}, +{"\U0001F477\u200D\u2640\uFE0F", 1}, +{"\U0001F477\u200D\u2640", 1}, +{"\U0001F477\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F477\U0001F3FB\u200D\u2640", 1}, +{"\U0001F477\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F477\U0001F3FC\u200D\u2640", 1}, +{"\U0001F477\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F477\U0001F3FD\u200D\u2640", 1}, +{"\U0001F477\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F477\U0001F3FE\u200D\u2640", 1}, +{"\U0001F477\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F477\U0001F3FF\u200D\u2640", 1}, +{"\U0001FAC5\U0001F3FB", 1}, +{"\U0001FAC5\U0001F3FC", 1}, +{"\U0001FAC5\U0001F3FD", 1}, +{"\U0001FAC5\U0001F3FE", 1}, +{"\U0001FAC5\U0001F3FF", 1}, +{"\U0001F934\U0001F3FB", 1}, +{"\U0001F934\U0001F3FC", 1}, +{"\U0001F934\U0001F3FD", 1}, +{"\U0001F934\U0001F3FE", 1}, +{"\U0001F934\U0001F3FF", 1}, +{"\U0001F478\U0001F3FB", 1}, +{"\U0001F478\U0001F3FC", 1}, +{"\U0001F478\U0001F3FD", 1}, +{"\U0001F478\U0001F3FE", 1}, +{"\U0001F478\U0001F3FF", 1}, +{"\U0001F473\U0001F3FB", 1}, +{"\U0001F473\U0001F3FC", 1}, +{"\U0001F473\U0001F3FD", 1}, +{"\U0001F473\U0001F3FE", 1}, +{"\U0001F473\U0001F3FF", 1}, +{"\U0001F473\u200D\u2642\uFE0F", 1}, +{"\U0001F473\u200D\u2642", 1}, +{"\U0001F473\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F473\U0001F3FB\u200D\u2642", 1}, +{"\U0001F473\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F473\U0001F3FC\u200D\u2642", 1}, +{"\U0001F473\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F473\U0001F3FD\u200D\u2642", 1}, +{"\U0001F473\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F473\U0001F3FE\u200D\u2642", 1}, +{"\U0001F473\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F473\U0001F3FF\u200D\u2642", 1}, +{"\U0001F473\u200D\u2640\uFE0F", 1}, +{"\U0001F473\u200D\u2640", 1}, +{"\U0001F473\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F473\U0001F3FB\u200D\u2640", 1}, +{"\U0001F473\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F473\U0001F3FC\u200D\u2640", 1}, +{"\U0001F473\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F473\U0001F3FD\u200D\u2640", 1}, +{"\U0001F473\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F473\U0001F3FE\u200D\u2640", 1}, +{"\U0001F473\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F473\U0001F3FF\u200D\u2640", 1}, +{"\U0001F472\U0001F3FB", 1}, +{"\U0001F472\U0001F3FC", 1}, +{"\U0001F472\U0001F3FD", 1}, +{"\U0001F472\U0001F3FE", 1}, +{"\U0001F472\U0001F3FF", 1}, +{"\U0001F9D5\U0001F3FB", 1}, +{"\U0001F9D5\U0001F3FC", 1}, +{"\U0001F9D5\U0001F3FD", 1}, +{"\U0001F9D5\U0001F3FE", 1}, +{"\U0001F9D5\U0001F3FF", 1}, +{"\U0001F935\U0001F3FB", 1}, +{"\U0001F935\U0001F3FC", 1}, +{"\U0001F935\U0001F3FD", 1}, +{"\U0001F935\U0001F3FE", 1}, +{"\U0001F935\U0001F3FF", 1}, +{"\U0001F935\u200D\u2642\uFE0F", 1}, +{"\U0001F935\u200D\u2642", 1}, +{"\U0001F935\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F935\U0001F3FB\u200D\u2642", 1}, +{"\U0001F935\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F935\U0001F3FC\u200D\u2642", 1}, +{"\U0001F935\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F935\U0001F3FD\u200D\u2642", 1}, +{"\U0001F935\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F935\U0001F3FE\u200D\u2642", 1}, +{"\U0001F935\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F935\U0001F3FF\u200D\u2642", 1}, +{"\U0001F935\u200D\u2640\uFE0F", 1}, +{"\U0001F935\u200D\u2640", 1}, +{"\U0001F935\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F935\U0001F3FB\u200D\u2640", 1}, +{"\U0001F935\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F935\U0001F3FC\u200D\u2640", 1}, +{"\U0001F935\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F935\U0001F3FD\u200D\u2640", 1}, +{"\U0001F935\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F935\U0001F3FE\u200D\u2640", 1}, +{"\U0001F935\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F935\U0001F3FF\u200D\u2640", 1}, +{"\U0001F470\U0001F3FB", 1}, +{"\U0001F470\U0001F3FC", 1}, +{"\U0001F470\U0001F3FD", 1}, +{"\U0001F470\U0001F3FE", 1}, +{"\U0001F470\U0001F3FF", 1}, +{"\U0001F470\u200D\u2642\uFE0F", 1}, +{"\U0001F470\u200D\u2642", 1}, +{"\U0001F470\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F470\U0001F3FB\u200D\u2642", 1}, +{"\U0001F470\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F470\U0001F3FC\u200D\u2642", 1}, +{"\U0001F470\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F470\U0001F3FD\u200D\u2642", 1}, +{"\U0001F470\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F470\U0001F3FE\u200D\u2642", 1}, +{"\U0001F470\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F470\U0001F3FF\u200D\u2642", 1}, +{"\U0001F470\u200D\u2640\uFE0F", 1}, +{"\U0001F470\u200D\u2640", 1}, +{"\U0001F470\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F470\U0001F3FB\u200D\u2640", 1}, +{"\U0001F470\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F470\U0001F3FC\u200D\u2640", 1}, +{"\U0001F470\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F470\U0001F3FD\u200D\u2640", 1}, +{"\U0001F470\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F470\U0001F3FE\u200D\u2640", 1}, +{"\U0001F470\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F470\U0001F3FF\u200D\u2640", 1}, +{"\U0001F930\U0001F3FB", 1}, +{"\U0001F930\U0001F3FC", 1}, +{"\U0001F930\U0001F3FD", 1}, +{"\U0001F930\U0001F3FE", 1}, +{"\U0001F930\U0001F3FF", 1}, +{"\U0001FAC3\U0001F3FB", 1}, +{"\U0001FAC3\U0001F3FC", 1}, +{"\U0001FAC3\U0001F3FD", 1}, +{"\U0001FAC3\U0001F3FE", 1}, +{"\U0001FAC3\U0001F3FF", 1}, +{"\U0001FAC4\U0001F3FB", 1}, +{"\U0001FAC4\U0001F3FC", 1}, +{"\U0001FAC4\U0001F3FD", 1}, +{"\U0001FAC4\U0001F3FE", 1}, +{"\U0001FAC4\U0001F3FF", 1}, +{"\U0001F931\U0001F3FB", 1}, +{"\U0001F931\U0001F3FC", 1}, +{"\U0001F931\U0001F3FD", 1}, +{"\U0001F931\U0001F3FE", 1}, +{"\U0001F931\U0001F3FF", 1}, +{"\U0001F469\u200D\U0001F37C", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F37C", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F37C", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F37C", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F37C", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F37C", 1}, +{"\U0001F468\u200D\U0001F37C", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F37C", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F37C", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F37C", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F37C", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F37C", 1}, +{"\U0001F9D1\u200D\U0001F37C", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F37C", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F37C", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F37C", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F37C", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F37C", 1}, +{"\U0001F47C\U0001F3FB", 1}, +{"\U0001F47C\U0001F3FC", 1}, +{"\U0001F47C\U0001F3FD", 1}, +{"\U0001F47C\U0001F3FE", 1}, +{"\U0001F47C\U0001F3FF", 1}, +{"\U0001F385\U0001F3FB", 1}, +{"\U0001F385\U0001F3FC", 1}, +{"\U0001F385\U0001F3FD", 1}, +{"\U0001F385\U0001F3FE", 1}, +{"\U0001F385\U0001F3FF", 1}, +{"\U0001F936\U0001F3FB", 1}, +{"\U0001F936\U0001F3FC", 1}, +{"\U0001F936\U0001F3FD", 1}, +{"\U0001F936\U0001F3FE", 1}, +{"\U0001F936\U0001F3FF", 1}, +{"\U0001F9D1\u200D\U0001F384", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F384", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F384", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F384", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F384", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F384", 1}, +{"\U0001F9B8\U0001F3FB", 1}, +{"\U0001F9B8\U0001F3FC", 1}, +{"\U0001F9B8\U0001F3FD", 1}, +{"\U0001F9B8\U0001F3FE", 1}, +{"\U0001F9B8\U0001F3FF", 1}, +{"\U0001F9B8\u200D\u2642\uFE0F", 1}, +{"\U0001F9B8\u200D\u2642", 1}, +{"\U0001F9B8\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9B8\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9B8\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9B8\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9B8\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9B8\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9B8\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9B8\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9B8\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9B8\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9B8\u200D\u2640\uFE0F", 1}, +{"\U0001F9B8\u200D\u2640", 1}, +{"\U0001F9B8\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9B8\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9B8\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9B8\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9B8\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9B8\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9B8\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9B8\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9B8\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9B8\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9B9\U0001F3FB", 1}, +{"\U0001F9B9\U0001F3FC", 1}, +{"\U0001F9B9\U0001F3FD", 1}, +{"\U0001F9B9\U0001F3FE", 1}, +{"\U0001F9B9\U0001F3FF", 1}, +{"\U0001F9B9\u200D\u2642\uFE0F", 1}, +{"\U0001F9B9\u200D\u2642", 1}, +{"\U0001F9B9\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9B9\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9B9\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9B9\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9B9\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9B9\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9B9\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9B9\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9B9\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9B9\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9B9\u200D\u2640\uFE0F", 1}, +{"\U0001F9B9\u200D\u2640", 1}, +{"\U0001F9B9\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9B9\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9B9\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9B9\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9B9\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9B9\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9B9\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9B9\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9B9\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9B9\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9D9\U0001F3FB", 1}, +{"\U0001F9D9\U0001F3FC", 1}, +{"\U0001F9D9\U0001F3FD", 1}, +{"\U0001F9D9\U0001F3FE", 1}, +{"\U0001F9D9\U0001F3FF", 1}, +{"\U0001F9D9\u200D\u2642\uFE0F", 1}, +{"\U0001F9D9\u200D\u2642", 1}, +{"\U0001F9D9\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9D9\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9D9\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9D9\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9D9\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9D9\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9D9\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9D9\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9D9\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9D9\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9D9\u200D\u2640\uFE0F", 1}, +{"\U0001F9D9\u200D\u2640", 1}, +{"\U0001F9D9\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9D9\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9D9\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9D9\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9D9\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9D9\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9D9\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9D9\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9D9\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9D9\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9DA\U0001F3FB", 1}, +{"\U0001F9DA\U0001F3FC", 1}, +{"\U0001F9DA\U0001F3FD", 1}, +{"\U0001F9DA\U0001F3FE", 1}, +{"\U0001F9DA\U0001F3FF", 1}, +{"\U0001F9DA\u200D\u2642\uFE0F", 1}, +{"\U0001F9DA\u200D\u2642", 1}, +{"\U0001F9DA\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9DA\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9DA\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9DA\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9DA\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9DA\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9DA\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9DA\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9DA\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9DA\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9DA\u200D\u2640\uFE0F", 1}, +{"\U0001F9DA\u200D\u2640", 1}, +{"\U0001F9DA\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9DA\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9DA\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9DA\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9DA\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9DA\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9DA\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9DA\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9DA\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9DA\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9DB\U0001F3FB", 1}, +{"\U0001F9DB\U0001F3FC", 1}, +{"\U0001F9DB\U0001F3FD", 1}, +{"\U0001F9DB\U0001F3FE", 1}, +{"\U0001F9DB\U0001F3FF", 1}, +{"\U0001F9DB\u200D\u2642\uFE0F", 1}, +{"\U0001F9DB\u200D\u2642", 1}, +{"\U0001F9DB\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9DB\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9DB\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9DB\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9DB\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9DB\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9DB\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9DB\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9DB\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9DB\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9DB\u200D\u2640\uFE0F", 1}, +{"\U0001F9DB\u200D\u2640", 1}, +{"\U0001F9DB\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9DB\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9DB\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9DB\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9DB\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9DB\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9DB\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9DB\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9DB\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9DB\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9DC\U0001F3FB", 1}, +{"\U0001F9DC\U0001F3FC", 1}, +{"\U0001F9DC\U0001F3FD", 1}, +{"\U0001F9DC\U0001F3FE", 1}, +{"\U0001F9DC\U0001F3FF", 1}, +{"\U0001F9DC\u200D\u2642\uFE0F", 1}, +{"\U0001F9DC\u200D\u2642", 1}, +{"\U0001F9DC\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9DC\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9DC\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9DC\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9DC\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9DC\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9DC\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9DC\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9DC\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9DC\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9DC\u200D\u2640\uFE0F", 1}, +{"\U0001F9DC\u200D\u2640", 1}, +{"\U0001F9DC\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9DC\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9DC\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9DC\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9DC\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9DC\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9DC\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9DC\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9DC\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9DC\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9DD\U0001F3FB", 1}, +{"\U0001F9DD\U0001F3FC", 1}, +{"\U0001F9DD\U0001F3FD", 1}, +{"\U0001F9DD\U0001F3FE", 1}, +{"\U0001F9DD\U0001F3FF", 1}, +{"\U0001F9DD\u200D\u2642\uFE0F", 1}, +{"\U0001F9DD\u200D\u2642", 1}, +{"\U0001F9DD\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9DD\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9DD\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9DD\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9DD\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9DD\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9DD\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9DD\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9DD\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9DD\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9DD\u200D\u2640\uFE0F", 1}, +{"\U0001F9DD\u200D\u2640", 1}, +{"\U0001F9DD\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9DD\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9DD\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9DD\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9DD\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9DD\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9DD\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9DD\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9DD\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9DD\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9DE\u200D\u2642\uFE0F", 1}, +{"\U0001F9DE\u200D\u2642", 1}, +{"\U0001F9DE\u200D\u2640\uFE0F", 1}, +{"\U0001F9DE\u200D\u2640", 1}, +{"\U0001F9DF\u200D\u2642\uFE0F", 1}, +{"\U0001F9DF\u200D\u2642", 1}, +{"\U0001F9DF\u200D\u2640\uFE0F", 1}, +{"\U0001F9DF\u200D\u2640", 1}, +{"\U0001F486\U0001F3FB", 1}, +{"\U0001F486\U0001F3FC", 1}, +{"\U0001F486\U0001F3FD", 1}, +{"\U0001F486\U0001F3FE", 1}, +{"\U0001F486\U0001F3FF", 1}, +{"\U0001F486\u200D\u2642\uFE0F", 1}, +{"\U0001F486\u200D\u2642", 1}, +{"\U0001F486\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F486\U0001F3FB\u200D\u2642", 1}, +{"\U0001F486\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F486\U0001F3FC\u200D\u2642", 1}, +{"\U0001F486\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F486\U0001F3FD\u200D\u2642", 1}, +{"\U0001F486\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F486\U0001F3FE\u200D\u2642", 1}, +{"\U0001F486\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F486\U0001F3FF\u200D\u2642", 1}, +{"\U0001F486\u200D\u2640\uFE0F", 1}, +{"\U0001F486\u200D\u2640", 1}, +{"\U0001F486\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F486\U0001F3FB\u200D\u2640", 1}, +{"\U0001F486\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F486\U0001F3FC\u200D\u2640", 1}, +{"\U0001F486\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F486\U0001F3FD\u200D\u2640", 1}, +{"\U0001F486\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F486\U0001F3FE\u200D\u2640", 1}, +{"\U0001F486\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F486\U0001F3FF\u200D\u2640", 1}, +{"\U0001F487\U0001F3FB", 1}, +{"\U0001F487\U0001F3FC", 1}, +{"\U0001F487\U0001F3FD", 1}, +{"\U0001F487\U0001F3FE", 1}, +{"\U0001F487\U0001F3FF", 1}, +{"\U0001F487\u200D\u2642\uFE0F", 1}, +{"\U0001F487\u200D\u2642", 1}, +{"\U0001F487\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F487\U0001F3FB\u200D\u2642", 1}, +{"\U0001F487\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F487\U0001F3FC\u200D\u2642", 1}, +{"\U0001F487\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F487\U0001F3FD\u200D\u2642", 1}, +{"\U0001F487\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F487\U0001F3FE\u200D\u2642", 1}, +{"\U0001F487\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F487\U0001F3FF\u200D\u2642", 1}, +{"\U0001F487\u200D\u2640\uFE0F", 1}, +{"\U0001F487\u200D\u2640", 1}, +{"\U0001F487\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F487\U0001F3FB\u200D\u2640", 1}, +{"\U0001F487\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F487\U0001F3FC\u200D\u2640", 1}, +{"\U0001F487\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F487\U0001F3FD\u200D\u2640", 1}, +{"\U0001F487\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F487\U0001F3FE\u200D\u2640", 1}, +{"\U0001F487\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F487\U0001F3FF\u200D\u2640", 1}, +{"\U0001F6B6\U0001F3FB", 1}, +{"\U0001F6B6\U0001F3FC", 1}, +{"\U0001F6B6\U0001F3FD", 1}, +{"\U0001F6B6\U0001F3FE", 1}, +{"\U0001F6B6\U0001F3FF", 1}, +{"\U0001F6B6\u200D\u2642\uFE0F", 1}, +{"\U0001F6B6\u200D\u2642", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2642", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2642", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2642", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2642", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2642", 1}, +{"\U0001F6B6\u200D\u2640\uFE0F", 1}, +{"\U0001F6B6\u200D\u2640", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2640", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2640", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2640", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2640", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2640", 1}, +{"\U0001F6B6\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u27A1", 1}, +{"\U0001F6B6\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F6B6\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FB\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FC\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FD\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FE\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F6B6\U0001F3FF\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F9CD\U0001F3FB", 1}, +{"\U0001F9CD\U0001F3FC", 1}, +{"\U0001F9CD\U0001F3FD", 1}, +{"\U0001F9CD\U0001F3FE", 1}, +{"\U0001F9CD\U0001F3FF", 1}, +{"\U0001F9CD\u200D\u2642\uFE0F", 1}, +{"\U0001F9CD\u200D\u2642", 1}, +{"\U0001F9CD\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9CD\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9CD\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9CD\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9CD\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9CD\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9CD\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9CD\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9CD\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9CD\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9CD\u200D\u2640\uFE0F", 1}, +{"\U0001F9CD\u200D\u2640", 1}, +{"\U0001F9CD\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9CD\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9CD\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9CD\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9CD\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9CD\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9CD\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9CD\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9CD\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9CD\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9CE\U0001F3FB", 1}, +{"\U0001F9CE\U0001F3FC", 1}, +{"\U0001F9CE\U0001F3FD", 1}, +{"\U0001F9CE\U0001F3FE", 1}, +{"\U0001F9CE\U0001F3FF", 1}, +{"\U0001F9CE\u200D\u2642\uFE0F", 1}, +{"\U0001F9CE\u200D\u2642", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9CE\u200D\u2640\uFE0F", 1}, +{"\U0001F9CE\u200D\u2640", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9CE\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u27A1", 1}, +{"\U0001F9CE\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F9CE\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FB\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FC\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FD\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FE\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F9CE\U0001F3FF\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F9D1\u200D\U0001F9AF", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9AF", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9AF", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9AF", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9AF", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9AF", 1}, +{"\U0001F9D1\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F468\u200D\U0001F9AF", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9AF", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9AF", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9AF", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9AF", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9AF", 1}, +{"\U0001F468\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F469\u200D\U0001F9AF", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9AF", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9AF", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9AF", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9AF", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9AF", 1}, +{"\U0001F469\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9AF\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9AF\u200D\u27A1", 1}, +{"\U0001F9D1\u200D\U0001F9BC", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9BC", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9BC", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9BC", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9BC", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9BC", 1}, +{"\U0001F9D1\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F468\u200D\U0001F9BC", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9BC", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9BC", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9BC", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9BC", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9BC", 1}, +{"\U0001F468\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F469\u200D\U0001F9BC", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9BC", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9BC", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9BC", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9BC", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9BC", 1}, +{"\U0001F469\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9BC\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9BC\u200D\u27A1", 1}, +{"\U0001F9D1\u200D\U0001F9BD", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9BD", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9BD", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9BD", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9BD", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9BD", 1}, +{"\U0001F9D1\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F468\u200D\U0001F9BD", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9BD", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9BD", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9BD", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9BD", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9BD", 1}, +{"\U0001F468\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F469\u200D\U0001F9BD", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9BD", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9BD", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9BD", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9BD", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9BD", 1}, +{"\U0001F469\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9BD\u200D\u27A1\uFE0F", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F9BD\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FB", 1}, +{"\U0001F3C3\U0001F3FC", 1}, +{"\U0001F3C3\U0001F3FD", 1}, +{"\U0001F3C3\U0001F3FE", 1}, +{"\U0001F3C3\U0001F3FF", 1}, +{"\U0001F3C3\u200D\u2642\uFE0F", 1}, +{"\U0001F3C3\u200D\u2642", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2642", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2642", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2642", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2642", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2642", 1}, +{"\U0001F3C3\u200D\u2640\uFE0F", 1}, +{"\U0001F3C3\u200D\u2640", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2640", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2640", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2640", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2640", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2640", 1}, +{"\U0001F3C3\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u27A1", 1}, +{"\U0001F3C3\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2640\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2640\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2640\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2640\u200D\u27A1", 1}, +{"\U0001F3C3\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FB\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FC\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FD\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FE\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2642\uFE0F\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2642\u200D\u27A1\uFE0F", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2642\uFE0F\u200D\u27A1", 1}, +{"\U0001F3C3\U0001F3FF\u200D\u2642\u200D\u27A1", 1}, +{"\U0001F483\U0001F3FB", 1}, +{"\U0001F483\U0001F3FC", 1}, +{"\U0001F483\U0001F3FD", 1}, +{"\U0001F483\U0001F3FE", 1}, +{"\U0001F483\U0001F3FF", 1}, +{"\U0001F57A\U0001F3FB", 1}, +{"\U0001F57A\U0001F3FC", 1}, +{"\U0001F57A\U0001F3FD", 1}, +{"\U0001F57A\U0001F3FE", 1}, +{"\U0001F57A\U0001F3FF", 1}, +{"\U0001F574\uFE0F", 1}, +{"\U0001F574\U0001F3FB", 1}, +{"\U0001F574\U0001F3FC", 1}, +{"\U0001F574\U0001F3FD", 1}, +{"\U0001F574\U0001F3FE", 1}, +{"\U0001F574\U0001F3FF", 1}, +{"\U0001F46F\u200D\u2642\uFE0F", 1}, +{"\U0001F46F\u200D\u2642", 1}, +{"\U0001F46F\u200D\u2640\uFE0F", 1}, +{"\U0001F46F\u200D\u2640", 1}, +{"\U0001F9D6\U0001F3FB", 1}, +{"\U0001F9D6\U0001F3FC", 1}, +{"\U0001F9D6\U0001F3FD", 1}, +{"\U0001F9D6\U0001F3FE", 1}, +{"\U0001F9D6\U0001F3FF", 1}, +{"\U0001F9D6\u200D\u2642\uFE0F", 1}, +{"\U0001F9D6\u200D\u2642", 1}, +{"\U0001F9D6\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9D6\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9D6\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9D6\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9D6\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9D6\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9D6\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9D6\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9D6\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9D6\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9D6\u200D\u2640\uFE0F", 1}, +{"\U0001F9D6\u200D\u2640", 1}, +{"\U0001F9D6\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9D6\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9D6\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9D6\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9D6\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9D6\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9D6\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9D6\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9D6\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9D6\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9D7\U0001F3FB", 1}, +{"\U0001F9D7\U0001F3FC", 1}, +{"\U0001F9D7\U0001F3FD", 1}, +{"\U0001F9D7\U0001F3FE", 1}, +{"\U0001F9D7\U0001F3FF", 1}, +{"\U0001F9D7\u200D\u2642\uFE0F", 1}, +{"\U0001F9D7\u200D\u2642", 1}, +{"\U0001F9D7\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9D7\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9D7\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9D7\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9D7\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9D7\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9D7\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9D7\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9D7\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9D7\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9D7\u200D\u2640\uFE0F", 1}, +{"\U0001F9D7\u200D\u2640", 1}, +{"\U0001F9D7\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9D7\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9D7\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9D7\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9D7\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9D7\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9D7\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9D7\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9D7\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9D7\U0001F3FF\u200D\u2640", 1}, +{"\U0001F3C7\U0001F3FB", 1}, +{"\U0001F3C7\U0001F3FC", 1}, +{"\U0001F3C7\U0001F3FD", 1}, +{"\U0001F3C7\U0001F3FE", 1}, +{"\U0001F3C7\U0001F3FF", 1}, +{"\u26F7\uFE0F", 1}, +{"\U0001F3C2\U0001F3FB", 1}, +{"\U0001F3C2\U0001F3FC", 1}, +{"\U0001F3C2\U0001F3FD", 1}, +{"\U0001F3C2\U0001F3FE", 1}, +{"\U0001F3C2\U0001F3FF", 1}, +{"\U0001F3CC\uFE0F", 1}, +{"\U0001F3CC\U0001F3FB", 1}, +{"\U0001F3CC\U0001F3FC", 1}, +{"\U0001F3CC\U0001F3FD", 1}, +{"\U0001F3CC\U0001F3FE", 1}, +{"\U0001F3CC\U0001F3FF", 1}, +{"\U0001F3CC\uFE0F\u200D\u2642\uFE0F", 1}, +{"\U0001F3CC\u200D\u2642\uFE0F", 1}, +{"\U0001F3CC\uFE0F\u200D\u2642", 1}, +{"\U0001F3CC\u200D\u2642", 1}, +{"\U0001F3CC\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F3CC\U0001F3FB\u200D\u2642", 1}, +{"\U0001F3CC\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F3CC\U0001F3FC\u200D\u2642", 1}, +{"\U0001F3CC\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F3CC\U0001F3FD\u200D\u2642", 1}, +{"\U0001F3CC\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F3CC\U0001F3FE\u200D\u2642", 1}, +{"\U0001F3CC\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F3CC\U0001F3FF\u200D\u2642", 1}, +{"\U0001F3CC\uFE0F\u200D\u2640\uFE0F", 1}, +{"\U0001F3CC\u200D\u2640\uFE0F", 1}, +{"\U0001F3CC\uFE0F\u200D\u2640", 1}, +{"\U0001F3CC\u200D\u2640", 1}, +{"\U0001F3CC\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F3CC\U0001F3FB\u200D\u2640", 1}, +{"\U0001F3CC\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F3CC\U0001F3FC\u200D\u2640", 1}, +{"\U0001F3CC\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F3CC\U0001F3FD\u200D\u2640", 1}, +{"\U0001F3CC\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F3CC\U0001F3FE\u200D\u2640", 1}, +{"\U0001F3CC\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F3CC\U0001F3FF\u200D\u2640", 1}, +{"\U0001F3C4\U0001F3FB", 1}, +{"\U0001F3C4\U0001F3FC", 1}, +{"\U0001F3C4\U0001F3FD", 1}, +{"\U0001F3C4\U0001F3FE", 1}, +{"\U0001F3C4\U0001F3FF", 1}, +{"\U0001F3C4\u200D\u2642\uFE0F", 1}, +{"\U0001F3C4\u200D\u2642", 1}, +{"\U0001F3C4\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F3C4\U0001F3FB\u200D\u2642", 1}, +{"\U0001F3C4\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F3C4\U0001F3FC\u200D\u2642", 1}, +{"\U0001F3C4\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F3C4\U0001F3FD\u200D\u2642", 1}, +{"\U0001F3C4\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F3C4\U0001F3FE\u200D\u2642", 1}, +{"\U0001F3C4\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F3C4\U0001F3FF\u200D\u2642", 1}, +{"\U0001F3C4\u200D\u2640\uFE0F", 1}, +{"\U0001F3C4\u200D\u2640", 1}, +{"\U0001F3C4\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F3C4\U0001F3FB\u200D\u2640", 1}, +{"\U0001F3C4\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F3C4\U0001F3FC\u200D\u2640", 1}, +{"\U0001F3C4\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F3C4\U0001F3FD\u200D\u2640", 1}, +{"\U0001F3C4\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F3C4\U0001F3FE\u200D\u2640", 1}, +{"\U0001F3C4\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F3C4\U0001F3FF\u200D\u2640", 1}, +{"\U0001F6A3\U0001F3FB", 1}, +{"\U0001F6A3\U0001F3FC", 1}, +{"\U0001F6A3\U0001F3FD", 1}, +{"\U0001F6A3\U0001F3FE", 1}, +{"\U0001F6A3\U0001F3FF", 1}, +{"\U0001F6A3\u200D\u2642\uFE0F", 1}, +{"\U0001F6A3\u200D\u2642", 1}, +{"\U0001F6A3\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F6A3\U0001F3FB\u200D\u2642", 1}, +{"\U0001F6A3\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F6A3\U0001F3FC\u200D\u2642", 1}, +{"\U0001F6A3\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F6A3\U0001F3FD\u200D\u2642", 1}, +{"\U0001F6A3\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F6A3\U0001F3FE\u200D\u2642", 1}, +{"\U0001F6A3\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F6A3\U0001F3FF\u200D\u2642", 1}, +{"\U0001F6A3\u200D\u2640\uFE0F", 1}, +{"\U0001F6A3\u200D\u2640", 1}, +{"\U0001F6A3\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F6A3\U0001F3FB\u200D\u2640", 1}, +{"\U0001F6A3\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F6A3\U0001F3FC\u200D\u2640", 1}, +{"\U0001F6A3\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F6A3\U0001F3FD\u200D\u2640", 1}, +{"\U0001F6A3\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F6A3\U0001F3FE\u200D\u2640", 1}, +{"\U0001F6A3\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F6A3\U0001F3FF\u200D\u2640", 1}, +{"\U0001F3CA\U0001F3FB", 1}, +{"\U0001F3CA\U0001F3FC", 1}, +{"\U0001F3CA\U0001F3FD", 1}, +{"\U0001F3CA\U0001F3FE", 1}, +{"\U0001F3CA\U0001F3FF", 1}, +{"\U0001F3CA\u200D\u2642\uFE0F", 1}, +{"\U0001F3CA\u200D\u2642", 1}, +{"\U0001F3CA\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F3CA\U0001F3FB\u200D\u2642", 1}, +{"\U0001F3CA\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F3CA\U0001F3FC\u200D\u2642", 1}, +{"\U0001F3CA\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F3CA\U0001F3FD\u200D\u2642", 1}, +{"\U0001F3CA\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F3CA\U0001F3FE\u200D\u2642", 1}, +{"\U0001F3CA\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F3CA\U0001F3FF\u200D\u2642", 1}, +{"\U0001F3CA\u200D\u2640\uFE0F", 1}, +{"\U0001F3CA\u200D\u2640", 1}, +{"\U0001F3CA\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F3CA\U0001F3FB\u200D\u2640", 1}, +{"\U0001F3CA\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F3CA\U0001F3FC\u200D\u2640", 1}, +{"\U0001F3CA\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F3CA\U0001F3FD\u200D\u2640", 1}, +{"\U0001F3CA\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F3CA\U0001F3FE\u200D\u2640", 1}, +{"\U0001F3CA\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F3CA\U0001F3FF\u200D\u2640", 1}, +{"\u26F9\uFE0F", 1}, +{"\u26F9\U0001F3FB", 1}, +{"\u26F9\U0001F3FC", 1}, +{"\u26F9\U0001F3FD", 1}, +{"\u26F9\U0001F3FE", 1}, +{"\u26F9\U0001F3FF", 1}, +{"\u26F9\uFE0F\u200D\u2642\uFE0F", 1}, +{"\u26F9\u200D\u2642\uFE0F", 1}, +{"\u26F9\uFE0F\u200D\u2642", 1}, +{"\u26F9\u200D\u2642", 1}, +{"\u26F9\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\u26F9\U0001F3FB\u200D\u2642", 1}, +{"\u26F9\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\u26F9\U0001F3FC\u200D\u2642", 1}, +{"\u26F9\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\u26F9\U0001F3FD\u200D\u2642", 1}, +{"\u26F9\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\u26F9\U0001F3FE\u200D\u2642", 1}, +{"\u26F9\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\u26F9\U0001F3FF\u200D\u2642", 1}, +{"\u26F9\uFE0F\u200D\u2640\uFE0F", 1}, +{"\u26F9\u200D\u2640\uFE0F", 1}, +{"\u26F9\uFE0F\u200D\u2640", 1}, +{"\u26F9\u200D\u2640", 1}, +{"\u26F9\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\u26F9\U0001F3FB\u200D\u2640", 1}, +{"\u26F9\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\u26F9\U0001F3FC\u200D\u2640", 1}, +{"\u26F9\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\u26F9\U0001F3FD\u200D\u2640", 1}, +{"\u26F9\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\u26F9\U0001F3FE\u200D\u2640", 1}, +{"\u26F9\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\u26F9\U0001F3FF\u200D\u2640", 1}, +{"\U0001F3CB\uFE0F", 1}, +{"\U0001F3CB\U0001F3FB", 1}, +{"\U0001F3CB\U0001F3FC", 1}, +{"\U0001F3CB\U0001F3FD", 1}, +{"\U0001F3CB\U0001F3FE", 1}, +{"\U0001F3CB\U0001F3FF", 1}, +{"\U0001F3CB\uFE0F\u200D\u2642\uFE0F", 1}, +{"\U0001F3CB\u200D\u2642\uFE0F", 1}, +{"\U0001F3CB\uFE0F\u200D\u2642", 1}, +{"\U0001F3CB\u200D\u2642", 1}, +{"\U0001F3CB\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F3CB\U0001F3FB\u200D\u2642", 1}, +{"\U0001F3CB\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F3CB\U0001F3FC\u200D\u2642", 1}, +{"\U0001F3CB\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F3CB\U0001F3FD\u200D\u2642", 1}, +{"\U0001F3CB\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F3CB\U0001F3FE\u200D\u2642", 1}, +{"\U0001F3CB\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F3CB\U0001F3FF\u200D\u2642", 1}, +{"\U0001F3CB\uFE0F\u200D\u2640\uFE0F", 1}, +{"\U0001F3CB\u200D\u2640\uFE0F", 1}, +{"\U0001F3CB\uFE0F\u200D\u2640", 1}, +{"\U0001F3CB\u200D\u2640", 1}, +{"\U0001F3CB\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F3CB\U0001F3FB\u200D\u2640", 1}, +{"\U0001F3CB\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F3CB\U0001F3FC\u200D\u2640", 1}, +{"\U0001F3CB\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F3CB\U0001F3FD\u200D\u2640", 1}, +{"\U0001F3CB\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F3CB\U0001F3FE\u200D\u2640", 1}, +{"\U0001F3CB\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F3CB\U0001F3FF\u200D\u2640", 1}, +{"\U0001F6B4\U0001F3FB", 1}, +{"\U0001F6B4\U0001F3FC", 1}, +{"\U0001F6B4\U0001F3FD", 1}, +{"\U0001F6B4\U0001F3FE", 1}, +{"\U0001F6B4\U0001F3FF", 1}, +{"\U0001F6B4\u200D\u2642\uFE0F", 1}, +{"\U0001F6B4\u200D\u2642", 1}, +{"\U0001F6B4\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F6B4\U0001F3FB\u200D\u2642", 1}, +{"\U0001F6B4\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F6B4\U0001F3FC\u200D\u2642", 1}, +{"\U0001F6B4\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F6B4\U0001F3FD\u200D\u2642", 1}, +{"\U0001F6B4\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F6B4\U0001F3FE\u200D\u2642", 1}, +{"\U0001F6B4\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F6B4\U0001F3FF\u200D\u2642", 1}, +{"\U0001F6B4\u200D\u2640\uFE0F", 1}, +{"\U0001F6B4\u200D\u2640", 1}, +{"\U0001F6B4\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F6B4\U0001F3FB\u200D\u2640", 1}, +{"\U0001F6B4\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F6B4\U0001F3FC\u200D\u2640", 1}, +{"\U0001F6B4\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F6B4\U0001F3FD\u200D\u2640", 1}, +{"\U0001F6B4\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F6B4\U0001F3FE\u200D\u2640", 1}, +{"\U0001F6B4\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F6B4\U0001F3FF\u200D\u2640", 1}, +{"\U0001F6B5\U0001F3FB", 1}, +{"\U0001F6B5\U0001F3FC", 1}, +{"\U0001F6B5\U0001F3FD", 1}, +{"\U0001F6B5\U0001F3FE", 1}, +{"\U0001F6B5\U0001F3FF", 1}, +{"\U0001F6B5\u200D\u2642\uFE0F", 1}, +{"\U0001F6B5\u200D\u2642", 1}, +{"\U0001F6B5\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F6B5\U0001F3FB\u200D\u2642", 1}, +{"\U0001F6B5\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F6B5\U0001F3FC\u200D\u2642", 1}, +{"\U0001F6B5\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F6B5\U0001F3FD\u200D\u2642", 1}, +{"\U0001F6B5\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F6B5\U0001F3FE\u200D\u2642", 1}, +{"\U0001F6B5\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F6B5\U0001F3FF\u200D\u2642", 1}, +{"\U0001F6B5\u200D\u2640\uFE0F", 1}, +{"\U0001F6B5\u200D\u2640", 1}, +{"\U0001F6B5\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F6B5\U0001F3FB\u200D\u2640", 1}, +{"\U0001F6B5\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F6B5\U0001F3FC\u200D\u2640", 1}, +{"\U0001F6B5\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F6B5\U0001F3FD\u200D\u2640", 1}, +{"\U0001F6B5\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F6B5\U0001F3FE\u200D\u2640", 1}, +{"\U0001F6B5\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F6B5\U0001F3FF\u200D\u2640", 1}, +{"\U0001F938\U0001F3FB", 1}, +{"\U0001F938\U0001F3FC", 1}, +{"\U0001F938\U0001F3FD", 1}, +{"\U0001F938\U0001F3FE", 1}, +{"\U0001F938\U0001F3FF", 1}, +{"\U0001F938\u200D\u2642\uFE0F", 1}, +{"\U0001F938\u200D\u2642", 1}, +{"\U0001F938\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F938\U0001F3FB\u200D\u2642", 1}, +{"\U0001F938\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F938\U0001F3FC\u200D\u2642", 1}, +{"\U0001F938\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F938\U0001F3FD\u200D\u2642", 1}, +{"\U0001F938\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F938\U0001F3FE\u200D\u2642", 1}, +{"\U0001F938\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F938\U0001F3FF\u200D\u2642", 1}, +{"\U0001F938\u200D\u2640\uFE0F", 1}, +{"\U0001F938\u200D\u2640", 1}, +{"\U0001F938\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F938\U0001F3FB\u200D\u2640", 1}, +{"\U0001F938\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F938\U0001F3FC\u200D\u2640", 1}, +{"\U0001F938\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F938\U0001F3FD\u200D\u2640", 1}, +{"\U0001F938\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F938\U0001F3FE\u200D\u2640", 1}, +{"\U0001F938\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F938\U0001F3FF\u200D\u2640", 1}, +{"\U0001F93C\u200D\u2642\uFE0F", 1}, +{"\U0001F93C\u200D\u2642", 1}, +{"\U0001F93C\u200D\u2640\uFE0F", 1}, +{"\U0001F93C\u200D\u2640", 1}, +{"\U0001F93D\U0001F3FB", 1}, +{"\U0001F93D\U0001F3FC", 1}, +{"\U0001F93D\U0001F3FD", 1}, +{"\U0001F93D\U0001F3FE", 1}, +{"\U0001F93D\U0001F3FF", 1}, +{"\U0001F93D\u200D\u2642\uFE0F", 1}, +{"\U0001F93D\u200D\u2642", 1}, +{"\U0001F93D\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F93D\U0001F3FB\u200D\u2642", 1}, +{"\U0001F93D\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F93D\U0001F3FC\u200D\u2642", 1}, +{"\U0001F93D\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F93D\U0001F3FD\u200D\u2642", 1}, +{"\U0001F93D\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F93D\U0001F3FE\u200D\u2642", 1}, +{"\U0001F93D\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F93D\U0001F3FF\u200D\u2642", 1}, +{"\U0001F93D\u200D\u2640\uFE0F", 1}, +{"\U0001F93D\u200D\u2640", 1}, +{"\U0001F93D\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F93D\U0001F3FB\u200D\u2640", 1}, +{"\U0001F93D\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F93D\U0001F3FC\u200D\u2640", 1}, +{"\U0001F93D\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F93D\U0001F3FD\u200D\u2640", 1}, +{"\U0001F93D\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F93D\U0001F3FE\u200D\u2640", 1}, +{"\U0001F93D\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F93D\U0001F3FF\u200D\u2640", 1}, +{"\U0001F93E\U0001F3FB", 1}, +{"\U0001F93E\U0001F3FC", 1}, +{"\U0001F93E\U0001F3FD", 1}, +{"\U0001F93E\U0001F3FE", 1}, +{"\U0001F93E\U0001F3FF", 1}, +{"\U0001F93E\u200D\u2642\uFE0F", 1}, +{"\U0001F93E\u200D\u2642", 1}, +{"\U0001F93E\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F93E\U0001F3FB\u200D\u2642", 1}, +{"\U0001F93E\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F93E\U0001F3FC\u200D\u2642", 1}, +{"\U0001F93E\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F93E\U0001F3FD\u200D\u2642", 1}, +{"\U0001F93E\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F93E\U0001F3FE\u200D\u2642", 1}, +{"\U0001F93E\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F93E\U0001F3FF\u200D\u2642", 1}, +{"\U0001F93E\u200D\u2640\uFE0F", 1}, +{"\U0001F93E\u200D\u2640", 1}, +{"\U0001F93E\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F93E\U0001F3FB\u200D\u2640", 1}, +{"\U0001F93E\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F93E\U0001F3FC\u200D\u2640", 1}, +{"\U0001F93E\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F93E\U0001F3FD\u200D\u2640", 1}, +{"\U0001F93E\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F93E\U0001F3FE\u200D\u2640", 1}, +{"\U0001F93E\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F93E\U0001F3FF\u200D\u2640", 1}, +{"\U0001F939\U0001F3FB", 1}, +{"\U0001F939\U0001F3FC", 1}, +{"\U0001F939\U0001F3FD", 1}, +{"\U0001F939\U0001F3FE", 1}, +{"\U0001F939\U0001F3FF", 1}, +{"\U0001F939\u200D\u2642\uFE0F", 1}, +{"\U0001F939\u200D\u2642", 1}, +{"\U0001F939\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F939\U0001F3FB\u200D\u2642", 1}, +{"\U0001F939\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F939\U0001F3FC\u200D\u2642", 1}, +{"\U0001F939\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F939\U0001F3FD\u200D\u2642", 1}, +{"\U0001F939\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F939\U0001F3FE\u200D\u2642", 1}, +{"\U0001F939\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F939\U0001F3FF\u200D\u2642", 1}, +{"\U0001F939\u200D\u2640\uFE0F", 1}, +{"\U0001F939\u200D\u2640", 1}, +{"\U0001F939\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F939\U0001F3FB\u200D\u2640", 1}, +{"\U0001F939\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F939\U0001F3FC\u200D\u2640", 1}, +{"\U0001F939\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F939\U0001F3FD\u200D\u2640", 1}, +{"\U0001F939\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F939\U0001F3FE\u200D\u2640", 1}, +{"\U0001F939\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F939\U0001F3FF\u200D\u2640", 1}, +{"\U0001F9D8\U0001F3FB", 1}, +{"\U0001F9D8\U0001F3FC", 1}, +{"\U0001F9D8\U0001F3FD", 1}, +{"\U0001F9D8\U0001F3FE", 1}, +{"\U0001F9D8\U0001F3FF", 1}, +{"\U0001F9D8\u200D\u2642\uFE0F", 1}, +{"\U0001F9D8\u200D\u2642", 1}, +{"\U0001F9D8\U0001F3FB\u200D\u2642\uFE0F", 1}, +{"\U0001F9D8\U0001F3FB\u200D\u2642", 1}, +{"\U0001F9D8\U0001F3FC\u200D\u2642\uFE0F", 1}, +{"\U0001F9D8\U0001F3FC\u200D\u2642", 1}, +{"\U0001F9D8\U0001F3FD\u200D\u2642\uFE0F", 1}, +{"\U0001F9D8\U0001F3FD\u200D\u2642", 1}, +{"\U0001F9D8\U0001F3FE\u200D\u2642\uFE0F", 1}, +{"\U0001F9D8\U0001F3FE\u200D\u2642", 1}, +{"\U0001F9D8\U0001F3FF\u200D\u2642\uFE0F", 1}, +{"\U0001F9D8\U0001F3FF\u200D\u2642", 1}, +{"\U0001F9D8\u200D\u2640\uFE0F", 1}, +{"\U0001F9D8\u200D\u2640", 1}, +{"\U0001F9D8\U0001F3FB\u200D\u2640\uFE0F", 1}, +{"\U0001F9D8\U0001F3FB\u200D\u2640", 1}, +{"\U0001F9D8\U0001F3FC\u200D\u2640\uFE0F", 1}, +{"\U0001F9D8\U0001F3FC\u200D\u2640", 1}, +{"\U0001F9D8\U0001F3FD\u200D\u2640\uFE0F", 1}, +{"\U0001F9D8\U0001F3FD\u200D\u2640", 1}, +{"\U0001F9D8\U0001F3FE\u200D\u2640\uFE0F", 1}, +{"\U0001F9D8\U0001F3FE\u200D\u2640", 1}, +{"\U0001F9D8\U0001F3FF\u200D\u2640\uFE0F", 1}, +{"\U0001F9D8\U0001F3FF\u200D\u2640", 1}, +{"\U0001F6C0\U0001F3FB", 1}, +{"\U0001F6C0\U0001F3FC", 1}, +{"\U0001F6C0\U0001F3FD", 1}, +{"\U0001F6C0\U0001F3FE", 1}, +{"\U0001F6C0\U0001F3FF", 1}, +{"\U0001F6CC\U0001F3FB", 1}, +{"\U0001F6CC\U0001F3FC", 1}, +{"\U0001F6CC\U0001F3FD", 1}, +{"\U0001F6CC\U0001F3FE", 1}, +{"\U0001F6CC\U0001F3FF", 1}, +{"\U0001F9D1\u200D\U0001F91D\u200D\U0001F9D1", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FB\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FC\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FD\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FE\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FF\u200D\U0001F91D\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F46D\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F46D\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F46D\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F46D\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F46D\U0001F3FF", 1}, +{"\U0001F46B\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F46B\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F46B\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F46B\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F46B\U0001F3FF", 1}, +{"\U0001F46C\U0001F3FB", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FB\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F46C\U0001F3FC", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FC\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F46C\U0001F3FD", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FD\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F46C\U0001F3FE", 1}, +{"\U0001F468\U0001F3FE\u200D\U0001F91D\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FF\u200D\U0001F91D\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F46C\U0001F3FF", 1}, +{"\U0001F48F\U0001F3FB", 1}, +{"\U0001F48F\U0001F3FC", 1}, +{"\U0001F48F\U0001F3FD", 1}, +{"\U0001F48F\U0001F3FE", 1}, +{"\U0001F48F\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F469\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468", 1}, +{"\U0001F469\u200D\u2764\u200D\U0001F48B\u200D\U0001F468", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468", 1}, +{"\U0001F468\u200D\u2764\u200D\U0001F48B\u200D\U0001F468", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469", 1}, +{"\U0001F469\u200D\u2764\u200D\U0001F48B\u200D\U0001F469", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F48B\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F491\U0001F3FB", 1}, +{"\U0001F491\U0001F3FC", 1}, +{"\U0001F491\U0001F3FD", 1}, +{"\U0001F491\U0001F3FE", 1}, +{"\U0001F491\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FB\u200D\u2764\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FC\u200D\u2764\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FD\u200D\u2764\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FE\u200D\u2764\u200D\U0001F9D1\U0001F3FF", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F9D1\U0001F3FB", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F9D1\U0001F3FC", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F9D1\U0001F3FD", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F9D1\U0001F3FF\u200D\u2764\u200D\U0001F9D1\U0001F3FE", 1}, +{"\U0001F469\u200D\u2764\uFE0F\u200D\U0001F468", 1}, +{"\U0001F469\u200D\u2764\u200D\U0001F468", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\u200D\u2764\uFE0F\u200D\U0001F468", 1}, +{"\U0001F468\u200D\u2764\u200D\U0001F468", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FB\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FC\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FD\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FE\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FB", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FC", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FD", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FE", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F468\U0001F3FF\u200D\u2764\u200D\U0001F468\U0001F3FF", 1}, +{"\U0001F469\u200D\u2764\uFE0F\u200D\U0001F469", 1}, +{"\U0001F469\u200D\u2764\u200D\U0001F469", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FB\u200D\u2764\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FC\u200D\u2764\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FD\u200D\u2764\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FE\u200D\u2764\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F469\U0001F3FB", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F469\U0001F3FC", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F469\U0001F3FD", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F469\U0001F3FE", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\uFE0F\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F469\U0001F3FF\u200D\u2764\u200D\U0001F469\U0001F3FF", 1}, +{"\U0001F468\u200D\U0001F469\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F469\u200D\U0001F467", 1}, +{"\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F469\u200D\U0001F466\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F467", 1}, +{"\U0001F468\u200D\U0001F468\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F468\u200D\U0001F467", 1}, +{"\U0001F468\u200D\U0001F468\u200D\U0001F467\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F468\u200D\U0001F466\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F468\u200D\U0001F467\u200D\U0001F467", 1}, +{"\U0001F469\u200D\U0001F469\u200D\U0001F466", 1}, +{"\U0001F469\u200D\U0001F469\u200D\U0001F467", 1}, +{"\U0001F469\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466", 1}, +{"\U0001F469\u200D\U0001F469\u200D\U0001F466\u200D\U0001F466", 1}, +{"\U0001F469\u200D\U0001F469\u200D\U0001F467\u200D\U0001F467", 1}, +{"\U0001F468\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F466\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F467", 1}, +{"\U0001F468\u200D\U0001F467\u200D\U0001F466", 1}, +{"\U0001F468\u200D\U0001F467\u200D\U0001F467", 1}, +{"\U0001F469\u200D\U0001F466", 1}, +{"\U0001F469\u200D\U0001F466\u200D\U0001F466", 1}, +{"\U0001F469\u200D\U0001F467", 1}, +{"\U0001F469\u200D\U0001F467\u200D\U0001F466", 1}, +{"\U0001F469\u200D\U0001F467\u200D\U0001F467", 1}, +{"\U0001F5E3\uFE0F", 1}, +{"\U0001F9D1\u200D\U0001F9D1\u200D\U0001F9D2", 1}, +{"\U0001F9D1\u200D\U0001F9D1\u200D\U0001F9D2\u200D\U0001F9D2", 1}, +{"\U0001F9D1\u200D\U0001F9D2", 1}, +{"\U0001F9D1\u200D\U0001F9D2\u200D\U0001F9D2", 1}, +{"\U0001F415\u200D\U0001F9BA", 1}, +{"\U0001F408\u200D\u2B1B", 1}, +{"\U0001F43F\uFE0F", 1}, +{"\U0001F43B\u200D\u2744\uFE0F", 1}, +{"\U0001F43B\u200D\u2744", 1}, +{"\U0001F54A\uFE0F", 1}, +{"\U0001F426\u200D\u2B1B", 1}, +{"\U0001F426\u200D\U0001F525", 1}, +{"\U0001F577\uFE0F", 1}, +{"\U0001F578\uFE0F", 1}, +{"\U0001F3F5\uFE0F", 1}, +{"\u2618\uFE0F", 1}, +{"\U0001F34B\u200D\U0001F7E9", 1}, +{"\U0001F336\uFE0F", 1}, +{"\U0001F344\u200D\U0001F7EB", 1}, +{"\U0001F37D\uFE0F", 1}, +{"\U0001F5FA\uFE0F", 1}, +{"\U0001F3D4\uFE0F", 1}, +{"\u26F0\uFE0F", 1}, +{"\U0001F3D5\uFE0F", 1}, +{"\U0001F3D6\uFE0F", 1}, +{"\U0001F3DC\uFE0F", 1}, +{"\U0001F3DD\uFE0F", 1}, +{"\U0001F3DE\uFE0F", 1}, +{"\U0001F3DF\uFE0F", 1}, +{"\U0001F3DB\uFE0F", 1}, +{"\U0001F3D7\uFE0F", 1}, +{"\U0001F3D8\uFE0F", 1}, +{"\U0001F3DA\uFE0F", 1}, +{"\u26E9\uFE0F", 1}, +{"\U0001F3D9\uFE0F", 1}, +{"\u2668\uFE0F", 1}, +{"\U0001F3CE\uFE0F", 1}, +{"\U0001F3CD\uFE0F", 1}, +{"\U0001F6E3\uFE0F", 1}, +{"\U0001F6E4\uFE0F", 1}, +{"\U0001F6E2\uFE0F", 1}, +{"\U0001F6F3\uFE0F", 1}, +{"\u26F4\uFE0F", 1}, +{"\U0001F6E5\uFE0F", 1}, +{"\u2708\uFE0F", 1}, +{"\U0001F6E9\uFE0F", 1}, +{"\U0001F6F0\uFE0F", 1}, +{"\U0001F6CE\uFE0F", 1}, +{"\u23F1\uFE0F", 1}, +{"\u23F2\uFE0F", 1}, +{"\U0001F570\uFE0F", 1}, +{"\U0001F321\uFE0F", 1}, +{"\u2600\uFE0F", 1}, +{"\u2601\uFE0F", 1}, +{"\u26C8\uFE0F", 1}, +{"\U0001F324\uFE0F", 1}, +{"\U0001F325\uFE0F", 1}, +{"\U0001F326\uFE0F", 1}, +{"\U0001F327\uFE0F", 1}, +{"\U0001F328\uFE0F", 1}, +{"\U0001F329\uFE0F", 1}, +{"\U0001F32A\uFE0F", 1}, +{"\U0001F32B\uFE0F", 1}, +{"\U0001F32C\uFE0F", 1}, +{"\u2602\uFE0F", 1}, +{"\u26F1\uFE0F", 1}, +{"\u2744\uFE0F", 1}, +{"\u2603\uFE0F", 1}, +{"\u2604\uFE0F", 1}, +{"\U0001F397\uFE0F", 1}, +{"\U0001F39F\uFE0F", 1}, +{"\U0001F396\uFE0F", 1}, +{"\u26F8\uFE0F", 1}, +{"\U0001F579\uFE0F", 1}, +{"\u2660\uFE0F", 1}, +{"\u2665\uFE0F", 1}, +{"\u2666\uFE0F", 1}, +{"\u2663\uFE0F", 1}, +{"\u265F\uFE0F", 1}, +{"\U0001F5BC\uFE0F", 1}, +{"\U0001F576\uFE0F", 1}, +{"\U0001F6CD\uFE0F", 1}, +{"\u26D1\uFE0F", 1}, +{"\U0001F399\uFE0F", 1}, +{"\U0001F39A\uFE0F", 1}, +{"\U0001F39B\uFE0F", 1}, +{"\u260E\uFE0F", 1}, +{"\U0001F5A5\uFE0F", 1}, +{"\U0001F5A8\uFE0F", 1}, +{"\u2328\uFE0F", 1}, +{"\U0001F5B1\uFE0F", 1}, +{"\U0001F5B2\uFE0F", 1}, +{"\U0001F39E\uFE0F", 1}, +{"\U0001F4FD\uFE0F", 1}, +{"\U0001F56F\uFE0F", 1}, +{"\U0001F5DE\uFE0F", 1}, +{"\U0001F3F7\uFE0F", 1}, +{"\u2709\uFE0F", 1}, +{"\U0001F5F3\uFE0F", 1}, +{"\u270F\uFE0F", 1}, +{"\u2712\uFE0F", 1}, +{"\U0001F58B\uFE0F", 1}, +{"\U0001F58A\uFE0F", 1}, +{"\U0001F58C\uFE0F", 1}, +{"\U0001F58D\uFE0F", 1}, +{"\U0001F5C2\uFE0F", 1}, +{"\U0001F5D2\uFE0F", 1}, +{"\U0001F5D3\uFE0F", 1}, +{"\U0001F587\uFE0F", 1}, +{"\u2702\uFE0F", 1}, +{"\U0001F5C3\uFE0F", 1}, +{"\U0001F5C4\uFE0F", 1}, +{"\U0001F5D1\uFE0F", 1}, +{"\U0001F5DD\uFE0F", 1}, +{"\u26CF\uFE0F", 1}, +{"\u2692\uFE0F", 1}, +{"\U0001F6E0\uFE0F", 1}, +{"\U0001F5E1\uFE0F", 1}, +{"\u2694\uFE0F", 1}, +{"\U0001F6E1\uFE0F", 1}, +{"\u2699\uFE0F", 1}, +{"\U0001F5DC\uFE0F", 1}, +{"\u2696\uFE0F", 1}, +{"\u26D3\uFE0F\u200D\U0001F4A5", 1}, +{"\u26D3\u200D\U0001F4A5", 1}, +{"\u26D3\uFE0F", 1}, +{"\u2697\uFE0F", 1}, +{"\U0001F6CF\uFE0F", 1}, +{"\U0001F6CB\uFE0F", 1}, +{"\u26B0\uFE0F", 1}, +{"\u26B1\uFE0F", 1}, +{"\u26A0\uFE0F", 1}, +{"\u2622\uFE0F", 1}, +{"\u2623\uFE0F", 1}, +{"\u2B06\uFE0F", 1}, +{"\u2197\uFE0F", 1}, +{"\u27A1\uFE0F", 1}, +{"\u2198\uFE0F", 1}, +{"\u2B07\uFE0F", 1}, +{"\u2199\uFE0F", 1}, +{"\u2B05\uFE0F", 1}, +{"\u2196\uFE0F", 1}, +{"\u2195\uFE0F", 1}, +{"\u2194\uFE0F", 1}, +{"\u21A9\uFE0F", 1}, +{"\u21AA\uFE0F", 1}, +{"\u2934\uFE0F", 1}, +{"\u2935\uFE0F", 1}, +{"\u269B\uFE0F", 1}, +{"\U0001F549\uFE0F", 1}, +{"\u2721\uFE0F", 1}, +{"\u2638\uFE0F", 1}, +{"\u262F\uFE0F", 1}, +{"\u271D\uFE0F", 1}, +{"\u2626\uFE0F", 1}, +{"\u262A\uFE0F", 1}, +{"\u262E\uFE0F", 1}, +{"\u25B6\uFE0F", 1}, +{"\u23ED\uFE0F", 1}, +{"\u23EF\uFE0F", 1}, +{"\u25C0\uFE0F", 1}, +{"\u23EE\uFE0F", 1}, +{"\u23F8\uFE0F", 1}, +{"\u23F9\uFE0F", 1}, +{"\u23FA\uFE0F", 1}, +{"\u23CF\uFE0F", 1}, +{"\u2640\uFE0F", 1}, +{"\u2642\uFE0F", 1}, +{"\u26A7\uFE0F", 1}, +{"\u2716\uFE0F", 1}, +{"\u267E\uFE0F", 1}, +{"\u203C\uFE0F", 1}, +{"\u2049\uFE0F", 1}, +{"\u3030\uFE0F", 1}, +{"\u2695\uFE0F", 1}, +{"\u267B\uFE0F", 1}, +{"\u269C\uFE0F", 1}, +{"\u2611\uFE0F", 1}, +{"\u2714\uFE0F", 1}, +{"\u303D\uFE0F", 1}, +{"\u2733\uFE0F", 1}, +{"\u2734\uFE0F", 1}, +{"\u2747\uFE0F", 1}, +{"\u00A9\uFE0F", 1}, +{"\u00AE\uFE0F", 1}, +{"\u2122\uFE0F", 1}, +{"\u0023\uFE0F\u20E3", 1}, +{"\u0023\u20E3", 1}, +{"\u002A\uFE0F\u20E3", 1}, +{"\u002A\u20E3", 1}, +{"\u0030\uFE0F\u20E3", 1}, +{"\u0030\u20E3", 1}, +{"\u0031\uFE0F\u20E3", 1}, +{"\u0031\u20E3", 1}, +{"\u0032\uFE0F\u20E3", 1}, +{"\u0032\u20E3", 1}, +{"\u0033\uFE0F\u20E3", 1}, +{"\u0033\u20E3", 1}, +{"\u0034\uFE0F\u20E3", 1}, +{"\u0034\u20E3", 1}, +{"\u0035\uFE0F\u20E3", 1}, +{"\u0035\u20E3", 1}, +{"\u0036\uFE0F\u20E3", 1}, +{"\u0036\u20E3", 1}, +{"\u0037\uFE0F\u20E3", 1}, +{"\u0037\u20E3", 1}, +{"\u0038\uFE0F\u20E3", 1}, +{"\u0038\u20E3", 1}, +{"\u0039\uFE0F\u20E3", 1}, +{"\u0039\u20E3", 1}, +{"\U0001F170\uFE0F", 1}, +{"\U0001F171\uFE0F", 1}, +{"\u2139\uFE0F", 1}, +{"\u24C2\uFE0F", 1}, +{"\U0001F17E\uFE0F", 1}, +{"\U0001F17F\uFE0F", 1}, +{"\U0001F202\uFE0F", 1}, +{"\U0001F237\uFE0F", 1}, +{"\u3297\uFE0F", 1}, +{"\u3299\uFE0F", 1}, +{"\u25FC\uFE0F", 1}, +{"\u25FB\uFE0F", 1}, +{"\u25AA\uFE0F", 1}, +{"\u25AB\uFE0F", 1}, +{"\U0001F3F3\uFE0F", 1}, +{"\U0001F3F3\uFE0F\u200D\U0001F308", 1}, +{"\U0001F3F3\u200D\U0001F308", 1}, +{"\U0001F3F3\uFE0F\u200D\u26A7\uFE0F", 1}, +{"\U0001F3F3\u200D\u26A7\uFE0F", 1}, +{"\U0001F3F3\uFE0F\u200D\u26A7", 1}, +{"\U0001F3F3\u200D\u26A7", 1}, +{"\U0001F3F4\u200D\u2620\uFE0F", 1}, +{"\U0001F3F4\u200D\u2620", 1}, +{"\U0001F1E6\U0001F1E8", 1}, +{"\U0001F1E6\U0001F1E9", 1}, +{"\U0001F1E6\U0001F1EA", 1}, +{"\U0001F1E6\U0001F1EB", 1}, +{"\U0001F1E6\U0001F1EC", 1}, +{"\U0001F1E6\U0001F1EE", 1}, +{"\U0001F1E6\U0001F1F1", 1}, +{"\U0001F1E6\U0001F1F2", 1}, +{"\U0001F1E6\U0001F1F4", 1}, +{"\U0001F1E6\U0001F1F6", 1}, +{"\U0001F1E6\U0001F1F7", 1}, +{"\U0001F1E6\U0001F1F8", 1}, +{"\U0001F1E6\U0001F1F9", 1}, +{"\U0001F1E6\U0001F1FA", 1}, +{"\U0001F1E6\U0001F1FC", 1}, +{"\U0001F1E6\U0001F1FD", 1}, +{"\U0001F1E6\U0001F1FF", 1}, +{"\U0001F1E7\U0001F1E6", 1}, +{"\U0001F1E7\U0001F1E7", 1}, +{"\U0001F1E7\U0001F1E9", 1}, +{"\U0001F1E7\U0001F1EA", 1}, +{"\U0001F1E7\U0001F1EB", 1}, +{"\U0001F1E7\U0001F1EC", 1}, +{"\U0001F1E7\U0001F1ED", 1}, +{"\U0001F1E7\U0001F1EE", 1}, +{"\U0001F1E7\U0001F1EF", 1}, +{"\U0001F1E7\U0001F1F1", 1}, +{"\U0001F1E7\U0001F1F2", 1}, +{"\U0001F1E7\U0001F1F3", 1}, +{"\U0001F1E7\U0001F1F4", 1}, +{"\U0001F1E7\U0001F1F6", 1}, +{"\U0001F1E7\U0001F1F7", 1}, +{"\U0001F1E7\U0001F1F8", 1}, +{"\U0001F1E7\U0001F1F9", 1}, +{"\U0001F1E7\U0001F1FB", 1}, +{"\U0001F1E7\U0001F1FC", 1}, +{"\U0001F1E7\U0001F1FE", 1}, +{"\U0001F1E7\U0001F1FF", 1}, +{"\U0001F1E8\U0001F1E6", 1}, +{"\U0001F1E8\U0001F1E8", 1}, +{"\U0001F1E8\U0001F1E9", 1}, +{"\U0001F1E8\U0001F1EB", 1}, +{"\U0001F1E8\U0001F1EC", 1}, +{"\U0001F1E8\U0001F1ED", 1}, +{"\U0001F1E8\U0001F1EE", 1}, +{"\U0001F1E8\U0001F1F0", 1}, +{"\U0001F1E8\U0001F1F1", 1}, +{"\U0001F1E8\U0001F1F2", 1}, +{"\U0001F1E8\U0001F1F3", 1}, +{"\U0001F1E8\U0001F1F4", 1}, +{"\U0001F1E8\U0001F1F5", 1}, +{"\U0001F1E8\U0001F1F7", 1}, +{"\U0001F1E8\U0001F1FA", 1}, +{"\U0001F1E8\U0001F1FB", 1}, +{"\U0001F1E8\U0001F1FC", 1}, +{"\U0001F1E8\U0001F1FD", 1}, +{"\U0001F1E8\U0001F1FE", 1}, +{"\U0001F1E8\U0001F1FF", 1}, +{"\U0001F1E9\U0001F1EA", 1}, +{"\U0001F1E9\U0001F1EC", 1}, +{"\U0001F1E9\U0001F1EF", 1}, +{"\U0001F1E9\U0001F1F0", 1}, +{"\U0001F1E9\U0001F1F2", 1}, +{"\U0001F1E9\U0001F1F4", 1}, +{"\U0001F1E9\U0001F1FF", 1}, +{"\U0001F1EA\U0001F1E6", 1}, +{"\U0001F1EA\U0001F1E8", 1}, +{"\U0001F1EA\U0001F1EA", 1}, +{"\U0001F1EA\U0001F1EC", 1}, +{"\U0001F1EA\U0001F1ED", 1}, +{"\U0001F1EA\U0001F1F7", 1}, +{"\U0001F1EA\U0001F1F8", 1}, +{"\U0001F1EA\U0001F1F9", 1}, +{"\U0001F1EA\U0001F1FA", 1}, +{"\U0001F1EB\U0001F1EE", 1}, +{"\U0001F1EB\U0001F1EF", 1}, +{"\U0001F1EB\U0001F1F0", 1}, +{"\U0001F1EB\U0001F1F2", 1}, +{"\U0001F1EB\U0001F1F4", 1}, +{"\U0001F1EB\U0001F1F7", 1}, +{"\U0001F1EC\U0001F1E6", 1}, +{"\U0001F1EC\U0001F1E7", 1}, +{"\U0001F1EC\U0001F1E9", 1}, +{"\U0001F1EC\U0001F1EA", 1}, +{"\U0001F1EC\U0001F1EB", 1}, +{"\U0001F1EC\U0001F1EC", 1}, +{"\U0001F1EC\U0001F1ED", 1}, +{"\U0001F1EC\U0001F1EE", 1}, +{"\U0001F1EC\U0001F1F1", 1}, +{"\U0001F1EC\U0001F1F2", 1}, +{"\U0001F1EC\U0001F1F3", 1}, +{"\U0001F1EC\U0001F1F5", 1}, +{"\U0001F1EC\U0001F1F6", 1}, +{"\U0001F1EC\U0001F1F7", 1}, +{"\U0001F1EC\U0001F1F8", 1}, +{"\U0001F1EC\U0001F1F9", 1}, +{"\U0001F1EC\U0001F1FA", 1}, +{"\U0001F1EC\U0001F1FC", 1}, +{"\U0001F1EC\U0001F1FE", 1}, +{"\U0001F1ED\U0001F1F0", 1}, +{"\U0001F1ED\U0001F1F2", 1}, +{"\U0001F1ED\U0001F1F3", 1}, +{"\U0001F1ED\U0001F1F7", 1}, +{"\U0001F1ED\U0001F1F9", 1}, +{"\U0001F1ED\U0001F1FA", 1}, +{"\U0001F1EE\U0001F1E8", 1}, +{"\U0001F1EE\U0001F1E9", 1}, +{"\U0001F1EE\U0001F1EA", 1}, +{"\U0001F1EE\U0001F1F1", 1}, +{"\U0001F1EE\U0001F1F2", 1}, +{"\U0001F1EE\U0001F1F3", 1}, +{"\U0001F1EE\U0001F1F4", 1}, +{"\U0001F1EE\U0001F1F6", 1}, +{"\U0001F1EE\U0001F1F7", 1}, +{"\U0001F1EE\U0001F1F8", 1}, +{"\U0001F1EE\U0001F1F9", 1}, +{"\U0001F1EF\U0001F1EA", 1}, +{"\U0001F1EF\U0001F1F2", 1}, +{"\U0001F1EF\U0001F1F4", 1}, +{"\U0001F1EF\U0001F1F5", 1}, +{"\U0001F1F0\U0001F1EA", 1}, +{"\U0001F1F0\U0001F1EC", 1}, +{"\U0001F1F0\U0001F1ED", 1}, +{"\U0001F1F0\U0001F1EE", 1}, +{"\U0001F1F0\U0001F1F2", 1}, +{"\U0001F1F0\U0001F1F3", 1}, +{"\U0001F1F0\U0001F1F5", 1}, +{"\U0001F1F0\U0001F1F7", 1}, +{"\U0001F1F0\U0001F1FC", 1}, +{"\U0001F1F0\U0001F1FE", 1}, +{"\U0001F1F0\U0001F1FF", 1}, +{"\U0001F1F1\U0001F1E6", 1}, +{"\U0001F1F1\U0001F1E7", 1}, +{"\U0001F1F1\U0001F1E8", 1}, +{"\U0001F1F1\U0001F1EE", 1}, +{"\U0001F1F1\U0001F1F0", 1}, +{"\U0001F1F1\U0001F1F7", 1}, +{"\U0001F1F1\U0001F1F8", 1}, +{"\U0001F1F1\U0001F1F9", 1}, +{"\U0001F1F1\U0001F1FA", 1}, +{"\U0001F1F1\U0001F1FB", 1}, +{"\U0001F1F1\U0001F1FE", 1}, +{"\U0001F1F2\U0001F1E6", 1}, +{"\U0001F1F2\U0001F1E8", 1}, +{"\U0001F1F2\U0001F1E9", 1}, +{"\U0001F1F2\U0001F1EA", 1}, +{"\U0001F1F2\U0001F1EB", 1}, +{"\U0001F1F2\U0001F1EC", 1}, +{"\U0001F1F2\U0001F1ED", 1}, +{"\U0001F1F2\U0001F1F0", 1}, +{"\U0001F1F2\U0001F1F1", 1}, +{"\U0001F1F2\U0001F1F2", 1}, +{"\U0001F1F2\U0001F1F3", 1}, +{"\U0001F1F2\U0001F1F4", 1}, +{"\U0001F1F2\U0001F1F5", 1}, +{"\U0001F1F2\U0001F1F6", 1}, +{"\U0001F1F2\U0001F1F7", 1}, +{"\U0001F1F2\U0001F1F8", 1}, +{"\U0001F1F2\U0001F1F9", 1}, +{"\U0001F1F2\U0001F1FA", 1}, +{"\U0001F1F2\U0001F1FB", 1}, +{"\U0001F1F2\U0001F1FC", 1}, +{"\U0001F1F2\U0001F1FD", 1}, +{"\U0001F1F2\U0001F1FE", 1}, +{"\U0001F1F2\U0001F1FF", 1}, +{"\U0001F1F3\U0001F1E6", 1}, +{"\U0001F1F3\U0001F1E8", 1}, +{"\U0001F1F3\U0001F1EA", 1}, +{"\U0001F1F3\U0001F1EB", 1}, +{"\U0001F1F3\U0001F1EC", 1}, +{"\U0001F1F3\U0001F1EE", 1}, +{"\U0001F1F3\U0001F1F1", 1}, +{"\U0001F1F3\U0001F1F4", 1}, +{"\U0001F1F3\U0001F1F5", 1}, +{"\U0001F1F3\U0001F1F7", 1}, +{"\U0001F1F3\U0001F1FA", 1}, +{"\U0001F1F3\U0001F1FF", 1}, +{"\U0001F1F4\U0001F1F2", 1}, +{"\U0001F1F5\U0001F1E6", 1}, +{"\U0001F1F5\U0001F1EA", 1}, +{"\U0001F1F5\U0001F1EB", 1}, +{"\U0001F1F5\U0001F1EC", 1}, +{"\U0001F1F5\U0001F1ED", 1}, +{"\U0001F1F5\U0001F1F0", 1}, +{"\U0001F1F5\U0001F1F1", 1}, +{"\U0001F1F5\U0001F1F2", 1}, +{"\U0001F1F5\U0001F1F3", 1}, +{"\U0001F1F5\U0001F1F7", 1}, +{"\U0001F1F5\U0001F1F8", 1}, +{"\U0001F1F5\U0001F1F9", 1}, +{"\U0001F1F5\U0001F1FC", 1}, +{"\U0001F1F5\U0001F1FE", 1}, +{"\U0001F1F6\U0001F1E6", 1}, +{"\U0001F1F7\U0001F1EA", 1}, +{"\U0001F1F7\U0001F1F4", 1}, +{"\U0001F1F7\U0001F1F8", 1}, +{"\U0001F1F7\U0001F1FA", 1}, +{"\U0001F1F7\U0001F1FC", 1}, +{"\U0001F1F8\U0001F1E6", 1}, +{"\U0001F1F8\U0001F1E7", 1}, +{"\U0001F1F8\U0001F1E8", 1}, +{"\U0001F1F8\U0001F1E9", 1}, +{"\U0001F1F8\U0001F1EA", 1}, +{"\U0001F1F8\U0001F1EC", 1}, +{"\U0001F1F8\U0001F1ED", 1}, +{"\U0001F1F8\U0001F1EE", 1}, +{"\U0001F1F8\U0001F1EF", 1}, +{"\U0001F1F8\U0001F1F0", 1}, +{"\U0001F1F8\U0001F1F1", 1}, +{"\U0001F1F8\U0001F1F2", 1}, +{"\U0001F1F8\U0001F1F3", 1}, +{"\U0001F1F8\U0001F1F4", 1}, +{"\U0001F1F8\U0001F1F7", 1}, +{"\U0001F1F8\U0001F1F8", 1}, +{"\U0001F1F8\U0001F1F9", 1}, +{"\U0001F1F8\U0001F1FB", 1}, +{"\U0001F1F8\U0001F1FD", 1}, +{"\U0001F1F8\U0001F1FE", 1}, +{"\U0001F1F8\U0001F1FF", 1}, +{"\U0001F1F9\U0001F1E6", 1}, +{"\U0001F1F9\U0001F1E8", 1}, +{"\U0001F1F9\U0001F1E9", 1}, +{"\U0001F1F9\U0001F1EB", 1}, +{"\U0001F1F9\U0001F1EC", 1}, +{"\U0001F1F9\U0001F1ED", 1}, +{"\U0001F1F9\U0001F1EF", 1}, +{"\U0001F1F9\U0001F1F0", 1}, +{"\U0001F1F9\U0001F1F1", 1}, +{"\U0001F1F9\U0001F1F2", 1}, +{"\U0001F1F9\U0001F1F3", 1}, +{"\U0001F1F9\U0001F1F4", 1}, +{"\U0001F1F9\U0001F1F7", 1}, +{"\U0001F1F9\U0001F1F9", 1}, +{"\U0001F1F9\U0001F1FB", 1}, +{"\U0001F1F9\U0001F1FC", 1}, +{"\U0001F1F9\U0001F1FF", 1}, +{"\U0001F1FA\U0001F1E6", 1}, +{"\U0001F1FA\U0001F1EC", 1}, +{"\U0001F1FA\U0001F1F2", 1}, +{"\U0001F1FA\U0001F1F3", 1}, +{"\U0001F1FA\U0001F1F8", 1}, +{"\U0001F1FA\U0001F1FE", 1}, +{"\U0001F1FA\U0001F1FF", 1}, +{"\U0001F1FB\U0001F1E6", 1}, +{"\U0001F1FB\U0001F1E8", 1}, +{"\U0001F1FB\U0001F1EA", 1}, +{"\U0001F1FB\U0001F1EC", 1}, +{"\U0001F1FB\U0001F1EE", 1}, +{"\U0001F1FB\U0001F1F3", 1}, +{"\U0001F1FB\U0001F1FA", 1}, +{"\U0001F1FC\U0001F1EB", 1}, +{"\U0001F1FC\U0001F1F8", 1}, +{"\U0001F1FD\U0001F1F0", 1}, +{"\U0001F1FE\U0001F1EA", 1}, +{"\U0001F1FE\U0001F1F9", 1}, +{"\U0001F1FF\U0001F1E6", 1}, +{"\U0001F1FF\U0001F1F2", 1}, +{"\U0001F1FF\U0001F1FC", 1}, +{"\U0001F3F4\U000E0067\U000E0062\U000E0065\U000E006E\U000E0067\U000E007F", 1}, +{"\U0001F3F4\U000E0067\U000E0062\U000E0073\U000E0063\U000E0074\U000E007F", 1}, +{"\U0001F3F4\U000E0067\U000E0062\U000E0077\U000E006C\U000E0073\U000E007F", 1}, +} diff --git a/tests/internal/test_map.odin b/tests/internal/test_map.odin index a9a8cf5d4..9bd5d34ea 100644 --- a/tests/internal/test_map.odin +++ b/tests/internal/test_map.odin @@ -16,10 +16,10 @@ map_insert_random_key_value :: proc(t: ^testing.T) { defer delete(m) unique_keys := 0 - r := rand.create(t.seed + seed_incr) + rand.reset(t.seed + seed_incr) for _ in 0.. bool { diff --git a/vendor/ENet/win32.odin b/vendor/ENet/win32.odin index 1df35ee45..d05cf5d99 100644 --- a/vendor/ENet/win32.odin +++ b/vendor/ENet/win32.odin @@ -39,7 +39,9 @@ foreign WinSock2 { return } } - if s.fd_count >= FD_SETSIZE do return + if s.fd_count >= FD_SETSIZE { + return + } s.fd_array[s.fd_count] = fd s.fd_count += 1 } diff --git a/vendor/OpenGL/wrappers.odin b/vendor/OpenGL/wrappers.odin index a04df6987..1eb8fc72f 100644 --- a/vendor/OpenGL/wrappers.odin +++ b/vendor/OpenGL/wrappers.odin @@ -454,20 +454,13 @@ when !GL_DEBUG { BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32) { impl_BeginQueryIndexed(target, index, id) } EndQueryIndexed :: proc "c" (target: u32, index: u32) { impl_EndQueryIndexed(target, index) } GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32) { impl_GetQueryIndexediv(target, index, pname, params) } - GetTextureHandleARB :: proc "c" (texture: u32) -> u64 - { return impl_GetTextureHandleARB(texture) } - GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32) -> u64 - { return impl_GetTextureSamplerHandleARB(texture, sampler) } - GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32) -> u64 - { return impl_GetImageHandleARB(texture, level, layered, layer, format) } - MakeTextureHandleResidentARB :: proc "c" (handle: u64) - { impl_MakeTextureHandleResidentARB(handle) } - MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32) - { impl_MakeImageHandleResidentARB(handle, access) } - MakeTextureHandleNonResidentARB:: proc "c" (handle: u64) - { impl_MakeTextureHandleNonResidentARB(handle) } - MakeImageHandleNonResidentARB :: proc "c" (handle: u64) - { impl_MakeImageHandleNonResidentARB(handle) } + GetTextureHandleARB :: proc "c" (texture: u32) -> u64 { return impl_GetTextureHandleARB(texture) } + GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32) -> u64 { return impl_GetTextureSamplerHandleARB(texture, sampler) } + GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32) -> u64 { return impl_GetImageHandleARB(texture, level, layered, layer, format) } + MakeTextureHandleResidentARB :: proc "c" (handle: u64) { impl_MakeTextureHandleResidentARB(handle) } + MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32) { impl_MakeImageHandleResidentARB(handle, access) } + MakeTextureHandleNonResidentARB:: proc "c" (handle: u64) { impl_MakeTextureHandleNonResidentARB(handle) } + MakeImageHandleNonResidentARB :: proc "c" (handle: u64) { impl_MakeImageHandleNonResidentARB(handle) } // VERSION_4_1 ReleaseShaderCompiler :: proc "c" () { impl_ReleaseShaderCompiler() } @@ -788,17 +781,17 @@ when !GL_DEBUG { { // add input arguments for arg, arg_index in args[num_ret:] { - if arg_index > 0 { fmt.printf(", ") } + if arg_index > 0 { fmt.printf(", ") } - if v, ok := arg.(u32); ok { // TODO: Assumes all u32 are GLenum (they're not, GLbitfield and GLuint are also mapped to u32), fix later by better typing - if err == .INVALID_ENUM { - fmt.printf("INVALID_ENUM=%d", v) + if v, ok := arg.(u32); ok { // TODO: Assumes all u32 are GLenum (they're not, GLbitfield and GLuint are also mapped to u32), fix later by better typing + if err == .INVALID_ENUM { + fmt.printf("INVALID_ENUM=%d", v) + } else { + fmt.printf("GL_%v=%d", GL_Enum(v), v) + } } else { - fmt.printf("GL_%v=%d", GL_Enum(v), v) + fmt.printf("%v", arg) } - } else { - fmt.printf("%v", arg) - } } // add return arguments @@ -817,7 +810,7 @@ when !GL_DEBUG { } // add location - fmt.printf(" in: %s(%d:%d)\n", from_loc.file_path, from_loc.line, from_loc.column) + fmt.printf(" in: %s(%d:%d)\n", from_loc.file_path, from_loc.line, from_loc.column) } } @@ -1265,20 +1258,13 @@ when !GL_DEBUG { BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32, loc := #caller_location) { impl_BeginQueryIndexed(target, index, id); debug_helper(loc, 0, target, index, id) } EndQueryIndexed :: proc "c" (target: u32, index: u32, loc := #caller_location) { impl_EndQueryIndexed(target, index); debug_helper(loc, 0, target, index) } GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryIndexediv(target, index, pname, params); debug_helper(loc, 0, target, index, pname, params) } - GetTextureHandleARB :: proc "c" (target: u32, loc := #caller_location) -> u64 - { ret := impl_GetTextureHandleARB(target); debug_helper(loc, 0, target); return ret } - GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32, loc := #caller_location) -> u64 - { ret := impl_GetTextureSamplerHandleARB(texture, sampler); debug_helper(loc, 0, texture, sampler); return ret } - GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32, loc := #caller_location) -> u64 - { ret := impl_GetImageHandleARB(texture, level, layered, layer, format); debug_helper(loc, 0, texture, level, layered, layer, format); return ret } - MakeTextureHandleResidentARB :: proc "c" (handle: u64, loc := #caller_location) - { impl_MakeTextureHandleResidentARB(handle); debug_helper(loc, 0, handle) } - MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32, loc := #caller_location) - { impl_MakeImageHandleResidentARB(handle, access); debug_helper(loc, 0, handle, access) } - MakeTextureHandleNonResidentARB:: proc "c" (handle: u64, loc := #caller_location) - { impl_MakeTextureHandleNonResidentARB(handle); debug_helper(loc, 0, handle) } - MakeImageHandleNonResidentARB :: proc "c" (handle: u64, loc := #caller_location) - { impl_MakeImageHandleNonResidentARB(handle); debug_helper(loc, 0, handle) } + GetTextureHandleARB :: proc "c" (target: u32, loc := #caller_location) -> u64 { ret := impl_GetTextureHandleARB(target); debug_helper(loc, 0, target); return ret } + GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32, loc := #caller_location) -> u64 { ret := impl_GetTextureSamplerHandleARB(texture, sampler); debug_helper(loc, 0, texture, sampler); return ret } + GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32, loc := #caller_location) -> u64 { ret := impl_GetImageHandleARB(texture, level, layered, layer, format); debug_helper(loc, 0, texture, level, layered, layer, format); return ret } + MakeTextureHandleResidentARB :: proc "c" (handle: u64, loc := #caller_location) { impl_MakeTextureHandleResidentARB(handle); debug_helper(loc, 0, handle) } + MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32, loc := #caller_location) { impl_MakeImageHandleResidentARB(handle, access); debug_helper(loc, 0, handle, access) } + MakeTextureHandleNonResidentARB:: proc "c" (handle: u64, loc := #caller_location) { impl_MakeTextureHandleNonResidentARB(handle); debug_helper(loc, 0, handle) } + MakeImageHandleNonResidentARB :: proc "c" (handle: u64, loc := #caller_location) { impl_MakeImageHandleNonResidentARB(handle); debug_helper(loc, 0, handle) } diff --git a/vendor/commonmark/cmark.odin b/vendor/commonmark/cmark.odin index 9ad71da3f..50544b9bd 100644 --- a/vendor/commonmark/cmark.odin +++ b/vendor/commonmark/cmark.odin @@ -494,15 +494,15 @@ free_cstring :: proc "c" (str: cstring) { free_rawptr(rawptr(str)) } free_string :: proc "c" (s: string) { - free_rawptr(raw_data(s)) + free_rawptr(raw_data(s)) } free :: proc{free_rawptr, free_cstring} // Wrap CMark allocator as Odin allocator @(private) cmark_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) { + size, alignment: int, + old_memory: rawptr, old_size: int, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) { cmark_alloc := cast(^Allocator)allocator_data switch mode { diff --git a/vendor/directx/d3d11/d3d11.odin b/vendor/directx/d3d11/d3d11.odin index 3af0f2965..83801e854 100644 --- a/vendor/directx/d3d11/d3d11.odin +++ b/vendor/directx/d3d11/d3d11.odin @@ -3775,39 +3775,41 @@ MESSAGE :: struct { IInfoQueue_VTable :: struct { using iunkown_vtable: IUnknown_VTable, - AddApplicationMessage: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, pDescription: cstring) -> HRESULT, - AddMessage: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: cstring) -> HRESULT, - AddRetrievalFilterEntries: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, - AddStorageFilterEntries: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, - ClearRetrievalFilter: proc "system" (this: ^IInfoQueue), - ClearStorageFilter: proc "system" (this: ^IInfoQueue), + SetMessageCountLimit: proc "system" (this: ^IInfoQueue, MessageCountLimit: u64) -> HRESULT, ClearStoredMessages: proc "system" (this: ^IInfoQueue), - GetBreakOnCategory: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY) -> BOOL, - GetBreakOnID: proc "system" (this: ^IInfoQueue, ID: MESSAGE_ID) -> BOOL, - GetBreakOnSeverity: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY) -> BOOL, GetMessage: proc "system" (this: ^IInfoQueue, MessageIndex: u64, pMessage: ^MESSAGE, pMessageByteLength: ^SIZE_T) -> HRESULT, - GetMessageCountLimit: proc "system" (this: ^IInfoQueue) -> u64, - GetMuteDebugOutput: proc "system" (this: ^IInfoQueue) -> BOOL, GetNumMessagesAllowedByStorageFilter: proc "system" (this: ^IInfoQueue) -> u64, GetNumMessagesDeniedByStorageFilter: proc "system" (this: ^IInfoQueue) -> u64, - GetNumMessagesDiscardedByMessageCountLimit: proc "system" (this: ^IInfoQueue) -> u64, GetNumStoredMessages: proc "system" (this: ^IInfoQueue) -> u64, GetNumStoredMessagesAllowedByRetrievalFilter: proc "system" (this: ^IInfoQueue) -> u64, - GetRetrievalFilter: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER, pFilterByteLength: ^SIZE_T) -> HRESULT, - GetRetrievalFilterStackSize: proc "system" (this: ^IInfoQueue) -> u64, + GetNumMessagesDiscardedByMessageCountLimit: proc "system" (this: ^IInfoQueue) -> u64, + GetMessageCountLimit: proc "system" (this: ^IInfoQueue) -> u64, + AddStorageFilterEntries: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, GetStorageFilter: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER, pFilterByteLength: ^SIZE_T) -> HRESULT, - GetStorageFilterStackSize: proc "system" (this: ^IInfoQueue) -> u64, - PopRetrievalFilter: proc "system" (this: ^IInfoQueue), - PopStorageFilter: proc "system" (this: ^IInfoQueue), - PushCopyOfRetrievalFilter: proc "system" (this: ^IInfoQueue) -> HRESULT, - PushCopyOfStorageFilter: proc "system" (this: ^IInfoQueue) -> HRESULT, - PushEmptyRetrievalFilter: proc "system" (this: ^IInfoQueue) -> HRESULT, + ClearStorageFilter: proc "system" (this: ^IInfoQueue), PushEmptyStorageFilter: proc "system" (this: ^IInfoQueue) -> HRESULT, + PushCopyOfStorageFilter: proc "system" (this: ^IInfoQueue) -> HRESULT, + PushStorageFilter: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + PopStorageFilter: proc "system" (this: ^IInfoQueue), + GetStorageFilterStackSize: proc "system" (this: ^IInfoQueue) -> u64, + AddRetrievalFilterEntries: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + GetRetrievalFilter: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER, pFilterByteLength: ^SIZE_T) -> HRESULT, + ClearRetrievalFilter: proc "system" (this: ^IInfoQueue), + PushEmptyRetrievalFilter: proc "system" (this: ^IInfoQueue) -> HRESULT, + PushCopyOfRetrievalFilter: proc "system" (this: ^IInfoQueue) -> HRESULT, + PushRetrievalFilter: proc "system" (this: ^IInfoQueue, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + PopRetrievalFilter: proc "system" (this: ^IInfoQueue), + GetRetrievalFilterStackSize: proc "system" (this: ^IInfoQueue) -> u64, + AddMessage: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: cstring) -> HRESULT, + AddApplicationMessage: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, pDescription: cstring) -> HRESULT, SetBreakOnCategory: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY, bEnable: BOOL) -> HRESULT, - SetBreakOnID: proc "system" (this: ^IInfoQueue, ID: MESSAGE_ID, bEnable: BOOL) -> HRESULT, SetBreakOnSeverity: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY, bEnable: BOOL) -> HRESULT, - SetMessageCountLimit: proc "system" (this: ^IInfoQueue, MessageCountLimit: u64) -> HRESULT, + SetBreakOnID: proc "system" (this: ^IInfoQueue, ID: MESSAGE_ID, bEnable: BOOL) -> HRESULT, + GetBreakOnCategory: proc "system" (this: ^IInfoQueue, Category: MESSAGE_CATEGORY) -> BOOL, + GetBreakOnSeverity: proc "system" (this: ^IInfoQueue, Severity: MESSAGE_SEVERITY) -> BOOL, + GetBreakOnID: proc "system" (this: ^IInfoQueue, ID: MESSAGE_ID) -> BOOL, SetMuteDebugOutput: proc "system" (this: ^IInfoQueue, bMute: BOOL), + GetMuteDebugOutput: proc "system" (this: ^IInfoQueue) -> BOOL, } MESSAGE_ID :: enum u32 { diff --git a/vendor/directx/dxgi/dxgi.odin b/vendor/directx/dxgi/dxgi.odin index 235e07633..5b6137cee 100644 --- a/vendor/directx/dxgi/dxgi.odin +++ b/vendor/directx/dxgi/dxgi.odin @@ -29,14 +29,9 @@ SIZE :: win32.SIZE WCHAR :: win32.WCHAR DWORD :: win32.DWORD -IUnknown :: struct { - using _iunknown_vtable: ^IUnknown_VTable, -} -IUnknown_VTable :: struct { - QueryInterface: proc "system" (this: ^IUnknown, riid: ^IID, ppvObject: ^rawptr) -> HRESULT, - AddRef: proc "system" (this: ^IUnknown) -> ULONG, - Release: proc "system" (this: ^IUnknown) -> ULONG, -} +IUnknown :: win32.IUnknown +IUnknown_VTable :: win32.IUnknown_VTable +LPUNKNOWN :: win32.LPUNKNOWN @(default_calling_convention="system") foreign dxgi { diff --git a/vendor/fontstash/fontstash.odin b/vendor/fontstash/fontstash.odin index 70edcd109..2c692db06 100644 --- a/vendor/fontstash/fontstash.odin +++ b/vendor/fontstash/fontstash.odin @@ -1,14 +1,14 @@ -//+build windows, linux, darwin //+vet !using-param package fontstash import "base:runtime" + import "core:log" -import "core:os" import "core:mem" import "core:math" import "core:strings" import "core:slice" + import stbtt "vendor:stb/truetype" // This is a port from Fontstash into odin - specialized for nanovg @@ -321,20 +321,6 @@ __AtlasAddWhiteRect :: proc(ctx: ^FontContext, w, h: int) -> bool { return true } -AddFontPath :: proc( - ctx: ^FontContext, - name: string, - path: string, -) -> int { - data, ok := os.read_entire_file(path) - - if !ok { - log.panicf("FONT: failed to read font at %s", path) - } - - return AddFontMem(ctx, name, data, true) -} - // push a font to the font stack // optionally init with ascii characters at a wanted size AddFontMem :: proc( @@ -798,10 +784,10 @@ __getVerticalAlign :: proc( case .BOTTOMLEFT: switch av { - case .TOP: res = -font.ascender * f32(pixelSize) / 10 - case .MIDDLE: res = -(font.ascender + font.descender) / 2 * f32(pixelSize) / 10 - case .BASELINE: res = 0 - case .BOTTOM: res = -font.descender * f32(pixelSize) / 10 + case .TOP: res = -font.ascender * f32(pixelSize) / 10 + case .MIDDLE: res = -(font.ascender + font.descender) / 2 * f32(pixelSize) / 10 + case .BASELINE: res = 0 + case .BOTTOM: res = -font.descender * f32(pixelSize) / 10 } } @@ -1192,4 +1178,4 @@ EndState :: proc(using ctx: ^FontContext) { } __dirtyRectReset(ctx) } -} \ No newline at end of file +} diff --git a/vendor/fontstash/fontstash_os.odin b/vendor/fontstash/fontstash_os.odin new file mode 100644 index 000000000..6182573bd --- /dev/null +++ b/vendor/fontstash/fontstash_os.odin @@ -0,0 +1,20 @@ +//+build !js +package fontstash + +import "core:log" +import "core:os" + +AddFontPath :: proc( + ctx: ^FontContext, + name: string, + path: string, +) -> int { + data, ok := os.read_entire_file(path) + + if !ok { + log.panicf("FONT: failed to read font at %s", path) + } + + return AddFontMem(ctx, name, data, true) +} + diff --git a/vendor/fontstash/fontstash_other.odin b/vendor/fontstash/fontstash_other.odin new file mode 100644 index 000000000..1c2ca3f28 --- /dev/null +++ b/vendor/fontstash/fontstash_other.odin @@ -0,0 +1,10 @@ +//+build js +package fontstash + +AddFontPath :: proc( + ctx: ^FontContext, + name: string, + path: string, +) -> int { + panic("fontstash.AddFontPath is unsupported on the JS target") +} diff --git a/vendor/glfw/native_linux.odin b/vendor/glfw/native_linux.odin index 9b9e14790..6833d2893 100644 --- a/vendor/glfw/native_linux.odin +++ b/vendor/glfw/native_linux.odin @@ -2,14 +2,18 @@ package glfw -// TODO: Native Linux -// Display* glfwGetX11Display(void); -// RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); -// RROutput glfwGetX11Monitor(GLFWmonitor* monitor); -// Window glfwGetX11Window(GLFWwindow* window); -// void glfwSetX11SelectionString(const char* string); -// const char* glfwGetX11SelectionString(void); +import "vendor:x11/xlib" -// struct wl_display* glfwGetWaylandDisplay(void); -// struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); -// struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); +@(default_calling_convention="c", link_prefix="glfw") +foreign { + GetX11Display :: proc() -> ^xlib.Display --- + GetX11Window :: proc(window: WindowHandle) -> xlib.Window --- + GetX11Adapter :: proc(monitor: MonitorHandle) -> xlib.RRCrtc --- + GetX11Monitor :: proc(monitor: MonitorHandle) -> xlib.RROutput --- + SetX11SelectionString :: proc(string: cstring) --- + GetX11SelectionString :: proc() -> cstring --- + + GetWaylandDisplay :: proc() -> rawptr /* struct wl_display* */ --- + GetWaylandWindow :: proc(window: WindowHandle) -> rawptr /* struct wl_surface* */ --- + GetWaylandMonitor :: proc(monitor: MonitorHandle) -> rawptr /* struct wl_output* */ --- +} diff --git a/vendor/sdl2/sdl2.odin b/vendor/sdl2/sdl2.odin index 719390adc..73d95e18a 100644 --- a/vendor/sdl2/sdl2.odin +++ b/vendor/sdl2/sdl2.odin @@ -235,8 +235,8 @@ foreign lib { // quit QuitRequested :: #force_inline proc "c" () -> bool { - PumpEvents() - return bool(PeepEvents(nil, 0, .PEEKEVENT, .QUIT, .QUIT) > 0) + PumpEvents() + return bool(PeepEvents(nil, 0, .PEEKEVENT, .QUIT, .QUIT) > 0) } diff --git a/vendor/sdl2/sdl_pixels.odin b/vendor/sdl2/sdl_pixels.odin index 9eccbc6ab..195f2920f 100644 --- a/vendor/sdl2/sdl_pixels.odin +++ b/vendor/sdl2/sdl_pixels.odin @@ -22,7 +22,7 @@ PIXELTYPE_ARRAYU8 :: 7 PIXELTYPE_ARRAYU16 :: 8 PIXELTYPE_ARRAYU32 :: 9 PIXELTYPE_ARRAYF16 :: 10 -PIXELTYPE_ARRAYF3 :: 11 +PIXELTYPE_ARRAYF32 :: 11 BITMAPORDER_NONE :: 0 BITMAPORDER_4321 :: 1 @@ -47,7 +47,7 @@ ARRAYORDER_RGBA :: 2 ARRAYORDER_ARGB :: 3 ARRAYORDER_BGR :: 4 ARRAYORDER_BGRA :: 5 -ARRAYORDER_ABG :: 6 +ARRAYORDER_ABGR :: 6 PACKEDLAYOUT_NONE :: 0 PACKEDLAYOUT_332 :: 1 diff --git a/vendor/stb/lib/stb_truetype_wasm.o b/vendor/stb/lib/stb_truetype_wasm.o new file mode 100644 index 000000000..15c4fa0d5 Binary files /dev/null and b/vendor/stb/lib/stb_truetype_wasm.o differ diff --git a/vendor/stb/src/Makefile b/vendor/stb/src/Makefile index 1027cf8d2..6123a95fa 100644 --- a/vendor/stb/src/Makefile +++ b/vendor/stb/src/Makefile @@ -6,6 +6,10 @@ else all: unix endif +wasm: + mkdir -p ../lib + clang -c -Os --target=wasm32 -nostdlib stb_truetype_wasm.c -o ../lib/stb_truetype_wasm.o + unix: mkdir -p ../lib $(CC) -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c diff --git a/vendor/stb/src/stb_truetype_wasm.c b/vendor/stb/src/stb_truetype_wasm.c new file mode 100644 index 000000000..e0b1fdc77 --- /dev/null +++ b/vendor/stb/src/stb_truetype_wasm.c @@ -0,0 +1,46 @@ +#include + +void *stbtt_malloc(size_t size); +void stbtt_free(void *ptr); + +void stbtt_qsort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*)); + +double stbtt_floor(double x); +double stbtt_ceil(double x); +double stbtt_sqrt(double x); +double stbtt_pow(double x, double y); +double stbtt_fmod(double x, double y); +double stbtt_cos(double x); +double stbtt_acos(double x); +double stbtt_fabs(double x); + +unsigned long stbtt_strlen(const char *str); + +void *memcpy(void *dst, const void *src, size_t count); +void *memset(void *dst, int x, size_t count); + +#define STBRP_SORT stbtt_qsort +#define STBRP_ASSERT(condition) ((void)0) + +#define STBTT_malloc(x,u) ((void)(u),stbtt_malloc(x)) +#define STBTT_free(x,u) ((void)(u),stbtt_free(x)) + +#define STBTT_assert(condition) ((void)0) + +#define STBTT_ifloor(x) ((int) stbtt_floor(x)) +#define STBTT_iceil(x) ((int) stbtt_ceil(x)) +#define STBTT_sqrt(x) stbtt_sqrt(x) +#define STBTT_pow(x,y) stbtt_pow(x,y) +#define STBTT_fmod(x,y) stbtt_fmod(x,y) +#define STBTT_cos(x) stbtt_cos(x) +#define STBTT_acos(x) stbtt_acos(x) +#define STBTT_fabs(x) stbtt_fabs(x) +#define STBTT_strlen(x) stbtt_strlen(x) +#define STBTT_memcpy memcpy +#define STBTT_memset memset + +#define STB_RECT_PACK_IMPLEMENTATION +#include "stb_rect_pack.h" + +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" diff --git a/vendor/stb/truetype/stb_truetype.odin b/vendor/stb/truetype/stb_truetype.odin index 876138c3a..6993cd2b7 100644 --- a/vendor/stb/truetype/stb_truetype.odin +++ b/vendor/stb/truetype/stb_truetype.odin @@ -17,6 +17,8 @@ when LIB != "" { } foreign import stbtt { LIB } +} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import stbtt "../lib/stb_truetype_wasm.o" } else { foreign import stbtt "system:stb_truetype" } diff --git a/vendor/stb/truetype/stb_truetype_wasm.odin b/vendor/stb/truetype/stb_truetype_wasm.odin new file mode 100644 index 000000000..cb516bc1d --- /dev/null +++ b/vendor/stb/truetype/stb_truetype_wasm.odin @@ -0,0 +1,89 @@ +//+build wasm32, wasm64p32 +package stb_truetype + +import "base:builtin" +import "base:intrinsics" +import "base:runtime" + +import "core:c" +import "core:math" +import "core:mem" +import "core:slice" +import "core:sort" + +@(require, linkage="strong", link_name="stbtt_malloc") +malloc :: proc "c" (size: uint) -> rawptr { + context = runtime.default_context() + ptr, _ := runtime.mem_alloc_non_zeroed(int(size)) + return raw_data(ptr) +} + +@(require, linkage="strong", link_name="stbtt_free") +free :: proc "c" (ptr: rawptr) { + context = runtime.default_context() + builtin.free(ptr) +} + +@(require, linkage="strong", link_name="stbtt_qsort") +qsort :: proc "c" (base: rawptr, num: uint, size: uint, cmp: proc "c" (a, b: rawptr) -> i32) { + context = runtime.default_context() + + Inputs :: struct { + base: rawptr, + num: uint, + size: uint, + cmp: proc "c" (a, b: rawptr) -> i32, + } + + sort.sort({ + collection = &Inputs{base, num, size, cmp}, + len = proc(it: sort.Interface) -> int { + inputs := (^Inputs)(it.collection) + return int(inputs.num) + }, + less = proc(it: sort.Interface, i, j: int) -> bool { + inputs := (^Inputs)(it.collection) + a := rawptr(uintptr(inputs.base) + (uintptr(i) * uintptr(inputs.size))) + b := rawptr(uintptr(inputs.base) + (uintptr(j) * uintptr(inputs.size))) + return inputs.cmp(a, b) < 0 + }, + swap = proc(it: sort.Interface, i, j: int) { + inputs := (^Inputs)(it.collection) + + a := rawptr(uintptr(inputs.base) + (uintptr(i) * uintptr(inputs.size))) + b := rawptr(uintptr(inputs.base) + (uintptr(j) * uintptr(inputs.size))) + + slice.ptr_swap_non_overlapping(a, b, int(inputs.size)) + }, + }) +} + +@(require, linkage="strong", link_name="stbtt_floor") +floor :: proc "c" (x: f64) -> f64 { return math.floor(x) } +@(require, linkage="strong", link_name="stbtt_ceil") +ceil :: proc "c" (x: f64) -> f64 { return math.ceil(x) } +@(require, linkage="strong", link_name="stbtt_sqrt") +sqrt :: proc "c" (x: f64) -> f64 { return math.sqrt(x) } +@(require, linkage="strong", link_name="stbtt_pow") +pow :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) } + +@(require, linkage="strong", link_name="stbtt_fmod") +fmod :: proc "c" (x, y: f64) -> f64 { + context = runtime.default_context(); + // NOTE: only called in the `stbtt_GetGlyphSDF` code path. + panic("`math.round` is broken on 32 bit targets, see #3856") +} + +@(require, linkage="strong", link_name="stbtt_cos") +cos :: proc "c" (x: f64) -> f64 { return math.cos(x) } +@(require, linkage="strong", link_name="stbtt_acos") +acos :: proc "c" (x: f64) -> f64 { return math.acos(x) } +@(require, linkage="strong", link_name="stbtt_fabs") +fabs :: proc "c" (x: f64) -> f64 { return math.abs(x) } + +@(require, linkage="strong", link_name="stbtt_strlen") +strlen :: proc "c" (str: cstring) -> c.ulong { return c.ulong(len(str)) } + +// NOTE: defined in runtime. +// void *memcpy(void *dst, const void *src, size_t count); +// void *memset(void *dst, int x, size_t count); diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index 65f53758f..a551887ff 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -94,15 +94,13 @@ def convert_type(t, prev_name, curr_name): if t == "": return t + if t.startswith("const"): + t = convert_type(t[6:], prev_name, curr_name) + elif t.endswith("*"): - elem = "" pointer = "^" - if t.startswith("const"): - ttype = t[6:len(t)-1] - elem = convert_type(ttype, prev_name, curr_name) - else: - ttype = t[:len(t)-1] - elem = convert_type(ttype, prev_name, curr_name) + ttype = t[:len(t)-1] + elem = convert_type(ttype, prev_name, curr_name) if curr_name.endswith("s") or curr_name.endswith("Table"): if prev_name.endswith("Count") or prev_name.endswith("Counts"): @@ -625,12 +623,14 @@ def parse_procedures(f): for rt, name, fields in data: proc_name = no_vk(name) - pf = [] prev_name = "" - for type_, fname in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:,|$)", fields): + for type_, fname, array_len in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:\[(\d+)\])?(?:,|$)", fields): curr_name = fix_arg(fname) - pf.append((do_type(type_, prev_name, curr_name), curr_name)) + ty = do_type(type_, prev_name, curr_name) + if array_len != "": + ty = f"^[{array_len}]{ty}" + pf.append((ty, curr_name)) prev_name = curr_name data_fields = ', '.join(["{}: {}".format(n, t) for t, n in pf if t != ""]) @@ -798,7 +798,7 @@ API_VERSION_1_2 :: (1<<22) | (2<<12) | (0) API_VERSION_1_3 :: (1<<22) | (3<<12) | (0) MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 { - return (major<<22) | (minor<<12) | (patch) +\treturn (major<<22) | (minor<<12) | (patch) } // Base types diff --git a/vendor/vulkan/core.odin b/vendor/vulkan/core.odin index 764156b8d..79b856595 100644 --- a/vendor/vulkan/core.odin +++ b/vendor/vulkan/core.odin @@ -8,7 +8,7 @@ API_VERSION_1_2 :: (1<<22) | (2<<12) | (0) API_VERSION_1_3 :: (1<<22) | (3<<12) | (0) MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 { - return (major<<22) | (minor<<12) | (patch) + return (major<<22) | (minor<<12) | (patch) } // Base types diff --git a/vendor/vulkan/procedures.odin b/vendor/vulkan/procedures.odin index 9a27b4f79..bec421f29 100644 --- a/vendor/vulkan/procedures.odin +++ b/vendor/vulkan/procedures.odin @@ -259,7 +259,7 @@ ProcCmdResolveImage2KHR :: #type proc "system ProcCmdSetAlphaToCoverageEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, alphaToCoverageEnable: b32) ProcCmdSetAlphaToOneEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, alphaToOneEnable: b32) ProcCmdSetAttachmentFeedbackLoopEnableEXT :: #type proc "system" (commandBuffer: CommandBuffer, aspectMask: ImageAspectFlags) -ProcCmdSetBlendConstants :: #type proc "system" (commandBuffer: CommandBuffer) +ProcCmdSetBlendConstants :: #type proc "system" (commandBuffer: CommandBuffer, blendConstants: ^[4]f32) ProcCmdSetCheckpointNV :: #type proc "system" (commandBuffer: CommandBuffer, pCheckpointMarker: rawptr) ProcCmdSetCoarseSampleOrderNV :: #type proc "system" (commandBuffer: CommandBuffer, sampleOrderType: CoarseSampleOrderTypeNV, customSampleOrderCount: u32, pCustomSampleOrders: [^]CoarseSampleOrderCustomNV) ProcCmdSetColorBlendAdvancedEXT :: #type proc "system" (commandBuffer: CommandBuffer, firstAttachment: u32, attachmentCount: u32, pColorBlendAdvanced: ^ColorBlendAdvancedEXT) @@ -302,8 +302,8 @@ ProcCmdSetEvent2KHR :: #type proc "system ProcCmdSetExclusiveScissorEnableNV :: #type proc "system" (commandBuffer: CommandBuffer, firstExclusiveScissor: u32, exclusiveScissorCount: u32, pExclusiveScissorEnables: [^]b32) ProcCmdSetExclusiveScissorNV :: #type proc "system" (commandBuffer: CommandBuffer, firstExclusiveScissor: u32, exclusiveScissorCount: u32, pExclusiveScissors: [^]Rect2D) ProcCmdSetExtraPrimitiveOverestimationSizeEXT :: #type proc "system" (commandBuffer: CommandBuffer, extraPrimitiveOverestimationSize: f32) -ProcCmdSetFragmentShadingRateEnumNV :: #type proc "system" (commandBuffer: CommandBuffer, shadingRate: FragmentShadingRateNV) -ProcCmdSetFragmentShadingRateKHR :: #type proc "system" (commandBuffer: CommandBuffer, pFragmentSize: ^Extent2D) +ProcCmdSetFragmentShadingRateEnumNV :: #type proc "system" (commandBuffer: CommandBuffer, shadingRate: FragmentShadingRateNV, combinerOps: ^[2]FragmentShadingRateCombinerOpKHR) +ProcCmdSetFragmentShadingRateKHR :: #type proc "system" (commandBuffer: CommandBuffer, pFragmentSize: ^Extent2D, combinerOps: ^[2]FragmentShadingRateCombinerOpKHR) ProcCmdSetFrontFace :: #type proc "system" (commandBuffer: CommandBuffer, frontFace: FrontFace) ProcCmdSetFrontFaceEXT :: #type proc "system" (commandBuffer: CommandBuffer, frontFace: FrontFace) ProcCmdSetLineRasterizationModeEXT :: #type proc "system" (commandBuffer: CommandBuffer, lineRasterizationMode: LineRasterizationModeEXT) diff --git a/vendor/wasm/js/runtime.js b/vendor/wasm/js/runtime.js index 5c7f97fae..74ad7568e 100644 --- a/vendor/wasm/js/runtime.js +++ b/vendor/wasm/js/runtime.js @@ -96,6 +96,10 @@ class WasmMemoryInterface { }; loadPtr(addr) { return this.loadU32(addr); } + loadB32(addr) { + return this.loadU32(addr) != 0; + } + loadBytes(ptr, len) { return new Uint8Array(this.memory.buffer, ptr, Number(len)); } @@ -104,6 +108,16 @@ class WasmMemoryInterface { const bytes = this.loadBytes(ptr, Number(len)); return new TextDecoder().decode(bytes); } + + loadCstring(ptr) { + const start = this.loadPtr(ptr); + if (start == 0) { + return null; + } + let len = 0; + for (; this.mem.getUint8(start+len) != 0; len += 1) {} + return this.loadString(start, len); + } storeU8(addr, value) { this.mem.setUint8 (addr, value); } storeI8(addr, value) { this.mem.setInt8 (addr, value); } @@ -1245,7 +1259,7 @@ class WebGLInterface { }; -function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) { +function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { const MAX_INFO_CONSOLE_LINES = 512; let infoConsoleLines = new Array(); let currentLine = {}; @@ -1366,8 +1380,15 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) { let event_temp_data = {}; let webglContext = new WebGLInterface(wasmMemoryInterface); + + const env = {}; + + if (memory) { + env.memory = memory; + } + return { - "env": {}, + env, "odin_env": { write: (fd, ptr, len) => { const str = wasmMemoryInterface.loadString(ptr, len); @@ -1720,13 +1741,16 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) { * @param {string} wasmPath - Path to the WASM module to run * @param {?HTMLPreElement} consoleElement - Optional console/pre element to append output to, in addition to the console * @param {any} extraForeignImports - Imports, in addition to the default runtime to provide the module + * @param {?WasmMemoryInterface} wasmMemoryInterface - Optional memory to use instead of the defaults * @param {?int} intSize - Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32` */ -async function runWasm(wasmPath, consoleElement, extraForeignImports, intSize = 4) { - const wasmMemoryInterface = new WasmMemoryInterface(); +async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemoryInterface, intSize = 4) { + if (!wasmMemoryInterface) { + wasmMemoryInterface = new WasmMemoryInterface(); + } wasmMemoryInterface.setIntSize(intSize); - let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement); + let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory); let exports = {}; if (extraForeignImports !== undefined) { @@ -1741,11 +1765,17 @@ async function runWasm(wasmPath, consoleElement, extraForeignImports, intSize = const wasm = await WebAssembly.instantiate(file, imports); exports = wasm.instance.exports; wasmMemoryInterface.setExports(exports); - wasmMemoryInterface.setMemory(exports.memory); + + if (exports.memory) { + if (wasmMemoryInterface.memory) { + console.warn("WASM module exports memory, but `runWasm` was given an interface with existing memory too"); + } + wasmMemoryInterface.setMemory(exports.memory); + } exports._start(); - // Define a `@export step :: proc(dt: f32) -> (continue: bool) {` + // Define a `@export step :: proc(dt: f32) -> (keep_going: bool) {` // in your app and it will get called every frame. // return `false` to stop the execution of the module. if (exports.step) { diff --git a/vendor/wgpu/.gitignore b/vendor/wgpu/.gitignore new file mode 100644 index 000000000..330d70755 --- /dev/null +++ b/vendor/wgpu/.gitignore @@ -0,0 +1,9 @@ +lib/* +!lib/.gitkeep +example/web/triangle.wasm +example/web/wgpu.js +example/web/runtime.js +example/example +example/example.exe +example/triangle +example/triangle.exe diff --git a/vendor/wgpu/README.md b/vendor/wgpu/README.md new file mode 100644 index 000000000..3561642f4 --- /dev/null +++ b/vendor/wgpu/README.md @@ -0,0 +1,48 @@ +# WGPU + +A cross-platform (and WASM) GPU API. + +WASM support is achieved by providing wrappers around the browser native WebGPU API +that are called instead of the [wgpu-native](https://github.com/gfx-rs/wgpu-native) library, +the wgpu-native library provides support for all other targets. + +Have a look at the `example/` directory for the rendering of a basic triangle. + +## Getting the wgpu-native libraries + +For native support (not the browser), some libraries are required. Fortunately this is +extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1), +the bindings are for v0.19.4.1 at the moment. + +These are expected in the `lib` folder under the same name as they are released (just unzipped). +By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`), +you can set `-define:WGPU_DEBUG=true` for it to look for a debug version, +and use `-define:WGPU_SHARED=true` to look for the shared libraries. + +## WASM + +For WASM, the module has to be built with a function table to enable callbacks. +You can do so using `-extra-linker-flags:"--export-table"`. + +Being able to allocate is also required (for some auxiliary APIs but also for mapping/unmapping buffers). + +You can set the context that is used for allocations by setting the global variable `wpgu.g_context`. +It will default to the `runtime.default_context`. + +Again, have a look at the `example/` and how it is set up, doing the `--import-memory` and the likes +is not strictly necessary but allows your app more memory than the minimal default. + +The bindings work on both `-target:js_wasm32` and `-target:js_wasm64p32`. + +## GLFW Glue + +There is an inner package `glfwglue` that can be used to glue together WGPU and GLFW. +It exports one procedure `GetSurface(wgpu.Instance, glfw.WindowHandle) -> glfw.Surface`. +The procedure will call the needed target specific procedures and return a surface configured +for the given window. + +To support Wayland on Linux, you need to have GLFW compiled to support it, and use +`-define:WGPU_GFLW_GLUE_SUPPORT_WAYLAND=true` to enable the package to check for Wayland. + +Do note that wgpu does not require GLFW, you can use native windows or another windowing library too. +For that you can take inspiration from `glfwglue` on glueing them together. diff --git a/vendor/wgpu/example/Makefile b/vendor/wgpu/example/Makefile new file mode 100644 index 000000000..f19997881 --- /dev/null +++ b/vendor/wgpu/example/Makefile @@ -0,0 +1,17 @@ +FILES := $(wildcard *) + +# NOTE: changing this requires changing the same values in the `web/index.html`. +INITIAL_MEMORY_PAGES := 2000 +MAX_MEMORY_PAGES := 65536 + +PAGE_SIZE := 65536 +INITIAL_MEMORY_BYTES := $(shell expr $(INITIAL_MEMORY_PAGES) \* $(PAGE_SIZE)) +MAX_MEMORY_BYTES := $(shell expr $(MAX_MEMORY_PAGES) \* $(PAGE_SIZE)) + +web/triangle.wasm: $(FILES) ../wgpu.js ../../wasm/js/runtime.js + odin build . \ + -target:js_wasm32 -out:web/triangle.wasm -o:size \ + -extra-linker-flags:"--export-table --import-memory --initial-memory=$(INITIAL_MEMORY_BYTES) --max-memory=$(MAX_MEMORY_BYTES)" + + cp ../wgpu.js web/wgpu.js + cp ../../wasm/js/runtime.js web/runtime.js diff --git a/vendor/wgpu/example/build.bat b/vendor/wgpu/example/build.bat new file mode 100644 index 000000000..cd3ca63ba --- /dev/null +++ b/vendor/wgpu/example/build.bat @@ -0,0 +1,12 @@ +REM NOTE: changing this requires changing the same values in the `web/index.html`. +set INITIAL_MEMORY_PAGES=2000 +set MAX_MEMORY_PAGES=65536 + +set PAGE_SIZE=65536 +set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE% +set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% + +call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" + +copy "..\wgpu.js" "web\wgpu.js" +copy "..\..\wasm\js\runtime.js" "web\runtime.js" \ No newline at end of file diff --git a/vendor/wgpu/example/main.odin b/vendor/wgpu/example/main.odin new file mode 100644 index 000000000..39161311c --- /dev/null +++ b/vendor/wgpu/example/main.odin @@ -0,0 +1,187 @@ +package vendor_wgpu_example_triangle + +import "base:runtime" + +import "core:fmt" + +import "vendor:wgpu" + +State :: struct { + ctx: runtime.Context, + os: OS, + + instance: wgpu.Instance, + surface: wgpu.Surface, + adapter: wgpu.Adapter, + device: wgpu.Device, + config: wgpu.SurfaceConfiguration, + queue: wgpu.Queue, + module: wgpu.ShaderModule, + pipeline_layout: wgpu.PipelineLayout, + pipeline: wgpu.RenderPipeline, +} + +@(private="file") +state: State + +main :: proc() { + state.ctx = context + + os_init(&state.os) + + state.instance = wgpu.CreateInstance(nil) + if state.instance == nil { + panic("WebGPU is not supported") + } + state.surface = os_get_surface(&state.os, state.instance) + + wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, on_adapter, nil) + + on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: cstring, userdata: rawptr) { + context = state.ctx + if status != .Success || adapter == nil { + fmt.panicf("request adapter failure: [%v] %s", status, message) + } + state.adapter = adapter + wgpu.AdapterRequestDevice(adapter, nil, on_device) + } + + on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: cstring, userdata: rawptr) { + context = state.ctx + if status != .Success || device == nil { + fmt.panicf("request device failure: [%v] %s", status, message) + } + state.device = device + + width, height := os_get_render_bounds(&state.os) + + state.config = wgpu.SurfaceConfiguration { + device = state.device, + usage = { .RenderAttachment }, + format = .BGRA8Unorm, + width = width, + height = height, + presentMode = .Fifo, + alphaMode = .Opaque, + } + wgpu.SurfaceConfigure(state.surface, &state.config) + + state.queue = wgpu.DeviceGetQueue(state.device) + + shader :: ` + @vertex + fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { + let x = f32(i32(in_vertex_index) - 1); + let y = f32(i32(in_vertex_index & 1u) * 2 - 1); + return vec4(x, y, 0.0, 1.0); + } + + @fragment + fn fs_main() -> @location(0) vec4 { + return vec4(1.0, 0.0, 0.0, 1.0); + }` + + state.module = wgpu.DeviceCreateShaderModule(state.device, &{ + nextInChain = &wgpu.ShaderModuleWGSLDescriptor{ + sType = .ShaderModuleWGSLDescriptor, + code = shader, + }, + }) + + state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{}) + state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{ + layout = state.pipeline_layout, + vertex = { + module = state.module, + entryPoint = "vs_main", + }, + fragment = &{ + module = state.module, + entryPoint = "fs_main", + targetCount = 1, + targets = &wgpu.ColorTargetState{ + format = .BGRA8Unorm, + writeMask = wgpu.ColorWriteMaskFlags_All, + }, + }, + primitive = { + topology = .TriangleList, + + }, + multisample = { + count = 1, + mask = 0xFFFFFFFF, + }, + }) + + os_run(&state.os) + } +} + +resize :: proc "c" () { + context = state.ctx + + state.config.width, state.config.height = os_get_render_bounds(&state.os) + wgpu.SurfaceConfigure(state.surface, &state.config) +} + +frame :: proc "c" (dt: f32) { + context = state.ctx + + surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface) + switch surface_texture.status { + case .Success: + // All good, could check for `surface_texture.suboptimal` here. + case .Timeout, .Outdated, .Lost: + // Skip this frame, and re-configure surface. + if surface_texture.texture != nil { + wgpu.TextureRelease(surface_texture.texture) + } + resize() + return + case .OutOfMemory, .DeviceLost: + // Fatal error + fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status) + } + defer wgpu.TextureRelease(surface_texture.texture) + + frame := wgpu.TextureCreateView(surface_texture.texture, nil) + defer wgpu.TextureViewRelease(frame) + + command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil) + defer wgpu.CommandEncoderRelease(command_encoder) + + render_pass_encoder := wgpu.CommandEncoderBeginRenderPass( + command_encoder, &{ + colorAttachmentCount = 1, + colorAttachments = &wgpu.RenderPassColorAttachment{ + view = frame, + loadOp = .Clear, + storeOp = .Store, + clearValue = { r = 0, g = 1, b = 0, a = 1 }, + }, + }, + ) + defer wgpu.RenderPassEncoderRelease(render_pass_encoder) + + wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) + wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) + wgpu.RenderPassEncoderEnd(render_pass_encoder) + + command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) + defer wgpu.CommandBufferRelease(command_buffer) + + wgpu.QueueSubmit(state.queue, { command_buffer }) + wgpu.SurfacePresent(state.surface) +} + +finish :: proc() { + wgpu.RenderPipelineRelease(state.pipeline) + wgpu.PipelineLayoutRelease(state.pipeline_layout) + wgpu.ShaderModuleRelease(state.module) + wgpu.QueueRelease(state.queue) + wgpu.DeviceRelease(state.device) + wgpu.AdapterRelease(state.adapter) + wgpu.SurfaceRelease(state.surface) + wgpu.InstanceRelease(state.instance) +} diff --git a/vendor/wgpu/example/os_glfw.odin b/vendor/wgpu/example/os_glfw.odin new file mode 100644 index 000000000..2b1817fa5 --- /dev/null +++ b/vendor/wgpu/example/os_glfw.odin @@ -0,0 +1,55 @@ +//+build !js +package vendor_wgpu_example_triangle + +import "core:time" + +import "vendor:glfw" +import "vendor:wgpu" +import "vendor:wgpu/glfwglue" + +OS :: struct { + window: glfw.WindowHandle, +} + +os_init :: proc(os: ^OS) { + if !glfw.Init() { + panic("[glfw] init failure") + } + + glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API) + os.window = glfw.CreateWindow(960, 540, "WGPU Native Triangle", nil, nil) + + glfw.SetFramebufferSizeCallback(os.window, size_callback) +} + +os_run :: proc(os: ^OS) { + dt: f32 + + for !glfw.WindowShouldClose(os.window) { + start := time.tick_now() + + glfw.PollEvents() + frame(dt) + + dt = f32(time.duration_seconds(time.tick_since(start))) + } + + finish() + + glfw.DestroyWindow(os.window) + glfw.Terminate() +} + +os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { + iw, ih := glfw.GetWindowSize(os.window) + return u32(iw), u32(ih) +} + +os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { + return glfwglue.GetSurface(instance, os.window) +} + +@(private="file") +size_callback :: proc "c" (window: glfw.WindowHandle, width, height: i32) { + resize() +} diff --git a/vendor/wgpu/example/os_js.odin b/vendor/wgpu/example/os_js.odin new file mode 100644 index 000000000..9634f4afe --- /dev/null +++ b/vendor/wgpu/example/os_js.odin @@ -0,0 +1,60 @@ +package vendor_wgpu_example_triangle + +import "vendor:wgpu" +import "vendor:wasm/js" + +OS :: struct { + initialized: bool, +} + +@(private="file") +g_os: ^OS + +os_init :: proc(os: ^OS) { + g_os = os + assert(js.add_window_event_listener(.Resize, nil, size_callback)) +} + +// NOTE: frame loop is done by the runtime.js repeatedly calling `step`. +os_run :: proc(os: ^OS) { + os.initialized = true +} + +os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { + rect := js.get_bounding_client_rect("body") + return u32(rect.width), u32(rect.height) +} + +os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromCanvasHTMLSelector{ + sType = .SurfaceDescriptorFromCanvasHTMLSelector, + selector = "#wgpu-canvas", + }, + }, + ) +} + +@(private="file", export) +step :: proc(dt: f32) -> bool { + if !g_os.initialized { + return true + } + + frame(dt) + return true +} + +@(private="file", fini) +os_fini :: proc() { + js.remove_window_event_listener(.Resize, nil, size_callback) + + finish() +} + +@(private="file") +size_callback :: proc(e: js.Event) { + resize() +} diff --git a/vendor/wgpu/example/web/index.html b/vendor/wgpu/example/web/index.html new file mode 100644 index 000000000..61872e35a --- /dev/null +++ b/vendor/wgpu/example/web/index.html @@ -0,0 +1,23 @@ + + + + + + WGPU WASM Triangle + + + + + + + + + diff --git a/vendor/wgpu/glfwglue/glue.odin b/vendor/wgpu/glfwglue/glue.odin new file mode 100644 index 000000000..83c497543 --- /dev/null +++ b/vendor/wgpu/glfwglue/glue.odin @@ -0,0 +1,6 @@ +//+build !linux +//+build !windows +//+build !darwin +package wgpu_glfw_glue + +#panic("package wgpu/glfwglue is not supported on the current target") diff --git a/vendor/wgpu/glfwglue/glue_darwin.odin b/vendor/wgpu/glfwglue/glue_darwin.odin new file mode 100644 index 000000000..c1477f4b0 --- /dev/null +++ b/vendor/wgpu/glfwglue/glue_darwin.odin @@ -0,0 +1,23 @@ +package wgpu_glfw_glue + +import "vendor:glfw" +import "vendor:wgpu" +import CA "vendor:darwin/QuartzCore" + +GetSurface :: proc(instance: wgpu.Instance, window: glfw.WindowHandle) -> wgpu.Surface { + ns_window := glfw.GetCocoaWindow(window) + ns_window->contentView()->setWantsLayer(true) + metal_layer := CA.MetalLayer_layer() + ns_window->contentView()->setLayer(metal_layer) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromMetalLayer{ + chain = wgpu.ChainedStruct{ + sType = .SurfaceDescriptorFromMetalLayer, + }, + layer = rawptr(metal_layer), + }, + }, + ) +} diff --git a/vendor/wgpu/glfwglue/glue_linux.odin b/vendor/wgpu/glfwglue/glue_linux.odin new file mode 100644 index 000000000..35c36a37d --- /dev/null +++ b/vendor/wgpu/glfwglue/glue_linux.odin @@ -0,0 +1,43 @@ +package wgpu_glfw_glue + +import "vendor:glfw" +import "vendor:wgpu" + +// GLFW needs to be compiled with wayland support for this to work. +SUPPORT_WAYLAND :: #config(WGPU_GFLW_GLUE_SUPPORT_WAYLAND, false) + +GetSurface :: proc(instance: wgpu.Instance, window: glfw.WindowHandle) -> wgpu.Surface { + when SUPPORT_WAYLAND { + if glfw.GetPlatform() == glfw.PLATFORM_WAYLAND { + display := glfw.GetWaylandDisplay() + surface := glfw.GetWaylandWindow(window) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWaylandSurface{ + chain = { + sType = .SurfaceDescriptorFromWaylandSurface, + }, + display = display, + surface = surface, + }, + }, + ) + } + } + + display := glfw.GetX11Display() + window := glfw.GetX11Window(window) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromXlibWindow{ + chain = { + sType = .SurfaceDescriptorFromXlibWindow, + }, + display = display, + window = u64(window), + }, + }, + ) +} diff --git a/vendor/wgpu/glfwglue/glue_windows.odin b/vendor/wgpu/glfwglue/glue_windows.odin new file mode 100644 index 000000000..73a933f37 --- /dev/null +++ b/vendor/wgpu/glfwglue/glue_windows.odin @@ -0,0 +1,23 @@ +package wgpu_glfw_glue + +import win "core:sys/windows" + +import "vendor:glfw" +import "vendor:wgpu" + +GetSurface :: proc(instance: wgpu.Instance, window: glfw.WindowHandle) -> wgpu.Surface { + hwnd := glfw.GetWin32Window(window) + hinstance := win.GetModuleHandleW(nil) + return wgpu.InstanceCreateSurface( + instance, + &wgpu.SurfaceDescriptor{ + nextInChain = &wgpu.SurfaceDescriptorFromWindowsHWND{ + chain = wgpu.ChainedStruct{ + sType = .SurfaceDescriptorFromWindowsHWND, + }, + hinstance = rawptr(hinstance), + hwnd = rawptr(hwnd), + }, + }, + ) +} diff --git a/vendor/wgpu/lib/.gitkeep b/vendor/wgpu/lib/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll new file mode 100644 index 000000000..650260bfc Binary files /dev/null and b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll differ diff --git a/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll.lib b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll.lib new file mode 100644 index 000000000..b838c2695 Binary files /dev/null and b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll.lib differ diff --git a/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.lib b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.lib new file mode 100644 index 000000000..ea4044d81 Binary files /dev/null and b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.lib differ diff --git a/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.pdb b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.pdb new file mode 100644 index 000000000..b30090276 Binary files /dev/null and b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.pdb differ diff --git a/vendor/wgpu/wgpu.js b/vendor/wgpu/wgpu.js new file mode 100644 index 000000000..4fe78c992 --- /dev/null +++ b/vendor/wgpu/wgpu.js @@ -0,0 +1,2916 @@ +(function() { + +/** + * Assumptions: + * - Ability to allocate memory, set the context to allocate with using the global `wgpu.g_context` + * - Exports a function table (for callbacks), added with `-extra-linker-flags:"--export-table"` + */ +class WebGPUInterface { + + /** + * @param {WasmMemoryInterface} mem + */ + constructor(mem) { + this.mem = mem; + + this.enums = { + FeatureName: [undefined, "depth-clip-control", "depth32float-stencil8", "timestamp-query", "texture-compression-bc", "texture-compression-etc2", "texture-compression-astc", "indirect-first-instance", "shader-f16", "rg11b10ufloat-renderable", "bgra8unorm-storage", "float32-filterable", ], + StoreOp: [undefined, "store", "discard", ], + LoadOp: [undefined, "clear", "load", ], + BufferBindingType: [undefined, "uniform", "storage", "read-only-storage", ], + SamplerBindingType: [undefined, "filtering", "non-filtering", "comparison", ], + TextureSampleType: [undefined, "float", "unfilterable-float", "depth", "sint", "uint", ], + TextureViewDimension: [undefined, "1d", "2d", "2d-array", "cube", "cube-array", "3d", ], + StorageTextureAccess: [undefined, "write-only", "read-only", "read-write", ], + TextureFormat: [undefined, "r8unorm", "r8snorm", "r8uint", "r8sint", "r16uint", "r16sint", "r16float", "rg8unorm", "rg8snorm", "rg8uint", "rg8sint", "r32float", "r32uint", "r32sint", "rg16uint", "rg16sint", "rg16float", "rgba8unorm", "rgba8unorm-srgb", "rgba8snorm", "rgba8uint", "rgba8sint", "bgra8unorm", "bgra8unorm-srgb", "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", "rgb9e5ufloat", "rg32float", "rg32uint", "rg32sint", "rgba16uint", "rgba16sint", "rgba16float", "rgba32float", "rgba32uint", "rgba32sint", "stencil8", "depth16unorm", "depth24plus", "depth24plus-stencil8", "depth32float", "depth32float-stencil8", "bc1-rgba-unorm", "bc1-rgba-unorm-srgb", "bc2-rgba-unorm", "bc2-rgba-unorm-srgb", "bc3-rgba-unorm", "bc3-rgba-unorm-srgb", "bc4-r-unorm", "bc4-r-snorm", "bc5-rg-unorm", "bc5-rg-snorm", "bc6h-rgb-ufloat", "bc6h-rgb-float", "bc7-rgba-unorm", "bc7-rgba-unorm-srgb", "etc2-rgb8unorm", "etc2-rgb8unorm-srgb", "etc2-rgb8a1unorm", "etc2-rgb8a1unorm-srgb", "etc2-rgba8unorm", "etc2-rgba8unorm-srgb", "eac-r11unorm", "eac-r11snorm", "eac-rg11unorm", "eac-rg11snorm", "astc-4x4-unorm", "astc-4x4-unorm-srgb", "astc-5x4-unorm", "astc-5x4-unorm-srgb", "astc-5x5-unorm", "astc-5x5-unorm-srgb", "astc-6x5-unorm", "astc-6x5-unorm-srgb", "astc-6x6-unorm", "astc-6x6-unorm-srgb", "astc-8x5-unorm", "astc-8x5-unorm-srgb", "astc-8x6-unorm", "astc-8x6-unorm-srgb", "astc-8x8-unorm", "astc-8x8-unorm-srgb", "astc-10x5-unorm", "astc-10x5-unorm-srgb", "astc-10x6-unorm", "astc-10x6-unorm-srgb", "astc-10x8-unorm", "astc-10x8-unorm-srgb", "astc-10x10-unorm", "astc-10x10-unorm-srgb", "astc-12x10-unorm", "astc-12x10-unorm-srgb", "astc-12x12-unorm", "astc-12x12-unorm-srgb", ], + QueryType: ["occlusion", "timestamp", ], + VertexStepMode: ["vertex", "instance", "vertex-buffer-not-used", ], + VertexFormat: [undefined, "uint8x2", "uint8x4", "sint8x2", "sint8x4", "unorm8x2", "unorm8x4", "snorm8x2", "snorm8x4", "uint16x2", "uint16x4", "sint16x2", "sint16x4", "unorm16x2", "unorm16x4", "snorm16x2", "snorm16x4", "float16x2", "float16x4", "float32", "float32x2", "float32x3", "float32x4", "uint32", "uint32x2", "uint32x3", "uint32x4", "sint32", "sint32x2", "sint32x3", "sint32x4", ], + PrimitiveTopology: ["point-list", "line-list", "line-strip", "triangle-list", "triangle-strip", ], + IndexFormat: [undefined, "uint16", "uint32", ], + FrontFace: ["ccw", "cw", ], + CullMode: ["none", "front", "back", ], + AddressMode: ["repeat", "mirror-repeat", "clamp-to-edge", ], + FilterMode: ["nearest", "linear", ], + MipmapFilterMode: ["nearest", "linear", ], + CompareFunction: [undefined, "never", "less", "less-equal", "greater", "greater-equal", "equal", "not-equal", "always", ], + TextureDimension: ["1d", "2d", "3d", ], + ErrorType: ["no-error", "validation", "out-of-memory", "internal", "unknown", "device-lost", ], + WGSLFeatureName: [undefined, "readonly_and_readwrite_storage_textures", "packed_4x8_integer_dot_product", "unrestricted_pointer_parameters", "pointer_composite_access", ], + PowerPreference: [undefined, "low-power", "high-performance", ], + CompositeAlphaMode: ["auto", "opaque", "premultiplied", "unpremultiplied", "inherit", ], + StencilOperation: ["keep", "zero", "replace", "invert", "increment-clamp", "decrement-clamp", "increment-wrap", "decrement-wrap", ], + BlendOperation: ["add", "subtract", "reverse-subtract", "min", "max", ], + BlendFactor: ["zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", ], + PresentMode: ["fifo", "fifo-relaxed", "immediate", "mailbox", ], + TextureAspect: ["all", "stencil-only", "depth-only"], + }; + + /** @type {WebGPUObjectManager<{}>} */ + this.instances = new WebGPUObjectManager("Instance", this.mem); + + /** @type {WebGPUObjectManager} */ + this.adapters = new WebGPUObjectManager("Adapter", this.mem); + + /** @type {WebGPUObjectManager} */ + this.bindGroups = new WebGPUObjectManager("BindGroup", this.mem); + + /** @type {WebGPUObjectManager} */ + this.bindGroupLayouts = new WebGPUObjectManager("BindGroupLayout", this.mem); + + /** @type {WebGPUObjectManager<{ buffer: GPUBuffer, mapping: ?{ range: ArrayBuffer, ptr: number, size: number } }>} */ + this.buffers = new WebGPUObjectManager("Buffer", this.mem); + + /** @type {WebGPUObjectManager} */ + this.devices = new WebGPUObjectManager("Device", this.mem); + + /** @type {WebGPUObjectManager} */ + this.commandBuffers = new WebGPUObjectManager("CommandBuffer", this.mem); + + /** @type {WebGPUObjectManager} */ + this.commandEncoders = new WebGPUObjectManager("CommandEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.computePassEncoders = new WebGPUObjectManager("ComputePassEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderPassEncoders = new WebGPUObjectManager("RenderPassEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.querySets = new WebGPUObjectManager("QuerySet", this.mem); + + /** @type {WebGPUObjectManager} */ + this.computePipelines = new WebGPUObjectManager("ComputePipeline", this.mem); + + /** @type {WebGPUObjectManager} */ + this.pipelineLayouts = new WebGPUObjectManager("PipelineLayout", this.mem); + + /** @type {WebGPUObjectManager} */ + this.queues = new WebGPUObjectManager("Queue", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderBundles = new WebGPUObjectManager("RenderBundle", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderBundleEncoders = new WebGPUObjectManager("RenderBundleEncoder", this.mem); + + /** @type {WebGPUObjectManager} */ + this.renderPipelines = new WebGPUObjectManager("RenderPipeline", this.mem); + + /** @type {WebGPUObjectManager} */ + this.samplers = new WebGPUObjectManager("Sampler", this.mem); + + /** @type {WebGPUObjectManager} */ + this.shaderModules = new WebGPUObjectManager("ShaderModule", this.mem); + + /** @type {WebGPUObjectManager} */ + this.surfaces = new WebGPUObjectManager("Surface", this.mem); + + /** @type {WebGPUObjectManager} */ + this.textures = new WebGPUObjectManager("Texture", this.mem); + + /** @type {WebGPUObjectManager} */ + this.textureViews = new WebGPUObjectManager("TextureView", this.mem); + } + + /** + * @param {number|BigInt} src + * @returns {number|BigInt} + */ + uint(src) { + if (this.mem.intSize == 8) { + return BigInt(src); + } else if (this.mem.intSize == 4) { + return src; + } else { + throw new Error("unreachable"); + } + } + + /** + * @param {number|BigInt} src + * @returns {number} + */ + unwrapBigInt(src) { + if (typeof src == "number") { + return src; + } + + const MAX_SAFE_INTEGER = 9007199254740991n; + if (typeof src != "bigint") { + throw new TypeError(`unwrapBigInt got invalid param of type ${typeof src}`); + } + + if (src > MAX_SAFE_INTEGER) { + throw new Error(`unwrapBigInt precision would be lost converting ${src}`); + } + + return Number(src); + } + + /** + * @param {boolean} condition + * @param {string} message + */ + assert(condition, message = "assertion failure") { + if (!condition) { + throw new Error(message); + } + } + + /** + * @template T + * + * @param {number} count + * @param {number} start + * @param {function(number): T} decoder + * @param {number} stride + * @returns {Array} + */ + array(count, start, decoder, stride) { + if (count == 0) { + return []; + } + this.assert(start != 0); + + const out = []; + for (let i = 0; i < count; i += 1) { + out.push(decoder.call(this, start)); + start += stride; + } + return out; + } + + /** + * @param {string} name + * @param {number} ptr + * @returns {`GPU${name}`} + */ + enumeration(name, ptr) { + const int = this.mem.loadI32(ptr); + this.assert(this.enums[name], `Unknown enumeration "${name}"`); + return this.enums[name][int]; + } + + /** + * @param {GPUSupportedFeatures} features + * @param {number} ptr + * @returns {BigInt|number} + */ + genericEnumerateFeatures(features, ptr) { + const availableFeatures = []; + this.enums.FeatureName.forEach((feature, value) => { + if (!feature) { + return; + } + + if (features.has(feature)) { + availableFeatures.push(value); + } + }); + + if (ptr != 0) { + for (let i = 0; i < availableFeatures.length; i += 1) { + this.mem.storeI32(ptr + (i * 4), availableFeatures[i]); + } + } + + return this.uint(availableFeatures.length); + } + + /** + * @param {GPUSupportedLimits} limits + * @param {number} ptr + */ + genericGetLimits(limits, supportedLimitsPtr) { + this.assert(supportedLimitsPtr != 0); + const limitsPtr = supportedLimitsPtr + 8; + + this.mem.storeU32(limitsPtr + 0, limits.maxTextureDimension1D); + this.mem.storeU32(limitsPtr + 4, limits.maxTextureDimension2D); + this.mem.storeU32(limitsPtr + 8, limits.maxTextureDimension3D); + this.mem.storeU32(limitsPtr + 12, limits.maxTextureArrayLayers); + this.mem.storeU32(limitsPtr + 16, limits.maxBindGroups); + this.mem.storeU32(limitsPtr + 20, limits.maxBindGroupsPlusVertexBuffers); + this.mem.storeU32(limitsPtr + 24, limits.maxBindingsPerBindGroup); + this.mem.storeU32(limitsPtr + 28, limits.maxDynamicUniformBuffersPerPipelineLayout); + this.mem.storeU32(limitsPtr + 32, limits.maxDynamicStorageBuffersPerPipelineLayout); + this.mem.storeU32(limitsPtr + 36, limits.maxSampledTexturesPerShaderStage); + this.mem.storeU32(limitsPtr + 40, limits.maxSamplersPerShaderStage); + this.mem.storeU32(limitsPtr + 44, limits.maxStorageBuffersPerShaderStage); + this.mem.storeU32(limitsPtr + 48, limits.maxStorageTexturesPerShaderStage); + this.mem.storeU32(limitsPtr + 52, limits.maxUniformBuffersPerShaderStage); + this.mem.storeU64(limitsPtr + 56, limits.maxUniformBufferBindingSize); + this.mem.storeU64(limitsPtr + 64, limits.maxStorageBufferBindingSize); + this.mem.storeU32(limitsPtr + 72, limits.minUniformBufferOffsetAlignment); + this.mem.storeU32(limitsPtr + 76, limits.minStorageBufferOffsetAlignment); + this.mem.storeU32(limitsPtr + 80, limits.maxVertexBuffers); + this.mem.storeU64(limitsPtr + 88, limits.maxBufferSize); + this.mem.storeU32(limitsPtr + 96, limits.maxVertexAttributes); + this.mem.storeU32(limitsPtr + 100, limits.maxVertexBufferArrayStride); + this.mem.storeU32(limitsPtr + 104, limits.maxInterStageShaderComponents); + this.mem.storeU32(limitsPtr + 108, limits.maxInterStageShaderVariables); + this.mem.storeU32(limitsPtr + 112, limits.maxColorAttachments); + this.mem.storeU32(limitsPtr + 116, limits.maxColorAttachmentBytesPerSample); + this.mem.storeU32(limitsPtr + 120, limits.maxComputeWorkgroupStorageSize); + this.mem.storeU32(limitsPtr + 124, limits.maxComputeInvocationsPerWorkgroup); + this.mem.storeU32(limitsPtr + 128, limits.maxComputeWorkgroupSizeX); + this.mem.storeU32(limitsPtr + 132, limits.maxComputeWorkgroupSizeY); + this.mem.storeU32(limitsPtr + 136, limits.maxComputeWorkgroupSizeZ); + this.mem.storeU32(limitsPtr + 140, limits.maxComputeWorkgroupsPerDimension); + + return true; + } + + /** + * @param {number} ptr + * @returns {GPUFeatureName} + */ + FeatureNamePtr(ptr) { + return this.FeatureName(this.mem.loadI32(ptr)); + } + + /** + * @param {number} featureInt + * @returns {GPUFeatureName} + */ + FeatureName(featureInt) { + return this.enums.FeatureName[featureInt]; + } + + /** + * @param {number} ptr + * @returns {GPUSupportedLimits} + */ + RequiredLimitsPtr(ptr) { + const start = this.mem.loadPtr(ptr); + if (start == 0) { + return undefined; + } + + return this.Limits(start + 8); + } + + /** + * @param {number} start + * @return {GPUSupportedLimits} + */ + Limits(start) { + const limitU32 = (ptr) => { + const value = this.mem.loadU32(ptr); + if (value == 0xFFFFFFFF) { // LIMIT_32_UNDEFINED. + return undefined; + } + return value; + }; + + const limitU64 = (ptr) => { + const part1 = this.mem.loadU32(ptr); + const part2 = this.mem.loadU32(ptr + 4); + if (part1 != 0xFFFFFFFF || part2 != 0xFFFFFFFF) { // LIMIT_64_UNDEFINED. + return this.mem.loadU64(ptr); + } + return undefined; + }; + + return { + maxTextureDimension1D: limitU32(start + 0), + maxTextureDimension2D: limitU32(start + 4), + maxTextureDimension3D: limitU32(start + 8), + maxTextureArrayLayers: limitU32(start + 12), + maxBindGroups: limitU32(start + 16), + maxBindGroupsPlusVertexBuffers: limitU32(start + 20), + maxBindingsPerBindGroup: limitU32(start + 24), + maxDynamicUniformBuffersPerPipelineLayout: limitU32(start + 28), + maxDynamicStorageBuffersPerPipelineLayout: limitU32(start + 32), + maxSampledTexturesPerShaderStage: limitU32(start + 36), + maxSamplersPerShaderStage: limitU32(start + 40), + maxStorageBuffersPerShaderStage: limitU32(start + 44), + maxStorageTexturesPerShaderStage: limitU32(start + 48), + maxUniformBuffersPerShaderStage: limitU32(start + 52), + maxUniformBufferBindingSize: limitU64(start + 56), + maxStorageBufferBindingSize: limitU64(start + 64), + minUniformBufferOffsetAlignment: limitU32(start + 72), + minStorageBufferOffsetAlignment: limitU32(start + 76), + maxVertexBuffers: limitU32(start + 80), + maxBufferSize: limitU64(start + 88), + maxVertexAttributes: limitU32(start + 96), + maxVertexBufferArrayStride: limitU32(start + 100), + maxInterStageShaderComponents: limitU32(start + 104), + maxInterStageShaderVariables: limitU32(start + 108), + maxColorAttachments: limitU32(start + 112), + maxColorAttachmentBytesPerSample: limitU32(start + 116), + maxComputeWorkgroupStorageSize: limitU32(start + 120), + maxComputeInvocationsPerWorkgroup: limitU32(start + 124), + maxComputeWorkgroupSizeX: limitU32(start + 128), + maxComputeWorkgroupSizeY: limitU32(start + 132), + maxComputeWorkgroupSizeZ: limitU32(start + 136), + maxComputeWorkgroupsPerDimension: limitU32(start + 140), + }; + } + + /** + * @param {number} start + * @returns {GPUQueueDescriptor} + */ + QueueDescriptor(start) { + return { + label: this.mem.loadCstring(start + 4), + }; + } + + /** + * @param {number} ptr + * @returns {GPUComputePassTimestampWrites} + */ + ComputePassTimestampWritesPtr(ptr) { + const start = this.mem.loadPtr(ptr); + if (start == 0) { + return undefined; + } + + return { + querySet: this.querySets.get(this.mem.loadPtr(start + 0)), + beginningOfPassWriteIndex: this.mem.loadU32(start + 4), + endOfPassWriteIndex: this.mem.loadU32(start + 8), + }; + } + + /** + * @param {number} start + * @returns {GPURenderPassColorAttachment} + */ + RenderPassColorAttachment(start) { + const viewIdx = this.mem.loadPtr(start + 4); + const resolveTargetIdx = this.mem.loadPtr(start + 8); + + return { + view: viewIdx > 0 ? this.textureViews.get(viewIdx) : undefined, + resolveTarget: resolveTargetIdx > 0 ? this.textureViews.get(resolveTargetIdx) : undefined, + loadOp: this.enumeration("LoadOp", start + 12), + storeOp: this.enumeration("StoreOp", start + 16), + clearValue: this.Color(start + 24), + }; + } + + /** + * @param {number} start + * @returns {GPUColor} + */ + Color(start) { + return { + r: this.mem.loadF64(start + 0), + g: this.mem.loadF64(start + 8), + b: this.mem.loadF64(start + 16), + a: this.mem.loadF64(start + 24), + }; + } + + /** + * @param {number} ptr + * @returns {GPURenderPassDepthStencilAttachment} + */ + RenderPassDepthStencilAttachmentPtr(ptr) { + const start = this.mem.loadPtr(ptr); + if (start == 0) { + return undefined; + } + + return { + view: this.textureViews.get(this.mem.loadPtr(start + 0)), + depthLoadOp: this.enumeration("LoadOp", start + 4), + depthStoreOp: this.enumeration("StoreOp", start + 8), + depthClearValue: this.mem.loadF32(start + 12), + depthReadOnly: this.mem.loadB32(start + 16), + stencilLoadOp: this.enumeration("LoadOp", start + 20), + stencilStoreOp: this.enumeration("StoreOp", start + 24), + stencilClearValue: this.mem.loadF32(start + 28), + stencilReadOnly: this.mem.loadB32(start + 32), + }; + } + + /** + * @param {number} ptr + * @returns {undefined|GPUQuerySet} + */ + QuerySet(ptr) { + ptr = this.mem.loadPtr(ptr); + if (ptr == 0) { + return undefined; + } + + return this.querySets.get(ptr); + } + + /** + * @param {number} ptr + * @returns {GPURenderPassTimestampWrites} + */ + RenderPassTimestampWritesPtr(ptr) { + return this.ComputePassTimestampWritesPtr(ptr); + } + + /** + * @param {number} start + * @returns {GPUImageDataLayout} + */ + TextureDataLayout(start) { + return { + offset: this.mem.loadU64(start + 8), + bytesPerRow: this.mem.loadU32(start + 16), + rowsPerImage: this.mem.loadU32(start + 20), + }; + } + + /** + * @param {number} start + * @returns {GPUImageCopyBuffer} + */ + ImageCopyBuffer(start) { + return { + ...this.TextureDataLayout(start + 8), + buffer: this.buffers.get(this.mem.loadPtr(start + 32)).buffer, + }; + } + + /** + * @param {number} start + * @returns {GPUImageCopyTexture} + */ + ImageCopyTexture(start) { + return { + texture: this.textures.get(this.mem.loadPtr(start + 4)), + mipLevel: this.mem.loadU32(start + 8), + origin: this.Origin3D(start + 12), + aspect: this.enumeration("TextureAspect", start + 24), + }; + } + + /** + * @param {number} start + * @returns {GPUOrigin3D} + */ + Origin3D(start) { + return { + x: this.mem.loadU32(start + 0), + y: this.mem.loadU32(start + 4), + z: this.mem.loadU32(start + 8), + }; + } + + /** + * @param {number} start + * @returns {GPUExtent3D} + */ + Extent3D(start) { + return { + width: this.mem.loadU32(start + 0), + height: this.mem.loadU32(start + 4), + depthOrArrayLayers: this.mem.loadU32(start + 8), + }; + } + + /** + * @param {number} start + * @returns {GPUBindGroupEntry} + */ + BindGroupEntry(start) { + const buffer = this.mem.loadPtr(start + 8); + const sampler = this.mem.loadPtr(start + 32); + const textureView = this.mem.loadPtr(start + 36); + + /** @type {GPUBindingResource} */ + let resource; + if (buffer > 0) { + resource = { + buffer: this.buffers.get(buffer).buffer, + offset: this.mem.loadU64(start + 16), + size: this.mem.loadU64(start + 24), + } + } else if (sampler > 0) { + resource = this.samplers.get(sampler); + } else if (textureView > 0) { + resource = this.textureViews.get(textureView); + } + + return { + binding: this.mem.loadU32(start + 4), + resource: resource, + }; + } + + /** + * @param {number} start + * @returns {GPUBindGroupLayoutEntry} + */ + BindGroupLayoutEntry(start) { + const entry = { + binding: this.mem.loadU32(start + 4), + visibility: this.mem.loadU32(start + 8), + buffer: this.BufferBindingLayout(start + 16), + sampler: this.SamplerBindingLayout(start + 40), + texture: this.TextureBindingLayout(start + 48), + storageTexture: this.StorageTextureBindingLayout(start + 64), + }; + if (!entry.buffer.type) { + entry.buffer = undefined; + } + if (!entry.sampler.type) { + entry.sampler = undefined; + } + if (!entry.texture.sampleType) { + entry.texture = undefined; + } + if (!entry.storageTexture.access) { + entry.storageTexture = undefined; + } + return entry; + } + + /** + * @param {number} start + * @returns {GPUBufferBindingLayout} + */ + BufferBindingLayout(start) { + return { + type: this.enumeration("BufferBindingType", start + 4), + hasDynamicOffset: this.mem.loadB32(start + 8), + minBindingSize: this.mem.loadU64(start + 16), + }; + } + + /** + * @param {number} start + * @returns {GPUSamplerBindingLayout} + */ + SamplerBindingLayout(start) { + return { + type: this.enumeration("SamplerBindingType", start + 4), + }; + } + + /** + * @param {number} start + * @returns {GPUTextureBindingLayout} + */ + TextureBindingLayout(start) { + return { + sampleType: this.enumeration("TextureSampleType", start + 4), + viewDimension: this.enumeration("TextureViewDimension", start + 8), + multisampled: this.mem.loadB32(start + 12), + }; + } + + /** + * @param {number} start + * @returns {GPUStorageTextureBindingLayout} + */ + StorageTextureBindingLayout(start) { + return { + access: this.enumeration("StorageTextureAccess", start + 4), + format: this.enumeration("TextureFormat", start + 8), + viewDimension: this.enumeration("TextureViewDimension", start + 12), + }; + } + + /** + * @param {number} start + * @returns {GPUProgrammableStage} + */ + ProgrammableStageDescriptor(start) { + const constantsArray = this.array( + this.mem.loadUint(start + 8 + this.mem.intSize), + this.mem.loadPtr(start + 8 + this.mem.intSize*2), + this.ConstantEntry, + 16, + ); + return { + module: this.shaderModules.get(this.mem.loadPtr(start + 4)), + entryPoint: this.mem.loadCstring(start + 8), + constants: constantsArray.reduce((prev, curr) => { + prev[curr.key] = curr.value; + return prev; + }, {}), + }; + } + + /** + * @param {number} start + * @returns {{ key: string, value: number }} + */ + ConstantEntry(start) { + return { + key: this.mem.loadCstring(start + 4), + value: this.mem.loadF64(start + 8), + }; + } + + /** + * @param {number} start + * @returns {GPUComputePipelineDescriptor} + */ + ComputePipelineDescriptor(start) { + const layoutIdx = this.mem.loadPtr(start + 8) + return { + label: this.mem.loadCstring(start + 4), + layout: layoutIdx > 0 ? this.pipelineLayouts.get(layoutIdx) : undefined, + compute: this.ProgrammableStageDescriptor(start + 8 + this.mem.intSize), + }; + } + + /** + * @param {number} start + * @returns {GPUVertexState} + */ + VertexState(start) { + let off = 8 + this.mem.intSize; + const constantsArray = this.array( + this.mem.loadUint(start + off), + this.mem.loadPtr(start + off + this.mem.intSize), + this.ConstantEntry, + 16, + ); + + off += this.mem.intSize * 2; + + return { + module: this.shaderModules.get(this.mem.loadPtr(start + 4)), + entryPoint: this.mem.loadCstring(start + 8), + constants: constantsArray.reduce((prev, curr) => { + prev[curr.key] = curr.value; + return prev; + }, {}), + buffers: this.array( + this.mem.loadUint(start + off), + this.mem.loadPtr(start + off + this.mem.intSize), + this.VertexBufferLayout, + this.mem.intSize == 8 ? 32 : 24, + ), + }; + } + + /** + * @param {number} start + * @returns {?GPUVertexBufferLayout} + */ + VertexBufferLayout(start) { + const stepMode = this.enumeration("VertexStepMode", start + 8); + if (stepMode == "vertex-buffer-not-used") { + return null; + } + return { + arrayStride: this.mem.loadU64(start + 0), + stepMode: stepMode, + attributes: this.array( + this.mem.loadUint(start + 8 + this.mem.intSize), + this.mem.loadPtr(start + 8 + this.mem.intSize*2), + this.VertexAttribute, + 24, + ), + }; + } + + /** + * @param {number} start + * @returns {GPUVertexAttribute} + */ + VertexAttribute(start) { + return { + format: this.enumeration("VertexFormat", start + 0), + offset: this.mem.loadU64(start + 8), + shaderLocation: this.mem.loadU32(start + 16), + }; + } + + /** + * @param {number} start + * @returns {GPUPrimitiveState} + */ + PrimitiveState(start) { + let unclippedDepth = undefined; + const nextInChain = this.mem.loadPtr(start); + if (nextInChain != 0) { + const nextInChainType = this.mem.loadI32(nextInChain + 4); + // PrimitiveDepthClipControl = 0x00000007, + if (nextInChainType == 7) { + unclippedDepth = this.mem.loadB32(nextInChain + 8); + } + } + + return { + topology: this.enumeration("PrimitiveTopology", start + 4), + stripIndexFormat: this.enumeration("IndexFormat", start + 8), + frontFace: this.enumeration("FrontFace", start + 12), + cullMode: this.enumeration("CullMode", start + 16), + unclippedDepth: unclippedDepth, + }; + } + + /** + * @param {number} start + * @returns {GPURenderPipelineDescriptor} + */ + RenderPipelineDescriptor(start) { + const layoutIdx = this.mem.loadPtr(start + 8); + const offs = this.mem.intSize == 8 ? [64, 84, 88, 104] : [40, 60, 64, 80]; + return { + label: this.mem.loadCstring(start + 4), + layout: layoutIdx > 0 ? this.pipelineLayouts.get(layoutIdx) : undefined, + vertex: this.VertexState(start + 8 + this.mem.intSize), + primitive: this.PrimitiveState(start + offs[0]), + depthStencil: this.DepthStencilStatePtr(start + offs[1]), + multisample: this.MultisampleState(start + offs[2]), + fragment: this.FragmentStatePtr(start + offs[3]), + }; + } + + /** + * @param {number} start + * @returns {GPUShaderModuleCompilationHint} + */ + ShaderModuleCompilationHint(start) { + return { + entryPoint: this.mem.loadCstring(start + 4), + layout: this.pipelineLayouts.get(this.mem.loadPtr(start + 8)), + }; + } + + /** + * @param {number} ptr + * @returns {?GPUDepthStencilState} + */ + DepthStencilStatePtr(ptr) { + const start = this.mem.loadPtr(ptr); + if (start == 0) { + return undefined; + } + + return { + format: this.enumeration("TextureFormat", start + 4), + depthWriteEnabled: this.mem.loadB32(start + 8), + depthCompare: this.enumeration("CompareFunction", start + 12), + stencilFront: this.StencilFaceState(start + 16), + stencilBack: this.StencilFaceState(start + 32), + stencilReadMask: this.mem.loadU32(start + 48), + stencilWriteMask: this.mem.loadU32(start + 52), + depthBias: this.mem.loadI32(start + 56), + depthBiasSlopeScale: this.mem.loadF32(start + 60), + depthBiasClamp: this.mem.loadF32(start + 64), + }; + } + + /** + * @param {number} start + * @returns {GPUStencilFaceState} + */ + StencilFaceState(start) { + return { + compare: this.enumeration("CompareFunction", start + 0), + failOp: this.enumeration("StencilOperation", start + 4), + depthFailOp: this.enumeration("StencilOperation", start + 8), + passOp: this.enumeration("StencilOperation", start + 12), + }; + } + + /** + * @param {number} start + * @returns {GPUMultisampleState} + */ + MultisampleState(start) { + return { + count: this.mem.loadU32(start + 4), + mask: this.mem.loadU32(start + 8), + alphaToCoverageEnabled: this.mem.loadB32(start + 12), + }; + } + + /** + * @param {number} ptr + * @returns {?GPUFragmentState} + */ + FragmentStatePtr(ptr) { + const start = this.mem.loadPtr(ptr); + if (start == 0) { + return undefined; + } + + let off = 8 + this.mem.intSize; + + const constantsArray = this.array( + this.mem.loadUint(start + off), + this.mem.loadPtr(start + off + this.mem.intSize), + this.ConstantEntry, + 16, + ); + + off += this.mem.intSize * 2; + + return { + module: this.shaderModules.get(this.mem.loadPtr(start + 4)), + entryPoint: this.mem.loadCstring(start + 8), + constants: constantsArray.reduce((prev, curr) => { + prev[curr.key] = curr.value; + return prev; + }, {}), + targets: this.array( + this.mem.loadUint(start + off), + this.mem.loadPtr(start + off + this.mem.intSize), + this.ColorTargetState, + 16, + ), + }; + } + + /** + * @param {number} start + * @returns {GPUColorTargetState} + */ + ColorTargetState(start) { + return { + format: this.enumeration("TextureFormat", start + 4), + blend: this.BlendStatePtr(start + 8), + writeMask: this.mem.loadU32(start + 12), + }; + } + + /** + * @param {number} ptr + * @returns {?GPUBlendState} + */ + BlendStatePtr(ptr) { + const start = this.mem.loadPtr(ptr); + if (start == 0) { + return undefined; + } + + return { + color: this.BlendComponent(start + 0), + alpha: this.BlendComponent(start + 12), + }; + } + + /** + * @param {number} start + * @returns {?GPUBlendComponent} + */ + BlendComponent(start) { + return { + operation: this.enumeration("BlendOperation", start + 0), + srcFactor: this.enumeration("BlendFactor", start + 4), + dstFactor: this.enumeration("BlendFactor", start + 8), + }; + } + + getInterface() { + return { + /** + * @param {0|number} descriptorPtr + * @returns {number} + */ + wgpuCreateInstance: (descriptorPtr) => { + if (!navigator.gpu) { + console.error("WebGPU is not supported by this browser"); + return 0; + } + + return this.instances.create({}); + }, + + /** + * @param {number} deviceIdx + * @param {number} procNamePtr + * @returns {number} + */ + wgpuGetProcAddress: (deviceIdx, procNamePtr) => { + console.error(`unimplemented: wgpuGetProcAddress`); + return 0; + }, + + /* ---------------------- Adapter ---------------------- */ + + /** + * @param {number} adapterIdx + * @param {number} featuresPtr + * @returns {number|BigInt} + */ + wgpuAdapterEnumerateFeatures: (adapterIdx, featuresPtr) => { + const adapter = this.adapters.get(adapterIdx); + return this.genericEnumerateFeatures(adapter.features, featuresPtr); + }, + + /** + * @param {number} adapterIdx + * @param {number} supportedLimitsPtr + * @returns {boolean} + */ + wgpuAdapterGetLimits: (adapterIdx, supportedLimitsPtr) => { + const adapter = this.adapters.get(adapterIdx); + return this.genericGetLimits(adapter.limits, supportedLimitsPtr); + }, + + /** + * @param {number} adapterIdx + * @param {number} propertiesPtr + */ + wgpuAdapterGetProperties: (adapterIdx, propertiesPtr) => { + this.assert(propertiesPtr != 0); + // Unknown adapter. + this.mem.storeI32(propertiesPtr + 28, 3); + // WebGPU backend. + this.mem.storeI32(propertiesPtr + 32, 2); + }, + + /** + * @param {number} adapterIdx + * @param {number} featureInt + * @returns {boolean} + */ + wgpuAdapterHasFeature: (adapterIdx, featureInt) => { + const adapter = this.adapters.get(adapterIdx); + return adapter.features.has(this.enums.FeatureName[featureInt]); + }, + + /** + * @param {number} adapterIdx + * @param {number} callbackPtr + * @param {0|number} userdata + */ + wgpuAdapterRequestAdapterInfo: async (adapterIdx, callbackPtr, userdata) => { + const adapter = this.adapters.get(adapterIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + + const info = await adapter.requestAdapterInfo(); + + const addr = this.mem.exports.wgpu_alloc(16); + + const vendorLength = new TextEncoder().encode(info.vendor).length; + const vendorAddr = this.mem.exports.wgpu_alloc(vendorLength); + this.mem.storeString(vendorAddr, info.vendor); + this.mem.storeI32(addr + 0, vendorAddr); + + const architectureLength = new TextEncoder().encode(info.architecture).length; + const architectureAddr = this.mem.exports.wgpu_alloc(architectureLength); + this.mem.storeString(architectureAddr, info.architecture); + this.mem.storeI32(addr + 4, architectureAddr); + + + const deviceLength = new TextEncoder().encode(info.device).length; + const deviceAddr = this.mem.exports.wgpu_alloc(deviceLength); + this.mem.storeString(deviceAddr, info.device); + this.mem.storeI32(addr + 8, deviceAddr); + + + const descriptionLength = new TextEncoder().encode(info.description).length; + const descriptionAddr = this.mem.exports.wgpu_alloc(descriptionLength); + this.mem.storeString(descriptionAddr, info.description); + this.mem.storeI32(addr + 12, descriptionAddr); + + callback(addr, userdata); + + this.mem.exports.wgpu_free(descriptionAddr); + this.mem.exports.wgpu_free(deviceAddr); + this.mem.exports.wgpu_free(architectureAddr); + this.mem.exports.wgpu_free(vendorAddr); + this.mem.exports.wgpu_free(addr); + }, + + /** + * @param {number} adapterIdx + * @param {0|number} descriptorPtr + * @param {number} callbackPtr + * @param {0|number} userdata + */ + wgpuAdapterRequestDevice: async (adapterIdx, descriptorPtr, callbackPtr, userdata) => { + const adapter = this.adapters.get(adapterIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + + /** @type {GPUDeviceDescriptor} */ + let descriptor; + if (descriptorPtr != 0) { + descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + requiredFeatures: this.array( + this.mem.loadUint(descriptorPtr + 8), + this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize), + this.FeatureNamePtr, + 4, + ), + requiredLimits: this.RequiredLimitsPtr(descriptorPtr + 8 + this.mem.intSize + 4), + defaultQueue: this.QueueDescriptor( descriptorPtr + 8 + this.mem.intSize + 4 + 4), + }; + } + + let deviceIdx; + try { + const device = await adapter.requestDevice(descriptor); + deviceIdx = this.devices.create(device); + // NOTE: don't callback here, any errors that happen later will then be caught by the catch here. + } catch (e) { + console.warn(e); + callback(1, null, null, userdata); + } + + callback(0, deviceIdx, null, userdata); + }, + + ...this.adapters.interface(), + + /* ---------------------- BindGroup ---------------------- */ + + ...this.bindGroups.interface(true), + + /* ---------------------- BindGroupLayout ---------------------- */ + + ...this.bindGroupLayouts.interface(true), + + /* ---------------------- Buffer ---------------------- */ + + /** @param {number} bufferIdx */ + wgpuBufferDestroy: (bufferIdx) => { + const buffer = this.buffers.get(bufferIdx); + buffer.buffer.destroy(); + }, + + /** + * @param {number} bufferIdx + * @param {number|BigInt} offset + * @param {number|BigInt} size + * @returns {number} + */ + wgpuBufferGetMappedRange: (bufferIdx, offset, size) => { + const buffer = this.buffers.get(bufferIdx); + offset = this.unwrapBigInt(offset); + size = this.unwrapBigInt(size); + + this.assert(!buffer.mapping, "buffer already mapped"); + + const range = buffer.buffer.getMappedRange(offset, size); + + const ptr = this.mem.exports.wgpu_alloc(range.byteLength); + + buffer.mapping = { range: range, ptr: ptr, size: range.byteLength }; + return ptr; + }, + + /** + * @param {number} bufferIdx + * @returns {BigInt} + */ + wgpuBufferGetSize: (bufferIdx) => { + const buffer = this.buffers.get(bufferIdx); + return BigInt(buffer.buffer.size); + }, + + /** + * @param {number} bufferIdx + * @returns {number} + */ + wgpuBufferGetUsage: (bufferIdx) => { + const buffer = this.buffers.get(bufferIdx); + return buffer.buffer.usage; + }, + + /** + * @param {number} bufferIdx + * @param {number} mode + * @param {number|BigInt} offset + * @param {number|BigInt} size + * @param {number} callbackPtr + * @param {0|number} userdata + */ + wgpuBufferMapAsync: async (bufferIdx, mode, offset, size, callbackPtr, userdata) => { + const buffer = this.buffers.get(bufferIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + offset = this.unwrapBigInt(offset); + size = this.unwrapBigInt(size); + + if (buffer.buffer.mapState == "pending") { + callback(this.enums.BufferMapAsyncStatus.MappingAlreadyPending, userdata); + } else { + let result; + try { + await buffer.buffer.mapAsync(mode, offset, size); + result = 0; // Success. + } catch(e) { + console.warn(e); + result = 2; // Unknown error. + + if (e instanceof DomException) { + if (e.name == "OperationError") { + result = 1; // Validation error. + } + } + } + + callback(result, userdata); + } + }, + + /** + * @param {number} bufferIdx + * @param {number} labelPtr + */ + wgpuBufferSetLabel: (bufferIdx, labelPtr) => { + const buffer = this.buffers.get(bufferIdx); + buffer.buffer.label = this.mem.loadCstring(labelPtr); + }, + + /** + * @param {number} bufferIdx + */ + wgpuBufferUnmap: (bufferIdx) => { + const buffer = this.buffers.get(bufferIdx); + this.assert(buffer.mapping, "buffer not mapped"); + + const mapping = new Uint8Array(this.mem.memory.buffer, buffer.mapping.ptr, buffer.mapping.size); + (new Uint8Array(buffer.mapping.range)).set(mapping); + + buffer.buffer.unmap(); + + this.mem.exports.wgpu_free(buffer.mapping.ptr); + buffer.mapping = null; + }, + + ...this.buffers.interface(), + + /* ---------------------- CommandBuffer ---------------------- */ + + ...this.commandBuffers.interface(true), + + /* ---------------------- CommandEncoder ---------------------- */ + + /** + * @param {number} commandEncoderIdx + * @param {0|number} descriptorPtr + * @return {number} The compute pass encoder + */ + wgpuCommandEncoderBeginComputePass: (commandEncoderIdx, descriptorPtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + + /** @type {?GPUComputePassDescriptor} */ + let descriptor; + if (descriptorPtr != 0) { + descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + timestampWrites: this.ComputePassTimestampWritesPtr(descriptorPtr + 8), + }; + } + + const computePassEncoder = commandEncoder.beginComputePass(descriptor); + return this.computePassEncoders.create(computePassEncoder); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} descriptorPtr + * @return {number} The render pass encoder + */ + wgpuCommandEncoderBeginRenderPass: (commandEncoderIdx, descriptorPtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + this.assert(descriptorPtr != 0); + + let maxDrawCount = undefined; + const nextInChain = this.mem.loadPtr(descriptorPtr); + if (nextInChain != 0) { + const nextInChainType = this.mem.loadI32(nextInChain + 4); + // RenderPassDescriptorMaxDrawCount = 0x0000000F, + if (nextInChainType == 0x0000000F) { + maxDrawCount = this.mem.loadU64(nextInChain + 8); + } + } + + /** @type {GPURenderPassDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + colorAttachments: this.array( + this.mem.loadUint(descriptorPtr + 8), + this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize), + this.RenderPassColorAttachment, + 56, + ), + depthStencilAttachment: this.RenderPassDepthStencilAttachmentPtr(descriptorPtr + 8 + this.mem.intSize + 4), + occlusionQuerySet: this.QuerySet(descriptorPtr + 8 + this.mem.intSize + 4 + 4), + timestampWrites: this.RenderPassTimestampWritesPtr(descriptorPtr + 8 + this.mem.intSize + 4 + 4), + maxDrawCount: maxDrawCount, + }; + + const renderPassEncoder = commandEncoder.beginRenderPass(descriptor); + return this.renderPassEncoders.create(renderPassEncoder); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} bufferIdx + * @param {BigInt} offset + * @param {BigInt} size + */ + wgpuCommandEncoderClearBuffer: (commandEncoderIdx, bufferIdx, offset, size) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + const buffer = this.buffers.get(bufferIdx); + offset = this.unwrapBigInt(offset); + size = this.unwrapBigInt(size); + commandEncoder.clearBuffer(buffer.buffer, offset, size); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} sourceIdx + * @param {BigInt} sourceOffset + * @param {number} destinationIdx + * @param {BigInt} destinationOffset + * @param {BigInt} size + */ + wgpuCommandEncoderCopyBufferToBuffer: (commandEncoderIdx, sourceIdx, sourceOffset, destinationIdx, destinationOffset, size) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + const source = this.buffers.get(sourceIdx); + const destination = this.buffers.get(destinationIdx); + sourceOffset = this.unwrapBigInt(sourceOffset); + destinationOffset = this.unwrapBigInt(destinationOffset); + size = this.unwrapBigInt(size); + commandEncoder.copyBufferToBuffer(source.buffer, sourceOffset, destination.buffer, destinationOffset, size); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} sourcePtr + * @param {number} destinationPtr + * @param {number} copySizePtr + */ + wgpuCommandEncoderCopyBufferToTexture: (commandEncoderIdx, sourcePtr, destinationPtr, copySizePtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + commandEncoder.copyBufferToTexture( + this.ImageCopyBuffer(sourcePtr), + this.ImageCopyTexture(destinationPtr), + this.Extent3D(copySizePtr), + ); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} sourcePtr + * @param {number} destinationPtr + * @param {number} copySizePtr + */ + wgpuCommandEncoderCopyTextureToBuffer: (commandEncoderIdx, sourcePtr, destinationPtr, copySizePtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + commandEncoder.copyTextureToBuffer( + this.ImageCopyTexture(sourcePtr), + this.ImageCopyBuffer(destinationPtr), + this.Extent3D(copySizePtr), + ); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} sourcePtr + * @param {number} destinationPtr + * @param {number} copySizePtr + */ + wgpuCommandEncoderCopyTextureToTexture: (commandEncoderIdx, sourcePtr, destinationPtr, copySizePtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + commandEncoder.copyTextureToTexture( + this.ImageCopyTexture(sourcePtr), + this.ImageCopyTexture(destinationPtr), + this.Extent3D(copySizePtr), + ); + }, + + /** + * @param {number} commandEncoderIdx + * @param {0|number} descriptorPtr + * @returns {number} The command buffer. + */ + wgpuCommandEncoderFinish: (commandEncoderIdx, descriptorPtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + + /** @type {undefined|GPUCommandBufferDescriptor} */ + let descriptor; + if (descriptorPtr != 0) { + descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + }; + } + + const commandBuffer = commandEncoder.finish(descriptor); + return this.commandBuffers.create(commandBuffer); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} markerLabelPtr + */ + wgpuCommandEncoderInsertDebugMarker: (commandEncoderIdx, markerLabelPtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + commandEncoder.insertDebugMarker(this.mem.loadCstring(markerLabelPtr)); + }, + + /** + * @param {number} commandEncoderIdx + */ + wgpuCommandEncoderPopDebugGroup: (commandEncoderIdx) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + commandEncoder.popDebugGroup(); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} markerLabelPtr + */ + wgpuCommandEncoderPushDebugGroup: (commandEncoderIdx, groupLabelPtr) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + commandEncoder.pushDebugGroup(this.mem.loadCstring(groupLabelPtr)); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} querySetIdx + * @param {number} firstQuery + * @param {number} queryCount + * @param {number} destinationIdx + * @param {BigInt} destinationOffset + */ + wgpuCommandEncoderResolveQuerySet: (commandEncoderIdx, querySetIdx, firstQuery, queryCount, destinationIdx, destinationOffset) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + const querySet = this.querySets.get(querySetIdx); + const destination = this.buffers.get(destinationIdx); + destinationOffset = this.unwrapBigInt(destinationOffset); + commandEncoder.resolveQuerySet(querySet, firstQuery, queryCount, destination.buffer, destinationOffset); + }, + + /** + * @param {number} commandEncoderIdx + * @param {number} querySetIdx + * @param {number} queryIndex + */ + wgpuCommandEncoderWriteTimestamp: (commandEncoderIdx, querySetIdx, queryIndex) => { + const commandEncoder = this.commandEncoders.get(commandEncoderIdx); + const querySet = this.querySets.get(querySetIdx); + commandEncoder.writeTimestamp(querySet, queryIndex); + }, + + ...this.commandEncoders.interface(true), + + /* ---------------------- ComputePassEncoder ---------------------- */ + + + /** + * @param {number} computePassEncoderIdx + * @param {number} workgroupCountX + * @param {number} workgroupCountY + * @param {number} workgroupCountZ + */ + wgpuComputePassEncoderDispachWorkgroups: (computePassEncoderIdx, workgroupCountX, workgroupCountY, workgroupCountZ) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + computePassEncoder.dispatchWorkgroups(workgroupCountX, workgroupCountY, workgroupCountZ); + }, + + /** + * @param {number} computePassEncoderIdx + * @param {number} indirectBufferIdx + * @param {BigInt} indirectOffset + */ + wgpuComputePassEncoderDispachWorkgroupsIndirect: (computePassEncoderIdx, indirectBufferIdx, indirectOffset) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + const indirectBuffer = this.buffers.get(indirectBufferIdx); + indirectOffset = this.unwrapBigInt(indirectOffset); + computePassEncoder.dispatchWorkgroupsIndirect(indirectBuffer.buffer, indirectOffset); + }, + + /** + * @param {number} computePassEncoderIdx + */ + wgpuComputePassEncoderEnd: (computePassEncoderIdx) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + computePassEncoder.end(); + }, + + /** + * @param {number} computePassEncoderIdx + * @param {number} markerLabelPtr + */ + wgpuComputePassEncoderInsertDebugMarker: (computePassEncoderIdx, markerLabelPtr) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + computePassEncoder.insertDebugMarker(this.mem.loadCstring(markerLabelPtr)); + }, + + /** + * @param {number} computePassEncoderIdx + */ + wgpuComputePassEncoderPopDebugGroup: (computePassEncoderIdx) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + computePassEncoder.popDebugGroup(); + }, + + /** + * @param {number} computePassEncoderIdx + * @param {number} markerLabelPtr + */ + wgpuComputePassEncoderPushDebugGroup: (computePassEncoderIdx, groupLabelPtr) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + computePassEncoder.pushDebugGroup(this.mem.loadCstring(groupLabelPtr)); + }, + + /** + * @param {number} computePassEncoderIdx + * @param {number} groupIndex + * @param {0|number} groupIdx + * @param {number|BigInt} dynamicOffsetCount + * @param {number} dynamicOffsetsPtr + */ + wgpuComputePassEncoderSetBindGroup: (computePassEncoderIdx, groupIndex, groupIdx, dynamicOffsetCount, dynamicOffsetsPtr) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount); + + let bindGroup; + if (groupIdx != 0) { + bindGroup = this.bindGroups.get(groupIdx); + } + + const dynamicOffsets = []; + for (let i = 0; i < dynamicOffsetCount; i += 1) { + dynamicOffsets.push(this.mem.loadU32(dynamicOffsetsPtr)); + dynamicOffsetsPtr += 4; + } + + computePassEncoder.setBindGroup(groupIndex, bindGroup, dynamicOffsets); + }, + + /** + * @param {number} computePassEncoderIdx + * @param {number} pipelineIdx + */ + wgpuComputePassEncoderSetPipeline: (computePassEncoderIdx, pipelineIdx) => { + const computePassEncoder = this.computePassEncoders.get(computePassEncoderIdx); + const pipeline = this.computePipelines.get(pipelineIdx); + computePassEncoder.setPipeline(pipeline); + }, + + ...this.computePassEncoders.interface(true), + + /* ---------------------- ComputePipeline ---------------------- */ + + /** + * @param {number} computePipelineIdx + * @param {number} groupIndex + * @returns {number} + */ + wgpuComputePipelineGetBindGroupLayout: (computePipelineIdx, groupIndex) => { + const computePipeline = this.computePipelines.get(computePipelineIdx); + const bindGroupLayout = computePipeline.getBindGroupLayout(groupIndex); + return this.bindGroupLayouts.create(bindGroupLayout); + }, + + ...this.computePipelines.interface(true), + + /* ---------------------- Device ---------------------- */ + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The bind group. + */ + wgpuDeviceCreateBindGroup: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + /** @type {GPUBindGroupDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + layout: this.bindGroupLayouts.get(this.mem.loadPtr(descriptorPtr + 8)), + entries: this.array( + this.mem.loadUint(descriptorPtr + 8 + this.mem.intSize), + this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize * 2), + this.BindGroupEntry, + 40, + ), + }; + + const bindGroup = device.createBindGroup(descriptor); + return this.bindGroups.create(bindGroup); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The bind group layout. + */ + wgpuDeviceCreateBindGroupLayout: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + /** @type {GPUBindGroupLayoutDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + entries: this.array( + this.mem.loadUint(descriptorPtr + 8), + this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize), + this.BindGroupLayoutEntry, + 80, + ), + }; + + const bindGroupLayout = device.createBindGroupLayout(descriptor); + return this.bindGroupLayouts.create(bindGroupLayout); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The buffer. + */ + wgpuDeviceCreateBuffer: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + /** @type {GPUBufferDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + usage: this.mem.loadU32(descriptorPtr + 8), + size: this.mem.loadU64(descriptorPtr + 16), + mappedAtCreation: this.mem.loadB32(descriptorPtr + 24), + }; + + const buffer = device.createBuffer(descriptor); + return this.buffers.create({buffer: buffer, mapping: null}); + }, + + /** + * @param {number} deviceIdx + * @param {0|number} descriptorPtr + * @returns {number} The command encoder. + */ + wgpuDeviceCreateCommandEncoder: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + + /** @type {GPUCommandEncoderDescriptor} */ + let descriptor; + if (descriptor != 0) { + descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + }; + } + + const commandEncoder = device.createCommandEncoder(descriptor); + return this.commandEncoders.create(commandEncoder); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The compute pipeline. + */ + wgpuDeviceCreateComputePipeline: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + const computePipeline = device.createComputePipeline(this.ComputePipelineDescriptor(descriptorPtr)); + return this.computePipelines.create(computePipeline); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @param {number} callbackPtr + * @param {number} userdata + */ + wgpuDeviceCreateComputePipelineAsync: async (deviceIdx, descriptorPtr, callbackPtr, userdata) => { + const device = this.devices.get(deviceIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + this.assert(descriptorPtr != 0); + + let result; + let resultIdx; + try { + const computePipeline = await device.createComputePipelineAsync(this.ComputePipelineDescriptor(descriptorPtr)); + resultIdx = this.computePipelines.create(computePipeline); + result = 0; /* Success */ + // NOTE: don't callback here, any errors that happen later will then be caught by the catch here. + } catch (e) { + console.warn(e); + result = 5; /* Unknown error */ + } + + callback(result, resultIdx, null, userdata); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The pipeline layout. + */ + wgpuDeviceCreatePipelineLayout: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + /** @type {GPUPipelineLayoutDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + bindGroupLayouts: this.array( + this.mem.loadUint(descriptorPtr + 8), + this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize), + (ptr) => this.bindGroupLayouts.get(this.mem.loadPtr(ptr)), + 4, + ), + }; + + const pipelineLayout = device.createPipelineLayout(descriptor); + return this.pipelineLayouts.create(pipelineLayout); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The query set. + */ + wgpuDeviceCreateQuerySet: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + /** @type {GPUQuerySetDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + type: this.QueryType(descriptorPtr + 8), + count: this.mem.loadU32(descriptorPtr + 12), + }; + + const querySet = device.createQuerySet(descriptor); + return this.querySets.create(querySet); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The query set. + */ + wgpuDeviceCreateRenderBundleEncoder: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + /** @type {GPURenderBundleEncoderDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + colorFormats: this.array( + this.mem.loadUint(descriptorPtr + 8), + this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize), + this.TextureFormat, + 4, + ), + depthStencilFormat: this.enumeration("TextureFormat", descriptorPtr + 8 + this.mem.intSize + 4), + sampleCount: this.mem.loadU32(descriptorPtr + 8 + this.mem.intSize + 8), + depthReadOnly: this.mem.loadB32(descriptorPtr + 8 + this.mem.intSize + 12), + stencilReadOnly: this.mem.loadB32(descriptorPtr + 8 + this.mem.intSize + 16), + }; + + const renderBundleEncoder = device.createRenderBundleEncoder(descriptor); + return this.renderBundleEncoders.create(renderBundleEncoder); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The render pipeline. + */ + wgpuDeviceCreateRenderPipeline: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + const descriptor = this.RenderPipelineDescriptor(descriptorPtr); + const renderPipeline = device.createRenderPipeline(descriptor); + return this.renderPipelines.create(renderPipeline); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @param {number} callbackPtr + * @param {number} userdata + */ + wgpuDeviceCreateRenderPipelineAsync: async (deviceIdx, descriptorPtr, callbackPtr, userdata) => { + const device = this.devices.get(deviceIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + this.assert(descriptorPtr != 0); + + let result; + let resultIdx; + try { + const renderPipeline = await device.createRenderPipelineAsync(this.RenderPipelineDescriptor(descriptorPtr)); + resultIdx = this.renderPipelines.create(renderPipeline); + result = 0; /* Success */ + // NOTE: don't callback here, any errors that happen later will then be caught by the catch here. + } catch (e) { + console.warn(e); + result = 5; /* Unknown error */ + } + + callback(result, resultIdx, null, userdata); + }, + + /** + * @param {number} deviceIdx + * @param {0|number} descriptorPtr + * @returns {number} The sampler. + */ + wgpuDeviceCreateSampler: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + + /** @type {?GPUSamplerDescriptor} */ + let descriptor; + if (descriptorPtr != 0) { + descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + addressModeU: this.enumeration("AddressMode", descriptorPtr + 8), + addressModeV: this.enumeration("AddressMode", descriptorPtr + 12), + addressModeW: this.enumeration("AddressMode", descriptorPtr + 16), + magFilter: this.enumeration("FilterMode", descriptorPtr + 20), + minFilter: this.enumeration("FilterMode", descriptorPtr + 24), + mipMapFilter: this.enumeration("MipmapFilterMode", descriptorPtr + 28), + lodMinClamp: this.mem.loadF32(descriptorPtr + 32), + lodMaxClamp: this.mem.loadF32(descriptorPtr + 36), + compare: this.enumeration("CompareFunction", descriptorPtr + 40), + maxAnisotropy: this.mem.loadU16(descriptorPtr + 44), + }; + } + + const sampler = device.createSampler(descriptor); + return this.samplers.create(sampler); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The shader module. + */ + wgpuDeviceCreateShaderModule: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + const nextInChain = this.mem.loadPtr(descriptorPtr); + const nextInChainType = this.mem.loadI32(nextInChain + 4); + + // ShaderModuleWGSLDescriptor = 0x00000006, + if (nextInChainType != 6) { + throw new TypeError(`Descriptor type should be 'ShaderModuleWGSLDescriptor', got ${nextInChainType}`); + } + + /** @type {GPUShaderModuleDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + code: this.mem.loadCstring(nextInChain + 8), + compilationHints: this.array( + this.mem.loadUint(descriptorPtr + 8), + this.mem.loadPtr(descriptorPtr + 8 + this.mem.intSize), + this.ShaderModuleCompilationHint, + 12, + ), + }; + + const shaderModule = device.createShaderModule(descriptor); + return this.shaderModules.create(shaderModule); + }, + + /** + * @param {number} deviceIdx + * @param {number} descriptorPtr + * @returns {number} The texture. + */ + wgpuDeviceCreateTexture: (deviceIdx, descriptorPtr) => { + const device = this.devices.get(deviceIdx); + this.assert(descriptorPtr != 0); + + /** @type {GPUTextureDescriptor} */ + const descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + usage: this.mem.loadU32(descriptorPtr + 8), + dimension: this.enumeration("TextureDimension", descriptorPtr + 12), + size: this.Extent3D(descriptorPtr + 16), + format: this.enumeration("TextureFormat", descriptorPtr + 28), + mipLevelCount: this.mem.loadU32(descriptorPtr + 32), + sampleCount: this.mem.loadU32(descriptorPtr + 36), + viewFormats: this.array( + this.mem.loadUint(descriptorPtr + 40), + this.mem.loadPtr(descriptorPtr + 40 + this.mem.intSize), + (ptr) => this.enumeration("TextureFormat", ptr), + 4, + ), + }; + + const texture = device.createTexture(descriptor); + return this.textures.create(texture); + }, + + /** + * @param {number} deviceIdx + */ + wgpuDeviceDestroy: (deviceIdx) => { + const device = this.devices.get(deviceIdx); + device.destroy(); + }, + + /** + * @param {number} deviceIdx + * @param {number} featuresPtr + * @returns {number|BigInt} + */ + wgpuDeviceEnumerateFeatures: (deviceIdx, featuresPtr) => { + const device = this.devices.get(deviceIdx); + return this.genericEnumerateFeatures(device.features, featuresPtr); + }, + + /** + * @param {number} deviceIdx + * @param {number} limitsPtr + * @returns {boolean} + */ + wgpuDeviceGetLimits: (deviceIdx, limitsPtr) => { + const device = this.devices.get(deviceIdx); + return this.genericGetLimits(device.limits, limitsPtr); + }, + + /** + * @param {number} deviceIdx + * @returns {number} + */ + wgpuDeviceGetQueue: (deviceIdx) => { + const device = this.devices.get(deviceIdx); + return this.queues.create(device.queue); + }, + + /** + * @param {number} deviceIdx + * @param {number} featureInt + * @returns {boolean} + */ + wgpuDeviceHasFeature: (deviceIdx, featureInt) => { + const device = this.devices.get(deviceIdx); + return device.features.has(this.enums.FeatureName[featureInt]); + }, + + /** + * @param {number} deviceIdx + * @param {number} callbackPtr + * @param {number} userdata + */ + wgpuDevicePopErrorScope: async (deviceIdx, callbackPtr, userdata) => { + const device = this.devices.get(deviceIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + const error = await device.popErrorScope(); + if (!error) { + callback(0, null, userdata); + return; + } + console.warn(error); + let status = 4; + if (error instanceof GPUValidationError) { + status = 1; + } else if (error instanceof GPUOutOfMemoryError) { + status = 2; + } else if (error instanceof GPUInternalError) { + status = 3; + } + callback(status, null, userdata); + }, + + /** + * @param {number} deviceIdx + * @param {number} filterInt + */ + wgpuDevicePushErrorScope: (deviceIdx, filterInt) => { + const device = this.devices.get(deviceIdx); + device.pushErrorScope(this.enums.ErrorFilter[filterInt]); + }, + + /** + * @param {number} deviceIdx + * @param {number} callbackPtr + * @param {number} userdata + */ + wgpuDeviceSetUncapturedErrorCallback: (deviceIdx, callbackPtr, userdata) => { + const device = this.devices.get(deviceIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + + device.onuncapturederror = (ev) => { + console.warn(ev.error); + let status = 4; + if (error instanceof GPUValidationError) { + status = 1; + } else if (error instanceof GPUOutOfMemoryError) { + status = 2; + } else if (error instanceof GPUInternalError) { + status = 3; + } + callback(status, null, userdata); + }; + }, + + ...this.devices.interface(true), + + /* ---------------------- Instance ---------------------- */ + + /** + * @param {number} instanceIdx + * @param {number} descriptorPtr + */ + wgpuInstanceCreateSurface: (instanceIdx, descriptorPtr) => { + this.assert(instanceIdx > 0); + this.assert(descriptorPtr != 0); + + const nextInChain = this.mem.loadPtr(descriptorPtr); + const nextInChainType = this.mem.loadI32(nextInChain + 4); + + // SurfaceDescriptorFromCanvasHTMLSelector = 0x00000004, + if (nextInChainType != 4) { + throw new TypeError(`Descriptor type should be 'SurfaceDescriptorFromCanvasHTMLSelector', got ${nextInChainType}`); + } + + const selector = this.mem.loadCstring(nextInChain + 8); + const surface = document.querySelector(selector); + if (!surface) { + throw new Error(`Selector '${selector}' did not match any element`); + } + if (!(surface instanceof HTMLCanvasElement)) { + throw new Error('Selector matches an element that is not a canvas'); + } + + return this.surfaces.create(surface); + }, + + /** + * @param {number} instanceIdx + * @param {number} featureInt + * @returns {boolean} + */ + wgpuInstanceHasWGSLLanguageFeature: (instanceIdx, featureInt) => { + return navigator.gpu.wgslLanguageFeatures.has(this.enums.WGSLFeatureName[featureInt]); + }, + + /** + * @param {number} instanceIdx + */ + wgpuInstanceProcessEvents: (instanceIdx) => { + console.warn("unimplemented: wgpuInstanceProcessEvents"); + }, + + /** + * @param {number} instanceIdx + * @param {0|number} optionsPtr + * @param {number} callbackPtr + * @param {number} userdata + */ + wgpuInstanceRequestAdapter: async (instanceIdx, optionsPtr, callbackPtr, userdata) => { + this.assert(instanceIdx > 0); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + + /** @type {GPURequestAdapterOptions} */ + let options; + if (optionsPtr != 0) { + options = { + powerPreference: this.enumeration("PowerPreference", optionsPtr + 8), + forceFallbackAdapter: this.mem.loadB32(optionsPtr + 16), + }; + } + + let adapterIdx; + try { + const adapter = await navigator.gpu.requestAdapter(options); + adapterIdx = this.adapters.create(adapter); + // NOTE: don't callback here, any errors that happen later will then be caught by the catch here. + } catch(e) { + console.warn(e); + callback(2, null, null, userdata); + } + + callback(0, adapterIdx, null, userdata); + }, + + ...this.instances.interface(false), + + /* ---------------------- PipelineLayout ---------------------- */ + + ...this.pipelineLayouts.interface(true), + + /* ---------------------- QuerySet ---------------------- */ + + /** + * @param {number} querySetIdx + */ + wgpuQuerySetDestroy: (querySetIdx) => { + const querySet = this.querySets.get(querySetIdx); + querySet.destroy(); + }, + + /** + * @param {number} querySetIdx + * @returns {number} + */ + wgpuQuerySetGetCount: (querySetIdx) => { + const querySet = this.querySets.get(querySetIdx); + return querySet.count; + }, + + /** + * @param {number} querySetIdx + * @returns {number} + */ + wgpuQuerySetGetType: (querySetIdx) => { + const querySet = this.querySets.get(querySetIdx); + return this.enums.QueryType.indexOf(querySet.type); + }, + + ...this.querySets.interface(true), + + /* ---------------------- Queue ---------------------- */ + + /** + * @param {number} queueIdx + * @param {number} callbackPtr + * @param {number} userdata + */ + wgpuQueueOnSubmittedWorkDone: async (queueIdx, callbackPtr, userdata) => { + const queue = this.queues.get(queueIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + let result; + try { + await queue.onSubmittedWorkDone(); + result = 0; + } catch(e) { + console.warn(e); + result = 1; + } + callback(result, userdata); + }, + + /** + * @param {number} queueIdx + * @param {BigInt|number} commandCount + * @param {number} commandsPtr + */ + wgpuQueueSubmit: (queueIdx, commandCount, commandsPtr) => { + const queue = this.queues.get(queueIdx); + const commands = this.array( + this.unwrapBigInt(commandCount), + commandsPtr, + (ptr) => this.commandBuffers.get(this.mem.loadPtr(ptr)), + 4, + ); + queue.submit(commands); + }, + + /** + * @param {number} queueIdx + * @param {number} bufferIdx + * @param {BigInt} bufferOffset + * @param {number} dataPtr + * @param {number|BigInt} size + */ + wgpuQueueWriteBuffer: (queueIdx, bufferIdx, bufferOffset, dataPtr, size) => { + const queue = this.queues.get(queueIdx); + const buffer = this.buffers.get(bufferIdx); + bufferOffset = this.unwrapBigInt(bufferOffset); + size = this.unwrapBigInt(size); + queue.writeBuffer(buffer.buffer, bufferOffset, this.mem.loadBytes(dataPtr, size), 0, size); + }, + + /** + * @param {number} queueIdx + * @param {number} destinationPtr + * @param {number} dataPtr + * @param {number|BigInt} dataSize + * @param {number} dataLayoutPtr + * @param {number} writeSizePtr + */ + wgpuQueueWriteTexture: (queueIdx, destinationPtr, dataPtr, dataSize, dataLayoutPtr, writeSizePtr) => { + const queue = this.queues.get(queueIdx); + const destination = this.ImageCopyTexture(destinationPtr); + dataSize = this.unwrapBigInt(dataSize); + const dataLayout = this.TextureDataLayout(dataLayoutPtr); + const writeSize = this.Extent3D(writeSizePtr); + queue.writeTexture(destination, this.mem.loadBytes(dataPtr, dataSize), dataLayout, writeSize); + }, + + ...this.queues.interface(true), + + /* ---------------------- RenderBundle ---------------------- */ + + ...this.renderBundles.interface(true), + + /* ---------------------- RenderBundleEncoder ---------------------- */ + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} vertexCount + * @param {number} instanceCount + * @param {number} firstVertex + * @param {number} firstInstance + */ + wgpuRenderBundleEncoderDraw: (renderBundleEncoderIdx, vertexCount, instanceCount, firstVertex, firstInstance) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + renderBundleEncoder.draw(vertexCount, instanceCount, firstVertex, firstInstance); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} indexCount + * @param {number} instanceCount + * @param {number} firstIndex + * @param {number} baseVertex + * @param {number} firstInstance + */ + wgpuRenderBundleEncoderDrawIndexed: (renderBundleEncoderIdx, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + renderBundleEncoder.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} indirectBufferIdx + * @param {BigInt} indirectOffset + */ + wgpuRenderBundleEncoderDrawIndexedIndirect: (renderBundleEncoderIdx, indirectBufferIdx, indirectOffset) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + indirectOffset = this.unwrapBigInt(indirectOffset); + const buffer = this.buffers.get(indirectBufferIdx); + renderBundleEncoder.drawIndexedIndirect(buffer.buffer, indirectOffset); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} indirectBufferIdx + * @param {BigInt} indirectOffset + */ + wgpuRenderBundleEncoderDrawIndirect: (renderBundleEncoderIdx, indirectBufferIdx, indirectOffset) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + indirectOffset = this.unwrapBigInt(indirectOffset); + const buffer = this.buffers.get(indirectBufferIdx); + renderBundleEncoder.drawIndirect(buffer.buffer, indirectOffset); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {0|number} descriptorPtr + * @returns {number} + */ + wgpuRenderBundleEncoderFinish: (renderBundleEncoderIdx, descriptorPtr) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + + /** @type {?GPURenderBundleDescriptor} */ + let descriptor; + if (descriptorPtr != 0) { + descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + }; + } + + const renderBundle = renderBundleEncoder.finish(descriptor); + return this.renderBundles.create(renderBundle); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} markerLabelPtr + */ + wgpuRenderBundleEncoderInsertDebugMarker: (renderBundleEncoderIdx, markerLabelPtr) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + this.assert(markerLabelPtr != 0); + const markerLabel = this.mem.loadCstring(markerLabelPtr); + renderBundleEncoder.insertDebugMarker(markerLabel); + }, + + /** + * @param {number} renderBundleEncoderIdx + */ + wgpuRenderBundleEncoderPopDebugGroup: (renderBundleEncoderIdx) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + renderBundleEncoder.popDebugGroup(); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} groupLabelPtr + */ + wgpuRenderBundleEncoderPushDebugGroup: (renderBundleEncoderIdx, groupLabelPtr) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + this.assert(groupLabelPtr!= 0); + const groupLabel = this.mem.loadCstring(groupLabelPtr); + renderBundleEncoder.pushDebugGroup(groupLabel); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} groupIndex + * @param {0|number} groupIdx + * @param {number|BigInt} dynamicOffsetCount + * @param {number} dynamicOffsetsPtr + */ + wgpuRenderBundleEncoderSetBindGroup: (renderBundleEncoderIdx, groupIndex, groupIdx, dynamicOffsetCount, dynamicOffsetsPtr) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + + let group; + if (groupIdx > 0) { + group = this.bindGroups.get(groupIdx); + } + + dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount); + const dynamicOffsets = this.array(dynamicOffsetCount, dynamicOffsetsPtr, this.mem.loadU32, 4); + + renderBundleEncoder.setBindGroup(groupIndex, group, dynamicOffsets); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} bufferIdx + * @param {number} formatInt + * @param {BigInt} offset + * @param {BigInt} size + */ + wgpuRenderBundleEncoderSetIndexBuffer: (renderBundleEncoderIdx, bufferIdx, formatInt, offset, size) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + const buffer = this.buffers.get(bufferIdx); + const format = this.enums.IndexFormat[formatInt]; + offset = this.unwrapBigInt(offset); + size = this.unwrapBigInt(size); + renderBundleEncoder.setIndexBuffer(buffer.buffer, format, offset, size); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} pipelineIdx + */ + wgpuRenderBundleEncoderSetPipeline: (renderBundleEncoderIdx, pipelineIdx) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + const pipeline = this.renderPipelines.get(pipelineIdx); + renderBundleEncoder.setPipeline(pipeline); + }, + + /** + * @param {number} renderBundleEncoderIdx + * @param {number} slot + * @param {0|number} bufferIdx + * @param {BigInt} offset + * @param {BigInt} size + */ + wgpuRenderBundleEncoderSetVertexBuffer: (renderBundleEncoderIdx, slot, bufferIdx, offset, size) => { + const renderBundleEncoder = this.renderBundleEncoders.get(renderBundleEncoderIdx); + + let buffer; + if (bufferIdx > 0) { + buffer = this.buffers.get(bufferIdx).buffer; + } + + offset = this.unwrapBigInt(offset); + size = this.unwrapBigInt(size); + renderBundleEncoder.setVertexBuffer(slot, buffer, offset, size); + }, + + ...this.renderBundleEncoders.interface(true), + + /* ---------------------- RenderPassEncoder ---------------------- */ + + /** + * @param {number} renderPassEncoderIdx + * @param {number} queryIndex + */ + wgpuRenderPassEncoderBeginOcclusionQuery: (renderPassEncoderIdx, queryIndex) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.beginOcclusionQuery(queryIndex); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} vertexCount + * @param {number} instanceCount + * @param {number} firstVertex + * @param {number} firstInstance + */ + wgpuRenderPassEncoderDraw: (renderPassEncoderIdx, vertexCount, instanceCount, firstVertex, firstInstance) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.draw(vertexCount, instanceCount, firstVertex, firstInstance); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} indexCount + * @param {number} instanceCount + * @param {number} firstIndex + * @param {number} baseVertex + * @param {number} firstInstance + */ + wgpuRenderPassEncoderDrawIndexed: (renderPassEncoderIdx, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} indirectBufferIdx + * @param {BigInt} indirectOffset + */ + wgpuRenderPassEncoderDrawIndexedIndirect: (renderPassEncoderIdx, indirectBufferIdx, indirectOffset) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + const buffer = this.buffers.get(indirectBufferIdx); + indirectOffset = this.unwrapBigInt(indirectOffset); + renderPassEncoder.drawIndexedIndirect(buffer.buffer, indirectOffset); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} indirectBufferIdx + * @param {BigInt} indirectOffset + */ + wgpuRenderPassEncoderDrawIndirect: (renderPassEncoderIdx, indirectBufferIdx, indirectOffset) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + const buffer = this.buffers.get(indirectBufferIdx); + indirectOffset = this.unwrapBigInt(indirectOffset); + renderPassEncoder.drawIndirect(buffer.buffer, indirectOffset); + }, + + /** + * @param {number} renderPassEncoderIdx + */ + wgpuRenderPassEncoderEnd: (renderPassEncoderIdx) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.end(); + }, + + /** + * @param {number} renderPassEncoderIdx + */ + wgpuRenderPassEncoderEndOcclusionQuery: (renderPassEncoderIdx) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.endOcclusionQuery(); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number|BigInt} bundleCount + * @param {number} bundlesPtr + */ + wgpuRenderPassEncoderExecuteBundles: (renderPassEncoderIdx, bundleCount, bundlesPtr) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + bundleCount = this.unwrapBigInt(bundleCount); + const bundles = this.array( + bundleCount, + bundlesPtr, + (ptr) => this.renderBundles.get(this.mem.loadPtr(ptr)), + 4, + ); + renderPassEncoder.executeBundles(bundles); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} markerLabelPtr + */ + wgpuRenderPassEncoderInsertDebugMarker: (renderPassEncoderIdx, markerLabelPtr) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + const markerLabel = this.mem.loadCstring(markerLabelPtr); + renderPassEncoder.insertDebugMarker(markerLabel); + }, + + /** + * @param {number} renderPassEncoderIdx + */ + wgpuRenderPassEncoderPopDebugGroup: (renderPassEncoderIdx) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.popDebugGroup(); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} groupLabelPtr + */ + wgpuRenderPassEncoderPushDebugGroup: (renderPassEncoderIdx, groupLabelPtr) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + const groupLabel = this.mem.loadCstring(groupLabelPtr); + renderPassEncoder.pushDebugGroup(groupLabel); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} groupIndex + * @param {0|number} groupIdx + * @param {number|BigInt} dynamicOffsetCount + * @param {number} dynamicOffsetsPtr + */ + wgpuRenderPassEncoderSetBindGroup: (renderPassEncoderIdx, groupIndex, groupIdx, dynamicOffsetCount, dynamicOffsetsPtr) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + + let group; + if (groupIdx > 0) { + group = this.bindGroups.get(groupIdx); + } + + dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount); + const dynamicOffsets = this.array(dynamicOffsetCount, dynamicOffsetsPtr, this.mem.loadU32, 4); + + renderPassEncoder.setBindGroup(groupIndex, group, dynamicOffsets); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} bufferIdx + * @param {number} formatInt + * @param {BigInt} offset + * @param {BigInt} size + */ + wgpuRenderPassEncoderSetIndexBuffer: (renderPassEncoderIdx, bufferIdx, formatInt, offset, size) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + const buffer = this.buffers.get(bufferIdx); + const format = this.enums.IndexFormat[formatInt]; + offset = this.unwrapBigInt(offset); + size = this.unwrapBigInt(size); + renderPassEncoder.setIndexBuffer(buffer.buffer, format, offset, size); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} pipelineIdx + */ + wgpuRenderPassEncoderSetPipeline: (renderPassEncoderIdx, pipelineIdx) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + const pipeline = this.renderPipelines.get(pipelineIdx); + renderPassEncoder.setPipeline(pipeline); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + */ + wgpuRenderPassEncoderSetScissorRect: (renderPassEncoderIdx, x, y, width, height) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.setScissorRect(x, y, width, height); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} reference + */ + wgpuRenderPassEncoderSetStencilReference: (renderPassEncoderIdx, reference) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.setStencilReference(reference); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} slot + * @param {0|number} bufferIdx + * @param {BigInt} offset + * @param {BigInt} size + */ + wgpuRenderPassEncoderSetVertexBuffer: (renderPassEncoderIdx, slot, bufferIdx, offset, size) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + + let buffer; + if (bufferIdx > 0) { + buffer = this.buffers.get(bufferIdx).buffer; + } + + offset = this.unwrapBigInt(offset); + size = this.unwrapBigInt(size); + renderPassEncoder.setVertexBuffer(slot, buffer, offset, size); + }, + + /** + * @param {number} renderPassEncoderIdx + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + * @param {number} minDepth + * @param {number} maxDepth + */ + wgpuRenderPassEncoderSetViewport: (renderPassEncoderIdx, x, y, width, height, minDepth, maxDepth) => { + const renderPassEncoder = this.renderPassEncoders.get(renderPassEncoderIdx); + renderPassEncoder.setViewport(x, y, width, height, minDepth, maxDepth); + }, + + ...this.renderPassEncoders.interface(true), + + /* ---------------------- RenderPipeline ---------------------- */ + + /** + * @param {number} renderPipelineIdx + * @param {number} groupIndex + * @returns {number} + */ + wgpuRenderPipelineGetBindGroupLayout: (renderPipelineIdx, groupIndex) => { + const renderPipeline = this.renderPipelines.get(renderPipelineIdx); + const bindGroupLayout = renderPipeline.getBindGroupLayout(groupIndex); + return this.bindGroupLayouts.create(bindGroupLayout); + }, + + ...this.renderPipelines.interface(true), + + /* ---------------------- Sampler ---------------------- */ + + ...this.samplers.interface(true), + + /* ---------------------- ShaderModule ---------------------- */ + + /** + * @param {number} shaderModuleIdx + * @param {number} callbackPtr + * @param {number} userdata + */ + wgpuShaderModuleGetCompilationInfo: async (shaderModuleIdx, callbackPtr, userdata) => { + const shaderModule = this.shaderModules.get(shaderModuleIdx); + const callback = this.mem.exports.__indirect_function_table.get(callbackPtr); + + let status = 0; + let retAddr = 0; + + const ptrsToFree = []; + + try { + const compilationInfo = await shaderModule.getCompilationInfo(); + + const size = compilationInfo.messages.length * 72; + const addr = this.mem.exports.wgpu_alloc(size); + ptrsToFree.push(addr); + compilationInfo.messages.forEach((message, i) => { + const messageLength = new TextEncoder().encode(message.message).length; + const messageAddr = this.mem.exports.wgpu_alloc(messageLength); + ptrsToFree.push(messageAddr); + this.mem.storeString(messageAddr, message.message); + this.mem.storeI32(addr + (i * size) + 4); + + this.mem.storeI32(addr + (i * size) + 8, this.enums.CompilationMessageType.indexOf(message.type)); + + this.mem.storeU64(addr + (i * size) + 16, message.lineNum); + this.mem.storeU64(addr + (i * size) + 24, message.linePos); + this.mem.storeU64(addr + (i * size) + 32, message.offset); + this.mem.storeU64(addr + (i * size) + 40, message.length); + + // TODO: UTF16 units. + this.mem.storeU64(addr + (i * size) + 48, message.linePos); + this.mem.storeU64(addr + (i * size) + 56, message.offset); + this.mem.storeU64(addr + (i * size) + 64, message.length); + }); + + retAddr = this.mem.exports.wgpu_alloc(3*this.mem.intSize); + ptrsToFree.push(retAddr); + this.mem.storeUint(retAddr + this.mem.intSize, compilationInfo.messages.length); + this.mem.storeI32(retAddr + this.mem.intSize*2, addr); + } catch (e) { + console.warn(e); + status = 1; + } + + callback(status, retAddr, userdata); + + ptrsToFree.forEach(ptr => this.mem.exports.wgpu_free(ptr)); + }, + + ...this.shaderModules.interface(true), + + /* ---------------------- Surface ---------------------- */ + + /** + * @param {number} surfaceIdx + * @param {number} configPtr + */ + wgpuSurfaceConfigure: (surfaceIdx, configPtr) => { + const surface = this.surfaces.get(surfaceIdx); + const context = surface.getContext('webgpu'); + + const widthOff = 16 + this.mem.intSize + 8; + surface.width = this.mem.loadU32(configPtr + widthOff); + surface.height = this.mem.loadU32(configPtr + widthOff + 4); + + /** @type {GPUCanvasConfiguration} */ + const config = { + device: this.devices.get(this.mem.loadPtr(configPtr + 4)), + format: this.enumeration("TextureFormat", configPtr + 8), + usage: this.mem.loadU32(configPtr + 12), + viewFormats: this.array( + this.mem.loadUint(configPtr + 16), + this.mem.loadPtr(configPtr + 16 + this.mem.intSize), + (ptr) => this.enumeration("TextureFormat", ptr), + 4, + ), + alphaMode: this.enumeration("CompositeAlphaMode", configPtr + widthOff - 4), + // // NOTE: present mode seems unused. + presentMode: this.enumeration("PresentMode", configPtr + widthOff + 4), + }; + + context.configure(config); + }, + + /** + * @param {number} surfaceIdx + * @param {number} adapterIdx + * @param {number} capabilitiesPtr + */ + wgpuSurfaceGetCapabilities: (surfaceIdx, adapterIdx, capabilitiesPtr) => { + const formatStr = navigator.gpu.getPreferredCanvasFormat(); + const format = this.enums.TextureFormat.indexOf(formatStr); + + this.mem.storeUint(capabilitiesPtr + this.mem.intSize, 1); + const formatAddr = this.mem.exports.wgpu_alloc(4); + this.mem.storeI32(formatAddr, format); + this.mem.storeI32(capabilitiesPtr + this.mem.intSize*2, formatAddr); + + // NOTE: present modes don't seem to actually do anything in JS, we can just give back a default FIFO though. + this.mem.storeUint(capabilitiesPtr + this.mem.intSize*3, 1); + const presentModesAddr = this.mem.exports.wgpu_alloc(4); + this.mem.storeI32(presentModesAddr, 0); + this.mem.storeI32(capabilitiesPtr + this.mem.intSize*4, presentModesAddr); + + // Browser seems to support opaque (1) and premultiplied (2). + this.mem.storeUint(capabilitiesPtr + this.mem.intSize*5, 2); + const alphaModesAddr = this.mem.exports.wgpu_alloc(8); + this.mem.storeI32(alphaModesAddr + 0, 1); // Opaque. + this.mem.storeI32(alphaModesAddr + 4, 2); // premultiplied. + this.mem.storeI32(capabilitiesPtr + this.mem.intSize*6, alphaModesAddr); + }, + + /** + * @param {number} surfaceIdx + * @param {number} texturePtr + */ + wgpuSurfaceGetCurrentTexture: (surfaceIdx, texturePtr) => { + const surface = this.surfaces.get(surfaceIdx); + const context = surface.getContext('webgpu'); + const texture = context.getCurrentTexture(); + + const textureIdx = this.textures.create(texture); + this.mem.storeI32(texturePtr, textureIdx); + + // TODO: determine suboptimal and/or status. + }, + + /** + * @param {number} surfaceIdx + * @param {number} texturePtr + * @returns {number} + */ + wgpuSurfaceGetPreferredFormat: (surfaceIdx, adapterIdx) => { + const formatStr = navigator.gpu.getPreferredCanvasFormat(); + const format = this.enums.TextureFormat.indexOf(formatStr); + return format; + }, + + /** + * @param {number} surfaceIdx + */ + wgpuSurfacePresent: (surfaceIdx) => { + // NOTE: Not really anything to do here. + }, + + /** + * @param {number} surfaceIdx + */ + wgpuSurfaceUnconfigure: (surfaceIdx) => { + const surface = this.surfaces.get(surfaceIdx); + surface.getContext('webgpu').unconfigure(); + }, + + ...this.surfaces.interface(true), + + /* ---------------------- SurfaceCapabilities ---------------------- */ + + /** + * @param {number} surfaceCapabilitiesPtr + */ + wgpuSurfaceCapabilitiesFreeMembers: (surfaceCapabilitiesPtr) => { + const formatsAddr = this.mem.loadI32(surfaceCapabilitiesPtr + this.mem.intSize*2); + this.mem.exports.wgpu_free(formatsAddr); + + const presentModesAddr = this.mem.loadI32(surfaceCapabilitiesPtr + this.mem.intSize*4); + this.mem.exports.wgpu_free(presentModesAddr); + + const alphaModesAddr = this.mem.loadI32(surfaceCapabilitiesPtr + this.mem.intSize*6); + this.mem.exports.wgpu_free(alphaModesAddr); + }, + + /* ---------------------- Texture ---------------------- */ + + /** + * @param {number} textureIdx + * @param {0|number} descriptorPtr + * @returns {number} + */ + wgpuTextureCreateView: (textureIdx, descriptorPtr) => { + const texture = this.textures.get(textureIdx); + + /** @type {?GPUTextureViewDescriptor} */ + let descriptor; + if (descriptorPtr != 0) { + descriptor = { + label: this.mem.loadCstring(descriptorPtr + 4), + format: this.enumeration("TextureFormat", descriptorPtr + 8), + dimension: this.enumeration("TextureViewDimension", descriptorPtr + 12), + baseMipLevel: this.mem.loadU32(descriptorPtr + 16), + mipLevelCount: this.mem.loadU32(descriptorPtr + 20), + baseArrayLayer: this.mem.loadU32(descriptorPtr + 24), + arrayLayerCount: this.mem.loadU32(descriptorPtr + 28), + aspect: this.enumeration("TextureAspect", descriptorPtr + 32), + }; + if (descriptor.arrayLayerCount == 0xFFFFFFFF) { + descriptor.arrayLayerCount = undefined; + } + if (descriptor.mipLevelCount == 0xFFFFFFFF) { + descriptor.mipLevelCount = undefined; + } + } + + const textureView = texture.createView(descriptor); + return this.textureViews.create(textureView); + }, + + /** + * @param {number} textureIdx + */ + wgpuTextureDestroy: (textureIdx) => { + const texture = this.textures.get(textureIdx); + texture.destroy(); + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureDepthOrArrayLayers: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return texture.depthOrArrayLayers; + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureGetDimension: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return this.enums.TextureDimension.indexOf(texture.dimension); + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureGetFormat: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return this.enums.TextureFormat.indexOf(texture.format); + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureGetHeight: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return texture.height; + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureGetMipLevelCount: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return texture.mipLevelCount; + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureGetSampleCount: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return texture.sampleCount; + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureGetUsage: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return texture.usage; + }, + + /** + * @param {number} textureIdx + * @returns {number} + */ + wgpuTextureGetWidth: (textureIdx) => { + const texture = this.textures.get(textureIdx); + return texture.width; + }, + + ...this.textures.interface(true), + + /* ---------------------- TextureView ---------------------- */ + + ...this.textureViews.interface(true), + }; + } +} + +/** @template T */ +class WebGPUObjectManager { + + /** + * @param {string} name + * @param {WasmMemoryInterface} mem + */ + constructor(name, mem) { + this.name = name; + this.mem = mem; + + this.idx = 0; + + /** @type {Record} */ + this.objects = {}; + } + + /** + * @param {T} object + * @returns {number} + */ + create(object) { + this.objects[this.idx] = { references: 1, object }; + this.idx += 1; + return this.idx; + } + + /** + * @param {number} idx + * @returns {T} + */ + get(idx) { + return this.objects[idx-1].object; + } + + /** @param {number} idx */ + release(idx) { + this.objects[idx-1].references -= 1; + if (this.objects[idx-1].references == 0) { + delete this.objects[idx-1]; + } + } + + /** @param {number} idx */ + reference(idx) { + this.objects[idx-1].references += 1; + } + + interface(withLabelSetter = false) { + const inter = {}; + inter[`wgpu${this.name}Reference`] = this.reference.bind(this); + inter[`wgpu${this.name}Release`] = this.release.bind(this); + if (withLabelSetter) { + inter[`wgpu${this.name}SetLabel`] = (idx, labelPtr) => { + const obj = this.get(idx); + obj.label = this.mem.loadCstring(labelPtr); + }; + } + return inter; + } +} + +window.odin = window.odin || {}; +window.odin.WebGPUInterface = WebGPUInterface; + +})(); diff --git a/vendor/wgpu/wgpu.odin b/vendor/wgpu/wgpu.odin new file mode 100644 index 000000000..74df83fde --- /dev/null +++ b/vendor/wgpu/wgpu.odin @@ -0,0 +1,1708 @@ +package wgpu + +import "base:intrinsics" + +WGPU_SHARED :: #config(WGPU_SHARED, false) +WGPU_DEBUG :: #config(WGPU_DEBUG, false) + +@(private) TYPE :: "debug" when WGPU_DEBUG else "release" + +when ODIN_OS == .Windows { + @(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "x86_64" when ODIN_ARCH == .i386 else #panic("unsupported WGPU Native architecture") + @(private) EXT :: ".dll.lib" when WGPU_SHARED else ".lib" + @(private) LIB :: "lib/wgpu-windows-" + ARCH + "-" + TYPE + "/wgpu_native" + EXT + + when !#exists(LIB) { + #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'") + } + + foreign import libwgpu { + LIB, + "system:d3dcompiler.lib", + "system:ws2_32.lib", + "system:userenv.lib", + "system:bcrypt.lib", + "system:ntdll.lib", + "system:opengl32.lib", + "system:advapi32.lib", + "system:user32.lib", + "system:gdi32.lib", + } +} else when ODIN_OS == .Darwin { + @(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "aarch64" when ODIN_ARCH == .arm64 else #panic("unsupported WGPU Native architecture") + @(private) EXT :: ".dylib" when WGPU_SHARED else ".a" + @(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT + + when !#exists(LIB) { + #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'") + } + + foreign import libwgpu { + LIB, + "system:CoreFoundation.framework", + "system:QuartzCore.framework", + "system:Metal.framework", + } +} else when ODIN_OS == .Linux { + @(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "aarch64" when ODIN_ARCH == .arm64 else #panic("unsupported WGPU Native architecture") + @(private) EXT :: ".so" when WGPU_SHARED else ".a" + @(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT + + when !#exists(LIB) { + #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'") + } + + foreign import libwgpu { + LIB, + "system:dl", + "system:m", + } +} else when ODIN_OS == .JS { + foreign import libwgpu "wgpu" +} + +ARRAY_LAYER_COUNT_UNDEFINED :: max(u32) +COPY_STRIDE_UNDEFINED :: max(u32) +DEPTH_SLICE_UNDEFINED :: max(u32) +LIMIT_U32_UNDEFINED :: max(u32) +LIMIT_U64_UNDEFINED :: max(u64) +MIP_LEVEL_COUNT_UNDEFINED :: max(u32) +QUERY_SET_INDEX_UNDEFINED :: max(u32) +WHOLE_MAP_SIZE :: max(uint) +WHOLE_SIZE :: max(u64) + +Flags :: u32 + +Adapter :: distinct rawptr +BindGroup :: distinct rawptr +BindGroupLayout :: distinct rawptr +Buffer :: distinct rawptr +CommandBuffer :: distinct rawptr +CommandEncoder :: distinct rawptr +ComputePassEncoder :: distinct rawptr +ComputePipeline :: distinct rawptr +Device :: distinct rawptr +Instance :: distinct rawptr +PipelineLayout :: distinct rawptr +QuerySet :: distinct rawptr +Queue :: distinct rawptr +RenderBundle :: distinct rawptr +RenderBundleEncoder :: distinct rawptr +RenderPassEncoder :: distinct rawptr +RenderPipeline :: distinct rawptr +Sampler :: distinct rawptr +ShaderModule :: distinct rawptr +Surface :: distinct rawptr +Texture :: distinct rawptr +TextureView :: distinct rawptr + +AdapterType :: enum i32 { + DiscreteGPU = 0x00000000, + IntegratedGPU = 0x00000001, + CPU = 0x00000002, + Unknown = 0x00000003, +} + +AddressMode :: enum i32 { + Repeat = 0x00000000, + MirrorRepeat = 0x00000001, + ClampToEdge = 0x00000002, +} + +BackendType :: enum i32 { + Undefined = 0x00000000, + Null = 0x00000001, + WebGPU = 0x00000002, + D3D11 = 0x00000003, + D3D12 = 0x00000004, + Metal = 0x00000005, + Vulkan = 0x00000006, + OpenGL = 0x00000007, + OpenGLES = 0x00000008, +} + +BlendFactor :: enum i32 { + Zero = 0x00000000, + One = 0x00000001, + Src = 0x00000002, + OneMinusSrc = 0x00000003, + SrcAlpha = 0x00000004, + OneMinusSrcAlpha = 0x00000005, + Dst = 0x00000006, + OneMinusDst = 0x00000007, + DstAlpha = 0x00000008, + OneMinusDstAlpha = 0x00000009, + SrcAlphaSaturated = 0x0000000A, + Constant = 0x0000000B, + OneMinusConstant = 0x0000000C, +} + +BlendOperation :: enum i32 { + Add = 0x00000000, + Subtract = 0x00000001, + ReverseSubtract = 0x00000002, + Min = 0x00000003, + Max = 0x00000004, +} + +BufferBindingType :: enum i32 { + Undefined = 0x00000000, + Uniform = 0x00000001, + Storage = 0x00000002, + ReadOnlyStorage = 0x00000003, +} + +BufferMapAsyncStatus :: enum i32 { + Success = 0x00000000, + ValidationError = 0x00000001, + Unknown = 0x00000002, + DeviceLost = 0x00000003, + DestroyedBeforeCallback = 0x00000004, + UnmappedBeforeCallback = 0x00000005, + MappingAlreadyPending = 0x00000006, + OffsetOutOfRange = 0x00000007, + SizeOutOfRange = 0x00000008, +} + +BufferMapState :: enum i32 { + Unmapped = 0x00000000, + Pending = 0x00000001, + Mapped = 0x00000002, +} + +CompareFunction :: enum i32 { + Undefined = 0x00000000, + Never = 0x00000001, + Less = 0x00000002, + LessEqual = 0x00000003, + Greater = 0x00000004, + GreaterEqual = 0x00000005, + Equal = 0x00000006, + NotEqual = 0x00000007, + Always = 0x00000008, +} + +CompilationInfoRequestStatus :: enum i32 { + Success = 0x00000000, + Error = 0x00000001, + DeviceLost = 0x00000002, + Unknown = 0x00000003, +} + +CompilationMessageType :: enum i32 { + Error = 0x00000000, + Warning = 0x00000001, + Info = 0x00000002, +} + +CompositeAlphaMode :: enum i32 { + Auto = 0x00000000, + Opaque = 0x00000001, + Premultiplied = 0x00000002, + Unpremultiplied = 0x00000003, + Inherit = 0x00000004, +} + +CreatePipelineAsyncStatus :: enum i32 { + Success = 0x00000000, + ValidationError = 0x00000001, + InternalError = 0x00000002, + DeviceLost = 0x00000003, + DeviceDestroyed = 0x00000004, + Unknown = 0x00000005, +} + +CullMode :: enum i32 { + None = 0x00000000, + Front = 0x00000001, + Back = 0x00000002, +} + +DeviceLostReason :: enum i32 { + Undefined = 0x00000000, + Destroyed = 0x00000001, +} + +ErrorFilter :: enum i32 { + Validation = 0x00000000, + OutOfMemory = 0x00000001, + Internal = 0x00000002, +} + +ErrorType :: enum i32 { + NoError = 0x00000000, + Validation = 0x00000001, + OutOfMemory = 0x00000002, + Internal = 0x00000003, + Unknown = 0x00000004, + DeviceLost = 0x00000005, +} + +FeatureName :: enum i32 { + // WebGPU. + Undefined = 0x00000000, + DepthClipControl = 0x00000001, + Depth32FloatStencil8 = 0x00000002, + TimestampQuery = 0x00000003, + TextureCompressionBC = 0x00000004, + TextureCompressionETC2 = 0x00000005, + TextureCompressionASTC = 0x00000006, + IndirectFirstInstance = 0x00000007, + ShaderF16 = 0x00000008, + RG11B10UfloatRenderable = 0x00000009, + BGRA8UnormStorage = 0x0000000A, + Float32Filterable = 0x0000000B, + + // Native. + PushConstants = 0x00030001, + TextureAdapterSpecificFormatFeatures, + MultiDrawIndirect, + MultiDrawIndirectCount, + VertexWritableStorage, + TextureBindingArray, + SampledTextureAndStorageBufferArrayNonUniformIndexing, + PipelineStatisticsQuery, + StorageResourceBindingArray, + PartiallyBoundBindingArray, +} + +FilterMode :: enum i32 { + Nearest = 0x00000000, + Linear = 0x00000001, +} + +FrontFace :: enum i32 { + CCW = 0x00000000, + CW = 0x00000001, +} + +IndexFormat :: enum i32 { + Undefined = 0x00000000, + Uint16 = 0x00000001, + Uint32 = 0x00000002, +} + +LoadOp :: enum i32 { + Undefined = 0x00000000, + Clear = 0x00000001, + Load = 0x00000002, +} + +MipmapFilterMode :: enum i32 { + Nearest = 0x00000000, + Linear = 0x00000001, +} + +PowerPreference :: enum i32 { + Undefined = 0x00000000, + LowPower = 0x00000001, + HighPerformance = 0x00000002, +} + +PresentMode :: enum i32 { + Fifo = 0x00000000, + FifoRelaxed = 0x00000001, + Immediate = 0x00000002, + Mailbox = 0x00000003, +} + +PrimitiveTopology :: enum i32 { + PointList = 0x00000000, + LineList = 0x00000001, + LineStrip = 0x00000002, + TriangleList = 0x00000003, + TriangleStrip = 0x00000004, +} + +QueryType :: enum i32 { + // WebGPU. + Occlusion = 0x00000000, + Timestamp = 0x00000001, + + // Native. + PipelineStatistics = 0x00030000, +} + +QueueWorkDoneStatus :: enum i32 { + Success = 0x00000000, + Error = 0x00000001, + Unknown = 0x00000002, + DeviceLost = 0x00000003, +} + +RequestAdapterStatus :: enum i32 { + Success = 0x00000000, + Unavailable = 0x00000001, + Error = 0x00000002, + Unknown = 0x00000003, +} + +RequestDeviceStatus :: enum i32 { + Success = 0x00000000, + Error = 0x00000001, + Unknown = 0x00000002, +} + +SType :: enum i32 { + // WebGPU. + Invalid = 0x00000000, + SurfaceDescriptorFromMetalLayer = 0x00000001, + SurfaceDescriptorFromWindowsHWND = 0x00000002, + SurfaceDescriptorFromXlibWindow = 0x00000003, + SurfaceDescriptorFromCanvasHTMLSelector = 0x00000004, + ShaderModuleSPIRVDescriptor = 0x00000005, + ShaderModuleWGSLDescriptor = 0x00000006, + PrimitiveDepthClipControl = 0x00000007, + SurfaceDescriptorFromWaylandSurface = 0x00000008, + SurfaceDescriptorFromAndroidNativeWindow = 0x00000009, + SurfaceDescriptorFromXcbWindow = 0x0000000A, + RenderPassDescriptorMaxDrawCount = 0x0000000F, + + // Native. + DeviceExtras = 0x00030001, + RequiredLimitsExtras, + PipelineLayoutExtras, + ShaderModuleGLSLDescriptor, + SupportedLimitsExtras, + InstanceExtras, + BindGroupEntryExtras, + BindGroupLayoutEntryExtras, + QuerySetDescriptorExtras, + SurfaceConfigurationExtras, +} + +SamplerBindingType :: enum i32 { + Undefined = 0x00000000, + Filtering = 0x00000001, + NonFiltering = 0x00000002, + Comparison = 0x00000003, +} + +StencilOperation :: enum i32 { + Keep = 0x00000000, + Zero = 0x00000001, + Replace = 0x00000002, + Invert = 0x00000003, + IncrementClamp = 0x00000004, + DecrementClamp = 0x00000005, + IncrementWrap = 0x00000006, + DecrementWrap = 0x00000007, +} + +StorageTextureAccess :: enum i32 { + Undefined = 0x00000000, + WriteOnly = 0x00000001, + ReadOnly = 0x00000002, + ReadWrite = 0x00000003, +} + +StoreOp :: enum i32 { + Undefined = 0x00000000, + Store = 0x00000001, + Discard = 0x00000002, +} + +SurfaceGetCurrentTextureStatus :: enum i32 { + Success = 0x00000000, + Timeout = 0x00000001, + Outdated = 0x00000002, + Lost = 0x00000003, + OutOfMemory = 0x00000004, + DeviceLost = 0x00000005, +} + +TextureAspect :: enum i32 { + All = 0x00000000, + StencilOnly = 0x00000001, + DepthOnly = 0x00000002, +} + +TextureDimension :: enum i32 { + _1D = 0x00000000, + _2D = 0x00000001, + _3D = 0x00000002, +} + +TextureFormat :: enum i32 { + Undefined = 0x00000000, + R8Unorm = 0x00000001, + R8Snorm = 0x00000002, + R8Uint = 0x00000003, + R8Sint = 0x00000004, + R16Uint = 0x00000005, + R16Sint = 0x00000006, + R16Float = 0x00000007, + RG8Unorm = 0x00000008, + RG8Snorm = 0x00000009, + RG8Uint = 0x0000000A, + RG8Sint = 0x0000000B, + R32Float = 0x0000000C, + R32Uint = 0x0000000D, + R32Sint = 0x0000000E, + RG16Uint = 0x0000000F, + RG16Sint = 0x00000010, + RG16Float = 0x00000011, + RGBA8Unorm = 0x00000012, + RGBA8UnormSrgb = 0x00000013, + RGBA8Snorm = 0x00000014, + RGBA8Uint = 0x00000015, + RGBA8Sint = 0x00000016, + BGRA8Unorm = 0x00000017, + BGRA8UnormSrgb = 0x00000018, + RGB10A2Uint = 0x00000019, + RGB10A2Unorm = 0x0000001A, + RG11B10Ufloat = 0x0000001B, + RGB9E5Ufloat = 0x0000001C, + RG32Float = 0x0000001D, + RG32Uint = 0x0000001E, + RG32Sint = 0x0000001F, + RGBA16Uint = 0x00000020, + RGBA16Sint = 0x00000021, + RGBA16Float = 0x00000022, + RGBA32Float = 0x00000023, + RGBA32Uint = 0x00000024, + RGBA32Sint = 0x00000025, + Stencil8 = 0x00000026, + Depth16Unorm = 0x00000027, + Depth24Plus = 0x00000028, + Depth24PlusStencil8 = 0x00000029, + Depth32Float = 0x0000002A, + Depth32FloatStencil8 = 0x0000002B, + BC1RGBAUnorm = 0x0000002C, + BC1RGBAUnormSrgb = 0x0000002D, + BC2RGBAUnorm = 0x0000002E, + BC2RGBAUnormSrgb = 0x0000002F, + BC3RGBAUnorm = 0x00000030, + BC3RGBAUnormSrgb = 0x00000031, + BC4RUnorm = 0x00000032, + BC4RSnorm = 0x00000033, + BC5RGUnorm = 0x00000034, + BC5RGSnorm = 0x00000035, + BC6HRGBUfloat = 0x00000036, + BC6HRGBFloat = 0x00000037, + BC7RGBAUnorm = 0x00000038, + BC7RGBAUnormSrgb = 0x00000039, + ETC2RGB8Unorm = 0x0000003A, + ETC2RGB8UnormSrgb = 0x0000003B, + ETC2RGB8A1Unorm = 0x0000003C, + ETC2RGB8A1UnormSrgb = 0x0000003D, + ETC2RGBA8Unorm = 0x0000003E, + ETC2RGBA8UnormSrgb = 0x0000003F, + EACR11Unorm = 0x00000040, + EACR11Snorm = 0x00000041, + EACRG11Unorm = 0x00000042, + EACRG11Snorm = 0x00000043, + ASTC4x4Unorm = 0x00000044, + ASTC4x4UnormSrgb = 0x00000045, + ASTC5x4Unorm = 0x00000046, + ASTC5x4UnormSrgb = 0x00000047, + ASTC5x5Unorm = 0x00000048, + ASTC5x5UnormSrgb = 0x00000049, + ASTC6x5Unorm = 0x0000004A, + ASTC6x5UnormSrgb = 0x0000004B, + ASTC6x6Unorm = 0x0000004C, + ASTC6x6UnormSrgb = 0x0000004D, + ASTC8x5Unorm = 0x0000004E, + ASTC8x5UnormSrgb = 0x0000004F, + ASTC8x6Unorm = 0x00000050, + ASTC8x6UnormSrgb = 0x00000051, + ASTC8x8Unorm = 0x00000052, + ASTC8x8UnormSrgb = 0x00000053, + ASTC10x5Unorm = 0x00000054, + ASTC10x5UnormSrgb = 0x00000055, + ASTC10x6Unorm = 0x00000056, + ASTC10x6UnormSrgb = 0x00000057, + ASTC10x8Unorm = 0x00000058, + ASTC10x8UnormSrgb = 0x00000059, + ASTC10x10Unorm = 0x0000005A, + ASTC10x10UnormSrgb = 0x0000005B, + ASTC12x10Unorm = 0x0000005C, + ASTC12x10UnormSrgb = 0x0000005D, + ASTC12x12Unorm = 0x0000005E, + ASTC12x12UnormSrgb = 0x0000005F, +} + +TextureSampleType :: enum i32 { + Undefined = 0x00000000, + Float = 0x00000001, + UnfilterableFloat = 0x00000002, + Depth = 0x00000003, + Sint = 0x00000004, + Uint = 0x00000005, +} + +TextureViewDimension :: enum i32 { + Undefined = 0x00000000, + _1D = 0x00000001, + _2D = 0x00000002, + _2DArray = 0x00000003, + Cube = 0x00000004, + CubeArray = 0x00000005, + _3D = 0x00000006, +} + +VertexFormat :: enum i32 { + Undefined = 0x00000000, + Uint8x2 = 0x00000001, + Uint8x4 = 0x00000002, + Sint8x2 = 0x00000003, + Sint8x4 = 0x00000004, + Unorm8x2 = 0x00000005, + Unorm8x4 = 0x00000006, + Snorm8x2 = 0x00000007, + Snorm8x4 = 0x00000008, + Uint16x2 = 0x00000009, + Uint16x4 = 0x0000000A, + Sint16x2 = 0x0000000B, + Sint16x4 = 0x0000000C, + Unorm16x2 = 0x0000000D, + Unorm16x4 = 0x0000000E, + Snorm16x2 = 0x0000000F, + Snorm16x4 = 0x00000010, + Float16x2 = 0x00000011, + Float16x4 = 0x00000012, + Float32 = 0x00000013, + Float32x2 = 0x00000014, + Float32x3 = 0x00000015, + Float32x4 = 0x00000016, + Uint32 = 0x00000017, + Uint32x2 = 0x00000018, + Uint32x3 = 0x00000019, + Uint32x4 = 0x0000001A, + Sint32 = 0x0000001B, + Sint32x2 = 0x0000001C, + Sint32x3 = 0x0000001D, + Sint32x4 = 0x0000001E, +} + +VertexStepMode :: enum i32 { + Vertex = 0x00000000, + Instance = 0x00000001, + VertexBufferNotUsed = 0x00000002, +} + +// WGSLFeatureName :: enum i32 { +// Undefined = 0x00000000, +// ReadonlyAndReadwriteStorageTextures = 0x00000001, +// Packed4x8IntegerDotProduct = 0x00000002, +// UnrestrictedPointerParameters = 0x00000003, +// PointerCompositeAccess = 0x00000004, +// } + +BufferUsage :: enum i32 { + MapRead = 0x00000000, + MapWrite = 0x00000001, + CopySrc = 0x00000002, + CopyDst = 0x00000003, + Index = 0x00000004, + Vertex = 0x00000005, + Uniform = 0x00000006, + Storage = 0x00000007, + Indirect = 0x00000008, + QueryResolve = 0x00000009, +} +BufferUsageFlags :: bit_set[BufferUsage; Flags] + +ColorWriteMask :: enum i32 { + Red = 0x00000000, + Green = 0x00000001, + Blue = 0x00000002, + Alpha = 0x00000003, +} +ColorWriteMaskFlags :: bit_set[ColorWriteMask; Flags] +ColorWriteMaskFlags_All :: ColorWriteMaskFlags{ .Red, .Green, .Blue, .Alpha } + +MapMode :: enum i32 { + Read = 0x00000000, + Write = 0x00000001, +} +MapModeFlags :: bit_set[MapMode; Flags] + +ShaderStage :: enum i32 { + Vertex = 0x00000000, + Fragment = 0x00000001, + Compute = 0x00000002, +} +ShaderStageFlags :: bit_set[ShaderStage; Flags] + +TextureUsage :: enum i32 { + CopySrc = 0x00000000, + CopyDst = 0x00000001, + TextureBinding = 0x00000002, + StorageBinding = 0x00000003, + RenderAttachment = 0x00000004, +} +TextureUsageFlags :: bit_set[TextureUsage; Flags] + + +BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr) +ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr) +DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr) +DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr) + +DeviceLostCallback :: #type proc "c" (reason: DeviceLostReason, message: cstring, userdata: rawptr) +ErrorCallback :: #type proc "c" (type: ErrorType, message: cstring, userdata: rawptr) + +Proc :: distinct rawptr + +QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr) +InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr) +AdapterRequestDeviceCallback :: #type proc "c" (status: RequestDeviceStatus, device: Device, message: cstring, /* NULLABLE */ userdata: rawptr) + +// AdapterRequestAdapterInfoCallback :: #type proc "c" (adapterInfo: AdapterInfo, /* NULLABLE */ userdata: rawptr) + +ChainedStruct :: struct { + next: ^ChainedStruct, + sType: SType, +} + +ChainedStructOut :: struct { + next: ^ChainedStructOut, + sType: SType, +} + +// AdapterInfo :: struct { +// next: ^ChainedStructOut, +// vendor: cstring, +// architecture: cstring, +// device: cstring, +// description: cstring, +// backendType: BackendType, +// adapterType: AdapterType, +// vendorID: u32, +// deviceID: u32, +// } + +AdapterProperties :: struct { + nextInChain: ^ChainedStructOut, + vendorID: u32, + vendorName: cstring, + architecture: cstring, + deviceID: u32, + name: cstring, + driverDescription: cstring, + adapterType: AdapterType, + backendType: BackendType, +} + +BindGroupEntry :: struct { + nextInChain: ^ChainedStruct, + binding: u32, + /* NULLABLE */ buffer: Buffer, + offset: u64, + size: u64, + /* NULLABLE */ sampler: Sampler, + /* NULLABLE */ textureView: TextureView, +} + +BlendComponent :: struct { + operation: BlendOperation, + srcFactor: BlendFactor, + dstFactor: BlendFactor, +} + +BufferBindingLayout :: struct { + nextInChain: ^ChainedStruct, + type: BufferBindingType, + hasDynamicOffset: b32, + minBindingSize: u64, +} + +BufferDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + usage: BufferUsageFlags, + size: u64, + mappedAtCreation: b32, +} + +Color :: struct { + r: f64, + g: f64, + b: f64, + a: f64, +} + +CommandBufferDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, +} + +CommandEncoderDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, +} + +CompilationMessage :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ message: cstring, + type: CompilationMessageType, + lineNum: u64, + linePos: u64, + offset: u64, + length: u64, + utf16LinePos: u64, + utf16Offset: u64, + utf16Length: u64, +} + +ComputePassTimestampWrites :: struct { + querySet: QuerySet, + beginningOfPassWriteIndex: u32, + endOfPassWriteIndex: u32, +} + +ConstantEntry :: struct { + nextInChain: ^ChainedStruct, + key: cstring, + value: f64, +} + +Extent3D :: struct { + width: u32, + height: u32, + depthOrArrayLayers: u32, +} + +InstanceDescriptor :: struct { + nextInChain: ^ChainedStruct, +} + +Limits :: struct { + maxTextureDimension1D: u32, + maxTextureDimension2D: u32, + maxTextureDimension3D: u32, + maxTextureArrayLayers: u32, + maxBindGroups: u32, + maxBindGroupsPlusVertexBuffers: u32, + maxBindingsPerBindGroup: u32, + maxDynamicUniformBuffersPerPipelineLayout: u32, + maxDynamicStorageBuffersPerPipelineLayout: u32, + maxSampledTexturesPerShaderStage: u32, + maxSamplersPerShaderStage: u32, + maxStorageBuffersPerShaderStage: u32, + maxStorageTexturesPerShaderStage: u32, + maxUniformBuffersPerShaderStage: u32, + maxUniformBufferBindingSize: u64, + maxStorageBufferBindingSize: u64, + minUniformBufferOffsetAlignment: u32, + minStorageBufferOffsetAlignment: u32, + maxVertexBuffers: u32, + maxBufferSize: u64, + maxVertexAttributes: u32, + maxVertexBufferArrayStride: u32, + maxInterStageShaderComponents: u32, + maxInterStageShaderVariables: u32, + maxColorAttachments: u32, + maxColorAttachmentBytesPerSample: u32, + maxComputeWorkgroupStorageSize: u32, + maxComputeInvocationsPerWorkgroup: u32, + maxComputeWorkgroupSizeX: u32, + maxComputeWorkgroupSizeY: u32, + maxComputeWorkgroupSizeZ: u32, + maxComputeWorkgroupsPerDimension: u32, +} + +MultisampleState :: struct { + nextInChain: ^ChainedStruct, + count: u32, + mask: u32, + alphaToCoverageEnabled: b32, +} + +Origin3D :: struct { + x: u32, + y: u32, + z: u32, +} + +PipelineLayoutDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + bindGroupLayoutCount: uint, + bindGroupLayouts: [^]BindGroupLayout `fmt:"v,bindGroupLayoutCount"`, +} + +PrimitiveDepthClipControl :: struct { + using chain: ChainedStruct, + unclippedDepth: b32, +} + +PrimitiveState :: struct { + nextInChain: ^ChainedStruct, + topology: PrimitiveTopology, + stripIndexFormat: IndexFormat, + frontFace: FrontFace, + cullMode: CullMode, +} + +QuerySetDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + type: QueryType, + count: u32, +} + +QueueDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, +} + +RenderBundleDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, +} + +RenderBundleEncoderDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + colorFormatCount: uint, + colorFormats: [^]TextureFormat `fmt:"v,colorFormatCount"`, + depthStencilFormat: TextureFormat, + sampleCount: u32, + depthReadOnly: b32, + stencilReadOnly: b32, +} + +RenderPassDepthStencilAttachment :: struct { + view: TextureView, + depthLoadOp: LoadOp, + depthStoreOp: StoreOp, + depthClearValue: f32, + depthReadOnly: b32, + stencilLoadOp: LoadOp, + stencilStoreOp: StoreOp, + stencilClearValue: u32, + stencilReadOnly: b32, +} + +RenderPassDescriptorMaxDrawCount :: struct { + using chain: ChainedStruct, + maxDrawCount: u64, +} + +RenderPassTimestampWrites :: struct { + querySet: QuerySet, + beginningOfPassWriteIndex: u32, + endOfPassWriteIndex: u32, +} + +RequestAdapterOptions :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ compatibleSurface: Surface, + powerPreference: PowerPreference, + backendType: BackendType, + forceFallbackAdapter: b32, +} + +SamplerBindingLayout :: struct { + nextInChain: ^ChainedStruct, + type: SamplerBindingType, +} + +SamplerDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + addressModeU: AddressMode, + addressModeV: AddressMode, + addressModeW: AddressMode, + magFilter: FilterMode, + minFilter: FilterMode, + mipmapFilter: MipmapFilterMode, + lodMinClamp: f32, + lodMaxClamp: f32, + compare: CompareFunction, + maxAnisotropy: u16, +} + +ShaderModuleCompilationHint :: struct { + nextInChain: ^ChainedStruct, + entryPoint: cstring, + layout: PipelineLayout, +} + +ShaderModuleSPIRVDescriptor :: struct { + using chain: ChainedStruct, + codeSize: u32, + code: /* const */ [^]u32 `fmt:"v,codeSize"`, +} + +ShaderModuleWGSLDescriptor :: struct { + using chain: ChainedStruct, + code: cstring, +} + +StencilFaceState :: struct { + compare: CompareFunction, + failOp: StencilOperation, + depthFailOp: StencilOperation, + passOp: StencilOperation, +} + +StorageTextureBindingLayout :: struct { + nextInChain: ^ChainedStruct, + access: StorageTextureAccess, + format: TextureFormat, + viewDimension: TextureViewDimension, +} + +SurfaceCapabilities :: struct { + nextInChain: ^ChainedStructOut, + formatCount: uint, + formats: /* const */ [^]TextureFormat `fmt:"v,formatCount"`, + presentModeCount: uint, + presentModes: /* const */ [^]PresentMode `fmt:"v,presentModeCount"`, + alphaModeCount: uint, + alphaModes: /* const */ [^]CompositeAlphaMode `fmt:"v,alphaModeCount"`, +} + +SurfaceConfiguration :: struct { + nextInChain: ^ChainedStruct, + device: Device, + format: TextureFormat, + usage: TextureUsageFlags, + viewFormatCount: uint, + viewFormats: [^]TextureFormat `fmt:"v,viewFormatCount"`, + alphaMode: CompositeAlphaMode, + width: u32, + height: u32, + presentMode: PresentMode, +} + +SurfaceDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, +} + +SurfaceDescriptorFromAndroidNativeWindow :: struct { + using chain: ChainedStruct, + window: rawptr, +} + +SurfaceDescriptorFromCanvasHTMLSelector :: struct { + using chain: ChainedStruct, + selector: cstring, +} + +SurfaceDescriptorFromMetalLayer :: struct { + using chain: ChainedStruct, + layer: rawptr, +} + +SurfaceDescriptorFromWaylandSurface :: struct { + using chain: ChainedStruct, + display: rawptr, + surface: rawptr, +} + +SurfaceDescriptorFromWindowsHWND :: struct { + using chain: ChainedStruct, + hinstance: rawptr, + hwnd: rawptr, +} + +SurfaceDescriptorFromXcbWindow :: struct { + using chain: ChainedStruct, + connection: rawptr, + window: u32, +} + +SurfaceDescriptorFromXlibWindow :: struct { + using chain: ChainedStruct, + display: rawptr, + window: u64, +} + +SurfaceTexture :: struct { + texture: Texture, + suboptimal: b32, + status: SurfaceGetCurrentTextureStatus, +} + +TextureBindingLayout :: struct { + nextInChain: ^ChainedStruct, + sampleType: TextureSampleType, + viewDimension: TextureViewDimension, + multisampled: b32, +} + +TextureDataLayout :: struct { + nextInChain: ^ChainedStruct, + offset: u64, + bytesPerRow: u32, + rowsPerImage: u32, +} + +TextureViewDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + format: TextureFormat, + dimension: TextureViewDimension, + baseMipLevel: u32, + mipLevelCount: u32, + baseArrayLayer: u32, + arrayLayerCount: u32, + aspect: TextureAspect, +} + +VertexAttribute :: struct { + format: VertexFormat, + offset: u64, + shaderLocation: u32, +} + +BindGroupDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + layout: BindGroupLayout, + entryCount: uint, + entries: [^]BindGroupEntry `fmt:"v,entryCount"`, +} + +BindGroupLayoutEntry :: struct { + nextInChain: ^ChainedStruct, + binding: u32, + visibility: ShaderStageFlags, + buffer: BufferBindingLayout, + sampler: SamplerBindingLayout, + texture: TextureBindingLayout, + storageTexture: StorageTextureBindingLayout, +} + +BlendState :: struct { + color: BlendComponent, + alpha: BlendComponent, +} + +CompilationInfo :: struct { + nextInChain: ^ChainedStruct, + messageCount: uint, + messages: [^]CompilationMessage `fmt:"v,messageCount"`, +} + +ComputePassDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + /* NULLABLE */ timestampWrites: /* const */ ^ComputePassTimestampWrites, +} + +DepthStencilState :: struct { + nextInChain: ^ChainedStruct, + format: TextureFormat, + depthWriteEnabled: b32, + depthCompare: CompareFunction, + stencilFront: StencilFaceState, + stencilBack: StencilFaceState, + stencilReadMask: u32, + stencilWriteMask: u32, + depthBias: i32, + depthBiasSlopeScale: f32, + depthBiasClamp: f32, +} + +ImageCopyBuffer :: struct { + nextInChain: ^ChainedStruct, + layout: TextureDataLayout, + buffer: Buffer, +} + +ImageCopyTexture :: struct { + nextInChain: ^ChainedStruct, + texture: Texture, + mipLevel: u32, + origin: Origin3D, + aspect: TextureAspect, +} + +ProgrammableStageDescriptor :: struct { + nextInChain: ^ChainedStruct, + module: ShaderModule, + /* NULLABLE */ entryPoint: cstring, + constantCount: uint, + constants: [^]ConstantEntry `fmt:"v,constantCount"`, +} + +RenderPassColorAttachment :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ view: TextureView, + // depthSlice: u32, + /* NULLABLE */ resolveTarget: TextureView, + loadOp: LoadOp, + storeOp: StoreOp, + clearValue: Color, +} + +RequiredLimits :: struct { + nextInChain: ^ChainedStruct, + limits: Limits, +} + +ShaderModuleDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + hintCount: uint, + hints: [^]ShaderModuleCompilationHint `fmt:"v,hintCount"`, +} + +SupportedLimits :: struct { + nextInChain: ^ChainedStructOut, + limits: Limits, +} + +TextureDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + usage: TextureUsageFlags, + dimension: TextureDimension, + size: Extent3D, + format: TextureFormat, + mipLevelCount: u32, + sampleCount: u32, + viewFormatCount: uint, + viewFormats: [^]TextureFormat `fmt:"v,viewFormatCount"`, +} + +VertexBufferLayout :: struct { + arrayStride: u64, + stepMode: VertexStepMode, + attributeCount: uint, + attributes: [^]VertexAttribute `fmt:"v,attributeCount"`, +} + +BindGroupLayoutDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + entryCount: uint, + entries: [^]BindGroupLayoutEntry `fmt:"v,entryCount"`, +} + +ColorTargetState :: struct { + nextInChain: ^ChainedStruct, + format: TextureFormat, + /* NULLABLE */ blend: /* const */ ^BlendState, + writeMask: ColorWriteMaskFlags, +} + +ComputePipelineDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + /* NULLABLE */ layout: PipelineLayout, + compute: ProgrammableStageDescriptor, +} + +DeviceDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + requiredFeatureCount: uint, + requiredFeatures: [^]FeatureName `fmt:"v,requiredFeatureCount"`, + /* NULLABLE */ requiredLimits: /* const */ ^RequiredLimits, + defaultQueue: QueueDescriptor, + deviceLostCallback: DeviceLostCallback, + deviceLostUserdata: rawptr, +} + +RenderPassDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + colorAttachmentCount: uint, + colorAttachments: [^]RenderPassColorAttachment `fmt:"v,colorAttachmentCount"`, + /* NULLABLE */ depthStencilAttachment: /* const */ ^RenderPassDepthStencilAttachment, + /* NULLABLE */ occlusionQuerySet: QuerySet, + /* NULLABLE */ timestampWrites: /* const */ ^RenderPassTimestampWrites, +} + +VertexState :: struct { + nextInChain: ^ChainedStruct, + module: ShaderModule, + /* NULLABLE */ entryPoint: cstring, + constantCount: uint, + constants: [^]ConstantEntry `fmt:"v,constantCount"`, + bufferCount: uint, + buffers: [^]VertexBufferLayout `fmt:"v,bufferCount"`, +} + +FragmentState :: struct { + nextInChain: ^ChainedStruct, + module: ShaderModule, + /* NULLABLE */ entryPoint: cstring, + constantCount: uint, + constants: [^]ConstantEntry `fmt:"v,constantCount"`, + targetCount: uint, + targets: [^]ColorTargetState `fmt:"v,targetCount"`, +} + +RenderPipelineDescriptor :: struct { + nextInChain: ^ChainedStruct, + /* NULLABLE */ label: cstring, + /* NULLABLE */ layout: PipelineLayout, + vertex: VertexState, + primitive: PrimitiveState, + /* NULLABLE */ depthStencil: /* const */ ^DepthStencilState, + multisample: MultisampleState, + /* NULLABLE */ fragment: /* const */ ^FragmentState, +} + +@(link_prefix="wgpu", default_calling_convention="c") +foreign libwgpu { + CreateInstance :: proc(/* NULLABLE */ descriptor: /* const */ ^InstanceDescriptor = nil) -> Instance --- + GetProcAddress :: proc(device: Device, procName: cstring) -> Proc --- + + // Methods of Adapter + @(link_name="wgpuAdapterEnumerateFeatures") + RawAdapterEnumerateFeatures :: proc(adapter: Adapter, features: [^]FeatureName) -> uint --- + @(link_name="wgpuAdapterGetLimits") + RawAdapterGetLimits :: proc(adapter: Adapter, limits: ^SupportedLimits) -> b32 --- + @(link_name="wgpuAdapterGetProperties") + RawAdapterGetProperties :: proc(adapter: Adapter, properties: ^AdapterProperties) --- + AdapterHasFeature :: proc(adapter: Adapter, feature: FeatureName) -> b32 --- + // AdapterRequestAdapterInfo :: proc(adapter: Adapter, callback: AdapterRequestAdapterInfoCallback, /* NULLABLE */ userdata: rawptr) --- + AdapterRequestDevice :: proc(adapter: Adapter, /* NULLABLE */ descriptor: /* const */ ^DeviceDescriptor, callback: AdapterRequestDeviceCallback, /* NULLABLE */ userdata: rawptr = nil) --- + AdapterReference :: proc(adapter: Adapter) --- + AdapterRelease :: proc(adapter: Adapter) --- + + // Methods of BindGroup + BindGroupSetLabel :: proc(bindGroup: BindGroup, label: cstring) --- + BindGroupReference :: proc(bindGroup: BindGroup) --- + BindGroupRelease :: proc(bindGroup: BindGroup) --- + + // Methods of BindGroupLayout + BindGroupLayoutSetLabel :: proc(bindGroupLayout: BindGroupLayout, label: cstring) --- + BindGroupLayoutReference :: proc(bindGroupLayout: BindGroupLayout) --- + BindGroupLayoutRelease :: proc(bindGroupLayout: BindGroupLayout) --- + + // Methods of Buffer + BufferDestroy :: proc(buffer: Buffer) --- + @(link_name="wgpuBufferGetConstMappedRange") + RawBufferGetConstMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> /* const */ rawptr --- + BufferGetMapState :: proc(buffer: Buffer) -> BufferMapState --- + @(link_name="wgpuBufferGetMappedRange") + RawBufferGetMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> rawptr --- + BufferGetSize :: proc(buffer: Buffer) -> u64 --- + BufferGetUsage :: proc(buffer: Buffer) -> BufferUsageFlags --- + BufferMapAsync :: proc(buffer: Buffer, mode: MapModeFlags, offset: uint, size: uint, callback: BufferMapAsyncCallback, /* NULLABLE */ userdata: rawptr = nil) --- + BufferSetLabel :: proc(buffer: Buffer, label: cstring) --- + BufferUnmap :: proc(buffer: Buffer) --- + BufferReference :: proc(buffer: Buffer) --- + BufferRelease :: proc(buffer: Buffer) --- + + // Methods of CommandBuffer + CommandBufferSetLabel :: proc(commandBuffer: CommandBuffer, label: cstring) --- + CommandBufferReference :: proc(commandBuffer: CommandBuffer) --- + CommandBufferRelease :: proc(commandBuffer: CommandBuffer) --- + + // Methods of CommandEncoder + CommandEncoderBeginComputePass :: proc(commandEncoder: CommandEncoder, /* NULLABLE */ descriptor: /* const */ ^ComputePassDescriptor = nil) -> ComputePassEncoder --- + CommandEncoderBeginRenderPass :: proc(commandEncoder: CommandEncoder, descriptor: /* const */ ^RenderPassDescriptor) -> RenderPassEncoder --- + CommandEncoderClearBuffer :: proc(commandEncoder: CommandEncoder, buffer: Buffer, offset: u64, size: u64) --- + CommandEncoderCopyBufferToBuffer :: proc(commandEncoder: CommandEncoder, source: Buffer, sourceOffset: u64, destination: Buffer, destinationOffset: u64, size: u64) --- + CommandEncoderCopyBufferToTexture :: proc(commandEncoder: CommandEncoder, source: /* const */ ^ImageCopyBuffer, destination: /* const */ ^ImageCopyTexture, copySize: /* const */ ^Extent3D) --- + CommandEncoderCopyTextureToBuffer :: proc(commandEncoder: CommandEncoder, source: /* const */ ^ImageCopyTexture, destination: /* const */ ^ImageCopyBuffer, copySize: /* const */ ^Extent3D) --- + CommandEncoderCopyTextureToTexture :: proc(commandEncoder: CommandEncoder, source: /* const */ ^ImageCopyTexture, destination: /* const */ ^ImageCopyTexture, copySize: /* const */ ^Extent3D) --- + CommandEncoderFinish :: proc(commandEncoder: CommandEncoder, /* NULLABLE */ descriptor: /* const */ ^CommandBufferDescriptor = nil) -> CommandBuffer --- + CommandEncoderInsertDebugMarker :: proc(commandEncoder: CommandEncoder, markerLabel: cstring) --- + CommandEncoderPopDebugGroup :: proc(commandEncoder: CommandEncoder) --- + CommandEncoderPushDebugGroup :: proc(commandEncoder: CommandEncoder, groupLabel: cstring) --- + CommandEncoderResolveQuerySet :: proc(commandEncoder: CommandEncoder, querySet: QuerySet, firstQuery: u32, queryCount: u32, destination: Buffer, destinationOffset: u64) --- + CommandEncoderSetLabel :: proc(commandEncoder: CommandEncoder, label: cstring) --- + CommandEncoderWriteTimestamp :: proc(commandEncoder: CommandEncoder, querySet: QuerySet, queryIndex: u32) --- + CommandEncoderReference :: proc(commandEncoder: CommandEncoder) --- + CommandEncoderRelease :: proc(commandEncoder: CommandEncoder) --- + + // Methods of ComputePassEncoder + ComputePassEncoderDispatchWorkgroups :: proc(computePassEncoder: ComputePassEncoder, workgroupCountX: u32, workgroupCountY: u32, workgroupCountZ: u32) --- + ComputePassEncoderDispatchWorkgroupsIndirect :: proc(computePassEncoder: ComputePassEncoder, indirectBuffer: Buffer, indirectOffset: u64) --- + ComputePassEncoderEnd :: proc(computePassEncoder: ComputePassEncoder) --- + ComputePassEncoderInsertDebugMarker :: proc(computePassEncoder: ComputePassEncoder, markerLabel: cstring) --- + ComputePassEncoderPopDebugGroup :: proc(computePassEncoder: ComputePassEncoder) --- + ComputePassEncoderPushDebugGroup :: proc(computePassEncoder: ComputePassEncoder, groupLabel: cstring) --- + @(link_name="wgpuComputePassEncoderSetBindGroup") + RawComputePassEncoderSetBindGroup :: proc(computePassEncoder: ComputePassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) --- + ComputePassEncoderSetLabel :: proc(computePassEncoder: ComputePassEncoder, label: cstring) --- + ComputePassEncoderSetPipeline :: proc(computePassEncoder: ComputePassEncoder, pipeline: ComputePipeline) --- + ComputePassEncoderReference :: proc(computePassEncoder: ComputePassEncoder) --- + ComputePassEncoderRelease :: proc(computePassEncoder: ComputePassEncoder) --- + + // Methods of ComputePipeline + ComputePipelineGetBindGroupLayout :: proc(computePipeline: ComputePipeline, groupIndex: u32) -> BindGroupLayout --- + ComputePipelineSetLabel :: proc(computePipeline: ComputePipeline, label: cstring) --- + ComputePipelineReference :: proc(computePipeline: ComputePipeline) --- + ComputePipelineRelease :: proc(computePipeline: ComputePipeline) --- + + // Methods of Device + DeviceCreateBindGroup :: proc(device: Device, descriptor: /* const */ ^BindGroupDescriptor) -> BindGroup --- + DeviceCreateBindGroupLayout :: proc(device: Device, descriptor: /* const */ ^BindGroupLayoutDescriptor) -> BindGroupLayout --- + DeviceCreateBuffer :: proc(device: Device, descriptor: /* const */ ^BufferDescriptor) -> Buffer --- + DeviceCreateCommandEncoder :: proc(device: Device, /* NULLABLE */ descriptor: /* const */ ^CommandEncoderDescriptor = nil) -> CommandEncoder --- + DeviceCreateComputePipeline :: proc(device: Device, descriptor: /* const */ ^ComputePipelineDescriptor) -> ComputePipeline --- + DeviceCreateComputePipelineAsync :: proc(device: Device, descriptor: /* const */ ^ComputePipelineDescriptor, callback: DeviceCreateComputePipelineAsyncCallback, /* NULLABLE */ userdata: rawptr = nil) --- + DeviceCreatePipelineLayout :: proc(device: Device, descriptor: /* const */ ^PipelineLayoutDescriptor) -> PipelineLayout --- + DeviceCreateQuerySet :: proc(device: Device, descriptor: /* const */ ^QuerySetDescriptor) -> QuerySet --- + DeviceCreateRenderBundleEncoder :: proc(device: Device, descriptor: /* const */ ^RenderBundleEncoderDescriptor) -> RenderBundleEncoder --- + DeviceCreateRenderPipeline :: proc(device: Device, descriptor: /* const */ ^RenderPipelineDescriptor) -> RenderPipeline --- + DeviceCreateRenderPipelineAsync :: proc(device: Device, descriptor: /* const */ ^RenderPipelineDescriptor, callback: DeviceCreateRenderPipelineAsyncCallback, /* NULLABLE */ userdata: rawptr = nil) --- + DeviceCreateSampler :: proc(device: Device, /* NULLABLE */ descriptor: /* const */ ^SamplerDescriptor = nil) -> Sampler --- + DeviceCreateShaderModule :: proc(device: Device, descriptor: /* const */ ^ShaderModuleDescriptor) -> ShaderModule --- + DeviceCreateTexture :: proc(device: Device, descriptor: /* const */ ^TextureDescriptor) -> Texture --- + DeviceDestroy :: proc(device: Device) --- + @(link_name="wgpuDeviceEnumerateFeatures") + RawDeviceEnumerateFeatures :: proc(device: Device, features: ^FeatureName) -> uint --- + @(link_name="wgpuDeviceGetLimits") + RawDeviceGetLimits :: proc(device: Device, limits: ^SupportedLimits) -> b32 --- + DeviceGetQueue :: proc(device: Device) -> Queue --- + DeviceHasFeature :: proc(device: Device, feature: FeatureName) -> b32 --- + DevicePopErrorScope :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) --- + DevicePushErrorScope :: proc(device: Device, filter: ErrorFilter) --- + DeviceSetLabel :: proc(device: Device, label: cstring) --- + DeviceSetUncapturedErrorCallback :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) --- + DeviceReference :: proc(device: Device) --- + DeviceRelease :: proc(device: Device) --- + + // Methods of Instance + InstanceCreateSurface :: proc(instance: Instance, descriptor: /* const */ ^SurfaceDescriptor) -> Surface --- + // InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 --- + InstanceProcessEvents :: proc(instance: Instance) --- + InstanceRequestAdapter :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^RequestAdapterOptions, callback: InstanceRequestAdapterCallback, /* NULLABLE */ userdata: rawptr = nil) --- + InstanceReference :: proc(instance: Instance) --- + InstanceRelease :: proc(instance: Instance) --- + + // Methods of PipelineLayout + PipelineLayoutSetLabel :: proc(pipelineLayout: PipelineLayout, label: cstring) --- + PipelineLayoutReference :: proc(pipelineLayout: PipelineLayout) --- + PipelineLayoutRelease :: proc(pipelineLayout: PipelineLayout) --- + + // Methods of QuerySet + QuerySetDestroy :: proc(querySet: QuerySet) --- + QuerySetGetCount :: proc(querySet: QuerySet) -> u32 --- + QuerySetGetType :: proc(querySet: QuerySet) -> QueryType --- + QuerySetSetLabel :: proc(querySet: QuerySet, label: cstring) --- + QuerySetReference :: proc(querySet: QuerySet) --- + QuerySetRelease :: proc(querySet: QuerySet) --- + + // Methods of Queue + QueueOnSubmittedWorkDone :: proc(queue: Queue, callback: QueueOnSubmittedWorkDoneCallback, /* NULLABLE */ userdata: rawptr = nil) --- + QueueSetLabel :: proc(queue: Queue, label: cstring) --- + @(link_name="wgpuQueueSubmit") + RawQueueSubmit :: proc(queue: Queue, commandCount: uint, commands: [^]CommandBuffer) --- + QueueWriteBuffer :: proc(queue: Queue, buffer: Buffer, bufferOffset: u64, data: /* const */ rawptr, size: uint) --- + QueueWriteTexture :: proc(queue: Queue, destination: /* const */ ^ImageCopyTexture, data: /* const */ rawptr, dataSize: uint, dataLayout: /* const */ ^TextureDataLayout, writeSize: /* const */ ^Extent3D) --- + QueueReference :: proc(queue: Queue) --- + QueueRelease :: proc(queue: Queue) --- + + // Methods of RenderBundle + RenderBundleSetLabel :: proc(renderBundle: RenderBundle, label: cstring) --- + RenderBundleReference :: proc(renderBundle: RenderBundle) --- + RenderBundleRelease :: proc(renderBundle: RenderBundle) --- + + // Methods of RenderBundleEncoder + RenderBundleEncoderDraw :: proc(renderBundleEncoder: RenderBundleEncoder, vertexCount: u32, instanceCount: u32, firstVertex: u32, firstInstance: u32) --- + RenderBundleEncoderDrawIndexed :: proc(renderBundleEncoder: RenderBundleEncoder, indexCount: u32, instanceCount: u32, firstIndex: u32, baseVertex: i32, firstInstance: u32) --- + RenderBundleEncoderDrawIndexedIndirect :: proc(renderBundleEncoder: RenderBundleEncoder, indirectBuffer: Buffer, indirectOffset: u64) --- + RenderBundleEncoderDrawIndirect :: proc(renderBundleEncoder: RenderBundleEncoder, indirectBuffer: Buffer, indirectOffset: u64) --- + RenderBundleEncoderFinish :: proc(renderBundleEncoder: RenderBundleEncoder, /* NULLABLE */ descriptor: /* const */ ^RenderBundleDescriptor = nil) -> RenderBundle --- + RenderBundleEncoderInsertDebugMarker :: proc(renderBundleEncoder: RenderBundleEncoder, markerLabel: cstring) --- + RenderBundleEncoderPopDebugGroup :: proc(renderBundleEncoder: RenderBundleEncoder) --- + RenderBundleEncoderPushDebugGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupLabel: cstring) --- + @(link_name="wgpuRenderBundleEncoderSetBindGroup") + RawRenderBundleEncoderSetBindGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) --- + RenderBundleEncoderSetIndexBuffer :: proc(renderBundleEncoder: RenderBundleEncoder, buffer: Buffer, format: IndexFormat, offset: u64, size: u64) --- + RenderBundleEncoderSetLabel :: proc(renderBundleEncoder: RenderBundleEncoder, label: cstring) --- + RenderBundleEncoderSetPipeline :: proc(renderBundleEncoder: RenderBundleEncoder, pipeline: RenderPipeline) --- + RenderBundleEncoderSetVertexBuffer :: proc(renderBundleEncoder: RenderBundleEncoder, slot: u32, /* NULLABLE */ buffer: Buffer, offset: u64, size: u64) --- + RenderBundleEncoderReference :: proc(renderBundleEncoder: RenderBundleEncoder) --- + RenderBundleEncoderRelease :: proc(renderBundleEncoder: RenderBundleEncoder) --- + + // Methods of RenderPassEncoder + RenderPassEncoderBeginOcclusionQuery :: proc(renderPassEncoder: RenderPassEncoder, queryIndex: u32) --- + RenderPassEncoderDraw :: proc(renderPassEncoder: RenderPassEncoder, vertexCount: u32, instanceCount: u32, firstVertex: u32, firstInstance: u32) --- + RenderPassEncoderDrawIndexed :: proc(renderPassEncoder: RenderPassEncoder, indexCount: u32, instanceCount: u32, firstIndex: u32, baseVertex: i32, firstInstance: u32) --- + RenderPassEncoderDrawIndexedIndirect :: proc(renderPassEncoder: RenderPassEncoder, indirectBuffer: Buffer, indirectOffset: u64) --- + RenderPassEncoderDrawIndirect :: proc(renderPassEncoder: RenderPassEncoder, indirectBuffer: Buffer, indirectOffset: u64) --- + RenderPassEncoderEnd :: proc(renderPassEncoder: RenderPassEncoder) --- + RenderPassEncoderEndOcclusionQuery :: proc(renderPassEncoder: RenderPassEncoder) --- + @(link_name="wgpuRenderPassEncoderExecuteBundles") + RawRenderPassEncoderExecuteBundles :: proc(renderPassEncoder: RenderPassEncoder, bundleCount: uint, bundles: [^]RenderBundle) --- + RenderPassEncoderInsertDebugMarker :: proc(renderPassEncoder: RenderPassEncoder, markerLabel: cstring) --- + RenderPassEncoderPopDebugGroup :: proc(renderPassEncoder: RenderPassEncoder) --- + RenderPassEncoderPushDebugGroup :: proc(renderPassEncoder: RenderPassEncoder, groupLabel: cstring) --- + @(link_name="wgpuRenderPassEncoderSetBindGroup") + RawRenderPassEncoderSetBindGroup :: proc(renderPassEncoder: RenderPassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) --- + RenderPassEncoderSetBlendConstant :: proc(renderPassEncoder: RenderPassEncoder, color: /* const */ ^Color) --- + RenderPassEncoderSetIndexBuffer :: proc(renderPassEncoder: RenderPassEncoder, buffer: Buffer, format: IndexFormat, offset: u64, size: u64) --- + RenderPassEncoderSetLabel :: proc(renderPassEncoder: RenderPassEncoder, label: cstring) --- + RenderPassEncoderSetPipeline :: proc(renderPassEncoder: RenderPassEncoder, pipeline: RenderPipeline) --- + RenderPassEncoderSetScissorRect :: proc(renderPassEncoder: RenderPassEncoder, x: u32, y: u32, width: u32, height: u32) --- + RenderPassEncoderSetStencilReference :: proc(renderPassEncoder: RenderPassEncoder, reference: u32) --- + RenderPassEncoderSetVertexBuffer :: proc(renderPassEncoder: RenderPassEncoder, slot: u32, /* NULLABLE */ buffer: Buffer, offset: u64, size: u64) --- + RenderPassEncoderSetViewport :: proc(renderPassEncoder: RenderPassEncoder, x: f32, y: f32, width: f32, height: f32, minDepth: f32, maxDepth: f32) --- + RenderPassEncoderReference :: proc(renderPassEncoder: RenderPassEncoder) --- + RenderPassEncoderRelease :: proc(renderPassEncoder: RenderPassEncoder) --- + + // Methods of RenderPipeline + RenderPipelineGetBindGroupLayout :: proc(renderPipeline: RenderPipeline, groupIndex: u32) -> BindGroupLayout --- + RenderPipelineSetLabel :: proc(renderPipeline: RenderPipeline, label: cstring) --- + RenderPipelineReference :: proc(renderPipeline: RenderPipeline) --- + RenderPipelineRelease :: proc(renderPipeline: RenderPipeline) --- + + // Methods of Sampler + SamplerSetLabel :: proc(sampler: Sampler, label: cstring) --- + SamplerReference :: proc(sampler: Sampler) --- + SamplerRelease :: proc(sampler: Sampler) --- + + // Methods of ShaderModule + ShaderModuleGetCompilationInfo :: proc(shaderModule: ShaderModule, callback: ShaderModuleGetCompilationInfoCallback, /* NULLABLE */ userdata: rawptr = nil) --- + ShaderModuleSetLabel :: proc(shaderModule: ShaderModule, label: cstring) --- + ShaderModuleReference :: proc(shaderModule: ShaderModule) --- + ShaderModuleRelease :: proc(shaderModule: ShaderModule) --- + + // Methods of Surface + SurfaceConfigure :: proc(surface: Surface, config: /* const */ ^SurfaceConfiguration) --- + @(link_name="wgpuSurfaceGetCapabilities") + RawSurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter, capabilities: ^SurfaceCapabilities) --- + @(link_name="wgpuSurfaceGetCurrentTexture") + RawSurfaceGetCurrentTexture :: proc(surface: Surface, surfaceTexture: ^SurfaceTexture) --- + SurfaceGetPreferredFormat :: proc(surface: Surface, adapter: Adapter) -> TextureFormat --- + SurfacePresent :: proc(surface: Surface) --- + // SurfaceSetLabel :: proc(surface: Surface, label: cstring) --- + SurfaceUnconfigure :: proc(surface: Surface) --- + SurfaceReference :: proc(surface: Surface) --- + SurfaceRelease :: proc(surface: Surface) --- + + // Methods of SurfaceCapabilities + SurfaceCapabilitiesFreeMembers :: proc(surfaceCapabilities: SurfaceCapabilities) --- + + // Methods of Texture + TextureCreateView :: proc(texture: Texture, /* NULLABLE */ descriptor: /* const */ ^TextureViewDescriptor = nil) -> TextureView --- + TextureDestroy :: proc(texture: Texture) --- + TextureGetDepthOrArrayLayers :: proc(texture: Texture) -> u32 --- + TextureGetDimension :: proc(texture: Texture) -> TextureDimension --- + TextureGetFormat :: proc(texture: Texture) -> TextureFormat --- + TextureGetHeight :: proc(texture: Texture) -> u32 --- + TextureGetMipLevelCount :: proc(texture: Texture) -> u32 --- + TextureGetSampleCount :: proc(texture: Texture) -> u32 --- + TextureGetUsage :: proc(texture: Texture) -> TextureUsageFlags --- + TextureGetWidth :: proc(texture: Texture) -> u32 --- + TextureSetLabel :: proc(texture: Texture, label: cstring) --- + TextureReference :: proc(texture: Texture) --- + TextureRelease :: proc(texture: Texture) --- + + // Methods of TextureView + TextureViewSetLabel :: proc(textureView: TextureView, label: cstring) --- + TextureViewReference :: proc(textureView: TextureView) --- + TextureViewRelease :: proc(textureView: TextureView) --- +} + +// Wrappers of Adapter + +AdapterEnumerateFeatures :: proc(adapter: Adapter, allocator := context.allocator) -> []FeatureName { + count := RawAdapterEnumerateFeatures(adapter, nil) + features := make([]FeatureName, count, allocator) + RawAdapterEnumerateFeatures(adapter, raw_data(features)) + return features +} + +AdapterGetLimits :: proc(adapter: Adapter) -> (limits: SupportedLimits, ok: bool) { + ok = bool(RawAdapterGetLimits(adapter, &limits)) + return +} + +AdapterGetProperties :: proc(adapter: Adapter) -> (properties: AdapterProperties) { + RawAdapterGetProperties(adapter, &properties) + return +} + +// Wrappers of Buffer + +BufferGetConstMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> []byte { + return ([^]byte)(RawBufferGetConstMappedRange(buffer, offset, size))[:size] +} + +BufferGetConstMappedRangeTyped :: proc(buffer: Buffer, offset: uint, $T: typeid) -> ^T + where !intrinsics.type_is_sliceable(T) { + + return (^T)(RawBufferGetConstMappedRange(buffer, 0, size_of(T))) +} + +BufferGetConstMappedRangeSlice :: proc(buffer: Buffer, offset: uint, length: uint, $T: typeid) -> []T { + return ([^]T)(RawBufferGetConstMappedRange(buffer, offset, size_of(T)*length))[:length] +} + +BufferGetMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> []byte { + return ([^]byte)(RawBufferGetMappedRange(buffer, offset, size))[:size] +} + +BufferGetMappedRangeTyped :: proc(buffer: Buffer, offset: uint, $T: typeid) -> ^T + where !intrinsics.type_is_sliceable(T) { + + return (^T)(RawBufferGetMappedRange(buffer, offset, size_of(T))) +} + +BufferGetMappedRangeSlice :: proc(buffer: Buffer, offset: uint, $T: typeid, length: uint) -> []T { + return ([^]T)(RawBufferGetMappedRange(buffer, offset, size_of(T)*length))[:length] +} + +// Wrappers of ComputePassEncoder + +ComputePassEncoderSetBindGroup :: proc(computePassEncoder: ComputePassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsets: []u32 = nil) { + RawComputePassEncoderSetBindGroup(computePassEncoder, groupIndex, group, len(dynamicOffsets), raw_data(dynamicOffsets)) +} + +// Wrappers of Device + +DeviceEnumerateFeatures :: proc(device: Device, allocator := context.allocator) -> []FeatureName { + count := RawDeviceEnumerateFeatures(device, nil) + features := make([]FeatureName, count, allocator) + RawDeviceEnumerateFeatures(device, raw_data(features)) + return features +} + +DeviceGetLimits :: proc(device: Device) -> (limits: SupportedLimits, ok: bool) { + ok = bool(RawDeviceGetLimits(device, &limits)) + return +} + +BufferWithDataDescriptor :: struct { + /* NULLABLE */ label: cstring, + usage: BufferUsageFlags, +} + +DeviceCreateBufferWithDataSlice :: proc(device: Device, descriptor: /* const */ ^BufferWithDataDescriptor, data: []$T) -> (buf: Buffer) { + size := u64(size_of(T) * len(data)) + buf = DeviceCreateBuffer(device, &{ + label = descriptor.label, + usage = descriptor.usage, + size = size, + mappedAtCreation = true, + }) + + mapping := BufferGetMappedRangeSlice(buf, 0, T, len(data)) + copy(mapping, data) + + BufferUnmap(buf) + return +} + +DeviceCreateBufferWithDataTyped :: proc(device: Device, descriptor: /* const */ ^BufferWithDataDescriptor, data: $T) -> (buf: Buffer) + where !intrinsics.type_is_sliceable(T) { + + buf = DeviceCreateBuffer(device, &{ + label = descriptor.label, + usage = descriptor.usage, + size = size_of(T), + mappedAtCreation = true, + }) + + mapping := BufferGetMappedRangeTyped(buf, 0, T) + mapping^ = data + + BufferUnmap(buf) + return +} + +DeviceCreateBufferWithData :: proc { + DeviceCreateBufferWithDataSlice, + DeviceCreateBufferWithDataTyped, +} + +// Wrappers of Queue + +QueueSubmit :: proc(queue: Queue, commands: []CommandBuffer) { + RawQueueSubmit(queue, len(commands), raw_data(commands)) +} + +// Wrappers of RenderBundleEncoder + +RenderBundleEncoderSetBindGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsets: []u32 = nil) { + RawRenderBundleEncoderSetBindGroup(renderBundleEncoder, groupIndex, group, len(dynamicOffsets), raw_data(dynamicOffsets)) +} + +// Wrappers of RenderPassEncoder + +RenderPassEncoderExecuteBundles :: proc(renderPassEncoder: RenderPassEncoder, bundles: []RenderBundle) { + RawRenderPassEncoderExecuteBundles(renderPassEncoder, len(bundles), raw_data(bundles)) +} + +RenderPassEncoderSetBindGroup :: proc(renderPassEncoder: RenderPassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsets: []u32 = nil) { + RawRenderPassEncoderSetBindGroup(renderPassEncoder, groupIndex, group, len(dynamicOffsets), raw_data(dynamicOffsets)) +} + +// Wrappers of Surface + +SurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter) -> (capabilities: SurfaceCapabilities) { + RawSurfaceGetCapabilities(surface, adapter, &capabilities) + return +} + +SurfaceGetCurrentTexture :: proc(surface: Surface) -> (surface_texture: SurfaceTexture) { + RawSurfaceGetCurrentTexture(surface, &surface_texture) + return +} + +// WGPU Native bindings + +BINDINGS_VERSION :: [4]u8{0, 19, 4, 1} +BINDINGS_VERSION_STRING :: "0.19.4.1" + +when ODIN_OS != .JS { + @(private="file", init) + wgpu_native_version_check :: proc() { + v := (transmute([4]u8)GetVersion()).wzyx + + if v != BINDINGS_VERSION { + buf: [1024]byte + n := copy(buf[:], "wgpu-native version mismatch: ") + n += copy(buf[n:], "bindings are for version ") + n += copy(buf[n:], BINDINGS_VERSION_STRING) + n += copy(buf[n:], ", but a different version is linked") + panic(string(buf[:n])) + } + } + + @(link_prefix="wgpu") + foreign libwgpu { + @(link_name="wgpuGenerateReport") + RawGenerateReport :: proc(instance: Instance, report: ^GlobalReport) --- + @(link_name="wgpuInstanceEnumerateAdapters") + RawInstanceEnumerateAdapters :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^InstanceEnumerateAdapterOptions, adapters: [^]Adapter) -> uint --- + + @(link_name="wgpuQueueSubmitForIndex") + RawQueueSubmitForIndex :: proc(queue: Queue, commandCount: uint, commands: [^]CommandBuffer) -> SubmissionIndex --- + + // Returns true if the queue is empty, or false if there are more queue submissions still in flight. + DevicePoll :: proc(device: Device, wait: b32, /* NULLABLE */ wrappedSubmissionIndex: /* const */ ^WrappedSubmissionIndex = nil) -> b32 --- + + SetLogCallback :: proc(callback: LogCallback, userdata: rawptr) --- + + SetLogLevel :: proc(level: LogLevel) --- + + GetVersion :: proc() -> u32 --- + + RenderPassEncoderSetPushConstants :: proc(encoder: RenderPassEncoder, stages: ShaderStageFlags, offset: u32, sizeBytes: u32, data: cstring) --- + + RenderPassEncoderMultiDrawIndirect :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count: u32) --- + RenderPassEncoderMultiDrawIndexedIndirect :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count: u32) --- + + RenderPassEncoderMultiDrawIndirectCount :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count_buffer: Buffer, count_buffer_offset: u64, max_count: u32) --- + RenderPassEncoderMultiDrawIndexedIndirectCount :: proc(encoder: RenderPassEncoder, buffer: Buffer, offset: u64, count_buffer: Buffer, count_buffer_offset: u64, max_count: u32) --- + + ComputePassEncoderBeginPipelineStatisticsQuery :: proc(computePassEncoder: ComputePassEncoder, querySet: QuerySet, queryIndex: u32) --- + ComputePassEncoderEndPipelineStatisticsQuery :: proc(computePassEncoder: ComputePassEncoder) --- + RenderPassEncoderBeginPipelineStatisticsQuery :: proc(renderPassEncoder: RenderPassEncoder, querySet: QuerySet, queryIndex: u32) --- + RenderPassEncoderEndPipelineStatisticsQuery :: proc(renderPassEncoder: RenderPassEncoder) --- + } + + GenerateReport :: proc(instance: Instance) -> (report: GlobalReport) { + RawGenerateReport(instance, &report) + return + } + + InstanceEnumerateAdapters :: proc(instance: Instance, options: ^InstanceEnumerateAdapterOptions = nil, allocator := context.allocator) -> (adapters: []Adapter) { + count := RawInstanceEnumerateAdapters(instance, options, nil) + adapters = make([]Adapter, count, allocator) + RawInstanceEnumerateAdapters(instance, options, raw_data(adapters)) + return + } + + QueueSubmitForIndex :: proc(queue: Queue, commands: []CommandBuffer) -> SubmissionIndex { + return RawQueueSubmitForIndex(queue, len(commands), raw_data(commands)) + } +} diff --git a/vendor/wgpu/wgpu_js.odin b/vendor/wgpu/wgpu_js.odin new file mode 100644 index 000000000..f375a0d69 --- /dev/null +++ b/vendor/wgpu/wgpu_js.odin @@ -0,0 +1,26 @@ +package wgpu + +import "base:runtime" + +g_context: runtime.Context + +@(private="file", init) +wgpu_init_allocator :: proc() { + if g_context.allocator.procedure == nil { + g_context = runtime.default_context() + } +} + +@(private="file", export) +wgpu_alloc :: proc "contextless" (size: i32) -> [^]byte { + context = g_context + bytes, err := runtime.mem_alloc(int(size), 16) + assert(err == nil, "wgpu_alloc failed") + return raw_data(bytes) +} + +@(private="file", export) +wgpu_free :: proc "contextless" (ptr: rawptr) { + context = g_context + assert(free(ptr) == nil, "wgpu_free failed") +} diff --git a/vendor/wgpu/wgpu_native_types.odin b/vendor/wgpu/wgpu_native_types.odin new file mode 100644 index 000000000..2133fdd50 --- /dev/null +++ b/vendor/wgpu/wgpu_native_types.odin @@ -0,0 +1,212 @@ +package wgpu + +import "base:runtime" + +LogLevel :: enum i32 { + Off, + Error, + Warn, + Info, + Debug, + Trace, +} + +InstanceBackend :: enum i32 { + Vulkan, + GL, + Metal, + DX12, + DX11, + BrowserWebGPU, +} +InstanceBackendFlags :: bit_set[InstanceBackend; Flags] +InstanceBackendFlags_All :: InstanceBackendFlags{} +InstanceBackendFlags_Primary :: InstanceBackendFlags{ .Vulkan, .Metal, .DX12, .BrowserWebGPU } +InstanceBackendFlags_Secondary :: InstanceBackendFlags{ .GL, .DX11 } + +InstanceFlag :: enum i32 { + Debug, + Validation, + DiscardHalLabels, +} +InstanceFlags :: bit_set[InstanceFlag; Flags] +InstanceFlags_Default :: InstanceFlags{} + +Dx12Compiler :: enum i32 { + Undefined, + Fxc, + Dxc, +} + +Gles3MinorVersion :: enum i32 { + Automatic, + Version0, + Version1, + Version2, +} + +PipelineStatisticName :: enum i32 { + VertexShaderInvocations, + ClipperInvocations, + ClipperPrimitivesOut, + FragmentShaderInvocations, + ComputeShaderInvocations, +} + +InstanceExtras :: struct { + using chain: ChainedStruct, + backends: InstanceBackendFlags, + flags: InstanceFlags, + dx12ShaderCompiler: Dx12Compiler, + gles3MinorVersion: Gles3MinorVersion, + dxilPath: cstring, + dxcPath: cstring, +} + +DeviceExtras :: struct { + using chain: ChainedStruct, + tracePath: cstring, +} + +NativeLimits :: struct { + maxPushConstantSize: u32, + maxNonSamplerBindings: u32, +} + +RequiredLimitsExtras :: struct { + using chain: ChainedStruct, + limits: NativeLimits, +} + +SupportedLimitsExtras :: struct { + using chain: ChainedStructOut, + limits: NativeLimits, +} + +PushConstantRange :: struct { + stages: ShaderStageFlags, + start: u32, + end: u32, +} + +PipelineLayoutExtras :: struct { + using chain: ChainedStruct, + pushConstantRangeCount: uint, + pushConstantRanges: [^]PushConstantRange `fmt:"v,pushConstantRangeCount"`, +} + +SubmissionIndex :: distinct u64 + +WrappedSubmissionIndex :: struct { + queue: Queue, + submissionIndex: SubmissionIndex, +} + +ShaderDefine :: struct { + name: cstring, + value: cstring, +} + +ShaderModuleGLSLDescriptor :: struct { + using chain: ChainedStruct, + stage: ShaderStage, + code: cstring, + defineCount: uint, + defines: [^]ShaderDefine `fmt:"v,defineCount"`, +} + +RegistryReport :: struct { + numAllocated: uint, + numKeptFromUser: uint, + numReleasedFromUser: uint, + numErrors: uint, + elementSize: uint, +} + +HubReport :: struct { + adapters: RegistryReport, + devices: RegistryReport, + queues: RegistryReport, + pipelineLayouts: RegistryReport, + shaderModules: RegistryReport, + bindGroupLayouts: RegistryReport, + bindGroups: RegistryReport, + commandBuffers: RegistryReport, + renderBundles: RegistryReport, + renderPipelines: RegistryReport, + computePipelines: RegistryReport, + querySets: RegistryReport, + buffers: RegistryReport, + textures: RegistryReport, + textureViews: RegistryReport, + samplers: RegistryReport, +} + +GlobalReport :: struct { + surfaces: RegistryReport, + backendType: BackendType, + vulkan: HubReport, + metal: HubReport, + dx12: HubReport, + gl: HubReport, +} + +InstanceEnumerateAdapterOptions :: struct { + nextInChain: ^ChainedStruct, + backends: InstanceBackendFlags, +} + +BindGroupEntryExtras :: struct { + using chain: ChainedStruct, + buffers: [^]Buffer `fmt:"v,bufferCount"`, + bufferCount: uint, + samplers: [^]Sampler `fmt:"v,samplerCount"`, + samplerCount: uint, + textureViews: [^]TextureView `fmt:"v,textureViewCount"`, + textureViewCount: uint, +} + +BindGroupLayoutEntryExtras :: struct { + using chain: ChainedStruct, + count: u32, +} + +QuerySetDescriptorExtras :: struct { + using chain: ChainedStruct, + pipelineStatistics: [^]PipelineStatisticName `fmt:"v,pipelineStatisticCount"`, + pipelineStatisticCount: uint, +} + +SurfaceConfigurationExtras :: struct { + using chain: ChainedStruct, + desiredMaximumFrameLatency: i32, +} + +LogCallback :: #type proc "c" (level: LogLevel, message: cstring, userdata: rawptr) + +// Wrappers + +ConvertOdinToWGPULogLevel :: proc(level: runtime.Logger_Level) -> LogLevel { + switch { + case level < .Debug: return .Trace + case level < .Info: return .Debug + case level < .Warning: return .Info + case level < .Error: return .Warn + case: return .Error + } +} + +ConvertWGPUToOdinLogLevel :: proc(level: LogLevel) -> runtime.Logger_Level { + switch level { + case .Off, .Trace, .Debug: return .Debug + case .Info: return .Info + case .Warn: return .Warning + case .Error: return .Error + case: return .Error + } +} + +ConvertLogLevel :: proc { + ConvertOdinToWGPULogLevel, + ConvertWGPUToOdinLogLevel, +} diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin index 0b87ab9f7..ce31a4e76 100644 --- a/vendor/x11/xlib/xlib_const.odin +++ b/vendor/x11/xlib/xlib_const.odin @@ -1,6 +1,80 @@ //+build linux, freebsd, openbsd package xlib +/* ---- X11/extensions/XKB.h ---------------------------------------------------------*/ + +XkbMinLegalKeyCode :: 8 +XkbMaxLegalKeyCode :: 255 +XkbMaxKeyCount :: XkbMaxLegalKeyCode - XkbMinLegalKeyCode + 1 +XkbPerKeyBitArraySize :: (XkbMaxLegalKeyCode + 1) / 8 +XkbKeyNameLength :: 4 +XkbNumVirtualMods :: 16 +XkbNumIndicators :: 32 +XkbNumKbdGroups :: 4 +XkbAnyActionDataSize :: 7 +XkbUseCoreKbd :: 0x0100 +XkbActionMessageLength :: 6 + +XkbInfoMask :: bit_set[XkbInfoMaskBits; int] +XkbInfoMaskBits :: enum u32 { + KeyTypes = 0, + KeySyms = 1, + ModifierMap = 2, + ExplicitComponents = 3, + KeyActions = 4, + KeyBehaviors = 5, + VirtualMods = 6, + VirtualModMap = 7, +} + +XkbAllClientInfoMask :: XkbInfoMask { + .KeyTypes, + .KeySyms, + .ModifierMap, +} + +XkbAllServerInfoMask :: XkbInfoMask { + .ExplicitComponents, + .KeyActions, + .KeyBehaviors, + .VirtualMods, + .VirtualModMap, +} + +XkbEventMask :: bit_set[XkbEventType; int] +XkbEventType :: enum i32 { + NewKeyboardNotify = 0, + MapNotify = 1, + StateNotify = 2, + ControlsNotify = 3, + IndicatorStateNotify = 4, + IndicatorMapNotify = 5, + NamesNotify = 6, + CompatMapNotify = 7, + BellNotify = 8, + ActionMessage = 9, + AccessXNotify = 10, + ExtensionDeviceNotify = 11, +} + +XkbAllEventsMask :: XkbEventMask { + .NewKeyboardNotify, + .MapNotify, + .StateNotify, + .ControlsNotify, + .IndicatorStateNotify, + .IndicatorMapNotify, + .NamesNotify, + .CompatMapNotify, + .BellNotify, + .ActionMessage, + .AccessXNotify, + .ExtensionDeviceNotify, +} + + +/* ---- X11/Xlib.h ---------------------------------------------------------*/ + // Special values for many types. Most of these constants // aren't attached to a specific type. diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index 20ec5bb39..17d172172 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -79,7 +79,7 @@ foreign xlib { DoesBackingStore :: proc(screen: ^Screen) -> BackingStore --- DoesSaveUnders :: proc(screen: ^Screen) -> b32 --- DisplayOfScreen :: proc(screen: ^Screen) -> ^Display --- - ScreenNumberOfScreens :: proc(screen: ^Screen) -> i32 --- + ScreenNumberOfScreen :: proc(screen: ^Screen) -> i32 --- EventMaskOfScreen :: proc(screen: ^Screen) -> EventMask --- WidthOfScreen :: proc(screen: ^Screen) -> i32 --- HeightOfScreen :: proc(screen: ^Screen) -> i32 --- @@ -1637,6 +1637,13 @@ foreign xlib { wm_hints: ^XWMHints, class_hints: ^XClassHint, ) --- + OpenIM :: proc( + display: ^Display, + rdb: XrmHashBucket, + res_name: cstring, + res_class: cstring, + ) -> XIM --- + SetLocaleModifiers :: proc(modifiers: cstring) -> cstring --- } @(default_calling_convention="c") @@ -1938,4 +1945,52 @@ foreign xlib { XrmInitialize :: proc() --- XrmGetStringDatabase :: proc(data: cstring) -> XrmDatabase --- XrmGetResource :: proc(db: XrmDatabase, name: cstring, class: cstring, type_return: ^cstring, val_return: ^XrmValue) -> b32 --- + + /* ---- X11/XKBlib.h ---------------------------------------------------------*/ + + XkbQueryExtension :: proc( + display: ^Display, + opcode_return: ^i32, + event_base_return: ^i32, + error_base_return: ^i32, + major_return: ^i32, + minor_return: ^i32, + ) -> b32 --- + XkbUseExtension :: proc( + display: ^Display, + major_return: ^i32, + minor_return: ^i32, + ) -> b32 --- + XkbGetMap :: proc( + display: ^Display, + which: XkbInfoMask, + device_spec: i32, + ) -> XkbDescPtr --- + XkbGetUpdatedMap :: proc( + display: ^Display, + which: XkbInfoMask, + desc: XkbDescPtr, + ) -> b32 --- + XkbSelectEvents :: proc( + display: ^Display, + deviceID: u32, + bits_to_change: XkbEventMask, + values: XkbEventMask, + ) -> b32 --- + XkbSetDetectableAutoRepeat :: proc( + display: ^Display, + detectable: b32, + supported: ^b32, + ) -> b32 --- + XkbGetState :: proc ( + display: ^Display, + device_spec: u32, + return_state: XkbStatePtr, + ) -> Status --- + XkbGetKeySyms :: proc( + display: ^Display, + first: u32, + num: u32, + xkb: XkbDescPtr, + ) -> Status --- } diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin index d333c3c79..d2bd2c5a3 100644 --- a/vendor/x11/xlib/xlib_types.odin +++ b/vendor/x11/xlib/xlib_types.odin @@ -24,6 +24,9 @@ Cursor :: XID Colormap :: XID GContext :: XID +RRCrtc :: XID +RROutput :: XID + KeyCode :: u8 /* ---- X11/Xlib.h ---------------------------------------------------------*/ @@ -1003,6 +1006,767 @@ XConnectionWatchProc :: #type proc "c" ( opening: b32, watch_data: rawptr) +/* ---- X11/extensions/XKBlib.h ---------------------------------------------------------*/ + +XkbAnyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: u32, +} + +XkbNewKeyboardNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + old_device: i32, + min_key_code: i32, + max_key_code: i32, + old_min_key_code: i32, + old_max_key_code: i32, + changed: u32, + req_major: i8, + req_minor: i8, +} + +XkbMapNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + changed: u32, + flags: u32, + first_type: i32, + num_types: i32, + min_key_code: KeyCode, + max_key_code: KeyCode, + first_key_sym: KeyCode, + first_key_act: KeyCode, + first_key_behavior: KeyCode, + first_key_explicit: KeyCode, + first_modmap_key: KeyCode, + first_vmodmap_key: KeyCode, + num_key_syms: i32, + num_key_acts: i32, + num_key_behaviors: i32, + num_key_explicit: i32, + num_modmap_keys: i32, + num_vmodmap_keys: i32, + vmods: u32, +} + +XkbStateNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + changed: u32, + group: i32, + base_group: i32, + latched_group: i32, + locked_group: i32, + mods: u32, + base_mods: u32, + latched_mods: u32, + locked_mods: u32, + compat_state: i32, + grab_mods: u8, + compat_grab_mods: u8, + lookup_mods: u8, + compat_lookup_mods: u8, + ptr_buttons: i32, + keycode: KeyCode, + event_type: i8, // should be EventType but needs to be i8 instead of i32 + req_major: i8, + req_minor: i8, +} + +XkbControlsNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + changed_ctrls: u32, + enabled_ctrls: u32, + enabled_ctrls_changes: u32, + num_groups: i32, + keycode: KeyCode, + event_type: i8, + req_major: i8, + req_minor: i8, +} + +XkbIndicatorNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + changed: u32, + state: u32, +} + +XkbNamesNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + changed: u32, + first_type: i32, + num_types: i32, + first_lvl: i32, + num_lvls: i32, + num_aliases: i32, + num_radio_groups: i32, + changed_vmods: u32, + changed_groups: u32, + changed_indicators: u32, + first_key: i32, + num_keys: i32, +} + +XkbCompatMapNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + changed_groups: u32, + first_si: i32, + num_si: i32, + num_total_si: i32, +} + +XkbBellNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + percent: i32, + pitch: i32, + duration: i32, + bell_class: i32, + bell_id: i32, + name: Atom, + window: Window, + event_only: b32, +} + +XkbActionMessageEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + keycode: KeyCode, + press: b32, + key_event_follows: b32, + group: i32, + mods: u32, + message: [XkbActionMessageLength+1]i8, +} + +XkbAccessXNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + detail: i32, + keycode: i32, + sk_delay: i32, + debounce_delay: i32, +} + +XkbExtensionDeviceNotifyEvent :: struct { + type: i32, + serial: u64, + send_event: b32, + display: ^Display, + time: Time, + xkb_type: XkbEventType, + device: i32, + reason: u32, + supported: u32, + unsupported: u32, + first_btn: i32, + num_btns: i32, + leds_defined: u32, + led_state: u32, + led_class: i32, + led_id: i32, +} + +XkbEvent :: struct #raw_union { + type: XkbEventType, + any: XkbAnyEvent, + new_kbd: XkbNewKeyboardNotifyEvent, + _map: XkbMapNotifyEvent, + state: XkbStateNotifyEvent, + ctrls: XkbControlsNotifyEvent, + indicators: XkbIndicatorNotifyEvent, + names: XkbNamesNotifyEvent, + compat: XkbCompatMapNotifyEvent, + bell: XkbBellNotifyEvent, + message: XkbActionMessageEvent, + accessx: XkbAccessXNotifyEvent, + device: XkbExtensionDeviceNotifyEvent, + core: XEvent, +} + +/* ---- X11/extensions/XKBgeom.h ---------------------------------------------------------*/ + +XkbPointRec :: struct { + x: i16, + y: i16, +} +XkbPointPtr :: ^XkbPointRec + +XkbBoundsRec :: struct { + x1, x2: i16, + y1, y2: i16, +} +XkbBoundsPtr :: ^XkbBoundsRec + +XkbOutlineRec :: struct { + num_points: u16, + sz_points: u16, + corner_radius: u16, + points: [^]XkbPointRec, +} +XkbOutlinePtr :: ^XkbOutlineRec + +XkbShapeRec :: struct { + name: Atom, + num_outlines: u16, + sz_outlines: u16, + outlines: [^]XkbOutlineRec, + approx: XkbOutlinePtr, + primary: XkbOutlinePtr, + bounds: XkbBoundsRec, +} +XkbShapePtr :: ^XkbShapeRec + +XkbPropertyRec :: struct { + name: cstring, + value: cstring, +} +XkbPropertyPtr :: ^XkbPropertyRec + +XkbColorRec :: struct { + pixel: u32, + spec: ^u8, // cstring? +} +XkbColorPtr :: ^XkbColorRec + +XkbKeyRec :: struct { + name: XkbKeyNameRec, + gap: i16, + shape_ndx: u8, + color_ndx: u8, +} +XkbKeyPtr :: ^XkbKeyRec + +XkbRowRec :: struct { + top: i16, + left: i16, + num_keys: u16, + sz_keys: u16, + vertical: i32, + keys: [^]XkbKeyRec, + bounds: XkbBoundsRec, +} +XkbRowPtr :: ^XkbRowRec + +XkbAnyDoodadRec :: struct { + name: Atom, + type: u8, + priority: u8, + top: i16, + left: i16, + angle: i16, +} +XkbAnyDoodadPtr :: ^XkbAnyDoodadRec + +XkbShapeDoodadRec :: struct { + name: Atom, + type: u8, + priority: u8, + top: i16, + left: i16, + angle: i16, + color_ndx: u16, + shape_ndx: u16, +} +XkbShapeDoodadPtr :: ^XkbShapeDoodadRec + +XkbTextDoodadRec :: struct { + name: Atom, + type: u8, + priority: u8, + top: i16, + left: i16, + angle: i16, + color_ndx: u16, + text: cstring, + font: cstring, +} +XkbTextDoodadPtr :: ^XkbTextDoodadRec + +XkbIndicatorDoodadRec :: struct { + name: Atom, + type: u8, + priority: u8, + top: i16, + left: i16, + angle: i16, + color_ndx: u16, + on_color_ndx: u16, + off_color_ndx: u16, +} +XkbIndicatorDoodadPtr :: ^XkbIndicatorDoodadRec + +XkbLogoDoodadRec :: struct { + name: Atom, + type: u8, + priority: u8, + top: i16, + left: i16, + angle: i16, + color_ndx: u16, + shape_ndx: u16, + logo_name: cstring, +} +XkbLogoDoodadPtr :: ^XkbLogoDoodadRec + +XkbDoodadRec :: struct #raw_union { + any: XkbAnyDoodadRec, + shape: XkbShapeDoodadRec, + text: XkbTextDoodadRec, + indicator: XkbIndicatorDoodadRec, + logo: XkbLogoDoodadRec, +} +XkbDoodadPtr :: ^XkbDoodadRec + +XkbOverlayKeyRec :: struct { + over: XkbKeyNameRec, + under: XkbKeyNameRec, +} +XkbOverlayKeyPtr :: ^XkbOverlayKeyRec + +XkbOverlayRowRec :: struct { + row_under: u16, + num_keys: u16, + sz_keys: u16, + keys: [^]XkbOverlayKeyRec, +} +XkbOverlayRowPtr :: ^XkbOverlayRowRec + +XkbOverlayRec :: struct { + name: Atom, + section_under: XkbSectionPtr, + num_rows: u16, + sz_rows: u16, + rows: [^]XkbOverlayRowRec, + bounds: [^]XkbBoundsRec, +} +XkbOverlayPtr :: ^XkbOverlayRec + +XkbSectionRec :: struct { + name: Atom, + priority: u8, + top: i16, + left: i16, + width: u16, + height: u16, + angle: i16, + num_rows: u16, + num_doodads: u16, + num_overlays: u16, + sz_rows: u16, + sz_doodads: u16, + sz_overlays: u16, + rows: [^]XkbRowRec, + doodads: [^]XkbDoodadRec, + bounds: XkbBoundsRec, + overlays: [^]XkbOverlayRec, +} +XkbSectionPtr :: ^XkbSectionRec + +XkbGeometryRec :: struct { + name: Atom, + width_mm: u16, + height_mm: u16, + label_font: cstring, + label_color: XkbColorPtr, + base_color: XkbColorPtr, + sz_properties: u16, + sz_colors: u16, + sz_shapes: u16, + sz_sections: u16, + sz_doodads: u16, + sz_key_aliases: u16, + num_properties: u16, + num_colors: u16, + num_shapes: u16, + num_sections: u16, + num_doodads: u16, + num_key_aliases: u16, + properties: [^]XkbPropertyRec, + colors: [^]XkbColorRec, + shapes: [^]XkbShapeRec, + sections: [^]XkbSectionRec, + doodads: [^]XkbDoodadRec, + key_aliases: [^]XkbKeyAliasRec, +} +XkbGeometryPtr :: ^XkbGeometryRec + + +/* ---- X11/extensions/XKBstr.h ---------------------------------------------------------*/ + +XkbStateRec :: struct { + group: u8, + locked_group: u8, + base_group: u16, + latched_group: u16, + mods: u8, + base_mods: u8, + latched_mods: u8, + locked_mods: u8, + compat_state: u8, + grab_mods: u8, + compat_grab_mods: u8, + lookup_mods: u8, + compat_lookup_mods: u8, + ptr_buttons: u16, +} +XkbStatePtr :: ^XkbStateRec + +XkbModsRec :: struct { + mask: u8, /* effective mods */ + real_mods: u8, + vmods: u16, +} +XkbModsPtr :: ^XkbModsRec + +XkbKTMapEntryRec :: struct { + active: b32, + level: u8, + mods: XkbModsRec, +} +XkbKTMapEntryPtr :: ^XkbKTMapEntryRec + +XkbKeyTypeRec :: struct { + mod: XkbModsRec, + num_levels: u8, + map_count: u8, + _map: [^]XkbKTMapEntryRec, + preserve: [^]XkbModsRec, + name: Atom, + level_names: [^]Atom, +} +XkbKeyTypePtr :: ^XkbKeyTypeRec + +XkbBehavior :: struct { + type: u8, + data: u8, +} + +XkbAnyAction :: struct { + type: u8, + data: [XkbAnyActionDataSize]u8, +} + +XkbModAction :: struct { + type: u8, + flags: u8, + mask: u8, + real_mods: u8, + vmods1: u8, + vmods2: u8, +} + +XkbGroupAction :: struct { + type: u8, + flags: u8, + group_XXX: i8, +} + +XkbISOAction :: struct { + type: u8, + flags: u8, + mask: u8, + real_mods: u8, + group_XXX: i8, + affect: u8, + vmods1: u8, + vmods2: u8, +} + +XkbPtrAction :: struct { + type: u8, + flags: u8, + high_XXX: u8, + low_XXX: u8, + high_YYY: u8, + low_YYY: u8, +} + +XkbPtrBtnAction :: struct { + type: u8, + flags: u8, + count: u8, + button: u8, +} + +XkbPtrDfltAction :: struct { + type: u8, + flags: u8, + affect: u8, + value_XXX: u8, +} + +XkbSwitchScreenAction :: struct { + type: u8, + flags: u8, + screenXXX: i8, +} + +XkbCtrlsAction :: struct { + type: u8, + flags: u8, + ctrls3: u8, + ctrls2: u8, + ctrls1: u8, + ctrls0: u8, +} + +XkbMessageAction :: struct { + type: u8, + flags: u8, + message: [6]u8, +} + +XkbRedirectKeyAction :: struct { + type: u8, + new_key: u8, + mods_mask: u8, + mods: u8, + vmods_mask0: u8, + vmods_mask1: u8, + vmods0: u8, + vmods1: u8, +} + +XkbDeviceBtnAction :: struct { + type: u8, + flags: u8, + count: u8, + button: u8, + device: u8, +} + +XkbDeviceValuatorAction :: struct { + type: u8, + device: u8, + v1_what: u8, + v1_ndx: u8, + v1_value: u8, + v2_what: u8, + v2_ndx: u8, + v2_value: u8, +} + +XkbAction :: struct #raw_union { + any: XkbAnyAction, + mod: XkbModAction, + group: XkbGroupAction, + iso: XkbISOAction, + ptr: XkbPtrAction, + btn: XkbPtrBtnAction, + dflt: XkbPtrDfltAction, + screen: XkbSwitchScreenAction, + ctrls: XkbCtrlsAction, + msg: XkbMessageAction, + redirect: XkbRedirectKeyAction, + devbtn: XkbDeviceBtnAction, + devval: XkbDeviceValuatorAction, + type: u8, +} + +XkbControlsRec :: struct { + mk_dflt_btn: u8, + num_groups: u8, + groups_wrap: u8, + internal: XkbModsRec, + ignore_lock: XkbModsRec, + enabled_ctrls: u32, + repeat_delay: u16, + repeat_interval: u16, + slow_keys_delay: u16, + debounce_delay: u16, + mk_delay: u16, + mk_interval: u16, + mk_time_to_max: u16, + mk_max_speed: u16, + mk_curve: i16, + ax_options: u16, + ax_timeout: u16, + axt_opts_mask: u16, + axt_opts_values: u16, + axt_ctrls_mask: u32, + axt_ctrls_values: u32, + per_key_repeat: [XkbPerKeyBitArraySize]u8, +} +XkbControlsPtr :: ^XkbControlsRec + +XkbServerMapRec :: struct { + num_acts: u16, + size_acts: u16, + acts: [^]XkbAction, + + behaviors: [^]XkbBehavior, + key_acts: [^]u16, + explicit: [^]u8, + vmods: [XkbNumVirtualMods]u8, + vmodmap: [^]u16, +} +XkbServerMapPtr :: ^XkbServerMapRec + +XkbSymMapRec :: struct { + kt_index: [XkbNumKbdGroups]u8, + group_info: u8, + width: u8, + offset: u16, +} +XkbSymMapPtr :: ^XkbSymMapRec + +XkbClientMapRec :: struct { + size_types: u8, + num_types: u8, + types: [^]XkbKeyTypeRec, + + size_syms: u16, + num_syms: u16, + syms: [^]XID, // Keysym + key_sym_map: [^]XkbSymMapRec, + + modmap: [^]u8, +} +XkbClientMapPtr :: ^XkbClientMapRec + +XkbSymInterpretRec :: struct { + sym: XID, // KeySym + flags: u8, + match: u8, + mods: u8, + virtual_mod: u8, + act: XkbAnyAction, +} +XkbSymInterpretPtr :: ^XkbSymInterpretRec + +XkbCompatMapRec :: struct { + sym_interpret: [^]XkbSymInterpretRec, + groups: [XkbNumKbdGroups]XkbModsRec, + num_si: u16, + size_si: u16, +} +XkbCompatMapPtr :: ^XkbCompatMapRec + +XkbIndicatorMapRec :: struct { + flags: u8, + which_groups: u8, + groups: u8, + which_mods: u8, + mods: XkbModsRec, + ctrls: u32, +} +XkbIndicatorMapPtr :: ^XkbIndicatorMapRec + +XkbIndicatorRec :: struct { + phys_indicators: u64, + maps: [XkbNumIndicators]XkbIndicatorMapRec, +} +XkbIndicatorPtr :: ^XkbIndicatorRec + +XkbKeyNameRec :: struct { + name: [XkbKeyNameLength]i8, // Non nul-terminated string +} +XkbKeyNamePtr :: ^XkbKeyNameRec + +XkbKeyAliasRec :: struct { + real: [XkbKeyNameLength]i8, // Non nul-terminated string + alias: [XkbKeyNameLength]i8, // Non nul-terminated string +} +XkbKeyAliasPtr :: ^XkbKeyAliasRec + +XkbNamesRec :: struct { + keycodes: Atom, + geometry: Atom, + symbols: Atom, + types: Atom, + compat: Atom, + vmods: [XkbNumVirtualMods]Atom, + indicators: [XkbNumIndicators]Atom, + groups: [XkbNumKbdGroups]Atom, + keys: [^]XkbKeyNameRec, + key_aliases: [^]XkbKeyAliasRec, + radio_groups: [^]Atom, + phys_symbol: Atom, + num_keys: u8, + num_key_aliases: u8, + num_rg: u16, +} +XkbNamesPtr :: ^XkbNamesRec + +XkbDescRec :: struct { + display: ^Display, + flags: u16, + device_spec: u16, + min_key_code: KeyCode, + max_key_code: KeyCode, + + ctrls: XkbControlsPtr, + server: XkbServerMapPtr, + _map: XkbClientMapPtr, + indicators: XkbIndicatorPtr, + names: XkbNamesPtr, + compat: XkbCompatMapPtr, + geom: XkbGeometryPtr, +} +XkbDescPtr :: ^XkbDescRec + + /* ---- X11/Xcms.h ---------------------------------------------------------*/ XcmsColorFormat :: uint